/** * @param int $Length * @throws AuthenticationException */ public function Read($Length = 1400) { // GoldSource RCON has same structure as Query $this->Socket->Read(); if ($this->Buffer->GetByte() !== SourceQuery::S2A_RCON) { return false; } $Buffer = $this->Buffer->Get(); $Trimmed = Trim($Buffer); if ($Trimmed === 'Bad rcon_password.') { throw new AuthenticationException($Trimmed, AuthenticationException::BAD_PASSWORD); } else { if ($Trimmed === 'You have been banned from this server.') { throw new AuthenticationException($Trimmed, AuthenticationException::BANNED); } } $ReadMore = false; // There is no indentifier of the end, so we just need to continue reading // TODO: Needs to be looked again, it causes timeouts do { $this->Socket->Read(); $ReadMore = $this->Buffer->Remaining() > 0 && $this->Buffer->GetByte() === SourceQuery::S2A_RCON; if ($ReadMore) { $Packet = $this->Buffer->Get(); $Buffer .= SubStr($Packet, 0, -2); // Let's assume if this packet is not long enough, there are no more after this one $ReadMore = StrLen($Packet) > 1000; // use 1300? } } while ($ReadMore); $this->Buffer->Set(Trim($Buffer)); }
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 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)); } }
public function Read($Length = 1400) { switch ($this->Socket->Engine) { case CI_SourceQuery::GOLDSOURCE: // GoldSource RCON has same structure as Query $this->Socket->Read(); if ($this->Buffer->GetByte() != SourceQuery::S2A_RCON) { return false; } $Buffer = $this->Buffer->Get(); $Trimmed = Trim($Buffer); if ($Trimmed == 'Bad rcon_password.' || $Trimmed == 'You have been banned from this server.') { throw new SourceQueryException($Trimmed); } $ReadMore = false; // There is no indentifier of the end, so we just need to continue reading // TODO: Needs to be looked again, it causes timeouts do { $this->Socket->Read(); $ReadMore = $this->Buffer->Remaining() > 0 && $this->Buffer->GetByte() == SourceQuery::S2A_RCON; if ($ReadMore) { $Packet = $this->Buffer->Get(); $Buffer .= SubStr($Packet, 0, -2); // Let's assume if this packet is not long enough, there are no more after this one $ReadMore = StrLen($Packet) > 1000; // use 1300? } } while ($ReadMore); $this->Buffer->Set(Trim($Buffer)); break; case CI_SourceQuery::SOURCE: $this->Buffer->Set(FRead($this->RconSocket, $Length)); $Buffer = ""; $PacketSize = $this->Buffer->GetLong(); $Buffer .= $this->Buffer->Get(); // TODO: multi packet reading $this->Buffer->Set($Buffer); break; } }
/** * 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) . ')'); } }
/** * 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); } }