Changeset - r25289:7c44ede418ad
[Not reviewed]
master
1 18 2
Patric Stout - 3 years ago 2021-04-26 13:18:10
truebrain@openttd.org
Codechange: move all NetworkGameInfo related functions to a single file

It currently was a bit scattered over the place. Part of
NetworkGameInfo is also the GRF Identifiers that goes with it.
21 files changed with 456 insertions and 398 deletions:
0 comments (0 inline, 0 general)
src/console_cmds.cpp
Show inline comments
 
@@ -13,6 +13,7 @@
 
#include "engine_func.h"
 
#include "landscape.h"
 
#include "saveload/saveload.h"
 
#include "network/core/game_info.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
 
#include "network/network_base.h"
src/network/core/CMakeLists.txt
Show inline comments
 
@@ -4,7 +4,8 @@ add_files(
 
    config.h
 
    core.cpp
 
    core.h
 
    game.h
 
    game_info.cpp
 
    game_info.h
 
    host.cpp
 
    host.h
 
    os_abstraction.h
src/network/core/core.cpp
Show inline comments
 
@@ -65,31 +65,3 @@ const char *NetworkGetErrorString(int er
 
	return buffer;
 
}
 
#endif /* defined(_WIN32) */
 

	
 
/**
 
 * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
 
 * @param p   the packet to write the data to
 
 * @param grf the GRFIdentifier to serialize
 
 */
 
void NetworkSocketHandler::SendGRFIdentifier(Packet *p, const GRFIdentifier *grf)
 
{
 
	uint j;
 
	p->Send_uint32(grf->grfid);
 
	for (j = 0; j < sizeof(grf->md5sum); j++) {
 
		p->Send_uint8 (grf->md5sum[j]);
 
	}
 
}
 

	
 
/**
 
 * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet
 
 * @param p   the packet to read the data from
 
 * @param grf the GRFIdentifier to deserialize
 
 */
 
void NetworkSocketHandler::ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf)
 
{
 
	uint j;
 
	grf->grfid = p->Recv_uint32();
 
	for (j = 0; j < sizeof(grf->md5sum); j++) {
 
		grf->md5sum[j] = p->Recv_uint8();
 
	}
 
}
src/network/core/core.h
Show inline comments
 
@@ -71,8 +71,6 @@ public:
 
	 */
 
	void Reopen() { this->has_quit = false; }
 

	
 
	void SendGRFIdentifier(Packet *p, const GRFIdentifier *grf);
 
	void ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf);
 
	void SendCompanyInformation(Packet *p, const struct Company *c, const struct NetworkCompanyStats *stats, uint max_len = NETWORK_COMPANY_NAME_LENGTH);
 
};
 

	
src/network/core/game.h
Show inline comments
 
deleted file
src/network/core/game_info.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 game_info.cpp Functions to convert NetworkGameInfo to Packet and back.
 
 */
 

	
 
#include "../../stdafx.h"
 
#include "game_info.h"
 
#include "../../core/bitmath_func.hpp"
 
#include "../../company_base.h"
 
#include "../../date_func.h"
 
#include "../../debug.h"
 
#include "../../map_func.h"
 
#include "../../settings_type.h"
 
#include "../../string_func.h"
 
#include "../../rev.h"
 
#include "../network_func.h"
 
#include "../network.h"
 
#include "packet.h"
 

	
 
#include "../../safeguards.h"
 

	
 

	
 
/**
 
 * How many hex digits of the git hash to include in network revision string.
 
 * Determined as 10 hex digits + 2 characters for -g/-u/-m prefix.
 
 */
 
static const uint GITHASH_SUFFIX_LEN = 12;
 

	
 
NetworkServerGameInfo _network_game_info; ///< Information about our game.
 

	
 
/**
 
 * Get the network version string used by this build.
 
 * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes.
 
 */
 
const char *GetNetworkRevisionString()
 
{
 
	/* This will be allocated on heap and never free'd, but only once so not a "real" leak. */
 
	static char *network_revision = nullptr;
 

	
 
	if (!network_revision) {
 
		/* Start by taking a chance on the full revision string. */
 
		network_revision = stredup(_openttd_revision);
 
		/* Ensure it's not longer than the packet buffer length. */
 
		if (strlen(network_revision) >= NETWORK_REVISION_LENGTH) network_revision[NETWORK_REVISION_LENGTH - 1] = '\0';
 

	
 
		/* Tag names are not mangled further. */
 
		if (_openttd_revision_tagged) {
 
			DEBUG(net, 1, "Network revision name is '%s'", network_revision);
 
			return network_revision;
 
		}
 

	
 
		/* Prepare a prefix of the git hash.
 
		 * Size is length + 1 for terminator, +2 for -g prefix. */
 
		assert(_openttd_revision_modified < 3);
 
		char githash_suffix[GITHASH_SUFFIX_LEN + 1] = "-";
 
		githash_suffix[1] = "gum"[_openttd_revision_modified];
 
		for (uint i = 2; i < GITHASH_SUFFIX_LEN; i++) {
 
			githash_suffix[i] = _openttd_revision_hash[i-2];
 
		}
 

	
 
		/* Where did the hash start in the original string?
 
		 * Overwrite from that position, unless that would go past end of packet buffer length. */
 
		ptrdiff_t hashofs = strrchr(_openttd_revision, '-') - _openttd_revision;
 
		if (hashofs + strlen(githash_suffix) + 1 > NETWORK_REVISION_LENGTH) hashofs = strlen(network_revision) - strlen(githash_suffix);
 
		/* Replace the git hash in revision string. */
 
		strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH);
 
		assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than
 
		DEBUG(net, 1, "Network revision name is '%s'", network_revision);
 
	}
 

	
 
	return network_revision;
 
}
 

	
 
/**
 
 * Extract the git hash from the revision string.
 
 * @param revstr The revision string (formatted as DATE-BRANCH-GITHASH).
 
 * @return The git has part of the revision.
 
 */
 
static const char *ExtractNetworkRevisionHash(const char *revstr)
 
{
 
	return strrchr(revstr, '-');
 
}
 

	
 
/**
 
 * Checks whether the given version string is compatible with our version.
 
 * First tries to match the full string, if that fails, attempts to compare just git hashes.
 
 * @param other the version string to compare to
 
 */
 
bool IsNetworkCompatibleVersion(const char *other)
 
{
 
	if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true;
 

	
 
	/* If this version is tagged, then the revision string must be a complete match,
 
	 * since there is no git hash suffix in it.
 
	 * This is needed to avoid situations like "1.9.0-beta1" comparing equal to "2.0.0-beta1".  */
 
	if (_openttd_revision_tagged) return false;
 

	
 
	const char *hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString());
 
	const char *hash2 = ExtractNetworkRevisionHash(other);
 
	return hash1 && hash2 && (strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0);
 
}
 

	
 
/**
 
 * Fill a NetworkGameInfo structure with the latest information of the server.
 
 * @param ngi the NetworkGameInfo struct to fill with data.
 
 */
 
void FillNetworkGameInfo(NetworkGameInfo &ngi)
 
{
 
	/* Update some game_info */
 
	ngi.clients_on     = _network_game_info.clients_on;
 
	ngi.start_date     = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
 

	
 
	ngi.use_password   = !StrEmpty(_settings_client.network.server_password);
 
	ngi.clients_max    = _settings_client.network.max_clients;
 
	ngi.companies_on   = (byte)Company::GetNumItems();
 
	ngi.companies_max  = _settings_client.network.max_companies;
 
	ngi.spectators_on  = NetworkSpectatorCount();
 
	ngi.spectators_max = _settings_client.network.max_spectators;
 
	ngi.game_date      = _date;
 
	ngi.map_width      = MapSizeX();
 
	ngi.map_height     = MapSizeY();
 
	ngi.map_set        = _settings_game.game_creation.landscape;
 
	ngi.dedicated      = _network_dedicated;
 
	ngi.grfconfig      = _grfconfig;
 

	
 
	strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name));
 
	strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision));
 
}
 

	
 
/**
 
 * Function that is called for every GRFConfig that is read when receiving
 
 * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This
 
 * function must set all appropriate fields. This GRF is later appended to
 
 * the grfconfig list of the NetworkGameInfo.
 
 * @param config the GRF to handle.
 
 */
 
static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
 
{
 
	/* Find the matching GRF file */
 
	const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum);
 
	if (f == nullptr) {
 
		/* Don't know the GRF, so mark game incompatible and the (possibly)
 
		 * already resolved name for this GRF (another server has sent the
 
		 * name of the GRF already */
 
		config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true);
 
		config->status = GCS_NOT_FOUND;
 
	} else {
 
		config->filename = f->filename;
 
		config->name = f->name;
 
		config->info = f->info;
 
		config->url = f->url;
 
	}
 
	SetBit(config->flags, GCF_COPY);
 
}
 

	
 
/**
 
 * Serializes the NetworkGameInfo struct to the packet.
 
 * @param p    the packet to write the data to.
 
 * @param info the NetworkGameInfo struct to serialize from.
 
 */
 
void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
 
{
 
	p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
 

	
 
	/*
 
	 *              Please observe the order.
 
	 * The parts must be read in the same order as they are sent!
 
	 */
 

	
 
	/* Update the documentation in game_info.h on changes
 
	 * to the NetworkGameInfo wire-protocol! */
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 4 */
 
	{
 
		/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
 
		 * the GRFs that are needed, i.e. the ones that the server has
 
		 * selected in the NewGRF GUI and not the ones that are used due
 
		 * to the fact that they are in [newgrf-static] in openttd.cfg */
 
		const GRFConfig *c;
 
		uint count = 0;
 

	
 
		/* Count number of GRFs to send information about */
 
		for (c = info->grfconfig; c != nullptr; c = c->next) {
 
			if (!HasBit(c->flags, GCF_STATIC)) count++;
 
		}
 
		p->Send_uint8 (count); // Send number of GRFs
 

	
 
		/* Send actual GRF Identifications */
 
		for (c = info->grfconfig; c != nullptr; c = c->next) {
 
			if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident);
 
		}
 
	}
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 3 */
 
	p->Send_uint32(info->game_date);
 
	p->Send_uint32(info->start_date);
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 2 */
 
	p->Send_uint8 (info->companies_max);
 
	p->Send_uint8 (info->companies_on);
 
	p->Send_uint8 (info->spectators_max);
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 1 */
 
	p->Send_string(info->server_name);
 
	p->Send_string(info->server_revision);
 
	p->Send_uint8 (0); // Used to be server-lang.
 
	p->Send_bool  (info->use_password);
 
	p->Send_uint8 (info->clients_max);
 
	p->Send_uint8 (info->clients_on);
 
	p->Send_uint8 (info->spectators_on);
 
	p->Send_string(""); // Used to be map-name.
 
	p->Send_uint16(info->map_width);
 
	p->Send_uint16(info->map_height);
 
	p->Send_uint8 (info->map_set);
 
	p->Send_bool  (info->dedicated);
 
}
 

	
 
/**
 
 * Deserializes the NetworkGameInfo struct from the packet.
 
 * @param p    the packet to read the data from.
 
 * @param info the NetworkGameInfo to deserialize into.
 
 */
 
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
 
{
 
	static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
 

	
 
	info->game_info_version = p->Recv_uint8();
 

	
 
	/*
 
	 *              Please observe the order.
 
	 * The parts must be read in the same order as they are sent!
 
	 */
 

	
 
	/* Update the documentation in game_info.h on changes
 
	 * to the NetworkGameInfo wire-protocol! */
 

	
 
	switch (info->game_info_version) {
 
		case 4: {
 
			GRFConfig **dst = &info->grfconfig;
 
			uint i;
 
			uint num_grfs = p->Recv_uint8();
 

	
 
			/* Broken/bad data. It cannot have that many NewGRFs. */
 
			if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
 

	
 
			for (i = 0; i < num_grfs; i++) {
 
				GRFConfig *c = new GRFConfig();
 
				DeserializeGRFIdentifier(p, &c->ident);
 
				HandleIncomingNetworkGameInfoGRFConfig(c);
 

	
 
				/* Append GRFConfig to the list */
 
				*dst = c;
 
				dst = &c->next;
 
			}
 
			FALLTHROUGH;
 
		}
 

	
 
		case 3:
 
			info->game_date      = Clamp(p->Recv_uint32(), 0, MAX_DATE);
 
			info->start_date     = Clamp(p->Recv_uint32(), 0, MAX_DATE);
 
			FALLTHROUGH;
 

	
 
		case 2:
 
			info->companies_max  = p->Recv_uint8 ();
 
			info->companies_on   = p->Recv_uint8 ();
 
			info->spectators_max = p->Recv_uint8 ();
 
			FALLTHROUGH;
 

	
 
		case 1:
 
			p->Recv_string(info->server_name,     sizeof(info->server_name));
 
			p->Recv_string(info->server_revision, sizeof(info->server_revision));
 
			p->Recv_uint8 (); // Used to contain server-lang.
 
			info->use_password   = p->Recv_bool  ();
 
			info->clients_max    = p->Recv_uint8 ();
 
			info->clients_on     = p->Recv_uint8 ();
 
			info->spectators_on  = p->Recv_uint8 ();
 
			if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
 
				info->game_date    = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
				info->start_date   = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			}
 
			while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
 
			info->map_width      = p->Recv_uint16();
 
			info->map_height     = p->Recv_uint16();
 
			info->map_set        = p->Recv_uint8 ();
 
			info->dedicated      = p->Recv_bool  ();
 

	
 
			if (info->map_set     >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
 
	}
 
}
 

	
 
/**
 
 * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
 
 * @param p    the packet to write the data to.
 
 * @param grf  the GRFIdentifier to serialize.
 
 */
 
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf)
 
{
 
	uint j;
 
	p->Send_uint32(grf->grfid);
 
	for (j = 0; j < sizeof(grf->md5sum); j++) {
 
		p->Send_uint8(grf->md5sum[j]);
 
	}
 
}
 

	
 
/**
 
 * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet
 
 * @param p    the packet to read the data from.
 
 * @param grf  the GRFIdentifier to deserialize.
 
 */
 
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf)
 
{
 
	uint j;
 
	grf->grfid = p->Recv_uint32();
 
	for (j = 0; j < sizeof(grf->md5sum); j++) {
 
		grf->md5sum[j] = p->Recv_uint8();
 
	}
 
}
src/network/core/game_info.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 game_info.h Convert NetworkGameInfo to Packet and back.
 
 */
 

	
 
#ifndef NETWORK_CORE_GAME_INFO_H
 
#define NETWORK_CORE_GAME_INFO_H
 

	
 
#include "config.h"
 
#include "core.h"
 
#include "../../newgrf_config.h"
 
#include "../../date_type.h"
 

	
 
/*
 
 * NetworkGameInfo has several revisions which we still need to support on the
 
 * wire. The table below shows the version and size for each field of the
 
 * serialized NetworkGameInfo.
 
 *
 
 * Version: Bytes:  Description:
 
 *   all      1       the version of this packet's structure
 
 *
 
 *   4+       1       number of GRFs attached (n)
 
 *   4+       n * 20  unique identifier for GRF files. Consists of:
 
 *                     - one 4 byte variable with the GRF ID
 
 *                     - 16 bytes (sent sequentially) for the MD5 checksum
 
 *                       of the GRF
 
 *
 
 *   3+       4       current game date in days since 1-1-0 (DMY)
 
 *   3+       4       game introduction date in days since 1-1-0 (DMY)
 
 *
 
 *   2+       1       maximum number of companies allowed on the server
 
 *   2+       1       number of companies on the server
 
 *   2+       1       maximum number of spectators allowed on the server
 
 *
 
 *   1+       var     string with the name of the server
 
 *   1+       var     string with the revision of the server
 
 *   1+       1       the language run on the server
 
 *                    (0 = any, 1 = English, 2 = German, 3 = French)
 
 *   1+       1       whether the server uses a password (0 = no, 1 = yes)
 
 *   1+       1       maximum number of clients allowed on the server
 
 *   1+       1       number of clients on the server
 
 *   1+       1       number of spectators on the server
 
 *   1 & 2    2       current game date in days since 1-1-1920 (DMY)
 
 *   1 & 2    2       game introduction date in days since 1-1-1920 (DMY)
 
 *   1+       var     string with the name of the map
 
 *   1+       2       width of the map in tiles
 
 *   1+       2       height of the map in tiles
 
 *   1+       1       type of map:
 
 *                    (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland)
 
 *   1+       1       whether the server is dedicated (0 = no, 1 = yes)
 
 */
 

	
 
/**
 
 * The game information that is not generated on-the-fly and has to
 
 * be sent to the clients.
 
 */
 
struct NetworkServerGameInfo {
 
	byte clients_on;                                ///< Current count of clients on server
 
};
 

	
 
/**
 
 * The game information that is sent from the server to the clients.
 
 */
 
struct NetworkGameInfo : NetworkServerGameInfo {
 
	GRFConfig *grfconfig;                           ///< List of NewGRF files used
 
	Date start_date;                                ///< When the game started
 
	Date game_date;                                 ///< Current date
 
	uint16 map_width;                               ///< Map width
 
	uint16 map_height;                              ///< Map height
 
	char server_name[NETWORK_NAME_LENGTH];          ///< Server name
 
	char hostname[NETWORK_HOSTNAME_LENGTH];         ///< Hostname of the server (if any)
 
	char server_revision[NETWORK_REVISION_LENGTH];  ///< The version number the server is using (e.g.: 'r304' or 0.5.0)
 
	bool dedicated;                                 ///< Is this a dedicated server?
 
	bool version_compatible;                        ///< Can we connect to this server or not? (based on server_revision)
 
	bool compatible;                                ///< Can we connect to this server or not? (based on server_revision _and_ grf_match
 
	bool use_password;                              ///< Is this server passworded?
 
	byte game_info_version;                         ///< Version of the game info
 
	byte clients_max;                               ///< Max clients allowed on server
 
	byte companies_on;                              ///< How many started companies do we have
 
	byte companies_max;                             ///< Max companies allowed on server
 
	byte spectators_on;                             ///< How many spectators do we have?
 
	byte spectators_max;                            ///< Max spectators allowed on server
 
	byte map_set;                                   ///< Graphical set
 
};
 

	
 
extern NetworkServerGameInfo _network_game_info;
 

	
 
const char *GetNetworkRevisionString();
 
bool IsNetworkCompatibleVersion(const char *other);
 

	
 
void FillNetworkGameInfo(NetworkGameInfo &ngi);
 

	
 
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf);
 
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf);
 

	
 
void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info);
 
void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info);
 

	
 
#endif /* NETWORK_CORE_GAME_INFO_H */
src/network/core/tcp_http.cpp
Show inline comments
 
@@ -13,6 +13,7 @@
 
#include "../../debug.h"
 
#include "../../rev.h"
 
#include "../network_func.h"
 
#include "game_info.h"
 

	
 
#include "tcp_http.h"
 

	
src/network/core/udp.cpp
Show inline comments
 
@@ -12,6 +12,7 @@
 
#include "../../stdafx.h"
 
#include "../../date_func.h"
 
#include "../../debug.h"
 
#include "game_info.h"
 
#include "udp.h"
 

	
 
#include "../../safeguards.h"
 
@@ -150,142 +151,6 @@ void NetworkUDPSocketHandler::ReceivePac
 
	}
 
}
 

	
 

	
 
/**
 
 * Serializes the NetworkGameInfo struct to the packet
 
 * @param p    the packet to write the data to
 
 * @param info the NetworkGameInfo struct to serialize
 
 */
 
void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
 
{
 
	p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
 

	
 
	/*
 
	 *              Please observe the order.
 
	 * The parts must be read in the same order as they are sent!
 
	 */
 

	
 
	/* Update the documentation in udp.h on changes
 
	 * to the NetworkGameInfo wire-protocol! */
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 4 */
 
	{
 
		/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
 
		 * the GRFs that are needed, i.e. the ones that the server has
 
		 * selected in the NewGRF GUI and not the ones that are used due
 
		 * to the fact that they are in [newgrf-static] in openttd.cfg */
 
		const GRFConfig *c;
 
		uint count = 0;
 

	
 
		/* Count number of GRFs to send information about */
 
		for (c = info->grfconfig; c != nullptr; c = c->next) {
 
			if (!HasBit(c->flags, GCF_STATIC)) count++;
 
		}
 
		p->Send_uint8 (count); // Send number of GRFs
 

	
 
		/* Send actual GRF Identifications */
 
		for (c = info->grfconfig; c != nullptr; c = c->next) {
 
			if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
 
		}
 
	}
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 3 */
 
	p->Send_uint32(info->game_date);
 
	p->Send_uint32(info->start_date);
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 2 */
 
	p->Send_uint8 (info->companies_max);
 
	p->Send_uint8 (info->companies_on);
 
	p->Send_uint8 (info->spectators_max);
 

	
 
	/* NETWORK_GAME_INFO_VERSION = 1 */
 
	p->Send_string(info->server_name);
 
	p->Send_string(info->server_revision);
 
	p->Send_uint8 (0); // Used to be server-lang.
 
	p->Send_bool  (info->use_password);
 
	p->Send_uint8 (info->clients_max);
 
	p->Send_uint8 (info->clients_on);
 
	p->Send_uint8 (info->spectators_on);
 
	p->Send_string(""); // Used to be map-name.
 
	p->Send_uint16(info->map_width);
 
	p->Send_uint16(info->map_height);
 
	p->Send_uint8 (info->map_set);
 
	p->Send_bool  (info->dedicated);
 
}
 

	
 
/**
 
 * Deserializes the NetworkGameInfo struct from the packet
 
 * @param p    the packet to read the data from
 
 * @param info the NetworkGameInfo to deserialize into
 
 */
 
void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info)
 
{
 
	static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
 

	
 
	info->game_info_version = p->Recv_uint8();
 

	
 
	/*
 
	 *              Please observe the order.
 
	 * The parts must be read in the same order as they are sent!
 
	 */
 

	
 
	/* Update the documentation in udp.h on changes
 
	 * to the NetworkGameInfo wire-protocol! */
 

	
 
	switch (info->game_info_version) {
 
		case 4: {
 
			GRFConfig **dst = &info->grfconfig;
 
			uint i;
 
			uint num_grfs = p->Recv_uint8();
 

	
 
			/* Broken/bad data. It cannot have that many NewGRFs. */
 
			if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
 

	
 
			for (i = 0; i < num_grfs; i++) {
 
				GRFConfig *c = new GRFConfig();
 
				this->ReceiveGRFIdentifier(p, &c->ident);
 
				this->HandleIncomingNetworkGameInfoGRFConfig(c);
 

	
 
				/* Append GRFConfig to the list */
 
				*dst = c;
 
				dst = &c->next;
 
			}
 
			FALLTHROUGH;
 
		}
 

	
 
		case 3:
 
			info->game_date      = Clamp(p->Recv_uint32(), 0, MAX_DATE);
 
			info->start_date     = Clamp(p->Recv_uint32(), 0, MAX_DATE);
 
			FALLTHROUGH;
 

	
 
		case 2:
 
			info->companies_max  = p->Recv_uint8 ();
 
			info->companies_on   = p->Recv_uint8 ();
 
			info->spectators_max = p->Recv_uint8 ();
 
			FALLTHROUGH;
 

	
 
		case 1:
 
			p->Recv_string(info->server_name,     sizeof(info->server_name));
 
			p->Recv_string(info->server_revision, sizeof(info->server_revision));
 
			p->Recv_uint8 (); // Used to contain server-lang.
 
			info->use_password   = p->Recv_bool  ();
 
			info->clients_max    = p->Recv_uint8 ();
 
			info->clients_on     = p->Recv_uint8 ();
 
			info->spectators_on  = p->Recv_uint8 ();
 
			if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
 
				info->game_date    = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
				info->start_date   = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
 
			}
 
			while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
 
			info->map_width      = p->Recv_uint16();
 
			info->map_height     = p->Recv_uint16();
 
			info->map_set        = p->Recv_uint8 ();
 
			info->dedicated      = p->Recv_bool  ();
 

	
 
			if (info->map_set     >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
 
	}
 
}
 

	
 
/**
 
 * Handle an incoming packets by sending it to the correct function.
 
 * @param p the received packet
src/network/core/udp.h
Show inline comments
 
@@ -13,7 +13,6 @@
 
#define NETWORK_CORE_UDP_H
 

	
 
#include "address.h"
 
#include "game.h"
 
#include "packet.h"
 

	
 
/** Enum with all types of UDP packets. The order MUST not be changed **/
 
@@ -63,40 +62,7 @@ protected:
 

	
 
	/**
 
	 * Return of server information to the client.
 
	 * This packet has several legacy versions, so we list the version and size of each "field":
 
	 *
 
	 * Version: Bytes:  Description:
 
	 *   all      1       the version of this packet's structure
 
	 *
 
	 *   4+       1       number of GRFs attached (n)
 
	 *   4+       n * 20  unique identifier for GRF files. Consists of:
 
	 *                     - one 4 byte variable with the GRF ID
 
	 *                     - 16 bytes (sent sequentially) for the MD5 checksum
 
	 *                       of the GRF
 
	 *
 
	 *   3+       4       current game date in days since 1-1-0 (DMY)
 
	 *   3+       4       game introduction date in days since 1-1-0 (DMY)
 
	 *
 
	 *   2+       1       maximum number of companies allowed on the server
 
	 *   2+       1       number of companies on the server
 
	 *   2+       1       maximum number of spectators allowed on the server
 
	 *
 
	 *   1+       var     string with the name of the server
 
	 *   1+       var     string with the revision of the server
 
	 *   1+       1       the language run on the server
 
	 *                    (0 = any, 1 = English, 2 = German, 3 = French)
 
	 *   1+       1       whether the server uses a password (0 = no, 1 = yes)
 
	 *   1+       1       maximum number of clients allowed on the server
 
	 *   1+       1       number of clients on the server
 
	 *   1+       1       number of spectators on the server
 
	 *   1 & 2    2       current game date in days since 1-1-1920 (DMY)
 
	 *   1 & 2    2       game introduction date in days since 1-1-1920 (DMY)
 
	 *   1+       var     string with the name of the map
 
	 *   1+       2       width of the map in tiles
 
	 *   1+       2       height of the map in tiles
 
	 *   1+       1       type of map:
 
	 *                    (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland)
 
	 *   1+       1       whether the server is dedicated (0 = no, 1 = yes)
 
	 * Serialized NetworkGameInfo. See game_info.h for details.
 
	 * @param p           The received packet.
 
	 * @param client_addr The origin of the packet.
 
	 */
 
@@ -217,15 +183,6 @@ protected:
 
	virtual void Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr);
 

	
 
	void HandleUDPPacket(Packet *p, NetworkAddress *client_addr);
 

	
 
	/**
 
	 * Function that is called for every GRFConfig that is read when receiving
 
	 * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This
 
	 * function must set all appropriate fields. This GRF is later appended to
 
	 * the grfconfig list of the NetworkGameInfo.
 
	 * @param config the GRF to handle
 
	 */
 
	virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); }
 
public:
 
	NetworkUDPSocketHandler(NetworkAddressList *bind = nullptr);
 

	
 
@@ -237,9 +194,6 @@ public:
 

	
 
	void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false);
 
	void ReceivePackets();
 

	
 
	void SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info);
 
	void ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info);
 
};
 

	
 
#endif /* NETWORK_CORE_UDP_H */
src/network/network.cpp
Show inline comments
 
@@ -54,7 +54,6 @@ bool _network_server;     ///< network-s
 
bool _network_available;  ///< is network mode available?
 
bool _network_dedicated;  ///< are we a dedicated server?
 
bool _is_network_server;  ///< Does this client wants to be a network-server?
 
NetworkServerGameInfo _network_game_info; ///< Information about our game.
 
NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies.
 
ClientID _network_own_client_id;      ///< Our client identifier.
 
ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client.
 
@@ -603,9 +602,10 @@ public:
 
	}
 
};
 

	
 
/* Query a server to fetch his game-info
 
 *  If game_info is true, only the gameinfo is fetched,
 
 *   else only the client_info is fetched */
 
/**
 
 * Query a server to fetch his game-info.
 
 * @param address the address to query.
 
 */
 
void NetworkTCPQueryServer(NetworkAddress address)
 
{
 
	if (!_network_available) return;
 
@@ -1110,79 +1110,6 @@ void NetworkShutDown()
 
	NetworkCoreShutdown();
 
}
 

	
 
/**
 
 * How many hex digits of the git hash to include in network revision string.
 
 * Determined as 10 hex digits + 2 characters for -g/-u/-m prefix.
 
 */
 
static const uint GITHASH_SUFFIX_LEN = 12;
 

	
 
/**
 
 * Get the network version string used by this build.
 
 * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes.
 
 */
 
const char * GetNetworkRevisionString()
 
{
 
	/* This will be allocated on heap and never free'd, but only once so not a "real" leak. */
 
	static char *network_revision = nullptr;
 

	
 
	if (!network_revision) {
 
		/* Start by taking a chance on the full revision string. */
 
		network_revision = stredup(_openttd_revision);
 
		/* Ensure it's not longer than the packet buffer length. */
 
		if (strlen(network_revision) >= NETWORK_REVISION_LENGTH) network_revision[NETWORK_REVISION_LENGTH - 1] = '\0';
 

	
 
		/* Tag names are not mangled further. */
 
		if (_openttd_revision_tagged) {
 
			DEBUG(net, 1, "Network revision name is '%s'", network_revision);
 
			return network_revision;
 
		}
 

	
 
		/* Prepare a prefix of the git hash.
 
		* Size is length + 1 for terminator, +2 for -g prefix. */
 
		assert(_openttd_revision_modified < 3);
 
		char githash_suffix[GITHASH_SUFFIX_LEN + 1] = "-";
 
		githash_suffix[1] = "gum"[_openttd_revision_modified];
 
		for (uint i = 2; i < GITHASH_SUFFIX_LEN; i++) {
 
			githash_suffix[i] = _openttd_revision_hash[i-2];
 
		}
 

	
 
		/* Where did the hash start in the original string?
 
		 * Overwrite from that position, unless that would go past end of packet buffer length. */
 
		ptrdiff_t hashofs = strrchr(_openttd_revision, '-') - _openttd_revision;
 
		if (hashofs + strlen(githash_suffix) + 1 > NETWORK_REVISION_LENGTH) hashofs = strlen(network_revision) - strlen(githash_suffix);
 
		/* Replace the git hash in revision string. */
 
		strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH);
 
		assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than
 
		DEBUG(net, 1, "Network revision name is '%s'", network_revision);
 
	}
 

	
 
	return network_revision;
 
}
 

	
 
static const char *ExtractNetworkRevisionHash(const char *revstr)
 
{
 
	return strrchr(revstr, '-');
 
}
 

	
 
/**
 
 * Checks whether the given version string is compatible with our version.
 
 * First tries to match the full string, if that fails, attempts to compare just git hashes.
 
 * @param other the version string to compare to
 
 */
 
bool IsNetworkCompatibleVersion(const char *other)
 
{
 
	if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true;
 

	
 
	/* If this version is tagged, then the revision string must be a complete match,
 
	 * since there is no git hash suffix in it.
 
	 * This is needed to avoid situations like "1.9.0-beta1" comparing equal to "2.0.0-beta1".  */
 
	if (_openttd_revision_tagged) return false;
 

	
 
	const char *hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString());
 
	const char *hash2 = ExtractNetworkRevisionHash(other);
 
	return hash1 && hash2 && (strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0);
 
}
 

	
 
#ifdef __EMSCRIPTEN__
 
extern "C" {
 

	
src/network/network_admin.cpp
Show inline comments
 
@@ -10,6 +10,7 @@
 
#include "../stdafx.h"
 
#include "../strings_func.h"
 
#include "../date_func.h"
 
#include "core/game_info.h"
 
#include "network_admin.h"
 
#include "network_base.h"
 
#include "network_server.h"
src/network/network_base.h
Show inline comments
 
@@ -14,6 +14,7 @@
 
#include "core/address.h"
 
#include "../core/pool_type.hpp"
 
#include "../company_type.h"
 
#include "../date_type.h"
 

	
 
/** Type for the pool with client information. */
 
typedef Pool<NetworkClientInfo, ClientIndex, 8, MAX_CLIENT_SLOTS, PT_NCLIENT> NetworkClientInfoPool;
src/network/network_client.cpp
Show inline comments
 
@@ -23,6 +23,7 @@
 
#include "../gfx_func.h"
 
#include "../error.h"
 
#include "../rev.h"
 
#include "core/game_info.h"
 
#include "network.h"
 
#include "network_base.h"
 
#include "network_client.h"
 
@@ -730,7 +731,7 @@ NetworkRecvStatus ClientNetworkGameSocke
 
	/* Check all GRFs */
 
	for (; grf_count > 0; grf_count--) {
 
		GRFIdentifier c;
 
		this->ReceiveGRFIdentifier(p, &c);
 
		DeserializeGRFIdentifier(p, &c);
 

	
 
		/* Check whether we know this GRF */
 
		const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum);
src/network/network_func.h
Show inline comments
 
@@ -22,8 +22,8 @@
 
#include "../gfx_type.h"
 
#include "../openttd.h"
 
#include "../company_type.h"
 
#include "../string_type.h"
 

	
 
extern NetworkServerGameInfo _network_game_info;
 
extern NetworkCompanyState *_network_company_states;
 

	
 
extern ClientID _network_own_client_id;
src/network/network_gamelist.h
Show inline comments
 
@@ -11,6 +11,7 @@
 
#define NETWORK_GAMELIST_H
 

	
 
#include "core/address.h"
 
#include "core/game_info.h"
 
#include "network_type.h"
 

	
 
/** Structure with information shown in the game list (GUI) */
src/network/network_gui.h
Show inline comments
 
@@ -11,6 +11,7 @@
 
#define NETWORK_GUI_H
 

	
 
#include "../company_type.h"
 
#include "../date_type.h"
 
#include "../economy_type.h"
 
#include "../window_type.h"
 
#include "network_type.h"
src/network/network_internal.h
Show inline comments
 
@@ -94,8 +94,6 @@ void NetworkAddServer(const char *b);
 
void NetworkRebuildHostList();
 
void UpdateNetworkGameWindow();
 

	
 
bool IsNetworkCompatibleVersion(const char *version);
 

	
 
/* From network_command.cpp */
 
/**
 
 * Everything we need to know about a command to be able to execute it.
src/network/network_server.cpp
Show inline comments
 
@@ -10,6 +10,7 @@
 
#include "../stdafx.h"
 
#include "../strings_func.h"
 
#include "../date_func.h"
 
#include "core/game_info.h"
 
#include "network_admin.h"
 
#include "network_server.h"
 
#include "network_udp.h"
 
@@ -477,7 +478,7 @@ NetworkRecvStatus ServerNetworkGameSocke
 

	
 
	p->Send_uint8 (grf_count);
 
	for (c = _grfconfig; c != nullptr; c = c->next) {
 
		if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
 
		if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident);
 
	}
 

	
 
	this->SendPacket(p);
src/network/network_type.h
Show inline comments
 
@@ -10,7 +10,7 @@
 
#ifndef NETWORK_TYPE_H
 
#define NETWORK_TYPE_H
 

	
 
#include "core/game.h"
 
#include "core/config.h"
 

	
 
/** How many clients can we have */
 
static const uint MAX_CLIENTS = 255;
src/network/network_udp.cpp
Show inline comments
 
@@ -16,6 +16,7 @@
 
#include "../date_func.h"
 
#include "../map_func.h"
 
#include "../debug.h"
 
#include "core/game_info.h"
 
#include "network_gamelist.h"
 
#include "network_internal.h"
 
#include "network_udp.h"
 
@@ -171,29 +172,10 @@ void ServerNetworkUDPSocketHandler::Rece
 
	}
 

	
 
	NetworkGameInfo ngi;
 

	
 
	/* Update some game_info */
 
	ngi.clients_on     = _network_game_info.clients_on;
 
	ngi.start_date     = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
 

	
 
	ngi.use_password   = !StrEmpty(_settings_client.network.server_password);
 
	ngi.clients_max    = _settings_client.network.max_clients;
 
	ngi.companies_on   = (byte)Company::GetNumItems();
 
	ngi.companies_max  = _settings_client.network.max_companies;
 
	ngi.spectators_on  = NetworkSpectatorCount();
 
	ngi.spectators_max = _settings_client.network.max_spectators;
 
	ngi.game_date      = _date;
 
	ngi.map_width      = MapSizeX();
 
	ngi.map_height     = MapSizeY();
 
	ngi.map_set        = _settings_game.game_creation.landscape;
 
	ngi.dedicated      = _network_dedicated;
 
	ngi.grfconfig      = _grfconfig;
 

	
 
	strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name));
 
	strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision));
 
	FillNetworkGameInfo(ngi);
 

	
 
	Packet packet(PACKET_UDP_SERVER_RESPONSE);
 
	this->SendNetworkGameInfo(&packet, &ngi);
 
	SerializeNetworkGameInfo(&packet, &ngi);
 

	
 
	/* Let the client know that we are here */
 
	this->SendPacket(&packet, client_addr);
 
@@ -284,7 +266,7 @@ void ServerNetworkUDPSocketHandler::Rece
 
		GRFIdentifier c;
 
		const GRFConfig *f;
 

	
 
		this->ReceiveGRFIdentifier(p, &c);
 
		DeserializeGRFIdentifier(p, &c);
 

	
 
		/* Find the matching GRF file */
 
		f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum);
 
@@ -311,7 +293,7 @@ void ServerNetworkUDPSocketHandler::Rece
 

	
 
		/* The name could be an empty string, if so take the filename */
 
		strecpy(name, in_reply[i]->GetName(), lastof(name));
 
		this->SendGRFIdentifier(&packet, &in_reply[i]->ident);
 
		SerializeGRFIdentifier(&packet, &in_reply[i]->ident);
 
		packet.Send_string(name);
 
	}
 

	
 
@@ -326,7 +308,6 @@ protected:
 
	void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) override;
 
	void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) override;
 
	void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) override;
 
	void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) override;
 
public:
 
	virtual ~ClientNetworkUDPSocketHandler() {}
 
};
 
@@ -344,7 +325,7 @@ void ClientNetworkUDPSocketHandler::Rece
 
	item = NetworkGameListAddItem(*client_addr);
 

	
 
	ClearGRFConfigList(&item->info.grfconfig);
 
	this->ReceiveNetworkGameInfo(p, &item->info);
 
	DeserializeNetworkGameInfo(p, &item->info);
 

	
 
	item->info.compatible = true;
 
	{
 
@@ -373,7 +354,7 @@ void ClientNetworkUDPSocketHandler::Rece
 

	
 
			packet.Send_uint8(in_request_count);
 
			for (i = 0; i < in_request_count; i++) {
 
				this->SendGRFIdentifier(&packet, &in_request[i]->ident);
 
				SerializeGRFIdentifier(&packet, &in_request[i]->ident);
 
			}
 

	
 
			this->SendPacket(&packet, &item->address);
 
@@ -447,7 +428,7 @@ void ClientNetworkUDPSocketHandler::Rece
 
		char name[NETWORK_GRF_NAME_LENGTH];
 
		GRFIdentifier c;
 

	
 
		this->ReceiveGRFIdentifier(p, &c);
 
		DeserializeGRFIdentifier(p, &c);
 
		p->Recv_string(name, sizeof(name));
 

	
 
		/* An empty name is not possible under normal circumstances
 
@@ -464,25 +445,6 @@ void ClientNetworkUDPSocketHandler::Rece
 
	}
 
}
 

	
 
void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
 
{
 
	/* Find the matching GRF file */
 
	const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum);
 
	if (f == nullptr) {
 
		/* Don't know the GRF, so mark game incompatible and the (possibly)
 
		 * already resolved name for this GRF (another server has sent the
 
		 * name of the GRF already */
 
		config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true);
 
		config->status = GCS_NOT_FOUND;
 
	} else {
 
		config->filename = f->filename;
 
		config->name = f->name;
 
		config->info = f->info;
 
		config->url = f->url;
 
	}
 
	SetBit(config->flags, GCF_COPY);
 
}
 

	
 
/** Broadcast to all ips */
 
static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket)
 
{
0 comments (0 inline, 0 general)