Compare commits

..
10 Commits
7 changed files with 165 additions and 100 deletions
+5
View File
@@ -117,6 +117,11 @@
Port="48010"
Protocol="udp"
Name="Moonlight - RTSPU"/>
<fire:FirewallException Id="MdnsFwException"
Scope="any"
Port="5353"
Protocol="udp"
Name="Moonlight - mDNS"/>
</Component>
<Component Id="Shortcuts" Guid="*">
<Shortcut Id="StartMenuShortcut"
+63 -40
View File
@@ -39,6 +39,7 @@ bool PCPMapPort(PSOCKADDR_STORAGE localAddr, int localAddrLen, PSOCKADDR_STORAGE
#define POLLING_DELAY_SEC 120
#define PORT_MAPPING_DURATION_SEC 3600
#define UPNP_DISCOVERY_DELAY_MS 5000
#define GAA_INITIAL_SIZE 8192
static struct port_entry {
int proto;
@@ -233,10 +234,7 @@ bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const
bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
{
union {
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
PIP_ADAPTER_ADDRESSES addresses;
ULONG error;
ULONG length;
PIP_ADAPTER_ADDRESSES currentAdapter;
@@ -245,22 +243,34 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
inet_pton(AF_INET, lanAddressString, &targetAddress);
// Get a list of all interfaces with IPv4 addresses on the system
length = sizeof(buffer);
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
&addresses,
&length);
addresses = NULL;
length = GAA_INITIAL_SIZE;
do {
free(addresses);
addresses = (PIP_ADAPTER_ADDRESSES)malloc(length);
if (addresses == NULL) {
printf("malloc(%u) failed" NL, length);
return false;
}
// Get a list of all interfaces with IPv4 addresses on the system
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
addresses,
&length);
} while (error == ERROR_BUFFER_OVERFLOW);
if (error != ERROR_SUCCESS) {
printf("GetAdaptersAddresses() failed: %d" NL, error);
free(addresses);
return false;
}
currentAdapter = &addresses;
currentAdapter = addresses;
currentAddress = nullptr;
while (currentAdapter != nullptr) {
currentAddress = currentAdapter->FirstUnicastAddress;
@@ -271,6 +281,7 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
if (RtlEqualMemory(&currentAddrV4->sin_addr, &targetAddress, sizeof(targetAddress))) {
*prefixLength = currentAddress->OnLinkPrefixLength;
free(addresses);
return true;
}
@@ -281,6 +292,7 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
}
printf("No adapter found with IPv4 address: %s" NL, lanAddressString);
free(addresses);
return false;
}
@@ -521,14 +533,8 @@ bool IsGameStreamEnabled()
printf("RegQueryValueExA() failed: %d" NL, error);
return false;
}
else if (!enabled) {
printf("GameStream is OFF!" NL);
return false;
}
else {
printf("GameStream is ON!" NL);
return true;
}
return enabled != 0;
}
void UpdatePortMappingsForTarget(bool enable, char* targetAddressIP4, char* internalAddressIP4, char* upstreamAddressIP4)
@@ -840,26 +846,33 @@ void ResetLogFile(bool standaloneExe)
DWORD WINAPI GameStreamStateChangeThread(PVOID Context)
{
HKEY key;
DWORD err;
// We're watching this key that way we can still detect GameStream turning on
// if GFE wasn't even installed when our service started
DWORD err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\NVIDIA Corporation", 0, KEY_READ | KEY_WOW64_64KEY, &key);
if (err != ERROR_SUCCESS) {
printf("RegOpenKeyExA() failed: %d" NL, err);
return err;
}
do {
// We're watching this key that way we can still detect GameStream turning on
// if GFE wasn't even installed when our service started
do {
err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\NVIDIA Corporation", 0, KEY_READ | KEY_WOW64_64KEY, &key);
if (err != ERROR_SUCCESS) {
// Wait 10 seconds and try again
Sleep(10000);
}
} while (err != ERROR_SUCCESS);
// Notify the main thread when the GameStream state changes
bool lastGameStreamState = IsGameStreamEnabled();
while ((err = RegNotifyChangeKeyValue(key, true, REG_NOTIFY_CHANGE_LAST_SET, nullptr, false)) == ERROR_SUCCESS) {
bool currentGameStreamState = IsGameStreamEnabled();
if (lastGameStreamState != currentGameStreamState) {
SetEvent((HANDLE)Context);
// Notify the main thread when the GameStream state changes
bool lastGameStreamState = IsGameStreamEnabled();
while ((err = RegNotifyChangeKeyValue(key, true, REG_NOTIFY_CHANGE_LAST_SET, nullptr, false)) == ERROR_SUCCESS) {
bool currentGameStreamState = IsGameStreamEnabled();
if (lastGameStreamState != currentGameStreamState) {
SetEvent((HANDLE)Context);
}
lastGameStreamState = currentGameStreamState;
}
lastGameStreamState = currentGameStreamState;
}
printf("RegNotifyChangeKeyValue() failed: %d" NL, err);
// If the key is deleted (by DDU or similar), we will hit this code path and poll until it comes back.
RegCloseKey(key);
} while (err == ERROR_KEY_DELETED);
return err;
}
@@ -892,7 +905,17 @@ int Run(bool standaloneExe)
for (;;) {
ResetEvent(gsChangeEvent);
ResetEvent(ifaceChangeEvent);
UpdatePortMappings(IsGameStreamEnabled());
bool gameStreamEnabled = IsGameStreamEnabled();
if (gameStreamEnabled) {
printf("GameStream is ON!" NL);
}
else {
printf("GameStream is OFF!" NL);
}
UpdatePortMappings(gameStreamEnabled);
// Refresh when half the duration is expired or if an IP interface
// change event occurs.
+1 -1
View File
@@ -118,7 +118,7 @@ bool PCPMapPort(PSOCKADDR_STORAGE localAddr, int localAddrLen, PSOCKADDR_STORAGE
int bytesRead;
union {
PCP_MAP_RESPONSE hdr;
char buf[1024];
char buf[1100];
} resp;
int lifetime;
+67 -38
View File
@@ -29,6 +29,8 @@
#define LOOPBACK_SERVER_PORT_OFFSET -10000
#define GAA_INITIAL_SIZE 8192
static struct port_entry {
int proto;
int port;
@@ -405,7 +407,7 @@ enum PortTestStatus {
PortTestError,
PortTestUnknown
};
PortTestStatus TestPort(PSOCKADDR_STORAGE addr, int proto, int port, bool withServer, bool isLoopbackRelay)
PortTestStatus TestPort(PSOCKADDR_STORAGE addr, int proto, int port, bool withServer, bool isLoopbackRelay, bool mtuTest)
{
SOCKET clientSock = INVALID_SOCKET, serverSock = INVALID_SOCKET;
int err;
@@ -530,11 +532,14 @@ PortTestStatus TestPort(PSOCKADDR_STORAGE addr, int proto, int port, bool withSe
return err == 1 ? PortTestOk : PortTestError;
}
else {
const char testMsg[] = "moonlight-test";
// Video packets are up to 1040 bytes.
const char testMsg[1040] = "moonlight-test";
// Send several test packets to ensure a random lost packet doesn't make the test fail
for (int i = 0; i < 5; i++) {
err = sendto(clientSock, testMsg, sizeof(testMsg), 0, (struct sockaddr*)&sin6, addrLen);
// Send the full payload for MTU tests and the truncated payload for other tests.
err = sendto(clientSock, testMsg,
mtuTest ? sizeof(testMsg) : strlen(testMsg), 0, (struct sockaddr*)&sin6, addrLen);
if (err == SOCKET_ERROR) {
fprintf(LOG_OUT, "sendto() failed: %d\n", WSAGetLastError());
closesocket(clientSock);
@@ -696,7 +701,8 @@ bool TestAllPorts(PSOCKADDR_STORAGE addr, char* portMsg, int portMsgLen, bool is
fprintf(LOG_OUT, "Testing %s %d...",
k_Ports[i].proto == IPPROTO_TCP ? "TCP" : "UDP",
k_Ports[i].port);
status = TestPort(addr, k_Ports[i].proto, k_Ports[i].port, k_Ports[i].withServer, isLoopbackRelay);
status = TestPort(addr, k_Ports[i].proto, k_Ports[i].port,
k_Ports[i].withServer, isLoopbackRelay, k_Ports[i].port == 47998);
}
if (status != PortTestOk) {
@@ -864,31 +870,40 @@ bool FindLocalInterfaceIPAddress(int family, PSOCKADDR_STORAGE addr)
bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
{
union {
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
PIP_ADAPTER_ADDRESSES addresses;
ULONG error;
ULONG length;
PIP_ADAPTER_ADDRESSES currentAdapter;
PIP_ADAPTER_UNICAST_ADDRESS currentAddress;
// Get all IPv4 interfaces
length = sizeof(buffer);
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
&addresses,
&length);
addresses = NULL;
length = GAA_INITIAL_SIZE;
do {
free(addresses);
addresses = (PIP_ADAPTER_ADDRESSES)malloc(length);
if (addresses == NULL) {
fprintf(LOG_OUT, "malloc(%u) failed\n", length);
return false;
}
// Get all IPv4 interfaces
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
addresses,
&length);
} while (error == ERROR_BUFFER_OVERFLOW);
if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error);
free(addresses);
return false;
}
currentAdapter = &addresses;
currentAdapter = addresses;
while (currentAdapter != NULL) {
// Look for ones that correspond to a ZeroTier device
if (wcsstr(currentAdapter->Description, L"ZeroTier")) {
@@ -897,6 +912,7 @@ bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
while (currentAddress != NULL) {
if (currentAddress->Address.lpSockaddr->sa_family == AF_INET) {
RtlCopyMemory(addr, currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength);
free(addresses);
return true;
}
@@ -907,15 +923,13 @@ bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
currentAdapter = currentAdapter->Next;
}
free(addresses);
return false;
}
bool FindDuplicateDefaultInterfaces(void)
{
union {
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
PIP_ADAPTER_ADDRESSES addresses;
ULONG error;
ULONG length;
MIB_IPFORWARDROW defaultRoute;
@@ -928,24 +942,36 @@ bool FindDuplicateDefaultInterfaces(void)
return false;
}
// Get all IPv4 interfaces
length = sizeof(buffer);
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_UNICAST |
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_INCLUDE_GATEWAYS |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
&addresses,
&length);
addresses = NULL;
length = GAA_INITIAL_SIZE;
do {
free(addresses);
addresses = (PIP_ADAPTER_ADDRESSES)malloc(length);
if (addresses == NULL) {
fprintf(LOG_OUT, "malloc(%u) failed\n", length);
return false;
}
// Get all IPv4 interfaces
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_UNICAST |
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_INCLUDE_GATEWAYS |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
addresses,
&length);
} while (error == ERROR_BUFFER_OVERFLOW);
if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error);
free(addresses);
return false;
}
currentAdapter = &addresses;
currentAdapter = addresses;
while (currentAdapter != NULL) {
if (currentAdapter->OperStatus == IfOperStatusUp &&
currentAdapter->FirstGatewayAddress != NULL &&
@@ -958,6 +984,7 @@ bool FindDuplicateDefaultInterfaces(void)
currentAdapter = currentAdapter->Next;
}
free(addresses);
return matchingInterfaces > 1;
}
@@ -1441,8 +1468,10 @@ int main(int argc, char* argv[])
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);
"Do not uninstall the Moonlight Internet Hosting Tool, unless you no longer want to stream over the Internet. It needs to remain installed on your PC to maintain the port forwarding entries on your router.\n\n"
"For the easiest setup, you can simply pair Moonlight to your gaming PC while they are both on the same network and Internet streaming will work automatically.\n\n"
"If your client is not connected to the same network as your gaming PC, you can type the following address into Moonlight's Add PC dialog: %s",
wanAddrStr);
DisplayMessage(msgBuf, nullptr, MpInfo);
return 0;
}
+26 -18
View File
@@ -100,29 +100,37 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
}
}
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
for (;;) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
int selectRes = select(0, &fds, nullptr, nullptr, &tv);
if (selectRes == 0) {
// Timeout - continue looping
continue;
int selectRes = select(0, &fds, nullptr, nullptr, &tv);
if (selectRes == 0) {
// Timeout - break to the enclosing loop
break;
}
else if (selectRes == SOCKET_ERROR) {
fprintf(LOG_OUT, "select() failed: %d\n", WSAGetLastError());
goto Exit;
}
// recvfrom() will return WSAECONNRESET if the socket has received an ICMP Port Unreachable
// message from one of the IP addresses we've attempted communication with. The socket is still
// operable (and may even contain queued messages to receive). We should ignore that error and
// continue reading, otherwise exit the loop.
bytesRead = recvfrom(sock, resp.buf, sizeof(resp.buf), 0, NULL, NULL);
if (bytesRead != SOCKET_ERROR || WSAGetLastError() != WSAECONNRESET) {
goto RecvDone;
}
}
else if (selectRes == SOCKET_ERROR) {
fprintf(LOG_OUT, "select() failed: %d\n", WSAGetLastError());
goto Exit;
}
// Error handling is below
bytesRead = recvfrom(sock, resp.buf, sizeof(resp.buf), 0, NULL, NULL);
break;
}
RecvDone:
if (bytesRead == 0) {
fprintf(LOG_OUT, "No response from STUN server\n");
goto Exit;
+2 -2
View File
@@ -1,7 +1,7 @@
#pragma once
#define VER_VERSION 5,3,1,0
#define VER_VERSION_STR "5.3.1.0"
#define VER_VERSION 5,4,0,0
#define VER_VERSION_STR "5.4.0.0"
#define VER_COMPANYNAME_STR "Moonlight Game Streaming Project"
#define VER_PRODUCTNAME_STR "Moonlight Internet Hosting Tool"