public function Command($Command)
 {
     $this->Write(SourceQuery::SERVERDATA_EXECCOMMAND, $Command);
     $this->Read();
     $this->Buffer->GetLong();
     // RequestID
     $Type = $this->Buffer->GetLong();
     if ($Type === SourceQuery::SERVERDATA_AUTH_RESPONSE) {
         throw new SourceQueryException('Bad rcon_password.');
     } else {
         if ($Type !== SourceQuery::SERVERDATA_RESPONSE_VALUE) {
             return false;
         }
     }
     $Buffer = $this->Buffer->Get();
     // We do this stupid hack to handle split packets
     // See https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Multiple-packet_Responses
     if (StrLen($Buffer) >= 4000) {
         do {
             $this->Write(SourceQuery::SERVERDATA_RESPONSE_VALUE);
             $this->Read();
             $this->Buffer->GetLong();
             // RequestID
             if ($this->Buffer->GetLong() !== SourceQuery::SERVERDATA_RESPONSE_VALUE) {
                 break;
             }
             $Buffer .= $this->Buffer->Get();
         } while (false);
         // TODO: This is so broken that we don't even try to read multiple times, needs to be revised
     }
     // TODO: It should use GetString, but there are no null bytes at the end, why?
     // $Buffer = $this->Buffer->GetString( );
     return $Buffer;
 }
Example #2
0
 public function Authorize($Password)
 {
     $this->RconPassword = $Password;
     switch ($this->Socket->Engine) {
         case CI_SourceQuery::GOLDSOURCE:
             $this->Write(0, 'challenge rcon');
             $this->Socket->Read();
             if ($this->Buffer->Get(14) != 'challenge rcon') {
                 return false;
             }
             $this->RconChallenge = Trim($this->Buffer->Get());
             break;
         case CI_SourceQuery::SOURCE:
             $this->Write(CI_SourceQuery::SERVERDATA_AUTH, $Password);
             $this->Read();
             $RequestID = $this->Buffer->GetLong();
             $Type = $this->Buffer->GetLong();
             // If we receive SERVERDATA_RESPONSE_VALUE, then we need to read again
             // More info: https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Additional_Comments
             if ($Type == CI_SourceQuery::SERVERDATA_RESPONSE_VALUE) {
                 $this->Read();
                 $RequestID = $this->Buffer->GetLong();
                 $Type = $this->Buffer->GetLong();
             }
             if ($RequestID == -1 || $Type != CI_SourceQuery::SERVERDATA_AUTH_RESPONSE) {
                 throw new CI_SourceQueryException('RCON authorization failed.');
             }
             $this->RconChallenge = 1;
             break;
     }
     return true;
 }
 public function Command($Command)
 {
     $this->Write(SourceQuery::SERVERDATA_EXECCOMMAND, $Command);
     $this->Read();
     $this->Buffer->GetLong();
     // RequestID
     $Type = $this->Buffer->GetLong();
     if ($Type === SourceQuery::SERVERDATA_AUTH_RESPONSE) {
         throw new AuthenticationException('Bad rcon_password.', AuthenticationException::BAD_PASSWORD);
     } else {
         if ($Type !== SourceQuery::SERVERDATA_RESPONSE_VALUE) {
             return false;
         }
     }
     $Buffer = $this->Buffer->Get();
     // We do this stupid hack to handle split packets
     // See https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Multiple-packet_Responses
     if (StrLen($Buffer) >= 4000) {
         do {
             $this->Write(SourceQuery::SERVERDATA_RESPONSE_VALUE);
             $this->Read();
             $this->Buffer->GetLong();
             // RequestID
             if ($this->Buffer->GetLong() !== SourceQuery::SERVERDATA_RESPONSE_VALUE) {
                 break;
             }
             $Buffer2 = $this->Buffer->Get();
             if ($Buffer2 === "") {
                 break;
             }
             $Buffer .= $Buffer2;
         } while (true);
     }
     return rtrim($Buffer, "");
 }
 public function Read($Length = 1400)
 {
     $this->Buffer->Set(FRead($this->Socket, $Length));
     if ($this->Buffer->Remaining() > 0 && $this->Buffer->GetLong() == -2) {
         $Packets = array();
         $IsCompressed = false;
         $ReadMore = false;
         do {
             $RequestID = $this->Buffer->GetLong();
             switch ($this->Engine) {
                 case SourceQuery::GOLDSOURCE:
                     $PacketCountAndNumber = $this->Buffer->GetByte();
                     $PacketCount = $PacketCountAndNumber & 0xf;
                     $PacketNumber = $PacketCountAndNumber >> 4;
                     break;
                 case SourceQuery::SOURCE:
                     $IsCompressed = ($RequestID & 0x80000000) != 0;
                     $PacketCount = $this->Buffer->GetByte();
                     $PacketNumber = $this->Buffer->GetByte() + 1;
                     if ($IsCompressed) {
                         $this->Buffer->GetLong();
                         // Split size
                         $PacketChecksum = $this->Buffer->GetUnsignedLong();
                     } else {
                         $this->Buffer->GetShort();
                         // Split size
                     }
                     break;
             }
             $Packets[$PacketNumber] = $this->Buffer->Get();
             $ReadMore = $PacketCount > sizeof($Packets);
         } while ($ReadMore && $this->Sherlock($Length));
         $Buffer = Implode($Packets);
         // TODO: Test this
         if ($IsCompressed) {
             // Let's make sure this function exists, it's not included in PHP by default
             if (!Function_Exists('bzdecompress')) {
                 throw new RuntimeException('Received compressed packet, PHP doesn\'t have Bzip2 library installed, can\'t decompress.');
             }
             $Data = bzdecompress($Data);
             if (CRC32($Data) != $PacketChecksum) {
                 throw new SourceQueryException('CRC32 checksum mismatch of uncompressed packet data.');
             }
         }
         $this->Buffer->Set(SubStr($Buffer, 4));
     }
 }
Example #5
0
 public function Read($Length = 1400)
 {
     $this->Buffer->Set(FRead($this->Socket, $Length));
     if ($this->Buffer->Remaining() === 0) {
         // TODO: Should we throw an exception here?
         return;
     }
     $Header = $this->Buffer->GetLong();
     if ($Header === -1) {
         // We don't have to do anything
     } else {
         if ($Header === -2) {
             $Packets = array();
             $IsCompressed = false;
             $ReadMore = false;
             do {
                 $RequestID = $this->Buffer->GetLong();
                 switch ($this->Engine) {
                     case SourceQuery::GOLDSOURCE:
                         $PacketCountAndNumber = $this->Buffer->GetByte();
                         $PacketCount = $PacketCountAndNumber & 0xf;
                         $PacketNumber = $PacketCountAndNumber >> 4;
                         break;
                     case SourceQuery::SOURCE:
                         $IsCompressed = ($RequestID & 0x80000000) !== 0;
                         $PacketCount = $this->Buffer->GetByte();
                         $PacketNumber = $this->Buffer->GetByte() + 1;
                         if ($IsCompressed) {
                             $this->Buffer->GetLong();
                             // Split size
                             $PacketChecksum = $this->Buffer->GetUnsignedLong();
                         } else {
                             $this->Buffer->GetShort();
                             // Split size
                         }
                         break;
                 }
                 $Packets[$PacketNumber] = $this->Buffer->Get();
                 $ReadMore = $PacketCount > sizeof($Packets);
             } while ($ReadMore && $this->Sherlock($Length));
             $Buffer = Implode($Packets);
             // TODO: Test this
             if ($IsCompressed) {
                 // Let's make sure this function exists, it's not included in PHP by default
                 if (!Function_Exists('bzdecompress')) {
                     throw new RuntimeException('Received compressed packet, PHP doesn\'t have Bzip2 library installed, can\'t decompress.');
                 }
                 $Buffer = bzdecompress($Buffer);
                 if (CRC32($Buffer) !== $PacketChecksum) {
                     throw new InvalidPacketException('CRC32 checksum mismatch of uncompressed packet data.', InvalidPacketException::CHECKSUM_MISMATCH);
                 }
             }
             $this->Buffer->Set(SubStr($Buffer, 4));
         } else {
             throw new InvalidPacketException('Socket read: Raw packet header mismatch. (0x' . DecHex($Header) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH);
         }
     }
 }
 public function Authorize($Password)
 {
     $this->RconPassword = $Password;
     $this->Write(0, 'challenge rcon');
     $this->Socket->Read();
     if ($this->Buffer->Get(14) !== 'challenge rcon') {
         return false;
     }
     $this->RconChallenge = Trim($this->Buffer->Get());
     return true;
 }
 /**
  * Get challenge (used for players/rules packets)
  *
  * @return bool True if all went well, false if server uses old GoldSource protocol, and it already contains answer
  */
 private function GetChallenge($Header, $ExpectedResult)
 {
     if ($this->Challenge) {
         return self::GETCHALLENGE_ALL_CLEAR;
     }
     $this->Socket->Write($Header, 0xffffffff);
     $this->Socket->Read();
     $Type = $this->Buffer->GetByte();
     switch ($Type) {
         case self::S2A_CHALLENGE:
             $this->Challenge = $this->Buffer->Get(4);
             return self::GETCHALLENGE_ALL_CLEAR;
         case $ExpectedResult:
             // Goldsource (HLTV)
             return self::GETCHALLENGE_CONTAINS_ANSWER;
         case 0:
             return self::GETCHALLENGE_FAILED;
         default:
             throw new SourceQueryException('GetChallenge: Packet header mismatch. (0x' . DecHex($Type) . ')');
     }
 }
Example #8
0
 /**
  * Get challenge (used for players/rules packets)
  *
  * @param $Header
  * @param $ExpectedResult
  * @throws InvalidPacketException
  * @return bool True if all went well, false if server uses old GoldSource protocol, and it already contains answer
  */
 private function GetChallenge($Header, $ExpectedResult)
 {
     if ($this->Challenge) {
         return self::GETCHALLENGE_ALL_CLEAR;
     }
     if ($this->UseOldGetChallengeMethod) {
         $Header = self::A2S_SERVERQUERY_GETCHALLENGE;
     }
     $this->Socket->Write($Header, 0xffffffff);
     $this->Socket->Read();
     $Type = $this->Buffer->GetByte();
     switch ($Type) {
         case self::S2A_CHALLENGE:
             $this->Challenge = $this->Buffer->Get(4);
             return self::GETCHALLENGE_ALL_CLEAR;
         case $ExpectedResult:
             // Goldsource (HLTV)
             return self::GETCHALLENGE_CONTAINS_ANSWER;
         case 0:
             return self::GETCHALLENGE_FAILED;
         default:
             throw new InvalidPacketException('GetChallenge: Packet header mismatch. (0x' . DecHex($Type) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH);
     }
 }