diff --git a/src/date.cpp b/src/date.cpp index d8d2cc5ef5..4ef16aed78 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -250,6 +250,7 @@ static void OnNewDay() { #ifdef ENABLE_NETWORK NetworkChatMessageDailyLoop(); + if (_network_server) NetworkServerDailyLoop(); #endif /* ENABLE_NETWORK */ DisasterDailyLoop(); diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp index 2d68fc68bd..60ccfd0643 100644 --- a/src/network/core/tcp_admin.cpp +++ b/src/network/core/tcp_admin.cpp @@ -52,6 +52,8 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) switch (this->HasClientQuit() ? INVALID_ADMIN_PACKET : type) { ADMIN_COMMAND(ADMIN_PACKET_ADMIN_JOIN) ADMIN_COMMAND(ADMIN_PACKET_ADMIN_QUIT) + ADMIN_COMMAND(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY) + ADMIN_COMMAND(ADMIN_PACKET_ADMIN_POLL) ADMIN_COMMAND(ADMIN_PACKET_SERVER_FULL) ADMIN_COMMAND(ADMIN_PACKET_SERVER_BANNED) @@ -107,6 +109,8 @@ NetworkRecvStatus NetworkAdminSocketHandler::NetworkPacketReceive_## type ##_com DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_JOIN) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_QUIT) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_POLL) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_FULL) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_BANNED) diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h index dae41c5f55..3ed4442573 100644 --- a/src/network/core/tcp_admin.h +++ b/src/network/core/tcp_admin.h @@ -28,6 +28,8 @@ enum PacketAdminType { ADMIN_PACKET_ADMIN_JOIN, ///< The admin announces and authenticates itself to the server. ADMIN_PACKET_ADMIN_QUIT, ///< The admin tells the server that it is quitting. + ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY, ///< The admin tells the server the update frequency of a particular piece of information. + ADMIN_PACKET_ADMIN_POLL, ///< The admin explicitly polls for a piece of information. ADMIN_PACKET_SERVER_FULL = 100, ///< The server tells the admin it cannot accept the admin. ADMIN_PACKET_SERVER_BANNED, ///< The server tells the admin it is banned. @@ -47,6 +49,23 @@ enum AdminStatus { ADMIN_STATUS_END ///< Must ALWAYS be on the end of this list!! (period) }; +/** Update types an admin can register a frequency for */ +enum AdminUpdateType { + ADMIN_UPDATE_END ///< Must ALWAYS be on the end of this list!! (period) +}; + +/** Update frequencies an admin can register. */ +enum AdminUpdateFrequency { + ADMIN_FREQUENCY_POLL = 0x01, ///< The admin can poll this. + ADMIN_FREQUENCY_DAILY = 0x02, ///< The admin gets information about this on a daily basis. + ADMIN_FREQUENCY_WEEKLY = 0x04, ///< The admin gets information about this on a weekly basis. + ADMIN_FREQUENCY_MONTHLY = 0x08, ///< The admin gets information about this on a monthly basis. + ADMIN_FREQUENCY_QUARTERLY = 0x10, ///< The admin gets information about this on a quarterly basis. + ADMIN_FREQUENCY_ANUALLY = 0x20, ///< The admin gets information about this on a yearly basis. + ADMIN_FREQUENCY_AUTOMATIC = 0x40, ///< The admin gets information about this when it changes. +}; +DECLARE_ENUM_AS_BIT_SET(AdminUpdateFrequency); + #define DECLARE_ADMIN_RECEIVE_COMMAND(type) virtual NetworkRecvStatus NetworkPacketReceive_## type ##_command(Packet *p) #define DEF_ADMIN_RECEIVE_COMMAND(cls, type) NetworkRecvStatus cls ##NetworkAdminSocketHandler::NetworkPacketReceive_ ## type ## _command(Packet *p) @@ -70,6 +89,20 @@ protected: */ DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_QUIT); + /** + * Register updates to be sent at certain frequencies (as announced in the PROTOCOL packet): + * uint16 Update type (see #AdminUpdateType). + * uint16 Update frequency (see #AdminUpdateFrequency), setting #ADMIN_FREQUENCY_POLL is always ignored. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY); + + /** + * 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. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_POLL); + /** * The server is full (connection gets closed). */ diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index b03f9422e4..11b8d8adeb 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -37,6 +37,12 @@ INSTANTIATE_POOL_METHODS(NetworkAdminSocket) /** The timeout for authorisation of the client. */ static const int ADMIN_AUTHORISATION_TIMEOUT = 10000; + +/** Frequencies, which may be registered for a certain update type. */ +static const AdminUpdateFrequency _admin_update_type_frequencies[] = { +}; +assert_compile(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END); + /** * Create a new socket for the server side of the admin network. * @param s The socket to connect with. @@ -115,6 +121,12 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol() /* announce the protocol version */ p->Send_uint8(NETWORK_GAME_ADMIN_VERSION); + for (int i = 0; i < ADMIN_UPDATE_END; i++) { + p->Send_bool (true); + p->Send_uint16(i); + p->Send_uint16(_admin_update_type_frequencies[i]); + } + p->Send_bool(false); this->Send_Packet(p); @@ -193,6 +205,41 @@ DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_QUIT) return this->CloseConnection(); } +DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY) +{ + if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); + + AdminUpdateType type = (AdminUpdateType)p->Recv_uint16(); + AdminUpdateFrequency freq = (AdminUpdateFrequency)p->Recv_uint16(); + + if (type >= ADMIN_UPDATE_END || (_admin_update_type_frequencies[type] & freq) != freq) { + /* The server does not know of this UpdateType. */ + DEBUG(net, 3, "[admin] Not supported update frequency %d (%d) from '%s' (%s).", type, freq, this->admin_name, this->admin_version); + return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET); + } + + this->update_frequency[type] = freq; + + return NETWORK_RECV_STATUS_OKAY; +} + +DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_POLL) +{ + if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); + + AdminUpdateType type = (AdminUpdateType)p->Recv_uint8(); + uint32 d1 = p->Recv_uint32(); + + switch (type) { + 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); + return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET); + } + + return NETWORK_RECV_STATUS_OKAY; +} + /* * Useful wrapper functions */ @@ -208,4 +255,23 @@ void ServerNetworkAdminSocketHandler::WelcomeAll() } } +/** + * Send (push) updates to the admin network as they have registered for these updates. + * @param freq the frequency to be processd. + */ +void NetworkAdminUpdate(AdminUpdateFrequency freq) +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + for (int i = 0; i < ADMIN_UPDATE_END; i++) { + if (as->update_frequency[i] & freq) { + /* Update the admin for the required details */ + switch (i) { + default: NOT_REACHED(); + } + } + } + } +} + #endif /* ENABLE_NETWORK */ diff --git a/src/network/network_admin.h b/src/network/network_admin.h index 1e0a3f2b6a..c958f876fe 100644 --- a/src/network/network_admin.h +++ b/src/network/network_admin.h @@ -27,9 +27,12 @@ class ServerNetworkAdminSocketHandler : public NetworkAdminSocketPool::PoolItem< protected: DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_JOIN); DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_QUIT); + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY); + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_POLL); NetworkRecvStatus SendProtocol(); public: + AdminUpdateFrequency update_frequency[ADMIN_UPDATE_END]; ///< Admin requested update intervals. uint32 realtime_connect; ///< Time of connection. NetworkAddress address; ///< Address of the admin. @@ -59,5 +62,7 @@ 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 NetworkAdminUpdate(AdminUpdateFrequency freq); + #endif /* ENABLE_NETWORK */ #endif /* NETWORK_ADMIN_H */ diff --git a/src/network/network_func.h b/src/network/network_func.h index da9499e816..00db245e33 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -59,6 +59,7 @@ void NetworkPrintClients(); void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode); /*** Commands ran by the server ***/ +void NetworkServerDailyLoop(); void NetworkServerMonthlyLoop(); void NetworkServerYearlyLoop(); void NetworkServerSendConfigUpdate(); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index ab2bd1632c..ca446dfed9 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -15,6 +15,7 @@ #include "../debug.h" #include "../strings_func.h" #include "../date_func.h" +#include "network_admin.h" #include "network_server.h" #include "network_udp.h" #include "network.h" @@ -1702,14 +1703,26 @@ void NetworkServer_Tick(bool send_frame) NetworkUDPAdvertise(); } +/** Yearly "callback". Called whenever the year changes. */ void NetworkServerYearlyLoop() { NetworkCheckRestartMap(); + NetworkAdminUpdate(ADMIN_FREQUENCY_ANUALLY); } +/** Monthly "callback". Called whenever the month changes. */ void NetworkServerMonthlyLoop() { NetworkAutoCleanCompanies(); + NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY); + if ((_cur_month % 3) == 0) NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY); +} + +/** Daily "callback". Called whenever the date changes. */ +void NetworkServerDailyLoop() +{ + NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY); + if ((_date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY); } const char *GetClientIP(NetworkClientInfo *ci)