Merge commit 'f1dfa661a1898cde06a38ab4cb230c95912b245b' into jgrpp-beta
# Conflicts: # src/lang/estonian.txt # src/lang/hungarian.txt # src/network/core/game_info.cpp # src/network/core/game_info.h # src/network/core/packet.h # src/network/network.cpp # src/network/network_client.cpp # src/network/network_server.cpp # src/network/network_udp.cpp # src/openttd.cpp # src/string_func.h
This commit is contained in:
@@ -23,11 +23,13 @@ static const int DEFAULT_CONNECT_TIMEOUT_SECONDS = 3; ///< Allow connect() three
|
||||
*/
|
||||
const char *NetworkAddress::GetHostname()
|
||||
{
|
||||
if (StrEmpty(this->hostname) && this->address.ss_family != AF_UNSPEC) {
|
||||
if (this->hostname.empty() && this->address.ss_family != AF_UNSPEC) {
|
||||
assert(this->address_length != 0);
|
||||
getnameinfo((struct sockaddr *)&this->address, this->address_length, this->hostname, sizeof(this->hostname), nullptr, 0, NI_NUMERICHOST);
|
||||
char buffer[NETWORK_HOSTNAME_LENGTH];
|
||||
getnameinfo((struct sockaddr *)&this->address, this->address_length, buffer, sizeof(buffer), nullptr, 0, NI_NUMERICHOST);
|
||||
this->hostname = buffer;
|
||||
}
|
||||
return this->hostname;
|
||||
return this->hostname.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,32 +246,32 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
/* Setting both hostname to nullptr and port to 0 is not allowed.
|
||||
* As port 0 means bind to any port, the other must mean that
|
||||
* we want to bind to 'all' IPs. */
|
||||
if (StrEmpty(this->hostname) && this->address_length == 0 && this->GetPort() == 0) {
|
||||
if (this->hostname.empty() && this->address_length == 0 && this->GetPort() == 0) {
|
||||
reset_hostname = true;
|
||||
int fam = this->address.ss_family;
|
||||
if (fam == AF_UNSPEC) fam = family;
|
||||
strecpy(this->hostname, fam == AF_INET ? "0.0.0.0" : "::", lastof(this->hostname));
|
||||
this->hostname = fam == AF_INET ? "0.0.0.0" : "::";
|
||||
}
|
||||
|
||||
static bool _resolve_timeout_error_message_shown = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
int e = getaddrinfo(StrEmpty(this->hostname) ? nullptr : this->hostname, port_name, &hints, &ai);
|
||||
int e = getaddrinfo(this->hostname.empty() ? nullptr : this->hostname.c_str(), port_name, &hints, &ai);
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
std::chrono::seconds duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
|
||||
if (!_resolve_timeout_error_message_shown && duration >= std::chrono::seconds(5)) {
|
||||
DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s took %i seconds",
|
||||
this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), (int)duration.count());
|
||||
this->hostname.c_str(), port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), (int)duration.count());
|
||||
DEBUG(net, 0, " this is likely an issue in the DNS name resolver's configuration causing it to time out");
|
||||
_resolve_timeout_error_message_shown = true;
|
||||
}
|
||||
|
||||
|
||||
if (reset_hostname) strecpy(this->hostname, "", lastof(this->hostname));
|
||||
if (reset_hostname) this->hostname.clear();
|
||||
|
||||
if (e != 0) {
|
||||
if (func != ResolveLoopProc) {
|
||||
DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s failed: %s",
|
||||
this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e)).c_str());
|
||||
this->hostname.c_str(), port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e)).c_str());
|
||||
}
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
@@ -452,11 +454,11 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets)
|
||||
{
|
||||
assert(sockets != nullptr);
|
||||
|
||||
/* Setting both hostname to nullptr and port to 0 is not allowed.
|
||||
/* Setting both hostname to "" and port to 0 is not allowed.
|
||||
* As port 0 means bind to any port, the other must mean that
|
||||
* we want to bind to 'all' IPs. */
|
||||
if (this->address_length == 0 && this->address.ss_family == AF_UNSPEC &&
|
||||
StrEmpty(this->hostname) && this->GetPort() == 0) {
|
||||
this->hostname.empty() && this->GetPort() == 0) {
|
||||
this->Resolve(AF_INET, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc);
|
||||
this->Resolve(AF_INET6, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc);
|
||||
} else {
|
||||
|
||||
@@ -28,10 +28,10 @@ typedef SmallMap<NetworkAddress, SOCKET> SocketList; ///< Type for a mapping
|
||||
*/
|
||||
class NetworkAddress {
|
||||
private:
|
||||
char hostname[NETWORK_HOSTNAME_LENGTH]; ///< The hostname
|
||||
int address_length; ///< The length of the resolved address
|
||||
sockaddr_storage address; ///< The resolved address
|
||||
bool resolved; ///< Whether the address has been (tried to be) resolved
|
||||
std::string hostname; ///< The hostname
|
||||
int address_length; ///< The length of the resolved address
|
||||
sockaddr_storage address; ///< The resolved address
|
||||
bool resolved; ///< Whether the address has been (tried to be) resolved
|
||||
|
||||
/**
|
||||
* Helper function to resolve something to a socket.
|
||||
@@ -52,7 +52,6 @@ public:
|
||||
address(address),
|
||||
resolved(address_length != 0)
|
||||
{
|
||||
*this->hostname = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +63,6 @@ public:
|
||||
address_length(address_length),
|
||||
resolved(address_length != 0)
|
||||
{
|
||||
*this->hostname = '\0';
|
||||
memset(&this->address, 0, sizeof(this->address));
|
||||
memcpy(&this->address, address, address_length);
|
||||
}
|
||||
@@ -75,16 +73,15 @@ public:
|
||||
* @param port the port
|
||||
* @param family the address family
|
||||
*/
|
||||
NetworkAddress(const char *hostname = "", uint16 port = 0, int family = AF_UNSPEC) :
|
||||
NetworkAddress(std::string_view hostname = "", uint16 port = 0, int family = AF_UNSPEC) :
|
||||
address_length(0),
|
||||
resolved(false)
|
||||
{
|
||||
/* Also handle IPv6 bracket enclosed hostnames */
|
||||
if (StrEmpty(hostname)) hostname = "";
|
||||
if (*hostname == '[') hostname++;
|
||||
strecpy(this->hostname, StrEmpty(hostname) ? "" : hostname, lastof(this->hostname));
|
||||
char *tmp = strrchr(this->hostname, ']');
|
||||
if (tmp != nullptr) *tmp = '\0';
|
||||
if (!hostname.empty() && hostname.front() == '[' && hostname.back() == ']') {
|
||||
hostname.remove_prefix(1);
|
||||
hostname.remove_suffix(1);
|
||||
}
|
||||
this->hostname = hostname;
|
||||
|
||||
memset(&this->address, 0, sizeof(this->address));
|
||||
this->address.ss_family = family;
|
||||
|
||||
@@ -113,7 +113,7 @@ bool IsNetworkCompatibleVersion(const char *other, bool extended)
|
||||
void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended)
|
||||
{
|
||||
/* Check if we are allowed on this server based on the revision-check. */
|
||||
ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision, extended);
|
||||
ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision.c_str(), extended);
|
||||
ngi.compatible = ngi.version_compatible;
|
||||
|
||||
/* Check if we have all the GRFs on the client-system too. */
|
||||
@@ -123,31 +123,37 @@ void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill a NetworkGameInfo structure with the latest information of the server.
|
||||
* @param ngi the NetworkGameInfo struct to fill with data.
|
||||
* Fill a NetworkServerGameInfo structure with the static content, or things
|
||||
* that are so static they can be updated on request from a settings change.
|
||||
*/
|
||||
void FillNetworkGameInfo(NetworkGameInfo &ngi)
|
||||
void FillStaticNetworkServerGameInfo()
|
||||
{
|
||||
/* Update some game_info */
|
||||
ngi.clients_on = _network_game_info.clients_on;
|
||||
ngi.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
|
||||
_network_game_info.use_password = !StrEmpty(_settings_client.network.server_password);
|
||||
_network_game_info.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
|
||||
_network_game_info.clients_max = _settings_client.network.max_clients;
|
||||
_network_game_info.companies_max = _settings_client.network.max_companies;
|
||||
_network_game_info.spectators_max = _settings_client.network.max_spectators;
|
||||
_network_game_info.map_width = MapSizeX();
|
||||
_network_game_info.map_height = MapSizeY();
|
||||
_network_game_info.landscape = _settings_game.game_creation.landscape;
|
||||
_network_game_info.dedicated = _network_dedicated;
|
||||
_network_game_info.grfconfig = _grfconfig;
|
||||
|
||||
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;
|
||||
_network_game_info.server_name = _settings_client.network.server_name;
|
||||
_network_game_info.server_revision = GetNetworkRevisionString();
|
||||
}
|
||||
|
||||
strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name));
|
||||
strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision));
|
||||
strecpy(ngi.short_server_revision, _openttd_revision, lastof(ngi.short_server_revision));
|
||||
/**
|
||||
* Get the NetworkServerGameInfo structure with the latest information of the server.
|
||||
* @return The current NetworkServerGameInfo.
|
||||
*/
|
||||
const NetworkServerGameInfo *GetCurrentNetworkServerGameInfo()
|
||||
{
|
||||
/* Client_on is used as global variable to keep track on the number of clients. */
|
||||
_network_game_info.companies_on = (byte)Company::GetNumItems();
|
||||
_network_game_info.spectators_on = NetworkSpectatorCount();
|
||||
_network_game_info.game_date = _date;
|
||||
return &_network_game_info;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +187,7 @@ static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config)
|
||||
* @param p the packet to write the data to.
|
||||
* @param info the NetworkGameInfo struct to serialize from.
|
||||
*/
|
||||
void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
|
||||
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info)
|
||||
{
|
||||
p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
|
||||
|
||||
@@ -247,7 +253,7 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
|
||||
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_uint8 (info->landscape);
|
||||
p->Send_bool (info->dedicated);
|
||||
}
|
||||
|
||||
@@ -256,7 +262,7 @@ void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
|
||||
* @param p the packet to write the data to
|
||||
* @param info the NetworkGameInfo struct to serialize
|
||||
*/
|
||||
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, uint16 flags, uint16 version)
|
||||
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkServerGameInfo *info, uint16 flags, uint16 version)
|
||||
{
|
||||
p->Send_uint8(0); // version num
|
||||
|
||||
@@ -275,7 +281,7 @@ void SerializeNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, ui
|
||||
p->Send_string(""); // Used to be map-name.
|
||||
p->Send_uint32(info->map_width);
|
||||
p->Send_uint32(info->map_height);
|
||||
p->Send_uint8 (info->map_set);
|
||||
p->Send_uint8 (info->landscape);
|
||||
p->Send_bool (info->dedicated);
|
||||
|
||||
{
|
||||
@@ -310,7 +316,7 @@ 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();
|
||||
byte game_info_version = p->Recv_uint8();
|
||||
|
||||
/*
|
||||
* Please observe the order.
|
||||
@@ -320,7 +326,7 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
|
||||
/* Update the documentation in game_info.h on changes
|
||||
* to the NetworkGameInfo wire-protocol! */
|
||||
|
||||
switch (info->game_info_version) {
|
||||
switch (game_info_version) {
|
||||
case 4: {
|
||||
GRFConfig **dst = &info->grfconfig;
|
||||
uint i;
|
||||
@@ -353,24 +359,24 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info)
|
||||
FALLTHROUGH;
|
||||
|
||||
case 1:
|
||||
p->Recv_string(info->server_name, sizeof(info->server_name));
|
||||
p->Recv_string(info->server_revision, sizeof(info->server_revision));
|
||||
info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
|
||||
info->server_revision = p->Recv_string(NETWORK_REVISION_LENGTH);
|
||||
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
|
||||
if (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->landscape = p->Recv_uint8 ();
|
||||
info->dedicated = p->Recv_bool ();
|
||||
|
||||
if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
|
||||
if (info->landscape >= NETWORK_NUM_LANDSCAPES) info->landscape = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,15 +392,13 @@ void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
|
||||
const uint8 version = p->Recv_uint8();
|
||||
if (version > 0) return; // Unknown version
|
||||
|
||||
info->game_info_version = 255;
|
||||
|
||||
info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
|
||||
info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
|
||||
info->companies_max = p->Recv_uint8 ();
|
||||
info->companies_on = p->Recv_uint8 ();
|
||||
info->spectators_max = p->Recv_uint8 ();
|
||||
p->Recv_string(info->server_name, sizeof(info->server_name));
|
||||
p->Recv_string(info->server_revision, sizeof(info->server_revision));
|
||||
info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);
|
||||
info->server_revision = p->Recv_string(NETWORK_LONG_REVISION_LENGTH);
|
||||
p->Recv_uint8 (); // Used to contain server-lang.
|
||||
info->use_password = p->Recv_bool ();
|
||||
info->clients_max = p->Recv_uint8 ();
|
||||
@@ -403,7 +407,7 @@ void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
|
||||
while (p->Recv_uint8() != 0) {} // Used to contain the map-name.
|
||||
info->map_width = p->Recv_uint32();
|
||||
info->map_height = p->Recv_uint32();
|
||||
info->map_set = p->Recv_uint8 ();
|
||||
info->landscape = p->Recv_uint8 ();
|
||||
info->dedicated = p->Recv_bool ();
|
||||
|
||||
{
|
||||
@@ -425,7 +429,7 @@ void DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
|
||||
}
|
||||
}
|
||||
|
||||
if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
|
||||
if (info->landscape >= NETWORK_NUM_LANDSCAPES) info->landscape = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,36 +57,34 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The game information that is not generated on-the-fly and has to
|
||||
* be sent to the clients.
|
||||
* The game information that is sent from the server to the client.
|
||||
*/
|
||||
struct NetworkServerGameInfo {
|
||||
byte clients_on; ///< Current count of clients on server
|
||||
GRFConfig *grfconfig; ///< List of NewGRF files used
|
||||
Date start_date; ///< When the game started
|
||||
Date game_date; ///< Current date
|
||||
uint32 map_width; ///< Map width
|
||||
uint32 map_height; ///< Map height
|
||||
std::string server_name; ///< Server name
|
||||
std::string server_revision; ///< The version number the server is using (e.g.: 'r304' or 0.5.0)
|
||||
bool dedicated; ///< Is this a dedicated server?
|
||||
bool use_password; ///< Is this server passworded?
|
||||
byte clients_on; ///< Current count of clients on server
|
||||
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 landscape; ///< The used landscape
|
||||
};
|
||||
|
||||
/**
|
||||
* The game information that is sent from the server to the clients.
|
||||
* The game information that is sent from the server to the clients
|
||||
* with extra information only required at the client side.
|
||||
*/
|
||||
struct NetworkGameInfo : NetworkServerGameInfo {
|
||||
GRFConfig *grfconfig; ///< List of NewGRF files used
|
||||
Date start_date; ///< When the game started
|
||||
Date game_date; ///< Current date
|
||||
uint32 map_width; ///< Map width
|
||||
uint32 map_height; ///< Map height
|
||||
char server_name[NETWORK_NAME_LENGTH]; ///< Server name
|
||||
char short_server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) (truncated)
|
||||
char server_revision[NETWORK_LONG_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;
|
||||
@@ -95,14 +93,15 @@ const char *GetNetworkRevisionString();
|
||||
bool IsNetworkCompatibleVersion(const char *other, bool extended = false);
|
||||
void CheckGameCompatibility(NetworkGameInfo &ngi, bool extended = false);
|
||||
|
||||
void FillNetworkGameInfo(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 DeserializeNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info);
|
||||
void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info);
|
||||
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, uint16 flags, uint16 version);
|
||||
void SerializeNetworkGameInfo(Packet *p, const NetworkServerGameInfo *info);
|
||||
void SerializeNetworkGameInfoExtended(Packet *p, const NetworkServerGameInfo *info, uint16 flags, uint16 version);
|
||||
|
||||
#endif /* NETWORK_CORE_GAME_INFO_H */
|
||||
|
||||
@@ -168,12 +168,11 @@ void Packet::Send_uint64(uint64 data)
|
||||
* the string + '\0'. No size-byte or something.
|
||||
* @param data The string to send
|
||||
*/
|
||||
void Packet::Send_string(const char *data)
|
||||
void Packet::Send_string(const std::string_view data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
/* Length of the string + 1 for the '\0' termination. */
|
||||
assert(this->CanWriteToPacket(strlen(data) + 1));
|
||||
while (this->buffer.emplace_back(*data++) != '\0') {}
|
||||
assert(this->CanWriteToPacket(data.size() + 1));
|
||||
this->buffer.insert(this->buffer.end(), data.begin(), data.end());
|
||||
this->buffer.emplace_back('\0');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,6 +403,35 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set
|
||||
str_validate(bufp, last, settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads characters (bytes) from the packet until it finds a '\0', or reaches a
|
||||
* maximum of \c length characters.
|
||||
* When the '\0' has not been reached in the first \c length read characters,
|
||||
* more characters are read from the packet until '\0' has been reached. However,
|
||||
* these characters will not end up in the returned string.
|
||||
* The length of the returned string will be at most \c length - 1 characters.
|
||||
* @param length The maximum length of the string including '\0'.
|
||||
* @param settings The string validation settings.
|
||||
* @return The validated string.
|
||||
*/
|
||||
std::string Packet::Recv_string(size_t length, StringValidationSettings settings)
|
||||
{
|
||||
assert(length > 1);
|
||||
|
||||
/* Both loops with Recv_uint8 terminate when reading past the end of the
|
||||
* packet as Recv_uint8 then closes the connection and returns 0. */
|
||||
std::string str;
|
||||
char character;
|
||||
while (--length > 0 && (character = this->Recv_uint8()) != '\0') str.push_back(character);
|
||||
|
||||
if (length == 0) {
|
||||
/* The string in the packet was longer. Read until the termination. */
|
||||
while (this->Recv_uint8() != '\0') {}
|
||||
}
|
||||
|
||||
return str_validate(str, settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of bytes that are still available for the Transfer functions.
|
||||
* @return The number of bytes that still have to be transfered.
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
void Send_uint16(uint16 data);
|
||||
void Send_uint32(uint32 data);
|
||||
void Send_uint64(uint64 data);
|
||||
void Send_string(const char *data);
|
||||
void Send_string(const std::string_view data);
|
||||
size_t Send_bytes (const byte *begin, const byte *end);
|
||||
void Send_binary(const char *data, const size_t size);
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
uint32 Recv_uint32();
|
||||
uint64 Recv_uint64();
|
||||
void Recv_string(char *buffer, size_t size, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
|
||||
std::string Recv_string(size_t length, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
|
||||
void Recv_string(std::string &buffer, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
|
||||
void Recv_binary(char *buffer, size_t size);
|
||||
void Recv_binary(std::string &buffer, size_t size);
|
||||
|
||||
@@ -87,7 +87,7 @@ protected:
|
||||
NetworkAddress address;
|
||||
|
||||
public:
|
||||
TCPConnecter(const NetworkAddress &address);
|
||||
TCPConnecter(const std::string &connection_string, uint16 default_port);
|
||||
/** Silence the warnings */
|
||||
virtual ~TCPConnecter() {}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "../../thread.h"
|
||||
|
||||
#include "tcp.h"
|
||||
#include "../network_internal.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
@@ -21,15 +22,16 @@ static std::vector<TCPConnecter *> _tcp_connecters;
|
||||
|
||||
/**
|
||||
* Create a new connecter for the given address
|
||||
* @param address the (un)resolved address to connect to
|
||||
* @param connection_string the address to connect to
|
||||
*/
|
||||
TCPConnecter::TCPConnecter(const NetworkAddress &address) :
|
||||
TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port) :
|
||||
connected(false),
|
||||
aborted(false),
|
||||
killed(false),
|
||||
sock(INVALID_SOCKET),
|
||||
address(address)
|
||||
sock(INVALID_SOCKET)
|
||||
{
|
||||
this->address = ParseConnectionString(connection_string, default_port);
|
||||
|
||||
_tcp_connecters.push_back(this);
|
||||
if (!StartNewThread(nullptr, "ottd:tcp", &TCPConnecter::ThreadEntry, this)) {
|
||||
this->Connect();
|
||||
|
||||
@@ -203,11 +203,9 @@ int NetworkHTTPSocketHandler::HandleHeader()
|
||||
|
||||
*url = '\0';
|
||||
|
||||
NetworkAddress address = ParseConnectionString(hname, 80);
|
||||
|
||||
/* Restore the URL. */
|
||||
*url = '/';
|
||||
new NetworkHTTPContentConnecter(address, callback, url, data, depth);
|
||||
new NetworkHTTPContentConnecter(hname, callback, url, data, depth);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,16 +81,14 @@ class NetworkHTTPContentConnecter : TCPConnecter {
|
||||
public:
|
||||
/**
|
||||
* Start the connecting.
|
||||
* @param address the address to connect to
|
||||
* @param callback the callback for HTTP retrieval
|
||||
* @param url the url at the server
|
||||
* @param data the data to send
|
||||
* @param depth the depth (redirect recursion) of the queries
|
||||
* @param connection_string The address to connect to.
|
||||
* @param callback The callback for HTTP retrieval.
|
||||
* @param url The url at the server.
|
||||
* @param data The data to send.
|
||||
* @param depth The depth (redirect recursion) of the queries.
|
||||
*/
|
||||
NetworkHTTPContentConnecter(const NetworkAddress &address,
|
||||
HTTPCallback *callback, const char *url,
|
||||
const char *data = nullptr, int depth = 0) :
|
||||
TCPConnecter(address),
|
||||
NetworkHTTPContentConnecter(const std::string &connection_string, HTTPCallback *callback, const char *url, const char *data = nullptr, int depth = 0) :
|
||||
TCPConnecter(connection_string, 80),
|
||||
callback(callback),
|
||||
url(stredup(url)),
|
||||
data(data),
|
||||
|
||||
@@ -28,11 +28,11 @@ NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
|
||||
this->bind.push_back(addr);
|
||||
}
|
||||
} else {
|
||||
/* As hostname nullptr and port 0/nullptr don't go well when
|
||||
/* As an empty hostname and port 0 don't go well when
|
||||
* resolving it we need to add an address for each of
|
||||
* the address families we support. */
|
||||
this->bind.emplace_back(nullptr, 0, AF_INET);
|
||||
this->bind.emplace_back(nullptr, 0, AF_INET6);
|
||||
this->bind.emplace_back("", 0, AF_INET);
|
||||
this->bind.emplace_back("", 0, AF_INET6);
|
||||
}
|
||||
|
||||
this->fragment_token = ((uint64) InteractiveRandom()) | (((uint64) InteractiveRandom()) << 32);
|
||||
|
||||
Reference in New Issue
Block a user