summaryrefslogtreecommitdiff
path: root/src/network/core
diff options
context:
space:
mode:
authorPatric Stout <truebrain@openttd.org>2021-07-03 11:04:32 +0200
committerPatric Stout <github@truebrain.nl>2021-07-10 20:17:07 +0200
commitb1280fd17ebaf9e4df086b63074d0bd8b8c9155d (patch)
tree6a421d4e079a765ba21181ad01ab21d13434ba9a /src/network/core
parente1e2212e0e09c7739f2eb8a4421a9ed7982801f5 (diff)
downloadopenttd-b1280fd17ebaf9e4df086b63074d0bd8b8c9155d.tar.xz
Add: use Game Coordinator to annouce public servers
Diffstat (limited to 'src/network/core')
-rw-r--r--src/network/core/CMakeLists.txt2
-rw-r--r--src/network/core/config.h73
-rw-r--r--src/network/core/tcp_coordinator.cpp80
-rw-r--r--src/network/core/tcp_coordinator.h115
4 files changed, 236 insertions, 34 deletions
diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt
index bf713be99..6eb255f6f 100644
--- a/src/network/core/CMakeLists.txt
+++ b/src/network/core/CMakeLists.txt
@@ -20,6 +20,8 @@ add_files(
tcp_content.cpp
tcp_content.h
tcp_content_type.h
+ tcp_coordinator.cpp
+ tcp_coordinator.h
tcp_game.cpp
tcp_game.h
tcp_http.cpp
diff --git a/src/network/core/config.h b/src/network/core/config.h
index 6d6038ec7..e0ec63a0c 100644
--- a/src/network/core/config.h
+++ b/src/network/core/config.h
@@ -14,6 +14,8 @@
/** 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 */
static const char * const NETWORK_CONTENT_SERVER_HOST = "content.openttd.org";
/** DNS hostname of the HTTP-content mirror server */
@@ -23,14 +25,15 @@ 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_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)
-static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP)
-static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network
-static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP)
+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)
+static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP)
+static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network
+static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP)
-static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet
+static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet
/*
* Technically a TCP packet could become 64kiB, however the high bit is kept so it becomes possible in the future
* to go to (significantly) larger packets if needed. This would entail a strategy such as employed for UTF-8.
@@ -45,40 +48,42 @@ static const uint16 UDP_MTU = 1460; ///< Number of
* Send_uint16(GB(size, 16, 14) | 0b10 << 14)
* Send_uint16(GB(size, 0, 16))
*/
-static const uint16 TCP_MTU = 32767; ///< Number of bytes we can pack in a single TCP packet
-static const uint16 COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility
+static const uint16 TCP_MTU = 32767; ///< Number of bytes we can pack in a single TCP packet
+static const uint16 COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility
-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_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'
-static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0'
-static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0'
-static const uint NETWORK_HOSTNAME_PORT_LENGTH = 80 + 6; ///< The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port number (with a max of 65536)
-static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0'
-static const uint NETWORK_REVISION_LENGTH = 33; ///< The maximum length of the revision, in bytes including '\0'
-static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH)
-static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0'
-static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0'
-static const uint NETWORK_RCONCOMMAND_LENGTH = 500; ///< The maximum length of a rconsole command, in bytes including '\0'
-static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = COMPAT_MTU-3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than COMPAT_MTU including header (3 bytes)
-static const uint NETWORK_CHAT_LENGTH = 900; ///< The maximum length of a chat message, in bytes including '\0'
-static const uint NETWORK_CONTENT_FILENAME_LENGTH = 48; ///< The maximum length of a content's filename, in bytes including '\0'.
-static const uint NETWORK_CONTENT_NAME_LENGTH = 32; ///< The maximum length of a content's name, in bytes including '\0'.
-static const uint NETWORK_CONTENT_VERSION_LENGTH = 16; ///< The maximum length of a content's version, in bytes including '\0'.
-static const uint NETWORK_CONTENT_URL_LENGTH = 96; ///< The maximum length of a content's url, in bytes including '\0'.
-static const uint NETWORK_CONTENT_DESC_LENGTH = 512; ///< The maximum length of a content's description, in bytes including '\0'.
-static const uint NETWORK_CONTENT_TAG_LENGTH = 32; ///< The maximum length of a content's tag, in bytes including '\0'.
+static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0'
+static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0'
+static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0'
+static const uint NETWORK_HOSTNAME_PORT_LENGTH = 80 + 6; ///< The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port number (with a max of 65536)
+static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0'
+static const uint NETWORK_REVISION_LENGTH = 33; ///< The maximum length of the revision, in bytes including '\0'
+static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH)
+static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0'
+static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0'
+static const uint NETWORK_RCONCOMMAND_LENGTH = 500; ///< The maximum length of a rconsole command, in bytes including '\0'
+static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = COMPAT_MTU - 3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than COMPAT_MTU including header (3 bytes)
+static const uint NETWORK_CHAT_LENGTH = 900; ///< The maximum length of a chat message, in bytes including '\0'
+static const uint NETWORK_CONTENT_FILENAME_LENGTH = 48; ///< The maximum length of a content's filename, in bytes including '\0'.
+static const uint NETWORK_CONTENT_NAME_LENGTH = 32; ///< The maximum length of a content's name, in bytes including '\0'.
+static const uint NETWORK_CONTENT_VERSION_LENGTH = 16; ///< The maximum length of a content's version, in bytes including '\0'.
+static const uint NETWORK_CONTENT_URL_LENGTH = 96; ///< The maximum length of a content's url, in bytes including '\0'.
+static const uint NETWORK_CONTENT_DESC_LENGTH = 512; ///< The maximum length of a content's description, in bytes including '\0'.
+static const uint NETWORK_CONTENT_TAG_LENGTH = 32; ///< The maximum length of a content's tag, in bytes including '\0'.
+static const uint NETWORK_ERROR_DETAIL_LENGTH = 100; ///< The maximum length of the error detail, in bytes including '\0'
-static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maximum length of the name of a GRF
+static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maximum length of the name of a GRF
/**
* Maximum number of GRFs that can be sent.
* This limit is reached when PACKET_UDP_SERVER_RESPONSE reaches the maximum size of UDP_MTU bytes.
*/
-static const uint NETWORK_MAX_GRF_COUNT = 62;
+static const uint NETWORK_MAX_GRF_COUNT = 62;
/**
* The number of landscapes in OpenTTD.
@@ -88,6 +93,6 @@ static const uint NETWORK_MAX_GRF_COUNT = 62;
* there is a compile assertion to check that this NUM_LANDSCAPE is equal
* to NETWORK_NUM_LANDSCAPES.
*/
-static const uint NETWORK_NUM_LANDSCAPES = 4;
+static const uint NETWORK_NUM_LANDSCAPES = 4;
#endif /* NETWORK_CORE_CONFIG_H */
diff --git a/src/network/core/tcp_coordinator.cpp b/src/network/core/tcp_coordinator.cpp
new file mode 100644
index 000000000..1cf5cd676
--- /dev/null
+++ b/src/network/core/tcp_coordinator.cpp
@@ -0,0 +1,80 @@
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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/>.
+ */
+
+/**
+ * @file tcp_coordinator.cpp Basic functions to receive and send Game Coordinator packets.
+ */
+
+#include "../../stdafx.h"
+#include "../../date_func.h"
+#include "../../debug.h"
+#include "tcp_coordinator.h"
+
+#include "../../safeguards.h"
+
+/**
+ * Handle the given packet, i.e. pass it to the right.
+ * parser receive command.
+ * @param p The packet to handle.
+ * @return True iff we should immediately handle further packets.
+ */
+bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p)
+{
+ PacketCoordinatorType type = (PacketCoordinatorType)p->Recv_uint8();
+
+ switch (type) {
+ case PACKET_COORDINATOR_GC_ERROR: return this->Receive_GC_ERROR(p);
+ case PACKET_COORDINATOR_SERVER_REGISTER: return this->Receive_SERVER_REGISTER(p);
+ case PACKET_COORDINATOR_GC_REGISTER_ACK: return this->Receive_GC_REGISTER_ACK(p);
+ case PACKET_COORDINATOR_SERVER_UPDATE: return this->Receive_SERVER_UPDATE(p);
+
+ default:
+ Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type);
+ return false;
+ }
+}
+
+/**
+ * Receive a packet at TCP level.
+ * @return Whether at least one packet was received.
+ */
+bool NetworkCoordinatorSocketHandler::ReceivePackets()
+{
+ /*
+ * We read only a few of the packets. This allows the GUI to update when
+ * a large set of servers is being received. Otherwise the interface
+ * "hangs" while the game is updating the server-list.
+ *
+ * What arbitrary number to choose is the ultimate question though.
+ */
+ Packet *p;
+ static const int MAX_PACKETS_TO_RECEIVE = 42;
+ int i = MAX_PACKETS_TO_RECEIVE;
+ while (--i != 0 && (p = this->ReceivePacket()) != nullptr) {
+ bool cont = this->HandlePacket(p);
+ delete p;
+ if (!cont) return true;
+ }
+
+ return i != MAX_PACKETS_TO_RECEIVE - 1;
+}
+
+/**
+ * Helper for logging receiving invalid packets.
+ * @param type The received packet type.
+ * @return Always false, as it's an error.
+ */
+bool NetworkCoordinatorSocketHandler::ReceiveInvalidPacket(PacketCoordinatorType type)
+{
+ Debug(net, 0, "[tcp/coordinator] Received illegal packet type {}", type);
+ return false;
+}
+
+bool NetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_ERROR); }
+bool NetworkCoordinatorSocketHandler::Receive_SERVER_REGISTER(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_REGISTER); }
+bool NetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_REGISTER_ACK); }
+bool NetworkCoordinatorSocketHandler::Receive_SERVER_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERVER_UPDATE); }
diff --git a/src/network/core/tcp_coordinator.h b/src/network/core/tcp_coordinator.h
new file mode 100644
index 000000000..a438f07aa
--- /dev/null
+++ b/src/network/core/tcp_coordinator.h
@@ -0,0 +1,115 @@
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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/>.
+ */
+
+/**
+ * @file tcp_coordinator.h Basic functions to receive and send TCP packets to/from the Game Coordinator server.
+ */
+
+#ifndef NETWORK_CORE_TCP_COORDINATOR_H
+#define NETWORK_CORE_TCP_COORDINATOR_H
+
+#include "os_abstraction.h"
+#include "tcp.h"
+#include "packet.h"
+#include "game_info.h"
+
+/**
+ * Enum with all types of TCP Game Coordinator packets. The order MUST not be changed.
+ *
+ * GC -> packets from Game Coordinator to either Client or Server.
+ * SERVER -> packets from Server to Game Coordinator.
+ * CLIENT -> packets from Client to Game Coordinator.
+ **/
+enum PacketCoordinatorType {
+ PACKET_COORDINATOR_GC_ERROR, ///< Game Coordinator indicates there was an error.
+ PACKET_COORDINATOR_SERVER_REGISTER, ///< Server registration.
+ PACKET_COORDINATOR_GC_REGISTER_ACK, ///< Game Coordinator accepts the registration.
+ PACKET_COORDINATOR_SERVER_UPDATE, ///< Server sends an set intervals an update of the server.
+ PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period).
+};
+
+/**
+ * The type of connection the Game Coordinator can detect we have.
+ */
+enum ConnectionType {
+ CONNECTION_TYPE_UNKNOWN, ///< The Game Coordinator hasn't informed us yet what type of connection we have.
+ CONNECTION_TYPE_ISOLATED, ///< The Game Coordinator failed to find a way to connect to your server. Nobody will be able to join.
+ CONNECTION_TYPE_DIRECT, ///< The Game Coordinator can directly connect to your server.
+};
+
+/**
+ * The type of error from the Game Coordinator.
+ */
+enum NetworkCoordinatorErrorType {
+ NETWORK_COORDINATOR_ERROR_UNKNOWN, ///< There was an unknown error.
+ NETWORK_COORDINATOR_ERROR_REGISTRATION_FAILED, ///< Your request for registration failed.
+};
+
+/** Base socket handler for all Game Coordinator TCP sockets. */
+class NetworkCoordinatorSocketHandler : public NetworkTCPSocketHandler {
+protected:
+ bool ReceiveInvalidPacket(PacketCoordinatorType type);
+
+ /**
+ * Game Coordinator indicates there was an error. This can either be a
+ * permanent error causing the connection to be dropped, or in response
+ * to a request that is invalid.
+ *
+ * uint8 Type of error (see NetworkCoordinatorErrorType).
+ * string Details of the error.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_GC_ERROR(Packet *p);
+
+ /**
+ * Server is starting a multiplayer game and wants to let the
+ * Game Coordinator know.
+ *
+ * uint8 Game Coordinator protocol version.
+ * uint8 Type of game (see ServerGameType).
+ * uint16 Local port of the server.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_SERVER_REGISTER(Packet *p);
+
+ /**
+ * Game Coordinator acknowledges the registration.
+ *
+ * uint8 Type of connection was detected (see ConnectionType).
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_GC_REGISTER_ACK(Packet *p);
+
+ /**
+ * Send an update of the current state of the server to the Game Coordinator.
+ *
+ * uint8 Game Coordinator protocol version.
+ * Serialized NetworkGameInfo. See game_info.hpp for details.
+ *
+ * @param p The packet that was just received.
+ * @return True upon success, otherwise false.
+ */
+ virtual bool Receive_SERVER_UPDATE(Packet *p);
+
+ bool HandlePacket(Packet *p);
+public:
+ /**
+ * Create a new cs socket handler for a given cs.
+ * @param s The socket we are connected with.
+ */
+ NetworkCoordinatorSocketHandler(SOCKET s = INVALID_SOCKET) : NetworkTCPSocketHandler(s) {}
+
+ bool ReceivePackets();
+};
+
+#endif /* NETWORK_CORE_TCP_COORDINATOR_H */