|
1 #include "rconsession.h" |
|
2 |
|
3 // ------------------------------------------------------------------------------------------------- |
|
4 // |
|
5 RCONSession::RCONSession() : |
|
6 m_state (RCON_DISCONNECTED), |
|
7 m_lastPing (0) |
|
8 { |
|
9 if (not m_socket.set_blocking (false)) |
|
10 { |
|
11 // TODO: find a better way to deal with errors |
|
12 fprintf (stderr, "unable to set socket as non-blocking: %s\n", |
|
13 m_socket.error_string().chars()); |
|
14 } |
|
15 } |
|
16 |
|
17 // ------------------------------------------------------------------------------------------------- |
|
18 // |
|
19 RCONSession::~RCONSession() {} |
|
20 |
|
21 // ------------------------------------------------------------------------------------------------- |
|
22 // |
|
23 METHOD |
|
24 RCONSession::connect (IPAddress address) -> void |
|
25 { |
|
26 m_address = address; |
|
27 m_state = RCON_CONNECTING; |
|
28 } |
|
29 |
|
30 // ------------------------------------------------------------------------------------------------- |
|
31 // |
|
32 METHOD |
|
33 RCONSession::disconnect() -> void |
|
34 { |
|
35 if (m_state == RCON_CONNECTED) |
|
36 { |
|
37 // Say goodbye to remote |
|
38 Bytestream packet; |
|
39 packet.write_byte (CLRC_DISCONNECT); |
|
40 this->send (packet); |
|
41 } |
|
42 |
|
43 m_state = RCON_DISCONNECTED; |
|
44 } |
|
45 |
|
46 // ------------------------------------------------------------------------------------------------- |
|
47 // |
|
48 METHOD |
|
49 RCONSession::send (const Bytestream& packet) -> void |
|
50 { |
|
51 m_socket.send (m_address, packet); |
|
52 } |
|
53 |
|
54 // ------------------------------------------------------------------------------------------------- |
|
55 // |
|
56 METHOD |
|
57 RCONSession::tick() -> void |
|
58 { |
|
59 time_t now; |
|
60 time (&now); |
|
61 |
|
62 if (m_lastPing < now) |
|
63 { |
|
64 if (m_state == RCON_CONNECTING) |
|
65 { |
|
66 send_hello(); |
|
67 } |
|
68 else if (m_state == RCON_AUTHENTICATING) |
|
69 { |
|
70 send_password(); |
|
71 } |
|
72 else if (m_state == RCON_CONNECTED and m_lastPing + 5 < now) |
|
73 { |
|
74 Bytestream packet; |
|
75 packet.write_byte (CLRC_PONG); |
|
76 send (packet); |
|
77 bump_last_ping(); |
|
78 } |
|
79 } |
|
80 |
|
81 for (Datagram datagram; m_socket.read (datagram);) |
|
82 handle_packet (datagram.data, datagram.from); |
|
83 } |
|
84 |
|
85 // ------------------------------------------------------------------------------------------------- |
|
86 // |
|
87 METHOD |
|
88 RCONSession::handle_packet (Bytestream& packet, const IPAddress& from) -> void |
|
89 { |
|
90 print ("Handling packet of %1 bytes\n", packet.written_length()); |
|
91 bool ok = true; |
|
92 |
|
93 while (packet.bytes_left() > 0) |
|
94 { |
|
95 print ("%1/%2 bytes left\n", packet.bytes_left(), packet.written_length()); |
|
96 int header = packet.read_byte (&ok); |
|
97 print ("recieved HEADER with %1\n", header); |
|
98 |
|
99 switch (ServerResponse (header)) |
|
100 { |
|
101 case SVRC_OLDPROTOCOL: |
|
102 fprintf (stderr, "wrong version\n"); |
|
103 m_state = RCON_DISCONNECTED; |
|
104 break; |
|
105 |
|
106 case SVRC_BANNED: |
|
107 fprintf (stderr, "you're banned\n"); |
|
108 m_state = RCON_DISCONNECTED; |
|
109 break; |
|
110 |
|
111 case SVRC_SALT: |
|
112 { |
|
113 String salt = packet.read_string(); |
|
114 m_salt = salt; |
|
115 m_state = RCON_AUTHENTICATING; |
|
116 send_password(); |
|
117 } |
|
118 break; |
|
119 |
|
120 case SVRC_LOGGEDIN: |
|
121 fprintf (stderr, "login successful\n"); |
|
122 m_state = RCON_CONNECTED; |
|
123 break; |
|
124 |
|
125 case SVRC_INVALIDPASSWORD: |
|
126 fprintf (stderr, "bad password\n"); |
|
127 m_state = RCON_DISCONNECTED; |
|
128 break; |
|
129 |
|
130 case SVRC_MESSAGE: |
|
131 { |
|
132 String message = packet.read_string(); |
|
133 print_to (stderr, "message: %1\n", message); |
|
134 } |
|
135 break; |
|
136 |
|
137 case SVRC_UPDATE: |
|
138 switch (RCONUpdateType (packet.read_byte (&ok))) |
|
139 { |
|
140 case SVRCU_PLAYERDATA: |
|
141 { |
|
142 int numplayers = packet.read_byte (&ok); |
|
143 Vector<String> players; |
|
144 |
|
145 while (numplayers--) |
|
146 players << packet.read_string (&ok); |
|
147 |
|
148 print_to (stderr, "players: %1\n", players); |
|
149 } |
|
150 break; |
|
151 |
|
152 case SVRCU_ADMINCOUNT: |
|
153 print_to (stderr, "num admins: %1\n", packet.read_byte (&ok)); |
|
154 break; |
|
155 |
|
156 case SVRCU_MAP: |
|
157 print_to (stderr, "new map: %1\n", packet.read_string (&ok)); |
|
158 break; |
|
159 } |
|
160 |
|
161 break; |
|
162 } |
|
163 |
|
164 if (not ok) |
|
165 print_to (stderr, "error while reading packet\n"); |
|
166 } |
|
167 } |
|
168 |
|
169 // ------------------------------------------------------------------------------------------------- |
|
170 // |
|
171 METHOD |
|
172 RCONSession::socket() -> UDPSocket* |
|
173 { |
|
174 return &m_socket; |
|
175 } |
|
176 |
|
177 // ------------------------------------------------------------------------------------------------- |
|
178 // |
|
179 METHOD |
|
180 RCONSession::send_hello() -> void |
|
181 { |
|
182 print ("connecting to %1...\n", m_address.to_string (IP_WITH_PORT)); |
|
183 Bytestream packet; |
|
184 packet.write_byte (CLRC_BEGINCONNECTION); |
|
185 packet.write_byte (RCON_PROTOCOL_VERSION); |
|
186 send (packet); |
|
187 bump_last_ping(); |
|
188 } |
|
189 |
|
190 // ------------------------------------------------------------------------------------------------- |
|
191 // |
|
192 METHOD |
|
193 RCONSession::send_password() -> void |
|
194 { |
|
195 print ("sending password...\n"); |
|
196 Bytestream packet; |
|
197 packet.write_byte (CLRC_PASSWORD); |
|
198 packet.write_string ((m_salt + m_password).md5()); |
|
199 send (packet); |
|
200 bump_last_ping(); |
|
201 } |
|
202 |
|
203 // ------------------------------------------------------------------------------------------------- |
|
204 // |
|
205 METHOD |
|
206 RCONSession::set_password (const String& password) -> void |
|
207 { |
|
208 m_password = password; |
|
209 } |
|
210 |
|
211 // ------------------------------------------------------------------------------------------------- |
|
212 // |
|
213 METHOD |
|
214 RCONSession::bump_last_ping() -> void |
|
215 { |
|
216 time_t now; |
|
217 time (&now); |
|
218 m_lastPing = now; |
|
219 } |