changeset 16262:4b80dac03c83 draft

(svn r20963) -Add: stubs for a remote administration connection
author rubidium <rubidium@openttd.org>
date Sun, 17 Oct 2010 17:31:03 +0000
parents 8dcd31422ab1
children aa43311655b5
files projects/openttd_vs100.vcxproj projects/openttd_vs100.vcxproj.filters projects/openttd_vs80.vcproj projects/openttd_vs90.vcproj source.list src/network/core/config.h src/network/core/tcp_admin.cpp src/network/core/tcp_admin.h src/network/network_admin.cpp src/network/network_admin.h src/network/network_type.h src/settings_type.h src/table/settings.h
diffstat 13 files changed, 584 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- 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" />
--- 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>
--- 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>
--- 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>
--- a/source.list
+++ b/source.list
@@ -39,6 +39,7 @@
 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_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.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
--- a/src/network/core/config.h
+++ b/src/network/core/config.h
@@ -29,10 +29,12 @@
 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?
new file mode 100644
--- /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 */
new file mode 100644
--- /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 */
new file mode 100644
--- /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 */
new file mode 100644
--- /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 */
--- a/src/network/network_type.h
+++ b/src/network/network_type.h
@@ -49,6 +49,14 @@
 /** 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?
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -136,6 +136,7 @@
 	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)
--- a/src/table/settings.h
+++ b/src/table/settings.h
@@ -636,6 +636,7 @@
 	  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),