1 /* $Id: network_admin.cpp 25845 2013-10-12 17:03:15Z planetmaker $ */
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/>.
10 /** @file network_admin.cpp Server part of the admin network protocol. */
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"
26 #include "../game/game.hpp"
28 #include "../safeguards.h"
31 /* This file handles all the admin network commands. */
33 /** Redirection of the (remote) console to the admin. */
34 AdminIndex _redirect_console_to_admin
= INVALID_ADMIN_ID
;
36 /** The amount of admins connected. */
37 byte _network_admins_connected
= 0;
39 /** The pool with sockets/clients. */
40 NetworkAdminSocketPool
_networkadminsocket_pool("NetworkAdminSocket");
41 INSTANTIATE_POOL_METHODS(NetworkAdminSocket
)
43 /** The timeout for authorisation of the client. */
44 static const int ADMIN_AUTHORISATION_TIMEOUT
= 10000;
47 /** Frequencies, which may be registered for a certain update type. */
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
, ///< ADMIN_UPDATE_DATE
50 ADMIN_FREQUENCY_POLL
| ADMIN_FREQUENCY_AUTOMATIC
, ///< ADMIN_UPDATE_CLIENT_INFO
51 ADMIN_FREQUENCY_POLL
| ADMIN_FREQUENCY_AUTOMATIC
, ///< ADMIN_UPDATE_COMPANY_INFO
52 ADMIN_FREQUENCY_POLL
| ADMIN_FREQUENCY_WEEKLY
| ADMIN_FREQUENCY_MONTHLY
| ADMIN_FREQUENCY_QUARTERLY
| ADMIN_FREQUENCY_ANUALLY
, ///< ADMIN_UPDATE_COMPANY_ECONOMY
53 ADMIN_FREQUENCY_POLL
| ADMIN_FREQUENCY_WEEKLY
| ADMIN_FREQUENCY_MONTHLY
| ADMIN_FREQUENCY_QUARTERLY
| ADMIN_FREQUENCY_ANUALLY
, ///< ADMIN_UPDATE_COMPANY_STATS
54 ADMIN_FREQUENCY_AUTOMATIC
, ///< ADMIN_UPDATE_CHAT
55 ADMIN_FREQUENCY_AUTOMATIC
, ///< ADMIN_UPDATE_CONSOLE
56 ADMIN_FREQUENCY_POLL
, ///< ADMIN_UPDATE_CMD_NAMES
57 ADMIN_FREQUENCY_AUTOMATIC
, ///< ADMIN_UPDATE_CMD_LOGGING
58 ADMIN_FREQUENCY_AUTOMATIC
, ///< ADMIN_UPDATE_GAMESCRIPT
61 assert_compile(lengthof(_admin_update_type_frequencies
) == ADMIN_UPDATE_END
);
64 * Create a new socket for the server side of the admin network.
65 * @param s The socket to connect with.
67 ServerNetworkAdminSocketHandler::ServerNetworkAdminSocketHandler(SOCKET s
) : NetworkAdminSocketHandler(s
)
69 _network_admins_connected
++;
70 this->status
= ADMIN_STATUS_INACTIVE
;
71 this->realtime_connect
= _realtime_tick
;
75 * Clear everything related to this admin.
77 ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler()
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
;
85 * Whether a connection is allowed or not at this moment.
86 * @return Whether the connection is allowed.
88 /* static */ bool ServerNetworkAdminSocketHandler::AllowConnection()
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());
98 /** Send the packets for the server sockets. */
99 /* static */ void ServerNetworkAdminSocketHandler::Send()
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);
115 * Handle the acception of a connection.
116 * @param s The socket of the new connection.
117 * @param address The address of the peer.
119 /* static */ void ServerNetworkAdminSocketHandler::AcceptConnection(SOCKET s
, const NetworkAddress
&address
)
121 ServerNetworkAdminSocketHandler
*as
= new ServerNetworkAdminSocketHandler(s
);
122 as
->address
= address
; // Save the IP of the client
126 * Sending functions for admin network
130 * Send an error to the admin.
131 * @param error The error to send.
133 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode error
)
135 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_ERROR
);
137 p
->Send_uint8(error
);
141 StringID strid
= GetNetworkErrorMsg(error
);
142 GetString(str
, strid
, lastof(str
));
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
);
146 return this->CloseConnection(true);
149 /** Send the protocol version to the admin. */
150 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendProtocol()
152 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_PROTOCOL
);
154 /* announce the protocol version */
155 p
->Send_uint8(NETWORK_GAME_ADMIN_VERSION
);
157 for (int i
= 0; i
< ADMIN_UPDATE_END
; i
++) {
160 p
->Send_uint16(_admin_update_type_frequencies
[i
]);
166 return this->SendWelcome();
169 /** Send a welcome message to the admin. */
170 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendWelcome()
172 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_WELCOME
);
174 p
->Send_string(_settings_client
.network
.server_name
);
175 p
->Send_string(_openttd_revision
);
176 p
->Send_bool (_network_dedicated
);
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());
187 return NETWORK_RECV_STATUS_OKAY
;
190 /** Tell the admin we started a new game. */
191 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendNewGame()
193 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_NEWGAME
);
195 return NETWORK_RECV_STATUS_OKAY
;
198 /** Tell the admin we're shutting down. */
199 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendShutdown()
201 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_SHUTDOWN
);
203 return NETWORK_RECV_STATUS_OKAY
;
206 /** Tell the admin the date. */
207 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendDate()
209 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_DATE
);
211 p
->Send_uint32(_date
);
214 return NETWORK_RECV_STATUS_OKAY
;
218 * Tell the admin that a client joined.
219 * @param client_id The client that joined.
221 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendClientJoin(ClientID client_id
)
223 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CLIENT_JOIN
);
225 p
->Send_uint32(client_id
);
228 return NETWORK_RECV_STATUS_OKAY
;
232 * Send an initial set of data from some client's information.
233 * @param cs The socket of the client.
234 * @param ci The information about the client.
236 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkClientSocket
*cs
, const NetworkClientInfo
*ci
)
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
;
241 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CLIENT_INFO
);
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
);
252 return NETWORK_RECV_STATUS_OKAY
;
257 * Send an update for some client's information.
258 * @param ci The information about a client.
260 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendClientUpdate(const NetworkClientInfo
*ci
)
262 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CLIENT_UPDATE
);
264 p
->Send_uint32(ci
->client_id
);
265 p
->Send_string(ci
->client_name
);
266 p
->Send_uint8 (ci
->client_playas
);
270 return NETWORK_RECV_STATUS_OKAY
;
274 * Tell the admin that a client quit.
275 * @param client_id The client that quit.
277 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendClientQuit(ClientID client_id
)
279 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CLIENT_QUIT
);
281 p
->Send_uint32(client_id
);
284 return NETWORK_RECV_STATUS_OKAY
;
288 * Tell the admin that a client made an error.
289 * @param client_id The client that made the error.
290 * @param error The error that was made.
292 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendClientError(ClientID client_id
, NetworkErrorCode error
)
294 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CLIENT_ERROR
);
296 p
->Send_uint32(client_id
);
297 p
->Send_uint8 (error
);
300 return NETWORK_RECV_STATUS_OKAY
;
304 * Tell the admin that a new company was founded.
305 * @param company_id The company that was founded.
307 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID company_id
)
309 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_COMPANY_NEW
);
310 p
->Send_uint8(company_id
);
314 return NETWORK_RECV_STATUS_OKAY
;
318 * Send the admin some information about a company.
319 * @param c The company to send the information about.
321 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company
*c
)
323 char company_name
[NETWORK_COMPANY_NAME_LENGTH
];
324 char manager_name
[NETWORK_COMPANY_NAME_LENGTH
];
326 SetDParam(0, c
->index
);
327 GetString(company_name
, STR_COMPANY_NAME
, lastof(company_name
));
329 SetDParam(0, c
->index
);
330 GetString(manager_name
, STR_PRESIDENT_NAME
, lastof(manager_name
));
332 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_COMPANY_INFO
);
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
343 for (size_t i
= 0; i
< lengthof(c
->share_owners
); i
++) {
344 p
->Send_uint8(c
->share_owners
[i
]);
349 return NETWORK_RECV_STATUS_OKAY
;
354 * Send an update about a company.
355 * @param c The company to send the update of.
357 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company
*c
)
359 char company_name
[NETWORK_COMPANY_NAME_LENGTH
];
360 char manager_name
[NETWORK_COMPANY_NAME_LENGTH
];
362 SetDParam(0, c
->index
);
363 GetString(company_name
, STR_COMPANY_NAME
, lastof(company_name
));
365 SetDParam(0, c
->index
);
366 GetString(manager_name
, STR_PRESIDENT_NAME
, lastof(manager_name
));
368 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_COMPANY_UPDATE
);
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
377 for (size_t i
= 0; i
< lengthof(c
->share_owners
); i
++) {
378 p
->Send_uint8(c
->share_owners
[i
]);
383 return NETWORK_RECV_STATUS_OKAY
;
387 * Tell the admin that a company got removed.
388 * @param company_id The company that got removed.
389 * @param acrr The reason for removal, e.g. bankruptcy or merger.
391 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCompanyRemove(CompanyID company_id
, AdminCompanyRemoveReason acrr
)
393 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_COMPANY_REMOVE
);
395 p
->Send_uint8(company_id
);
400 return NETWORK_RECV_STATUS_OKAY
;
403 /** Send economic information of all companies. */
404 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCompanyEconomy()
406 const Company
*company
;
407 FOR_ALL_COMPANIES(company
) {
408 /* Get the income. */
410 for (uint i
= 0; i
< lengthof(company
->yearly_expenses
[0]); i
++) {
411 income
-= company
->yearly_expenses
[0][i
];
414 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_COMPANY_ECONOMY
);
416 p
->Send_uint8(company
->index
);
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
>()));
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
>()));
435 return NETWORK_RECV_STATUS_OKAY
;
438 /** Send statistics about the companies. */
439 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCompanyStats()
441 /* Fetch the latest version of the stats. */
442 NetworkCompanyStats company_stats
[MAX_COMPANIES
];
443 NetworkPopulateCompanyStats(company_stats
);
445 const Company
*company
;
447 /* Go through all the companies. */
448 FOR_ALL_COMPANIES(company
) {
449 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_COMPANY_STATS
);
451 /* Send the information. */
452 p
->Send_uint8(company
->index
);
454 for (uint i
= 0; i
< NETWORK_VEH_END
; i
++) {
455 p
->Send_uint16(company_stats
[company
->index
].num_vehicle
[i
]);
458 for (uint i
= 0; i
< NETWORK_VEH_END
; i
++) {
459 p
->Send_uint16(company_stats
[company
->index
].num_station
[i
]);
465 return NETWORK_RECV_STATUS_OKAY
;
469 * Send a chat message.
470 * @param action The action associated with the message.
471 * @param desttype The destination type.
472 * @param client_id The origin of the chat message.
473 * @param msg The actual message.
474 * @param data Arbitrary extra data.
476 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendChat(NetworkAction action
, DestType desttype
, ClientID client_id
, const char *msg
, int64 data
)
478 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CHAT
);
480 p
->Send_uint8 (action
);
481 p
->Send_uint8 (desttype
);
482 p
->Send_uint32(client_id
);
484 p
->Send_uint64(data
);
487 return NETWORK_RECV_STATUS_OKAY
;
491 * Send a notification indicating the rcon command has completed.
492 * @param command The original command sent.
494 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendRconEnd(const char *command
)
496 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_RCON_END
);
498 p
->Send_string(command
);
501 return NETWORK_RECV_STATUS_OKAY
;
505 * Send the reply of an rcon command.
506 * @param colour The colour of the text.
507 * @param result The result of the command.
509 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendRcon(uint16 colour
, const char *result
)
511 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_RCON
);
513 p
->Send_uint16(colour
);
514 p
->Send_string(result
);
517 return NETWORK_RECV_STATUS_OKAY
;
520 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet
*p
)
522 if (this->status
== ADMIN_STATUS_INACTIVE
) return this->SendError(NETWORK_ERROR_NOT_EXPECTED
);
524 char command
[NETWORK_RCONCOMMAND_LENGTH
];
526 p
->Recv_string(command
, sizeof(command
));
528 DEBUG(net
, 2, "[admin] Rcon command from '%s' (%s): '%s'", this->admin_name
, this->admin_version
, command
);
530 _redirect_console_to_admin
= this->index
;
531 IConsoleCmdExec(command
);
532 _redirect_console_to_admin
= INVALID_ADMIN_ID
;
533 return this->SendRconEnd(command
);
536 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet
*p
)
538 if (this->status
== ADMIN_STATUS_INACTIVE
) return this->SendError(NETWORK_ERROR_NOT_EXPECTED
);
540 char json
[NETWORK_GAMESCRIPT_JSON_LENGTH
];
542 p
->Recv_string(json
, sizeof(json
));
544 DEBUG(net
, 2, "[admin] GameScript JSON from '%s' (%s): '%s'", this->admin_name
, this->admin_version
, json
);
546 Game::NewEvent(new ScriptEventAdminPort(json
));
547 return NETWORK_RECV_STATUS_OKAY
;
550 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_PING(Packet
*p
)
552 if (this->status
== ADMIN_STATUS_INACTIVE
) return this->SendError(NETWORK_ERROR_NOT_EXPECTED
);
554 uint32 d1
= p
->Recv_uint32();
556 DEBUG(net
, 2, "[admin] Ping from '%s' (%s): '%d'", this->admin_name
, this->admin_version
, d1
);
558 return this->SendPong(d1
);
562 * Send console output of other clients.
563 * @param origin The origin of the string.
564 * @param string The string that's put on the console.
566 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendConsole(const char *origin
, const char *string
)
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
;
574 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CONSOLE
);
576 p
->Send_string(origin
);
577 p
->Send_string(string
);
580 return NETWORK_RECV_STATUS_OKAY
;
584 * Send GameScript JSON output.
585 * @param json The JSON string.
587 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendGameScript(const char *json
)
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
;
594 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_GAMESCRIPT
);
596 p
->Send_string(json
);
599 return NETWORK_RECV_STATUS_OKAY
;
602 /** Send ping-reply (pong) to admin **/
603 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendPong(uint32 d1
)
605 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_PONG
);
610 return NETWORK_RECV_STATUS_OKAY
;
613 /** Send the names of the commands. */
614 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCmdNames()
616 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CMD_NAMES
);
618 for (uint i
= 0; i
< CMD_END
; i
++) {
619 const char *cmdname
= GetCommandName(i
);
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
) {
628 p
= new Packet(ADMIN_PACKET_SERVER_CMD_NAMES
);
633 p
->Send_string(cmdname
);
636 /* Marker to notify the end of the packet has been reached. */
640 return NETWORK_RECV_STATUS_OKAY
;
644 * Send a command for logging purposes.
645 * @param client_id The client executing the command.
646 * @param cp The command that would be executed.
648 NetworkRecvStatus
ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID client_id
, const CommandPacket
*cp
)
650 Packet
*p
= new Packet(ADMIN_PACKET_SERVER_CMD_LOGGING
);
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
);
663 return NETWORK_RECV_STATUS_OKAY
;
667 * Receiving functions
670 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet
*p
)
672 if (this->status
!= ADMIN_STATUS_INACTIVE
) return this->SendError(NETWORK_ERROR_NOT_EXPECTED
);
674 char password
[NETWORK_PASSWORD_LENGTH
];
675 p
->Recv_string(password
, sizeof(password
));
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
);
683 p
->Recv_string(this->admin_name
, sizeof(this->admin_name
));
684 p
->Recv_string(this->admin_version
, sizeof(this->admin_version
));
686 if (StrEmpty(this->admin_name
) || StrEmpty(this->admin_version
)) {
687 /* no name or version supplied */
688 return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET
);
691 this->status
= ADMIN_STATUS_ACTIVE
;
693 DEBUG(net
, 1, "[admin] '%s' (%s) has connected", this->admin_name
, this->admin_version
);
695 return this->SendProtocol();
698 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet
*p
)
700 /* The admin is leaving nothing else to do */
701 return this->CloseConnection();
704 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet
*p
)
706 if (this->status
== ADMIN_STATUS_INACTIVE
) return this->SendError(NETWORK_ERROR_NOT_EXPECTED
);
708 AdminUpdateType type
= (AdminUpdateType
)p
->Recv_uint16();
709 AdminUpdateFrequency freq
= (AdminUpdateFrequency
)p
->Recv_uint16();
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
);
717 this->update_frequency
[type
] = freq
;
719 return NETWORK_RECV_STATUS_OKAY
;
722 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet
*p
)
724 if (this->status
== ADMIN_STATUS_INACTIVE
) return this->SendError(NETWORK_ERROR_NOT_EXPECTED
);
726 AdminUpdateType type
= (AdminUpdateType
)p
->Recv_uint8();
727 uint32 d1
= p
->Recv_uint32();
730 case ADMIN_UPDATE_DATE
:
731 /* The admin is requesting the current date. */
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());
744 if (d1
== CLIENT_ID_SERVER
) {
745 this->SendClientInfo(NULL
, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER
));
747 cs
= NetworkClientSocket::GetByClientID((ClientID
)d1
);
748 if (cs
!= NULL
) this->SendClientInfo(cs
, cs
->GetInfo());
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
);
761 company
= Company::GetIfValid(d1
);
762 if (company
!= NULL
) this->SendCompanyInfo(company
);
766 case ADMIN_UPDATE_COMPANY_ECONOMY
:
767 /* The admin is requesting economy info. */
768 this->SendCompanyEconomy();
771 case ADMIN_UPDATE_COMPANY_STATS
:
772 /* the admin is requesting company stats. */
773 this->SendCompanyStats();
776 case ADMIN_UPDATE_CMD_NAMES
:
777 /* The admin is requesting the names of DoCommands. */
778 this->SendCmdNames();
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
);
787 return NETWORK_RECV_STATUS_OKAY
;
790 NetworkRecvStatus
ServerNetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet
*p
)
792 if (this->status
== ADMIN_STATUS_INACTIVE
) return this->SendError(NETWORK_ERROR_NOT_EXPECTED
);
794 NetworkAction action
= (NetworkAction
)p
->Recv_uint8();
795 DestType desttype
= (DestType
)p
->Recv_uint8();
796 int dest
= p
->Recv_uint32();
798 char msg
[NETWORK_CHAT_LENGTH
];
799 p
->Recv_string(msg
, NETWORK_CHAT_LENGTH
);
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);
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
);
814 return NETWORK_RECV_STATUS_OKAY
;
818 * Useful wrapper functions
822 * Notify the admin network of a new client (if they did opt in for the respective update).
823 * @param cs the client info.
824 * @param new_client if this is a new client, send the respective packet too.
826 void NetworkAdminClientInfo(const NetworkClientSocket
*cs
, bool new_client
)
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());
833 as
->SendClientJoin(cs
->client_id
);
840 * Notify the admin network of a client update (if they did opt in for the respective update).
841 * @param ci the client info.
843 void NetworkAdminClientUpdate(const NetworkClientInfo
*ci
)
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
);
854 * Notify the admin network that a client quit (if they have opt in for the respective update).
855 * @param client_id of the client that quit.
857 void NetworkAdminClientQuit(ClientID client_id
)
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
);
868 * Notify the admin network of a client error (if they have opt in for the respective update).
869 * @param client_id the client that made the error.
870 * @param error_code the error that was caused.
872 void NetworkAdminClientError(ClientID client_id
, NetworkErrorCode error_code
)
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
);
883 * Notify the admin network of company details.
884 * @param company the company of which details will be sent into the admin network.
885 * @param new_company whether this is a new company or not.
887 void NetworkAdminCompanyInfo(const Company
*company
, bool new_company
)
889 if (company
== NULL
) {
890 DEBUG(net
, 1, "[admin] Empty company given for update");
894 ServerNetworkAdminSocketHandler
*as
;
895 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as
) {
896 if (as
->update_frequency
[ADMIN_UPDATE_COMPANY_INFO
] != ADMIN_FREQUENCY_AUTOMATIC
) continue;
898 as
->SendCompanyInfo(company
);
900 as
->SendCompanyNew(company
->index
);
906 * Notify the admin network of company updates.
907 * @param company company of which updates are going to be sent into the admin network.
909 void NetworkAdminCompanyUpdate(const Company
*company
)
911 if (company
== NULL
) return;
913 ServerNetworkAdminSocketHandler
*as
;
914 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as
) {
915 if (as
->update_frequency
[ADMIN_UPDATE_COMPANY_INFO
] != ADMIN_FREQUENCY_AUTOMATIC
) continue;
917 as
->SendCompanyUpdate(company
);
922 * Notify the admin network of a company to be removed (including the reason why).
923 * @param company_id ID of the company that got removed.
924 * @param bcrr the reason why the company got removed (e.g. bankruptcy).
926 void NetworkAdminCompanyRemove(CompanyID company_id
, AdminCompanyRemoveReason bcrr
)
928 ServerNetworkAdminSocketHandler
*as
;
929 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as
) {
930 as
->SendCompanyRemove(company_id
, bcrr
);
936 * Send chat to the admin network (if they did opt in for the respective update).
938 void NetworkAdminChat(NetworkAction action
, DestType desttype
, ClientID client_id
, const char *msg
, int64 data
, bool from_admin
)
940 if (from_admin
) return;
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
);
951 * Pass the rcon reply to the admin.
952 * @param admin_index The admin to give the reply.
953 * @param colour_code The colour of the string.
954 * @param string The string to show.
956 void NetworkServerSendAdminRcon(AdminIndex admin_index
, TextColour colour_code
, const char *string
)
958 ServerNetworkAdminSocketHandler::Get(admin_index
)->SendRcon(colour_code
, string
);
962 * Send console to the admin network (if they did opt in for the respective update).
963 * @param origin the origin of the message.
964 * @param string the message as printed on the console.
966 void NetworkAdminConsole(const char *origin
, const char *string
)
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
);
977 * Send GameScript JSON to the admin network (if they did opt in for the respective update).
978 * @param json The JSON data as received from the GameScript.
980 void NetworkAdminGameScript(const char *json
)
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
);
991 * Distribute CommandPacket details over the admin network for logging purposes.
992 * @param owner The owner of the CommandPacket (who sent us the CommandPacket).
993 * @param cp The CommandPacket to be distributed.
995 void NetworkAdminCmdLogging(const NetworkClientSocket
*owner
, const CommandPacket
*cp
)
997 ClientID client_id
= owner
== NULL
? _network_own_client_id
: owner
->client_id
;
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
);
1008 * Send a Welcome packet to all connected admins
1010 void ServerNetworkAdminSocketHandler::WelcomeAll()
1012 ServerNetworkAdminSocketHandler
*as
;
1013 FOR_ALL_ACTIVE_ADMIN_SOCKETS(as
) {
1019 * Send (push) updates to the admin network as they have registered for these updates.
1020 * @param freq the frequency to be processed.
1022 void NetworkAdminUpdate(AdminUpdateFrequency freq
)
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 */
1030 case ADMIN_UPDATE_DATE
:
1034 case ADMIN_UPDATE_COMPANY_ECONOMY
:
1035 as
->SendCompanyEconomy();
1038 case ADMIN_UPDATE_COMPANY_STATS
:
1039 as
->SendCompanyStats();
1042 default: NOT_REACHED();
1049 #endif /* ENABLE_NETWORK */