Compare commits

...

13 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
Cameron Gutman
48c0136b9d Redirect stdout to NUL if the log file can't be opened 2022-04-16 21:25:25 -05:00
Cameron Gutman
c4291ff47a Revert "Don't crash if the log file can't be opened"
We don't have a stdout to _dup2() into when run as a service.

This reverts commit 16ddcb82d94dd99a8bee8887434acd528411773c.
2022-04-16 21:20:18 -05:00
Cameron Gutman
41ab166b8a Version 2.5.4 2022-04-16 13:32:05 -05:00
Cameron Gutman
f1cef10928 Update MiniUPnP and libnatpmp
MiniUPnP  -> 689d1fd
libnatpmp -> 724dc69
2022-04-16 13:30:01 -05:00
Cameron Gutman
16ddcb82d9 Don't crash if the log file can't be opened 2022-04-16 12:47:20 -05:00
Cameron Gutman
21152240cf Update Visual C++ Runtime 2022-04-16 11:55:46 -05:00
Cameron Gutman
98e2ddd1e0 Update toolset to VS 2022 2022-04-16 11:38:55 -05:00
Cameron Gutman
13738092df Update Visual C++ Runtime installer 2021-08-15 12:30:06 -05:00
16 changed files with 314 additions and 49 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);
@ -853,7 +853,11 @@ void ResetLogFile(bool standaloneExe)
MoveFileExA(currentLogFilePath, oldLogFilePath, MOVEFILE_REPLACE_EXISTING);
// Redirect stdout to this new file
freopen(currentLogFilePath, "w", stdout);
if (freopen(currentLogFilePath, "w", stdout) == NULL) {
// If we couldn't create a log file, just redirect stdout to NUL.
// We have to open _something_ or printf() will crash.
freopen("NUL", "w", stdout);
}
}
// Print a log header
@ -865,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;
@ -873,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) {
@ -884,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

@ -29,26 +29,26 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<?define VCREDIST_VER = "14.28.29910" ?>
<?define VCREDIST_X86_SIZE = "14308616" ?>
<?define VCREDIST_X86_SHA1 = "CC6D8F9286645F2A11BCAE9D0E000CF012B08112" ?>
<?define VCREDIST_X86_URL = "https://download.visualstudio.microsoft.com/download/pr/d64b93c3-f270-4750-9e75-bc12b2e899fb/4521ED84B9B1679A706E719423D54EF5E413DC50DDE1CF362232D7359D7E89C4/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"
@ -20,13 +20,13 @@
<WixVariable Id="WixUILicenseRtf" Value="" />
<util:ProductSearch Id="VCREDIST_142_x86"
<util:ProductSearch Id="VCREDIST_14_x86"
UpgradeCode="$(var.VCREDIST_X86_UPGRADE_CODE)"
Result="version"
Variable="VCREDIST_142_x86" />
Variable="VCREDIST_14_x86" />
<Chain>
<ExePackage Name="Microsoft Visual C++ 2015-2019 Redistributable - x86"
<ExePackage Name="Microsoft Visual C++ 2015-2022 Redistributable - x86"
Cache="no"
Compressed="no"
PerMachine="yes"
@ -34,12 +34,12 @@
Vital="yes"
InstallCommand="/install /quiet /norestart"
DownloadUrl="$(var.VCREDIST_X86_URL)"
DetectCondition="VCREDIST_142_x86 &gt;= v$(var.VCREDIST_VER)">
DetectCondition="VCREDIST_14_x86 &gt;= v$(var.VCREDIST_VER)">
<RemotePayload Description="Microsoft Visual C++ 2015-2019 Redistributable - x86"
ProductName="Microsoft Visual C++ 2015-2019 Redistributable - x86"
<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,9 +1,9 @@
/* $Id: miniupnpc.h,v 1.55 2020/11/09 19:49:32 nanard Exp $ */
/* $Id: miniupnpc.h,v 1.59 2021/09/28 21:39:17 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project: miniupnp
* http://miniupnp.free.fr/
* Author: Thomas Bernard
* Copyright (c) 2005-2018 Thomas Bernard
* Copyright (c) 2005-2021 Thomas Bernard
* This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED
@ -20,7 +20,7 @@
#define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */
#define MINIUPNPC_VERSION "2.2.0"
#define MINIUPNPC_VERSION "2.2.3"
#define MINIUPNPC_API_VERSION 17
/* Source port:

View File

@ -7,7 +7,7 @@
#ifndef MINIUPNPC_SOCKETDEF_H_INCLUDED
#define MINIUPNPC_SOCKETDEF_H_INCLUDED
#ifdef _MSC_VER
#ifdef _WIN32
#define ISINVALID(s) (INVALID_SOCKET==(s))

View File

@ -1,13 +1,15 @@
/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 nanard Exp $ */
/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org
* Author : Thomas Bernard
* Copyright (c) 2011 Thomas Bernard
* Copyright (c) 2021 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided within this distribution */
#ifndef MINIUPNPCTYPES_H_INCLUDED
#define MINIUPNPCTYPES_H_INCLUDED
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
/* Use unsigned long long when available :
* strtoull is C99 */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define UNSIGNED_INTEGER unsigned long long
#define STRTOUI strtoull
#else

View File

@ -0,0 +1,65 @@
/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef PORTLISTINGPARSE_H_INCLUDED
#define PORTLISTINGPARSE_H_INCLUDED
#include "miniupnpc_declspec.h"
/* for the definition of UNSIGNED_INTEGER */
#include "miniupnpctypes.h"
#ifdef __cplusplus
extern "C" {
#endif
/* sample of PortMappingEntry :
<p:PortMappingEntry>
<p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>
<p:NewExternalPort>2345</p:NewExternalPort>
<p:NewProtocol>TCP</p:NewProtocol>
<p:NewInternalPort>2345</p:NewInternalPort>
<p:NewInternalClient>192.168.1.137</p:NewInternalClient>
<p:NewEnabled>1</p:NewEnabled>
<p:NewDescription>dooom</p:NewDescription>
<p:NewLeaseTime>345</p:NewLeaseTime>
</p:PortMappingEntry>
*/
typedef enum { PortMappingEltNone,
PortMappingEntry, NewRemoteHost,
NewExternalPort, NewProtocol,
NewInternalPort, NewInternalClient,
NewEnabled, NewDescription,
NewLeaseTime } portMappingElt;
struct PortMapping {
struct PortMapping * l_next; /* list next element */
UNSIGNED_INTEGER leaseTime;
unsigned short externalPort;
unsigned short internalPort;
char remoteHost[64];
char internalClient[64];
char description[64];
char protocol[4];
unsigned char enabled;
};
struct PortMappingParserData {
struct PortMapping * l_head; /* list head */
portMappingElt curelt;
};
MINIUPNP_LIBSPEC void
ParsePortListing(const char * buffer, int bufsize,
struct PortMappingParserData * pdata);
MINIUPNP_LIBSPEC void
FreePortListing(struct PortMappingParserData * pdata);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,8 +1,8 @@
/* $Id: upnpdev.h,v 1.3 2020/05/29 15:57:42 nanard Exp $ */
/* $Id: upnpdev.h,v 1.4 2021/08/21 09:45:01 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD
* copyright (c) 2005-2020 Thomas Bernard
* copyright (c) 2005-2021 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED
@ -20,7 +20,7 @@ struct UPNPDev {
char * st;
char * usn;
unsigned int scope_id;
#if defined(__STDC_VERSION) && __STDC_VERSION__ >= 199901L
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 flexible array member */
char buffer[];
#elif defined(__GNUC__)

View File

@ -0,0 +1,63 @@
/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2013 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
#ifndef UPNPREPLYPARSE_H_INCLUDED
#define UPNPREPLYPARSE_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
struct NameValue {
struct NameValue * l_next;
char name[64];
char value[128];
};
struct NameValueParserData {
struct NameValue * l_head;
char curelt[64];
char * portListing;
int portListingLength;
int topelt;
const char * cdata;
int cdatalen;
};
/* ParseNameValue() */
void
ParseNameValue(const char * buffer, int bufsize,
struct NameValueParserData * data);
/* ClearNameValueList() */
void
ClearNameValueList(struct NameValueParserData * pdata);
/* GetValueFromNameValueList() */
char *
GetValueFromNameValueList(struct NameValueParserData * pdata,
const char * Name);
#if 0
/* GetValueFromNameValueListIgnoreNS() */
char *
GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata,
const char * Name);
#endif
/* DisplayNameValueList() */
#ifdef DEBUG
void
DisplayNameValueList(char * buffer, int bufsize);
#endif
#ifdef __cplusplus
}
#endif
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
#pragma once
#define VER_VERSION 2,5,3,0
#define VER_VERSION_STR "2.5.3.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"