Compare commits

...

5 Commits

Author SHA1 Message Date
Cameron Gutman
e0db902f7d Fix crash when toggling GameStream on 2023-08-26 00:42:27 -05:00
Cameron Gutman
4c94ecfce1 Version 2.6.0 2023-08-25 23:42:01 -05:00
Cameron Gutman
fccf9e7191 Only operate the relay and maintain the pinholes when GameStream is enabled
Sunshine will soon have native IPv6 support, so we need to stay out of its way.
2023-08-25 23:39:30 -05:00
Cameron Gutman
2793d3d1d2 Update VCRedist 2023-05-27 22:27:27 -05:00
Cameron Gutman
3ba36a58d7 Update VCRedist 2022-08-09 20:28:25 -05:00
3 changed files with 160 additions and 29 deletions

View File

@ -311,7 +311,7 @@ TcpListenerThreadProc(LPVOID Context)
return 0;
}
int StartTcpRelay(unsigned short Port)
int StartTcpRelay(unsigned short Port, SOCKET* Listener)
{
SOCKET listeningSocket;
SOCKADDR_IN6 addr6;
@ -348,7 +348,7 @@ int StartTcpRelay(unsigned short Port)
return ERROR_OUTOFMEMORY;
}
tuple->listener = listeningSocket;
tuple->listener = *Listener = listeningSocket;
tuple->port = Port;
thread = CreateThread(NULL, 0, TcpListenerThreadProc, tuple, 0, NULL);
@ -507,7 +507,7 @@ UdpRelayThreadProc(LPVOID Context)
return 0;
}
int StartUdpRelay(unsigned short Port)
int StartUdpRelay(unsigned short Port, SOCKET* Ipv4Socket, SOCKET* Ipv6Socket)
{
SOCKET ipv6Socket;
SOCKET ipv4Socket;
@ -572,8 +572,8 @@ int StartUdpRelay(unsigned short Port)
return ERROR_OUTOFMEMORY;
}
tuple->ipv4Socket = ipv4Socket;
tuple->ipv6Socket = ipv6Socket;
tuple->ipv4Socket = *Ipv4Socket = ipv4Socket;
tuple->ipv6Socket = *Ipv6Socket = ipv6Socket;
tuple->port = Port;
thread = CreateThread(NULL, 0, UdpRelayThreadProc, tuple, 0, NULL);
@ -869,6 +869,83 @@ void ResetLogFile(bool standaloneExe)
printf("The current UTC time is: %s\n", timeString);
}
bool IsGameStreamEnabled()
{
DWORD error;
DWORD enabled;
DWORD len;
HKEY key;
error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\NVIDIA Corporation\\NvStream", 0, KEY_READ | KEY_WOW64_64KEY, &key);
if (error != ERROR_SUCCESS) {
printf("RegOpenKeyEx() failed: %d\n", error);
return false;
}
len = sizeof(enabled);
error = RegQueryValueExA(key, "EnableStreaming", nullptr, nullptr, (LPBYTE)&enabled, &len);
RegCloseKey(key);
if (error != ERROR_SUCCESS) {
printf("RegQueryValueExA() failed: %d\n", error);
return false;
}
return enabled != 0;
}
DWORD WINAPI GameStreamStateChangeThread(PVOID Context)
{
HKEY key;
DWORD 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_NAME | REG_NOTIFY_CHANGE_LAST_SET, nullptr, false)) == ERROR_SUCCESS) {
bool currentGameStreamState = IsGameStreamEnabled();
if (lastGameStreamState != currentGameStreamState) {
SetEvent((HANDLE)Context);
}
lastGameStreamState = currentGameStreamState;
}
// 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;
}
void StartRelay(SOCKET* tcpSockets, SOCKET* udpSockets) {
int err;
for (int i = 0; i < ARRAYSIZE(TCP_PORTS); i++) {
err = StartTcpRelay(TCP_PORTS[i], &tcpSockets[i]);
if (err != 0) {
printf("Failed to start relay on TCP %d: %d\n", TCP_PORTS[i], err);
tcpSockets[i] = INVALID_SOCKET;
}
}
for (int i = 0; i < ARRAYSIZE(UDP_PORTS); i++) {
err = StartUdpRelay(UDP_PORTS[i], &udpSockets[i * 2], &udpSockets[i * 2 + 1]);
if (err != 0) {
printf("Failed to start relay on UDP %d: %d\n", UDP_PORTS[i], err);
udpSockets[i * 2] = udpSockets[i * 2 + 1] = INVALID_SOCKET;
}
}
}
int Run(bool standaloneExe)
{
int err;
@ -877,6 +954,7 @@ int Run(bool standaloneExe)
ResetLogFile(standaloneExe);
HANDLE ifaceChangeEvent = CreateEvent(nullptr, true, false, nullptr);
HANDLE gameStreamStateChangeEvent = CreateEvent(nullptr, true, false, nullptr);
err = WSAStartup(MAKEWORD(2, 0), &data);
if (err == SOCKET_ERROR) {
@ -888,38 +966,91 @@ int Run(bool standaloneExe)
HANDLE ifaceChangeHandle;
NotifyIpInterfaceChange(AF_INET6, IpInterfaceChangeNotificationCallback, ifaceChangeEvent, false, &ifaceChangeHandle);
// Watch for GameStream state changes
HANDLE stateChangeThread = CreateThread(NULL, 0, GameStreamStateChangeThread, gameStreamStateChangeEvent, 0, NULL);
if (stateChangeThread == NULL) {
printf("CreateThread() failed: %d\n", GetLastError());
return GetLastError();
}
CloseHandle(stateChangeThread);
// Ensure we get adequate CPU time even when the PC is heavily loaded
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
for (int i = 0; i < ARRAYSIZE(TCP_PORTS); i++) {
err = StartTcpRelay(TCP_PORTS[i]);
if (err != 0) {
printf("Failed to start relay on TCP %d: %d\n", TCP_PORTS[i], err);
return err;
}
}
// Keep track of TCP and UDP sockets for the relays. UDP requires 2 sockets per port (1 for v4 and 1 for v6).
SOCKET tcpSockets[ARRAYSIZE(TCP_PORTS)] = {};
SOCKET udpSockets[ARRAYSIZE(UDP_PORTS) * 2] = {};
for (int i = 0; i < ARRAYSIZE(UDP_PORTS); i++) {
err = StartUdpRelay(UDP_PORTS[i]);
if (err != 0) {
printf("Failed to start relay on UDP %d: %d\n", UDP_PORTS[i], err);
return err;
}
// Start the relays if GameStream is on
if (IsGameStreamEnabled()) {
StartRelay(tcpSockets, udpSockets);
}
for (;;) {
ResetEvent(ifaceChangeEvent);
UpdatePcpPinholes();
UpdateUpnpPinholes();
// Update pinholes if GameStream is enabled
if (IsGameStreamEnabled()) {
printf("GameStream is enabled\n");
UpdatePcpPinholes();
UpdateUpnpPinholes();
}
else {
printf("GameStream is disabled\n");
}
printf("Going to sleep...\n");
fflush(stdout);
if (WaitForSingleObject(ifaceChangeEvent, 120 * 1000) == WAIT_FAILED) {
HANDLE objects[] = { ifaceChangeEvent, gameStreamStateChangeEvent };
switch (WaitForMultipleObjects(2, objects, FALSE, 120 * 1000)) {
case WAIT_OBJECT_0:
// Interface state changed. Update pinholes immediately.
ResetLogFile(standaloneExe);
printf("Woke up for network interface change\n");
break;
case WAIT_OBJECT_0 + 1:
// GameStream state changed
ResetLogFile(standaloneExe);
printf("Woke up for GameStream state change\n");
ResetEvent(gameStreamStateChangeEvent);
// Shutdown all relay sockets to trigger the relay threads to terminate.
// The relay threads will call closesocket().
for (int i = 0; i < ARRAYSIZE(tcpSockets); i++) {
if (tcpSockets[i] != NULL && tcpSockets[i] != INVALID_SOCKET) {
shutdown(tcpSockets[i], SD_BOTH);
CancelIoEx((HANDLE)tcpSockets[i], NULL);
tcpSockets[i] = INVALID_SOCKET;
}
}
for (int i = 0; i < ARRAYSIZE(udpSockets); i++) {
if (udpSockets[i] != NULL && udpSockets[i] != INVALID_SOCKET) {
shutdown(udpSockets[i], SD_BOTH);
CancelIoEx((HANDLE)udpSockets[i], NULL);
udpSockets[i] = INVALID_SOCKET;
}
}
// If GameStream is now enabled, start the relay
if (IsGameStreamEnabled()) {
StartRelay(tcpSockets, udpSockets);
}
else {
printf("Stopped relay after GameStream was disabled\n");
}
break;
case WAIT_TIMEOUT:
// Time to refresh the pinholes
ResetLogFile(standaloneExe);
printf("Woke up on refresh timer\n");
break;
case WAIT_FAILED:
return -1;
}
ResetLogFile(standaloneExe);
}
return 0;

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<?define VCREDIST_VER = "14.31.31103" ?>
<?define VCREDIST_X86_SIZE = "13725768" ?>
<?define VCREDIST_X86_SHA1 = "15fe8e70c3c5582b70df173cd9b580331677735a" ?>
<?define VCREDIST_X86_URL = "https://download.visualstudio.microsoft.com/download/pr/144a5711-f076-44fa-bf55-f7e0121eb30c/B7AE307237F869E09F7413691A2CD1944357B5CEE28049C0A0D3430B47BB3EDC/VC_redist.x86.exe" ?>
<?define VCREDIST_VER = "14.36.32532.0" ?>
<?define VCREDIST_X86_SIZE = "13837672" ?>
<?define VCREDIST_X86_SHA1 = "C9B5B7969E499A4FD9E580EF4187322778E1936A" ?>
<?define VCREDIST_X86_URL = "https://download.visualstudio.microsoft.com/download/pr/eaab1f82-787d-4fd7-8c73-f782341a0c63/5365A927487945ECB040E143EA770ADBB296074ECE4021B1D14213BDE538C490/VC_redist.x86.exe" ?>
<?define VCREDIST_X86_UPGRADE_CODE = "65E5BD06-6392-3027-8C26-853107D3CF1A" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
@ -39,7 +39,7 @@
<RemotePayload Description="Microsoft Visual C++ 2015-2022 Redistributable - x86"
ProductName="Microsoft Visual C++ 2015-2022 Redistributable - x86"
Size="$(var.VCREDIST_X86_SIZE)"
Version="$(var.VCREDIST_VER).0"
Version="$(var.VCREDIST_VER)"
Hash="$(var.VCREDIST_X86_SHA1)"/>
<!-- Newer version installed is fine -->

View File

@ -1,7 +1,7 @@
#pragma once
#define VER_VERSION 2,5,4,0
#define VER_VERSION_STR "2.5.4.0"
#define VER_VERSION 2,6,0,0
#define VER_VERSION_STR "2.6.0.0"
#define VER_COMPANYNAME_STR "Moonlight Game Streaming Project"
#define VER_PRODUCTNAME_STR "Moonlight Internet Hosting Tool"