diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/core/config.h | 2 | ||||
-rw-r--r-- | src/network/core/tcp_admin.cpp | 119 | ||||
-rw-r--r-- | src/network/core/tcp_admin.h | 137 | ||||
-rw-r--r-- | src/network/network_admin.cpp | 202 | ||||
-rw-r--r-- | src/network/network_admin.h | 62 | ||||
-rw-r--r-- | src/network/network_type.h | 8 |
6 files changed, 530 insertions, 0 deletions
diff --git a/src/network/core/config.h b/src/network/core/config.h index 2df6162e2..584e0382a 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -29,10 +29,12 @@ static const uint16 NETWORK_MASTER_SERVER_PORT = 3978; ///< The default port 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 too (TCP) static const uint16 SEND_MTU = 1460; ///< Number of bytes we can pack in a single packet +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? diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp new file mode 100644 index 000000000..2d68fc68b --- /dev/null +++ b/src/network/core/tcp_admin.cpp @@ -0,0 +1,119 @@ +/* $Id$ */ + +/* + * 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_admin.cpp Basic functions to receive and send TCP packets to and from the admin network. + */ + +#ifdef ENABLE_NETWORK + +#include "../../stdafx.h" + +#include "../network_internal.h" +#include "tcp_admin.h" +#include "../../debug.h" + +NetworkAdminSocketHandler::NetworkAdminSocketHandler(SOCKET s) +{ + this->sock = s; +} + +NetworkAdminSocketHandler::~NetworkAdminSocketHandler() +{ +} + +NetworkRecvStatus NetworkAdminSocketHandler::CloseConnection(bool error) +{ + delete this; + return NETWORK_RECV_STATUS_CONN_LOST; +} + +/** + * Defines a simple (switch) case for each network packet. + * @param type the packet type to create the case for. + */ +#define ADMIN_COMMAND(type) case type: return this->NetworkPacketReceive_ ## type ## _command(p); break; + +/** + * Handle the given packet, i.e. pass it to the right parser receive command. + * @param p the packet to handle. + * @return #NetworkRecvStatus of handling. + */ +NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) +{ + PacketAdminType type = (PacketAdminType)p->Recv_uint8(); + + switch (this->HasClientQuit() ? INVALID_ADMIN_PACKET : type) { + ADMIN_COMMAND(ADMIN_PACKET_ADMIN_JOIN) + ADMIN_COMMAND(ADMIN_PACKET_ADMIN_QUIT) + + ADMIN_COMMAND(ADMIN_PACKET_SERVER_FULL) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_BANNED) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_ERROR) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_PROTOCOL) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_WELCOME) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_NEWGAME) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_SHUTDOWN) + + default: + if (this->HasClientQuit()) { + DEBUG(net, 0, "[tcp/admin] received invalid packet type %d from '%s' (%s)", type, this->admin_name, this->admin_version); + } else { + DEBUG(net, 0, "[tcp/admin] received illegal packet from '%s' (%s)", this->admin_name, this->admin_version); + } + + this->CloseConnection(); + return NETWORK_RECV_STATUS_MALFORMED_PACKET; + } +} + +/** + * Do the actual receiving of packets. + * As long as HandlePacket returns OKAY packets are handled. Upon + * failure, or no more packets to process the last result of + * HandlePacket is returned. + * @return #NetworkRecvStatus of the last handled packet. + */ +NetworkRecvStatus NetworkAdminSocketHandler::Recv_Packets() +{ + Packet *p; + while ((p = this->Recv_Packet()) != NULL) { + NetworkRecvStatus res = HandlePacket(p); + if (res != NETWORK_RECV_STATUS_OKAY) return res; + } + + return NETWORK_RECV_STATUS_OKAY; +} + +/** + * Create stub implementations for all receive commands that only + * show a warning that the given command is not available for the + * socket where the packet came from. + * @param type the packet type to create the stub for. + */ +#define DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(type) \ +NetworkRecvStatus NetworkAdminSocketHandler::NetworkPacketReceive_## type ##_command(Packet *p) \ +{ \ + DEBUG(net, 0, "[tcp/admin] received illegal packet type %d from admin %s (%s)", \ + type, this->admin_name, this->admin_version); \ + return NETWORK_RECV_STATUS_MALFORMED_PACKET; \ +} + +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_SERVER_FULL) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_BANNED) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_ERROR) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_PROTOCOL) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_WELCOME) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_NEWGAME) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_SHUTDOWN) + +#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h new file mode 100644 index 000000000..dae41c5f5 --- /dev/null +++ b/src/network/core/tcp_admin.h @@ -0,0 +1,137 @@ +/* $Id$ */ + +/* + * 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_admin.h Basic functions to receive and send TCP packets to and from the admin network. + */ + +#ifndef NETWORK_CORE_TCP_ADMIN_H +#define NETWORK_CORE_TCP_ADMIN_H + +#include "os_abstraction.h" +#include "tcp.h" +#include "../network_type.h" +#include "../../core/pool_type.hpp" + +#ifdef ENABLE_NETWORK + +/** + * Enum with types of TCP packets specific to the admin network. + * This protocol may only be extended to ensure stability. + */ +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_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. + ADMIN_PACKET_SERVER_ERROR, ///< The server tells the admin an error has occurred. + ADMIN_PACKET_SERVER_PROTOCOL, ///< The server tells the admin its protocol version. + ADMIN_PACKET_SERVER_WELCOME, ///< The server welcomes the admin to a game. + ADMIN_PACKET_SERVER_NEWGAME, ///< The server tells the admin its going to start a new game. + ADMIN_PACKET_SERVER_SHUTDOWN, ///< The server tells the admin its shutting down. + + INVALID_ADMIN_PACKET = 0xFF, ///< An invalid marker for admin packets. +}; + +/** Status of an admin. */ +enum AdminStatus { + ADMIN_STATUS_INACTIVE, ///< The admin is not connected nor active. + ADMIN_STATUS_ACTIVE, ///< The admin is active. + ADMIN_STATUS_END ///< Must ALWAYS be on the end of this list!! (period) +}; + +#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) + +/** Main socket handler for admin related connections. */ +class NetworkAdminSocketHandler : public NetworkTCPSocketHandler { +protected: + char admin_name[NETWORK_CLIENT_NAME_LENGTH]; ///< Name of the admin. + char admin_version[NETWORK_REVISION_LENGTH]; ///< Version string of the admin. + AdminStatus status; ///< Status of this admin. + + /** + * Join the admin network: + * string Password the server is expecting for this network. + * string Name of the application being used to connect. + * string Version string of the application being used to connect. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_JOIN); + + /** + * Notification to the server that this admin is quitting. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_QUIT); + + /** + * The server is full (connection gets closed). + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_FULL); + + /** + * The source IP address is banned (connection gets closed). + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_BANNED); + + /** + * An error was caused by this admin connection (connection gets closed). + * uint8 NetworkErrorCode the error caused. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_ERROR); + + /** + * Inform a just joined admin about the protocol specifics: + * uint8 Protocol version. + * bool Further protocol data follows (repeats through all update packet types). + * uint16 Update packet type. + * uint16 Frequencies allowed for this update packet (bitwise). + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_PROTOCOL); + + /** + * Welcome a connected admin to the game: + * string Name of the Server (e.g. as advertised to master server). + * string OpenTTD version string. + * bool Server is dedicated. + * string Name of the Map. + * uint32 Random seed of the Map. + * uint8 Landscape of the Map. + * uint32 Start date of the Map. + * uint16 Map width. + * uint16 Map height. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_WELCOME); + + /** + * Notification about a newgame. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_NEWGAME); + + /** + * Notification about the server shutting down. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_SHUTDOWN); + + NetworkRecvStatus HandlePacket(Packet *p); +public: + NetworkRecvStatus CloseConnection(bool error = true); + + NetworkAdminSocketHandler(SOCKET s); + ~NetworkAdminSocketHandler(); + + NetworkRecvStatus Recv_Packets(); + + const char *Recv_Command(Packet *p, CommandPacket *cp); + void Send_Command(Packet *p, const CommandPacket *cp); +}; + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_TCP_ADMIN_H */ diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp new file mode 100644 index 000000000..90da9ac6a --- /dev/null +++ b/src/network/network_admin.cpp @@ -0,0 +1,202 @@ +/* $Id$ */ + +/* + * 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 network_admin.cpp Server part of the admin network protocol. */ + +#ifdef ENABLE_NETWORK + +#include "../stdafx.h" +#include "../debug.h" +#include "../strings_func.h" +#include "../date_func.h" +#include "network_admin.h" +#include "network.h" +#include "network_base.h" +#include "../company_base.h" +#include "../console_func.h" +#include "../core/pool_func.hpp" +#include "../map_func.h" +#include "../rev.h" + +#include "table/strings.h" + +/* This file handles all the admin network commands. */ + +/** The amount of admins connected. */ +byte _network_admins_connected = 0; + +NetworkAdminSocketPool _networkadminsocket_pool("NetworkAdminSocket"); +INSTANTIATE_POOL_METHODS(NetworkAdminSocket) + +/** + * Create a new socket for the server side of the admin network. + * @param s The socket to connect with. + */ +ServerNetworkAdminSocketHandler::ServerNetworkAdminSocketHandler(SOCKET s) : NetworkAdminSocketHandler(s) +{ + _network_admins_connected++; + this->status = ADMIN_STATUS_INACTIVE; +} + +/** + * Clear everything related to this admin. + */ +ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler() +{ + _network_admins_connected--; + DEBUG(net, 1, "[admin] '%s' (%s) has disconnected", this->admin_name, this->admin_version); +} + +/** + * Whether a connection is allowed or not at this moment. + * @return Whether the connection is allowed. + */ +/* static */ bool ServerNetworkAdminSocketHandler::AllowConnection() +{ + return !StrEmpty(_settings_client.network.admin_password) && _network_admins_connected < MAX_ADMINS; +} + +/** Send the packets for the server sockets. */ +/* static */ void ServerNetworkAdminSocketHandler::Send() +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + if (as->writable) { + as->Send_Packets(); + } + } +} + +/* static */ void ServerNetworkAdminSocketHandler::AcceptConnection(SOCKET s, const NetworkAddress &address) +{ + ServerNetworkAdminSocketHandler *as = new ServerNetworkAdminSocketHandler(s); + as->address = address; // Save the IP of the client +} + +/*********** + * Sending functions for admin network + ************/ + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode error) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_ERROR); + + p->Send_uint8(error); + this->Send_Packet(p); + + char str[100]; + StringID strid = GetNetworkErrorMsg(error); + GetString(str, strid, lastof(str)); + + DEBUG(net, 1, "[admin] the admin '%s' (%s) made an error and has been disconnected. Reason: '%s'", this->admin_name, this->admin_version, str); + + return this->CloseConnection(true); +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol() +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_PROTOCOL); + + /* announce the protocol version */ + p->Send_uint8(NETWORK_GAME_ADMIN_VERSION); + + p->Send_bool(false); + this->Send_Packet(p); + + return this->SendWelcome(); +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome() +{ + this->status = ADMIN_STATUS_ACTIVE; + + Packet *p = new Packet(ADMIN_PACKET_SERVER_WELCOME); + + p->Send_string(_settings_client.network.server_name); + p->Send_string(_openttd_revision); + p->Send_bool (_network_dedicated); + + p->Send_string(_network_game_info.map_name); + p->Send_uint32(_settings_game.game_creation.generation_seed); + p->Send_uint8 (_settings_game.game_creation.landscape); + p->Send_uint32(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1)); + p->Send_uint16(MapSizeX()); + p->Send_uint16(MapSizeY()); + + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendNewGame() +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_NEWGAME); + this->Send_Packet(p); + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendShutdown() +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_SHUTDOWN); + this->Send_Packet(p); + return NETWORK_RECV_STATUS_OKAY; +} + +/*********** + * Receiving functions + ************/ + +DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_JOIN) +{ + if (this->status != ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); + + char password[NETWORK_PASSWORD_LENGTH]; + p->Recv_string(password, sizeof(password)); + + if (StrEmpty(_settings_client.network.admin_password) || + strcmp(password, _settings_client.network.admin_password) != 0) { + /* Password is invalid */ + return this->SendError(NETWORK_ERROR_WRONG_PASSWORD); + } + + p->Recv_string(this->admin_name, sizeof(this->admin_name)); + p->Recv_string(this->admin_version, sizeof(this->admin_version)); + + if (StrEmpty(this->admin_name) || StrEmpty(this->admin_version)) { + /* no name or version supplied */ + return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET); + } + + DEBUG(net, 1, "[admin] '%s' (%s) has connected", this->admin_name, this->admin_version); + + return this->SendProtocol(); +} + +DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_QUIT) +{ + /* The admin is leaving nothing else to do */ + return this->CloseConnection(); +} + +/* + * Useful wrapper functions + */ + +/** + * Send a Welcome packet to all connected admins + */ +void ServerNetworkAdminSocketHandler::WelcomeAll() +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + as->SendWelcome(); + } +} + +#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_admin.h b/src/network/network_admin.h new file mode 100644 index 000000000..ffa37ed44 --- /dev/null +++ b/src/network/network_admin.h @@ -0,0 +1,62 @@ +/* $Id$ */ + +/* + * 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 network_admin.h Server part of the admin network protocol. */ + +#ifndef NETWORK_ADMIN_H +#define NETWORK_ADMIN_H + +#ifdef ENABLE_NETWORK + +#include "network_internal.h" +#include "core/tcp_listen.h" +#include "core/tcp_admin.h" + +class ServerNetworkAdminSocketHandler; +typedef Pool<ServerNetworkAdminSocketHandler, AdminIndex, 2, MAX_ADMINS> NetworkAdminSocketPool; +extern NetworkAdminSocketPool _networkadminsocket_pool; + +/** Class for handling the server side of the game connection. */ +class ServerNetworkAdminSocketHandler : public NetworkAdminSocketPool::PoolItem<&_networkadminsocket_pool>, public NetworkAdminSocketHandler, public TCPListenHandler<ServerNetworkAdminSocketHandler, ADMIN_PACKET_SERVER_FULL, ADMIN_PACKET_SERVER_BANNED> { +protected: + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_JOIN); + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_QUIT); + + NetworkRecvStatus SendProtocol(); +public: + NetworkAddress address; ///< Address of the admin. + + ServerNetworkAdminSocketHandler(SOCKET s); + ~ServerNetworkAdminSocketHandler(); + + NetworkRecvStatus SendError(NetworkErrorCode error); + NetworkRecvStatus SendWelcome(); + NetworkRecvStatus SendNewGame(); + NetworkRecvStatus SendShutdown(); + + static void Send(); + static void AcceptConnection(SOCKET s, const NetworkAddress &address); + static bool AllowConnection(); + static void WelcomeAll(); + + /** + * Get the name used by the listener. + * @return the name to show in debug logs and the like. + */ + static const char *GetName() + { + return "admin"; + } +}; + +#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) + +#endif /* ENABLE_NETWORK */ +#endif /* NETWORK_ADMIN_H */ diff --git a/src/network/network_type.h b/src/network/network_type.h index 5b83620e6..f40a1cdd5 100644 --- a/src/network/network_type.h +++ b/src/network/network_type.h @@ -49,6 +49,14 @@ enum ClientID { /** Indices into the client tables */ typedef uint8 ClientIndex; +/** Indices into the admin tables. */ +typedef uint8 AdminIndex; + +/** Maximum number of allowed admins. */ +static const AdminIndex MAX_ADMINS = 16; +/** An invalid admin marker. */ +static const AdminIndex INVALID_ADMIN_ID = UINT8_MAX; + /** Simple calculated statistics of a company */ struct NetworkCompanyStats { uint16 num_vehicle[NETWORK_VEH_END]; ///< How many vehicles are there of this type? |