10#include "../../stdafx.h"
13#include "../network_internal.h"
14#include "../../debug.h"
16#include "../../safeguards.h"
25 if (this->
hostname.empty() && this->address.ss_family != AF_UNSPEC) {
28 getnameinfo((
struct sockaddr *)&this->
address, this->
address_length, buffer,
sizeof(buffer),
nullptr, 0, NI_NUMERICHOST);
40 switch (this->
address.ss_family) {
43 return ntohs(((
const struct sockaddr_in *)&this->
address)->sin_port);
46 return ntohs(((
const struct sockaddr_in6 *)&this->address)->sin6_port);
59 switch (this->
address.ss_family) {
62 ((
struct sockaddr_in*)&this->
address)->sin_port = htons(port);
66 ((
struct sockaddr_in6*)&this->
address)->sin6_port = htons(port);
83 case AF_INET:
return with_family ?
"{}:{} (IPv4)" :
"{}:{}";
84 case AF_INET6:
return with_family ?
"[{}]:{} (IPv6)" :
"[{}]:{}";
85 default:
return with_family ?
"{}:{} (IPv?)" :
"{}:{}";
106 return !INVALID_SOCKET;
137 return this->
address.ss_family == family;
151 int cidr = this->
address.ss_family == AF_INET ? 32 : 128;
156 auto cidr_separator_location = netmask.find(
'/');
157 if (cidr_separator_location != std::string::npos) {
158 int tmp_cidr = atoi(netmask.substr(cidr_separator_location + 1).c_str());
161 if (tmp_cidr > 0 && tmp_cidr < cidr) cidr = tmp_cidr;
164 mask_address =
NetworkAddress(netmask.substr(0, cidr_separator_location), 0, this->address.ss_family);
173 switch (this->
address.ss_family) {
175 ip = (uint32_t*)&((
struct sockaddr_in*)&this->
address)->sin_addr.s_addr;
176 mask = (uint32_t*)&((
struct sockaddr_in*)&mask_address.
address)->sin_addr.s_addr;
180 ip = (uint32_t*)&((
struct sockaddr_in6*)&this->
address)->sin6_addr;
181 mask = (uint32_t*)&((
struct sockaddr_in6*)&mask_address.
address)->sin6_addr;
189 uint32_t msk = cidr >= 32 ? (uint32_t)-1 : htonl(-(1 << (32 - cidr)));
190 if ((*mask++ & msk) != (*ip++ & msk))
return false;
210 struct addrinfo hints;
211 memset(&hints, 0,
sizeof (hints));
212 hints.ai_family = family;
213 hints.ai_flags = flags;
214 hints.ai_socktype = socktype;
217 std::string port_name = std::to_string(this->
GetPort());
219 bool reset_hostname =
false;
223 if (this->
hostname.empty() && this->address_length == 0 && this->GetPort() == 0) {
224 reset_hostname =
true;
225 int fam = this->
address.ss_family;
226 if (fam == AF_UNSPEC) fam = family;
227 this->
hostname = fam == AF_INET ?
"0.0.0.0" :
"::";
230 static bool _resolve_timeout_error_message_shown =
false;
231 auto start = std::chrono::steady_clock::now();
232 int e = getaddrinfo(this->
hostname.empty() ?
nullptr : this->
hostname.c_str(), port_name.c_str(), &hints, &ai);
233 auto end = std::chrono::steady_clock::now();
234 std::chrono::seconds duration = std::chrono::duration_cast<std::chrono::seconds>(end - start);
235 if (!_resolve_timeout_error_message_shown && duration >= std::chrono::seconds(5)) {
236 Debug(net, 0,
"getaddrinfo for hostname \"{}\", port {}, address family {} and socket type {} took {} seconds",
238 Debug(net, 0,
" this is likely an issue in the DNS name resolver's configuration causing it to time out");
239 _resolve_timeout_error_message_shown =
true;
243 if (reset_hostname) this->
hostname.clear();
247 Debug(net, 0,
"getaddrinfo for hostname \"{}\", port {}, address family {} and socket type {} failed: {}",
250 return INVALID_SOCKET;
253 SOCKET sock = INVALID_SOCKET;
254 for (
struct addrinfo *runp = ai; runp !=
nullptr; runp = runp->ai_next) {
258 if (sockets !=
nullptr) {
260 if (std::any_of(sockets->begin(), sockets->end(), [&
address](
const auto &p) { return p.second == address; }))
continue;
263 if (sock == INVALID_SOCKET)
continue;
265 if (sockets ==
nullptr) {
267 assert(
sizeof(this->
address) >= runp->ai_addrlen);
268 memcpy(&this->
address, runp->ai_addr, runp->ai_addrlen);
276 if (this->
address.ss_family == AF_INET) {
277 sockaddr_in *address_ipv4 = (sockaddr_in *)&this->
address;
278 memset(address_ipv4->sin_zero, 0,
sizeof(address_ipv4->sin_zero));
285 (*sockets)[sock] = addr;
286 sock = INVALID_SOCKET;
302 SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
303 if (sock == INVALID_SOCKET) {
307 return INVALID_SOCKET;
310 if (runp->ai_socktype == SOCK_STREAM && !
SetNoDelay(sock)) {
319 if (runp->ai_family == AF_INET6 &&
320 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (
const char*)&on,
sizeof(on)) == -1) {
324 if (bind(sock, runp->ai_addr, (
int)runp->ai_addrlen) != 0) {
327 return INVALID_SOCKET;
330 if (runp->ai_socktype != SOCK_DGRAM && listen(sock, 1) != 0) {
333 return INVALID_SOCKET;
342 Debug(net, 3,
"Listening on {}", address);
353 assert(sockets !=
nullptr);
359 this->hostname.empty() && this->GetPort() == 0) {
376 case SOCK_STREAM:
return "tcp";
377 case SOCK_DGRAM:
return "udp";
378 default:
return "unsupported";
391 case AF_UNSPEC:
return "either IPv4 or IPv6";
392 case AF_INET:
return "IPv4";
393 case AF_INET6:
return "IPv6";
394 default:
return "unsupported";
405 sockaddr_storage addr = {};
406 socklen_t addr_len =
sizeof(addr);
407 if (getpeername(sock, (sockaddr *)&addr, &addr_len) != 0) {
421 sockaddr_storage addr = {};
422 socklen_t addr_len =
sizeof(addr);
423 if (getsockname(sock, (sockaddr *)&addr, &addr_len) != 0) {
457 uint16_t port = default_port;
static const char * GetAddressFormatString(uint16_t family, bool with_family)
Helper to get the formatting string of an address for a given family.
static SOCKET ListenLoopProc(addrinfo *runp)
Helper function to resolve a listening.
static SOCKET ResolveLoopProc(addrinfo *)
Helper function to resolve without opening a socket.
Wrapper for network addresses.
@ SERVER_ADDRESS_INVITE_CODE
Server-address is based on an invite code.
@ SERVER_ADDRESS_DIRECT
Server-address is based on an hostname:port.
std::map< SOCKET, NetworkAddress > SocketList
Type for a mapping between address and socket.
Wrapper for (un)resolved network addresses; there's no reason to transform a numeric IP to a string a...
static NetworkAddress GetPeerAddress(SOCKET sock)
Get the peer address of a socket as NetworkAddress.
static const char * AddressFamilyAsString(int family)
Convert the address family into a string.
bool resolved
Whether the address has been (tried to be) resolved.
int GetAddressLength()
Get the (valid) length of the address.
static const char * SocketTypeAsString(int socktype)
Convert the socket type into a string.
sockaddr_storage address
The resolved address.
bool IsFamily(int family)
Checks of this address is of the given family.
bool IsResolved() const
Check whether the IP address has been resolved already.
static const std::string GetPeerName(SOCKET sock)
Get the peer name of a socket in string format.
static NetworkAddress GetSockAddress(SOCKET sock)
Get the local address of a socket as NetworkAddress.
bool IsInNetmask(const std::string &netmask)
Checks whether this IP address is contained by the given netmask.
std::string hostname
The hostname.
uint16_t GetPort() const
Get the port.
void Listen(int socktype, SocketList *sockets)
Make the given socket listen.
SOCKET Resolve(int family, int socktype, int flags, SocketList *sockets, LoopProc func)
Resolve this address into a socket.
void SetPort(uint16_t port)
Set the port.
const sockaddr_storage * GetAddress()
Get the address in its internal representation.
const std::string & GetHostname()
Get the hostname; in case it wasn't given the IPv4 dotted representation is given.
int address_length
The length of the resolved address.
std::string GetAddressAsString(bool with_family=true)
Get the address as a string, e.g.
static NetworkError GetLast()
Get the last network error.
Address to a game server.
std::string connection_string
The connection string for this ServerAddress.
static ServerAddress Parse(const std::string &connection_string, uint16_t default_port, CompanyID *company_id=nullptr)
Convert a string containing either "hostname", "hostname:port" or invite code to a ServerAddress,...
Owner
Enum for all companies/owners.
static const uint NETWORK_HOSTNAME_LENGTH
The maximum length of the host name, in bytes including '\0'.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
std::string_view ParseCompanyFromConnectionString(const std::string &connection_string, CompanyID *company_id)
Parse the company part ("#company" postfix) of a connecting string.
std::string_view ParseFullConnectionString(const std::string &connection_string, uint16_t &port, CompanyID *company_id)
Converts a string to ip/port/company Format: IP:port::company.
bool SetReusePort(SOCKET d)
Try to set the socket to reuse ports.
bool SetNoDelay(SOCKET d)
Try to set the socket to not delay sending.
bool SetNonBlocking(SOCKET d)
Try to set the socket into non-blocking mode.
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.