diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/network/core/config.h | 6 | ||||
-rw-r--r-- | src/network/network_gamelist.cpp | 64 | ||||
-rw-r--r-- | src/network/network_gamelist.h | 2 | ||||
-rw-r--r-- | src/network/network_udp.cpp | 333 | ||||
-rw-r--r-- | src/network/network_udp.h | 2 | ||||
-rw-r--r-- | src/settings_type.h | 2 |
6 files changed, 8 insertions, 401 deletions
diff --git a/src/network/core/config.h b/src/network/core/config.h index e0ec63a0c..ab1c3082e 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -12,8 +12,6 @@ #ifndef NETWORK_CORE_CONFIG_H #define NETWORK_CORE_CONFIG_H -/** DNS hostname of the masterserver */ -static const char * const NETWORK_MASTER_SERVER_HOST = "master.openttd.org"; /** DNS hostname of the Game Coordinator server */ static const char * const NETWORK_COORDINATOR_SERVER_HOST = "coordinator.openttd.org"; /** DNS hostname of the content server */ @@ -22,10 +20,7 @@ static const char * const NETWORK_CONTENT_SERVER_HOST = "content.opent static const char * const NETWORK_CONTENT_MIRROR_HOST = "binaries.openttd.org"; /** URL of the HTTP mirror system */ static const char * const NETWORK_CONTENT_MIRROR_URL = "/bananas"; -/** Message sent to the masterserver to 'identify' this client as OpenTTD */ -static const char * const NETWORK_MASTER_SERVER_WELCOME_MESSAGE = "OpenTTDRegister"; -static const uint16 NETWORK_MASTER_SERVER_PORT = 3978; ///< The default port of the master server (UDP) static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976; ///< The default port of the Game Coordinator server (TCP) static const uint16 NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP) static const uint16 NETWORK_CONTENT_MIRROR_PORT = 80; ///< The default port of the content mirror (TCP) @@ -54,7 +49,6 @@ static const uint16 COMPAT_MTU = 1460; ///< Numbe static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use? static const byte NETWORK_GAME_INFO_VERSION = 4; ///< What version of game-info do we use? static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this? -static const byte NETWORK_MASTER_SERVER_VERSION = 2; ///< What version of master-server-protocol do we use? static const byte NETWORK_COORDINATOR_VERSION = 1; ///< What version of game-coordinator-protocol do we use? static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index b4f34983f..92964bf25 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -23,45 +23,6 @@ NetworkGameList *_network_game_list = nullptr; ///< Game list of this client. int _network_game_list_version = 0; ///< Current version of all items in the list. -/** The games to insert when the GUI thread has time for us. */ -static std::atomic<NetworkGameList *> _network_game_delayed_insertion_list(nullptr); - -/** - * Add a new item to the linked gamelist, but do it delayed in the next tick - * or so to prevent race conditions. - * @param item the item to add. Will be freed once added. - */ -void NetworkGameListAddItemDelayed(NetworkGameList *item) -{ - item->next = _network_game_delayed_insertion_list.load(std::memory_order_relaxed); - while (!_network_game_delayed_insertion_list.compare_exchange_weak(item->next, item, std::memory_order_acq_rel)) {} -} - -/** Perform the delayed (thread safe) insertion into the game list */ -static void NetworkGameListHandleDelayedInsert() -{ - while (true) { - NetworkGameList *ins_item = _network_game_delayed_insertion_list.load(std::memory_order_relaxed); - while (ins_item != nullptr && !_network_game_delayed_insertion_list.compare_exchange_weak(ins_item, ins_item->next, std::memory_order_acq_rel)) {} - if (ins_item == nullptr) break; // No item left. - - NetworkGameList *item = NetworkGameListAddItem(ins_item->connection_string); - - if (item != nullptr) { - if (item->info.server_name.empty()) { - ClearGRFConfigList(&item->info.grfconfig); - item->info = {}; - item->info.server_name = ins_item->info.server_name; - item->online = false; - } - item->manually |= ins_item->manually; - if (item->manually) NetworkRebuildHostList(); - UpdateNetworkGameWindow(); - } - delete ins_item; - } -} - /** * Add a new item to the linked gamelist. If the IP and Port match * return the existing item instead of adding it again @@ -149,31 +110,6 @@ void NetworkGameListRemoveExpired() UpdateNetworkGameWindow(); } -static const uint MAX_GAME_LIST_REQUERY_COUNT = 10; ///< How often do we requery in number of times per server? -static const uint REQUERY_EVERY_X_GAMELOOPS = 60; ///< How often do we requery in time? -static const uint REFRESH_GAMEINFO_X_REQUERIES = 50; ///< Refresh the game info itself after REFRESH_GAMEINFO_X_REQUERIES * REQUERY_EVERY_X_GAMELOOPS game loops - -/** Requeries the (game) servers we have not gotten a reply from */ -void NetworkGameListRequery() -{ - NetworkGameListHandleDelayedInsert(); - - static uint8 requery_cnt = 0; - - if (++requery_cnt < REQUERY_EVERY_X_GAMELOOPS) return; - requery_cnt = 0; - - for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) { - item->retries++; - if (item->retries < REFRESH_GAMEINFO_X_REQUERIES && (item->online || item->retries >= MAX_GAME_LIST_REQUERY_COUNT)) continue; - - /* item gets mostly zeroed by NetworkUDPQueryServer */ - uint8 retries = item->retries; - NetworkUDPQueryServer(item->connection_string); - item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries; - } -} - /** * Rebuild the GRFConfig's of the servers in the game list as we did * a rescan and might have found new NewGRFs. diff --git a/src/network/network_gamelist.h b/src/network/network_gamelist.h index 2bab7626e..7fdd37c66 100644 --- a/src/network/network_gamelist.h +++ b/src/network/network_gamelist.h @@ -33,10 +33,8 @@ struct NetworkGameList { extern NetworkGameList *_network_game_list; extern int _network_game_list_version; -void NetworkGameListAddItemDelayed(NetworkGameList *item); NetworkGameList *NetworkGameListAddItem(const std::string &connection_string); void NetworkGameListRemoveItem(NetworkGameList *remove); void NetworkGameListRemoveExpired(); -void NetworkGameListRequery(); #endif /* NETWORK_GAMELIST_H */ diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index ffa07f087..3deb7e312 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -23,12 +23,10 @@ #include "network.h" #include "../core/endian_func.hpp" #include "../company_base.h" -#include "../thread.h" #include "../rev.h" #include "../newgrf_text.h" #include "../strings_func.h" #include "table/strings.h" -#include <mutex> #include "core/udp.h" @@ -40,79 +38,32 @@ static uint16 _network_udp_broadcast; ///< Timeout for the UDP broadcasts. /** Some information about a socket, which exists before the actual socket has been created to provide locking and the likes. */ struct UDPSocket { const std::string name; ///< The name of the socket. - std::mutex mutex; ///< Mutex for everything that (indirectly) touches the sockets within the handler. NetworkUDPSocketHandler *socket; ///< The actual socket, which may be nullptr when not initialized yet. - std::atomic<int> receive_iterations_locked; ///< The number of receive iterations the mutex was locked. - UDPSocket(const std::string &name_) : name(name_), socket(nullptr) {} + UDPSocket(const std::string &name) : name(name), socket(nullptr) {} void CloseSocket() { - std::lock_guard<std::mutex> lock(mutex); - socket->CloseSocket(); - delete socket; - socket = nullptr; + this->socket->CloseSocket(); + delete this->socket; + this->socket = nullptr; } void ReceivePackets() { - std::unique_lock<std::mutex> lock(mutex, std::defer_lock); - if (!lock.try_lock()) { - if (++receive_iterations_locked % 32 == 0) { - Debug(net, 0, "{} background UDP loop processing appears to be blocked. Your OS may be low on UDP send buffers.", name); - } - return; - } - - receive_iterations_locked.store(0); - socket->ReceivePackets(); + this->socket->ReceivePackets(); } }; static UDPSocket _udp_client("Client"); ///< udp client socket static UDPSocket _udp_server("Server"); ///< udp server socket -/** - * Helper function doing the actual work for querying the server. - * @param connection_string The address of the server. - * @param needs_mutex Whether we need to acquire locks when sending the packet or not. - * @param manually Whether the address was entered manually. - */ -static void DoNetworkUDPQueryServer(const std::string &connection_string, bool needs_mutex, bool manually) -{ - /* Clear item in gamelist */ - NetworkGameList *item = new NetworkGameList(connection_string, manually); - item->info.server_name = connection_string; - NetworkGameListAddItemDelayed(item); - - std::unique_lock<std::mutex> lock(_udp_client.mutex, std::defer_lock); - if (needs_mutex) lock.lock(); - /* Init the packet */ - NetworkAddress address = NetworkAddress(ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT)); - Packet p(PACKET_UDP_CLIENT_FIND_SERVER); - if (_udp_client.socket != nullptr) _udp_client.socket->SendPacket(&p, &address); -} - -/** - * Query a specific server. - * @param connection_string The address of the server. - * @param manually Whether the address was entered manually. - */ -void NetworkUDPQueryServer(const std::string &connection_string, bool manually) -{ - if (!StartNewThread(nullptr, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(connection_string), true, std::move(manually))) { - DoNetworkUDPQueryServer(connection_string, true, manually); - } -} - ///*** Communication with clients (we are server) ***/ /** Helper class for handling all server side communication. */ class ServerNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) override; - void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) override; - void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) override; public: /** * Create the socket. @@ -124,307 +75,40 @@ public: void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { - /* Just a fail-safe.. should never happen */ - if (!_network_udp_server) { - return; - } - Packet packet(PACKET_UDP_SERVER_RESPONSE); - SerializeNetworkGameInfo(&packet, GetCurrentNetworkServerGameInfo()); - - /* Let the client know that we are here */ this->SendPacket(&packet, client_addr); Debug(net, 7, "Queried from {}", client_addr->GetHostname()); } -void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) -{ - /* Just a fail-safe.. should never happen */ - if (!_network_udp_server) return; - - Packet packet(PACKET_UDP_SERVER_DETAIL_INFO); - - /* Send the amount of active companies */ - packet.Send_uint8 (NETWORK_COMPANY_INFO_VERSION); - packet.Send_uint8 ((uint8)Company::GetNumItems()); - - /* Fetch the latest version of the stats */ - NetworkCompanyStats company_stats[MAX_COMPANIES]; - NetworkPopulateCompanyStats(company_stats); - - /* The minimum company information "blob" size. */ - static const uint MIN_CI_SIZE = 54; - uint max_cname_length = NETWORK_COMPANY_NAME_LENGTH; - - if (!packet.CanWriteToPacket(Company::GetNumItems() * (MIN_CI_SIZE + NETWORK_COMPANY_NAME_LENGTH))) { - /* Assume we can at least put the company information in the packets. */ - assert(packet.CanWriteToPacket(Company::GetNumItems() * MIN_CI_SIZE)); - - /* At this moment the company names might not fit in the - * packet. Check whether that is really the case. */ - - for (;;) { - size_t required = 0; - for (const Company *company : Company::Iterate()) { - char company_name[NETWORK_COMPANY_NAME_LENGTH]; - SetDParam(0, company->index); - GetString(company_name, STR_COMPANY_NAME, company_name + max_cname_length - 1); - required += MIN_CI_SIZE; - required += strlen(company_name); - } - if (packet.CanWriteToPacket(required)) break; - - /* Try again, with slightly shorter strings. */ - assert(max_cname_length > 0); - max_cname_length--; - } - } - - /* Go through all the companies */ - for (const Company *company : Company::Iterate()) { - /* Send the information */ - this->SendCompanyInformation(&packet, company, &company_stats[company->index], max_cname_length); - } - - this->SendPacket(&packet, client_addr); -} - -/** - * A client has requested the names of some NewGRFs. - * - * Replying this can be tricky as we have a limit of UDP_MTU bytes - * in the reply packet and we can send up to 100 bytes per NewGRF - * (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name). - * As UDP_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it - * could be that a packet overflows. To stop this we only reply - * with the first N NewGRFs so that if the first N + 1 NewGRFs - * would be sent, the packet overflows. - * in_reply and in_reply_count are used to keep a list of GRFs to - * send in the reply. - */ -void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) -{ - uint8 num_grfs; - uint i; - - const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT]; - uint8 in_reply_count = 0; - size_t packet_len = 0; - - Debug(net, 7, "NewGRF data request from {}", client_addr->GetAddressAsString()); - - num_grfs = p->Recv_uint8 (); - if (num_grfs > NETWORK_MAX_GRF_COUNT) return; - - for (i = 0; i < num_grfs; i++) { - GRFIdentifier c; - const GRFConfig *f; - - DeserializeGRFIdentifier(p, &c); - - /* Find the matching GRF file */ - f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); - if (f == nullptr) continue; // The GRF is unknown to this server - - /* If the reply might exceed the size of the packet, only reply - * the current list and do not send the other data. - * The name could be an empty string, if so take the filename. */ - packet_len += sizeof(c.grfid) + sizeof(c.md5sum) + - std::min(strlen(f->GetName()) + 1, (size_t)NETWORK_GRF_NAME_LENGTH); - if (packet_len > UDP_MTU - 4) { // 4 is 3 byte header + grf count in reply - break; - } - in_reply[in_reply_count] = f; - in_reply_count++; - } - - if (in_reply_count == 0) return; - - Packet packet(PACKET_UDP_SERVER_NEWGRFS); - packet.Send_uint8(in_reply_count); - for (i = 0; i < in_reply_count; i++) { - char name[NETWORK_GRF_NAME_LENGTH]; - - /* The name could be an empty string, if so take the filename */ - strecpy(name, in_reply[i]->GetName(), lastof(name)); - SerializeGRFIdentifier(&packet, &in_reply[i]->ident); - packet.Send_string(name); - } - - this->SendPacket(&packet, client_addr); -} - ///*** Communication with servers (we are client) ***/ /** Helper class for handling all client side communication. */ class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) override; - void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) override; - void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) override; public: virtual ~ClientNetworkUDPSocketHandler() {} }; void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { - NetworkGameList *item; - - /* Just a fail-safe.. should never happen */ - if (_network_udp_server) return; - Debug(net, 3, "Server response from {}", client_addr->GetAddressAsString()); - /* Find next item */ - item = NetworkGameListAddItem(client_addr->GetAddressAsString(false)); - - /* Clear any existing GRFConfig chain. */ - ClearGRFConfigList(&item->info.grfconfig); - /* Retrieve the NetworkGameInfo from the packet. */ - DeserializeNetworkGameInfo(p, &item->info); - /* Check for compatability with the client. */ - CheckGameCompatibility(item->info); - /* Ensure we consider the server online. */ - item->online = true; - /* Make sure this entry never expires. */ - item->version = INT32_MAX; - - { - /* Checks whether there needs to be a request for names of GRFs and makes - * the request if necessary. GRFs that need to be requested are the GRFs - * that do not exist on the clients system and we do not have the name - * resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER. - * The in_request array and in_request_count are used so there is no need - * to do a second loop over the GRF list, which can be relatively expensive - * due to the string comparisons. */ - const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT]; - const GRFConfig *c; - uint in_request_count = 0; - - for (c = item->info.grfconfig; c != nullptr; c = c->next) { - if (c->status != GCS_NOT_FOUND || strcmp(c->GetName(), UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue; - in_request[in_request_count] = c; - in_request_count++; - } - - if (in_request_count > 0) { - /* There are 'unknown' GRFs, now send a request for them */ - uint i; - Packet packet(PACKET_UDP_CLIENT_GET_NEWGRFS); - - packet.Send_uint8(in_request_count); - for (i = 0; i < in_request_count; i++) { - SerializeGRFIdentifier(&packet, &in_request[i]->ident); - } - - NetworkAddress address = NetworkAddress(ParseConnectionString(item->connection_string, NETWORK_DEFAULT_PORT)); - this->SendPacket(&packet, &address); - } - } - - if (client_addr->GetAddress()->ss_family == AF_INET6) { - item->info.server_name.append(" (IPv6)"); - } - - UpdateNetworkGameWindow(); -} - -void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) -{ - /* packet begins with the protocol version (uint8) - * then an uint16 which indicates how many - * ip:port pairs are in this packet, after that - * an uint32 (ip) and an uint16 (port) for each pair. - */ - - ServerListType type = (ServerListType)(p->Recv_uint8() - 1); - - if (type < SLT_END) { - for (int i = p->Recv_uint16(); i != 0 ; i--) { - sockaddr_storage addr_storage; - memset(&addr_storage, 0, sizeof(addr_storage)); - - if (type == SLT_IPv4) { - addr_storage.ss_family = AF_INET; - ((sockaddr_in*)&addr_storage)->sin_addr.s_addr = TO_LE32(p->Recv_uint32()); - } else { - assert(type == SLT_IPv6); - addr_storage.ss_family = AF_INET6; - byte *addr = (byte*)&((sockaddr_in6*)&addr_storage)->sin6_addr; - for (uint i = 0; i < sizeof(in6_addr); i++) *addr++ = p->Recv_uint8(); - } - NetworkAddress addr(addr_storage, type == SLT_IPv4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6)); - addr.SetPort(p->Recv_uint16()); - - /* Somehow we reached the end of the packet */ - if (this->HasClientQuit()) return; - - DoNetworkUDPQueryServer(addr.GetAddressAsString(false), false, false); - } - } -} - -/** The return of the client's request of the names of some NewGRFs */ -void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) -{ - uint8 num_grfs; - uint i; - - Debug(net, 7, "NewGRF data reply from {}", client_addr->GetAddressAsString()); - - num_grfs = p->Recv_uint8 (); - if (num_grfs > NETWORK_MAX_GRF_COUNT) return; - - for (i = 0; i < num_grfs; i++) { - GRFIdentifier c; - - DeserializeGRFIdentifier(p, &c); - std::string name = p->Recv_string(NETWORK_GRF_NAME_LENGTH); - - /* An empty name is not possible under normal circumstances - * and causes problems when showing the NewGRF list. */ - if (name.empty()) continue; - - /* Try to find the GRFTextWrapper for the name of this GRF ID and MD5sum tuple. - * If it exists and not resolved yet, then name of the fake GRF is - * overwritten with the name from the reply. */ - GRFTextWrapper unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); - if (unknown_name && strcmp(GetGRFStringFromGRFText(unknown_name), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { - AddGRFTextToList(unknown_name, name); - } - } + NetworkAddServer(client_addr->GetAddressAsString(false), false, true); } /** Broadcast to all ips */ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) { for (NetworkAddress &addr : _broadcast_list) { - Packet p(PACKET_UDP_CLIENT_FIND_SERVER); - Debug(net, 5, "Broadcasting to {}", addr.GetHostname()); + Packet p(PACKET_UDP_CLIENT_FIND_SERVER); socket->SendPacket(&p, &addr, true, true); } } - -/** Request the the server-list from the master server */ -void NetworkUDPQueryMasterServer() -{ - Packet p(PACKET_UDP_CLIENT_GET_LIST); - NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT); - - /* packet only contains protocol version */ - p.Send_uint8(NETWORK_MASTER_SERVER_VERSION); - p.Send_uint8(SLT_AUTODETECT); - - std::lock_guard<std::mutex> lock(_udp_client.mutex); - _udp_client.socket->SendPacket(&p, &out_addr, true); - - Debug(net, 6, "Master server queried at {}", out_addr.GetAddressAsString()); -} - /** Find all servers */ void NetworkUDPSearchGame() { @@ -446,8 +130,6 @@ void NetworkUDPInitialize() Debug(net, 3, "Initializing UDP listeners"); assert(_udp_client.socket == nullptr && _udp_server.socket == nullptr); - std::scoped_lock lock(_udp_client.mutex, _udp_server.mutex); - _udp_client.socket = new ClientNetworkUDPSocketHandler(); NetworkAddressList server; @@ -461,7 +143,6 @@ void NetworkUDPInitialize() /** Start the listening of the UDP server component. */ void NetworkUDPServerListen() { - std::lock_guard<std::mutex> lock(_udp_server.mutex); _network_udp_server = _udp_server.socket->Listen(); } diff --git a/src/network/network_udp.h b/src/network/network_udp.h index 735e5f223..b640da018 100644 --- a/src/network/network_udp.h +++ b/src/network/network_udp.h @@ -14,8 +14,6 @@ void NetworkUDPInitialize(); void NetworkUDPSearchGame(); -void NetworkUDPQueryMasterServer(); -void NetworkUDPQueryServer(const std::string &connection_string, bool manually = false); void NetworkUDPClose(); void NetworkUDPServerListen(); void NetworkBackgroundUDPLoop(); diff --git a/src/settings_type.h b/src/settings_type.h index 05efc11e5..3377bdede 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -270,7 +270,7 @@ struct NetworkSettings { std::string server_password; ///< password for joining this server std::string rcon_password; ///< password for rconsole (server side) std::string admin_password; ///< password for the admin network - bool server_advertise; ///< advertise the server to the masterserver + bool server_advertise; ///< Advertise the server to the game coordinator. std::string client_name; ///< name of the player (as client) std::string default_company_pass; ///< default password for new companies in encrypted form std::string connect_to_ip; ///< default for the "Add server" query |