diff options
-rw-r--r-- | src/network/core/tcp_admin.cpp | 10 | ||||
-rw-r--r-- | src/network/core/tcp_admin.h | 47 | ||||
-rw-r--r-- | src/network/network_admin.cpp | 135 | ||||
-rw-r--r-- | src/network/network_admin.h | 9 | ||||
-rw-r--r-- | src/network/network_server.cpp | 10 |
5 files changed, 210 insertions, 1 deletions
diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp index 29cd251ed..ee254968a 100644 --- a/src/network/core/tcp_admin.cpp +++ b/src/network/core/tcp_admin.cpp @@ -64,6 +64,11 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) ADMIN_COMMAND(ADMIN_PACKET_SERVER_SHUTDOWN) ADMIN_COMMAND(ADMIN_PACKET_SERVER_DATE) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_JOIN) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_INFO) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_UPDATE) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_QUIT) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_ERROR) default: if (this->HasClientQuit()) { @@ -123,5 +128,10 @@ DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_NEWGAME) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_SHUTDOWN) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_DATE) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_JOIN) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_INFO) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_UPDATE) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_QUIT) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_ERROR) #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h index f93b5c388..656fa9503 100644 --- a/src/network/core/tcp_admin.h +++ b/src/network/core/tcp_admin.h @@ -40,6 +40,11 @@ enum PacketAdminType { ADMIN_PACKET_SERVER_SHUTDOWN, ///< The server tells the admin its shutting down. ADMIN_PACKET_SERVER_DATE, ///< The server tells the admin what the current game date is. + ADMIN_PACKET_SERVER_CLIENT_JOIN, ///< The server tells the admin that a client has joined. + ADMIN_PACKET_SERVER_CLIENT_INFO, ///< The server gives the admin information about a client. + ADMIN_PACKET_SERVER_CLIENT_UPDATE, ///< The server gives the admin an information update on a client. + ADMIN_PACKET_SERVER_CLIENT_QUIT, ///< The server tells the admin that a client quit. + ADMIN_PACKET_SERVER_CLIENT_ERROR, ///< The server tells the admin that a client caused an error. INVALID_ADMIN_PACKET = 0xFF, ///< An invalid marker for admin packets. }; @@ -54,6 +59,7 @@ enum AdminStatus { /** Update types an admin can register a frequency for */ enum AdminUpdateType { ADMIN_UPDATE_DATE, ///< Updates about the date of the game. + ADMIN_UPDATE_CLIENT_INFO, ///< Updates about the information of clients. ADMIN_UPDATE_END ///< Must ALWAYS be on the end of this list!! (period) }; @@ -102,7 +108,8 @@ protected: /** * Poll the server for certain updates, an invalid poll (e.g. not existent id) gets silently dropped: * uint8 #AdminUpdateType the server should answer for, only if #AdminUpdateFrequency #ADMIN_FREQUENCY_POLL is advertised in the PROTOCOL packet. - * uint32 ID relevant to the packet type. + * uint32 ID relevant to the packet type, e.g. + * - the client ID for #ADMIN_UPDATE_CLIENT_INFO. Use UINT32_MAX to show all clients. */ DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_POLL); @@ -161,6 +168,44 @@ protected: */ DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_DATE); + /** + * Notification of a new client: + * uint32 ID of the new client. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_JOIN); + + /** + * Client information of a specific client: + * uint32 ID of the client. + * string Network address of the client. + * string Name of the client. + * uint8 Language of the client. + * uint32 Date the client joined the game. + * uint8 ID of the company the client is playing as (255 for spectators). + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_INFO); + + /** + * Client update details on a specific client (e.g. after rename or move): + * uint32 ID of the client. + * string Name of the client. + * uint8 ID of the company the client is playing as (255 for spectators). + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_UPDATE); + + /** + * Notification about a client leaving the game. + * uint32 ID of the client that just left. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_QUIT); + + /** + * Notification about a client error (and thus the clients disconnection). + * uint32 ID of the client that made the error. + * uint8 Error the client made (see NetworkErrorCode). + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_ERROR); + NetworkRecvStatus HandlePacket(Packet *p); public: NetworkRecvStatus CloseConnection(bool error = true); diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index 18c4870b4..9e6402310 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -41,6 +41,7 @@ static const int ADMIN_AUTHORISATION_TIMEOUT = 10000; /** Frequencies, which may be registered for a certain update type. */ static const AdminUpdateFrequency _admin_update_type_frequencies[] = { ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_DAILY | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY, ///< ADMIN_UPDATE_DATE + ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_CLIENT_INFO }; assert_compile(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END); @@ -180,6 +181,66 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate() return NETWORK_RECV_STATUS_OKAY; } +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID client_id) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_JOIN); + + p->Send_uint32(client_id); + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkClientInfo *ci) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_INFO); + + p->Send_uint32(ci->client_id); + p->Send_string(const_cast<NetworkAddress &>(ci->client_address).GetHostname()); + p->Send_string(ci->client_name); + p->Send_uint8 (ci->client_lang); + p->Send_uint32(ci->join_date); + p->Send_uint8 (ci->client_playas); + + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const NetworkClientInfo *ci) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_UPDATE); + + p->Send_uint32(ci->client_id); + p->Send_string(ci->client_name); + p->Send_uint8 (ci->client_playas); + + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID client_id) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_QUIT); + + p->Send_uint32(client_id); + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID client_id, NetworkErrorCode error) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_ERROR); + + p->Send_uint32(client_id); + p->Send_uint8 (error); + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + /*********** * Receiving functions ************/ @@ -247,6 +308,19 @@ DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_POLL) this->SendDate(); break; + case ADMIN_UPDATE_CLIENT_INFO: + /* The admin is requesting client info. */ + const NetworkClientInfo *ci; + if (d1 == UINT32_MAX) { + FOR_ALL_CLIENT_INFOS(ci) { + this->SendClientInfo(ci); + } + } else { + ci = NetworkFindClientInfoFromClientID((ClientID)d1); + if (ci != NULL) this->SendClientInfo(ci); + } + break; + default: /* An unsupported "poll" update type. */ DEBUG(net, 3, "[admin] Not supported poll %d (%d) from '%s' (%s).", type, d1, this->admin_name, this->admin_version); @@ -261,6 +335,67 @@ DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_POLL) */ /** + * Notify the admin network of a new client (if they did opt in for the respective update). + * @param ci the client info. + * @param new_client if this is a new client, send the respective packet too. + */ +void NetworkAdminClientInfo(const NetworkClientInfo *ci, bool new_client) +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { + as->SendClientInfo(ci); + if (new_client) { + as->SendClientJoin(ci->client_id); + } + } + } +} + +/** + * Notify the admin network of a client update (if they did opt in for the respective update). + * @param ci the client info. + */ +void NetworkAdminClientUpdate(const NetworkClientInfo *ci) +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { + as->SendClientUpdate(ci); + } + } +} + +/** + * Notify the admin network that a client quit (if they have opt in for the respective update). + * @param client_id of the client that quit. + */ +void NetworkAdminClientQuit(ClientID client_id) +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { + as->SendClientQuit(client_id); + } + } +} + +/** + * Notify the admin network of a client error (if they have opt in for the respective update). + * @param client_id the client that made the error. + * @param error_code the error that was caused. + */ +void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code) +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { + as->SendClientError(client_id, error_code); + } + } +} + +/** * Send a Welcome packet to all connected admins */ void ServerNetworkAdminSocketHandler::WelcomeAll() diff --git a/src/network/network_admin.h b/src/network/network_admin.h index bbddf2183..384553081 100644 --- a/src/network/network_admin.h +++ b/src/network/network_admin.h @@ -44,6 +44,11 @@ public: NetworkRecvStatus SendNewGame(); NetworkRecvStatus SendShutdown(); NetworkRecvStatus SendDate(); + NetworkRecvStatus SendClientJoin(ClientID client_id); + NetworkRecvStatus SendClientInfo(const NetworkClientInfo *ci); + NetworkRecvStatus SendClientUpdate(const NetworkClientInfo *ci); + NetworkRecvStatus SendClientQuit(ClientID client_id); + NetworkRecvStatus SendClientError(ClientID client_id, NetworkErrorCode error); static void Send(); static void AcceptConnection(SOCKET s, const NetworkAddress &address); @@ -63,6 +68,10 @@ public: #define FOR_ALL_ADMIN_SOCKETS_FROM(var, start) FOR_ALL_ITEMS_FROM(ServerNetworkAdminSocketHandler, adminsocket_index, var, start) #define FOR_ALL_ADMIN_SOCKETS(var) FOR_ALL_ADMIN_SOCKETS_FROM(var, 0) +void NetworkAdminClientInfo(const NetworkClientInfo *ci, bool new_client = false); +void NetworkAdminClientUpdate(const NetworkClientInfo *ci); +void NetworkAdminClientQuit(ClientID client_id); +void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code); void NetworkAdminUpdate(AdminUpdateFrequency freq); #endif /* ENABLE_NETWORK */ diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index ca446dfed..0a49a277b 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -284,6 +284,8 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err new_cs->SendErrorQuit(this->client_id, error); } } + + NetworkAdminClientError(this->client_id, error); } else { DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", this->client_id, str); } @@ -985,6 +987,8 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_MAP_OK) } } + NetworkAdminClientInfo(this->GetInfo(), true); + /* also update the new client with our max values */ this->SendConfigUpdate(); @@ -1093,6 +1097,8 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_ERROR) } } + NetworkAdminClientError(this->client_id, errorno); + return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } @@ -1118,6 +1124,8 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_QUIT) } } + NetworkAdminClientQuit(this->client_id); + return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } @@ -1473,6 +1481,8 @@ void NetworkUpdateClientInfo(ClientID client_id) FOR_ALL_CLIENT_SOCKETS(cs) { cs->SendClientInfo(ci); } + + NetworkAdminClientUpdate(ci); } /* Check if we want to restart the map */ |