diff --git a/src/Connection.c b/src/Connection.c index 2dc3cc3..65fe4c1 100644 --- a/src/Connection.c +++ b/src/Connection.c @@ -213,7 +213,7 @@ int LiStartConnection(PSERVER_INFORMATION serverInfo, PSTREAM_CONFIGURATION stre Limelog("Resolving host name..."); ListenerCallbacks.stageStarting(STAGE_NAME_RESOLUTION); - err = resolveHostName(serverInfo->address, &RemoteAddr, &RemoteAddrLen); + err = resolveHostName(serverInfo->address, AF_UNSPEC, 47984, &RemoteAddr, &RemoteAddrLen); if (err != 0) { Limelog("failed: %d\n", err); ListenerCallbacks.stageFailed(STAGE_NAME_RESOLUTION, err); diff --git a/src/PlatformSockets.c b/src/PlatformSockets.c index d25d7ae..67e7c7f 100644 --- a/src/PlatformSockets.c +++ b/src/PlatformSockets.c @@ -1,6 +1,8 @@ #include "PlatformSockets.h" #include "Limelight-internal.h" +#define TEST_PORT_TIMEOUT_SEC 3 + #define RCV_BUFFER_SIZE_MIN 32767 #define RCV_BUFFER_SIZE_STEP 16384 @@ -282,43 +284,53 @@ int enableNoDelay(SOCKET s) { return 0; } -int resolveHostName(const char* host, struct sockaddr_storage* addr, SOCKADDR_LEN* addrLen) +int resolveHostName(const char* host, int family, int tcpTestPort, struct sockaddr_storage* addr, SOCKADDR_LEN* addrLen) { #ifndef __vita__ - struct addrinfo hints, *res; + struct addrinfo hints, *res, *currentAddr; int err; - // We must first try IPv4-only because GFE doesn't listen on IPv6, - // so we'll only want to use an IPv6 address if it's the only address we have. - // For NAT64 networks, the IPv4 address resolution will fail but the IPv6 address - // will give us working connectivity to the host. All other networks will use IPv4 - // addresses. memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; + hints.ai_family = family; hints.ai_flags = AI_ADDRCONFIG; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; err = getaddrinfo(host, NULL, &hints, &res); - if (err != 0 || res == NULL) { - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_ADDRCONFIG; - err = getaddrinfo(host, NULL, &hints, &res); - if (err != 0) { - Limelog("getaddrinfo() failed: %d\n", err); - return err; - } - - if (res == NULL) { - Limelog("getaddrinfo() returned success without addresses\n"); - return -1; + if (err != 0) { + Limelog("getaddrinfo(%s) failed: %d\n", host, err); + return err; + } + else if (res == NULL) { + Limelog("getaddrinfo(%s) returned success without addresses\n", host); + return -1; + } + + for (currentAddr = res; currentAddr != NULL; currentAddr = currentAddr->ai_next) { + // Use the test port to ensure this address is working + if (tcpTestPort != 0) { + SOCKET testSocket = connectTcpSocket((struct sockaddr_storage*)currentAddr->ai_addr, + currentAddr->ai_addrlen, + tcpTestPort, + TEST_PORT_TIMEOUT_SEC); + if (testSocket == INVALID_SOCKET) { + // Try the next address + continue; + } + else { + closeSocket(testSocket); + } } + + memcpy(addr, currentAddr->ai_addr, currentAddr->ai_addrlen); + *addrLen = currentAddr->ai_addrlen; + + freeaddrinfo(res); + return 0; } - // Use the first address in the list - memcpy(addr, res->ai_addr, res->ai_addrlen); - *addrLen = res->ai_addrlen; - + Limelog("No working addresses found for host: %s\n", host); freeaddrinfo(res); - return 0; + return -1; #else struct hostent *phost = gethostbyname(host); if (!phost) { diff --git a/src/PlatformSockets.h b/src/PlatformSockets.h index 5821727..e9176d1 100644 --- a/src/PlatformSockets.h +++ b/src/PlatformSockets.h @@ -72,7 +72,7 @@ typedef socklen_t SOCKADDR_LEN; #define URLSAFESTRING_LEN (INET6_ADDRSTRLEN+2) void addrToUrlSafeString(struct sockaddr_storage* addr, char* string); -int resolveHostName(const char* host, struct sockaddr_storage* addr, SOCKADDR_LEN* addrLen); +int resolveHostName(const char* host, int family, int tcpTestPort, struct sockaddr_storage* addr, SOCKADDR_LEN* addrLen); SOCKET connectTcpSocket(struct sockaddr_storage* dstaddr, SOCKADDR_LEN addrlen, unsigned short port, int timeoutSec); SOCKET bindUdpSocket(int addrfamily, int bufferSize); int enableNoDelay(SOCKET s); diff --git a/src/SimpleStun.c b/src/SimpleStun.c index d087dbc..f4b256d 100644 --- a/src/SimpleStun.c +++ b/src/SimpleStun.c @@ -52,18 +52,12 @@ int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, un char buf[1024]; } resp; - err = resolveHostName(stunServer, &stunAddr, &stunAddrLen); + err = resolveHostName(stunServer, AF_INET, 0, &stunAddr, &stunAddrLen); if (err != 0) { Limelog("Failed to resolve STUN server: %d\n", err); return err; } - // We must use IPv4 to talk to the STUN server to get our IPv4 address back - if (stunAddr.ss_family != AF_INET) { - Limelog("STUN server was not reachable over IPv4\n"); - return -1; - } - sock = bindUdpSocket(AF_INET, 2048); if (sock == INVALID_SOCKET) { err = LastSocketFail();