Changeset - r25801:cac5091e0a66
[Not reviewed]
master
0 5 0
Patric Stout - 3 years ago 2021-07-03 09:12:28
truebrain@openttd.org
Add: use Game Coordinator to get latest public server listing
5 files changed with 137 insertions and 14 deletions:
0 comments (0 inline, 0 general)
src/network/core/tcp_coordinator.cpp
Show inline comments
 
@@ -28,12 +28,14 @@ bool NetworkCoordinatorSocketHandler::Ha
 

	
 
	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);
 
		case PACKET_COORDINATOR_CLIENT_LISTING:  return this->Receive_CLIENT_LISTING(p);
 
		case PACKET_COORDINATOR_GC_LISTING:      return this->Receive_GC_LISTING(p);
 

	
 
		default:
 
			Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type);
 
			return false;
 
	}
 
}
 
@@ -75,6 +77,8 @@ bool NetworkCoordinatorSocketHandler::Re
 
}
 

	
 
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); }
 
bool NetworkCoordinatorSocketHandler::Receive_CLIENT_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_LISTING); }
 
bool NetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_LISTING); }
src/network/core/tcp_coordinator.h
Show inline comments
 
@@ -26,12 +26,14 @@
 
 **/
 
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_CLIENT_LISTING,  ///< Client is requesting a listing of all public servers.
 
	PACKET_COORDINATOR_GC_LISTING,      ///< Game Coordinator returns a listing of all public servers.
 
	PACKET_COORDINATOR_END,             ///< Must ALWAYS be on the end of this list!! (period).
 
};
 

	
 
/**
 
 * The type of connection the Game Coordinator can detect we have.
 
 */
 
@@ -98,12 +100,39 @@ protected:
 
	 *
 
	 * @param p The packet that was just received.
 
	 * @return True upon success, otherwise false.
 
	 */
 
	virtual bool Receive_SERVER_UPDATE(Packet *p);
 

	
 
	/**
 
	 * Client requests a list of all public servers.
 
	 *
 
	 *  uint8   Game Coordinator protocol version.
 
	 *  uint8   Game-info version used by this client.
 
	 *  string  Revision of the client.
 
	 *
 
	 * @param p The packet that was just received.
 
	 * @return True upon success, otherwise false.
 
	 */
 
	virtual bool Receive_CLIENT_LISTING(Packet *p);
 

	
 
	/**
 
	 * Game Coordinator replies with a list of all public servers. Multiple
 
	 * of these packets are received after a request till all servers are
 
	 * sent over. Last packet will have server count of 0.
 
	 *
 
	 *  uint16  Amount of public servers in this packet.
 
	 *  For each server:
 
	 *    string  Connection string for this server.
 
	 *    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_GC_LISTING(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.
 
	 */
src/network/network_coordinator.cpp
Show inline comments
 
@@ -16,12 +16,13 @@
 
#include "../strings_func.h"
 
#include "../window_func.h"
 
#include "../window_type.h"
 
#include "network.h"
 
#include "network_coordinator.h"
 
#include "network_gamelist.h"
 
#include "network_internal.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.
 
@@ -44,12 +45,13 @@ public:
 

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

	
 
		_network_coordinator_client.sock = s;
 
		_network_coordinator_client.last_activity = std::chrono::steady_clock::now();
 
		_network_coordinator_client.connecting = false;
 
	}
 
};
 

	
 
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_ERROR(Packet *p)
 
{
 
@@ -108,20 +110,58 @@ bool ClientNetworkCoordinatorSocketHandl
 
		Debug(net, 3, "----------------------------------------");
 
	}
 

	
 
	return true;
 
}
 

	
 
bool ClientNetworkCoordinatorSocketHandler::Receive_GC_LISTING(Packet *p)
 
{
 
	uint8 servers = p->Recv_uint16();
 

	
 
	/* End of list; we can now remove all expired items from the list. */
 
	if (servers == 0) {
 
		NetworkGameListRemoveExpired();
 
		return true;
 
	}
 

	
 
	for (; servers > 0; servers--) {
 
		std::string connection_string = p->Recv_string(NETWORK_HOSTNAME_PORT_LENGTH);
 

	
 
		/* Read the NetworkGameInfo from the packet. */
 
		NetworkGameInfo ngi = {};
 
		DeserializeNetworkGameInfo(p, &ngi);
 

	
 
		/* Now we know the join-key, we can add it to our list. */
 
		NetworkGameList *item = NetworkGameListAddItem(connection_string);
 

	
 
		/* Clear any existing GRFConfig chain. */
 
		ClearGRFConfigList(&item->info.grfconfig);
 
		/* Copy the new NetworkGameInfo info. */
 
		item->info = ngi;
 
		/* Check for compatability with the client. */
 
		CheckGameCompatibility(item->info);
 
		/* Mark server as online. */
 
		item->online = true;
 
		/* Mark the item as up-to-date. */
 
		item->version = _network_game_list_version;
 
	}
 

	
 
	UpdateNetworkGameWindow();
 
	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;
 
	this->last_activity = std::chrono::steady_clock::now();
 

	
 
	new NetworkCoordinatorConnecter(NETWORK_COORDINATOR_SERVER_HOST);
 
}
 

	
 
NetworkRecvStatus ClientNetworkCoordinatorSocketHandler::CloseConnection(bool error)
 
{
 
	NetworkCoordinatorSocketHandler::CloseConnection(error);
 
@@ -170,12 +210,29 @@ void ClientNetworkCoordinatorSocketHandl
 
	SerializeNetworkGameInfo(p, GetCurrentNetworkServerGameInfo());
 

	
 
	this->SendPacket(p);
 
}
 

	
 
/**
 
 * Request a listing of all public servers.
 
 */
 
void ClientNetworkCoordinatorSocketHandler::GetListing()
 
{
 
	this->Connect();
 

	
 
	_network_game_list_version++;
 

	
 
	Packet *p = new Packet(PACKET_COORDINATOR_CLIENT_LISTING);
 
	p->Send_uint8(NETWORK_COORDINATOR_VERSION);
 
	p->Send_uint8(NETWORK_GAME_INFO_VERSION);
 
	p->Send_string(_openttd_revision);
 

	
 
	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. */
 
@@ -223,12 +280,19 @@ void ClientNetworkCoordinatorSocketHandl
 
	first_reconnect = true;
 

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

	
 
	if (!_network_server && std::chrono::steady_clock::now() > this->last_activity + IDLE_TIMEOUT) {
 
		this->CloseConnection();
 
		return;
 
	}
 

	
 
	if (this->CanSendReceive()) {
 
		this->ReceivePackets();
 
		if (this->ReceivePackets()) {
 
			this->last_activity = std::chrono::steady_clock::now();
 
		}
 
	}
 

	
 
	this->SendPackets();
 
}
src/network/network_coordinator.h
Show inline comments
 
@@ -18,34 +18,44 @@
 
 *
 
 * 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.
 
 *
 
 * For clients (listing):
 
 *  - Client sends CLIENT_LISTING.
 
 *  - Game Coordinator returns the full list of public servers via GC_LISTING (multiple packets).
 
 */
 

	
 
/** 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;
 
	bool Receive_GC_LISTING(Packet *p) override;
 

	
 
public:
 
	/** The idle timeout; when to close the connection because it's idle. */
 
	static constexpr std::chrono::seconds IDLE_TIMEOUT = std::chrono::seconds(60);
 

	
 
	std::chrono::steady_clock::time_point last_activity;  ///< The last time there was network activity.
 
	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();
 
	void GetListing();
 
};
 

	
 
extern ClientNetworkCoordinatorSocketHandler _network_coordinator_client;
 

	
 
#endif /* NETWORK_COORDINATOR_H */
src/network/network_gui.cpp
Show inline comments
 
@@ -15,12 +15,13 @@
 
#include "network_gui.h"
 
#include "network_gamelist.h"
 
#include "network.h"
 
#include "network_base.h"
 
#include "network_content.h"
 
#include "network_server.h"
 
#include "network_coordinator.h"
 
#include "../gui.h"
 
#include "network_udp.h"
 
#include "../window_func.h"
 
#include "../gfx_func.h"
 
#include "../widgets/dropdown_type.h"
 
#include "../widgets/dropdown_func.h"
 
@@ -51,12 +52,14 @@
 

	
 
#include "../safeguards.h"
 

	
 
static void ShowNetworkStartServerWindow();
 
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
 

	
 
static const int NETWORK_LIST_REFRESH_DELAY = 30; ///< Time, in seconds, between updates of the network list.
 

	
 
static ClientID _admin_client_id = INVALID_CLIENT_ID; ///< For what client a confirmation window is open.
 
static CompanyID _admin_company_id = INVALID_COMPANY; ///< For what company a confirmation window is open.
 

	
 
/**
 
 * Visibility of the server. Public servers advertise, where private servers
 
 * do not.
 
@@ -216,20 +219,21 @@ protected:
 
	static Listing last_sorting;
 

	
 
	/* Constants for sorting servers */
 
	static GUIGameServerList::SortFunction * const sorter_funcs[];
 
	static GUIGameServerList::FilterFunction * const filter_funcs[];
 

	
 
	NetworkGameList *server;      ///< selected server
 
	NetworkGameList *last_joined; ///< the last joined server
 
	GUIGameServerList servers;    ///< list with game servers.
 
	ServerListPosition list_pos;  ///< position of the selected server
 
	Scrollbar *vscroll;           ///< vertical scrollbar of the list of servers
 
	QueryString name_editbox;     ///< Client name editbox.
 
	QueryString filter_editbox;   ///< Editbox for filter on servers
 
	GUITimer requery_timer;       ///< Timer for network requery
 
	NetworkGameList *server;        ///< Selected server.
 
	NetworkGameList *last_joined;   ///< The last joined server.
 
	GUIGameServerList servers;      ///< List with game servers.
 
	ServerListPosition list_pos;    ///< Position of the selected server.
 
	Scrollbar *vscroll;             ///< Vertical scrollbar of the list of servers.
 
	QueryString name_editbox;       ///< Client name editbox.
 
	QueryString filter_editbox;     ///< Editbox for filter on servers.
 
	GUITimer requery_timer;         ///< Timer for network requery.
 
	bool searched_internet = false; ///< Did we ever press "Search Internet" button?
 

	
 
	int lock_offset; ///< Left offset for lock icon.
 
	int blot_offset; ///< Left offset for green/yellow/red compatibility icon.
 
	int flag_offset; ///< Left offset for language flag icon.
 

	
 
	/**
 
@@ -241,14 +245,24 @@ protected:
 
	{
 
		if (!this->servers.NeedRebuild()) return;
 

	
 
		/* Create temporary array of games to use for listing */
 
		this->servers.clear();
 

	
 
		bool found_current_server = false;
 
		for (NetworkGameList *ngl = _network_game_list; ngl != nullptr; ngl = ngl->next) {
 
			this->servers.push_back(ngl);
 
			if (ngl == this->server) {
 
				found_current_server = true;
 
			}
 
		}
 
		/* A refresh can cause the current server to be delete; so unselect. */
 
		if (!found_current_server) {
 
			if (this->server == this->last_joined) this->last_joined = nullptr;
 
			this->server = nullptr;
 
			this->list_pos = SLP_INVALID;
 
		}
 

	
 
		/* Apply the filter condition immediately, if a search string has been provided. */
 
		StringFilter sf;
 
		sf.SetFilterTerm(this->filter_editbox.text.buf);
 

	
 
@@ -476,13 +490,13 @@ public:
 
		EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
 
#endif
 

	
 
		this->last_joined = NetworkAddServer(_settings_client.network.last_joined, false);
 
		this->server = this->last_joined;
 

	
 
		this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
 
		this->requery_timer.SetInterval(NETWORK_LIST_REFRESH_DELAY * 1000);
 

	
 
		this->servers.SetListing(this->last_sorting);
 
		this->servers.SetSortFuncs(this->sorter_funcs);
 
		this->servers.SetFilterFuncs(this->filter_funcs);
 
		this->servers.ForceRebuild();
 
	}
 
@@ -722,13 +736,14 @@ public:
 
					if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1);
 
				}
 
				break;
 
			}
 

	
 
			case WID_NG_SEARCH_INTERNET:
 
				NetworkUDPQueryMasterServer();
 
				_network_coordinator_client.GetListing();
 
				this->searched_internet = true;
 
				break;
 

	
 
			case WID_NG_SEARCH_LAN:
 
				NetworkUDPSearchGame();
 
				break;
 

	
 
@@ -838,16 +853,17 @@ public:
 
	{
 
		this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX);
 
	}
 

	
 
	void OnRealtimeTick(uint delta_ms) override
 
	{
 
		if (!this->searched_internet) return;
 
		if (!this->requery_timer.Elapsed(delta_ms)) return;
 
		this->requery_timer.SetInterval(MILLISECONDS_PER_TICK);
 

	
 
		NetworkGameListRequery();
 
		this->requery_timer.SetInterval(NETWORK_LIST_REFRESH_DELAY * 1000);
 

	
 
		_network_coordinator_client.GetListing();
 
	}
 
};
 

	
 
Listing NetworkGameWindow::last_sorting = {false, 5};
 
GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = {
 
	&NGameNameSorter,
0 comments (0 inline, 0 general)