mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-04-23 16:39:09 +00:00
Rewrite STUN code to avoid requiring TCP and use multiple servers in parallel
This commit is contained in:
@@ -38,9 +38,9 @@ typedef struct _STUN_MESSAGE {
|
|||||||
int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, unsigned int* wanAddr)
|
int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, unsigned int* wanAddr)
|
||||||
{
|
{
|
||||||
SOCKET sock;
|
SOCKET sock;
|
||||||
struct sockaddr_storage stunAddr;
|
struct addrinfo* stunAddrs;
|
||||||
struct sockaddr_in* stunAddrIn;
|
struct addrinfo hints;
|
||||||
SOCKADDR_LEN stunAddrLen;
|
char stunPortStr[6];
|
||||||
int err;
|
int err;
|
||||||
STUN_MESSAGE reqMsg;
|
STUN_MESSAGE reqMsg;
|
||||||
int i;
|
int i;
|
||||||
@@ -58,13 +58,21 @@ int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, un
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = resolveHostName(stunServer, AF_INET, 3478, &stunAddr, &stunAddrLen);
|
memset(&hints, 0, sizeof(hints));
|
||||||
if (err != 0) {
|
hints.ai_family = AF_INET;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
|
hints.ai_flags = AI_ADDRCONFIG;
|
||||||
|
|
||||||
|
sprintf(stunPortStr, "%u", stunPort);
|
||||||
|
err = getaddrinfo(stunServer, stunPortStr, &hints, &stunAddrs);
|
||||||
|
if (err != 0 || stunAddrs == NULL) {
|
||||||
Limelog("Failed to resolve STUN server: %d\n", err);
|
Limelog("Failed to resolve STUN server: %d\n", err);
|
||||||
|
stunAddrs = NULL;
|
||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock = bindUdpSocket(AF_INET, 2048);
|
sock = bindUdpSocket(hints.ai_family, 2048);
|
||||||
if (sock == INVALID_SOCKET) {
|
if (sock == INVALID_SOCKET) {
|
||||||
err = LastSocketFail();
|
err = LastSocketFail();
|
||||||
Limelog("Failed to connect to STUN server: %d\n", err);
|
Limelog("Failed to connect to STUN server: %d\n", err);
|
||||||
@@ -79,29 +87,29 @@ int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, un
|
|||||||
}
|
}
|
||||||
|
|
||||||
bytesRead = SOCKET_ERROR;
|
bytesRead = SOCKET_ERROR;
|
||||||
for (i = 0; i < STUN_RECV_TIMEOUT_SEC * 1000 / UDP_RECV_POLL_TIMEOUT_MS; i++) {
|
for (i = 0; i < STUN_RECV_TIMEOUT_SEC * 1000 / UDP_RECV_POLL_TIMEOUT_MS && bytesRead <= 0; i++) {
|
||||||
// Retransmit the request every second until the timeout elapses
|
// Retransmit the request every second until the timeout elapses or we get a response
|
||||||
if (i % (1000 / UDP_RECV_POLL_TIMEOUT_MS) == 0) {
|
if (i % (1000 / UDP_RECV_POLL_TIMEOUT_MS) == 0) {
|
||||||
stunAddrIn = (struct sockaddr_in*)&stunAddr;
|
struct addrinfo *current;
|
||||||
stunAddrIn->sin_port = htons(stunPort);
|
|
||||||
err = (int)sendto(sock, (char *)&reqMsg, sizeof(reqMsg), 0,
|
// Send a request to each resolved address but stop if we get a response
|
||||||
(struct sockaddr*)stunAddrIn, stunAddrLen);
|
for (current = stunAddrs; current != NULL && bytesRead <= 0; current = current->ai_next) {
|
||||||
if (err == SOCKET_ERROR) {
|
err = (int)sendto(sock, (char *)&reqMsg, sizeof(reqMsg), 0, current->ai_addr, current->ai_addrlen);
|
||||||
err = LastSocketFail();
|
if (err == SOCKET_ERROR) {
|
||||||
Limelog("Failed to send STUN binding request: %d\n", err);
|
err = LastSocketFail();
|
||||||
closeSocket(sock);
|
Limelog("Failed to send STUN binding request: %d\n", err);
|
||||||
goto Exit;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait UDP_RECV_POLL_TIMEOUT_MS before moving on to the next server to
|
||||||
|
// avoid having to spam the other STUN servers if we find a working one.
|
||||||
|
bytesRead = recvUdpSocket(sock, resp.buf, sizeof(resp.buf), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// This waits in UDP_RECV_POLL_TIMEOUT_MS increments
|
// This waits in UDP_RECV_POLL_TIMEOUT_MS increments
|
||||||
bytesRead = recvUdpSocket(sock, resp.buf, sizeof(resp.buf), 1);
|
bytesRead = recvUdpSocket(sock, resp.buf, sizeof(resp.buf), 1);
|
||||||
if (bytesRead == 0) {
|
|
||||||
// Timeout - continue looping
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closeSocket(sock);
|
closeSocket(sock);
|
||||||
@@ -176,6 +184,10 @@ int LiFindExternalAddressIP4(const char* stunServer, unsigned short stunPort, un
|
|||||||
err = -6;
|
err = -6;
|
||||||
|
|
||||||
Exit:
|
Exit:
|
||||||
|
if (stunAddrs != NULL) {
|
||||||
|
freeaddrinfo(stunAddrs);
|
||||||
|
}
|
||||||
|
|
||||||
cleanupPlatformSockets();
|
cleanupPlatformSockets();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user