diff --git a/Source/Core/Common/TraversalClient.cpp b/Source/Core/Common/TraversalClient.cpp index e384c1cca8e0..644d26d06cb6 100644 --- a/Source/Core/Common/TraversalClient.cpp +++ b/Source/Core/Common/TraversalClient.cpp @@ -14,8 +14,9 @@ namespace Common { -TraversalClient::TraversalClient(ENetHost* netHost, const std::string& server, const u16 port) - : m_NetHost(netHost), m_Server(server), m_port(port) +TraversalClient::TraversalClient(ENetHost* netHost, const std::string& server, const u16 port, + const u16 port_alt) + : m_NetHost(netHost), m_Server(server), m_port(port), m_portAlt(port_alt) { netHost->intercept = TraversalClient::InterceptCallback; @@ -146,6 +147,8 @@ void TraversalClient::HandleServerPacket(TraversalPacket* packet) { if (it->packet.requestId == packet->requestId) { + if (packet->requestId == m_TestRequestId) + HandleTraversalTest(); m_OutgoingTraversalPackets.erase(it); break; } @@ -161,6 +164,7 @@ void TraversalClient::HandleServerPacket(TraversalPacket* packet) } m_HostId = packet->helloFromServer.yourHostId; m_external_address = packet->helloFromServer.yourAddress; + NewTraversalTest(); m_State = State::Connected; if (m_Client) m_Client->OnTraversalStateChanged(); @@ -175,7 +179,18 @@ void TraversalClient::HandleServerPacket(TraversalPacket* packet) ENetBuffer buf; buf.data = message; buf.dataLength = sizeof(message) - 1; - enet_socket_send(m_NetHost->socket, &addr, &buf, 1); + if (m_ttlReady) + { + int oldttl; + enet_socket_get_option(m_NetHost->socket, ENET_SOCKOPT_TTL, &oldttl); + enet_socket_set_option(m_NetHost->socket, ENET_SOCKOPT_TTL, m_ttl); + enet_socket_send(m_NetHost->socket, &addr, &buf, 1); + enet_socket_set_option(m_NetHost->socket, ENET_SOCKOPT_TTL, oldttl); + } + else + { + enet_socket_send(m_NetHost->socket, &addr, &buf, 1); + } } else { @@ -231,12 +246,15 @@ void TraversalClient::OnFailure(FailureReason reason) void TraversalClient::ResendPacket(OutgoingTraversalPacketInfo* info) { + bool testPacket = + m_TestSocket != ENET_SOCKET_NULL && info->packet.type == TraversalPacketType::TestPlease; info->sendTime = enet_time_get(); info->tries++; ENetBuffer buf; buf.data = &info->packet; buf.dataLength = sizeof(info->packet); - if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1) + if (enet_socket_send(testPacket ? m_TestSocket : m_NetHost->socket, &m_ServerAddress, &buf, 1) == + -1) OnFailure(FailureReason::SocketSendError); } @@ -275,6 +293,112 @@ void TraversalClient::HandlePing() } } +void TraversalClient::NewTraversalTest() +{ + // create test socket + 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}; + if (m_TestSocket == ENET_SOCKET_NULL || enet_socket_bind(m_TestSocket, &addr) < 0) + { + // error, abort + if (m_TestSocket != ENET_SOCKET_NULL) + { + enet_socket_destroy(m_TestSocket); + m_TestSocket = ENET_SOCKET_NULL; + } + return; + } + enet_socket_set_option(m_TestSocket, ENET_SOCKOPT_NONBLOCK, 1); + // create holepunch packet + TraversalPacket packet = {}; + packet.type = TraversalPacketType::Ping; + packet.ping.hostId = m_HostId; + packet.requestId = Common::Random::GenerateValue(); + // create buffer + ENetBuffer buf; + buf.data = &packet; + buf.dataLength = sizeof(packet); + // send to alt port + ENetAddress altAddress = m_ServerAddress; + altAddress.port = m_portAlt; + // set up ttl and send + int oldttl; + enet_socket_get_option(m_TestSocket, ENET_SOCKOPT_TTL, &oldttl); + enet_socket_set_option(m_TestSocket, ENET_SOCKOPT_TTL, m_ttl); + if (enet_socket_send(m_TestSocket, &altAddress, &buf, 1) == -1) + { + // error, abort + enet_socket_destroy(m_TestSocket); + m_TestSocket = ENET_SOCKET_NULL; + return; + } + enet_socket_set_option(m_TestSocket, ENET_SOCKOPT_TTL, oldttl); + // send the test request + packet.type = TraversalPacketType::TestPlease; + m_TestRequestId = SendTraversalPacket(packet); +} + +void TraversalClient::HandleTraversalTest() +{ + if (m_TestSocket != ENET_SOCKET_NULL) + { + // check for packet on test socket (with timeout) + u32 deadline = enet_time_get() + 50; + u32 waitCondition; + do + { + waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT; + u32 currentTime = enet_time_get(); + if (currentTime > deadline || + enet_socket_wait(m_TestSocket, &waitCondition, deadline - currentTime) != 0) + { + // error or timeout, exit the loop and assume test failure + waitCondition = 0; + break; + } + else if (waitCondition & ENET_SOCKET_WAIT_RECEIVE) + { + // try reading the packet and see if it's relevant + ENetAddress raddr; + TraversalPacket packet; + ENetBuffer buf; + buf.data = &packet; + buf.dataLength = sizeof(packet); + int rv = enet_socket_receive(m_TestSocket, &raddr, &buf, 1); + if (rv < 0) + { + // error, exit the loop and assume test failure + waitCondition = 0; + break; + } + else if (rv < sizeof(packet) || raddr.host != m_ServerAddress.host || + raddr.host != m_portAlt || packet.requestId != m_TestRequestId) + { + // irrelevant packet, ignore + continue; + } + } + } while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT); + // regardless of what happens next, we can throw out the socket + enet_socket_destroy(m_TestSocket); + m_TestSocket = ENET_SOCKET_NULL; + if (waitCondition & ENET_SOCKET_WAIT_RECEIVE) + { + // success, we can stop now + m_ttlReady = true; + m_Client->OnTtlDetermined(m_ttl); + } + else + { + // fail, increment and retry + if (++m_ttl < 32) + NewTraversalTest(); + } + } +} + TraversalRequestId TraversalClient::SendTraversalPacket(const TraversalPacket& packet) { OutgoingTraversalPacketInfo info; @@ -313,15 +437,19 @@ ENet::ENetHostPtr g_MainNetHost; // explicitly requested. static std::string g_OldServer; static u16 g_OldServerPort; +static u16 g_OldServerPortAlt; static u16 g_OldListenPort; -bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port) +bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 server_port_alt, + u16 listen_port) { if (!g_MainNetHost || !g_TraversalClient || server != g_OldServer || - server_port != g_OldServerPort || listen_port != g_OldListenPort) + server_port != g_OldServerPort || server_port_alt != g_OldServerPortAlt || + listen_port != g_OldListenPort) { g_OldServer = server; g_OldServerPort = server_port; + g_OldServerPortAlt = server_port_alt; g_OldListenPort = listen_port; ENetAddress addr = {ENET_HOST_ANY, listen_port}; @@ -337,7 +465,8 @@ bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 liste } host->mtu = std::min(host->mtu, NetPlay::MAX_ENET_MTU); g_MainNetHost = std::move(host); - g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, server_port)); + g_TraversalClient.reset( + new TraversalClient(g_MainNetHost.get(), server, server_port, server_port_alt)); } return true; } diff --git a/Source/Core/Common/TraversalClient.h b/Source/Core/Common/TraversalClient.h index b0717ae0a99f..efe0e2f7d1f4 100644 --- a/Source/Core/Common/TraversalClient.h +++ b/Source/Core/Common/TraversalClient.h @@ -24,6 +24,7 @@ class TraversalClientClient virtual void OnTraversalStateChanged() = 0; virtual void OnConnectReady(ENetAddress addr) = 0; virtual void OnConnectFailed(TraversalConnectFailedReason reason) = 0; + virtual void OnTtlDetermined(u8 ttl) = 0; }; class TraversalClient @@ -43,7 +44,8 @@ class TraversalClient SocketSendError, ResendTimeout, }; - TraversalClient(ENetHost* netHost, const std::string& server, const u16 port); + TraversalClient(ENetHost* netHost, const std::string& server, const u16 port, + const u16 port_alt = 0); ~TraversalClient(); TraversalHostId GetHostID() const; @@ -79,6 +81,9 @@ class TraversalClient void HandlePing(); static int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event); + void NewTraversalTest(); + void HandleTraversalTest(); + ENetHost* m_NetHost; TraversalHostId m_HostId{}; TraversalInetAddress m_external_address{}; @@ -90,7 +95,13 @@ class TraversalClient ENetAddress m_ServerAddress{}; std::string m_Server; u16 m_port; + u16 m_portAlt; u32 m_PingTime = 0; + + ENetSocket m_TestSocket = ENET_SOCKET_NULL; + TraversalRequestId m_TestRequestId = 0; + u8 m_ttl = 2; + bool m_ttlReady = false; }; extern std::unique_ptr g_TraversalClient; @@ -98,6 +109,7 @@ extern std::unique_ptr g_TraversalClient; extern ENet::ENetHostPtr g_MainNetHost; // Create g_TraversalClient and g_MainNetHost if necessary. -bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 listen_port = 0); +bool EnsureTraversalClient(const std::string& server, u16 server_port, u16 server_port_alt = 0, + u16 listen_port = 0); void ReleaseTraversalClient(); } // namespace Common diff --git a/Source/Core/Common/TraversalProto.h b/Source/Core/Common/TraversalProto.h index 1946d7b9a911..8ee45d1fa773 100644 --- a/Source/Core/Common/TraversalProto.h +++ b/Source/Core/Common/TraversalProto.h @@ -31,6 +31,10 @@ enum class TraversalPacketType : u8 ConnectReady = 6, // [s->c] Alternately, the server might not have heard of this host. ConnectFailed = 7, + // [c->s] Perform a traveral test. This will send two acks: + // one via the server's alt port, and one to the address corresponding to + // the given host ID. + TestPlease = 8, }; constexpr u8 TraversalProtoVersion = 0; @@ -91,6 +95,10 @@ struct TraversalPacket TraversalRequestId requestId; TraversalConnectFailedReason reason; } connectFailed; + struct + { + TraversalHostId hostId; + } testPlease; }; }; #pragma pack(pop) diff --git a/Source/Core/Common/TraversalServer.cpp b/Source/Core/Common/TraversalServer.cpp index b9b05519fa07..05797b66599b 100644 --- a/Source/Core/Common/TraversalServer.cpp +++ b/Source/Core/Common/TraversalServer.cpp @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -26,6 +28,7 @@ #define DEBUG 0 #define NUMBER_OF_TRIES 5 #define PORT 6262 +#define PORT_ALT 6226 static u64 currentTime; @@ -33,6 +36,7 @@ struct OutgoingPacketInfo { Common::TraversalPacket packet; Common::TraversalRequestId misc; + bool fromAlt; sockaddr_in6 dest; int tries; u64 sendTime; @@ -119,6 +123,7 @@ using ConnectedClients = using OutgoingPackets = std::unordered_map; static int sock; +static int sockAlt; static OutgoingPackets outgoingPackets; static ConnectedClients connectedClients; @@ -186,25 +191,27 @@ static const char* SenderName(sockaddr_in6* addr) return buf; } -static void TrySend(const void* buffer, size_t size, sockaddr_in6* addr) +static void TrySend(const void* buffer, size_t size, sockaddr_in6* addr, bool fromAlt) { #if DEBUG const auto* packet = static_cast(buffer); - printf("-> %d %llu %s\n", static_cast(packet->type), + printf("%s-> %d %llu %s\n", fromAlt ? "alt " : "", static_cast(packet->type), static_cast(packet->requestId), SenderName(addr)); #endif - if ((size_t)sendto(sock, buffer, size, 0, (sockaddr*)addr, sizeof(*addr)) != size) + if ((size_t)sendto(fromAlt ? sockAlt : sock, buffer, size, 0, (sockaddr*)addr, sizeof(*addr)) != + size) { perror("sendto"); } } -static Common::TraversalPacket* AllocPacket(const sockaddr_in6& dest, +static Common::TraversalPacket* AllocPacket(const sockaddr_in6& dest, bool fromAlt, Common::TraversalRequestId misc = 0) { Common::TraversalRequestId requestId{}; Common::Random::Generate(&requestId, sizeof(requestId)); OutgoingPacketInfo* info = &outgoingPackets[requestId]; + info->fromAlt = fromAlt; info->dest = dest; info->misc = misc; info->tries = 0; @@ -219,12 +226,13 @@ static void SendPacket(OutgoingPacketInfo* info) { info->tries++; info->sendTime = currentTime; - TrySend(&info->packet, sizeof(info->packet), &info->dest); + TrySend(&info->packet, sizeof(info->packet), &info->dest, info->fromAlt); } static void ResendPackets() { - std::vector> todoFailures; + std::vector> + todoFailures; todoFailures.clear(); for (auto it = outgoingPackets.begin(); it != outgoingPackets.end();) { @@ -235,7 +243,8 @@ static void ResendPackets() { if (info->packet.type == Common::TraversalPacketType::PleaseSendPacket) { - todoFailures.push_back(std::make_pair(info->packet.pleaseSendPacket.address, info->misc)); + todoFailures.push_back( + std::make_tuple(info->packet.pleaseSendPacket.address, info->fromAlt, info->misc)); } it = outgoingPackets.erase(it); continue; @@ -250,14 +259,14 @@ static void ResendPackets() for (const auto& p : todoFailures) { - Common::TraversalPacket* fail = AllocPacket(MakeSinAddr(p.first)); + Common::TraversalPacket* fail = AllocPacket(MakeSinAddr(std::get<0>(p)), std::get<1>(p)); fail->type = Common::TraversalPacketType::ConnectFailed; - fail->connectFailed.requestId = p.second; + fail->connectFailed.requestId = std::get<2>(p); fail->connectFailed.reason = Common::TraversalConnectFailedReason::ClientDidntRespond; } } -static void HandlePacket(Common::TraversalPacket* packet, sockaddr_in6* addr) +static void HandlePacket(Common::TraversalPacket* packet, sockaddr_in6* addr, bool toAlt) { #if DEBUG printf("<- %d %llu %s\n", static_cast(packet->type), @@ -276,7 +285,7 @@ static void HandlePacket(Common::TraversalPacket* packet, sockaddr_in6* addr) if (info->packet.type == Common::TraversalPacketType::PleaseSendPacket) { - auto* ready = AllocPacket(MakeSinAddr(info->packet.pleaseSendPacket.address)); + auto* ready = AllocPacket(MakeSinAddr(info->packet.pleaseSendPacket.address), toAlt); if (packet->ack.ok) { ready->type = Common::TraversalPacketType::ConnectReady; @@ -303,7 +312,7 @@ static void HandlePacket(Common::TraversalPacket* packet, sockaddr_in6* addr) case Common::TraversalPacketType::HelloFromClient: { u8 ok = packet->helloFromClient.protoVersion <= Common::TraversalProtoVersion; - Common::TraversalPacket* reply = AllocPacket(*addr); + Common::TraversalPacket* reply = AllocPacket(*addr, toAlt); reply->type = Common::TraversalPacketType::HelloFromServer; reply->helloFromServer.ok = ok; if (ok) @@ -336,19 +345,35 @@ static void HandlePacket(Common::TraversalPacket* packet, sockaddr_in6* addr) auto r = EvictFind(connectedClients, hostId); if (!r.found) { - Common::TraversalPacket* reply = AllocPacket(*addr); + Common::TraversalPacket* reply = AllocPacket(*addr, toAlt); reply->type = Common::TraversalPacketType::ConnectFailed; reply->connectFailed.requestId = packet->requestId; reply->connectFailed.reason = Common::TraversalConnectFailedReason::NoSuchClient; } else { - Common::TraversalPacket* please = AllocPacket(MakeSinAddr(*r.value), packet->requestId); + Common::TraversalPacket* please = + AllocPacket(MakeSinAddr(*r.value), toAlt, packet->requestId); please->type = Common::TraversalPacketType::PleaseSendPacket; please->pleaseSendPacket.address = MakeInetAddress(*addr); } break; } + case Common::TraversalPacketType::TestPlease: + { + Common::TraversalHostId& hostId = packet->testPlease.hostId; + auto r = EvictFind(connectedClients, hostId); + if (r.found) + { + Common::TraversalPacket ack = {}; + ack.type = Common::TraversalPacketType::Ack; + ack.requestId = packet->requestId; + ack.ack.ok = true; + sockaddr_in6 mainAddr = MakeSinAddr(*r.value); + TrySend(&ack, sizeof(ack), &mainAddr, toAlt); + } + break; + } default: fprintf(stderr, "received unknown packet type %d from %s\n", static_cast(packet->type), SenderName(addr)); @@ -360,7 +385,8 @@ static void HandlePacket(Common::TraversalPacket* packet, sockaddr_in6* addr) ack.type = Common::TraversalPacketType::Ack; ack.requestId = packet->requestId; ack.ack.ok = packetOk; - TrySend(&ack, sizeof(ack), addr); + TrySend(&ack, sizeof(ack), addr, + packet->type != Common::TraversalPacketType::TestPlease ? toAlt : !toAlt); } } @@ -373,6 +399,12 @@ int main() perror("socket"); return 1; } + sockAlt = socket(PF_INET6, SOCK_DGRAM, 0); + if (sockAlt == -1) + { + perror("socket alt"); + return 1; + } int no = 0; rv = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); if (rv < 0) @@ -380,6 +412,12 @@ int main() perror("setsockopt IPV6_V6ONLY"); return 1; } + rv = setsockopt(sockAlt, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no)); + if (rv < 0) + { + perror("setsockopt IPV6_V6ONLY alt"); + return 1; + } in6_addr any = IN6ADDR_ANY_INIT; sockaddr_in6 addr; #ifdef SIN6_LEN @@ -397,6 +435,13 @@ int main() perror("bind"); return 1; } + addr.sin6_port = htons(PORT_ALT); + rv = bind(sockAlt, (sockaddr*)&addr, sizeof(addr)); + if (rv < 0) + { + perror("bind alt"); + return 1; + } timeval tv; tv.tv_sec = 0; @@ -407,19 +452,55 @@ int main() perror("setsockopt SO_RCVTIMEO"); return 1; } + rv = setsockopt(sockAlt, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + if (rv < 0) + { + perror("setsockopt SO_RCVTIMEO alt"); + return 1; + } #ifdef HAVE_LIBSYSTEMD - sd_notifyf(0, "READY=1\nSTATUS=Listening on port %d", PORT); + sd_notifyf(0, "READY=1\nSTATUS=Listening on port %d (alt port: %d)", PORT, PORT_ALT); #endif while (true) { + tv.tv_sec = 0; + tv.tv_usec = 300000; + fd_set readSet; + FD_ZERO(&readSet); + FD_SET(sock, &readSet); + FD_SET(sockAlt, &readSet); + rv = select(std::max(sock, sockAlt) + 1, &readSet, nullptr, nullptr, &tv); + if (rv < 0) + { + if (errno != EINTR && errno != EAGAIN) + { + perror("recvfrom"); + return 1; + } + } + + int recvsock; + if (FD_ISSET(sock, &readSet)) + { + recvsock = sock; + } + else if (FD_ISSET(sockAlt, &readSet)) + { + recvsock = sockAlt; + } + else + { + ResendPackets(); + continue; + } sockaddr_in6 raddr; socklen_t addrLen = sizeof(raddr); Common::TraversalPacket packet{}; // note: switch to recvmmsg (yes, mmsg) if this becomes // expensive - rv = recvfrom(sock, &packet, sizeof(packet), 0, (sockaddr*)&raddr, &addrLen); + rv = recvfrom(recvsock, &packet, sizeof(packet), 0, (sockaddr*)&raddr, &addrLen); currentTime = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); @@ -437,7 +518,7 @@ int main() } else { - HandlePacket(&packet, &raddr); + HandlePacket(&packet, &raddr, recvsock == sockAlt); } ResendPackets(); #ifdef HAVE_LIBSYSTEMD diff --git a/Source/Core/Core/Config/NetplaySettings.cpp b/Source/Core/Core/Config/NetplaySettings.cpp index d0dab392bd82..094c0e7211f3 100644 --- a/Source/Core/Core/Config/NetplaySettings.cpp +++ b/Source/Core/Core/Config/NetplaySettings.cpp @@ -16,6 +16,7 @@ static constexpr u16 DEFAULT_LISTEN_PORT = 2626; const Info NETPLAY_TRAVERSAL_SERVER{{System::Main, "NetPlay", "TraversalServer"}, "stun.dolphin-emu.org"}; const Info NETPLAY_TRAVERSAL_PORT{{System::Main, "NetPlay", "TraversalPort"}, 6262}; +const Info NETPLAY_TRAVERSAL_PORT_ALT{{System::Main, "NetPlay", "TraversalPortAlt"}, 6226}; const Info NETPLAY_TRAVERSAL_CHOICE{{System::Main, "NetPlay", "TraversalChoice"}, "direct"}; const Info NETPLAY_INDEX_URL{{System::Main, "NetPlay", "IndexServer"}, diff --git a/Source/Core/Core/Config/NetplaySettings.h b/Source/Core/Core/Config/NetplaySettings.h index 7704808bc798..db51aaf860bc 100644 --- a/Source/Core/Core/Config/NetplaySettings.h +++ b/Source/Core/Core/Config/NetplaySettings.h @@ -16,6 +16,7 @@ namespace Config extern const Info NETPLAY_TRAVERSAL_SERVER; extern const Info NETPLAY_TRAVERSAL_PORT; +extern const Info NETPLAY_TRAVERSAL_PORT_ALT; extern const Info NETPLAY_TRAVERSAL_CHOICE; extern const Info NETPLAY_HOST_CODE; extern const Info NETPLAY_INDEX_URL; diff --git a/Source/Core/Core/NetPlayClient.h b/Source/Core/Core/NetPlayClient.h index aba54b12dd4e..7ab716aef74f 100644 --- a/Source/Core/Core/NetPlayClient.h +++ b/Source/Core/Core/NetPlayClient.h @@ -72,6 +72,7 @@ class NetPlayUI virtual void OnTraversalStateChanged(Common::TraversalClient::State state) = 0; virtual void OnGameStartAborted() = 0; virtual void OnGolferChanged(bool is_golfer, const std::string& golfer_name) = 0; + virtual void OnTtlDetermined(u8 ttl) = 0; virtual bool IsRecording() = 0; virtual std::shared_ptr @@ -148,6 +149,7 @@ class NetPlayClient : public Common::TraversalClientClient void OnTraversalStateChanged() override; void OnConnectReady(ENetAddress addr) override; void OnConnectFailed(Common::TraversalConnectFailedReason reason) override; + void OnTtlDetermined(u8 ttl) override {} bool IsFirstInGamePad(int ingame_pad) const; int NumLocalPads() const; diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index cfe498ca312e..a20aee39ce5e 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -116,15 +116,17 @@ struct NetSettings struct NetTraversalConfig { NetTraversalConfig() = default; - NetTraversalConfig(bool use_traversal_, std::string traversal_host_, u16 traversal_port_) + NetTraversalConfig(bool use_traversal_, std::string traversal_host_, u16 traversal_port_, + u16 traversal_port_alt_ = 0) : use_traversal{use_traversal_}, traversal_host{std::move(traversal_host_)}, - traversal_port{traversal_port_} + traversal_port{traversal_port_}, traversal_port_alt{traversal_port_alt_} { } bool use_traversal = false; std::string traversal_host; u16 traversal_port = 0; + u16 traversal_port_alt = 0; }; enum class MessageID : u8 diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index 5452d9e80f5f..cff261baafc4 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -133,7 +133,8 @@ NetPlayServer::NetPlayServer(const u16 port, const bool forward_port, NetPlayUI* if (traversal_config.use_traversal) { if (!Common::EnsureTraversalClient(traversal_config.traversal_host, - traversal_config.traversal_port, port)) + traversal_config.traversal_port, + traversal_config.traversal_port_alt, port)) { return; } @@ -1264,6 +1265,11 @@ void NetPlayServer::OnTraversalStateChanged() m_dialog->OnTraversalStateChanged(state); } +void NetPlayServer::OnTtlDetermined(u8 ttl) +{ + m_dialog->OnTtlDetermined(ttl); +} + // called from ---GUI--- thread void NetPlayServer::SendChatMessage(const std::string& msg) { diff --git a/Source/Core/Core/NetPlayServer.h b/Source/Core/Core/NetPlayServer.h index 0498ff12fc65..621b7cfe404a 100644 --- a/Source/Core/Core/NetPlayServer.h +++ b/Source/Core/Core/NetPlayServer.h @@ -144,6 +144,7 @@ class NetPlayServer : public Common::TraversalClientClient void OnTraversalStateChanged() override; void OnConnectReady(ENetAddress) override {} void OnConnectFailed(Common::TraversalConnectFailedReason) override {} + void OnTtlDetermined(u8 ttl) override; void UpdatePadMapping(); void UpdateGBAConfig(); void UpdateWiimoteMapping(); diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index aef0f94cc84e..5dfc58c0dafd 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1563,14 +1563,16 @@ bool MainWindow::NetPlayHost(const UICommon::GameFile& game) const std::string traversal_host = Config::Get(Config::NETPLAY_TRAVERSAL_SERVER); const u16 traversal_port = Config::Get(Config::NETPLAY_TRAVERSAL_PORT); + const u16 traversal_port_alt = Config::Get(Config::NETPLAY_TRAVERSAL_PORT_ALT); if (is_traversal) host_port = Config::Get(Config::NETPLAY_LISTEN_PORT); // Create Server - Settings::Instance().ResetNetPlayServer(new NetPlay::NetPlayServer( - host_port, use_upnp, m_netplay_dialog, - NetPlay::NetTraversalConfig{is_traversal, traversal_host, traversal_port})); + Settings::Instance().ResetNetPlayServer( + new NetPlay::NetPlayServer(host_port, use_upnp, m_netplay_dialog, + NetPlay::NetTraversalConfig{is_traversal, traversal_host, + traversal_port, traversal_port_alt})); if (!Settings::Instance().GetNetPlayServer()->is_connected) { diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp index c5edb9c0d97a..bdaa507e05cb 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp @@ -1037,6 +1037,11 @@ void NetPlayDialog::OnGolferChanged(const bool is_golfer, const std::string& gol DisplayMessage(tr("%1 is now golfing").arg(QString::fromStdString(golfer_name)), ""); } +void NetPlayDialog::OnTtlDetermined(u8 ttl) +{ + DisplayMessage(tr("Using TTL %1 for probe packet").arg(QString::number(ttl)), ""); +} + bool NetPlayDialog::IsRecording() { std::optional is_recording = RunOnObject(m_record_input_action, &QAction::isChecked); diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h index 84f9ff0fbe70..f053772a1876 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h @@ -71,6 +71,7 @@ class NetPlayDialog : public QDialog, public NetPlay::NetPlayUI void OnTraversalStateChanged(Common::TraversalClient::State state) override; void OnGameStartAborted() override; void OnGolferChanged(bool is_golfer, const std::string& golfer_name) override; + void OnTtlDetermined(u8 ttl) override; void OnIndexAdded(bool success, const std::string error) override; void OnIndexRefreshFailed(const std::string error) override;