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); |