-
Notifications
You must be signed in to change notification settings - Fork 154
/
Copy pathGoldSourceRcon.php
144 lines (115 loc) · 3.25 KB
/
GoldSourceRcon.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<?php
declare(strict_types=1);
/**
* @author Pavel Djundik
*
* @link https://xpaw.me
* @link https://github.com/xPaw/PHP-Source-Query
*
* @license GNU Lesser General Public License, version 2.1
*
* @internal
*/
namespace xPaw\SourceQuery;
use xPaw\SourceQuery\Exception\AuthenticationException;
use xPaw\SourceQuery\Exception\InvalidPacketException;
use xPaw\SourceQuery\Exception\SocketException;
/**
* Class GoldSourceRcon
*/
class GoldSourceRcon extends BaseRcon
{
/**
* Points to socket class
*/
private BaseSocket $Socket;
private string $RconPassword = '';
private string $RconChallenge = '';
public function __construct( BaseSocket $Socket )
{
$this->Socket = $Socket;
}
public function Close( ) : void
{
$this->RconChallenge = '';
$this->RconPassword = '';
}
public function Open( ) : void
{
//
}
public function Write( int $Header, string $String = '' ) : bool
{
if( $this->Socket->Socket === null )
{
throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED );
}
$Command = pack( 'cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String );
$Length = strlen( $Command );
return $Length === fwrite( $this->Socket->Socket, $Command, $Length );
}
/**
* @throws AuthenticationException
*/
public function Read( ) : Buffer
{
// GoldSource RCON has same structure as Query
$Buffer = $this->Socket->Read( );
$StringBuffer = '';
$ReadMore = false;
// There is no indentifier of the end, so we just need to continue reading
do
{
$ReadMore = $Buffer->Remaining( ) > 0;
if( $ReadMore )
{
if( $Buffer->ReadByte( ) !== SourceQuery::S2A_RCON )
{
throw new InvalidPacketException( 'Invalid rcon response.', InvalidPacketException::PACKET_HEADER_MISMATCH );
}
$Packet = $Buffer->Read( );
$StringBuffer .= $Packet;
//$StringBuffer .= 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?
if( $ReadMore )
{
$Buffer = $this->Socket->Read( );
}
}
}
while( $ReadMore );
$Trimmed = trim( $StringBuffer );
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 );
}
$Buffer->Set( $Trimmed );
return $Buffer;
}
public function Command( string $Command ) : string
{
if( !$this->RconChallenge )
{
throw new AuthenticationException( 'Tried to execute a RCON command before successful authorization.', AuthenticationException::BAD_PASSWORD );
}
$this->Write( 0, 'rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0" );
$Buffer = $this->Read( );
return $Buffer->Read( );
}
public function Authorize( string $Password ) : void
{
$this->RconPassword = $Password;
$this->Write( 0, 'challenge rcon' );
$Buffer = $this->Socket->Read( );
if( $Buffer->Read( 14 ) !== 'challenge rcon' )
{
throw new AuthenticationException( 'Failed to get RCON challenge.', AuthenticationException::BAD_PASSWORD );
}
$this->RconChallenge = trim( $Buffer->Read( ) );
}
}