OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

network_admin.cpp
Go to the documentation of this file.
1 /* $Id: network_admin.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
9
12 #ifdef ENABLE_NETWORK
13
14 #include "../stdafx.h"
15 #include "../strings_func.h"
16 #include "../date_func.h"
17 #include "network_admin.h"
18 #include "network_base.h"
19 #include "network_server.h"
20 #include "../command_func.h"
21 #include "../company_base.h"
22 #include "../console_func.h"
23 #include "../core/pool_func.hpp"
24 #include "../map_func.h"
25 #include "../rev.h"
26 #include "../game/game.hpp"
27
28 #include "../safeguards.h"
29
30
31 /* This file handles all the admin network commands. */
32
34 AdminIndex _redirect_console_to_admin = INVALID_ADMIN_ID;
35
37 byte _network_admins_connected = 0;
38
40 NetworkAdminSocketPool _networkadminsocket_pool("NetworkAdminSocket");
41 INSTANTIATE_POOL_METHODS(NetworkAdminSocket)
42
43
44 static const int ADMIN_AUTHORISATION_TIMEOUT = 10000;
45
46
48 static const AdminUpdateFrequency _admin_update_type_frequencies[] = {
49 ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_DAILY | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY,
50 ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_AUTOMATIC,
51 ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_AUTOMATIC,
52 ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY,
53 ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY,
54 ADMIN_FREQUENCY_AUTOMATIC,
55 ADMIN_FREQUENCY_AUTOMATIC,
56 ADMIN_FREQUENCY_POLL,
57 ADMIN_FREQUENCY_AUTOMATIC,
58 ADMIN_FREQUENCY_AUTOMATIC,
59 };
61 assert_compile(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END);
62
67 ServerNetworkAdminSocketHandler::ServerNetworkAdminSocketHandler(SOCKET s) : NetworkAdminSocketHandler(s)
68 {
69 _network_admins_connected++;
70 this->status = ADMIN_STATUS_INACTIVE;
71 this->realtime_connect = _realtime_tick;
72 }
73
77 ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler()
78 {
79 _network_admins_connected--;
80 DEBUG(net, 1, "[admin] '%s' (%s) has disconnected", this->admin_name, this->admin_version);
81 if (_redirect_console_to_admin == this->index) _redirect_console_to_admin = INVALID_ADMIN_ID;
82 }
83
88 /* static */ bool ServerNetworkAdminSocketHandler::AllowConnection()
89 {
90 bool accept = !StrEmpty(_settings_client.network.admin_password) && _network_admins_connected < MAX_ADMINS;
91 /* We can't go over the MAX_ADMINS limit here. However, if we accept
92 * the connection, there has to be space in the pool. */
93 assert_compile(NetworkAdminSocketPool::MAX_SIZE == MAX_ADMINS);
94 assert(!accept || ServerNetworkAdminSocketHandler::CanAllocateItem());
95 return accept;
96 }
97
99 /* static */ void ServerNetworkAdminSocketHandler::Send()
100 {
101 ServerNetworkAdminSocketHandler *as;
102 FOR_ALL_ADMIN_SOCKETS(as) {
103 if (as->status == ADMIN_STATUS_INACTIVE && as->realtime_connect + ADMIN_AUTHORISATION_TIMEOUT < _realtime_tick) {
104 DEBUG(net, 1, "[admin] Admin did not send its authorisation within %d seconds", ADMIN_AUTHORISATION_TIMEOUT / 1000);
105 as->CloseConnection(true);
106 continue;
107 }
108 if (as->writable) {
109 as->SendPackets();
110 }
111 }
112 }
113
119 /* static */ void ServerNetworkAdminSocketHandler::AcceptConnection(SOCKET s, const NetworkAddress &address)
120 {
121 ServerNetworkAdminSocketHandler *as = new ServerNetworkAdminSocketHandler(s);
122 as->address = address; // Save the IP of the client
123 }
124
125 /***********
126 * Sending functions for admin network
127 ************/
128
133 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode error)
134 {
135 Packet *p = new Packet(ADMIN_PACKET_SERVER_ERROR);
136
137 p->Send_uint8(error);
138 this->SendPacket(p);
139
140 char str[100];
141 StringID strid = GetNetworkErrorMsg(error);
142 GetString(str, strid, lastof(str));
143
144 DEBUG(net, 1, "[admin] the admin '%s' (%s) made an error and has been disconnected. Reason: '%s'", this->admin_name, this->admin_version, str);
145
146 return this->CloseConnection(true);
147 }
148
150 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol()
151 {
152 Packet *p = new Packet(ADMIN_PACKET_SERVER_PROTOCOL);
153
154 /* announce the protocol version */
155 p->Send_uint8(NETWORK_GAME_ADMIN_VERSION);
156
157 for (int i = 0; i < ADMIN_UPDATE_END; i++) {
158 p->Send_bool (true);
159 p->Send_uint16(i);
160 p->Send_uint16(_admin_update_type_frequencies[i]);
161 }
162
163 p->Send_bool(false);
164 this->SendPacket(p);
165
166 return this->SendWelcome();
167 }
168
170 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome()
171 {
172 Packet *p = new Packet(ADMIN_PACKET_SERVER_WELCOME);
173
174 p->Send_string(_settings_client.network.server_name);
175 p->Send_string(_openttd_revision);
176 p->Send_bool (_network_dedicated);
177
178 p->Send_string(_network_game_info.map_name);
179 p->Send_uint32(_settings_game.game_creation.generation_seed);
180 p->Send_uint8 (_settings_game.game_creation.landscape);
181 p->Send_uint32(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
182 p->Send_uint16(MapSizeX());
183 p->Send_uint16(MapSizeY());
184
185 this->SendPacket(p);
186
187 return NETWORK_RECV_STATUS_OKAY;
188 }
189
191 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendNewGame()
192 {
193 Packet *p = new Packet(ADMIN_PACKET_SERVER_NEWGAME);
194 this->SendPacket(p);
195 return NETWORK_RECV_STATUS_OKAY;
196 }
197
199 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendShutdown()
200 {
201 Packet *p = new Packet(ADMIN_PACKET_SERVER_SHUTDOWN);
202 this->SendPacket(p);
203 return NETWORK_RECV_STATUS_OKAY;
204 }
205
207 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate()
208 {
209 Packet *p = new Packet(ADMIN_PACKET_SERVER_DATE);
210
211 p->Send_uint32(_date);
212 this->SendPacket(p);
213
214 return NETWORK_RECV_STATUS_OKAY;
215 }
216
221 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID client_id)
222 {
223 Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_JOIN);
224
225 p->Send_uint32(client_id);
226 this->SendPacket(p);
227
228 return NETWORK_RECV_STATUS_OKAY;
229 }
230
236 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkClientSocket *cs, const NetworkClientInfo *ci)
237 {
238 /* Only send data when we're a proper client, not just someone trying to query the server. */
239 if (ci == NULL) return NETWORK_RECV_STATUS_OKAY;
240
241 Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_INFO);
242
243 p->Send_uint32(ci->client_id);
244 p->Send_string(cs == NULL ? "" : const_cast<NetworkAddress &>(cs->client_address).GetHostname());
245 p->Send_string(ci->client_name);
246 p->Send_uint8 (ci->client_lang);
247 p->Send_uint32(ci->join_date);
248 p->Send_uint8 (ci->client_playas);
249
250 this->SendPacket(p);
251
252 return NETWORK_RECV_STATUS_OKAY;
253 }
254
255
260 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const NetworkClientInfo *ci)
261 {
262 Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_UPDATE);
263
264 p->Send_uint32(ci->client_id);
265 p->Send_string(ci->client_name);
266 p->Send_uint8 (ci->client_playas);
267
268 this->SendPacket(p);
269
270 return NETWORK_RECV_STATUS_OKAY;
271 }
272
277 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID client_id)
278 {
279 Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_QUIT);
280
281 p->Send_uint32(client_id);
282 this->SendPacket(p);
283
284 return NETWORK_RECV_STATUS_OKAY;
285 }
286
292 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID client_id, NetworkErrorCode error)
293 {
294 Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_ERROR);
295
296 p->Send_uint32(client_id);
297 p->Send_uint8 (error);
298 this->SendPacket(p);
299
300 return NETWORK_RECV_STATUS_OKAY;
301 }
302
307 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID company_id)
308 {
309 Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_NEW);
310 p->Send_uint8(company_id);
311
312 this->SendPacket(p);
313
314 return NETWORK_RECV_STATUS_OKAY;
315 }
316
321 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company *c)
322 {
323 char company_name[NETWORK_COMPANY_NAME_LENGTH];
324 char manager_name[NETWORK_COMPANY_NAME_LENGTH];
325
326 SetDParam(0, c->index);
327 GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
328
329 SetDParam(0, c->index);
330 GetString(manager_name, STR_PRESIDENT_NAME, lastof(manager_name));
331
332 Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_INFO);
333
334 p->Send_uint8 (c->index);
335 p->Send_string(company_name);
336 p->Send_string(manager_name);
337 p->Send_uint8 (c->colour);
338 p->Send_bool (NetworkCompanyIsPassworded(c->index));
339 p->Send_uint32(c->inaugurated_year);
340 p->Send_bool (c->is_ai);
341 p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy
342
343 for (size_t i = 0; i < lengthof(c->share_owners); i++) {
344 p->Send_uint8(c->share_owners[i]);
345 }
346
347 this->SendPacket(p);
348
349 return NETWORK_RECV_STATUS_OKAY;
350 }
351
352
357 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company *c)
358 {
359 char company_name[NETWORK_COMPANY_NAME_LENGTH];
360 char manager_name[NETWORK_COMPANY_NAME_LENGTH];
361
362 SetDParam(0, c->index);
363 GetString(company_name, STR_COMPANY_NAME, lastof(company_name));
364
365 SetDParam(0, c->index);
366 GetString(manager_name, STR_PRESIDENT_NAME, lastof(manager_name));
367
368 Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_UPDATE);
369
370 p->Send_uint8 (c->index);
371 p->Send_string(company_name);
372 p->Send_string(manager_name);
373 p->Send_uint8 (c->colour);
374 p->Send_bool (NetworkCompanyIsPassworded(c->index));
375 p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy
376
377 for (size_t i = 0; i < lengthof(c->share_owners); i++) {
378 p->Send_uint8(c->share_owners[i]);
379 }
380
381 this->SendPacket(p);
382
383 return NETWORK_RECV_STATUS_OKAY;
384 }
385
391 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason acrr)
392 {
393 Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_REMOVE);
394
395 p->Send_uint8(company_id);
396 p->Send_uint8(acrr);
397
398 this->SendPacket(p);
399
400 return NETWORK_RECV_STATUS_OKAY;
401 }
402
404 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyEconomy()
405 {
406 const Company *company;
407 FOR_ALL_COMPANIES(company) {
408 /* Get the income. */
409 Money income = 0;
410 for (uint i = 0; i < lengthof(company->yearly_expenses[0]); i++) {
411 income -= company->yearly_expenses[0][i];
412 }
413
414 Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_ECONOMY);
415
416 p->Send_uint8(company->index);
417
418 /* Current information. */
419 p->Send_uint64(company->money);
420 p->Send_uint64(company->current_loan);
421 p->Send_uint64(income);
422 p->Send_uint16(min(UINT16_MAX, company->cur_economy.delivered_cargo.GetSum<OverflowSafeInt64>()));
423
424 /* Send stats for the last 2 quarters. */
425 for (uint i = 0; i < 2; i++) {
426 p->Send_uint64(company->old_economy[i].company_value);
427 p->Send_uint16(company->old_economy[i].performance_history);
428 p->Send_uint16(min(UINT16_MAX, company->old_economy[i].delivered_cargo.GetSum<OverflowSafeInt64>()));
429 }
430
431 this->SendPacket(p);
432 }
433
434
435 return NETWORK_RECV_STATUS_OKAY;
436 }
437
439 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyStats()
440 {
441 /* Fetch the latest version of the stats. */
442 NetworkCompanyStats company_stats[MAX_COMPANIES];
443 NetworkPopulateCompanyStats(company_stats);
444
445 const Company *company;
446
447 /* Go through all the companies. */
448 FOR_ALL_COMPANIES(company) {
449 Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_STATS);
450
451 /* Send the information. */
452 p->Send_uint8(company->index);
453
454 for (uint i = 0; i < NETWORK_VEH_END; i++) {
455 p->Send_uint16(company_stats[company->index].num_vehicle[i]);
456 }
457
458 for (uint i = 0; i < NETWORK_VEH_END; i++) {
459 p->Send_uint16(company_stats[company->index].num_station[i]);
460 }
461
462 this->SendPacket(p);
463 }
464
465 return NETWORK_RECV_STATUS_OKAY;
466 }
467
476 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data)
477 {
478 Packet *p = new Packet(ADMIN_PACKET_SERVER_CHAT);
479
480 p->Send_uint8 (action);
481 p->Send_uint8 (desttype);
482 p->Send_uint32(client_id);
483 p->Send_string(msg);
484 p->Send_uint64(data);
485
486 this->SendPacket(p);
487 return NETWORK_RECV_STATUS_OKAY;
488 }
489
494 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const char *command)
495 {
496 Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON_END);
497
498 p->Send_string(command);
499 this->SendPacket(p);
500
501 return NETWORK_RECV_STATUS_OKAY;
502 }
503
509 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRcon(uint16 colour, const char *result)
510 {
511 Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON);
512
513 p->Send_uint16(colour);
514 p->Send_string(result);
515 this->SendPacket(p);
516
517 return NETWORK_RECV_STATUS_OKAY;
518 }
519
520 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p)
521 {
522 if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
523
524 char command[NETWORK_RCONCOMMAND_LENGTH];
525
526 p->Recv_string(command, sizeof(command));
527
528 DEBUG(net, 2, "[admin] Rcon command from '%s' (%s): '%s'", this->admin_name, this->admin_version, command);
529
530 _redirect_console_to_admin = this->index;
531 IConsoleCmdExec(command);
532 _redirect_console_to_admin = INVALID_ADMIN_ID;
533 return this->SendRconEnd(command);
534 }
535
536 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet *p)
537 {
538 if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
539
540 char json[NETWORK_GAMESCRIPT_JSON_LENGTH];
541
542 p->Recv_string(json, sizeof(json));
543
544 DEBUG(net, 2, "[admin] GameScript JSON from '%s' (%s): '%s'", this->admin_name, this->admin_version, json);
545
546 Game::NewEvent(new ScriptEventAdminPort(json));
547 return NETWORK_RECV_STATUS_OKAY;
548 }
549
550 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p)
551 {
552 if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
553
554 uint32 d1 = p->Recv_uint32();
555
556 DEBUG(net, 2, "[admin] Ping from '%s' (%s): '%d'", this->admin_name, this->admin_version, d1);
557
558 return this->SendPong(d1);
559 }
560
566 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const char *origin, const char *string)
567 {
568 /* If the length of both strings, plus the 2 '\0' terminations and 3 bytes of the packet
569 * are bigger than the MTU, just ignore the message. Better safe than sorry. It should
570 * never occur though as the longest strings are chat messages, which are still 30%
571 * smaller than SEND_MTU. */
572 if (strlen(origin) + strlen(string) + 2 + 3 >= SEND_MTU) return NETWORK_RECV_STATUS_OKAY;
573
574 Packet *p = new Packet(ADMIN_PACKET_SERVER_CONSOLE);
575
576 p->Send_string(origin);
577 p->Send_string(string);
578 this->SendPacket(p);
579
580 return NETWORK_RECV_STATUS_OKAY;
581 }
582
587 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const char *json)
588 {
589 /* At the moment we cannot transmit anything larger than MTU. So we limit
590 * the maximum amount of json data that can be sent. Account also for
591 * the trailing \0 of the string */
592 if (strlen(json) + 1 >= NETWORK_GAMESCRIPT_JSON_LENGTH) return NETWORK_RECV_STATUS_OKAY;
593
594 Packet *p = new Packet(ADMIN_PACKET_SERVER_GAMESCRIPT);
595
596 p->Send_string(json);
597 this->SendPacket(p);
598
599 return NETWORK_RECV_STATUS_OKAY;
600 }
601
603 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32 d1)
604 {
605 Packet *p = new Packet(ADMIN_PACKET_SERVER_PONG);
606
607 p->Send_uint32(d1);
608 this->SendPacket(p);
609
610 return NETWORK_RECV_STATUS_OKAY;
611 }
612
614 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames()
615 {
616 Packet *p = new Packet(ADMIN_PACKET_SERVER_CMD_NAMES);
617
618 for (uint i = 0; i < CMD_END; i++) {
619 const char *cmdname = GetCommandName(i);
620
621 /* Should SEND_MTU be exceeded, start a new packet
622 * (magic 5: 1 bool "more data" and one uint16 "command id", one
623 * byte for string '\0' termination and 1 bool "no more data" */
624 if (p->size + strlen(cmdname) + 5 >= SEND_MTU) {
625 p->Send_bool(false);
626 this->SendPacket(p);
627
628 p = new Packet(ADMIN_PACKET_SERVER_CMD_NAMES);
629 }
630
631 p->Send_bool(true);
632 p->Send_uint16(i);
633 p->Send_string(cmdname);
634 }
635
636 /* Marker to notify the end of the packet has been reached. */
637 p->Send_bool(false);
638 this->SendPacket(p);
639
640 return NETWORK_RECV_STATUS_OKAY;
641 }
642
648 NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID client_id, const CommandPacket *cp)
649 {
650 Packet *p = new Packet(ADMIN_PACKET_SERVER_CMD_LOGGING);
651
652 p->Send_uint32(client_id);
653 p->Send_uint8 (cp->company);
654 p->Send_uint16(cp->cmd & CMD_ID_MASK);
655 p->Send_uint32(cp->p1);
656 p->Send_uint32(cp->p2);
657 p->Send_uint32(cp->tile);
658 p->Send_string(cp->text);
659 p->Send_uint32(cp->frame);
660
661 this->SendPacket(p);
662
663 return NETWORK_RECV_STATUS_OKAY;
664 }
665
666 /***********
667 * Receiving functions
668 ************/
669
670 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p)
671 {
672 if (this->status != ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
673
674 char password[NETWORK_PASSWORD_LENGTH];
675 p->Recv_string(password, sizeof(password));
676
677 if (StrEmpty(_settings_client.network.admin_password) ||
678 strcmp(password, _settings_client.network.admin_password) != 0) {
679 /* Password is invalid */
680 return this->SendError(NETWORK_ERROR_WRONG_PASSWORD);
681 }
682
683 p->Recv_string(this->admin_name, sizeof(this->admin_name));
684 p->Recv_string(this->admin_version, sizeof(this->admin_version));
685
686 if (StrEmpty(this->admin_name) || StrEmpty(this->admin_version)) {
687 /* no name or version supplied */
688 return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
689 }
690
691 this->status = ADMIN_STATUS_ACTIVE;
692
693 DEBUG(net, 1, "[admin] '%s' (%s) has connected", this->admin_name, this->admin_version);
694
695 return this->SendProtocol();
696 }
697
698 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet *p)
699 {
700 /* The admin is leaving nothing else to do */
701 return this->CloseConnection();
702 }
703
704 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet *p)
705 {
706 if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
707
708 AdminUpdateType type = (AdminUpdateType)p->Recv_uint16();
709 AdminUpdateFrequency freq = (AdminUpdateFrequency)p->Recv_uint16();
710
711 if (type >= ADMIN_UPDATE_END || (_admin_update_type_frequencies[type] & freq) != freq) {
712 /* The server does not know of this UpdateType. */
713 DEBUG(net, 3, "[admin] Not supported update frequency %d (%d) from '%s' (%s).", type, freq, this->admin_name, this->admin_version);
714 return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
715 }
716
717 this->update_frequency[type] = freq;
718
719 return NETWORK_RECV_STATUS_OKAY;
720 }
721
722 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p)
723 {
724 if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
725
726 AdminUpdateType type = (AdminUpdateType)p->Recv_uint8();
727 uint32 d1 = p->Recv_uint32();
728
729 switch (type) {
730 case ADMIN_UPDATE_DATE:
731 /* The admin is requesting the current date. */
732 this->SendDate();
733 break;
734
735 case ADMIN_UPDATE_CLIENT_INFO:
736 /* The admin is requesting client info. */
737 const NetworkClientSocket *cs;
738 if (d1 == UINT32_MAX) {
739 this->SendClientInfo(NULL, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER));
740 FOR_ALL_CLIENT_SOCKETS(cs) {
741 this->SendClientInfo(cs, cs->GetInfo());
742 }
743 } else {
744 if (d1 == CLIENT_ID_SERVER) {
745 this->SendClientInfo(NULL, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER));
746 } else {
747 cs = NetworkClientSocket::GetByClientID((ClientID)d1);
748 if (cs != NULL) this->SendClientInfo(cs, cs->GetInfo());
749 }
750 }
751 break;
752
753 case ADMIN_UPDATE_COMPANY_INFO:
754 /* The admin is asking for company info. */
755 const Company *company;
756 if (d1 == UINT32_MAX) {
757 FOR_ALL_COMPANIES(company) {
758 this->SendCompanyInfo(company);
759 }
760 } else {
761 company = Company::GetIfValid(d1);
762 if (company != NULL) this->SendCompanyInfo(company);
763 }
764 break;
765
766 case ADMIN_UPDATE_COMPANY_ECONOMY:
767 /* The admin is requesting economy info. */
768 this->SendCompanyEconomy();
769 break;
770
771 case ADMIN_UPDATE_COMPANY_STATS:
772 /* the admin is requesting company stats. */
773 this->SendCompanyStats();
774 break;
775
776 case ADMIN_UPDATE_CMD_NAMES:
777 /* The admin is requesting the names of DoCommands. */
778 this->SendCmdNames();
779 break;
780
781 default:
782 /* An unsupported "poll" update type. */
783 DEBUG(net, 3, "[admin] Not supported poll %d (%d) from '%s' (%s).", type, d1, this->admin_name, this->admin_version);
784 return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
785 }
786
787 return NETWORK_RECV_STATUS_OKAY;
788 }
789
790 NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p)
791 {
792 if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
793
794 NetworkAction action = (NetworkAction)p->Recv_uint8();
795 DestType desttype = (DestType)p->Recv_uint8();
796 int dest = p->Recv_uint32();
797
798 char msg[NETWORK_CHAT_LENGTH];
799 p->Recv_string(msg, NETWORK_CHAT_LENGTH);
800
801 switch (action) {
802 case NETWORK_ACTION_CHAT:
803 case NETWORK_ACTION_CHAT_CLIENT:
804 case NETWORK_ACTION_CHAT_COMPANY:
805 case NETWORK_ACTION_SERVER_MESSAGE:
806 NetworkServerSendChat(action, desttype, dest, msg, _network_own_client_id, 0, true);
807 break;
808
809 default:
810 DEBUG(net, 3, "[admin] Invalid chat action %d from admin '%s' (%s).", action, this->admin_name, this->admin_version);
811 return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET);
812 }
813
814 return NETWORK_RECV_STATUS_OKAY;
815 }
816
817 /*
818 * Useful wrapper functions
819 */
820
826 void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client)
827 {
828 ServerNetworkAdminSocketHandler *as;
829 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
830 if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) {
831 as->SendClientInfo(cs, cs->GetInfo());
832 if (new_client) {
833 as->SendClientJoin(cs->client_id);
834 }
835 }
836 }
837 }
838
843 void NetworkAdminClientUpdate(const NetworkClientInfo *ci)
844 {
845 ServerNetworkAdminSocketHandler *as;
846 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
847 if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) {
848 as->SendClientUpdate(ci);
849 }
850 }
851 }
852
857 void NetworkAdminClientQuit(ClientID client_id)
858 {
859 ServerNetworkAdminSocketHandler *as;
860 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
861 if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) {
862 as->SendClientQuit(client_id);
863 }
864 }
865 }
866
872 void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code)
873 {
874 ServerNetworkAdminSocketHandler *as;
875 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
876 if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) {
877 as->SendClientError(client_id, error_code);
878 }
879 }
880 }
881
887 void NetworkAdminCompanyInfo(const Company *company, bool new_company)
888 {
889 if (company == NULL) {
890 DEBUG(net, 1, "[admin] Empty company given for update");
891 return;
892 }
893
894 ServerNetworkAdminSocketHandler *as;
895 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
896 if (as->update_frequency[ADMIN_UPDATE_COMPANY_INFO] != ADMIN_FREQUENCY_AUTOMATIC) continue;
897
898 as->SendCompanyInfo(company);
899 if (new_company) {
900 as->SendCompanyNew(company->index);
901 }
902 }
903 }
904
909 void NetworkAdminCompanyUpdate(const Company *company)
910 {
911 if (company == NULL) return;
912
913 ServerNetworkAdminSocketHandler *as;
914 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
915 if (as->update_frequency[ADMIN_UPDATE_COMPANY_INFO] != ADMIN_FREQUENCY_AUTOMATIC) continue;
916
917 as->SendCompanyUpdate(company);
918 }
919 }
920
926 void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr)
927 {
928 ServerNetworkAdminSocketHandler *as;
929 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
930 as->SendCompanyRemove(company_id, bcrr);
931 }
932 }
933
934
938 void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data, bool from_admin)
939 {
940 if (from_admin) return;
941
942 ServerNetworkAdminSocketHandler *as;
943 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
944 if (as->update_frequency[ADMIN_UPDATE_CHAT] & ADMIN_FREQUENCY_AUTOMATIC) {
945 as->SendChat(action, desttype, client_id, msg, data);
946 }
947 }
948 }
949
956 void NetworkServerSendAdminRcon(AdminIndex admin_index, TextColour colour_code, const char *string)
957 {
958 ServerNetworkAdminSocketHandler::Get(admin_index)->SendRcon(colour_code, string);
959 }
960
966 void NetworkAdminConsole(const char *origin, const char *string)
967 {
968 ServerNetworkAdminSocketHandler *as;
969 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
970 if (as->update_frequency[ADMIN_UPDATE_CONSOLE] & ADMIN_FREQUENCY_AUTOMATIC) {
971 as->SendConsole(origin, string);
972 }
973 }
974 }
975
980 void NetworkAdminGameScript(const char *json)
981 {
982 ServerNetworkAdminSocketHandler *as;
983 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
984 if (as->update_frequency[ADMIN_UPDATE_GAMESCRIPT] & ADMIN_FREQUENCY_AUTOMATIC) {
985 as->SendGameScript(json);
986 }
987 }
988 }
989
995 void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket *cp)
996 {
997 ClientID client_id = owner == NULL ? _network_own_client_id : owner->client_id;
998
999 ServerNetworkAdminSocketHandler *as;
1000 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
1001 if (as->update_frequency[ADMIN_UPDATE_CMD_LOGGING] & ADMIN_FREQUENCY_AUTOMATIC) {
1002 as->SendCmdLogging(client_id, cp);
1003 }
1004 }
1005 }
1006
1010 void ServerNetworkAdminSocketHandler::WelcomeAll()
1011 {
1012 ServerNetworkAdminSocketHandler *as;
1013 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
1014 as->SendWelcome();
1015 }
1016 }
1017
1022 void NetworkAdminUpdate(AdminUpdateFrequency freq)
1023 {
1024 ServerNetworkAdminSocketHandler *as;
1025 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) {
1026 for (int i = 0; i < ADMIN_UPDATE_END; i++) {
1027 if (as->update_frequency[i] & freq) {
1028 /* Update the admin for the required details */
1029 switch (i) {
1030 case ADMIN_UPDATE_DATE:
1031 as->SendDate();
1032 break;
1033
1034 case ADMIN_UPDATE_COMPANY_ECONOMY:
1035 as->SendCompanyEconomy();
1036 break;
1037
1038 case ADMIN_UPDATE_COMPANY_STATS:
1039 as->SendCompanyStats();
1040 break;
1041
1042 default: NOT_REACHED();
1043 }
1044 }
1045 }
1046 }
1047 }
1048
1049 #endif /* ENABLE_NETWORK */