summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--projects/openttd_vs100.vcxproj4
-rw-r--r--projects/openttd_vs100.vcxproj.filters12
-rw-r--r--projects/openttd_vs80.vcproj16
-rw-r--r--projects/openttd_vs90.vcproj16
-rw-r--r--source.list4
-rw-r--r--src/network/core/config.h2
-rw-r--r--src/network/core/tcp_admin.cpp119
-rw-r--r--src/network/core/tcp_admin.h137
-rw-r--r--src/network/network_admin.cpp202
-rw-r--r--src/network/network_admin.h62
-rw-r--r--src/network/network_type.h8
-rw-r--r--src/settings_type.h1
-rw-r--r--src/table/settings.h1
13 files changed, 584 insertions, 0 deletions
diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj
index 69e635eed..34173c190 100644
--- a/projects/openttd_vs100.vcxproj
+++ b/projects/openttd_vs100.vcxproj
@@ -331,6 +331,7 @@
<ClCompile Include="..\src\mixer.cpp" />
<ClCompile Include="..\src\music.cpp" />
<ClCompile Include="..\src\network\network.cpp" />
+ <ClCompile Include="..\src\network\network_admin.cpp" />
<ClCompile Include="..\src\network\network_client.cpp" />
<ClCompile Include="..\src\network\network_command.cpp" />
<ClCompile Include="..\src\network\network_content.cpp" />
@@ -457,6 +458,7 @@
<ClInclude Include="..\src\map_type.h" />
<ClInclude Include="..\src\mixer.h" />
<ClInclude Include="..\src\network\network.h" />
+ <ClInclude Include="..\src\network\network_admin.h" />
<ClInclude Include="..\src\network\network_base.h" />
<ClInclude Include="..\src\network\network_client.h" />
<ClInclude Include="..\src\network\network_content.h" />
@@ -1039,6 +1041,8 @@
<ClInclude Include="..\src\network\core\tcp_content.h" />
<ClCompile Include="..\src\network\core\tcp_game.cpp" />
<ClInclude Include="..\src\network\core\tcp_game.h" />
+ <ClCompile Include="..\src\network\core\tcp_admin.cpp" />
+ <ClInclude Include="..\src\network\core\tcp_admin.h" />
<ClCompile Include="..\src\network\core\tcp_http.cpp" />
<ClInclude Include="..\src\network\core\tcp_http.h" />
<ClInclude Include="..\src\network\core\tcp_listen.h" />
diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters
index 98740669e..af54dea30 100644
--- a/projects/openttd_vs100.vcxproj.filters
+++ b/projects/openttd_vs100.vcxproj.filters
@@ -213,6 +213,9 @@
<ClCompile Include="..\src\network\network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="..\src\network\network_admin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="..\src\network\network_client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -591,6 +594,9 @@
<ClInclude Include="..\src\network\network.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="..\src\network\network_admin.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="..\src\network\network_base.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -2337,6 +2343,12 @@
<ClInclude Include="..\src\network\core\tcp_game.h">
<Filter>Network Core</Filter>
</ClInclude>
+ <ClCompile Include="..\src\network\core\tcp_admin.cpp">
+ <Filter>Network Core</Filter>
+ </ClCompile>
+ <ClInclude Include="..\src\network\core\tcp_admin.h">
+ <Filter>Network Core</Filter>
+ </ClInclude>
<ClCompile Include="..\src\network\core\tcp_http.cpp">
<Filter>Network Core</Filter>
</ClCompile>
diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj
index 1e8fa9d97..eb9d856b3 100644
--- a/projects/openttd_vs80.vcproj
+++ b/projects/openttd_vs80.vcproj
@@ -595,6 +595,10 @@
>
</File>
<File
+ RelativePath=".\..\src\network\network_admin.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\network\network_client.cpp"
>
</File>
@@ -1103,6 +1107,10 @@
>
</File>
<File
+ RelativePath=".\..\src\network\network_admin.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\network\network_base.h"
>
</File>
@@ -3511,6 +3519,14 @@
>
</File>
<File
+ RelativePath=".\..\src\network\core\tcp_admin.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\network\core\tcp_admin.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\network\core\tcp_http.cpp"
>
</File>
diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj
index dde8192f0..1afdab103 100644
--- a/projects/openttd_vs90.vcproj
+++ b/projects/openttd_vs90.vcproj
@@ -592,6 +592,10 @@
>
</File>
<File
+ RelativePath=".\..\src\network\network_admin.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\network\network_client.cpp"
>
</File>
@@ -1100,6 +1104,10 @@
>
</File>
<File
+ RelativePath=".\..\src\network\network_admin.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\network\network_base.h"
>
</File>
@@ -3508,6 +3516,14 @@
>
</File>
<File
+ RelativePath=".\..\src\network\core\tcp_admin.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\network\core\tcp_admin.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\network\core\tcp_http.cpp"
>
</File>
diff --git a/source.list b/source.list
index c59f96d4d..528a7b987 100644
--- a/source.list
+++ b/source.list
@@ -39,6 +39,7 @@ misc.cpp
mixer.cpp
music.cpp
network/network.cpp
+network/network_admin.cpp
network/network_client.cpp
network/network_command.cpp
network/network_content.cpp
@@ -190,6 +191,7 @@ map_func.h
map_type.h
mixer.h
network/network.h
+network/network_admin.h
network/network_base.h
network/network_client.h
network/network_content.h
@@ -834,6 +836,8 @@ network/core/tcp_content.cpp
network/core/tcp_content.h
network/core/tcp_game.cpp
network/core/tcp_game.h
+network/core/tcp_admin.cpp
+network/core/tcp_admin.h
network/core/tcp_http.cpp
network/core/tcp_http.h
network/core/tcp_listen.h
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?
diff --git a/src/settings_type.h b/src/settings_type.h
index e12507938..381e78c3e 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -136,6 +136,7 @@ struct NetworkSettings {
char server_name[NETWORK_NAME_LENGTH]; ///< name of the server
char server_password[NETWORK_PASSWORD_LENGTH]; ///< passowrd for joining this server
char rcon_password[NETWORK_PASSWORD_LENGTH]; ///< passowrd for rconsole (server side)
+ char admin_password[NETWORK_PASSWORD_LENGTH]; ///< password for the admin network
bool server_advertise; ///< advertise the server to the masterserver
uint8 lan_internet; ///< search on the LAN or internet for servers
char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< name of the player (as client)
diff --git a/src/table/settings.h b/src/table/settings.h
index 330fd918c..d2416ad2f 100644
--- a/src/table/settings.h
+++ b/src/table/settings.h
@@ -636,6 +636,7 @@ const SettingDesc _settings[] = {
SDTC_STR(network.client_name, SLE_STRB, S, 0, NULL, STR_NULL, UpdateClientName),
SDTC_STR(network.server_password, SLE_STRB, S, NO, NULL, STR_NULL, UpdateServerPassword),
SDTC_STR(network.rcon_password, SLE_STRB, S, NO, NULL, STR_NULL, UpdateRconPassword),
+ SDTC_STR(network.admin_password, SLE_STRB, S, NO, NULL, STR_NULL, NULL),
SDTC_STR(network.default_company_pass, SLE_STRB, S, 0, NULL, STR_NULL, NULL),
SDTC_STR(network.server_name, SLE_STRB, S, NO, NULL, STR_NULL, NULL),
SDTC_STR(network.connect_to_ip, SLE_STRB, S, 0, NULL, STR_NULL, NULL),