فهرست منبع

Merge pull request #1 from OpenGamePanel/master

Updating
rocco27 8 سال پیش
والد
کامیت
83e18a8f50
8فایلهای تغییر یافته به همراه610 افزوده شده و 225 حذف شده
  1. 198 0
      ArmaBE/ArmaBE.pm
  2. 1 1
      EHCP/addAccount.php
  3. 1 1
      EHCP/updateInfo.php
  4. 24 16
      KKrcon/HL2.pm
  5. 41 27
      KKrcon/KKrcon.pm
  6. 249 130
      ogp_agent.pl
  7. 65 35
      ogp_agent_run
  8. 31 15
      php-query/lgsl/lgsl_protocol.php

+ 198 - 0
ArmaBE/ArmaBE.pm

@@ -0,0 +1,198 @@
+# ArmaBE - Perl extension BattlEye ARMA Rcon interface
+# Original Source for BattlEye source - https://github.com/Jaegerhaus/BE-RCon-Tools
+#
+# $Id:$
+#
+
+package ArmaBE;
+
+use strict;
+use warnings;
+use IO::Socket::INET;
+
+# release version
+our $VERSION = "0.01";
+
+# create class
+sub new {
+	my $class = shift;
+
+	# create object with defaults
+	my $self = {
+		hostname	=> undef,
+		port		=> 27015,
+		password	=> undef,
+		timeout		=> 5,
+		connected	=> 0,
+		authenticated	=> 0,
+		socket		=> undef,
+		sequence	=> 0,
+	};
+
+	# create object
+	bless($self, $class);
+
+	# initialize class instances
+	$self->init();
+
+	# parse constructor args
+	while (my ($key, $val) = splice(@_, 0, 2)) {
+		$key = lc($key);
+		if    ($key eq "hostname") { $self->hostname($val) }
+		elsif ($key eq "port")     { $self->port($val)     }
+		elsif ($key eq "password") { $self->password($val) }
+		elsif ($key eq "timeout")  { $self->timeout($val)  }
+		else { print STDERR "Unknown attribute: $key\n" }
+	}
+
+	return $self;
+}
+
+# initialize class instances
+sub init {
+	my $self = shift;
+	my $class = ref($self);
+
+	# manipulate symbol table.. gotta love perl
+	no strict "refs";
+	no warnings;
+	foreach my $instance (keys %$self) {
+		*{"${class}::${instance}"} = sub {
+			my $self = shift;
+			my $value = shift;
+			my $ref = \$self->{$instance};
+			if (defined $value) {
+				$$ref = $value;
+				return $self;
+			} else {
+				return $$ref;
+			}
+		};
+	}
+}
+
+# run a command and return its response
+sub run {
+	my $self = shift;
+	my $command = shift;
+
+	if (!$self->connected()) {
+		$self->connect();
+	}
+
+	if (!$self->authenticated()) {
+		$self->authenticate();
+	}
+
+	if ($self->authenticated()) {
+		my $socket = $self->socket();
+		print $socket $self->packet("\1\0".$command);
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+# create tcp socket
+sub connect {
+	my $self = shift;
+
+	my $socket = IO::Socket::INET->new(
+		PeerAddr        => $self->hostname(),
+		PeerPort        => $self->port(),
+		Timeout		=> $self->timeout(),
+		Proto           => "udp",
+	) || die "Failed to connect: $!\n";
+
+	$self->socket($socket);
+	$self->connected(1);
+}
+
+# authenticate rcon session
+sub authenticate {
+	my $self = shift;
+
+	# send authentication packet to server
+	my $socket = $self->socket();
+	print $socket $self->packet("\0".$self->password());
+
+	my $response = $self->response();
+	my $authenticated = int(substr($response, -1));
+
+	$self->authenticated($authenticated);
+}
+
+######################
+# PROTOCOL FUNCTIONS #
+######################
+
+# rcon command protocol:
+# https://www.battleye.com/downloads/BERConProtocol.txt
+
+sub crc32 {
+	my ($self,$input,$init_value,$polynomial) = @_;
+
+	$init_value = 0 unless (defined $init_value);
+	$polynomial = 0xedb88320 unless (defined $polynomial);
+
+	my @lookup_table;
+
+	for (my $i=0; $i<256; $i++) {
+		my $x = $i;
+		for (my $j=0; $j<8; $j++) {
+			if ($x & 1) {
+				$x = ($x >> 1) ^ $polynomial;
+			} else {
+				$x = $x >> 1;
+			}
+		}
+		push @lookup_table, $x;
+	}
+
+	my $crc = $init_value ^ 0xffffffff;
+
+	foreach my $x (unpack ('C*', $input)) {
+		$crc = (($crc >> 8) & 0xffffff) ^ $lookup_table[ ($crc ^ $x) & 0xff ];
+	}
+
+	$crc = $crc ^ 0xffffffff;
+
+	return $crc;
+}
+
+# create a packet of type (AUTH or CMD)
+sub packet {
+	my $self = shift;
+	my $payload = shift;
+
+	my $break = pack('C', 0xff);
+	my $packet = "BE"
+		. pack('V', $self->crc32($break . $payload))
+		. $break
+		. $payload;
+
+	return $packet;
+}
+
+# receive packet
+sub response {
+	my $self = shift;
+	my $payload = $self->read();
+
+	return $payload;
+}
+
+# read length of bytes from socket with timeout
+sub read {
+	my $self = shift;
+	my $received;
+	my $socket = $self->socket();
+	
+	$socket->recv($received, 9);
+
+	return unpack('H*', $received);
+}
+
+1;
+
+__END__

+ 1 - 1
EHCP/addAccount.php

@@ -63,7 +63,7 @@ if (isset($ftp_username) && isset($ftp_pass) && isset($rDir)) {
     // If the last character in the path is a slash (/) - Remove it from the string
     
     if (substr_count($rDir, '/') >= 2 && $rDir[strlen($rDir) - 1] == "/") {
-        $end = strlen($rDir) - 2;
+        $end = strlen($rDir) - 1;
         $rDir = substr($rDir, 0, $end);
     }
     

+ 1 - 1
EHCP/updateInfo.php

@@ -85,7 +85,7 @@ if (!isset($ftp_username) || !isset($update_dir)) {
     // If the last character in the path is a slash (/) - Remove it from the string
     
     if (substr_count($update_dir, '/') > 2 && $update_dir[strlen($update_dir) - 1] == "/") {
-        $end = strlen($update_dir) - 2;
+        $end = strlen($update_dir) - 1;
         $update_dir = substr($update_dir, 0, $end);
     }
     

+ 24 - 16
KKrcon/HL2.pm

@@ -46,7 +46,7 @@ sub new {
 		elsif ($key eq "port")     { $self->port($val)     }
 		elsif ($key eq "password") { $self->password($val) }
 		elsif ($key eq "timeout")  { $self->timeout($val)  }
-		else { print STDERR "uknown attribute: $key\n" }
+		else { print STDERR "Unknown attribute: $key\n" }
 	}
 
 	return $self;
@@ -104,7 +104,7 @@ sub connect {
 		Timeout		=> $self->timeout(),
 		Proto           => "tcp",
 		Type            => SOCK_STREAM,
-	) || die "failed to connect: $!\n";
+	) || die "Failed to connect: $!\n";
 
 	$self->socket($socket);
 	$self->connected(1);
@@ -168,18 +168,12 @@ sub packet {
 # receive packet
 sub response {
 	my $self = shift;
+	my $payload = $self->read();
 
-	my $size = unpack("V", $self->read(4));
+	# remove protocol cruft and null terminators
+	$payload =~ s/\x00{2}$//;
 
-	if ($size) {
-		my $payload = $self->read($size);
-
-		# remove protocol cruft and null terminators
-		$payload =~ s/^.{8}//;
-		$payload =~ s/\x00{2}$//;
-
-		return $payload;
-	}
+	return $payload;
 }
 
 # read length of bytes from socket with timeout
@@ -191,10 +185,24 @@ sub read {
 	my $timeout = $self->timeout();
 	my $select = IO::Select->new($socket);
 
-	if ($select->can_read($timeout)) {
-		$socket->sysread(my $read, $length, 0);
-		return $read;
+	my $reply = "";
+	my $buffer;
+
+	my ($size, $request_id, $command_response, $data);
+
+	while ($select->can_read(0.5)) {
+		$socket->recv($buffer, 4, MSG_PEEK);
+		$size = unpack("V", $buffer);
+		last if (!defined($size));
+		$socket->recv($buffer, $size+4, MSG_WAITALL);
+
+		($size, $request_id, $command_response, $data) =
+			unpack('VVVZ*x', $buffer);
+
+		$reply .= "$data";
 	}
+
+	return $reply;
 }
 
 1;
@@ -331,4 +339,4 @@ Chris Jones, E<lt>[email protected]<gt>
  it under the same terms as Perl itself, either Perl version 5.8.5 or,
  at your option, any later version of Perl 5 you may have available.
 
-=cut
+=cut

+ 41 - 27
KKrcon/KKrcon.pm

@@ -69,7 +69,6 @@ sub new
 	$self->{"error"} = "";
 	
 	# Set up socket parameters
-	$self->{"_proto"}  = getprotobyname('udp');
 	$self->{"_ipaddr"} = gethostbyname($self->{"server_host"})
 		or die("KKrcon: could not resolve Host \"" . $self->{"server_host"} . "\"\n");
 	
@@ -128,20 +127,10 @@ sub _sendrecv
 	my $host = $self->{"server_host"};
 	my $port = $self->{"server_port"};
 	my $ipaddr = $self->{"_ipaddr"};
-	my $proto  = $self->{"_proto"};
 	
 	# Open socket
-	socket(RCON, PF_INET, SOCK_DGRAM, $proto)
-		or die("KKrcon: socket: $!\n");
-	
-	# bind causes problems if hostname() gets wrong interface...
-	# and it doesn't seem to be necessary
-	#
-	#my $iaddr = gethostbyname(hostname());
-	#my $paddr = sockaddr_in(0, $iaddr);
-	#bind(RCON, $paddr)
-	#	or die("KKrcon: bind: $!\n");
-	
+	socket(RCON, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die("KKrcon: socket: $!\n");
+
 	my $hispaddr = sockaddr_in($port, $ipaddr);
 	
 	unless(defined(send(RCON, $msg, 0, $hispaddr)))
@@ -149,26 +138,51 @@ sub _sendrecv
 		die("KKrcon: send $ip:$port : $!");
 	}
 
-	my $rin = "";
+	my $rin;
 	vec($rin, fileno(RCON), 1) = 1;
-	
-	my $ans = "TIMEOUT";
-	if (select($rin, undef, undef, 10.0))
-	{
-		$ans = "";
+	my $ans;
+
+	if (select($rin, undef, undef, 10.0)) {
 		$hispaddr = recv(RCON, $ans, 8192, 0);
-		$ans =~ s/\x00+$//;			# trailing crap
-		$ans =~ s/^\xFF\xFF\xFF\xFFl//;		# HL response
-		$ans =~ s/^\xFF\xFF\xFF\xFFn//;		# QW response
-		$ans =~ s/^\xFF\xFF\xFF\xFF//;		# Q2/Q3 response
-		$ans =~ s/^\xFE\xFF\xFF\xFF.....//;	# old HL bug/feature
+
+		if (defined($ans)) {
+			$ans =~ s/^\xFF\xFF\xFF\xFFprint\n//;    # CoD2 response
+			$ans =~ s/\x00+$//;			# trailing crap
+			$ans =~ s/^\xFF\xFF\xFF\xFFl//;		# HL response
+			$ans =~ s/^\xFF\xFF\xFF\xFFn//;		# QW response
+			$ans =~ s/^\xFF\xFF\xFF\xFF//;		# Q2/Q3 response
+			$ans =~ s/^\xFE\xFF\xFF\xFF.....//;	# old HL bug/feature
+
+			if (length($ans) > 512) {
+				my $tmp;
+				my @explode;
+
+				while (select($rin, undef, undef, 0.05)) {
+					@explode = split(/\n/, $ans);
+					$explode[$#explode] =~ s/^ //;
+					$explode[$#explode] = 'X' . $explode[$#explode];
+					$ans = join("\n", @explode);
+
+					$hispaddr = recv(RCON, $tmp, 8192, 0);
+
+					if (defined($tmp)) {
+						$tmp =~ s/^\xFF\xFF\xFF\xFFprint\n//;    # CoD2 response
+						$tmp =~ s/\x00+$//;			# trailing crap
+						$tmp =~ s/^\xFF\xFF\xFF\xFFl//;		# HL response
+						$tmp =~ s/^\xFF\xFF\xFF\xFFn//;		# QW response
+						$tmp =~ s/^\xFF\xFF\xFF\xFF//;		# Q2/Q3 response
+						$tmp =~ s/^\xFE\xFF\xFF\xFF.....//;	# old HL bug/feature
+						$ans .= $tmp;
+					}
+				}
+			}
+		}
 	}
 	
 	# Close socket
 	close(RCON);
 	
-	if ($ans eq "TIMEOUT")
-	{
+	if (!defined($ans)) {
 		$ans = "";
 		$self->{"error"} = "Rcon timeout";
 	}
@@ -265,4 +279,4 @@ sub getPlayer
 
 
 1;
-# end
+# end

+ 249 - 130
ogp_agent.pl

@@ -66,6 +66,7 @@ use constant AGENT_PID_FILE =>
 use constant STEAM_LICENSE_OK => "Accept";
 use constant STEAM_LICENSE	=> $Cfg::Config{steam_license};
 use constant MANUAL_TMP_DIR   => Path::Class::Dir->new(AGENT_RUN_DIR, 'tmp');
+use constant SHARED_GAME_TMP_DIR   => Path::Class::Dir->new(AGENT_RUN_DIR, 'shared');
 use constant STEAMCMD_CLIENT_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'steamcmd');
 use constant STEAMCMD_CLIENT_BIN =>
   Path::Class::File->new(STEAMCMD_CLIENT_DIR, 'steamcmd.sh');
@@ -172,6 +173,13 @@ if (!-d SCREEN_LOGS_DIR && !mkdir SCREEN_LOGS_DIR)
 	exit -1;
 }
 
+# Check the global shared games folder
+if (!-d SHARED_GAME_TMP_DIR && !mkdir SHARED_GAME_TMP_DIR)
+{
+	logger "Could not create " . SHARED_GAME_TMP_DIR . " directory $!.", 1;
+	exit -1;
+}
+
 if (check_steam_cmd_client() == -1)
 {
 	print "ERROR: You must download and uncompress the new steamcmd package.";
@@ -228,7 +236,7 @@ elsif ($no_startups != 1)
 			my (
 				$home_id,   $home_path,   $server_exe,
 				$run_dir,   $startup_cmd, $server_port,
-				$server_ip, $cpu, $nice, $preStart, $envVars
+				$server_ip, $cpu, $nice, $preStart, $envVars, $game_key
 			   ) = split(',', $_);
 
 			if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) ==
@@ -243,7 +251,7 @@ elsif ($no_startups != 1)
 			universal_start_without_decrypt(
 										 $home_id,   $home_path,   $server_exe,
 										 $run_dir,   $startup_cmd, $server_port,
-										 $server_ip, $cpu,	$nice, $preStart, $envVars
+										 $server_ip, $cpu,	$nice, $preStart, $envVars, $game_key
 										   );
 		}
 		close(STARTFILE);
@@ -458,7 +466,7 @@ sub create_screen_id
 sub create_screen_cmd
 {
 	my ($screen_id, $exec_cmd) = @_;
-	$exec_cmd = replace_OGP_Vars($screen_id, $exec_cmd);
+	$exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd);
 	return
 	  sprintf('export WINEDEBUG="fixme-all" && export DISPLAY=:1 && screen -d -m -t "%1$s" -c ' . SCREENRC_FILE . ' -S %1$s %2$s',
 			  $screen_id, $exec_cmd);
@@ -467,10 +475,10 @@ sub create_screen_cmd
 
 sub create_screen_cmd_loop
 {
-	my ($screen_id, $exec_cmd, $envVars) = @_;
+	my ($screen_id, $exec_cmd, $envVars, $skipLoop) = @_;
 	my $server_start_bashfile = $screen_id . "_startup_scr.sh";
 	
-	$exec_cmd = replace_OGP_Vars($screen_id, $exec_cmd);
+	$exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd);
 	
 	# Allow file to be overwritten
 	if(-e $server_start_bashfile){
@@ -481,29 +489,36 @@ sub create_screen_cmd_loop
 	# If it crashes without user intervention, it will restart
 	open (SERV_START_SCRIPT, '>', $server_start_bashfile);
 	
-	my $respawn_server_command = "#!/bin/bash" . "\n" 
-	. "function startServer(){" . "\n" ;
+	my $respawn_server_command = "#!/bin/bash" . "\n";
+	
+	if(!$skipLoop){
+		$respawn_server_command .= "function startServer(){" . "\n";
+	}
 	
 	if(defined $envVars && $envVars ne ""){
 		$respawn_server_command .= $envVars;
 	}
 	
-	$respawn_server_command .= "NUMSECONDS=`expr \$(date +%s)`" . "\n"
-	. "until " . $exec_cmd . "; do" . "\n" 
-	. "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n"
-	. "if [ \"\$DIFF\" -gt 15 ]; then" . "\n" 
-	. "NUMSECONDS=`expr \$(date +%s)`" . "\n"
-	. "echo \"Server '" . $exec_cmd . "' crashed with exit code \$?.  Respawning...\" >&2 " . "\n" 
-	. "fi" . "\n" 
-	. "sleep 3" . "\n" 
-	. "done" . "\n" 
-	. "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n"
-	
-	. "if [ ! -e \"SERVER_STOPPED\" ] && [ \"\$DIFF\" -gt 15 ]; then" . "\n"
-	. "startServer" . "\n"
-	. "fi" . "\n"
-	. "}" . "\n"
-	. "startServer" . "\n";
+	if(!$skipLoop){
+		$respawn_server_command .= "NUMSECONDS=`expr \$(date +%s)`" . "\n"
+		. "until " . $exec_cmd . "; do" . "\n" 
+		. "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n"
+		. "if [ \"\$DIFF\" -gt 15 ]; then" . "\n" 
+		. "NUMSECONDS=`expr \$(date +%s)`" . "\n"
+		. "echo \"Server '" . $exec_cmd . "' crashed with exit code \$?.  Respawning...\" >&2 " . "\n" 
+		. "fi" . "\n" 
+		. "sleep 3" . "\n" 
+		. "done" . "\n" 
+		. "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n"
+		
+		. "if [ ! -e \"SERVER_STOPPED\" ] && [ \"\$DIFF\" -gt 15 ]; then" . "\n"
+		. "startServer" . "\n"
+		. "fi" . "\n"
+		. "}" . "\n"
+		. "startServer" . "\n";
+	}else{
+		$respawn_server_command .= $exec_cmd . "\n";
+	}
 	
 	print SERV_START_SCRIPT $respawn_server_command;
 	close (SERV_START_SCRIPT);
@@ -519,31 +534,56 @@ sub create_screen_cmd_loop
 
 }
 
-sub replace_OGP_Vars{
-	# This function replaces constants from game server XML Configs with OGP paths for Steam Auto Updates for example
-	my ($screen_id, $exec_cmd) = @_;
-	my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1);
-	my $steamInsFile = $screen_id_for_txt_update . "_install.txt";
-	my $steamCMDPath = STEAMCMD_CLIENT_DIR;
-	my $fullPath = Path::Class::File->new($steamCMDPath, $steamInsFile);
-	
-	# If the install file exists, the game can be auto updated, else it will be ignored by the game for improper syntax
-	# To generate the install file, the "Install/Update via Steam" button must be clicked on at least once!
-	if(-e $fullPath){
-		$exec_cmd =~ s/{OGP_STEAM_CMD_DIR}/$steamCMDPath/g;
-		$exec_cmd =~ s/{STEAMCMD_INSTALL_FILE}/$steamInsFile/g;
+sub handle_lock_command_line{
+	my ($command) = @_;
+	if(defined $command && $command ne ""){
+		if ($command =~ m/{OGP_LOCK_FILE}/) {
+			$command =~ s/{OGP_LOCK_FILE}\s*//g;
+			return secure_path_without_decrypt("chattr+i", $command);
+		}
 	}
 	
-	return $exec_cmd;
+	return 0;
 }
 
 sub replace_OGP_Env_Vars{
 	# This function replaces constants from environment variables set in the XML
-	my ($homeid, $homepath, $strToReplace) = @_;
+	my ($screen_id, $homeid, $homepath, $exec_cmd, $game_key) = @_;
+	
+	# Handle steam specific replacements
+	if(defined $screen_id && $screen_id ne ""){
+		my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1);
+		my $steamInsFile = $screen_id_for_txt_update . "_install.txt";
+		my $steamCMDPath = STEAMCMD_CLIENT_DIR;
+		my $fullPath = Path::Class::File->new($steamCMDPath, $steamInsFile);
+		
+		# If the install file exists, the game can be auto updated, else it will be ignored by the game for improper syntax
+		# To generate the install file, the "Install/Update via Steam" button must be clicked on at least once!
+		if(-e $fullPath){
+			$exec_cmd =~ s/{OGP_STEAM_CMD_DIR}/$steamCMDPath/g;
+			$exec_cmd =~ s/{STEAMCMD_INSTALL_FILE}/$steamInsFile/g;
+		}
+	}
 
-	$strToReplace =~ s/{OGP_HOME_DIR}/$homepath/g;
 	
-	return $strToReplace;
+	# Handle home directory replacement
+	if(defined $homepath && $homepath ne ""){
+		$exec_cmd =~ s/{OGP_HOME_DIR}/$homepath/g;
+	}
+	
+	# Handle global game shared directory replacement
+	if(defined $game_key && $game_key ne ""){
+		my $readable_game_key = lc(substr($game_key, 0, rindex($game_key,"_")));		
+		my $shared_path = Path::Class::Dir->new(SHARED_GAME_TMP_DIR, $readable_game_key);
+		# Create the folder if it doesn't exist
+		if (!-d $shared_path && !mkdir $shared_path)
+		{
+			logger "Could not create " . $shared_path . " directory $!.", 1;
+		}
+		$exec_cmd =~ s/{OGP_GAME_SHARED_DIR}/$shared_path/g;
+	}
+	
+	return $exec_cmd;
 }
 
 sub encode_list
@@ -690,12 +730,9 @@ sub universal_start_without_decrypt
 {
 	my (
 		$home_id, $home_path, $server_exe, $run_dir,
-		$startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars
+		$startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key
 	   ) = @_;
 	   
-	# Replace any {OGP_HOME_DIR} in the $start_cmd with the server's home directory path
-	$startup_cmd = replace_OGP_Env_Vars($home_id, $home_path, $startup_cmd);
-	   
 	if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1)
 	{
 		logger "This server is already running (ID: $home_id).";
@@ -747,7 +784,7 @@ sub universal_start_without_decrypt
 		my @prestartenvvars = split /[\r\n]+/, $envVars;
 		my $envVarStr = "";
 		foreach my $line (@prestartenvvars) {
-			$line = replace_OGP_Env_Vars($home_id, $home_path, $line);
+			$line = replace_OGP_Env_Vars("", $home_id, $home_path, $line, $game_key);
 			if($line ne ""){
 				logger "Configuring environment variable: $line";
 				$envVarStr .= "$line\n";
@@ -802,6 +839,9 @@ sub universal_start_without_decrypt
 	my $command;
 	my $run_before_start;
 	
+	# Replace any OGP variables found in the command line
+	$startup_cmd = replace_OGP_Env_Vars($screen_id, $home_id, $home_path, $startup_cmd, $game_key);
+	
 	if($file_extension eq ".exe" or $file_extension eq ".bat")
 	{
 		$command = "wine $server_exe $startup_cmd";
@@ -815,7 +855,7 @@ sub universal_start_without_decrypt
 			deleteStoppedStatFile($home_path);
 			$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars);
 		}else{
-			$cli_bin = create_screen_cmd($screen_id, $command);
+			$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1);
 		}
 	}
 	elsif($file_extension eq ".jar")
@@ -831,7 +871,7 @@ sub universal_start_without_decrypt
 			deleteStoppedStatFile($home_path);
 			$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars);
 		}else{
-			$cli_bin = create_screen_cmd($screen_id, $command);
+			$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1);
 		}
 	}
 	else
@@ -847,7 +887,7 @@ sub universal_start_without_decrypt
 			deleteStoppedStatFile($home_path);
 			$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars);
 		}else{
-			$cli_bin = create_screen_cmd($screen_id, $command);
+			$cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1);
 		}
 	}
 		
@@ -857,8 +897,8 @@ sub universal_start_without_decrypt
 	logger
 	  "Startup command [ $cli_bin ] will be executed in dir $game_binary_dir.";
 	
-	# Run before start script and set environment variables which will affect create_screen_cmd only... loop already has the envvars as well
-	$run_before_start = run_before_start_commands($home_id, $home_path, $preStart, $envVars);
+	# Run before start script
+	$run_before_start = run_before_start_commands($home_id, $home_path, $preStart);
 	
 	system($cli_bin);
 	
@@ -1116,6 +1156,8 @@ sub stop_server_without_decrypt
 	my ($home_id, $server_ip, $server_port, $control_protocol,
 		$control_password, $control_type, $home_path) = @_;
 		
+	my $usedProtocolToStop = 0;
+		
 	my $startup_file = Path::Class::File->new(GAME_STARTUP_DIR, "$server_ip-$server_port");
 	
 	if (-e $startup_file)
@@ -1161,6 +1203,7 @@ sub stop_server_without_decrypt
 
 			my $rconCommand = "quit";
 			$rcon->execute($rconCommand);
+			$usedProtocolToStop = 1;
 		}
 		elsif ($control_protocol eq "rcon2")
 		{
@@ -1174,6 +1217,49 @@ sub stop_server_without_decrypt
 
 			my $rconCommand = "quit";
 			$rcon2->run($rconCommand);
+			$usedProtocolToStop = 1;
+		}
+		elsif ($control_protocol eq "armabe")
+		{
+			use ArmaBE::ArmaBE;
+			my $armabe = new ArmaBE(
+								  hostname => $server_ip,
+								  port	 => $server_port, # Uses server port for now (Arma 2), Arma 3 BE uses a different, user definable port
+								  password => $control_password,
+								  timeout  => 2
+								 );
+
+			my $rconCommand = "#shutdown";
+			my $armabe_result = $armabe->run($rconCommand);
+			if ($armabe_result) {
+				logger "ArmaBE Shutdown command sent successfully";		
+				$usedProtocolToStop = 1;
+			}
+		}
+		
+		my @server_pids = get_home_pids($home_id);
+		
+		# Gives the server time to shutdown with rcon in case it takes a while for the server to shutdown (arma for example) before we forcefully kill it
+		if ($usedProtocolToStop == 1){
+			my $timeWaited = 0;
+			my $pidSize = @server_pids;
+			my $maxWaitTime = 5;
+			
+			# Maximum time to wait can now be configured as a preference
+			if(defined($Cfg::Preferences{protocol_shutdown_waittime}) && $Cfg::Preferences{protocol_shutdown_waittime} =~ /^\d+?$/){
+				$maxWaitTime = $Cfg::Preferences{protocol_shutdown_waittime};
+			}
+			
+			while ($pidSize > 0 && $timeWaited < $maxWaitTime) {
+				select(undef, undef, undef, 0.25); # Sleeps for 250ms
+				
+				# Add to time waited
+				$timeWaited += 0.25;
+				
+				# Recheck server home PIDs
+				@server_pids = get_home_pids($home_id);
+				$pidSize = @server_pids;
+			}
 		}
 		
 		if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 0)
@@ -1185,8 +1271,8 @@ sub stop_server_without_decrypt
 		{
 			logger "Failed to send rcon quit. Stopping server with kill command.";
 		}
-
-		my @server_pids = get_home_pids($home_id);
+		
+		@server_pids = get_home_pids($home_id);
 		
 		my $cnt;
 		foreach my $pid (@server_pids)
@@ -1296,24 +1382,37 @@ sub send_rcon_command
 			my $encoded_content = encode_list(@modedlines);
 			return "1;" . $encoded_content;
 		}
-		else
-		{		
-			if ($control_protocol eq "rcon2")
-			{
-				use KKrcon::HL2;
-				my $rcon2 = new HL2(
-									  hostname => $server_ip,
-									  port	 => $server_port,
-									  password => $control_password,
-									  timeout  => 2
-									 );
-													
-				logger "Sending RCON command to $server_ip:$server_port: \n $rconCommand \n  .";
-						
-				my(@modedlines) = $rcon2->run($rconCommand);
-				my $encoded_content = encode_list(@modedlines);
-				return "1;" . $encoded_content;
-			}
+		elsif ($control_protocol eq "rcon2")
+		{
+			use KKrcon::HL2;
+			my $rcon2 = new HL2(
+								  hostname => $server_ip,
+								  port	 => $server_port,
+								  password => $control_password,
+								  timeout  => 2
+								 );
+			
+			logger "Sending RCON command to $server_ip:$server_port: \n $rconCommand \n  .";
+					
+			my(@modedlines) = $rcon2->run($rconCommand);
+			my $encoded_content = encode_list(@modedlines);
+			return "1;" . $encoded_content;
+		}
+		elsif ($control_protocol eq "armabe")
+		{
+			use ArmaBE::ArmaBE;
+			my $armabe = new ArmaBE(
+								  hostname => $server_ip,
+								  port	 => $server_port, # Uses server port for now (Arma 2), Arma 3 BE uses a different, user definable port
+								  password => $control_password,
+								  timeout  => 2
+								 );
+			
+			logger "Sending RCON command to $server_ip:$server_port: \n $rconCommand \n  .";
+					
+			my(@modedlines) = $armabe->run($rconCommand);
+			my $encoded_content = encode_list(@modedlines);
+			return "1;" . $encoded_content;
 		}
 	}
 	else
@@ -1647,6 +1746,30 @@ sub start_file_download
 				uncompress_file_without_decrypt($download_file_path,
 												$destination);
 			}
+			
+			# Run post scripts if any
+			if ($post_script ne "")
+			{
+				logger "Running postscript commands.";
+				my @postcmdlines = split /[\r\n]+/, $post_script;
+				my $postcmdfile = $destination."/".'postinstall.sh';
+				open  FILE, '>', $postcmdfile;
+				print FILE "cd $destination\n";
+				foreach my $line (@postcmdlines) {
+					logger "Postscript command received \"" . $line ."\".";
+					if(handle_lock_command_line($line) == 0){
+						print FILE "$line\n";
+					}else{
+						logger "Lock command completed successfully";					
+					}
+				}
+				print FILE "rm -f $destination/postinstall.sh\n";
+				close FILE;
+				chmod 0755, $postcmdfile;
+				my $screen_id = create_screen_id("post_script", $$);
+				my $cli_bin = create_screen_cmd($screen_id, "bash $postcmdfile");
+				system($cli_bin);
+			}
 		}
 		else
 		{
@@ -1660,27 +1783,6 @@ sub start_file_download
 	}
 	else
 	{
-		if ($post_script ne "")
-		{
-			logger "Running postscript commands.";
-			my @postcmdlines = split /[\r\n]+/, $post_script;
-			my $postcmdfile = $destination."/".'postinstall.sh';
-			open  FILE, '>', $postcmdfile;
-			print FILE "cd $destination\n";
-			print FILE "while kill -0 $pid >/dev/null 2>&1\n";
-			print FILE "do\n";
-			print FILE "	sleep 1\n";
-			print FILE "done\n";
-			foreach my $line (@postcmdlines) {
-				print FILE "$line\n";
-			}
-			print FILE "rm -f $destination/postinstall.sh\n";
-			close FILE;
-			chmod 0755, $postcmdfile;
-			my $screen_id = create_screen_id("post_script", $pid);
-			my $cli_bin = create_screen_cmd($screen_id, "bash $postcmdfile");
-			system($cli_bin);
-		}
 		logger "Download process for $download_file_path has pid number $pid.";
 		return "$pid";
 	}
@@ -1699,7 +1801,7 @@ sub lock_additional_files_logic{
 	
 	my $commandStr = "";
 	$filesToLock = startup_comma_format_to_multiline($filesToLock);
-	$filesToLock = replace_OGP_Env_Vars("", $homedir, $filesToLock);
+	$filesToLock = replace_OGP_Env_Vars("", "", $homedir, $filesToLock);
 	my @filesToProcess = split /[\r\n]+/, $filesToLock;
 	foreach my $line (@filesToProcess) {
 		my $fullPath = $homedir . "/" . $line;
@@ -1732,7 +1834,7 @@ sub lock_additional_files_logic{
 sub run_before_start_commands
 {
 	#return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
-	my ($server_id, $homedir, $beforestartcmd, $envVars) = @_;
+	my ($server_id, $homedir, $beforestartcmd) = @_;
 	
 	if ($homedir ne "" && $server_id ne ""){
 		# Run any prestart scripts
@@ -1751,21 +1853,7 @@ sub run_before_start_commands
 			close FILE;
 			chmod 0755, $prestartcmdfile;
 			system("bash $prestartcmdfile");
-		}
-		
-		
-		# Set and export any environment variables for game server developers unwilling to properly learn Linux
-		if (defined $envVars && $envVars ne ""){
-			my @prestartenvvars = split /[\r\n]+/, $envVars;
-			foreach my $line (@prestartenvvars) {
-				$line = replace_OGP_Env_Vars($server_id, $homedir, $line);
-				if($line ne ""){
-					logger "Configuring environment variable: $line";
-					system($line);
-				}
-			}
-		}
-		
+		}		
 	}else{
 		return -2;
 	}
@@ -1781,6 +1869,12 @@ sub multiline_to_startup_comma_format{
 	return $multiLineVar;
 }
 
+sub multiline_to_bash_commands{
+	my ($multiLineVar) = @_;
+	$multiLineVar =~ s/[\n]+/ && /g;
+	return $multiLineVar;
+}
+
 sub startup_comma_format_to_multiline{
 	my ($multiLineVar) = @_;
 	$multiLineVar =~ s/{OGPNEWLINE}/\n/g;
@@ -2037,7 +2131,7 @@ sub steam_cmd
 ### @return 0 In error case.
 sub steam_cmd_without_decrypt
 {
-	my ($home_id, $home_path, $mod, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock) = @_;
+	my ($home_id, $home_path, $mod, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, $arch_bits) = @_;
 	
 	if ( check_b4_chdir($home_path) != 0)
 	{
@@ -2068,6 +2162,12 @@ sub steam_cmd_without_decrypt
 	{
 		print FILE "\@sSteamCmdForcePlatformType windows\n";
 	}
+	
+	# Handle requested SteamCMD architecture
+	if(defined $arch_bits && $arch_bits ne ""){
+		print FILE "\@sSteamCmdForcePlatformBitness " . $arch_bits . "\n";
+	}
+	
 	if($guard ne '')
 	{
 		print FILE "set_steam_guard_code $guard\n";
@@ -2162,7 +2262,7 @@ sub automatic_steam_update
 	my ($home_id, $game_home, $server_ip, $server_port, $exec_path, $exec_folder_path,
 		$control_protocol, $control_password, $control_type,
 		$appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $precmd, $postcmd, $cfg_os, $filesToLockUnlock,
-		$startup_cmd, $cpu, $nice, $preStart, $envVars) = &decrypt_params(@_);
+		$startup_cmd, $cpu, $nice, $preStart, $envVars, $game_key, $arch_bits) = &decrypt_params(@_);
 
 	# Is the server currently running? if it is, we'll try to start it after updating.
 	my $isServerRunning = is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1 ? 1 : 0;
@@ -2188,7 +2288,7 @@ sub automatic_steam_update
 	}
 
 	# steam_cmd: Returns 0 if the update failed, in which case, don't try starting the server - because we may have an incomplete or corrupt installation.
-	if (steam_cmd_without_decrypt($home_id, $game_home, $appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock) == 0)
+	if (steam_cmd_without_decrypt($home_id, $game_home, $appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, $arch_bits) == 0)
 	{
 		logger("Failed to start steam_cmd for server $home_id.");
 		return -8;
@@ -2203,7 +2303,7 @@ sub automatic_steam_update
 				if (is_screen_running_without_decrypt(SCREEN_TYPE_UPDATE, $home_id) == 0)
 				{
 
-					if (universal_start_without_decrypt($home_id, $game_home, $exec_path, $exec_folder_path, $startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars) != 1)
+					if (universal_start_without_decrypt($home_id, $game_home, $exec_path, $exec_folder_path, $startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key) != 1)
 					{
 						logger("Failed to start server $home_id after automatic update.");
 						return -7;
@@ -2270,6 +2370,8 @@ sub uncompress_file
 
 sub uncompress_file_without_decrypt
 {
+	# Globals
+	$Archive::Extract::PREFER_BIN = 1;
 
 	# File must include full path.
 	my ($file, $destination) = @_;
@@ -2292,23 +2394,37 @@ sub uncompress_file_without_decrypt
 		}
 	}
 
-	my $ae = Archive::Extract->new(archive => $file);
+	my $filesize = (stat($file))[7];
+	
+	if($filesize >= 3221225472 && $file =~ /\.zip$/i){
+		# Archive::Extract seems to have problems with large zip files, so for files greater than 3GB in size, let the system handle it
+		logger "Using system call to unzip.";
+		system("unzip -o $file -d $destination");
+		if($? != 0){
+			logger "Done.";
+			return -1; 
+		}
+	}else{
 
-	if (!$ae)
-	{
-		logger "Could not create archive instance for file $file.";
-		return -1;
-	}
+		my $ae = Archive::Extract->new(archive => $file);
 
-	my $ok = $ae->extract(to => $destination);
+		if (!$ae)
+		{
+			logger "Could not create archive instance for file $file.";
+			return -1;
+		}
 
-	if (!$ok)
-	{
-		logger "File $file could not be uncompressed.";
-		return -1;
-	}
+		my $ok = $ae->extract(to => $destination);
 
-	logger "File uncompressed/extracted successfully.";
+		if (!$ok)
+		{
+			logger "File $file could not be uncompressed.";
+			return -1;
+		}
+
+		logger "File uncompressed/extracted successfully.";
+	}
+	
 	return 1;
 }
 
@@ -2608,14 +2724,14 @@ sub restart_server_without_decrypt
 {
 	my ($home_id, $server_ip, $server_port, $control_protocol,
 		$control_password, $control_type, $home_path, $server_exe, $run_dir,
-		$cmd, $cpu, $nice, $preStart, $envVars) = @_;
+		$cmd, $cpu, $nice, $preStart, $envVars, $game_key) = @_;
 
 	if (stop_server_without_decrypt($home_id, $server_ip, 
 									$server_port, $control_protocol,
 									$control_password, $control_type, $home_path) == 0)
 	{
 		if (universal_start_without_decrypt($home_id, $home_path, $server_exe, $run_dir,
-											$cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars) == 1)
+											$cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key) == 1)
 		{
 			return 1;
 		}
@@ -2641,6 +2757,7 @@ sub sudo_exec_without_decrypt
 {
 	my ($sudo_exec) = @_;
 	$sudo_exec =~ s/('+)/'"$1"'/g;
+	logger "Running the following command \"" . $sudo_exec . "\" with sudo.";
 	my $command = "echo '$SUDOPASSWD'|sudo -kS -p \"\" su -c '$sudo_exec;echo \$?' root 2>&1";
 	my @cmdret = qx($command);
 	chomp(@cmdret);
@@ -2648,8 +2765,10 @@ sub sudo_exec_without_decrypt
 	chomp($ret);
 	if ("X$ret" eq "X0")
 	{
+		logger "Command \"" . $sudo_exec . "\" was successfully run with sudo.";
 		return "1;".encode_list(@cmdret);
 	}
+	logger "Command \"" . $sudo_exec . "\" run with sudo failed with exit code $ret.";
 	return -1;
 }
 
@@ -2774,7 +2893,7 @@ sub ftp_mgr
 				return "1;".encode_list(`php-cgi -f sites_ftp_user_update.php username=\'$login\' password=\'$password\'`);
 			}
 		}
-		elsif(defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "EHCP" && -e "/etc/init.d/ehcp")
+		elsif(defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "EHCP" && (-e "/etc/init.d/ehcp" || -e "/lib/systemd/system/ehcp.service" || -e "/etc/systemd/system/ehcp.service" ))
 		{
 			use constant EHCP_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'EHCP');
 
@@ -3833,7 +3952,7 @@ sub shell_action
 	elsif($action eq 'get_tasklist')
 	{
 		my %taskList;
-		$taskList{'task'} = encode_base64(`ps -Ao user,pid,pcpu,pmem,comm,args --sort=-pcpu | head -n 30`);
+		$taskList{'task'} = encode_base64(`top -b -c -i -w512 -n2 | awk '/^top/{i++}i==2' | grep "COMMAND" -A 30`);
 		return {%taskList};
 	}
 	elsif($action eq 'get_timestamp')
@@ -3898,4 +4017,4 @@ sub remote_query
 		return encode_base64($response, "");
 	}
 	return -1;
-}
+}

+ 65 - 35
ogp_agent_run

@@ -7,38 +7,53 @@
 #
 # The ogp_agent_run script should be at the top level of the agent tree
 # Make sure we are in that directory since the script assumes this is the case
+
+#####################
+#  Important VARS   #
+#####################
+
 AGENTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-BASH_PREFS_CONF="$AGENTDIR/Cfg/bash_prefs.cfg" 
-chmod -Rf ug+rw $AGENTDIR 2>/dev/null
-if [ -d "$AGENTDIR/steamcmd" ]; then
-	chmod ug+x $AGENTDIR/steamcmd/linux32/* 2>/dev/null
-	chmod ug+x $AGENTDIR/steamcmd/*.sh 2>/dev/null
-fi
-if [ -d "$AGENTDIR/screenlogs" ]; then
-	chmod -Rf ug=rwx $AGENTDIR/screenlogs
-fi
-chmod ug+x $AGENTDIR/ogp_agent.pl 2>/dev/null
-chmod ug+x $AGENTDIR/ogp_agent_run 2>/dev/null
-chmod ug+x $AGENTDIR/agent_conf.sh 2>/dev/null
+BASH_PREFS_CONF="$AGENTDIR/Cfg/bash_prefs.cfg"
+REPONAME=OGP-Agent-Linux
+GitHubUsername="OpenGamePanel"
 
-if test `id -u` -eq 0; then
-	echo
-	echo
-	echo "************** WARNING ***************"
-	echo "Running OGP's agent as root  "
-	echo "is highly discouraged. It is generally"
-	echo "unnecessary to use root privileges to "
-	echo "execute the agent.         "
-	echo "**************************************"
-	echo
-	echo
-	timeout=10
-	while test $timeout -gt 0; do
-		echo -n "The agent will continue to launch in $timeout seconds\r"
-		timeout=`expr $timeout - 1`
-		sleep 1
-	done
-fi
+#####################
+#     FUNCTIONS     #
+#####################
+
+setupOGPDirPerms(){
+	
+	chmod -Rf ug+rw $AGENTDIR 2>/dev/null
+	if [ -d "$AGENTDIR/steamcmd" ]; then
+		chmod ug+x $AGENTDIR/steamcmd/linux32/* 2>/dev/null
+		chmod ug+x $AGENTDIR/steamcmd/*.sh 2>/dev/null
+	fi
+	if [ -d "$AGENTDIR/screenlogs" ]; then
+		chmod -Rf ug=rwx $AGENTDIR/screenlogs
+	fi
+	chmod ug+x $AGENTDIR/ogp_agent.pl 2>/dev/null
+	chmod ug+x $AGENTDIR/ogp_agent_run 2>/dev/null
+	chmod ug+x $AGENTDIR/agent_conf.sh 2>/dev/null
+
+	if test `id -u` -eq 0; then
+		echo
+		echo
+		echo "************** WARNING ***************"
+		echo "Running OGP's agent as root  "
+		echo "is highly discouraged. It is generally"
+		echo "unnecessary to use root privileges to "
+		echo "execute the agent.         "
+		echo "**************************************"
+		echo
+		echo
+		timeout=10
+		while test $timeout -gt 0; do
+			echo -n "The agent will continue to launch in $timeout seconds\r"
+			timeout=`expr $timeout - 1`
+			sleep 1
+		done
+	fi
+}
 
 ogpGitCleanup(){
 	echo "Cleaning up..."
@@ -121,6 +136,15 @@ init() {
 		then
 			AUTO_UPDATE="yes"
 		fi
+		
+		# Use custom github update address
+		if [ ! -z "$github_update_username" ]; then
+			REVISIONTest=`curl -s https://github.com/${github_update_username}/${REPONAME}/commits/master.atom | egrep -o "([a-f0-9]{40})" | awk 'NR==1{print $1}'`
+			if [ ! -z "$REVISIONTest" ]; then
+				GitHubUsername=${github_update_username}
+			fi
+		fi
+		
 	else
 		AUTO_UPDATE="yes"
 	fi
@@ -182,9 +206,8 @@ update() {
 				mkdir tmp
 			fi
 			cd tmp
-			REPONAME=OGP-Agent-Linux
-			REVISION=`curl -s https://github.com/OpenGamePanel/${REPONAME}/commits/master.atom | egrep -o "([a-f0-9]{40})" | awk 'NR==1{print $1}'`
-			curl -Os https://raw.githubusercontent.com/OpenGamePanel/${REPONAME}/${REVISION}/ogp_agent_run
+			REVISION=`curl -s https://github.com/${GitHubUsername}/${REPONAME}/commits/master.atom | egrep -o "([a-f0-9]{40})" | awk 'NR==1{print $1}'`
+			curl -Os https://raw.githubusercontent.com/${GitHubUsername}/${REPONAME}/${REVISION}/ogp_agent_run
 			currentOGPAgentRunContent=$(cat "./ogp_agent_run")
 			# Check to make sure ogp_agent_run downloaded successfully from GitHub before we attempt to replace it.
 			# This should fix random 404 people have been experiencing
@@ -207,7 +230,7 @@ update() {
 			if [ "$CURRENT" == "$REVISION" ]; then
 				echo "The agent is up to date."
 			else
-				URL=https://github.com/OpenGamePanel/${REPONAME}/archive/${REVISION}.zip
+				URL=https://github.com/${GitHubUsername}/${REPONAME}/archive/${REVISION}.zip
 				HEAD=$(curl -L -s --head -w "%{http_code}" "$URL" -o "ogp_agent_latest.zip")
 				if [ "$HEAD" == "200" ]; then
 					echo "Updating agent using curl."
@@ -221,7 +244,7 @@ update() {
 							ogpGitCleanup
 						else
 							cd ${REPONAME}-${REVISION}
-							cp -avf systemd Schedule Time FastDownload php-query ogp_agent.pl ogp_screenrc ogp_agent_run agent_conf.sh $AGENTDIR &> /dev/null
+							cp -avf systemd ArmaBE Schedule Time FastDownload php-query ogp_agent.pl ogp_screenrc ogp_agent_run agent_conf.sh $AGENTDIR &> /dev/null
 							if test $? -ne 0; then
 								echo "`date`: The agent files cannot be overwritten."
 								cd ..
@@ -311,6 +334,13 @@ quit() {
 	kill -2 $$
 }
 
+#####################
+#   MAIN APP CODE   #
+#####################
+
+# Setup OGP and Read Preferences
+setupOGPDirPerms
+
 # Initialise
 init $*
 

+ 31 - 15
php-query/lgsl/lgsl_protocol.php

@@ -25,14 +25,14 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"aarmy"			=> "Americas Army",
 		"aarmy3"		=> "Americas Army 3",
 		"arcasimracing"	=> "Arca Sim Racing",
-		"arkse"         => "Ark Survival Evolved",
+		"arkse"			=> "ARK: Survival Evolved",
 		"arma"			=> "ArmA: Armed Assault",
 		"arma2"			=> "ArmA 2",
 		"arma2oa"		=> "ArmA 2 Operation Arrowhead",
 		"arma2co"		=> "ArmA 2 Combined Operations",
 		"arma3"			=> "ArmA 3",
 		"arma3alpha"	=> "ArmA 3 Alpha",
-		"avorion"	=> "Avorion",
+		"avorion"		=> "Avorion",
 		"avp2"			=> "Aliens VS. Predator 2",
 		"avp2010"		=> "Aliens VS. Predator ( 2010 By Rebellion )",
 		"bfbc2"			=> "Battlefield Bad Company 2",
@@ -48,11 +48,12 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"callofduty4"	=> "Call Of Duty 4",
 		"callofdutymw2"	=> "Call of Duty Modern Warfare 2",
 		"cncrenegade"	=> "Command and Conquer: Renegade",
+		"conanexiles"	=> "Conan Exiles",
 		"crysis"		=> "Crysis",
 		"crysiswars"	=> "Crysis Wars",
 		"cs2d"			=> "Counter-Strike 2D",
 		"cube"			=> "Cube Engine",
-		"dayz_arma2co"	=> "Dayz ArmA 2 Combined Operations",
+		"dayzmod"          => "DayZ Mod",
 		"doomskulltag"	=> "Doom - Skulltag",
 		"doomzdaemon"	=> "Doom - ZDaemon",
 		"doom3"			=> "Doom 3",
@@ -108,9 +109,11 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"quake4"		=> "Quake 4",
 		"ravenshield"	=> "Raven Shield",
 		"redorchestra"	=> "Red Orchestra",
-		"redorchestra2" => "Red Orchestra 2 & Rising Storm",
+		"redorchestra2"	=> "Red Orchestra 2 & Rising Storm",
 		"rfactor"		=> "RFactor",
+		"risingstorm2"	=> "Rising Storm 2: Vietnam",
 		"ror"			=> "Rigs of Rods",
+		"rust"			=> "Rust",
 		"samp"			=> "San Andreas Multiplayer",
 		"savage"		=> "Savage",
 		"savage2"		=> "Savage 2",
@@ -162,7 +165,7 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"aarmy_"		=> "03",
 		"aarmy3"		=> "26",
 		"arcasimracing"	=> "16",
-		"arkse"         => "05",
+		"arkse"			=> "05",
 		"arma"			=> "09",
 		"arma2"			=> "06",
 		"arma2oa"		=> "06",
@@ -185,11 +188,12 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"callofduty4"	=> "02",
 		"callofdutymw2"	=> "02",
 		"cncrenegade"	=> "03",
+		"conanexiles"	=> "05",
 		"crysis"		=> "06",
 		"crysiswars"	=> "06",
 		"cs2d"			=> "29",
 		"cube"			=> "24",
-		"dayz_arma2co"	=> "06",
+		"dayzmod"  => "05",
 		"doomskulltag"	=> "27",
 		"doomzdaemon"	=> "28",
 		"doom3"			=> "10",
@@ -250,8 +254,11 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"quake4"		=> "10",
 		"ravenshield"	=> "04",
 		"redorchestra"	=> "13",
-		"redorchestra2" => "05",
+		"redorchestra2"	=> "05",
 		"rfactor"		=> "16",
+		"risingstorm2"	=> "05",
+		"ror"			=> "36",
+		"rust"			=> "05",
 		"samp"			=> "12",
 		"savage"		=> "17",
 		"savage2"		=> "18",
@@ -284,6 +291,7 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"ut2004"		=> "13",
 		"ut2004_"		=> "03",
 		"ut3"			=> "11",
+		"vbox"			=> "38",
 		"vcmp"			=> "12",
 		"vietcong"		=> "03",
 		"vietcong2"		=> "09",
@@ -305,14 +313,14 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"aarmy"			=> "qtracker://{IP}:{S_PORT}?game=ArmyOperations&action=show",
 		"aarmy3"		=> "qtracker://{IP}:{S_PORT}?game=AmericasArmy3&action=show",
 		"arcasimracing"	=> "http://en.wikipedia.org/wiki/ARCA_Sim_Racing",
-		"arkse"         => "steam://connect/{IP}:{S_PORT}",
+		"arkse"			=> "steam://connect/{IP}:{Q_PORT}",
 		"arma"			=> "qtracker://{IP}:{S_PORT}?game=ArmedAssault&action=show",
 		"arma2"			=> "http://en.wikipedia.org/wiki/ARMA_2",
 		"arma2oa"		=> "http://en.wikipedia.org/wiki/ARMA_2",
 		"arma2co"		=> "http://en.wikipedia.org/wiki/ARMA_2",
 		"arma3"			=> "steam://connect/{IP}:{S_PORT}",
 		"arma3alpha"	=> "http://en.wikipedia.org/wiki/ARMA_2",
-		"avorion" 	=> "steam://connect/{IP}:{S_PORT}",
+		"avorion"		=> "steam://connect/{IP}:{S_PORT}",
 		"avp2"			=> "qtracker://{IP}:{S_PORT}?game=AliensversusPredator2&action=show",
 		"avp2010"		=> "http://en.wikipedia.org/wiki/Aliens_vs._Predator_%28video_game%29",
 		"bfbc2"			=> "http://en.wikipedia.org/wiki/Battlefield_bad_company_2",
@@ -328,11 +336,12 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"callofduty4"	=> "qtracker://{IP}:{S_PORT}?game=CallOfDuty4&action=show",
 		"callofdutymw2"	=> "aiw://connect/{IP}:{S_PORT}",
 		"cncrenegade"	=> "qtracker://{IP}:{S_PORT}?game=CommandConquerRenegade&action=show",
+		"conanexiles"	=> "steam://connect/{IP}:{S_PORT}",
 		"crysis"		=> "qtracker://{IP}:{S_PORT}?game=Crysis&action=show",
 		"crysiswars"	=> "qtracker://{IP}:{S_PORT}?game=CrysisWars&action=show",
 		"cs2d"			=> "http://www.cs2d.com",
 		"cube"			=> "http://cubeengine.com",
-		"dayz_arma2co"	=> "http://en.wikipedia.org/wiki/ARMA_2",
+		"dayzmod"          => "steam://connect/{IP}:{S_PORT}",
 		"doomskulltag"	=> "http://skulltag.com",
 		"doomzdaemon"	=> "http://www.zdaemon.org",
 		"doom3"			=> "qtracker://{IP}:{S_PORT}?game=Doom3&action=show",
@@ -387,9 +396,11 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		"quake4"		=> "qtracker://{IP}:{S_PORT}?game=Quake4&action=show",
 		"ravenshield"	=> "http://en.wikipedia.org/wiki/Tom_Clancy's_Rainbow_Six_3",
 		"redorchestra"	=> "steam://connect/{IP}:{C_PORT}",
-		"redorchestra2" => "steam://connect/{IP}:{S_PORT}",
+		"redorchestra2"	=> "steam://connect/{IP}:{S_PORT}",
 		"rfactor"		=> "rfactor://{IP}:{S_PORT}",
+		"risingstorm2"	=> "steam://connect/{IP}:{S_PORT}",
 		"ror"			=> "http://www.rigsofrods.com/servers/",
+		"rust"			=> "steam://connect/{IP}:{S_PORT}",
 		"samp"			=> "samp://{IP}:{C_PORT}",
 		"savage"		=> "http://en.wikipedia.org/wiki/Savage:_The_Battle_for_Newerth",
 		"savage2"		=> "http://en.wikipedia.org/wiki/Savage_2:_A_Tortured_Soul",
@@ -431,6 +442,9 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 		// SOFTWARE PORT IS THE QUERY PORT UNLESS SET
 		if (!$s_port) { $s_port = $q_port; }
 
+		// Force the SimpleXMLElement into a plain string
+		$type = (string) $type;
+
 	   // TRY USING THE STANDARD LAUNCH LINK FOR ALTERNATE PROTOCOLS IF ONE IS NOT SET
 		$type = str_replace("_", "", $type);
 
@@ -449,16 +463,18 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 			case "aarmy"			: $c_to_q = 1;		$c_def = 1716;	$q_def = 1717;	$c_to_s = 0;	break;
 			case "aarmy3"			: $c_to_q = 0;		$c_def = 8777;	$q_def = 39300;	$c_to_s = 0;	break;
 			case "arcasimracing"	: $c_to_q = -100;	$c_def = 34397;	$q_def = 34297;	$c_to_s = 0;	break;
-			case "arkse"			: $c_to_q = 0;		$c_def = 0;		$q_def = 0;		$c_to_s = 0;	break;
+			case "arkse"			: $c_to_q = 19238;	$c_def = 7777;	$q_def = 27015;	$c_to_s = 0;	break;
 			case "arma3"			: $c_to_q = 1; 		$c_def = 2302; 	$q_def = 2303; 	$c_to_s = 0; 	break;
-			case "avorion" 			: $c_to_q = 20; 	$c_def = 27000;	$q_def = 27020; $c_to_s = 0;  	break;
+			case "avorion"			: $c_to_q = 20; 	$c_def = 27000;	$q_def = 27020; $c_to_s = 0;  	break;
 			case "bfbc2"			: $c_to_q = 0;		$c_def = 19567;	$q_def = 48888;	$c_to_s = 0;	break;
 			case "bfvietnam"		: $c_to_q = 0;		$c_def = 15567;	$q_def = 23000;	$c_to_s = 0;	break;
 			case "bf1942"			: $c_to_q = 0;		$c_def = 14567;	$q_def = 23000;	$c_to_s = 0;	break;
 			case "bf2"				: $c_to_q = 13333;	$c_def = 16567;	$q_def = 29900;	$c_to_s = 0;	break;
 			case "bf3"				: $c_to_q = 22000;	$c_def = 25200;	$q_def = 47200;	$c_to_s = 0;	break;
 			case "bf2142"			: $c_to_q = 0;		$c_def = 17567;	$q_def = 29900;	$c_to_s = 0;	break;
+			case "conanexiles"		: $c_to_q = 2;		$c_def = 24000;	$q_def = 24002;	$c_to_s = 0;	break;
 			case "cube"				: $c_to_q = 1;		$c_def = 28785;	$q_def = 28786;	$c_to_s = 0;	break;
+			case "dayzmod"                     : $c_to_q = 1;	  	$c_def = 2302;  $q_def = 2303;  $c_to_s = 0;    break;
 			case "dh2005"			: $c_to_q = 0;		$c_def = 23459;	$q_def = 34567;	$c_to_s = 0;	break;
 			case "farcry"			: $c_to_q = 123;	$c_def = 49001;	$q_def = 49124;	$c_to_s = 0;	break;
 			case "flashpoint"		: $c_to_q = 1;		$c_def = 2302;	$q_def = 2303;	$c_to_s = 0;	break;
@@ -484,6 +500,7 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 			case "redorchestra"		: $c_to_q = 1;		$c_def = 7758;	$q_def = 7759;	$c_to_s = 0;	break;
 			case "redorchestra2" 	: $c_to_q = 19238; 	$c_def = 7777; 	$q_def = 27015; $c_to_s = 0;  	break;
 			case "rfactor"			: $c_to_q = -100;	$c_def = 34397;	$q_def = 34297;	$c_to_s = 0;	break;
+			case "risingstorm2"		: $c_to_q = 19238; 	$c_def = 7777; 	$q_def = 27015; $c_to_s = 0;  	break;
 			case "serioussam"		: $c_to_q = 1;		$c_def = 25600;	$q_def = 25601;	$c_to_s = 0;	break;
 			case "soldat"			: $c_to_q = 123;	$c_def = 23073;	$q_def = 23196;	$c_to_s = 0;	break;
 			case "stalker"			: $c_to_q = 2;		$c_def = 5447;	$q_def = 5445;	$c_to_s = 0;	break;
@@ -521,7 +538,6 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 	function lgsl_query_live($type, $ip, $c_port, $q_port, $s_port, $request)
 	{
 //---------------------------------------------------------+
-
 		if (preg_match("/[^0-9a-z\.\-\[\]\:]/i", $ip))
 		{
 			exit("LGSL PROBLEM: INVALID IP OR HOSTNAME");
@@ -1609,7 +1625,7 @@ if (!function_exists('lgsl_version')) { // START OF DOUBLE LOAD PROTECTION
 			if (!empty($server['e']['gsgamename'])) { $server['s']['game'] = $server['e']['gsgamename']; } // FEAR
 			if (!empty($server['e']['game_id']))	{ $server['s']['game'] = $server['e']['game_id']; }	// BFVIETNAM
 
-			if ($server['b']['type'] == "arma" || $server['b']['type'] == "arma2" || $server['b']['type'] == "arma2oa" || $server['b']['type'] == "arma2co" || $server['b']['type'] == "dayz_arma2co")
+			if ($server['b']['type'] == "arma" || $server['b']['type'] == "arma2" || $server['b']['type'] == "arma2oa" || $server['b']['type'] == "arma2co" || $server['b']['type'] == "dayzmod")
 			{
 				$server['s']['map'] = $server['e']['mission'];
 			}