| 1 #include "rconsession.h" |
1 #include "rconsession.h" |
| 2 #include "../interface.h" |
2 #include "../interface.h" |
| 3 |
3 |
| 4 // ------------------------------------------------------------------------------------------------- |
4 // ------------------------------------------------------------------------------------------------- |
| 5 // |
5 // |
| 6 RCONSession::RCONSession() : |
6 RCONSession::RCONSession (Interface* iface) : |
| 7 m_state (RCON_DISCONNECTED), |
7 m_state (RCON_DISCONNECTED), |
| 8 m_lastPing (0), |
8 m_lastPing (0), |
| 9 m_numAdmins (0) |
9 m_numAdmins (0), |
| |
10 m_interface (iface) |
| 10 { |
11 { |
| 11 if (not m_socket.set_blocking (false)) |
12 if (not m_socket.set_blocking (false)) |
| 12 { |
13 { |
| 13 print_to (stderr, "unable to set socket as non-blocking: %s\n", |
14 print_to (stderr, "unable to set socket as non-blocking: %s\n", |
| 14 m_socket.error_string().chars()); |
15 m_socket.error_string().chars()); |
| 20 // |
21 // |
| 21 RCONSession::~RCONSession() {} |
22 RCONSession::~RCONSession() {} |
| 22 |
23 |
| 23 // ------------------------------------------------------------------------------------------------- |
24 // ------------------------------------------------------------------------------------------------- |
| 24 // |
25 // |
| 25 METHOD |
26 void RCONSession::connect (IPAddress address) |
| 26 RCONSession::connect (IPAddress address) -> void |
|
| 27 { |
27 { |
| 28 m_address = address; |
28 m_address = address; |
| 29 m_state = RCON_CONNECTING; |
29 m_state = RCON_CONNECTING; |
| 30 Interface::update_statusbar(); |
30 m_interface->update_statusbar(); |
| 31 send_hello(); |
31 send_hello(); |
| 32 } |
32 } |
| 33 |
33 |
| 34 // ------------------------------------------------------------------------------------------------- |
34 // ------------------------------------------------------------------------------------------------- |
| 35 // |
35 // |
| 36 METHOD |
36 void RCONSession::disconnect() |
| 37 RCONSession::disconnect() -> void |
|
| 38 { |
37 { |
| 39 if (m_state > RCON_CONNECTING) |
38 if (m_state > RCON_CONNECTING) |
| 40 { |
39 { |
| 41 // Say goodbye to remote |
40 // Say goodbye to remote |
| 42 Bytestream packet; |
41 Bytestream packet; |
| 43 packet.write_byte (CLRC_DISCONNECT); |
42 packet.write_byte (CLRC_DISCONNECT); |
| 44 this->send (packet); |
43 this->send (packet); |
| 45 print ("Disconnected from %1\n", m_address.to_string (IP_WITH_PORT)); |
44 m_interface->print ("Disconnected from %1\n", m_address.to_string (IP_WITH_PORT)); |
| 46 Interface::update_statusbar(); |
45 m_interface->update_statusbar(); |
| 47 } |
46 } |
| 48 |
47 |
| 49 m_state = RCON_DISCONNECTED; |
48 m_state = RCON_DISCONNECTED; |
| 50 } |
49 } |
| 51 |
50 |
| 52 // ------------------------------------------------------------------------------------------------- |
51 // ------------------------------------------------------------------------------------------------- |
| 53 // |
52 // |
| 54 METHOD |
53 void RCONSession::send (const Bytestream& packet) |
| 55 RCONSession::send (const Bytestream& packet) -> void |
|
| 56 { |
54 { |
| 57 m_socket.send (m_address, packet); |
55 m_socket.send (m_address, packet); |
| 58 } |
56 } |
| 59 |
57 |
| 60 // ------------------------------------------------------------------------------------------------- |
58 // ------------------------------------------------------------------------------------------------- |
| 61 // |
59 // |
| 62 METHOD |
60 void RCONSession::tick() |
| 63 RCONSession::tick() -> void |
|
| 64 { |
61 { |
| 65 if (m_state == RCON_DISCONNECTED) |
62 if (m_state == RCON_DISCONNECTED) |
| 66 return; |
63 return; |
| 67 |
64 |
| 68 time_t now; |
65 time_t now; |
| 106 int header = packet.read_byte(); |
102 int header = packet.read_byte(); |
| 107 |
103 |
| 108 switch (ServerResponse (header)) |
104 switch (ServerResponse (header)) |
| 109 { |
105 { |
| 110 case SVRC_OLDPROTOCOL: |
106 case SVRC_OLDPROTOCOL: |
| 111 print_error ("Your RCON client is using outdated protocol.\n"); |
107 m_interface->print_error ("Your RCON client is using outdated protocol.\n"); |
| 112 m_state = RCON_DISCONNECTED; |
108 m_state = RCON_DISCONNECTED; |
| 113 break; |
109 break; |
| 114 |
110 |
| 115 case SVRC_BANNED: |
111 case SVRC_BANNED: |
| 116 print_error ("You have been banned from the server.\n"); |
112 m_interface->print_error ("You have been banned from the server.\n"); |
| 117 m_state = RCON_DISCONNECTED; |
113 m_state = RCON_DISCONNECTED; |
| 118 break; |
114 break; |
| 119 |
115 |
| 120 case SVRC_SALT: |
116 case SVRC_SALT: |
| 121 m_salt = packet.read_string(); |
117 m_salt = packet.read_string(); |
| 122 m_state = RCON_AUTHENTICATING; |
118 m_state = RCON_AUTHENTICATING; |
| 123 send_password(); |
119 send_password(); |
| 124 break; |
120 break; |
| 125 |
121 |
| 126 case SVRC_INVALIDPASSWORD: |
122 case SVRC_INVALIDPASSWORD: |
| 127 print_error ("Login failed.\n"); |
123 m_interface->print_error ("Login failed.\n"); |
| 128 m_state = RCON_DISCONNECTED; |
124 m_state = RCON_DISCONNECTED; |
| 129 break; |
125 break; |
| 130 |
126 |
| 131 case SVRC_MESSAGE: |
127 case SVRC_MESSAGE: |
| 132 { |
128 { |
| 133 String message = packet.read_string(); |
129 String message = packet.read_string(); |
| 134 message.normalize(); |
130 message.normalize(); |
| 135 print ("%1\n", message); |
131 m_interface->print ("%1\n", message); |
| 136 } |
132 } |
| 137 break; |
133 break; |
| 138 |
134 |
| 139 case SVRC_LOGGEDIN: |
135 case SVRC_LOGGEDIN: |
| 140 print ("Login successful!\n"); |
136 m_interface->print ("Login successful!\n"); |
| 141 m_serverProtocol = packet.read_byte(); |
137 m_serverProtocol = packet.read_byte(); |
| 142 m_hostname = packet.read_string(); |
138 m_hostname = packet.read_string(); |
| 143 Interface::set_title (m_hostname); |
139 m_interface->set_title (m_hostname); |
| 144 m_state = RCON_CONNECTED; |
140 m_state = RCON_CONNECTED; |
| 145 |
141 |
| 146 for (int i = packet.read_byte(); i > 0; --i) |
142 for (int i = packet.read_byte(); i > 0; --i) |
| 147 process_server_updates (packet); |
143 process_server_updates (packet); |
| 148 |
144 |
| 149 print ("Previous messages:\n"); |
145 m_interface->print ("Previous messages:\n"); |
| 150 |
146 |
| 151 for (int i = packet.read_byte(); i > 0; --i) |
147 for (int i = packet.read_byte(); i > 0; --i) |
| 152 { |
148 { |
| 153 String message = packet.read_string(); |
149 String message = packet.read_string(); |
| 154 message.normalize(); |
150 message.normalize(); |
| 155 print ("--- %1\n", message); |
151 m_interface->print ("--- %1\n", message); |
| 156 } |
152 } |
| 157 |
153 |
| 158 print ("End of previous messages.\n"); |
154 m_interface->print ("End of previous messages.\n"); |
| 159 break; |
155 break; |
| 160 |
156 |
| 161 case SVRC_UPDATE: |
157 case SVRC_UPDATE: |
| 162 process_server_updates (packet); |
158 process_server_updates (packet); |
| 163 break; |
159 break; |
| 164 |
160 |
| 165 case SVRC_TOOMANYTABCOMPLETES: |
161 case SVRC_TOOMANYTABCOMPLETES: |
| 166 { |
162 { |
| 167 unsigned int numCompletions = packet.read_short(); |
163 unsigned int numCompletions = packet.read_short(); |
| 168 print ("%1 completions for '%2'.\n", |
164 m_interface->print ("%1 completions for '%2'.\n", |
| 169 int (numCompletions), m_lastTabComplete); |
165 int (numCompletions), m_lastTabComplete); |
| 170 } |
166 } |
| 171 break; |
167 break; |
| 172 |
168 |
| 173 case SVRC_TABCOMPLETE: |
169 case SVRC_TABCOMPLETE: |
| 176 |
172 |
| 177 for (signed int i = packet.read_byte(); i > 0; --i) |
173 for (signed int i = packet.read_byte(); i > 0; --i) |
| 178 completes << packet.read_string(); |
174 completes << packet.read_string(); |
| 179 |
175 |
| 180 if (completes.size() == 1) |
176 if (completes.size() == 1) |
| 181 Interface::tab_complete (m_lastTabComplete, completes[0]); |
177 { |
| |
178 m_interface->tab_complete (m_lastTabComplete, completes[0]); |
| |
179 } |
| 182 else if (not completes.is_empty()) |
180 else if (not completes.is_empty()) |
| 183 { |
181 { |
| 184 print ("Completions for '%1':\n", m_lastTabComplete); |
182 m_interface->print ("Completions for '%1':\n", m_lastTabComplete); |
| 185 |
183 |
| 186 for (int i = 0; i < completes.size(); i += 8) |
184 for (int i = 0; i < completes.size(); i += 8) |
| 187 { |
185 { |
| 188 Range<int> spliceRange (i, min (i + 8, completes.size() - 1)); |
186 Range<int> spliceRange (i, min (i + 8, completes.size() - 1)); |
| 189 StringList splice (completes.splice (spliceRange)); |
187 StringList splice (completes.splice (spliceRange)); |
| 190 print ("- %1\n", splice.join (", ")); |
188 m_interface->print ("- %1\n", splice.join (", ")); |
| 191 } |
189 } |
| 192 } |
190 } |
| 193 } |
191 } |
| 194 break; |
192 break; |
| 195 } |
193 } |
| 196 } |
194 } |
| 197 } |
195 } |
| 198 catch (std::exception& e) |
196 catch (std::exception& e) |
| 199 { |
197 { |
| 200 print_warning ("Couldn't process packet: %1\n", e.what()); |
198 m_interface->print_warning ("Couldn't process packet: %1\n", e.what()); |
| 201 } |
199 } |
| 202 } |
200 } |
| 203 |
201 |
| 204 METHOD |
202 void RCONSession::process_server_updates (Bytestream& packet) |
| 205 RCONSession::process_server_updates (Bytestream& packet) -> void |
|
| 206 { |
203 { |
| 207 int header = packet.read_byte(); |
204 int header = packet.read_byte(); |
| 208 |
205 |
| 209 switch (RCONUpdateType (header)) |
206 switch (RCONUpdateType (header)) |
| 210 { |
207 { |
| 213 StringList players; |
210 StringList players; |
| 214 |
211 |
| 215 for (int i = packet.read_byte(); i > 0; --i) |
212 for (int i = packet.read_byte(); i > 0; --i) |
| 216 players.append (packet.read_string()); |
213 players.append (packet.read_string()); |
| 217 |
214 |
| 218 Interface::set_player_names (players); |
215 m_interface->set_player_names (players); |
| 219 } |
216 } |
| 220 break; |
217 break; |
| 221 |
218 |
| 222 case SVRCU_ADMINCOUNT: |
219 case SVRCU_ADMINCOUNT: |
| 223 m_numAdmins = packet.read_byte(); |
220 m_numAdmins = packet.read_byte(); |
| 224 Interface::update_statusbar(); |
221 m_interface->update_statusbar(); |
| 225 break; |
222 break; |
| 226 |
223 |
| 227 case SVRCU_MAP: |
224 case SVRCU_MAP: |
| 228 m_level = packet.read_string(); |
225 m_level = packet.read_string(); |
| 229 Interface::update_statusbar(); |
226 m_interface->update_statusbar(); |
| 230 break; |
227 break; |
| 231 |
228 |
| 232 default: |
229 default: |
| 233 print_warning ("Unknown server update type: %d\n", header); |
230 m_interface->print_warning ("Unknown server update type: %d\n", header); |
| 234 break; |
231 break; |
| 235 } |
232 } |
| 236 } |
233 } |
| 237 |
234 |
| 238 // ------------------------------------------------------------------------------------------------- |
235 // ------------------------------------------------------------------------------------------------- |
| 239 // |
236 // |
| 240 METHOD |
237 UDPSocket* RCONSession::socket() |
| 241 RCONSession::socket() -> UDPSocket* |
|
| 242 { |
238 { |
| 243 return &m_socket; |
239 return &m_socket; |
| 244 } |
240 } |
| 245 |
241 |
| 246 // ------------------------------------------------------------------------------------------------- |
242 // ------------------------------------------------------------------------------------------------- |
| 247 // |
243 // |
| 248 METHOD |
244 void RCONSession::send_hello() |
| 249 RCONSession::send_hello() -> void |
245 { |
| 250 { |
246 m_interface->print ("Connecting to %1...\n", m_address.to_string (IP_WITH_PORT)); |
| 251 print ("Connecting to %1...\n", m_address.to_string (IP_WITH_PORT)); |
|
| 252 Bytestream packet; |
247 Bytestream packet; |
| 253 packet.write_byte (CLRC_BEGINCONNECTION); |
248 packet.write_byte (CLRC_BEGINCONNECTION); |
| 254 packet.write_byte (RCON_PROTOCOL_VERSION); |
249 packet.write_byte (RCON_PROTOCOL_VERSION); |
| 255 send (packet); |
250 send (packet); |
| 256 bump_last_ping(); |
251 bump_last_ping(); |
| 257 } |
252 } |
| 258 |
253 |
| 259 // ------------------------------------------------------------------------------------------------- |
254 // ------------------------------------------------------------------------------------------------- |
| 260 // |
255 // |
| 261 METHOD |
256 void RCONSession::send_password() |
| 262 RCONSession::send_password() -> void |
257 { |
| 263 { |
258 m_interface->print ("Authenticating...\n"); |
| 264 print ("Authenticating...\n"); |
|
| 265 Bytestream packet; |
259 Bytestream packet; |
| 266 packet.write_byte (CLRC_PASSWORD); |
260 packet.write_byte (CLRC_PASSWORD); |
| 267 packet.write_string ((m_salt + m_password).md5()); |
261 packet.write_string ((m_salt + m_password).md5()); |
| 268 send (packet); |
262 send (packet); |
| 269 bump_last_ping(); |
263 bump_last_ping(); |
| 270 } |
264 } |
| 271 |
265 |
| 272 // ------------------------------------------------------------------------------------------------- |
266 // ------------------------------------------------------------------------------------------------- |
| 273 // |
267 // |
| 274 METHOD |
268 void RCONSession::set_password (const String& password) |
| 275 RCONSession::set_password (const String& password) -> void |
|
| 276 { |
269 { |
| 277 m_password = password; |
270 m_password = password; |
| 278 } |
271 } |
| 279 |
272 |
| 280 // ------------------------------------------------------------------------------------------------- |
273 // ------------------------------------------------------------------------------------------------- |
| 281 // |
274 // |
| 282 METHOD |
275 void RCONSession::bump_last_ping() |
| 283 RCONSession::bump_last_ping() -> void |
|
| 284 { |
276 { |
| 285 time_t now; |
277 time_t now; |
| 286 time (&now); |
278 time (&now); |
| 287 m_lastPing = now; |
279 m_lastPing = now; |
| 288 } |
280 } |
| 289 |
281 |
| 290 // ------------------------------------------------------------------------------------------------- |
282 // ------------------------------------------------------------------------------------------------- |
| 291 // |
283 // |
| 292 STATIC METHOD |
284 bool RCONSession::is_active() const |
| 293 RCONSession::get_session() -> RCONSession* |
|
| 294 { |
|
| 295 static RCONSession session; |
|
| 296 return &session; |
|
| 297 } |
|
| 298 |
|
| 299 // ------------------------------------------------------------------------------------------------- |
|
| 300 // |
|
| 301 METHOD |
|
| 302 RCONSession::is_active() const -> bool |
|
| 303 { |
285 { |
| 304 return state() != RCON_DISCONNECTED; |
286 return state() != RCON_DISCONNECTED; |
| 305 } |
287 } |
| 306 |
288 |
| 307 // ------------------------------------------------------------------------------------------------- |
289 // ------------------------------------------------------------------------------------------------- |
| 308 // Returns true if the message was successfully sent. |
290 // Returns true if the message was successfully sent. |
| 309 // |
291 // |
| 310 METHOD |
292 bool RCONSession::send_command (const String& message) |
| 311 RCONSession::send_command (const String& message) -> bool |
|
| 312 { |
293 { |
| 313 if (m_state != RCON_CONNECTED or message.is_empty()) |
294 if (m_state != RCON_CONNECTED or message.is_empty()) |
| 314 return false; |
295 return false; |
| 315 |
296 |
| 316 Bytestream packet; |
297 Bytestream packet; |
| 321 return true; |
302 return true; |
| 322 } |
303 } |
| 323 |
304 |
| 324 // ------------------------------------------------------------------------------------------------- |
305 // ------------------------------------------------------------------------------------------------- |
| 325 // |
306 // |
| 326 METHOD |
307 RCONSessionState RCONSession::state() const |
| 327 RCONSession::state() const -> RCONSessionState |
|
| 328 { |
308 { |
| 329 return m_state; |
309 return m_state; |
| 330 } |
310 } |
| 331 |
311 |
| 332 // ------------------------------------------------------------------------------------------------- |
312 // ------------------------------------------------------------------------------------------------- |
| 333 // |
313 // |
| 334 METHOD |
314 const IPAddress& RCONSession::address() const |
| 335 RCONSession::address() const -> const IPAddress& |
|
| 336 { |
315 { |
| 337 return m_address; |
316 return m_address; |
| 338 } |
317 } |
| 339 |
318 |
| 340 // ------------------------------------------------------------------------------------------------- |
319 // ------------------------------------------------------------------------------------------------- |
| 341 // |
320 // |
| 342 METHOD |
321 int RCONSession::num_admins() const |
| 343 RCONSession::num_admins() const -> int |
|
| 344 { |
322 { |
| 345 return m_numAdmins; |
323 return m_numAdmins; |
| 346 } |
324 } |
| 347 |
325 |
| 348 // ------------------------------------------------------------------------------------------------- |
326 // ------------------------------------------------------------------------------------------------- |
| 349 // |
327 // |
| 350 METHOD |
328 const String& RCONSession::level() const |
| 351 RCONSession::level() const -> const String& |
|
| 352 { |
329 { |
| 353 return m_level; |
330 return m_level; |
| 354 } |
331 } |
| 355 |
332 |
| 356 // ------------------------------------------------------------------------------------------------- |
333 // ------------------------------------------------------------------------------------------------- |
| 357 // |
334 // |
| 358 METHOD |
335 void RCONSession::request_tab_complete (const String& part) |
| 359 RCONSession::request_tab_complete (const String& part) -> void |
|
| 360 { |
336 { |
| 361 if (m_serverProtocol >= 4) |
337 if (m_serverProtocol >= 4) |
| 362 { |
338 { |
| 363 Bytestream packet; |
339 Bytestream packet; |
| 364 packet.write_byte (CLRC_TABCOMPLETE); |
340 packet.write_byte (CLRC_TABCOMPLETE); |