Changeset - r25688:4e6b21bba5fc
[Not reviewed]
master
0 3 0
rubidium42 - 3 years ago 2021-06-13 21:41:15
rubidium@openttd.org
Codechange: [Network] Use string_view for network compatability check
3 files changed with 16 insertions and 14 deletions:
0 comments (0 inline, 0 general)
src/network/core/game_info.cpp
Show inline comments
 
@@ -29,25 +29,25 @@
 
/**
 
 * 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 including '\0' terminator.
 
 */
 
const char *GetNetworkRevisionString()
 
std::string_view GetNetworkRevisionString()
 
{
 
	static std::string network_revision;
 

	
 
	if (network_revision.empty()) {
 
		std::string network_revision = _openttd_revision;
 
		if (_openttd_revision_tagged) {
 
			/* Tagged; do not mangle further, though ensure it's not too long. */
 
			if (network_revision.size() >= NETWORK_REVISION_LENGTH) network_revision.resize(NETWORK_REVISION_LENGTH - 1);
 
		} else {
 
			/* Not tagged; add the githash suffix while ensuring the string does not become too long. */
 
			assert(_openttd_revision_modified < 3);
 
			std::string githash_suffix = fmt::format("-{}{}", "gum"[_openttd_revision_modified], _openttd_revision_hash);
 
@@ -56,63 +56,65 @@ const char *GetNetworkRevisionString()
 
			/* Where did the hash start in the original string? Overwrite from that position, unless that would create a too long string. */
 
			size_t hash_end = network_revision.find_last_of('-');
 
			if (hash_end == std::string::npos) hash_end = network_revision.size();
 
			if (hash_end + githash_suffix.size() >= NETWORK_REVISION_LENGTH) hash_end = NETWORK_REVISION_LENGTH - githash_suffix.size() - 1;
 

	
 
			/* Replace the git hash in revision string. */
 
			network_revision.replace(hash_end, std::string::npos, githash_suffix);
 
		}
 
		assert(network_revision.size() < NETWORK_REVISION_LENGTH); // size does not include terminator, constant does, hence strictly less than
 
		Debug(net, 3, "Network revision name: {}", network_revision);
 
	}
 

	
 
	return network_revision.c_str();
 
	return network_revision;
 
}
 

	
 
/**
 
 * Extract the git hash from the revision string.
 
 * @param revstr The revision string (formatted as DATE-BRANCH-GITHASH).
 
 * @param revision_string The revision string (formatted as DATE-BRANCH-GITHASH).
 
 * @return The git has part of the revision.
 
 */
 
static const char *ExtractNetworkRevisionHash(const char *revstr)
 
static std::string_view ExtractNetworkRevisionHash(std::string_view revision_string)
 
{
 
	return strrchr(revstr, '-');
 
	size_t index = revision_string.find_last_of('-');
 
	if (index == std::string::npos) return {};
 
	return revision_string.substr(index);
 
}
 

	
 
/**
 
 * 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)
 
bool IsNetworkCompatibleVersion(std::string_view other)
 
{
 
	if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true;
 
	if (GetNetworkRevisionString() == other) 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 != nullptr && hash2 != nullptr && strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0;
 
	std::string_view hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString());
 
	std::string_view hash2 = ExtractNetworkRevisionHash(other);
 
	return hash1 == hash2;
 
}
 

	
 
/**
 
 * Check if an game entry is compatible with our client.
 
 */
 
void CheckGameCompatibility(NetworkGameInfo &ngi)
 
{
 
	/* Check if we are allowed on this server based on the revision-check. */
 
	ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision.c_str());
 
	ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision);
 
	ngi.compatible = ngi.version_compatible;
 

	
 
	/* Check if we have all the GRFs on the client-system too. */
 
	for (const GRFConfig *c = ngi.grfconfig; c != nullptr; c = c->next) {
 
		if (c->status == GCS_NOT_FOUND) ngi.compatible = false;
 
	}
 
}
 

	
 
/**
 
 * Fill a NetworkServerGameInfo structure with the static content, or things
 
 * that are so static they can be updated on request from a settings change.
 
 */
src/network/core/game_info.h
Show inline comments
 
@@ -80,26 +80,26 @@ struct NetworkServerGameInfo {
 

	
 
/**
 
 * The game information that is sent from the server to the clients
 
 * with extra information only required at the client side.
 
 */
 
struct NetworkGameInfo : NetworkServerGameInfo {
 
	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
 
};
 

	
 
extern NetworkServerGameInfo _network_game_info;
 

	
 
const char *GetNetworkRevisionString();
 
bool IsNetworkCompatibleVersion(const char *other);
 
std::string_view GetNetworkRevisionString();
 
bool IsNetworkCompatibleVersion(std::string_view other);
 
void CheckGameCompatibility(NetworkGameInfo &ngi);
 

	
 
void FillStaticNetworkServerGameInfo();
 
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo();
 

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

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

	
 
#endif /* NETWORK_CORE_GAME_INFO_H */
src/network/network_server.cpp
Show inline comments
 
@@ -869,25 +869,25 @@ NetworkRecvStatus ServerNetworkGameSocke
 

	
 
NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p)
 
{
 
	if (this->status != STATUS_INACTIVE) {
 
		/* Illegal call, return error and ignore the packet */
 
		return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
 
	}
 

	
 
	std::string client_revision = p->Recv_string(NETWORK_REVISION_LENGTH);
 
	uint32 newgrf_version = p->Recv_uint32();
 

	
 
	/* Check if the client has revision control enabled */
 
	if (!IsNetworkCompatibleVersion(client_revision.c_str()) || _openttd_newgrf_version != newgrf_version) {
 
	if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) {
 
		/* Different revisions!! */
 
		return this->SendError(NETWORK_ERROR_WRONG_REVISION);
 
	}
 

	
 
	std::string client_name = p->Recv_string(NETWORK_CLIENT_NAME_LENGTH);
 
	CompanyID playas = (Owner)p->Recv_uint8();
 

	
 
	if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
 

	
 
	/* join another company does not affect these values */
 
	switch (playas) {
 
		case COMPANY_NEW_COMPANY: // New company
0 comments (0 inline, 0 general)