diff --git a/.gitmodules b/.gitmodules index 64995f1c31..45064e2b9b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -69,9 +69,6 @@ [submodule "Externals/xxhash/xxHash"] path = Externals/xxhash/xxHash url = https://github.com/Cyan4973/xxHash.git -[submodule "Externals/enet/enet"] - path = Externals/enet/enet - url = https://github.com/lsalzman/enet.git [submodule "hidapi-src"] path = Externals/hidapi/hidapi-src url = https://github.com/libusb/hidapi @@ -84,3 +81,6 @@ [submodule "Externals/Vulkan-Headers"] path = Externals/Vulkan-Headers url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "enet"] + path = Externals/enet/enet + url = https://github.com/freeminer/enet.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 3495e3b2b3..61c9bf264a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -660,7 +660,10 @@ endif() dolphin_find_optional_system_library(pugixml Externals/pugixml) -dolphin_find_optional_system_library_pkgconfig(ENET libenet>=1.3.18 enet::enet Externals/enet) +# Using static enet from Externals since we are using a fork that supports +# IPv6 (freeminers/enet) +message(STATUS "Using static enet from Externals (freeminer/enet)") +add_subdirectory(Externals/enet) dolphin_find_optional_system_library_pkgconfig(xxhash libxxhash>=0.8.2 xxhash::xxhash Externals/xxhash) diff --git a/Externals/enet/enet b/Externals/enet/enet index 2a85cd6445..9a74b51109 160000 --- a/Externals/enet/enet +++ b/Externals/enet/enet @@ -1 +1 @@ -Subproject commit 2a85cd64459f6ba038d233a634d9440490dbba12 +Subproject commit 9a74b511091a172cd78bf57f0d4a440f41600de1 diff --git a/Source/Core/Common/ENet.cpp b/Source/Core/Common/ENet.cpp index f99c4476c5..a14bc1715a 100644 --- a/Source/Core/Common/ENet.cpp +++ b/Source/Core/Common/ENet.cpp @@ -18,7 +18,7 @@ void WakeupThread(ENetHost* host) address.port = host->address.port; else enet_socket_get_address(host->socket, &address); - address.host = 0x0100007f; // localhost + address.host = in6addr_loopback; // localhost or ::1 u8 byte = 0; ENetBuffer buf; buf.data = &byte; @@ -62,4 +62,22 @@ bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id) return true; } + +std::optional AddressFromString(const std::string& addr_str) +{ + in6_addr addr; + memset(&addr, 0, sizeof(in6_addr)); + if (!inet_pton(AF_INET6, addr_str.c_str(), &addr)) + { + in_addr addr_v4; + if (!inet_pton(AF_INET, addr_str.c_str(), &addr_v4)) { + return {}; + } + + u32 v6_mapped_addr[4] = {0, 0, htonl(0x0000ffff), *reinterpret_cast(&addr_v4)}; + memcpy(&addr, v6_mapped_addr, sizeof(in6_addr)); + } + + return addr; +} } // namespace Common::ENet diff --git a/Source/Core/Common/ENet.h b/Source/Core/Common/ENet.h index a79a59e4a7..99a7dc5bf8 100644 --- a/Source/Core/Common/ENet.h +++ b/Source/Core/Common/ENet.h @@ -7,6 +7,7 @@ #include #include +#include #include "Common/CommonTypes.h" @@ -21,6 +22,7 @@ using ENetHostPtr = std::unique_ptr; void WakeupThread(ENetHost* host); int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event); bool SendPacket(ENetPeer* socket, const sf::Packet& packet, u8 channel_id); +std::optional AddressFromString(const std::string& addr); // used for traversal packets and wake-up packets constexpr int SKIPPABLE_EVENT = 42; diff --git a/Source/Core/Common/QoSSession.cpp b/Source/Core/Common/QoSSession.cpp index f143517427..0e53d498b2 100644 --- a/Source/Core/Common/QoSSession.cpp +++ b/Source/Core/Common/QoSSession.cpp @@ -20,13 +20,13 @@ QoSSession::QoSSession(ENetPeer* peer, int tos_val) : m_peer(peer) if (!QOSCreateHandle(&ver, &m_qos_handle)) return; - sockaddr_in sin = {}; + sockaddr_in6 sin6 = {}; - sin.sin_family = AF_INET; - sin.sin_port = ENET_HOST_TO_NET_16(peer->host->address.port); - sin.sin_addr.s_addr = peer->host->address.host; + sin6.sin6_family = AF_INET6; + sin6.sin6_port = ENET_HOST_TO_NET_16(peer->host->address.port); + memcpy(&sin6.sin6_addr, &peer->host->address.host, sizeof(struct in6_addr)); - if (QOSAddSocketToFlow(m_qos_handle, peer->host->socket, reinterpret_cast(&sin), + if (QOSAddSocketToFlow(m_qos_handle, peer->host->socket, reinterpret_cast(&sin6), QOSTrafficTypeControl, QOS_NON_ADAPTIVE_FLOW, &m_qos_flow_id)) { // We shift the complete ToS value by 3 to get rid of the 3 bit ECN field diff --git a/Source/Core/Common/TraversalClient.cpp b/Source/Core/Common/TraversalClient.cpp index 44b8390f90..7e58adb643 100644 --- a/Source/Core/Common/TraversalClient.cpp +++ b/Source/Core/Common/TraversalClient.cpp @@ -49,12 +49,17 @@ TraversalClient::FailureReason TraversalClient::GetFailureReason() const void TraversalClient::ReconnectToServer() { - if (enet_address_set_host(&m_ServerAddress, m_Server.c_str())) + if (auto addr = Common::ENet::AddressFromString(m_Server)) + { + m_ServerAddress.host = *addr; + } + else { OnFailure(FailureReason::BadHost); return; } m_ServerAddress.port = m_port; + m_ServerAddress.sin6_scope_id = 0; m_State = State::Connecting; @@ -71,12 +76,16 @@ static ENetAddress MakeENetAddress(const TraversalInetAddress& address) ENetAddress eaddr{}; if (address.isIPV6) { - eaddr.port = 0; // no support yet :( + memcpy(&eaddr.host, &address.address, sizeof(address.address)); + eaddr.port = ntohs(address.port); + eaddr.sin6_scope_id = 0; } else { - eaddr.host = address.address[0]; + u32 ipv4_mapped_addr[4] = {0, 0, 0xffff0000, address.address[0]}; + memcpy(&eaddr.host, &ipv4_mapped_addr, sizeof(ipv4_mapped_addr)); eaddr.port = ntohs(address.port); + eaddr.sin6_scope_id = 0; } return eaddr; } @@ -97,7 +106,7 @@ void TraversalClient::ConnectToClient(std::string_view host) bool TraversalClient::TestPacket(u8* data, size_t size, ENetAddress* from) { - if (from->host == m_ServerAddress.host && from->port == m_ServerAddress.port) + if (in6_equal(from->host, m_ServerAddress.host) && from->port == m_ServerAddress.port) { if (size < sizeof(TraversalPacket)) { @@ -299,7 +308,7 @@ void TraversalClient::NewTraversalTest() if (m_TestSocket != ENET_SOCKET_NULL) enet_socket_destroy(m_TestSocket); m_TestSocket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); - ENetAddress addr = {ENET_HOST_ANY, 0}; + ENetAddress addr = {in6addr_any, 0, 0}; if (m_TestSocket == ENET_SOCKET_NULL || enet_socket_bind(m_TestSocket, &addr) < 0) { // error, abort @@ -373,8 +382,8 @@ void TraversalClient::HandleTraversalTest() waitCondition = 0; break; } - else if (rv < int(sizeof(packet)) || raddr.host != m_ServerAddress.host || - raddr.host != m_portAlt || packet.requestId != m_TestRequestId) + else if (rv < int(sizeof(packet)) || !in6_equal(raddr.host, m_ServerAddress.host) || + raddr.port != m_portAlt || packet.requestId != m_TestRequestId) { // irrelevant packet, ignore continue; @@ -452,7 +461,7 @@ bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 serve g_OldServerPortAlt = server_port_alt; g_OldListenPort = listen_port; - ENetAddress addr = {ENET_HOST_ANY, listen_port}; + ENetAddress addr = {in6addr_any, listen_port, 0}; auto host = Common::ENet::ENetHostPtr{enet_host_create(&addr, // address 50, // peerCount NetPlay::CHANNEL_COUNT, // channelLimit diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 82c594dff6..6d144a792e 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -147,8 +147,12 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlay m_client->mtu = std::min(m_client->mtu, NetPlay::MAX_ENET_MTU); ENetAddress addr; - enet_address_set_host(&addr, address.c_str()); + if (auto parsed_addr = Common::ENet::AddressFromString(address)) + { + addr.host = *parsed_addr; + } addr.port = port; + addr.sin6_scope_id = 0; m_server = enet_host_connect(m_client, &addr, CHANNEL_COUNT, 0); diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index ae88ba3d82..31051a7b6f 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -152,8 +152,9 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI* else { ENetAddress serverAddr; - serverAddr.host = ENET_HOST_ANY; + serverAddr.host = in6addr_any; serverAddr.port = port; + serverAddr.sin6_scope_id = 0; m_server = enet_host_create(&serverAddr, 10, CHANNEL_COUNT, 0, 0); if (m_server != nullptr) { @@ -304,8 +305,9 @@ void NetPlayServer::ThreadFunc() { // Actual client initialization is deferred to the receive event, so here // we'll just log the new connection. - INFO_LOG_FMT(NETPLAY, "Peer connected from: {:x}:{}", netEvent.peer->address.host, - netEvent.peer->address.port); + char host_str[48]; + enet_address_get_host_ip(&netEvent.peer->address, host_str, 48); + INFO_LOG_FMT(NETPLAY, "Peer connected from: {}:{}", host_str, netEvent.peer->address.port); } break; case ENET_EVENT_TYPE_RECEIVE: @@ -320,16 +322,19 @@ void NetPlayServer::ThreadFunc() // uninitialized client, we'll assume this is their initialization packet ConnectionError error; { - INFO_LOG_FMT(NETPLAY, "Initializing peer {:x}:{}", netEvent.peer->address.host, - netEvent.peer->address.port); + char host_str[48]; + enet_address_get_host_ip(&netEvent.peer->address, host_str, 48); + INFO_LOG_FMT(NETPLAY, "Initializing peer {}:{}", host_str, netEvent.peer->address.port); std::lock_guard lkg(m_crit.game); error = OnConnect(netEvent.peer, rpac); } if (error != ConnectionError::NoError) { - INFO_LOG_FMT(NETPLAY, "Error {} initializing peer {:x}:{}", u8(error), - netEvent.peer->address.host, netEvent.peer->address.port); + char host_str[48]; + enet_address_get_host_ip(&netEvent.peer->address, host_str, 48); + INFO_LOG_FMT(NETPLAY, "Error {} initializing peer {}:{}", u8(error), host_str, + netEvent.peer->address.port); sf::Packet spac; spac << error; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 93ad16a59e..f3ca9cd920 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1570,7 +1570,7 @@ bool MainWindow::NetPlayJoin() u16 host_port; if (server) { - host_ip = "127.0.0.1"; + host_ip = "::1"; host_port = server->GetPort(); } else