diff options
Diffstat (limited to 'src/network/core')
-rw-r--r-- | src/network/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/network/core/address.cpp | 42 | ||||
-rw-r--r-- | src/network/core/address.h | 2 | ||||
-rw-r--r-- | src/network/core/config.cpp | 14 | ||||
-rw-r--r-- | src/network/core/config.h | 4 | ||||
-rw-r--r-- | src/network/core/os_abstraction.cpp | 17 | ||||
-rw-r--r-- | src/network/core/os_abstraction.h | 1 | ||||
-rw-r--r-- | src/network/core/tcp.h | 3 | ||||
-rw-r--r-- | src/network/core/tcp_connect.cpp | 12 | ||||
-rw-r--r-- | src/network/core/tcp_coordinator.cpp | 6 | ||||
-rw-r--r-- | src/network/core/tcp_coordinator.h | 48 | ||||
-rw-r--r-- | src/network/core/tcp_listen.h | 72 | ||||
-rw-r--r-- | src/network/core/tcp_stun.cpp | 29 | ||||
-rw-r--r-- | src/network/core/tcp_stun.h | 53 |
14 files changed, 257 insertions, 48 deletions
diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt index 82bf7843d..bcecad38c 100644 --- a/src/network/core/CMakeLists.txt +++ b/src/network/core/CMakeLists.txt @@ -28,6 +28,8 @@ add_files( tcp_http.cpp tcp_http.h tcp_listen.h + tcp_stun.cpp + tcp_stun.h udp.cpp udp.h ) diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 4c090c14a..9a2d3dc48 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -313,13 +313,12 @@ static SOCKET ListenLoopProc(addrinfo *runp) Debug(net, 1, "Setting no-delay mode failed: {}", NetworkError::GetLast().AsString()); } - int on = 1; - /* The (const char*) cast is needed for windows!! */ - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { + if (!SetReusePort(sock)) { Debug(net, 0, "Setting reuse-address mode failed: {}", NetworkError::GetLast().AsString()); } #ifndef __OS2__ + int on = 1; if (runp->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) { Debug(net, 3, "Could not disable IPv4 over IPv6: {}", NetworkError::GetLast().AsString()); @@ -401,16 +400,45 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets) } /** + * Get the peer address of a socket as NetworkAddress. + * @param sock The socket to get the peer address of. + * @return The NetworkAddress of the peer address. + */ +/* static */ NetworkAddress NetworkAddress::GetPeerAddress(SOCKET sock) +{ + sockaddr_storage addr = {}; + socklen_t addr_len = sizeof(addr); + if (getpeername(sock, (sockaddr *)&addr, &addr_len) != 0) { + Debug(net, 0, "Failed to get address of the peer: {}", NetworkError::GetLast().AsString()); + return NetworkAddress(); + } + return NetworkAddress(addr, addr_len); +} + +/** + * Get the local address of a socket as NetworkAddress. + * @param sock The socket to get the local address of. + * @return The NetworkAddress of the local address. + */ +/* static */ NetworkAddress NetworkAddress::GetSockAddress(SOCKET sock) +{ + sockaddr_storage addr = {}; + socklen_t addr_len = sizeof(addr); + if (getsockname(sock, (sockaddr *)&addr, &addr_len) != 0) { + Debug(net, 0, "Failed to get address of the socket: {}", NetworkError::GetLast().AsString()); + return NetworkAddress(); + } + return NetworkAddress(addr, addr_len); +} + +/** * Get the peer name of a socket in string format. * @param sock The socket to get the peer name of. * @return The string representation of the peer name. */ /* static */ const std::string NetworkAddress::GetPeerName(SOCKET sock) { - sockaddr_storage addr; - socklen_t addr_len = sizeof(addr); - getpeername(sock, (sockaddr *)&addr, &addr_len); - return NetworkAddress(addr, addr_len).GetAddressAsString(); + return NetworkAddress::GetPeerAddress(sock).GetAddressAsString(); } /** diff --git a/src/network/core/address.h b/src/network/core/address.h index 9e09632d3..f9c2eaef6 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -175,6 +175,8 @@ public: static const char *SocketTypeAsString(int socktype); static const char *AddressFamilyAsString(int family); + static NetworkAddress GetPeerAddress(SOCKET sock); + static NetworkAddress GetSockAddress(SOCKET sock); static const std::string GetPeerName(SOCKET sock); }; diff --git a/src/network/core/config.cpp b/src/network/core/config.cpp index c5fe3adbd..6e7f8a11c 100644 --- a/src/network/core/config.cpp +++ b/src/network/core/config.cpp @@ -39,9 +39,19 @@ const char *NetworkCoordinatorConnectionString() } /** + * Get the connection string for the STUN server from the environment variable OTTD_STUN_CS, + * or when it has not been set a hard coded default DNS hostname of the production server. + * @return The STUN server's connection string. + */ +const char *NetworkStunConnectionString() +{ + return GetEnv("OTTD_STUN_CS", "stun.openttd.org"); +} + +/** * Get the connection string for the content server from the environment variable OTTD_CONTENT_SERVER_CS, * or when it has not been set a hard coded default DNS hostname of the production server. - * @return The game coordinator's connection string. + * @return The content server's connection string. */ const char *NetworkContentServerConnectionString() { @@ -51,7 +61,7 @@ const char *NetworkContentServerConnectionString() /** * Get the connection string for the content mirror from the environment variable OTTD_CONTENT_MIRROR_CS, * or when it has not been set a hard coded default DNS hostname of the production server. - * @return The game coordinator's connection string. + * @return The content mirror's connection string. */ const char *NetworkContentMirrorConnectionString() { diff --git a/src/network/core/config.h b/src/network/core/config.h index 757556993..6039c4252 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -13,6 +13,7 @@ #define NETWORK_CORE_CONFIG_H const char *NetworkCoordinatorConnectionString(); +const char *NetworkStunConnectionString(); const char *NetworkContentServerConnectionString(); const char *NetworkContentMirrorConnectionString(); @@ -20,6 +21,7 @@ const char *NetworkContentMirrorConnectionString(); static const char * const NETWORK_CONTENT_MIRROR_URL = "/bananas"; static const uint16 NETWORK_COORDINATOR_SERVER_PORT = 3976; ///< The default port of the Game Coordinator server (TCP) +static const uint16 NETWORK_STUN_SERVER_PORT = 3975; ///< The default port of the STUN server (TCP) static const uint16 NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP) static const uint16 NETWORK_CONTENT_MIRROR_PORT = 80; ///< The default port of the content mirror (TCP) static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP) @@ -47,7 +49,7 @@ static const uint16 COMPAT_MTU = 1460; ///< Numbe static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use? static const byte NETWORK_GAME_INFO_VERSION = 5; ///< What version of game-info do we use? static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this? -static const byte NETWORK_COORDINATOR_VERSION = 2; ///< What version of game-coordinator-protocol do we use? +static const byte NETWORK_COORDINATOR_VERSION = 3; ///< What version of game-coordinator-protocol do we use? static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0' diff --git a/src/network/core/os_abstraction.cpp b/src/network/core/os_abstraction.cpp index 202806a34..225c95d93 100644 --- a/src/network/core/os_abstraction.cpp +++ b/src/network/core/os_abstraction.cpp @@ -160,6 +160,23 @@ bool SetNoDelay(SOCKET d) } /** + * Try to set the socket to reuse ports. + * @param d The socket to reuse ports on. + * @return True if disabling the delaying succeeded, otherwise false. + */ +bool SetReusePort(SOCKET d) +{ +#ifdef _WIN32 + /* Windows has no SO_REUSEPORT, but for our usecases SO_REUSEADDR does the same job. */ + int reuse_port = 1; + return setsockopt(d, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_port, sizeof(reuse_port)) == 0; +#else + int reuse_port = 1; + return setsockopt(d, SOL_SOCKET, SO_REUSEPORT, &reuse_port, sizeof(reuse_port)) == 0; +#endif +} + +/** * Get the error from a socket, if any. * @param d The socket to get the error from. * @return The errno on the socket. diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index fbde92c05..6bb6101a1 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -196,6 +196,7 @@ static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address bool SetNonBlocking(SOCKET d); bool SetNoDelay(SOCKET d); +bool SetReusePort(SOCKET d); NetworkError GetSocketError(SOCKET d); /* Make sure these structures have the size we expect them to be */ diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index b4b4398de..52d9cfddb 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -99,6 +99,7 @@ private: std::string connection_string; ///< Current address we are connecting to (before resolving). NetworkAddress bind_address; ///< Address we're binding to, if any. + int family = AF_UNSPEC; ///< Family we are using to connect with. void Resolve(); void OnResolved(addrinfo *ai); @@ -114,7 +115,7 @@ private: public: TCPConnecter() {}; - TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address = {}); + TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address = {}, int family = AF_UNSPEC); virtual ~TCPConnecter(); /** diff --git a/src/network/core/tcp_connect.cpp b/src/network/core/tcp_connect.cpp index 6db2500f3..29e9048d9 100644 --- a/src/network/core/tcp_connect.cpp +++ b/src/network/core/tcp_connect.cpp @@ -29,8 +29,9 @@ static std::vector<TCPConnecter *> _tcp_connecters; * @param default_port If not indicated in connection_string, what port to use. * @param bind_address The local bind address to use. Defaults to letting the OS find one. */ -TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address) : - bind_address(bind_address) +TCPConnecter::TCPConnecter(const std::string &connection_string, uint16 default_port, NetworkAddress bind_address, int family) : + bind_address(bind_address), + family(family) { this->connection_string = NormalizeConnectionString(connection_string, default_port); @@ -99,6 +100,10 @@ void TCPConnecter::Connect(addrinfo *address) return; } + if (!SetReusePort(sock)) { + Debug(net, 0, "Setting reuse-port mode failed: {}", NetworkError::GetLast().AsString()); + } + if (this->bind_address.GetPort() > 0) { if (bind(sock, (const sockaddr *)this->bind_address.GetAddress(), this->bind_address.GetAddressLength()) != 0) { Debug(net, 1, "Could not bind socket on {}: {}", this->bind_address.GetAddressAsString(), NetworkError::GetLast().AsString()); @@ -170,6 +175,9 @@ void TCPConnecter::OnResolved(addrinfo *ai) /* Convert the addrinfo into NetworkAddresses. */ for (addrinfo *runp = ai; runp != nullptr; runp = runp->ai_next) { + /* Skip entries if the family is set and it is not matching. */ + if (this->family != AF_UNSPEC && this->family != runp->ai_family) continue; + if (resort) { if (runp->ai_family == AF_INET6) { addresses_ipv6.emplace_back(runp); diff --git a/src/network/core/tcp_coordinator.cpp b/src/network/core/tcp_coordinator.cpp index dfd73147e..abcff9579 100644 --- a/src/network/core/tcp_coordinator.cpp +++ b/src/network/core/tcp_coordinator.cpp @@ -39,6 +39,9 @@ bool NetworkCoordinatorSocketHandler::HandlePacket(Packet *p) case PACKET_COORDINATOR_GC_CONNECT_FAILED: return this->Receive_GC_CONNECT_FAILED(p); case PACKET_COORDINATOR_CLIENT_CONNECTED: return this->Receive_CLIENT_CONNECTED(p); case PACKET_COORDINATOR_GC_DIRECT_CONNECT: return this->Receive_GC_DIRECT_CONNECT(p); + case PACKET_COORDINATOR_GC_STUN_REQUEST: return this->Receive_GC_STUN_REQUEST(p); + case PACKET_COORDINATOR_SERCLI_STUN_RESULT: return this->Receive_SERCLI_STUN_RESULT(p); + case PACKET_COORDINATOR_GC_STUN_CONNECT: return this->Receive_GC_STUN_CONNECT(p); default: Debug(net, 0, "[tcp/coordinator] Received invalid packet type {}", type); @@ -94,3 +97,6 @@ bool NetworkCoordinatorSocketHandler::Receive_SERCLI_CONNECT_FAILED(Packet *p) { bool NetworkCoordinatorSocketHandler::Receive_GC_CONNECT_FAILED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_CONNECT_FAILED); } bool NetworkCoordinatorSocketHandler::Receive_CLIENT_CONNECTED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_CLIENT_CONNECTED); } bool NetworkCoordinatorSocketHandler::Receive_GC_DIRECT_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_DIRECT_CONNECT); } +bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_REQUEST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_REQUEST); } +bool NetworkCoordinatorSocketHandler::Receive_SERCLI_STUN_RESULT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_SERCLI_STUN_RESULT); } +bool NetworkCoordinatorSocketHandler::Receive_GC_STUN_CONNECT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_COORDINATOR_GC_STUN_CONNECT); } diff --git a/src/network/core/tcp_coordinator.h b/src/network/core/tcp_coordinator.h index 2d793b1b6..40502e7e3 100644 --- a/src/network/core/tcp_coordinator.h +++ b/src/network/core/tcp_coordinator.h @@ -38,6 +38,9 @@ enum PacketCoordinatorType { PACKET_COORDINATOR_GC_CONNECT_FAILED, ///< Game Coordinator informs client/server it has given up on the connection attempt. PACKET_COORDINATOR_CLIENT_CONNECTED, ///< Client informs the Game Coordinator the connection with the server is established. PACKET_COORDINATOR_GC_DIRECT_CONNECT, ///< Game Coordinator tells client to directly connect to the hostname:port of the server. + PACKET_COORDINATOR_GC_STUN_REQUEST, ///< Game Coordinator tells client/server to initiate a STUN request. + PACKET_COORDINATOR_SERCLI_STUN_RESULT, ///< Client/server informs the Game Coordinator of the result of the STUN request. + PACKET_COORDINATOR_GC_STUN_CONNECT, ///< Game Coordinator tells client/server to connect() reusing the STUN local address. PACKET_COORDINATOR_END, ///< Must ALWAYS be on the end of this list!! (period) }; @@ -48,6 +51,7 @@ enum ConnectionType { CONNECTION_TYPE_UNKNOWN, ///< The Game Coordinator hasn't informed us yet what type of connection we have. CONNECTION_TYPE_ISOLATED, ///< The Game Coordinator failed to find a way to connect to your server. Nobody will be able to join. CONNECTION_TYPE_DIRECT, ///< The Game Coordinator can directly connect to your server. + CONNECTION_TYPE_STUN, ///< The Game Coordinator can connect to your server via a STUN request. }; /** @@ -215,6 +219,50 @@ protected: */ virtual bool Receive_GC_DIRECT_CONNECT(Packet *p); + /** + * Game Coordinator requests the client/server to do a STUN request to the + * STUN server. Important is to remember the local port these STUN requests + * are sent from, as this will be needed for later conenctions too. + * The client/server should do multiple STUN requests for every available + * interface that connects to the Internet (e.g., once for IPv4 and once + * for IPv6). + * + * string Token to track the current connect request. + * + * @param p The packet that was just received. + * @return True upon success, otherwise false. + */ + virtual bool Receive_GC_STUN_REQUEST(Packet *p); + + /** + * Client/server informs the Game Coordinator the result of a STUN request. + * + * uint8 Game Coordinator protocol version. + * string Token to track the current connect request. + * uint8 Interface number, as given during STUN request. + * bool Whether the STUN connection was successful. + * + * @param p The packet that was just received. + * @return True upon success, otherwise false. + */ + virtual bool Receive_SERCLI_STUN_RESULT(Packet *p); + + /** + * Game Coordinator informs the client/server of its STUN peer (the host:ip + * of the other side). It should start a connect() to this peer ASAP with + * the local address as used with the STUN request. + * + * string Token to track the current connect request. + * uint8 Tracking number to track current connect request. + * uint8 Interface number, as given during STUN request. + * string Host of the peer. + * uint16 Port of the peer. + * + * @param p The packet that was just received. + * @return True upon success, otherwise false. + */ + virtual bool Receive_GC_STUN_CONNECT(Packet *p); + bool HandlePacket(Packet *p); public: /** diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index 03945e230..0c7b11df1 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -30,6 +30,42 @@ class TCPListenHandler { static SocketList sockets; public: + static bool ValidateClient(SOCKET s, NetworkAddress &address) + { + /* Check if the client is banned. */ + for (const auto &entry : _network_ban_list) { + if (address.IsInNetmask(entry)) { + Packet p(Tban_packet); + p.PrepareToSend(); + + Debug(net, 2, "[{}] Banned ip tried to join ({}), refused", Tsocket::GetName(), entry); + + if (p.TransferOut<int>(send, s, 0) < 0) { + Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString()); + } + closesocket(s); + return false; + } + } + + /* Can we handle a new client? */ + if (!Tsocket::AllowConnection()) { + /* No more clients allowed? + * Send to the client that we are full! */ + Packet p(Tfull_packet); + p.PrepareToSend(); + + if (p.TransferOut<int>(send, s, 0) < 0) { + Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString()); + } + closesocket(s); + + return false; + } + + return true; + } + /** * Accepts clients from the sockets. * @param ls Socket to accept clients from. @@ -53,41 +89,7 @@ public: SetNoDelay(s); // XXX error handling? - /* Check if the client is banned */ - bool banned = false; - for (const auto &entry : _network_ban_list) { - banned = address.IsInNetmask(entry); - if (banned) { - Packet p(Tban_packet); - p.PrepareToSend(); - - Debug(net, 2, "[{}] Banned ip tried to join ({}), refused", Tsocket::GetName(), entry); - - if (p.TransferOut<int>(send, s, 0) < 0) { - Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString()); - } - closesocket(s); - break; - } - } - /* If this client is banned, continue with next client */ - if (banned) continue; - - /* Can we handle a new client? */ - if (!Tsocket::AllowConnection()) { - /* no more clients allowed? - * Send to the client that we are full! */ - Packet p(Tfull_packet); - p.PrepareToSend(); - - if (p.TransferOut<int>(send, s, 0) < 0) { - Debug(net, 0, "[{}] send failed: {}", Tsocket::GetName(), NetworkError::GetLast().AsString()); - } - closesocket(s); - - continue; - } - + if (!Tsocket::ValidateClient(s, address)) continue; Tsocket::AcceptConnection(s, address); } } diff --git a/src/network/core/tcp_stun.cpp b/src/network/core/tcp_stun.cpp new file mode 100644 index 000000000..b6aeff683 --- /dev/null +++ b/src/network/core/tcp_stun.cpp @@ -0,0 +1,29 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * @file tcp_stun.cpp Basic functions to receive and send STUN packets. + */ + +#include "../../stdafx.h" +#include "../../debug.h" +#include "tcp_stun.h" + +#include "../../safeguards.h" + +/** + * Helper for logging receiving invalid packets. + * @param type The received packet type. + * @return Always false, as it's an error. + */ +bool NetworkStunSocketHandler::ReceiveInvalidPacket(PacketStunType type) +{ + Debug(net, 0, "[tcp/stun] Received illegal packet type {}", type); + return false; +} + +bool NetworkStunSocketHandler::Receive_SERCLI_STUN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_STUN_SERCLI_STUN); } diff --git a/src/network/core/tcp_stun.h b/src/network/core/tcp_stun.h new file mode 100644 index 000000000..e96a97ef3 --- /dev/null +++ b/src/network/core/tcp_stun.h @@ -0,0 +1,53 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * @file tcp_stun.h Basic functions to receive and send TCP packets to/from the STUN server. + */ + +#ifndef NETWORK_CORE_TCP_STUN_H +#define NETWORK_CORE_TCP_STUN_H + +#include "os_abstraction.h" +#include "tcp.h" +#include "packet.h" + +/** Enum with all types of TCP STUN packets. The order MUST not be changed. **/ +enum PacketStunType { + PACKET_STUN_SERCLI_STUN, ///< Send a STUN request to the STUN server. + PACKET_STUN_END, ///< Must ALWAYS be on the end of this list!! (period) +}; + +/** Base socket handler for all STUN TCP sockets. */ +class NetworkStunSocketHandler : public NetworkTCPSocketHandler { +protected: + bool ReceiveInvalidPacket(PacketStunType type); + + /** + * Send a STUN request to the STUN server letting the Game Coordinator know + * what our actually public IP:port is. + * + * uint8 Game Coordinator protocol version. + * string Token to track the current STUN request. + * uint8 Which interface number this is (for example, IPv4 or IPv6). + * The Game Coordinator relays this number back in later packets. + * + * @param p The packet that was just received. + * @return True upon success, otherwise false. + */ + virtual bool Receive_SERCLI_STUN(Packet *p); + +public: + /** + * Create a new cs socket handler for a given cs. + * @param s the socket we are connected with. + * @param address IP etc. of the client. + */ + NetworkStunSocketHandler(SOCKET s = INVALID_SOCKET) : NetworkTCPSocketHandler(s) {} +}; + +#endif /* NETWORK_CORE_TCP_STUN_H */ |