Index: ps/trunk/source/lobby/IXmppClient.h =================================================================== --- ps/trunk/source/lobby/IXmppClient.h +++ ps/trunk/source/lobby/IXmppClient.h @@ -22,10 +22,6 @@ class ScriptRequest; -namespace StunClient { - struct StunEndpoint; -} - class IXmppClient { public: @@ -64,7 +60,7 @@ virtual bool GuiPollHasPlayerListUpdate() = 0; virtual void SendMUCMessage(const std::string& message) = 0; - virtual void SendStunEndpointToHost(const StunClient::StunEndpoint& stunEndpoint, const std::string& hostJID) = 0; + virtual void SendStunEndpointToHost(const std::string& ip, u16 port, const std::string& hostJID) = 0; }; extern IXmppClient *g_XmppClient; Index: ps/trunk/source/lobby/XmppClient.h =================================================================== --- ps/trunk/source/lobby/XmppClient.h +++ ps/trunk/source/lobby/XmppClient.h @@ -106,7 +106,7 @@ JS::Value GUIGetBoardList(const ScriptRequest& rq); JS::Value GUIGetProfile(const ScriptRequest& rq); - void SendStunEndpointToHost(const StunClient::StunEndpoint& stunEndpoint, const std::string& hostJID); + void SendStunEndpointToHost(const std::string& ip, u16 port, const std::string& hostJID); /** * Convert gloox values to string or time. Index: ps/trunk/source/lobby/XmppClient.cpp =================================================================== --- ps/trunk/source/lobby/XmppClient.cpp +++ ps/trunk/source/lobby/XmppClient.cpp @@ -20,12 +20,7 @@ #include "XmppClient.h" #include "StanzaExtensions.h" -#ifdef WIN32 -# include -#endif - #include "i18n/L10n.h" -#include "lib/external_libraries/enet.h" #include "lib/utf8.h" #include "network/NetServer.h" #include "network/NetClient.h" @@ -883,7 +878,7 @@ LOGWARNING("XmppClient: Received game with no IP in response to Game Register"); return true; } - g_NetServer->SetConnectionData(publicIP, g_NetServer->GetPublicPort(), false); + g_NetServer->SetConnectionData(publicIP, g_NetServer->GetPublicPort()); return true; } @@ -1484,18 +1479,13 @@ #undef CASE } -void XmppClient::SendStunEndpointToHost(const StunClient::StunEndpoint& stunEndpoint, const std::string& hostJIDStr) +void XmppClient::SendStunEndpointToHost(const std::string& ip, u16 port, const std::string& hostJIDStr) { DbgXMPP("SendStunEndpointToHost " << hostJIDStr); - char ipStr[256] = "(error)"; - ENetAddress addr; - addr.host = ntohl(stunEndpoint.ip); - enet_address_get_host_ip(&addr, ipStr, ARRAY_SIZE(ipStr)); - glooxwrapper::JID hostJID(hostJIDStr); glooxwrapper::Jingle::Session session = m_sessionManager->createSession(hostJID); - session.sessionInitiate(ipStr, stunEndpoint.port); + session.sessionInitiate(ip.c_str(), port); } void XmppClient::handleSessionAction(gloox::Jingle::Action action, glooxwrapper::Jingle::Session& session, const glooxwrapper::Jingle::Session::Jingle& jingle) Index: ps/trunk/source/lobby/glooxwrapper/glooxwrapper.h =================================================================== --- ps/trunk/source/lobby/glooxwrapper/glooxwrapper.h +++ ps/trunk/source/lobby/glooxwrapper/glooxwrapper.h @@ -673,7 +673,7 @@ Session(gloox::Jingle::Session* wrapped, bool owned); ~Session(); - bool sessionInitiate(char* ipStr, uint16_t port); + bool sessionInitiate(const char* ipStr, uint16_t port); }; class GLOOXWRAPPER_API SessionHandler Index: ps/trunk/source/lobby/glooxwrapper/glooxwrapper.cpp =================================================================== --- ps/trunk/source/lobby/glooxwrapper/glooxwrapper.cpp +++ ps/trunk/source/lobby/glooxwrapper/glooxwrapper.cpp @@ -841,7 +841,7 @@ delete m_Wrapped; } -bool glooxwrapper::Jingle::Session::sessionInitiate(char* ipStr, u16 port) +bool glooxwrapper::Jingle::Session::sessionInitiate(const char* ipStr, u16 port) { gloox::Jingle::ICEUDP::CandidateList candidateList; Index: ps/trunk/source/network/NetClient.cpp =================================================================== --- ps/trunk/source/network/NetClient.cpp +++ ps/trunk/source/network/NetClient.cpp @@ -240,15 +240,8 @@ ENetHost* enetClient = nullptr; if (g_XmppClient && m_UseSTUN) { - // Find an unused port - for (int i = 0; i < 5 && !enetClient; ++i) - { - // Ports below 1024 are privileged on unix - u16 port = 1024 + rand() % (UINT16_MAX - 1024); - ENetAddress hostAddr{ ENET_HOST_ANY, port }; - enetClient = enet_host_create(&hostAddr, 1, 1, 0, 0); - ++hostAddr.port; - } + ENetAddress hostAddr{ ENET_HOST_ANY, ENET_PORT_ANY }; + enetClient = enet_host_create(&hostAddr, 1, 1, 0, 0); if (!enetClient) { @@ -259,9 +252,9 @@ return false; } - StunClient::StunEndpoint stunEndpoint; CStr ip; - if (!StunClient::FindStunEndpointJoin(*enetClient, stunEndpoint, ip)) + u16 port; + if (!StunClient::FindPublicIP(*enetClient, ip, port)) { PushGuiMessage( "type", "netstatus", @@ -280,7 +273,7 @@ return true; } - g_XmppClient->SendStunEndpointToHost(stunEndpoint, hostJID); + g_XmppClient->SendStunEndpointToHost(ip, port, hostJID); SDL_Delay(1000); Index: ps/trunk/source/network/NetServer.h =================================================================== --- ps/trunk/source/network/NetServer.h +++ ps/trunk/source/network/NetServer.h @@ -149,7 +149,8 @@ void SendHolePunchingMessage(const CStr& ip, u16 port); - void SetConnectionData(const CStr& ip, u16 port, bool useSTUN); + void SetConnectionData(const CStr& ip, u16 port); + bool SetConnectionDataViaSTUN(); bool GetUseSTUN() const; Index: ps/trunk/source/network/NetServer.cpp =================================================================== --- ps/trunk/source/network/NetServer.cpp +++ ps/trunk/source/network/NetServer.cpp @@ -1658,11 +1658,20 @@ return m_Worker->m_Host->address.port; } -void CNetServer::SetConnectionData(const CStr& ip, const u16 port, bool useSTUN) +void CNetServer::SetConnectionData(const CStr& ip, const u16 port) { m_PublicIp = ip; m_PublicPort = port; - m_UseSTUN = useSTUN; + m_UseSTUN = false; +} + +bool CNetServer::SetConnectionDataViaSTUN() +{ + m_UseSTUN = true; + std::lock_guard lock(m_Worker->m_WorkerMutex); + if (!m_Worker->m_Host) + return false; + return StunClient::FindPublicIP(*m_Worker->m_Host, m_PublicIp, m_PublicPort); } bool CNetServer::CheckPasswordAndIncrement(const CStr& password, const std::string& username) Index: ps/trunk/source/network/StunClient.h =================================================================== --- ps/trunk/source/network/StunClient.h +++ ps/trunk/source/network/StunClient.h @@ -27,18 +27,20 @@ namespace StunClient { +/** + * Return the publicly accessible IP of the given ENet host/socket. + * This is done by contacting STUN server. + * The return IP & port should only be considered valid for the give host/socket. + */ +bool FindPublicIP(ENetHost& enetClient, CStr8& ip, u16& port); -struct StunEndpoint { - u32 ip; - u16 port; -}; - -void SendStunRequest(ENetHost& transactionHost, u32 targetIp, u16 targetPort); - -bool FindStunEndpointHost(CStr8& ip, u16& port); - -bool FindStunEndpointJoin(ENetHost& transactionHost, StunClient::StunEndpoint& stunEndpoint, CStr8& ip); - +/** + * Send a message to the target server with the given ENet host/socket. + * This will open a port on the local gateway (if any) to receive trafic, + * allowing the recipient to answer (thus 'punching a hole' in the NAT). + * NB: this assumes consistent NAT, i.e. the outgoing port is always the same for the given client, + * thus allowing the IP discovered via STUN to be sent to the target server. + */ void SendHolePunchingMessages(ENetHost& enetClient, const std::string& serverAddress, u16 serverPort); /** Index: ps/trunk/source/network/StunClient.cpp =================================================================== --- ps/trunk/source/network/StunClient.cpp +++ ps/trunk/source/network/StunClient.cpp @@ -20,43 +20,25 @@ #include "StunClient.h" -#include "lib/sysdep/os.h" - -#include -#include - -#include -#include - -#include -#if OS_WIN -# include -# include -#else -# include -# include -#endif - -#include - -#include "lib/external_libraries/enet.h" - -#if OS_WIN -#include "lib/sysdep/os/win/wposix/wtime.h" -#endif - +#include "lib/byte_order.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/CStr.h" -unsigned int m_StunServerIP; -int m_StunServerPort; +#include "lib/external_libraries/enet.h" + +#include +#include +#include + +namespace StunClient +{ /** * These constants are defined in Section 6 of RFC 5389. */ const u32 m_MagicCookie = 0x2112A442; -const u32 m_MethodTypeBinding = 0x0001; +const u16 m_MethodTypeBinding = 0x01; const u32 m_BindingSuccessResponse = 0x0101; /** @@ -87,43 +69,74 @@ */ u8 m_TransactionID[12]; +ENetAddress m_StunServer; + /** - * Discovered STUN endpoint + * Public IP + port discovered via the STUN transaction. */ -u32 m_IP; -u16 m_Port; +ENetAddress m_PublicAddress; -void AddUInt16(std::vector& buffer, const u16 value) -{ - buffer.push_back((value >> 8) & 0xff); - buffer.push_back(value & 0xff); -} - -void AddUInt32(std::vector& buffer, const u32 value) +/** + * Push POD data to a network-byte-order buffer. + * TODO: this should be optimised & moved to byte_order.h + */ +template +void AddToBuffer(std::vector& buffer, const T value) { - buffer.push_back((value >> 24) & 0xff); - buffer.push_back((value >> 16) & 0xff); - buffer.push_back((value >> 8) & 0xff); - buffer.push_back( value & 0xff); + static_assert(std::is_pod_v, "T must be POD"); + buffer.reserve(buffer.size() + n); + // std::byte* can alias anything so this is legal. + const std::byte* ptr = reinterpret_cast(&value); + for (size_t a = 0; a < n; ++a) +#if BYTE_ORDER == LITTLE_ENDIAN + buffer.push_back(static_cast(*(ptr + n - 1 - a))); +#else + buffer.push_back(static_cast(*(ptr + a))); +#endif } -template +/** + * Read POD data from a network-byte-order buffer. + * TODO: this should be optimised & moved to byte_order.h + */ +template bool GetFromBuffer(const std::vector& buffer, u32& offset, T& result) { + static_assert(std::is_pod_v, "T must be POD"); if (offset + n > buffer.size()) return false; - int a = n; + // std::byte* can alias anything so this is legal. + std::byte* ptr = reinterpret_cast(&result); + for (size_t a = 0; a < n; ++a) +#if BYTE_ORDER == LITTLE_ENDIAN + *ptr++ = static_cast(buffer[offset + n - 1 - a]); +#else + *ptr++ = static_cast(buffer[offset + a]); +#endif + offset += n; - while (a--) - { - // Prevent shift count overflow if the type is u8 - if (n > 1) - result <<= 8; + return true; +} + +void SendStunRequest(ENetHost& transactionHost, ENetAddress addr) +{ + std::vector buffer; + AddToBuffer(buffer, m_MethodTypeBinding); + AddToBuffer(buffer, 0); // length + AddToBuffer(buffer, m_MagicCookie); - result += buffer[offset - 1 - a]; + for (std::size_t i = 0; i < sizeof(m_TransactionID); ++i) + { + u8 random_byte = rand() % 256; + buffer.push_back(random_byte); + m_TransactionID[i] = random_byte; } - return true; + + ENetBuffer enetBuffer; + enetBuffer.data = buffer.data(); + enetBuffer.dataLength = buffer.size(); + enet_socket_send(transactionHost.socket, &addr, &enetBuffer, 1); } /** @@ -134,73 +147,24 @@ bool CreateStunRequest(ENetHost& transactionHost) { CStr server_name; + int port; CFG_GET_VAL("lobby.stun.server", server_name); - CFG_GET_VAL("lobby.stun.port", m_StunServerPort); - - debug_printf("GetPublicAddress: Using STUN server %s:%d\n", server_name.c_str(), m_StunServerPort); - - addrinfo hints; - addrinfo* res; + CFG_GET_VAL("lobby.stun.port", port); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version - hints.ai_socktype = SOCK_STREAM; + LOGMESSAGE("StunClient: Using STUN server %s:%d\n", server_name.c_str(), port); - // Resolve the stun server name so we can send it a STUN request - int status = getaddrinfo(server_name.c_str(), nullptr, &hints, &res); - if (status != 0) - { -#ifdef UNICODE - LOGERROR("GetPublicAddress: Error in getaddrinfo: %s", utf8_from_wstring(gai_strerror(status))); -#else - LOGERROR("GetPublicAddress: Error in getaddrinfo: %s", gai_strerror(status)); -#endif + ENetAddress addr; + addr.port = port; + if (enet_address_set_host(&addr, server_name.c_str()) == -1) return false; - } - ENSURE(res); + m_StunServer = addr; - // Documentation says it points to "one or more addrinfo structures" - sockaddr_in* current_interface = reinterpret_cast(res->ai_addr); - m_StunServerIP = ntohl(current_interface->sin_addr.s_addr); + StunClient::SendStunRequest(transactionHost, addr); - StunClient::SendStunRequest(transactionHost, m_StunServerIP, m_StunServerPort); - - freeaddrinfo(res); return true; } -void StunClient::SendStunRequest(ENetHost& transactionHost, u32 targetIp, u16 targetPort) -{ - std::vector buffer; - AddUInt16(buffer, m_MethodTypeBinding); - AddUInt16(buffer, 0); // length - AddUInt32(buffer, m_MagicCookie); - - for (std::size_t i = 0; i < sizeof(m_TransactionID); ++i) - { - u8 random_byte = rand() % 256; - buffer.push_back(random_byte); - m_TransactionID[i] = random_byte; - } - - sockaddr_in to; - int to_len = sizeof(to); - memset(&to, 0, to_len); - - to.sin_family = AF_INET; - to.sin_port = htons(targetPort); - to.sin_addr.s_addr = htonl(targetIp); - - sendto( - transactionHost.socket, - reinterpret_cast(buffer.data()), - static_cast(buffer.size()), - 0, - reinterpret_cast(&to), - to_len); -} - /** * Gets the response from the STUN server and checks it for its validity. */ @@ -212,40 +176,37 @@ memset(input_buffer, 0, LEN); - sockaddr_in addr; - socklen_t from_len = sizeof(addr); + ENetBuffer enetBuffer; + enetBuffer.data = input_buffer; + enetBuffer.dataLength = LEN; - int len = recvfrom(transactionHost.socket, input_buffer, LEN, 0, reinterpret_cast(&addr), &from_len); + ENetAddress sender = m_StunServer; + int len = enet_socket_receive(transactionHost.socket, &sender, &enetBuffer, 1); int delay = 200; CFG_GET_VAL("lobby.stun.delay", delay); // Wait to receive the message because enet sockets are non-blocking const int max_tries = 5; - for (int count = 0; len < 0 && (count < max_tries || max_tries == -1); ++count) + for (int count = 0; len <= 0 && (count < max_tries || max_tries == -1); ++count) { - usleep(delay * 1000); - len = recvfrom(transactionHost.socket, input_buffer, LEN, 0, reinterpret_cast(&addr), &from_len); + std::this_thread::sleep_for(std::chrono::milliseconds(delay)); + len = enet_socket_receive(transactionHost.socket, &sender, &enetBuffer, 1); } - if (len < 0) + if (len <= 0) { - LOGERROR("GetPublicAddress: recvfrom error (%d): %s", errno, strerror(errno)); + LOGERROR("ReceiveStunResponse: recvfrom error (%d): %s", errno, strerror(errno)); return false; } - u32 sender_ip = ntohl(static_cast(addr.sin_addr.s_addr)); - u16 sender_port = ntohs(addr.sin_port); - - if (sender_ip != m_StunServerIP) - LOGERROR("GetPublicAddress: Received stun response from different address: %d:%d (%d.%d.%d.%d:%d) %s", - addr.sin_addr.s_addr, - addr.sin_port, - (sender_ip >> 24) & 0xff, - (sender_ip >> 16) & 0xff, - (sender_ip >> 8) & 0xff, - (sender_ip >> 0) & 0xff, - sender_port, + if (memcmp(&sender, &m_StunServer, sizeof(m_StunServer)) != 0) + LOGERROR("ReceiveStunResponse: Received stun response from different address: %d.%d.%d.%d:%d %s", + (sender.host >> 24) & 0xff, + (sender.host >> 16) & 0xff, + (sender.host >> 8) & 0xff, + (sender.host >> 0) & 0xff, + sender.port, input_buffer); // Convert to network string. @@ -260,7 +221,7 @@ u32 offset = 0; u16 responseType = 0; - if (!GetFromBuffer(buffer, offset, responseType) || responseType != m_BindingSuccessResponse) + if (!GetFromBuffer(buffer, offset, responseType) || responseType != m_BindingSuccessResponse) { LOGERROR("STUN response isn't a binding success response"); return false; @@ -270,7 +231,7 @@ offset += 2; u32 cookie = 0; - if (!GetFromBuffer(buffer, offset, cookie) || cookie != m_MagicCookie) + if (!GetFromBuffer(buffer, offset, cookie) || cookie != m_MagicCookie) { LOGERROR("STUN response doesn't contain the magic cookie"); return false; @@ -279,7 +240,7 @@ for (std::size_t i = 0; i < sizeof(m_TransactionID); ++i) { u8 transactionChar = 0; - if (!GetFromBuffer(buffer, offset, transactionChar) || transactionChar != m_TransactionID[i]) + if (!GetFromBuffer(buffer, offset, transactionChar) || transactionChar != m_TransactionID[i]) { LOGERROR("STUN response doesn't contain the transaction ID"); return false; @@ -290,8 +251,8 @@ { u16 type = 0; u16 size = 0; - if (!GetFromBuffer(buffer, offset, type) || - !GetFromBuffer(buffer, offset, size)) + if (!GetFromBuffer(buffer, offset, type) || + !GetFromBuffer(buffer, offset, size)) { LOGERROR("STUN response contains invalid attribute"); return false; @@ -315,7 +276,7 @@ ++offset; u8 ipFamily = 0; - if (!GetFromBuffer(buffer, offset, ipFamily) || ipFamily != m_IPAddressFamilyIPv4) + if (!GetFromBuffer(buffer, offset, ipFamily) || ipFamily != m_IPAddressFamilyIPv4) { LOGERROR("Unsupported address family, IPv4 is expected"); return false; @@ -323,8 +284,8 @@ u16 port = 0; u32 ip = 0; - if (!GetFromBuffer(buffer, offset, port) || - !GetFromBuffer(buffer, offset, ip)) + if (!GetFromBuffer(buffer, offset, port) || + !GetFromBuffer(buffer, offset, ip)) { LOGERROR("Mapped address doesn't contain IP and port"); return false; @@ -337,8 +298,10 @@ ip ^= m_MagicCookie; } - m_Port = port; - m_IP = ip; + // ENetAddress takes a host byte-order port and network byte-order IP. + // Network byte order is big endian, so convert appropriately. + m_PublicAddress.host = to_be32(ip); + m_PublicAddress.port = port; break; } @@ -371,48 +334,24 @@ ParseStunResponse(buffer); } -bool StunClient::FindStunEndpointHost(CStr& ip, u16& port) -{ - ENetAddress hostAddr{ENET_HOST_ANY, static_cast(port)}; - ENetHost* transactionHost = enet_host_create(&hostAddr, 1, 1, 0, 0); - if (!transactionHost) - return false; - - bool success = STUNRequestAndResponse(*transactionHost); - enet_host_destroy(transactionHost); - if (!success) - return false; - - // Convert m_IP to string - char ipStr[256] = "(error)"; - ENetAddress addr; - addr.host = ntohl(m_IP); - int result = enet_address_get_host_ip(&addr, ipStr, ARRAY_SIZE(ipStr)); - - ip = ipStr; - port = m_Port; - return result == 0; -} - -bool StunClient::FindStunEndpointJoin(ENetHost& transactionHost, StunClient::StunEndpoint& stunEndpoint, CStr& ip) +bool FindPublicIP(ENetHost& transactionHost, CStr& ip, u16& port) { if (!STUNRequestAndResponse(transactionHost)) return false; // Convert m_IP to string char ipStr[256] = "(error)"; - ENetAddress addr; - addr.host = ntohl(m_IP); - enet_address_get_host_ip(&addr, ipStr, ARRAY_SIZE(ipStr)); + enet_address_get_host_ip(&m_PublicAddress, ipStr, ARRAY_SIZE(ipStr)); ip = ipStr; - stunEndpoint.ip = m_IP; - stunEndpoint.port = m_Port; + port = m_PublicAddress.port; + + LOGMESSAGE("StunClient: external IP address is %s:%i", ip.c_str(), port); return true; } -void StunClient::SendHolePunchingMessages(ENetHost& enetClient, const std::string& serverAddress, u16 serverPort) +void SendHolePunchingMessages(ENetHost& enetClient, const std::string& serverAddress, u16 serverPort) { // Convert ip string to int64 ENetAddress addr; @@ -425,12 +364,12 @@ // Send an UDP message from enet host to ip:port for (int i = 0; i < 3; ++i) { - StunClient::SendStunRequest(enetClient, htonl(addr.host), serverPort); - usleep(delay * 1000); + SendStunRequest(enetClient, addr); + std::this_thread::sleep_for(std::chrono::milliseconds(delay)); } } -bool StunClient::FindLocalIP(CStr& ip) +bool FindLocalIP(CStr& ip) { // Open an UDP socket. ENetSocket socket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); @@ -450,12 +389,15 @@ if (enet_socket_get_address(socket, &addr) == -1) return false; + enet_socket_destroy(socket); + // Convert to a human readable string. - char buf[INET_ADDRSTRLEN]; - if (enet_address_get_host_ip(&addr, buf, INET_ADDRSTRLEN) == -1) + char buf[50]; + if (enet_address_get_host_ip(&addr, buf, ARRAY_SIZE(buf)) == -1) return false; ip = buf; return true; } +} Index: ps/trunk/source/network/scripting/JSInterface_Network.cpp =================================================================== --- ps/trunk/source/network/scripting/JSInterface_Network.cpp +++ ps/trunk/source/network/scripting/JSInterface_Network.cpp @@ -98,37 +98,31 @@ // Always use lobby authentication for lobby matches to prevent impersonation and smurfing, in particular through mods that implemented an UI for arbitrary or other players nicknames. bool hasLobby = !!g_XmppClient; g_NetServer = new CNetServer(hasLobby); - // In lobby, we send our public ip and port on request to the players, who want to connect. - // In either case we need to know our public IP. If using STUN, we'll use that, + + if (!g_NetServer->SetupConnection(serverPort)) + { + ScriptException::Raise(rq, "Failed to start server"); + SAFE_DELETE(g_NetServer); + return; + } + + // In lobby, we send our public ip and port on request to the players who want to connect. + // Thus we need to know our public IP. Use STUN if that's available, // otherwise, the lobby's reponse to the game registration stanza will tell us our public IP. if (hasLobby) { - CStr ip; if (!useSTUN) // Don't store IP - the lobby bot will send it later. // (if a client tries to connect before it's setup, they'll be disconnected) - g_NetServer->SetConnectionData("", serverPort, false); - else + g_NetServer->SetConnectionData("", serverPort); + else if (!g_NetServer->SetConnectionDataViaSTUN()) { - u16 port = serverPort; - // This is using port variable to store return value, do not pass serverPort itself. - if (!StunClient::FindStunEndpointHost(ip, port)) - { - ScriptException::Raise(rq, "Failed to host via STUN."); - SAFE_DELETE(g_NetServer); - return; - } - g_NetServer->SetConnectionData(ip, port, true); + ScriptException::Raise(rq, "Failed to host via STUN."); + SAFE_DELETE(g_NetServer); + return; } } - if (!g_NetServer->SetupConnection(serverPort)) - { - ScriptException::Raise(rq, "Failed to start server"); - SAFE_DELETE(g_NetServer); - return; - } - // Generate a secret to identify the host client. std::string secret = ps_generate_guid(); Index: ps/trunk/source/network/tests/test_StunClient.h =================================================================== --- ps/trunk/source/network/tests/test_StunClient.h +++ ps/trunk/source/network/tests/test_StunClient.h @@ -20,6 +20,7 @@ #include "network/StunClient.h" #include "lib/external_libraries/enet.h" +#include "ps/ConfigDB.h" #include "ps/CStr.h" class TestStunClient : public CxxTest::TestSuite @@ -60,4 +61,19 @@ if (dots != 3) TS_FAIL("StunClient::FindLocalIP did not return a valid IPV4 address: wrong separators"); } + + void test_stun_DISABLED() + { + // Disabled test -> should return your external IP by connecting to our STUN server. + CConfigDB::Initialise(); + CStr ip; + u16 port; + g_ConfigDB.SetValueString(CFG_COMMAND, "lobby.stun.server", "lobby.wildfiregames.com"); + g_ConfigDB.SetValueString(CFG_COMMAND, "lobby.stun.port", "3478"); + ENetAddress addr { ENET_HOST_ANY, ENET_PORT_ANY }; + ENetHost* host = enet_host_create(&addr, 1, 1, 0, 0); + StunClient::FindPublicIP(*host, ip, port); + LOGWARNING("%s %i", ip.c_str(), port); + CConfigDB::Shutdown(); + } };