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:
Jonathan G Rennison
2021-09-18 22:10:04 +01:00
47 changed files with 525 additions and 350 deletions

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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;
}
/**

View File

@@ -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 */

View File

@@ -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.

View File

@@ -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);

View File

@@ -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() {}

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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),

View File

@@ -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);