diff --git a/CMakeLists.txt b/CMakeLists.txt index e2d5343e7..a6311be2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ option(SERVER_ONLY "Create a server only (i.e. no graphics or sound)" OFF) option(CHECK_ASSETS "Check if assets are installed in ../stk-assets" ON) option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angelscript. If you enable this option, make sure to use a compatible version." OFF) option(USE_SYSTEM_ENET "Use system ENet instead of the built-in version, when available." ON) -option(USE_IPV6 "Allow create or connect to game server with ipv6 address, system enet will not be used." OFF) +option(USE_IPV6 "Allow create or connect to game server with ipv6 address, system enet will not be used." ON) option(USE_SYSTEM_GLEW "Use system GLEW instead of the built-in version, when available." ON) option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, when available." OFF) option(USE_SQLITE3 "Use sqlite to manage server stats and ban list." ON) diff --git a/lib/enet/unix.c b/lib/enet/unix.c index 406a3498b..a66aa1242 100644 --- a/lib/enet/unix.c +++ b/lib/enet/unix.c @@ -59,7 +59,7 @@ typedef int socklen_t; static enet_uint32 timeBase = 0; #ifdef ENABLE_IPV6 -extern void unixInitialize(void); +extern void stkInitialize(void); extern int isIPV6(void); extern void getIPV6FromMappedAddress(const ENetAddress* ea, struct sockaddr_in6* in6); extern void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea); @@ -69,7 +69,7 @@ int enet_initialize (void) { #ifdef ENABLE_IPV6 - unixInitialize(); + stkInitialize(); #endif return 0; } @@ -268,7 +268,7 @@ enet_socket_create (ENetSocketType type) #endif int socket_fd = socket (af_family, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); #ifdef ENABLE_IPV6 - if (isIPV6()) + if (isIPV6() && socket_fd != -1) { int no = 0; // Allow ipv6 socket listen to ipv4 connection (as long as the host has ipv4 address) diff --git a/lib/enet/win32.c b/lib/enet/win32.c index 04c724665..c639644bd 100644 --- a/lib/enet/win32.c +++ b/lib/enet/win32.c @@ -8,6 +8,14 @@ #define ENET_BUILDING_LIB 1 #include "enet/enet.h" +#ifdef ENABLE_IPV6 +#include +extern void stkInitialize(void); +extern int isIPV6(void); +extern void getIPV6FromMappedAddress(const ENetAddress* ea, struct sockaddr_in6* in6); +extern void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea); +#endif + static enet_uint32 timeBase = 0; int @@ -29,6 +37,10 @@ enet_initialize (void) timeBeginPeriod (1); +#ifdef ENABLE_IPV6 + stkInitialize(); +#endif + return 0; } @@ -120,26 +132,42 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng int enet_socket_bind (ENetSocket socket, const ENetAddress * address) { - struct sockaddr_in sin; - - memset (& sin, 0, sizeof (struct sockaddr_in)); - - sin.sin_family = AF_INET; - - if (address != NULL) +#ifdef ENABLE_IPV6 + // In STK we only bind port and listen to any address + if (isIPV6()) { - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; + struct sockaddr_in6 sin; + memset (&sin, 0, sizeof (struct sockaddr_in6)); + sin.sin6_family = AF_INET6; + sin.sin6_addr = in6addr_any; + sin.sin6_port = ENET_HOST_TO_NET_16 (address -> port); + return bind (socket, (struct sockaddr *) & sin, + sizeof (struct sockaddr_in6)) == SOCKET_ERROR ? -1 : 0; } else +#endif { - sin.sin_port = 0; - sin.sin_addr.s_addr = INADDR_ANY; - } + struct sockaddr_in sin; - return bind (socket, - (struct sockaddr *) & sin, - sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; + } } int @@ -166,7 +194,26 @@ enet_socket_listen (ENetSocket socket, int backlog) ENetSocket enet_socket_create (ENetSocketType type) { - return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +#ifdef ENABLE_IPV6 + int af_family = isIPV6() == 1 ? PF_INET6 : PF_INET; +#else + int af_family = PF_INET; +#endif + SOCKET socket_fd = socket (af_family, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +#ifdef ENABLE_IPV6 + if (isIPV6() && socket_fd != INVALID_SOCKET) + { + int no = 0; + // Allow ipv6 socket listen to ipv4 connection (as long as the host has ipv4 address) + int ret = setsockopt(socket_fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&no, sizeof(no)); + if (ret != 0) + { + closesocket(socket_fd); + return INVALID_SOCKET; + } + } +#endif + return socket_fd; } int @@ -294,9 +341,36 @@ enet_socket_send (ENetSocket socket, const ENetBuffer * buffers, size_t bufferCount) { + struct sockaddr* sin_send = NULL; + INT sin_size = 0; struct sockaddr_in sin; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 sin6; +#endif DWORD sentLength; + if (address != NULL) + { +#ifdef ENABLE_IPV6 + if (isIPV6()) + { + getIPV6FromMappedAddress(address, &sin6); + sin_send = (struct sockaddr*)&sin6; + sin_size = sizeof(struct sockaddr_in6); + } + else +#endif + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + sin_send = (struct sockaddr*)&sin; + sin_size = sizeof(struct sockaddr_in); + } + } + if (address != NULL) { memset (& sin, 0, sizeof (struct sockaddr_in)); @@ -311,8 +385,8 @@ enet_socket_send (ENetSocket socket, (DWORD) bufferCount, & sentLength, 0, - address != NULL ? (struct sockaddr *) & sin : NULL, - address != NULL ? sizeof (struct sockaddr_in) : 0, + sin_send, + sin_size, NULL, NULL) == SOCKET_ERROR) { @@ -331,17 +405,37 @@ enet_socket_receive (ENetSocket socket, ENetBuffer * buffers, size_t bufferCount) { - INT sinLength = sizeof (struct sockaddr_in); + struct sockaddr* sin_recv = NULL; + INT sinLength = 0; DWORD flags = 0, recvLength; struct sockaddr_in sin; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 sin6; +#endif + +#ifdef ENABLE_IPV6 + if (address != NULL) + { + if (isIPV6()) + { + sin_recv = (struct sockaddr*)&sin6; + sinLength = sizeof(struct sockaddr_in6); + } + else + { + sin_recv = (struct sockaddr*)&sin; + sinLength = sizeof(struct sockaddr_in); + } + } +#endif if (WSARecvFrom (socket, (LPWSABUF) buffers, (DWORD) bufferCount, & recvLength, & flags, - address != NULL ? (struct sockaddr *) & sin : NULL, + sin_recv, address != NULL ? & sinLength : NULL, NULL, NULL) == SOCKET_ERROR) @@ -361,8 +455,17 @@ enet_socket_receive (ENetSocket socket, if (address != NULL) { - address -> host = (enet_uint32) sin.sin_addr.s_addr; - address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); +#ifdef ENABLE_IPV6 + if (isIPV6()) + { + getMappedFromIPV6(&sin6, address); + } + else +#endif + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } } return (int) recvLength; diff --git a/src/network/protocols/connect_to_server.cpp b/src/network/protocols/connect_to_server.cpp index f7781f6d7..a72e4b159 100644 --- a/src/network/protocols/connect_to_server.cpp +++ b/src/network/protocols/connect_to_server.cpp @@ -29,9 +29,9 @@ #include "network/protocol_manager.hpp" #include "network/servers_manager.hpp" #include "network/server.hpp" +#include "network/stk_ipv6.hpp" #include "network/stk_host.hpp" #include "network/stk_peer.hpp" -#include "network/unix_ipv6.hpp" #include "online/xml_request.hpp" #include "states_screens/online/networking_lobby.hpp" #include "utils/time.hpp" diff --git a/src/network/stk_host.cpp b/src/network/stk_host.cpp index f909cb3e3..4bc6a93d6 100644 --- a/src/network/stk_host.cpp +++ b/src/network/stk_host.cpp @@ -23,7 +23,6 @@ #include "io/file_manager.hpp" #include "network/event.hpp" #include "network/game_setup.hpp" -#include "network/unix_ipv6.hpp" #include "network/network_config.hpp" #include "network/network_console.hpp" #include "network/network_player_profile.hpp" @@ -33,6 +32,7 @@ #include "network/protocols/server_lobby.hpp" #include "network/protocol_manager.hpp" #include "network/server_config.hpp" +#include "network/stk_ipv6.hpp" #include "network/stk_peer.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" @@ -726,7 +726,7 @@ void STKHost::setPublicAddress() Log::debug("STKHost", "Using STUN server %s", server_name.c_str()); uint64_t ping = StkTime::getMonoTimeMs(); std::string ipv4_string = getIPFromStun( - m_network->getENetHost()->socket, server_name, true/*ipv4*/); + (int)m_network->getENetHost()->socket, server_name, true/*ipv4*/); TransportAddress addr(ipv4_string); if (!addr.isUnset()) { @@ -737,7 +737,7 @@ void STKHost::setPublicAddress() if (isIPV6()) { m_public_ipv6_address = getIPFromStun( - m_network->getENetHost()->socket, server_name, + (int)m_network->getENetHost()->socket, server_name, false/*ipv4*/); if (m_public_ipv6_address.empty()) { @@ -755,16 +755,32 @@ void STKHost::setPublicAddress() //----------------------------------------------------------------------------- void STKHost::setPrivatePort() { - struct sockaddr_in sin; - socklen_t len = sizeof(sin); - ENetHost *host = m_network->getENetHost(); - if (getsockname(host->socket, (struct sockaddr *)&sin, &len) == -1) + if (isIPV6()) { - Log::error("STKHost", "Error while using getsockname()."); - m_private_port = 0; + struct sockaddr_in6 sin6; + socklen_t len = sizeof(sin6); + ENetHost *host = m_network->getENetHost(); + if (getsockname(host->socket, (struct sockaddr *)&sin6, &len) == -1) + { + Log::error("STKHost", "Error while using getsockname()."); + m_private_port = 0; + } + else + m_private_port = ntohs(sin6.sin6_port); } else - m_private_port = ntohs(sin.sin_port); + { + struct sockaddr_in sin; + socklen_t len = sizeof(sin); + ENetHost *host = m_network->getENetHost(); + if (getsockname(host->socket, (struct sockaddr *)&sin, &len) == -1) + { + Log::error("STKHost", "Error while using getsockname()."); + m_private_port = 0; + } + else + m_private_port = ntohs(sin.sin_port); + } } // setPrivatePort //----------------------------------------------------------------------------- diff --git a/src/network/unix_ipv6.cpp b/src/network/stk_ipv6.cpp similarity index 91% rename from src/network/unix_ipv6.cpp rename to src/network/stk_ipv6.cpp index a0d6f9613..48dbdab95 100644 --- a/src/network/unix_ipv6.cpp +++ b/src/network/stk_ipv6.cpp @@ -51,12 +51,8 @@ std::string getIPV6ReadableFromIn6(const struct sockaddr_in6* in) { std::string result; char ipv6[INET6_ADDRSTRLEN] = {}; -#ifdef WIN32 - struct sockaddr_in6 copied = *in; - inet_ntop(AF_INET6, &copied, ipv6, INET6_ADDRSTRLEN); -#else - inet_ntop(AF_INET6, &(in->sin6_addr), ipv6, INET6_ADDRSTRLEN); -#endif + struct in6_addr ipv6_addr = in->sin6_addr; + inet_ntop(AF_INET6, &ipv6_addr, ipv6, INET6_ADDRSTRLEN); result = ipv6; return result; } // getIPV6ReadableFromIn6 @@ -134,7 +130,7 @@ extern "C" int getaddrinfo_compat(const char* hostname, } #ifndef ENABLE_IPV6 -#include "network/unix_ipv6.hpp" +#include "network/stk_ipv6.hpp" // ---------------------------------------------------------------------------- int isIPV6() { @@ -164,7 +160,7 @@ void addMappedAddress(const ENetAddress* ea, const struct sockaddr_in6* in6) #else -#include "network/unix_ipv6.hpp" +#include "network/stk_ipv6.hpp" #include "network/transport_address.hpp" #include "utils/string_utils.hpp" #include "utils/log.hpp" @@ -203,13 +199,13 @@ void setIPV6(int val) } // setIPV6 // ---------------------------------------------------------------------------- -void unixInitialize() +void stkInitialize() { // Clear previous setting, in case user changed wifi or mobile data g_mapped_ipv6_used = 0; g_ipv6 = 0; g_mapped_ips.clear(); -} // unixInitialize +} // stkInitialize // ---------------------------------------------------------------------------- std::string getIPV6ReadableFromMappedAddress(const ENetAddress* ea) @@ -276,13 +272,21 @@ void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea) return; } - uint16_t w0 = in6->sin6_addr.s6_addr16[0]; - uint16_t w1 = in6->sin6_addr.s6_addr16[1]; - uint16_t w2 = in6->sin6_addr.s6_addr16[2]; - uint16_t w3 = in6->sin6_addr.s6_addr16[3]; - uint16_t w4 = in6->sin6_addr.s6_addr16[4]; - uint16_t w5 = in6->sin6_addr.s6_addr16[5]; - if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 && w5 == 0xFFFF) + uint8_t w0 = in6->sin6_addr.s6_addr[0]; + uint8_t w1 = in6->sin6_addr.s6_addr[1]; + uint8_t w2 = in6->sin6_addr.s6_addr[2]; + uint8_t w3 = in6->sin6_addr.s6_addr[3]; + uint8_t w4 = in6->sin6_addr.s6_addr[4]; + uint8_t w5 = in6->sin6_addr.s6_addr[5]; + uint8_t w6 = in6->sin6_addr.s6_addr[6]; + uint8_t w7 = in6->sin6_addr.s6_addr[7]; + uint8_t w8 = in6->sin6_addr.s6_addr[8]; + uint8_t w9 = in6->sin6_addr.s6_addr[9]; + uint8_t w10 = in6->sin6_addr.s6_addr[10]; + uint8_t w11 = in6->sin6_addr.s6_addr[11]; + if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 && + w5 == 0 && w6 == 0 && w7 == 0 && w8 == 0 && w9 == 0 && + w10 == 0xff && w11 == 0xff) { ea->host = ((in_addr*)(in6->sin6_addr.s6_addr + 12))->s_addr; ea->port = ntohs(in6->sin6_port); diff --git a/src/network/unix_ipv6.hpp b/src/network/stk_ipv6.hpp similarity index 98% rename from src/network/unix_ipv6.hpp rename to src/network/stk_ipv6.hpp index 333b36241..14929189a 100644 --- a/src/network/unix_ipv6.hpp +++ b/src/network/stk_ipv6.hpp @@ -23,7 +23,7 @@ extern "C" { #endif int isIPV6(); void setIPV6(int val); -void unixInitialize(); +void stkInitialize(); void getIPV6FromMappedAddress(const ENetAddress* ea, struct sockaddr_in6* in6); void getMappedFromIPV6(const struct sockaddr_in6* in6, ENetAddress* ea); void addMappedAddress(const ENetAddress* ea, const struct sockaddr_in6* in6); diff --git a/src/network/stk_peer.cpp b/src/network/stk_peer.cpp index cda6fc215..4852b5421 100644 --- a/src/network/stk_peer.cpp +++ b/src/network/stk_peer.cpp @@ -23,9 +23,9 @@ #include "network/event.hpp" #include "network/network_config.hpp" #include "network/network_string.hpp" +#include "network/stk_ipv6.hpp" #include "network/stk_host.hpp" #include "network/transport_address.hpp" -#include "network/unix_ipv6.hpp" #include "utils/log.hpp" #include "utils/string_utils.hpp" #include "utils/time.hpp"