Changeset - r25392:925cc07e1a56
[Not reviewed]
master
0 4 0
rubidium42 - 3 years ago 2021-05-04 17:32:37
rubidium@openttd.org
Codechange: [Network] Move connection string parsing away from C-strings
4 files changed with 57 insertions and 70 deletions:
0 comments (0 inline, 0 general)
src/network/network.cpp
Show inline comments
 
@@ -33,6 +33,7 @@
 
#include "../core/pool_func.hpp"
 
#include "../gfx_func.h"
 
#include "../error.h"
 
#include <charconv>
 

	
 
#include "../safeguards.h"
 

	
 
@@ -453,36 +454,51 @@ static void CheckPauseOnJoin()
 
 * Converts a string to ip/port/company
 
 *  Format: IP:port#company
 
 *
 
 * connection_string will be re-terminated to separate out the hostname, port will
 
 * be set to the port strings given by the user, inside the memory area originally
 
 * occupied by connection_string. Similar for company, if set.
 
 * Returns the IP part as a string view into the passed string. This view is
 
 * valid as long the passed connection string is valid. If there is no port
 
 * present in the connection string, the port reference will not be touched.
 
 * When there is no company ID present in the connection string or company_id
 
 * is nullptr, then company ID will not be touched.
 
 *
 
 * @param connection_string The string with the connection data.
 
 * @param port              The port reference to set.
 
 * @param company_id        The company ID to set, if available.
 
 * @return A std::string_view into the connection string with the (IP) address part.
 
 */
 
void ParseFullConnectionString(const char **company, const char **port, char *connection_string)
 
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16 &port, CompanyID *company_id)
 
{
 
	bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':'));
 
	for (char *p = connection_string; *p != '\0'; p++) {
 
		switch (*p) {
 
			case '[':
 
				ipv6 = true;
 
				break;
 
	std::string_view ip = connection_string;
 
	if (company_id != nullptr) {
 
		size_t offset = ip.find_last_of('#');
 
		if (offset != std::string::npos) {
 
			std::string_view company_string = ip.substr(offset + 1);
 
			ip = ip.substr(0, offset);
 

	
 
			case ']':
 
				ipv6 = false;
 
				break;
 

	
 
			case '#':
 
				if (company == nullptr) continue;
 
				*company = p + 1;
 
				*p = '\0';
 
				break;
 

	
 
			case ':':
 
				if (ipv6) break;
 
				*port = p + 1;
 
				*p = '\0';
 
				break;
 
			uint8 company_value;
 
			auto [_, err] = std::from_chars(company_string.data(), company_string.data() + company_string.size(), company_value);
 
			if (err == std::errc()) {
 
				if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
 
					if (company_value > MAX_COMPANIES || company_value == 0) {
 
						*company_id = COMPANY_SPECTATOR;
 
					} else {
 
						/* "#1" means the first company, which has index 0. */
 
						*company_id = (CompanyID)(company_value - 1);
 
					}
 
				} else {
 
					*company_id = (CompanyID)company_value;
 
				}
 
			}
 
		}
 
	}
 

	
 
	size_t port_offset = ip.find_last_of(':');
 
	size_t ipv6_close = ip.find_last_of(']');
 
	if (port_offset != std::string::npos && (ipv6_close == std::string::npos || ipv6_close < port_offset)) {
 
		std::string_view port_string = ip.substr(port_offset + 1);
 
		ip = ip.substr(0, port_offset);
 
		std::from_chars(port_string.data(), port_string.data() + port_string.size(), port);
 
	}
 
	return ip;
 
}
 

	
 
/**
 
@@ -493,16 +509,11 @@ void ParseFullConnectionString(const cha
 
 * @param default_port The default port to set port to if not in connection_string.
 
 * @return A valid NetworkAddress of the parsed information.
 
 */
 
NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port)
 
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port)
 
{
 
	char internal_connection_string[NETWORK_HOSTNAME_PORT_LENGTH];
 
	strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string));
 

	
 
	const char *port = nullptr;
 
	ParseFullConnectionString(nullptr, &port, internal_connection_string);
 

	
 
	int rport = port != nullptr ? atoi(port) : default_port;
 
	return NetworkAddress(internal_connection_string, rport);
 
	uint16 port = default_port;
 
	std::string_view ip = ParseFullConnectionString(connection_string, port);
 
	return NetworkAddress(ip, port);
 
}
 

	
 
/**
 
@@ -510,37 +521,16 @@ NetworkAddress ParseConnectionString(con
 
 * NetworkAddress, where the string can be postfixed with "#company" to
 
 * indicate the requested company.
 
 *
 
 * @param company Pointer to the company variable to set iff indicted.
 
 * @param connection_string The string to parse.
 
 * @param default_port The default port to set port to if not in connection_string.
 
 * @param company Pointer to the company variable to set iff indicted.
 
 * @return A valid NetworkAddress of the parsed information.
 
 */
 
static NetworkAddress ParseGameConnectionString(CompanyID *company, const std::string &connection_string, int default_port)
 
static NetworkAddress ParseGameConnectionString(const std::string &connection_string, uint16 default_port, CompanyID *company)
 
{
 
	char internal_connection_string[NETWORK_HOSTNAME_PORT_LENGTH + 4]; // 4 extra for the "#" and company
 
	strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string));
 

	
 
	const char *port_s = nullptr;
 
	const char *company_s = nullptr;
 
	ParseFullConnectionString(&company_s, &port_s, internal_connection_string);
 

	
 
	if (company_s != nullptr) {
 
		uint company_value = atoi(company_s);
 

	
 
		if (company_value != COMPANY_NEW_COMPANY && company_value != COMPANY_SPECTATOR) {
 
			if (company_value > MAX_COMPANIES || company_value == 0) {
 
				*company = COMPANY_SPECTATOR;
 
			} else {
 
				/* "#1" means the first company, which has index 0. */
 
				*company = (CompanyID)(company_value - 1);
 
			}
 
		} else {
 
			*company = (CompanyID)company_value;
 
		}
 
	}
 

	
 
	int port = port_s != nullptr ? atoi(port_s) : default_port;
 
	return NetworkAddress(internal_connection_string, port);
 
	uint16 port = default_port;
 
	std::string_view ip = ParseFullConnectionString(connection_string, port, company);
 
	return NetworkAddress(ip, port);
 
}
 

	
 
/**
 
@@ -751,7 +741,7 @@ public:
 
bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const char *join_server_password, const char *join_company_password)
 
{
 
	CompanyID join_as = default_company;
 
	std::string resolved_connection_string = ParseGameConnectionString(&join_as, connection_string, NETWORK_DEFAULT_PORT).GetAddressAsString(false);
 
	std::string resolved_connection_string = ParseGameConnectionString(connection_string, NETWORK_DEFAULT_PORT, &join_as).GetAddressAsString(false);
 

	
 
	if (!_network_available) return false;
 
	if (!NetworkValidateClientName()) return false;
src/network/network_func.h
Show inline comments
 
@@ -45,7 +45,7 @@ void NetworkReboot();
 
void NetworkDisconnect(bool blocking = false, bool close_admins = true);
 
void NetworkGameLoop();
 
void NetworkBackgroundLoop();
 
void ParseFullConnectionString(const char **company, const char **port, char *connection_string);
 
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16 &port, CompanyID *company_id = nullptr);
 
void NetworkStartDebugLog(const std::string &connection_string);
 
void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
 

	
src/network/network_internal.h
Show inline comments
 
@@ -119,6 +119,6 @@ StringID GetNetworkErrorMsg(NetworkError
 
bool NetworkFindName(char *new_name, const char *last);
 
const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed);
 

	
 
NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port);
 
NetworkAddress ParseConnectionString(const std::string &connection_string, uint16 default_port);
 

	
 
#endif /* NETWORK_INTERNAL_H */
src/openttd.cpp
Show inline comments
 
@@ -405,7 +405,7 @@ void OpenBrowser(const char *url)
 
struct AfterNewGRFScan : NewGRFScanCallback {
 
	Year startyear;                    ///< The start year.
 
	uint32 generation_seed;            ///< Seed for the new game.
 
	char *dedicated_host;              ///< Hostname for the dedicated server.
 
	std::string dedicated_host;        ///< Hostname for the dedicated server.
 
	uint16 dedicated_port;             ///< Port for the dedicated server.
 
	char *network_conn;                ///< Information about the server to connect to, or nullptr.
 
	const char *join_server_password;  ///< The password to join the server with.
 
@@ -417,7 +417,7 @@ struct AfterNewGRFScan : NewGRFScanCallb
 
	 */
 
	AfterNewGRFScan() :
 
			startyear(INVALID_YEAR), generation_seed(GENERATE_NEW_SEED),
 
			dedicated_host(nullptr), dedicated_port(0), network_conn(nullptr),
 
			dedicated_port(0), network_conn(nullptr),
 
			join_server_password(nullptr), join_company_password(nullptr),
 
			save_config(true)
 
	{
 
@@ -458,7 +458,7 @@ struct AfterNewGRFScan : NewGRFScanCallb
 
		if (startyear != INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", startyear);
 
		if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed;
 

	
 
		if (dedicated_host != nullptr) {
 
		if (!dedicated_host.empty()) {
 
			_network_bind_list.clear();
 
			_network_bind_list.emplace_back(dedicated_host);
 
		}
 
@@ -565,10 +565,7 @@ int openttd_main(int argc, char *argv[])
 
			dedicated = true;
 
			SetDebugString("net=6");
 
			if (mgo.opt != nullptr) {
 
				const char *port = nullptr;
 
				ParseFullConnectionString(nullptr, &port, mgo.opt);
 
				if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt;
 
				if (port != nullptr) scanner->dedicated_port = atoi(port);
 
				scanner->dedicated_host = ParseFullConnectionString(mgo.opt, scanner->dedicated_port);
 
			}
 
			break;
 
		case 'f': _dedicated_forks = true; break;
0 comments (0 inline, 0 general)