mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2025-07-01 07:15:39 +00:00
Use higher packet size for remote streaming over end-to-end IPv6 connection
The IPv6 spec guarantees a minimum of 1280 byte MTUs
This commit is contained in:
parent
5e75d4e1f1
commit
c245fe599d
@ -386,18 +386,28 @@ int LiStartConnection(PSERVER_INFORMATION serverInfo, PSTREAM_CONFIGURATION stre
|
||||
// now that we have resolved the target address and impose the video packet
|
||||
// size cap if required.
|
||||
if (StreamConfig.streamingRemotely == STREAM_CFG_AUTO) {
|
||||
if (isPrivateNetworkAddress(&RemoteAddr)) {
|
||||
bool isNat64 = isNat64SynthesizedAddress(&RemoteAddr);
|
||||
|
||||
// It's possible to have a NAT64 prefix on a ULA or other private range,
|
||||
// so we must exclude NAT64 addresses from our local address checks.
|
||||
if (!isNat64 && isPrivateNetworkAddress(&RemoteAddr)) {
|
||||
StreamConfig.streamingRemotely = STREAM_CFG_LOCAL;
|
||||
}
|
||||
else {
|
||||
StreamConfig.streamingRemotely = STREAM_CFG_REMOTE;
|
||||
|
||||
if (StreamConfig.packetSize > 1024) {
|
||||
// Cap packet size at 1024 for remote streaming to avoid
|
||||
// MTU problems and fragmentation.
|
||||
Limelog("Packet size capped at 1KB for remote streaming\n");
|
||||
if (RemoteAddr.ss_family == AF_INET || isNat64) {
|
||||
// Cap packet size at 1024 for remote IPv4 streaming to avoid fragmentation.
|
||||
Limelog("Packet size capped at 1024 bytes for remote IPv4 streaming\n");
|
||||
StreamConfig.packetSize = 1024;
|
||||
}
|
||||
else {
|
||||
// IPv6 guarantees a minimum MTU of 1280 before fragmentation, so use a higher
|
||||
// packet size cap for remote IPv6 streaming (when not using NAT64 which isn't
|
||||
// end-to-end IPv6 traffic).
|
||||
Limelog("Packet size capped at 1184 bytes for remote IPv6 streaming\n");
|
||||
StreamConfig.packetSize = 1184;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,6 +716,119 @@ bool isPrivateNetworkAddress(struct sockaddr_storage* address) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNat64SynthesizedAddress(struct sockaddr_storage* address) {
|
||||
#ifdef AF_INET6
|
||||
if (address->ss_family == AF_INET6) {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)address;
|
||||
struct addrinfo hints, *res, *currentAddr;
|
||||
int err;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_flags = AI_ADDRCONFIG;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
err = getaddrinfo("ipv4only.arpa.", NULL, &hints, &res);
|
||||
if (err != 0) {
|
||||
Limelog("Client is not running in NAT64 environment (%d)\n", err);
|
||||
return false;
|
||||
}
|
||||
else if (res == NULL) {
|
||||
Limelog("getaddrinfo(ipv4only.arpa.) returned success without addresses\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (currentAddr = res; currentAddr != NULL; currentAddr = currentAddr->ai_next) {
|
||||
struct sockaddr_in6* candidate6 = (struct sockaddr_in6*)currentAddr->ai_addr;
|
||||
static const unsigned char wellKnownAddresses[2][4] = {
|
||||
{ 0xC0, 0x00, 0x00, 0xAA }, // 192.0.0.170
|
||||
{ 0xC0, 0x00, 0x00, 0xAB }, // 192.0.0.171
|
||||
};
|
||||
|
||||
if (candidate6->sin6_family != AF_INET6) {
|
||||
// This shouldn't be possible but check anyway
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int foundCount = 0;
|
||||
int prefixLen = 0;
|
||||
int suffixStart = 0;
|
||||
|
||||
// Search for each well-known IPv4 address at all locations specified by
|
||||
// https://datatracker.ietf.org/doc/html/rfc6052#section-2.2
|
||||
if (memcmp(&candidate6->sin6_addr.s6_addr[4], wellKnownAddresses[i], 4) == 0) {
|
||||
foundCount++;
|
||||
|
||||
prefixLen = 4;
|
||||
suffixStart = 9;
|
||||
}
|
||||
if (memcmp(&candidate6->sin6_addr.s6_addr[5], &wellKnownAddresses[i][0], 3) == 0 &&
|
||||
memcmp(&candidate6->sin6_addr.s6_addr[9], &wellKnownAddresses[i][3], 1) == 0) {
|
||||
foundCount++;
|
||||
|
||||
prefixLen = 5;
|
||||
suffixStart = 10;
|
||||
}
|
||||
if (memcmp(&candidate6->sin6_addr.s6_addr[6], &wellKnownAddresses[i][0], 2) == 0 &&
|
||||
memcmp(&candidate6->sin6_addr.s6_addr[9], &wellKnownAddresses[i][2], 2) == 0) {
|
||||
foundCount++;
|
||||
|
||||
prefixLen = 6;
|
||||
suffixStart = 11;
|
||||
}
|
||||
if (memcmp(&candidate6->sin6_addr.s6_addr[7], &wellKnownAddresses[i][0], 1) == 0 &&
|
||||
memcmp(&candidate6->sin6_addr.s6_addr[9], &wellKnownAddresses[i][1], 3) == 0) {
|
||||
foundCount++;
|
||||
|
||||
prefixLen = 7;
|
||||
suffixStart = 12;
|
||||
}
|
||||
if (memcmp(&candidate6->sin6_addr.s6_addr[9], &wellKnownAddresses[i], 4) == 0) {
|
||||
foundCount++;
|
||||
|
||||
prefixLen = 8;
|
||||
suffixStart = 13;
|
||||
}
|
||||
if (memcmp(&candidate6->sin6_addr.s6_addr[12], &wellKnownAddresses[i], 4) == 0) {
|
||||
foundCount++;
|
||||
|
||||
prefixLen = 12;
|
||||
suffixStart = 16;
|
||||
}
|
||||
|
||||
// We must find the well-known address exactly once. If we find it zero or multiple
|
||||
// times, we must try the second well-known address or other AAAA records.
|
||||
if (foundCount != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have a valid NAT64 address identified, so we know we're running in an NAT64 environment.
|
||||
//
|
||||
// Now we must check to see if the address we resolved for the remote host actually falls
|
||||
// within the NAT64 range to see if we must restrict ourselves to the IPv4 MTU.
|
||||
if (memcmp(&sin6->sin6_addr.s6_addr[0], &candidate6->sin6_addr.s6_addr[0], prefixLen) == 0 &&
|
||||
(suffixStart == 16 || memcmp(&sin6->sin6_addr.s6_addr[suffixStart],
|
||||
&candidate6->sin6_addr.s6_addr[suffixStart],
|
||||
16 - suffixStart) == 0)) {
|
||||
freeaddrinfo(res);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// This one didn't match, so let's break out of the loop and try the next AAAA record.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable platform-specific low latency options (best-effort)
|
||||
void enterLowLatencyMode(void) {
|
||||
#if defined(LC_WINDOWS_DESKTOP)
|
||||
|
@ -110,6 +110,7 @@ void shutdownTcpSocket(SOCKET s);
|
||||
int setNonFatalRecvTimeoutMs(SOCKET s, int timeoutMs);
|
||||
void closeSocket(SOCKET s);
|
||||
bool isPrivateNetworkAddress(struct sockaddr_storage* address);
|
||||
bool isNat64SynthesizedAddress(struct sockaddr_storage* address);
|
||||
int pollSockets(struct pollfd* pollFds, int pollFdsCount, int timeoutMs);
|
||||
bool isSocketReadable(SOCKET s);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user