sources/network/rconsession.cpp

branch
protocol5
changeset 159
970d58a01e8b
parent 153
82aac80a2f1d
parent 158
de7574d292ad
child 160
cf514fa0f1cc
equal deleted inserted replaced
155:9f71f854474a 159:970d58a01e8b
34 BEGIN_ZFC_NAMESPACE 34 BEGIN_ZFC_NAMESPACE
35 35
36 // ------------------------------------------------------------------------------------------------- 36 // -------------------------------------------------------------------------------------------------
37 // 37 //
38 RCONSession::RCONSession() : 38 RCONSession::RCONSession() :
39 m_state (RCON_DISCONNECTED), 39 m_state(RCON_DISCONNECTED),
40 m_lastPing (0), 40 m_lastPing(0),
41 m_numAdmins (0), 41 m_adminCount(0),
42 m_interface (nullptr) 42 m_interface(nullptr)
43 { 43 {
44 if (not m_socket.set_blocking (false)) 44 if (not m_socket.set_blocking(false))
45 { 45 {
46 fprintf (stderr, "unable to set socket as non-blocking: %s\n", 46 fprintf(stderr, "unable to set socket as non-blocking: %s\n",
47 m_socket.error_string().chars()); 47 m_socket.error_string().chars());
48 exit (EXIT_FAILURE); 48 exit(EXIT_FAILURE);
49 } 49 }
50 } 50 }
51 51
52 // ------------------------------------------------------------------------------------------------- 52 // -------------------------------------------------------------------------------------------------
53 // 53 //
54 RCONSession::~RCONSession() {} 54 RCONSession::~RCONSession() {}
55 55
56 // ------------------------------------------------------------------------------------------------- 56 // -------------------------------------------------------------------------------------------------
57 // 57 //
58 void RCONSession::connect (IPAddress address) 58 void RCONSession::connect(IPAddress address)
59 { 59 {
60 m_address = address; 60 m_address = address;
61 m_state = RCON_CONNECTING; 61 m_state = RCON_CONNECTING;
62 m_interface->updateStatusBar(); 62 m_interface->updateStatusBar();
63 send_hello(); 63 sendHello();
64 } 64 }
65 65
66 // ------------------------------------------------------------------------------------------------- 66 // -------------------------------------------------------------------------------------------------
67 // 67 //
68 void RCONSession::disconnect() 68 void RCONSession::disconnect()
69 { 69 {
70 if (m_state > RCON_CONNECTING) 70 if (m_state > RCON_CONNECTING)
71 { 71 {
72 // Say goodbye to remote 72 // Say goodbye to remote
73 Bytestream packet; 73 send({CLRC_DISCONNECT});
74 packet.write_byte (CLRC_DISCONNECT);
75 this->send (packet);
76 m_interface->disconnected(); 74 m_interface->disconnected();
77 } 75 }
78 76
79 m_state = RCON_DISCONNECTED; 77 m_state = RCON_DISCONNECTED;
80 } 78 }
81 79
82 // ------------------------------------------------------------------------------------------------- 80 // -------------------------------------------------------------------------------------------------
83 // 81 //
84 void RCONSession::send (const Bytestream& packet) 82 void RCONSession::send(const ByteArray& packet)
85 { 83 {
86 m_socket.send (m_address, packet); 84 m_socket.send(m_address, packet);
87 } 85 }
88 86
89 // ------------------------------------------------------------------------------------------------- 87 // -------------------------------------------------------------------------------------------------
90 // 88 //
91 void RCONSession::tick() 89 void RCONSession::tick()
92 { 90 {
93 if (m_state == RCON_DISCONNECTED) 91 if (m_state == RCON_DISCONNECTED)
94 return; 92 return;
95 93
96 time_t now; 94 time_t now;
97 time (&now); 95 time(&now);
98 96
99 if (m_lastPing < now) 97 if (m_lastPing < now)
100 { 98 {
101 if (m_state == RCON_CONNECTING) 99 if (m_state == RCON_CONNECTING)
102 { 100 {
103 send_hello(); 101 sendHello();
104 } 102 }
105 else if (m_state == RCON_AUTHENTICATING) 103 else if (m_state == RCON_AUTHENTICATING)
106 { 104 {
107 send_password(); 105 sendPassword();
108 } 106 }
109 else if (m_state == RCON_CONNECTED and m_lastPing + 5 < now) 107 else if (m_state == RCON_CONNECTED and m_lastPing + 5 < now)
110 { 108 {
111 Bytestream packet; 109 send({CLRC_PONG});
112 packet.write_byte (CLRC_PONG); 110 bumpLastPing();
113 send (packet);
114 bump_last_ping();
115 } 111 }
116 } 112 }
117 113
118 for (Datagram datagram; m_socket.read (datagram);) 114 for (Datagram datagram; m_socket.read(datagram);)
119 handle_packet (datagram); 115 handlePacket(datagram);
120 } 116 }
121 117
122 // ------------------------------------------------------------------------------------------------- 118 // -------------------------------------------------------------------------------------------------
123 // 119 //
124 void RCONSession::handle_packet (Datagram& datagram) 120 void RCONSession::handlePacket(Datagram& datagram)
125 { 121 {
126 if (datagram.address != m_address) 122 if (datagram.address != m_address)
127 return; 123 return;
124
125 Bytestream stream(datagram.message);
128 126
129 try 127 try
130 { 128 {
131 int32_t header = datagram.message.read_long(); 129 int32_t header = datagram.message.read_long();
132 int32_t sequenceNumber = (header != 0) ? datagram.message.read_long() : 0; 130 int32_t sequenceNumber = (header != 0) ? datagram.message.read_long() : 0;
133 m_interface->print("Recieved packet with header 0x%x and sequence number #%d\n", header, sequenceNumber); 131 m_interface->print("Recieved packet with header 0x%x and sequence number #%d\n", header, sequenceNumber);
134 132
135 while (datagram.message.bytes_left() > 0) 133 while (datagram.message.bytes_left() > 0)
136 { 134 {
137 int header = datagram.message.read_byte(); 135 int header = stream.readByte();
138 136
139 switch (ServerResponse (header)) 137 switch (ServerResponse(header))
140 { 138 {
141 case SVRC_OLDPROTOCOL: 139 case SVRC_OLDPROTOCOL:
142 m_interface->printError ("Your RCON client is using outdated protocol.\n"); 140 m_interface->printError("Your RCON client is using outdated protocol.\n");
143 m_state = RCON_DISCONNECTED; 141 m_state = RCON_DISCONNECTED;
144 break; 142 break;
145 143
146 case SVRC_BANNED: 144 case SVRC_BANNED:
147 m_interface->printError ("You have been banned from the server.\n"); 145 m_interface->printError("You have been banned from the server.\n");
148 m_state = RCON_DISCONNECTED; 146 m_state = RCON_DISCONNECTED;
149 break; 147 break;
150 148
151 case SVRC_SALT: 149 case SVRC_SALT:
152 m_salt = datagram.message.read_string(); 150 m_salt = stream.readString();
153 m_state = RCON_AUTHENTICATING; 151 m_state = RCON_AUTHENTICATING;
154 send_password(); 152 sendPassword();
155 break; 153 break;
156 154
157 case SVRC_INVALIDPASSWORD: 155 case SVRC_INVALIDPASSWORD:
158 m_interface->printError ("Login failed.\n"); 156 m_interface->printError("Login failed.\n");
159 m_state = RCON_DISCONNECTED; 157 m_state = RCON_DISCONNECTED;
160 break; 158 break;
161 159
162 case SVRC_MESSAGE: 160 case SVRC_MESSAGE:
163 { 161 {
164 String message = datagram.message.read_string(); 162 String message = stream.readString();
165 message.normalize(); 163 message.normalize();
166 m_interface->printText ("%s\n", message.chars()); 164 m_interface->printText("%s\n", message.chars());
167 } 165 }
168 break; 166 break;
169 167
170 case SVRC_LOGGEDIN: 168 case SVRC_LOGGEDIN:
171 m_interface->print ("Login successful!\n"); 169 m_interface->print("Login successful!\n");
172 m_serverProtocol = datagram.message.read_byte(); 170 m_serverProtocol = stream.readByte();
173 m_hostname = datagram.message.read_string(); 171 m_hostname = stream.readString();
174 m_interface->setTitle (m_hostname); 172 m_interface->setTitle(m_hostname);
175 m_state = RCON_CONNECTED; 173 m_state = RCON_CONNECTED;
176 174
177 for (int i = datagram.message.read_byte(); i > 0; --i) 175 for (int i = stream.readByte(); i > 0; --i)
178 process_server_updates (datagram.message); 176 processServerUpdates(stream);
179 177
180 m_interface->print ("Previous messages:\n"); 178 m_interface->print("Previous messages:\n");
181 179
182 for (int i = datagram.message.read_byte(); i > 0; --i) 180 for (int i = stream.readByte(); i > 0; --i)
183 { 181 {
184 String message = datagram.message.read_string(); 182 String message = stream.readString();
185 message.normalize(); 183 message.normalize();
186 m_interface->printText ("--- %s\n", message.chars()); 184 m_interface->printText("--- %s\n", message.chars());
187 } 185 }
188 186
189 m_interface->print ("End of previous messages.\n"); 187 m_interface->print("End of previous messages.\n");
190 188
191 // Watch sv_hostname so that we can update the titlebar when it changes. 189 // Watch sv_hostname so that we can update the titlebar when it changes.
192 request_watch("sv_hostname"); 190 request_watch("sv_hostname");
193 m_interface->print ("Watch requested.\n"); 191 m_interface->print ("Watch requested.\n");
194 break; 192 break;
195 193
196 case SVRC_UPDATE: 194 case SVRC_UPDATE:
197 process_server_updates (datagram.message); 195 processServerUpdates(stream);
198 break; 196 break;
199 197
200 case SVRC_TOOMANYTABCOMPLETES: 198 case SVRC_TOOMANYTABCOMPLETES:
201 { 199 {
202 unsigned int numCompletions = datagram.message.read_short(); 200 unsigned int numCompletions = stream.readShort();
203 m_interface->print ("%d completions for '%s'.\n", 201 m_interface->print("%d completions for '%s'.\n",
204 int (numCompletions), m_lastTabComplete.chars()); 202 int(numCompletions), m_lastTabComplete.chars());
205 } 203 }
206 break; 204 break;
207 205
208 case SVRC_TABCOMPLETE: 206 case SVRC_TABCOMPLETE:
209 { 207 {
210 StringList completes; 208 StringList completes;
211 completes.resize(datagram.message.read_byte()); 209 completes.resize(stream.readByte());
212 210
213 for (String& completion : completes) 211 for (String& completion : completes)
214 completion = datagram.message.read_string(); 212 completion = stream.readString();
215 213
216 if (completes.size() == 1) 214 if (completes.size() == 1)
217 { 215 {
218 m_interface->tabComplete (m_lastTabComplete, completes[0]); 216 m_interface->tabComplete(m_lastTabComplete, completes[0]);
219 } 217 }
220 else if (not completes.is_empty()) 218 else if (not completes.is_empty())
221 { 219 {
222 m_interface->print ("Completions for '%s':\n", m_lastTabComplete.chars()); 220 m_interface->print("Completions for '%s':\n", m_lastTabComplete.chars());
223 221
224 for (int i : range(0, completes.size(), 8)) 222 for (int i : range(0, completes.size(), 8))
225 { 223 {
226 Range<int> spliceRange (i, min (i + 8, completes.size())); 224 Range<int> spliceRange(i, min(i + 8, completes.size()));
227 StringList splice (completes.splice (spliceRange)); 225 StringList splice(completes.splice(spliceRange));
228 m_interface->print ("- %s\n", splice.join (", ").chars()); 226 m_interface->print("- %s\n", splice.join(", ").chars());
229 } 227 }
230 } 228 }
231 } 229 }
232 break; 230 break;
233 231
267 } 265 }
268 } 266 }
269 } 267 }
270 catch (std::exception& e) 268 catch (std::exception& e)
271 { 269 {
272 m_interface->printWarning ("Couldn't process packet: %s\n", e.what()); 270 m_interface->printWarning("Couldn't process packet: %s\n", e.what());
273 } 271 }
274 } 272 }
275 273
276 void RCONSession::process_server_updates (Bytestream& packet) 274 void RCONSession::processServerUpdates(Bytestream& packet)
277 { 275 {
278 int header = packet.read_byte(); 276 int header = packet.readByte();
279 277
280 switch (RCONUpdateType (header)) 278 switch (RCONUpdateType(header))
281 { 279 {
282 case SVRCU_PLAYERDATA: 280 case SVRCU_PLAYERDATA:
283 { 281 {
284 StringList players; 282 StringList players;
285 283
286 for (int i = packet.read_byte(); i > 0; --i) 284 for (int i = packet.readByte(); i > 0; --i)
287 players.append (packet.read_string()); 285 players.append(packet.readString());
288 286
289 m_interface->setPlayerNames (players); 287 m_interface->setPlayerNames(players);
290 } 288 }
291 break; 289 break;
292 290
293 case SVRCU_ADMINCOUNT: 291 case SVRCU_ADMINCOUNT:
294 m_numAdmins = packet.read_byte(); 292 m_adminCount = packet.readByte();
295 m_interface->updateStatusBar(); 293 m_interface->updateStatusBar();
296 break; 294 break;
297 295
298 case SVRCU_MAP: 296 case SVRCU_MAP:
299 m_level = packet.read_string(); 297 m_level = packet.readString();
300 m_interface->updateStatusBar(); 298 m_interface->updateStatusBar();
301 break; 299 break;
302 300
303 default: 301 default:
304 m_interface->printWarning ("Unknown server update type: %d\n", header); 302 m_interface->printWarning("Unknown server update type: %d\n", header);
305 break; 303 break;
306 } 304 }
307 } 305 }
308 306
309 // ------------------------------------------------------------------------------------------------- 307 // -------------------------------------------------------------------------------------------------
310 // 308 //
311 UDPSocket* RCONSession::socket() 309 UDPSocket* RCONSession::getSocket()
312 { 310 {
313 return &m_socket; 311 return &m_socket;
314 } 312 }
315 313
316 // ------------------------------------------------------------------------------------------------- 314 // -------------------------------------------------------------------------------------------------
317 // 315 //
318 void RCONSession::send_hello() 316 void RCONSession::sendHello()
319 { 317 {
320 m_interface->print ("Connecting to %s...\n", 318 m_interface->print("Connecting to %s...\n", m_address.to_string(IPAddress::WITH_PORT).chars());
321 m_address.to_string (IPAddress::WITH_PORT).chars()); 319 send({CLRC_BEGINCONNECTION, RCON_PROTOCOL_VERSION});
322 Bytestream packet; 320 bumpLastPing();
323 packet.write_byte (CLRC_BEGINCONNECTION); 321 }
324 packet.write_byte (RCON_PROTOCOL_VERSION); 322
325 send (packet); 323 // -------------------------------------------------------------------------------------------------
326 bump_last_ping(); 324 //
327 } 325 void RCONSession::sendPassword()
328 326 {
329 // ------------------------------------------------------------------------------------------------- 327 m_interface->print("Authenticating...\n");
330 // 328 ByteArray message;
331 void RCONSession::send_password() 329 Bytestream stream(message);
332 { 330 stream.writeByte(CLRC_PASSWORD);
333 m_interface->print ("Authenticating...\n"); 331 stream.writeString((m_salt + m_password).md5());
334 Bytestream packet; 332 send(message);
335 packet.write_byte (CLRC_PASSWORD); 333 bumpLastPing();
336 packet.write_string ((m_salt + m_password).md5()); 334 }
337 send (packet); 335
338 bump_last_ping(); 336 // -------------------------------------------------------------------------------------------------
339 } 337 //
340 338 void RCONSession::setPassword(const String& password)
341 // -------------------------------------------------------------------------------------------------
342 //
343 void RCONSession::set_password (const String& password)
344 { 339 {
345 m_password = password; 340 m_password = password;
346 } 341 }
347 342
348 // ------------------------------------------------------------------------------------------------- 343 // -------------------------------------------------------------------------------------------------
349 // 344 //
350 void RCONSession::bump_last_ping() 345 void RCONSession::bumpLastPing()
351 { 346 {
352 time_t now; 347 time_t now;
353 time (&now); 348 time(&now);
354 m_lastPing = now; 349 m_lastPing = now;
355 } 350 }
356 351
357 // ------------------------------------------------------------------------------------------------- 352 // -------------------------------------------------------------------------------------------------
358 // 353 //
359 bool RCONSession::is_active() const 354 bool RCONSession::isActive() const
360 { 355 {
361 return state() != RCON_DISCONNECTED; 356 return getState() != RCON_DISCONNECTED;
362 } 357 }
363 358
364 // ------------------------------------------------------------------------------------------------- 359 // -------------------------------------------------------------------------------------------------
365 // Returns true if the message was successfully sent. 360 // Returns true if the message was successfully sent.
366 // 361 //
367 bool RCONSession::send_command (const String& message) 362 bool RCONSession::sendCommand(const String& commandString)
368 { 363 {
369 if (m_state != RCON_CONNECTED or message.isEmpty()) 364 if (m_state != RCON_CONNECTED or commandString.isEmpty())
370 return false; 365 return false;
371 366
372 Bytestream packet; 367 ByteArray message;
373 packet.write_byte (CLRC_COMMAND); 368 Bytestream stream(message);
374 packet.write_string (message); 369 stream.writeByte(CLRC_COMMAND);
375 send (packet); 370 stream.writeString(commandString);
376 bump_last_ping(); 371 send(message);
372 bumpLastPing();
377 return true; 373 return true;
378 } 374 }
379 375
380 // ------------------------------------------------------------------------------------------------- 376 // -------------------------------------------------------------------------------------------------
381 // 377 //
382 RCONSessionState RCONSession::state() const 378 RCONSessionState RCONSession::getState() const
383 { 379 {
384 return m_state; 380 return m_state;
385 } 381 }
386 382
387 // ------------------------------------------------------------------------------------------------- 383 // -------------------------------------------------------------------------------------------------
391 return m_address; 387 return m_address;
392 } 388 }
393 389
394 // ------------------------------------------------------------------------------------------------- 390 // -------------------------------------------------------------------------------------------------
395 // 391 //
396 int RCONSession::num_admins() const 392 int RCONSession::getAdminCount() const
397 { 393 {
398 return m_numAdmins; 394 return m_adminCount;
399 } 395 }
400 396
401 // ------------------------------------------------------------------------------------------------- 397 // -------------------------------------------------------------------------------------------------
402 // 398 //
403 const String& RCONSession::level() const 399 const String& RCONSession::getLevel() const
404 { 400 {
405 return m_level; 401 return m_level;
406 } 402 }
407 403
408 // ------------------------------------------------------------------------------------------------- 404 // -------------------------------------------------------------------------------------------------
409 // 405 //
410 void RCONSession::request_tab_complete (const String& part) 406 void RCONSession::requestTabCompletion(const String& part)
411 { 407 {
412 if (m_serverProtocol >= 4) 408 if (m_serverProtocol >= 4)
413 { 409 {
414 Bytestream packet; 410 ByteArray message;
415 packet.write_byte (CLRC_TABCOMPLETE); 411 Bytestream stream(message);
416 packet.write_string (part); 412 stream.writeByte(CLRC_TABCOMPLETE);
417 send (packet); 413 stream.writeString(part);
418 bump_last_ping(); 414 send(message);
415 bumpLastPing();
419 m_lastTabComplete = part; 416 m_lastTabComplete = part;
420 } 417 }
421 else 418 else
422 { 419 {
423 m_interface->print ("This server does not support tab-completion\n", m_serverProtocol); 420 m_interface->print("This server does not support tab-completion\n", m_serverProtocol);
424 } 421 }
425 } 422 }
426 423
427 // ------------------------------------------------------------------------------------------------- 424 // -------------------------------------------------------------------------------------------------
428 // 425 //
429 void RCONSession::set_interface (Interface* iface) 426 void RCONSession::setInterface(Interface* interface)
430 { 427 {
431 m_interface = iface; 428 m_interface = interface;
432 } 429 }
433 430
434 // ------------------------------------------------------------------------------------------------- 431 // -------------------------------------------------------------------------------------------------
435 // 432 //
436 void RCONSession::request_watch (const String& cvar) 433 void RCONSession::request_watch (const String& cvar)

mercurial