From a9bf4ffd707257b9e956b766a07e809045add9a5 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 18 Jul 2020 16:13:56 -0700 Subject: [PATCH] Always run the loopback server test It appears that in rare cases NAT reflection can work where real WAN traffic fails --- mist/mist.cpp | 151 +++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 82 deletions(-) diff --git a/mist/mist.cpp b/mist/mist.cpp index 2afed89..c85e7fb 100644 --- a/mist/mist.cpp +++ b/mist/mist.cpp @@ -1283,101 +1283,88 @@ int main(int argc, char* argv[]) // Go directly to the relay check if we have only IPv6 connectivity igdDisconnected = false; locallyReportedWanAddr = {}; - goto RelayCheck; } - // Try to connect via WAN IPv4 address - fprintf(LOG_OUT, "Testing GameStream ports via STUN-reported WAN address\n"); - if (!TestAllPorts(&ss, portMsgBuf, sizeof(portMsgBuf), false, true)) { - RelayCheck: - struct addrinfo hint = {}; - struct addrinfo* result; + struct addrinfo hint = {}; + struct addrinfo* result; - // We can get here if the router doesn't support NAT reflection. - // We'll need to call out to our loopback server to get a second opinion. + hint.ai_family = AF_UNSPEC; + hint.ai_flags = AI_ADDRCONFIG; + err = getaddrinfo("loopback.moonlight-stream.org", NULL, &hint, &result); + if (err != 0 || result == NULL) { + fprintf(LOG_OUT, "getaddrinfo() failed: %d\n", err); + } + else { + bool allPortsFailedOnV4 = true; - hint.ai_family = AF_UNSPEC; - hint.ai_flags = AI_ADDRCONFIG; - err = getaddrinfo("loopback.moonlight-stream.org", NULL, &hint, &result); - if (err != 0 || result == NULL) { - fprintf(LOG_OUT, "getaddrinfo() failed: %d\n", err); + // First try the relay server over IPv4. If this passes, it's considered a full success + fprintf(LOG_OUT, "Testing GameStream ports via IPv4 loopback server\n"); + for (struct addrinfo* current = result; current != NULL; current = current->ai_next) { + if (current->ai_family == AF_INET) { + fprintf(CONSOLE_OUT, "Testing GameStream connectivity over the Internet using a relay server...\n"); + if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, portMsgBuf, sizeof(portMsgBuf), true, true, &allPortsFailedOnV4)) { + freeaddrinfo(result); + snprintf(msgBuf, sizeof(msgBuf), "This PC is ready to host over the Internet!\n\n" + "For the easiest setup, you should pair Moonlight to your gaming PC from your home network before trying to stream over the Internet.\n\n" + "If you can't, you can type the following address into Moonlight's Add PC dialog: %s", wanAddrStr); + DisplayMessage(msgBuf, nullptr, MpInfo); + return 0; + } + } } - else { - bool allPortsFailedOnV4 = true; - // First try the relay server over IPv4. If this passes, it's considered a full success - fprintf(LOG_OUT, "Testing GameStream ports via IPv4 loopback server\n"); - for (struct addrinfo* current = result; current != NULL; current = current->ai_next) { - if (current->ai_family == AF_INET) { - fprintf(CONSOLE_OUT, "Testing GameStream connectivity over the Internet using a relay server...\n"); - if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, portMsgBuf, sizeof(portMsgBuf), true, true, &allPortsFailedOnV4)) { + // If that fails, try the relay server over IPv6. If this passes, it will be a partial success + fprintf(LOG_OUT, "Testing GameStream ports via IPv6 loopback server\n"); + for (struct addrinfo* current = result; current != NULL; current = current->ai_next) { + if (current->ai_family == AF_INET6) { + fprintf(CONSOLE_OUT, "Testing GameStream connectivity over the Internet using an IPv6 relay server...\n"); + // Pass the portMsgBuf only if we've detected an IPv6-only setup. Otherwise, we want to preserve + // the failing ports from the IPv4 to display in the error dialog. + if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, + ss.ss_family == AF_INET6 ? portMsgBuf : NULL, + ss.ss_family == AF_INET6 ? sizeof(portMsgBuf) : 0, true, true)) { + // We will terminate the test at the IPv6 limited connectivity warning in the following cases: + // 1) Double-NAT/CGN - indicates the connection is fundamentally limited to IPv6 for end-to-end connectivity + // 2) IPv6-only - indicates the connection is fundamentally limited to IPv6 for all connectivity + // 3) All ports failed the test with our IPv4 relay - This is one final heuristic to weed out IPv4 misconfigurations. If we have some ports open, + // it clearly indicates IPv4 support is possible, just currently misconfigured. + // + // Our last (implicit) heuristic is that we actually managed to establish an IPv6 connection. This means that there was either + // no IPv6 firewall (hopefully not) or that we were able to talk to a PCP/IGDv6 gateway to allow us through. Hopefully if we have + // a gateway that is unresponsive to UPnP/NAT-PMP, we wouldn't even be able to establish this connection so we would inherently fall + // to the checks below for IPv4 issues. + if (IsDoubleNAT(&locallyReportedWanAddr) || igdDisconnected || IsPossibleCGN(&locallyReportedWanAddr) || ss.ss_family == AF_INET6 || allPortsFailedOnV4) { + snprintf(msgBuf, sizeof(msgBuf), "This PC has limited connectivity for Internet hosting. It will work only for clients on certain networks.\n\n" + "If you want to try streaming with this configuration, you must pair Moonlight to your gaming PC from your home network before trying to stream over the Internet.\n\n" + "To get full connectivity, please contact your ISP and ask for a \"public IP address\" which they may offer for free upon request. For more information and workarounds, click the Help button."); + DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#limited-connectivity-for-hosting-error", MpWarn); freeaddrinfo(result); - goto AllTestsPassed; + return 0; } } } - - // If that fails, try the relay server over IPv6. If this passes, it will be a partial success - fprintf(LOG_OUT, "Testing GameStream ports via IPv6 loopback server\n"); - for (struct addrinfo* current = result; current != NULL; current = current->ai_next) { - if (current->ai_family == AF_INET6) { - fprintf(CONSOLE_OUT, "Testing GameStream connectivity over the Internet using an IPv6 relay server...\n"); - // Pass the portMsgBuf only if we've detected an IPv6-only setup. Otherwise, we want to preserve - // the failing ports from the IPv4 to display in the error dialog. - if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, - ss.ss_family == AF_INET6 ? portMsgBuf : NULL, - ss.ss_family == AF_INET6 ? sizeof(portMsgBuf) : 0, true, true)) { - // We will terminate the test at the IPv6 limited connectivity warning in the following cases: - // 1) Double-NAT/CGN - indicates the connection is fundamentally limited to IPv6 for end-to-end connectivity - // 2) IPv6-only - indicates the connection is fundamentally limited to IPv6 for all connectivity - // 3) All ports failed the test with our IPv4 relay - This is one final heuristic to weed out IPv4 misconfigurations. If we have some ports open, - // it clearly indicates IPv4 support is possible, just currently misconfigured. - // - // Our last (implicit) heuristic is that we actually managed to establish an IPv6 connection. This means that there was either - // no IPv6 firewall (hopefully not) or that we were able to talk to a PCP/IGDv6 gateway to allow us through. Hopefully if we have - // a gateway that is unresponsive to UPnP/NAT-PMP, we wouldn't even be able to establish this connection so we would inherently fall - // to the checks below for IPv4 issues. - if (IsDoubleNAT(&locallyReportedWanAddr) || igdDisconnected || IsPossibleCGN(&locallyReportedWanAddr) || ss.ss_family == AF_INET6 || allPortsFailedOnV4) { - snprintf(msgBuf, sizeof(msgBuf), "This PC has limited connectivity for Internet hosting. It will work only for clients on certain networks.\n\n" - "If you want to try streaming with this configuration, you must pair Moonlight to your gaming PC from your home network before trying to stream over the Internet.\n\n" - "To get full connectivity, please contact your ISP and ask for a \"public IP address\" which they may offer for free upon request. For more information and workarounds, click the Help button."); - DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#limited-connectivity-for-hosting-error", MpWarn); - freeaddrinfo(result); - return 0; - } - } - } - } - - freeaddrinfo(result); } - // Many UPnP devices report IGD disconnected when double-NATed. If it was really offline, - // we probably would not have even gotten past STUN. - if (IsDoubleNAT(&locallyReportedWanAddr) || igdDisconnected) { - snprintf(msgBuf, sizeof(msgBuf), "Your router appears be connected to the Internet through another router. Click the Help button for guidance on fixing this issue."); - DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#connected-through-another-router-error"); - } - else if (IsPossibleCGN(&locallyReportedWanAddr)) { - snprintf(msgBuf, sizeof(msgBuf), "Your ISP is running a Carrier-Grade NAT that is preventing you from hosting services like Moonlight on the Internet.\n\n" - "Ask your ISP for a \"public IP address\" which they may offer for free upon request. For more information and workarounds, click the Help button."); - DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#carrier-grade-nat-error"); - } - else { - snprintf(msgBuf, sizeof(msgBuf), "Internet GameStream connectivity check failed.\n\n" - "First, try restarting your router. If that fails, check that UPnP is enabled in your router settings. For more information and workarounds, click the Help button.\n\n" - "The following ports were not forwarded properly:\n%s", portMsgBuf); - DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#internet-gamestream-connectivity-check-error"); - } - - return -1; + freeaddrinfo(result); } -AllTestsPassed: - snprintf(msgBuf, sizeof(msgBuf), "This PC is ready to host over the Internet!\n\n" - "For the easiest setup, you should pair Moonlight to your gaming PC from your home network before trying to stream over the Internet.\n\n" - "If you can't, you can type the following address into Moonlight's Add PC dialog: %s", wanAddrStr); - DisplayMessage(msgBuf, nullptr, MpInfo); + // Many UPnP devices report IGD disconnected when double-NATed. If it was really offline, + // we probably would not have even gotten past STUN. + if (IsDoubleNAT(&locallyReportedWanAddr) || igdDisconnected) { + snprintf(msgBuf, sizeof(msgBuf), "Your router appears be connected to the Internet through another router. Click the Help button for guidance on fixing this issue."); + DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#connected-through-another-router-error"); + } + else if (IsPossibleCGN(&locallyReportedWanAddr)) { + snprintf(msgBuf, sizeof(msgBuf), "Your ISP is running a Carrier-Grade NAT that is preventing you from hosting services like Moonlight on the Internet.\n\n" + "Ask your ISP for a \"public IP address\" which they may offer for free upon request. For more information and workarounds, click the Help button."); + DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#carrier-grade-nat-error"); + } + else { + snprintf(msgBuf, sizeof(msgBuf), "Internet GameStream connectivity check failed.\n\n" + "First, try restarting your router. If that fails, check that UPnP is enabled in your router settings. For more information and workarounds, click the Help button.\n\n" + "The following ports were not forwarded properly:\n%s", portMsgBuf); + DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Internet-Streaming-Errors#internet-gamestream-connectivity-check-error"); + } - return 0; + return -1; } \ No newline at end of file