Changeset - r25800:5bcbdca2efaf
[Not reviewed]
master
0 9 4
Patric Stout - 3 years ago 2021-07-03 09:04:32
truebrain@openttd.org
Add: use Game Coordinator to annouce public servers
13 files changed with 535 insertions and 5 deletions:
0 comments (0 inline, 0 general)
src/lang/english.txt
Show inline comments
 
@@ -1995,7 +1995,7 @@ STR_FACE_TIE                            
 
STR_FACE_EARRING                                                :Earring:
 
STR_FACE_TIE_EARRING_TOOLTIP                                    :{BLACK}Change tie or earring
 

	
 
STR_NETWORK_SERVER_VISIBILITY_PRIVATE                           :Private
 
STR_NETWORK_SERVER_VISIBILITY_LOCAL                             :Local
 
STR_NETWORK_SERVER_VISIBILITY_PUBLIC                            :Public
 

	
 
# Network server list
 
@@ -2136,6 +2136,8 @@ STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT
 
STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION               :Name of the server
 
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY                       :{BLACK}Visibility
 
STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP               :{BLACK}Whether other people can see your server in the public listing
 
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE                  :{BLACK}Connection type
 
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TOOLTIP          :{BLACK}Whether and how your server can be reached by others
 
STR_NETWORK_CLIENT_LIST_PLAYER                                  :{BLACK}Player
 
STR_NETWORK_CLIENT_LIST_PLAYER_NAME                             :{BLACK}Name
 
STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP                     :{BLACK}Your player name
 
@@ -2154,6 +2156,12 @@ STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF
 
STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP                :{BLACK}This is the host of the game
 
STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT                    :{BLACK}{NUM} client{P "" s} / {NUM} compan{P y ies}
 

	
 
############ Begin of ConnectionType
 
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_UNKNOWN          :{BLACK}Local
 
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_ISOLATED         :{RED}Remote players can't connect
 
STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_DIRECT           :{BLACK}Public
 
############ End of ConnectionType
 

	
 
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK                       :Kick
 
STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN                        :Ban
 
STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET                     :Delete
 
@@ -2281,6 +2289,10 @@ STR_NETWORK_MESSAGE_SERVER_SHUTDOWN     
 
STR_NETWORK_MESSAGE_SERVER_REBOOT                               :{WHITE}The server is restarting...{}Please wait...
 
STR_NETWORK_MESSAGE_KICKED                                      :*** {RAW_STRING} was kicked. Reason: ({RAW_STRING})
 

	
 
STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED               :{WHITE}Server registration failed
 
STR_NETWORK_ERROR_COORDINATOR_ISOLATED                          :{WHITE}Your server doesn't allow remote connections
 
STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL                   :{WHITE}Other players won't be able to connect to your server
 

	
 
# Content downloading window
 
STR_CONTENT_TITLE                                               :{WHITE}Content downloading
 
STR_CONTENT_TYPE_CAPTION                                        :{BLACK}Type
src/network/CMakeLists.txt
Show inline comments
 
@@ -14,6 +14,8 @@ add_files(
 
    network_content.h
 
    network_content_gui.cpp
 
    network_content_gui.h
 
    network_coordinator.cpp
 
    network_coordinator.h
 
    network_func.h
 
    network_gamelist.cpp
 
    network_gamelist.h
src/network/core/CMakeLists.txt
Show inline comments
 
@@ -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
src/network/core/config.h
Show inline comments
 
@@ -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 */
 
@@ -24,6 +26,7 @@ static const char * const NETWORK_CONTEN
 
static const char * const NETWORK_MASTER_SERVER_WELCOME_MESSAGE = "OpenTTDRegister";
 

	
 
static const uint16 NETWORK_MASTER_SERVER_PORT    = 3978;         ///< The default port of the master server (UDP)
 
static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976;           ///< The default port of the Game Coordinator server (TCP)
 
static const uint16 NETWORK_CONTENT_SERVER_PORT   = 3978;         ///< The default port of the content server (TCP)
 
static const uint16 NETWORK_CONTENT_MIRROR_PORT   =   80;         ///< The default port of the content mirror (TCP)
 
static const uint16 NETWORK_DEFAULT_PORT          = 3979;         ///< The default port of the game server (TCP & UDP)
 
@@ -52,6 +55,7 @@ static const byte NETWORK_GAME_ADMIN_VER
 
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'
 
@@ -71,6 +75,7 @@ static const uint NETWORK_CONTENT_VERSIO
 
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
 

	
src/network/core/tcp_coordinator.cpp
Show inline comments
 
new file 100644
 
/*
 
 * 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); }
src/network/core/tcp_coordinator.h
Show inline comments
 
new file 100644
 
/*
 
 * 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 */
src/network/network.cpp
Show inline comments
 
@@ -19,6 +19,7 @@
 
#include "network_udp.h"
 
#include "network_gamelist.h"
 
#include "network_base.h"
 
#include "network_coordinator.h"
 
#include "core/udp.h"
 
#include "core/host.h"
 
#include "network_gui.h"
 
@@ -591,6 +592,8 @@ void NetworkClose(bool close_admins)
 
		}
 
		ServerNetworkGameSocketHandler::CloseListeners();
 
		ServerNetworkAdminSocketHandler::CloseListeners();
 

	
 
		_network_coordinator_client.CloseConnection();
 
	} else if (MyClient::my_client != nullptr) {
 
		MyClient::SendQuit();
 
		MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CLIENT_QUIT);
 
@@ -932,6 +935,10 @@ bool NetworkServerStart()
 

	
 
	NetworkInitGameInfo();
 

	
 
	if (_settings_client.network.server_advertise) {
 
		_network_coordinator_client.Register();
 
	}
 

	
 
	/* execute server initialization script */
 
	IConsoleCmdExec("exec scripts/on_server.scr 0");
 
	/* if the server is dedicated ... add some other script */
 
@@ -1032,6 +1039,7 @@ static void NetworkSend()
 
void NetworkBackgroundLoop()
 
{
 
	_network_content_client.SendReceive();
 
	_network_coordinator_client.SendReceive();
 
	TCPConnecter::CheckCallbacks();
 
	NetworkHTTPSocketHandler::HTTPReceive();
 

	
src/network/network_coordinator.cpp
Show inline comments
 
new file 100644
 

	
 
/*
 
 * 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_coordinator.cpp Game Coordinator sending/receiving part of the network protocol. */
 

	
 
#include "../stdafx.h"
 
#include "../debug.h"
 
#include "../error.h"
 
#include "../rev.h"
 
#include "../settings_type.h"
 
#include "../strings_func.h"
 
#include "../window_func.h"
 
#include "../window_type.h"
 
#include "network.h"
 
#include "network_coordinator.h"
 
#include "network_gamelist.h"
 
#include "table/strings.h"
 

	
 
#include "../safeguards.h"
 

	
 
static const auto NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES = std::chrono::seconds(30); ///< How many time between updates the server sends to the Game Coordinator.
 
ClientNetworkCoordinatorSocketHandler _network_coordinator_client; ///< The connection to the Game Coordinator.
 
ConnectionType _network_server_connection_type = CONNECTION_TYPE_UNKNOWN; ///< What type of connection the Game Coordinator detected we are on.
 

	
 
/** Connect to the Game Coordinator server. */
 
class NetworkCoordinatorConnecter : TCPConnecter {
 
public:
 
	/**
 
	 * Initiate the connecting.
 
	 * @param address The address of the Game Coordinator server.
 
	 */
 
	NetworkCoordinatorConnecter(const std::string &connection_string) : TCPConnecter(connection_string, NETWORK_COORDINATOR_SERVER_PORT) {}
 

	
 
	void OnFailure() override
 
	{
 
		_network_coordinator_client.connecting = false;
 
		_network_coordinator_client.CloseConnection(true);
 
	}
 

	
 
	void OnConnect(SOCKET s) override
 
	{
 
		assert(_network_coordinator_client.sock == INVALID_SOCKET);
 

	
 
		_network_coordinator_client.sock = s;
 
		_network_coordinator_client.connecting = false;
 
	}
 
};
 

	
 
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p)
 
{
 
	NetworkCoordinatorErrorType error = (NetworkCoordinatorErrorType)p->Recv_uint8();
 
	std::string detail = p->Recv_string(NETWORK_ERROR_DETAIL_LENGTH);
 

	
 
	switch (error) {
 
		case NETWORK_COORDINATOR_ERROR_UNKNOWN:
 
			this->CloseConnection();
 
			return false;
 

	
 
		case NETWORK_COORDINATOR_ERROR_REGISTRATION_FAILED:
 
			SetDParamStr(0, detail);
 
			ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED, STR_JUST_RAW_STRING, WL_ERROR);
 

	
 
			/* To prevent that we constantly try to reconnect, switch to private game. */
 
			_settings_client.network.server_advertise = false;
 

	
 
			this->CloseConnection();
 
			return false;
 

	
 
		default:
 
			Debug(net, 0, "Invalid error type {} received from Game Coordinator", error);
 
			this->CloseConnection();
 
			return false;
 
	}
 
}
 

	
 
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_REGISTER_ACK(Packet *p)
 
{
 
	/* Schedule sending an update. */
 
	this->next_update = std::chrono::steady_clock::now();
 

	
 
	_network_server_connection_type = (ConnectionType)p->Recv_uint8();
 

	
 
	if (_network_server_connection_type == CONNECTION_TYPE_ISOLATED) {
 
		ShowErrorMessage(STR_NETWORK_ERROR_COORDINATOR_ISOLATED, STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL, WL_ERROR);
 
	}
 

	
 
	SetWindowDirty(WC_CLIENT_LIST, 0);
 

	
 
	if (_network_dedicated) {
 
		std::string connection_type;
 
		switch (_network_server_connection_type) {
 
			case CONNECTION_TYPE_ISOLATED: connection_type = "Remote players can't connect"; break;
 
			case CONNECTION_TYPE_DIRECT:   connection_type = "Public"; break;
 

	
 
			case CONNECTION_TYPE_UNKNOWN: // Never returned from Game Coordinator.
 
			default: connection_type = "Unknown"; break; // Should never happen, but don't fail if it does.
 
		}
 

	
 
		Debug(net, 3, "----------------------------------------");
 
		Debug(net, 3, "Your server is now registered with the Game Coordinator:");
 
		Debug(net, 3, "  Game type:       Public");
 
		Debug(net, 3, "  Connection type: {}", connection_type);
 
		Debug(net, 3, "----------------------------------------");
 
	}
 

	
 
	return true;
 
}
 

	
 
void ClientNetworkCoordinatorSocketHandler::Connect()
 
{
 
	/* We are either already connected or are trying to connect. */
 
	if (this->sock != INVALID_SOCKET || this->connecting) return;
 

	
 
	this->Reopen();
 

	
 
	this->connecting = true;
 
	new NetworkCoordinatorConnecter(NETWORK_COORDINATOR_SERVER_HOST);
 
}
 

	
 
NetworkRecvStatus ClientNetworkCoordinatorSocketHandler::CloseConnection(bool error)
 
{
 
	NetworkCoordinatorSocketHandler::CloseConnection(error);
 

	
 
	this->CloseSocket();
 
	this->connecting = false;
 

	
 
	_network_server_connection_type = CONNECTION_TYPE_UNKNOWN;
 
	this->next_update = {};
 

	
 
	SetWindowDirty(WC_CLIENT_LIST, 0);
 

	
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
/**
 
 * Register our server to receive our join-key.
 
 */
 
void ClientNetworkCoordinatorSocketHandler::Register()
 
{
 
	_network_server_connection_type = CONNECTION_TYPE_UNKNOWN;
 
	this->next_update = {};
 

	
 
	SetWindowDirty(WC_CLIENT_LIST, 0);
 

	
 
	this->Connect();
 

	
 
	Packet *p = new Packet(PACKET_COORDINATOR_SERVER_REGISTER);
 
	p->Send_uint8(NETWORK_COORDINATOR_VERSION);
 
	p->Send_uint8(SERVER_GAME_TYPE_PUBLIC);
 
	p->Send_uint16(_settings_client.network.server_port);
 

	
 
	this->SendPacket(p);
 
}
 

	
 
/**
 
 * Send an update of our server status to the Game Coordinator.
 
 */
 
void ClientNetworkCoordinatorSocketHandler::SendServerUpdate()
 
{
 
	Debug(net, 6, "Sending server update to Game Coordinator");
 
	this->next_update = std::chrono::steady_clock::now() + NETWORK_COORDINATOR_DELAY_BETWEEN_UPDATES;
 

	
 
	Packet *p = new Packet(PACKET_COORDINATOR_SERVER_UPDATE);
 
	p->Send_uint8(NETWORK_COORDINATOR_VERSION);
 
	SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo());
 

	
 
	this->SendPacket(p);
 
}
 

	
 
/**
 
 * Check whether we received/can send some data from/to the Game Coordinator server and
 
 * when that's the case handle it appropriately.
 
 */
 
void ClientNetworkCoordinatorSocketHandler::SendReceive()
 
{
 
	/* Private games are not listed via the Game Coordinator. */
 
	if (_network_server && !_settings_client.network.server_advertise) {
 
		if (this->sock != INVALID_SOCKET) {
 
			this->CloseConnection();
 
		}
 
		return;
 
	}
 

	
 
	static int last_attempt_backoff = 1;
 
	static bool first_reconnect = true;
 

	
 
	if (this->sock == INVALID_SOCKET) {
 
		static std::chrono::steady_clock::time_point last_attempt = {};
 

	
 
		/* Don't auto-reconnect when we are not a server. */
 
		if (!_network_server) return;
 
		/* Don't reconnect if we are connecting. */
 
		if (this->connecting) return;
 
		/* Throttle how often we try to reconnect. */
 
		if (std::chrono::steady_clock::now() < last_attempt + std::chrono::seconds(1) * last_attempt_backoff) return;
 

	
 
		last_attempt = std::chrono::steady_clock::now();
 
		/* Delay reconnecting with up to 32 seconds. */
 
		if (last_attempt_backoff < 32) {
 
			last_attempt_backoff *= 2;
 
		}
 

	
 
		/* Do not reconnect on the first attempt, but only initialize the
 
		 * last_attempt variables.  Otherwise after an outage all servers
 
		 * reconnect at the same time, potentially overwhelming the
 
		 * Game Coordinator. */
 
		if (first_reconnect) {
 
			first_reconnect = false;
 
			return;
 
		}
 

	
 
		Debug(net, 1, "Connection with Game Coordinator lost; reconnecting...");
 
		this->Register();
 
		return;
 
	}
 

	
 
	last_attempt_backoff = 1;
 
	first_reconnect = true;
 

	
 
	if (_network_server && _network_server_connection_type != CONNECTION_TYPE_UNKNOWN && std::chrono::steady_clock::now() > this->next_update) {
 
		this->SendServerUpdate();
 
	}
 

	
 
	if (this->CanSendReceive()) {
 
		this->ReceivePackets();
 
	}
 

	
 
	this->SendPackets();
 
}
src/network/network_coordinator.h
Show inline comments
 
new file 100644
 

	
 
/*
 
 * 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_coordinator.h Part of the network protocol handling Game Coordinator requests. */
 

	
 
#ifndef NETWORK_COORDINATOR_H
 
#define NETWORK_COORDINATOR_H
 

	
 
#include "core/tcp_coordinator.h"
 

	
 
/**
 
 * Game Coordinator communication.
 
 *
 
 * For servers:
 
 *  - Server sends SERVER_REGISTER.
 
 *  - Game Coordinator probes server to check if it can directly connect.
 
 *  - Game Coordinator sends GC_REGISTER_ACK with type of connection.
 
 *  - Server sends every 30 seconds SERVER_UPDATE.
 
 */
 

	
 
/** Class for handling the client side of the Game Coordinator connection. */
 
class ClientNetworkCoordinatorSocketHandler : public NetworkCoordinatorSocketHandler {
 
private:
 
	std::chrono::steady_clock::time_point next_update; ///< When to send the next update (if server and public).
 

	
 
protected:
 
	bool Receive_GC_ERROR(Packet *p) override;
 
	bool Receive_GC_REGISTER_ACK(Packet *p) override;
 

	
 
public:
 
	bool connecting; ///< Are we connecting to the Game Coordinator?
 

	
 
	ClientNetworkCoordinatorSocketHandler() : connecting(false) {}
 

	
 
	NetworkRecvStatus CloseConnection(bool error = true) override;
 
	void SendReceive();
 

	
 
	void Connect();
 

	
 
	void Register();
 
	void SendServerUpdate();
 
};
 

	
 
extern ClientNetworkCoordinatorSocketHandler _network_coordinator_client;
 

	
 
#endif /* NETWORK_COORDINATOR_H */
src/network/network_gui.cpp
Show inline comments
 
@@ -62,7 +62,7 @@ static CompanyID _admin_company_id = INV
 
 * do not.
 
 */
 
static const StringID _server_visibility_dropdown[] = {
 
	STR_NETWORK_SERVER_VISIBILITY_PRIVATE,
 
	STR_NETWORK_SERVER_VISIBILITY_LOCAL,
 
	STR_NETWORK_SERVER_VISIBILITY_PUBLIC,
 
	INVALID_STRING_ID
 
};
 
@@ -1607,21 +1607,26 @@ static const NWidgetPart _nested_client_
 
			NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER, STR_NULL), SetPadding(4, 4, 0, 4), SetPIP(0, 2, 0),
 
				NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0),
 
					NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME, STR_NULL),
 
					NWidget(NWID_SPACER), SetMinimalSize(20, 0),
 
					NWidget(NWID_SPACER), SetMinimalSize(10, 0),
 
					NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_SERVER_NAME), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetDataTip(STR_BLACK_RAW_STRING, STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
					NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_SERVER_NAME_EDIT), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP),
 
				EndContainer(),
 
				NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0),
 
					NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY, STR_NULL),
 
					NWidget(NWID_SPACER), SetMinimalSize(20, 0), SetFill(1, 0), SetResize(1, 0),
 
					NWidget(NWID_SPACER), SetMinimalSize(10, 0), SetFill(1, 0), SetResize(1, 0),
 
					NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetDataTip(STR_BLACK_STRING, STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP),
 
				EndContainer(),
 
				NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0),
 
					NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE, STR_NULL),
 
					NWidget(NWID_SPACER), SetMinimalSize(10, 0),
 
					NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_SERVER_CONNECTION_TYPE), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
				EndContainer(),
 
			EndContainer(),
 
		EndContainer(),
 
		NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER, STR_NULL), SetPadding(4, 4, 4, 4), SetPIP(0, 2, 0),
 
			NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0),
 
				NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME, STR_NULL),
 
				NWidget(NWID_SPACER), SetMinimalSize(20, 0),
 
				NWidget(NWID_SPACER), SetMinimalSize(10, 0),
 
				NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_CLIENT_NAME), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetDataTip(STR_BLACK_RAW_STRING, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
				NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_CLIENT_NAME_EDIT), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP),
 
			EndContainer(),
 
@@ -2050,6 +2055,10 @@ public:
 
				SetDParam(0, _server_visibility_dropdown[_settings_client.network.server_advertise]);
 
				break;
 

	
 
			case WID_CL_SERVER_CONNECTION_TYPE:
 
				SetDParam(0, STR_NETWORK_CLIENT_LIST_SERVER_CONNECTION_TYPE_UNKNOWN + _network_server_connection_type);
 
				break;
 

	
 
			case WID_CL_CLIENT_NAME:
 
				SetDParamStr(0, _settings_client.network.client_name);
 
				break;
src/network/network_internal.h
Show inline comments
 
@@ -11,6 +11,7 @@
 
#define NETWORK_INTERNAL_H
 

	
 
#include "network_func.h"
 
#include "core/tcp_coordinator.h"
 
#include "core/tcp_game.h"
 

	
 
#include "../command_type.h"
 
@@ -82,6 +83,7 @@ extern NetworkJoinStatus _network_join_s
 
extern uint8 _network_join_waiting;
 
extern uint32 _network_join_bytes;
 
extern uint32 _network_join_bytes_total;
 
extern ConnectionType _network_server_connection_type;
 

	
 
extern uint8 _network_reconnect;
 

	
src/network/network_type.h
Show inline comments
 
@@ -35,6 +35,15 @@ enum NetworkVehicleType {
 
	NETWORK_VEH_END
 
};
 

	
 
/**
 
 * Game type the server can be using.
 
 * Used on the network protocol to communicate with Game Coordinator.
 
 */
 
enum ServerGameType : uint8 {
 
	SERVER_GAME_TYPE_LOCAL = 0,
 
	SERVER_GAME_TYPE_PUBLIC,
 
};
 

	
 
/** 'Unique' identifier to be given to clients */
 
enum ClientID : uint32 {
 
	INVALID_CLIENT_ID = 0, ///< Client is not part of anything
src/widgets/network_widget.h
Show inline comments
 
@@ -101,6 +101,7 @@ enum ClientListWidgets {
 
	WID_CL_SERVER_NAME,                ///< Server name.
 
	WID_CL_SERVER_NAME_EDIT,           ///< Edit button for server name.
 
	WID_CL_SERVER_VISIBILITY,          ///< Server visibility.
 
	WID_CL_SERVER_CONNECTION_TYPE,     ///< The type of connection the Game Coordinator detected for this server.
 
	WID_CL_CLIENT_NAME,                ///< Client name.
 
	WID_CL_CLIENT_NAME_EDIT,           ///< Edit button for client name.
 
	WID_CL_MATRIX,                     ///< Company/client list.
0 comments (0 inline, 0 general)