Compare commits

...
45 Commits
Author SHA1 Message Date
Cameron Gutman 404af38d10 Version 5.5.2 2021-02-02 18:16:27 -06:00
Cameron Gutman dd72f65ffb Fix inaccurate test results on IPv6 when a temporary address is in use and no pinholes are created for it 2021-02-01 19:59:41 -06:00
Cameron Gutman 6589dc4853 Update GSv6Fwd with CET and CFG 2021-02-01 19:53:52 -06:00
Cameron Gutman 9772139229 Print UPnP root desc URL in logs 2021-02-01 19:41:14 -06:00
Cameron Gutman 03c89e4022 Update MiniUPnPc to 36cc66edda92093b24e051e38bd16a64900272e9
Built with CFG and CET enabled
2021-02-01 19:40:44 -06:00
Cameron Gutman d1fe5f6a9b Rebuilt libnatpmp with CET and CFG
Commit 4536032ae32268a45c073a4d5e91bbab4534773a
2021-02-01 19:40:24 -06:00
Cameron Gutman a88b8d0d04 Enable CFG and CET for MISS and MIST 2021-02-01 19:26:14 -06:00
Cameron Gutman fa5ae73abb Version 5.5.1 2020-11-29 23:38:14 -06:00
Cameron Gutman 4d197cae02 Improve performance and reliability when stopping MISS 2020-11-29 22:25:27 -06:00
Cameron Gutman 624af65b55 Fix minor installer build warnings 2020-11-29 22:06:02 -06:00
Cameron Gutman 6b1a0856cc Update miniupnpc to ba130320f4180f8f9a54c48c0634e0ea0118fa38
This adds DLL version resources for Windows Installer
2020-11-29 22:05:43 -06:00
Cameron Gutman 01a1012e74 Use preprocessor variables to improve readability 2020-11-29 20:21:37 -06:00
Cameron Gutman 66b36684ec Only download the CRT redistributable if it's newer than what is installed 2020-11-29 17:23:48 -06:00
Cameron Gutman e7db5242c9 Update installer for new DLLs 2020-11-29 15:58:20 -06:00
Cameron Gutman 5e09217af4 Update GSv6Fwd to use DLLs instead of static build 2020-11-29 15:57:10 -06:00
Cameron Gutman c21a64c874 Remove x64 solution target 2020-11-29 14:51:56 -06:00
Cameron Gutman ebe91d6799 Update project build files for the new DLLs 2020-11-29 14:51:41 -06:00
Cameron Gutman 077c9814e0 Sign pre-built libraries 2020-11-29 14:49:37 -06:00
Cameron Gutman 393dfb70a7 Update miniupnpc to 677e0db63649ad2aeb536783eb745c651f2fd5c2
Rebuild as DLL to prevent MSVC version incompatibility
2020-11-29 14:35:02 -06:00
Cameron Gutman 88fb77083f Update libnatpmp to 4536032ae32268a45c073a4d5e91bbab4534773a
Rebuild as a DLL to prevent MSVC version compatibility issues
2020-11-29 14:27:53 -06:00
Cameron Gutman 38514d08c1 Version 5.5 2020-10-10 13:58:23 -05:00
Cameron Gutman 5d75b11a35 Fix success text typos 2020-10-10 13:56:10 -05:00
Cameron Gutman f511b830ea Handle deletion of the 'HKLM\Software\NVIDIA Corporation' key 2020-10-10 13:35:05 -05:00
Cameron Gutman 8a45ea2066 Test for MTU problems 2020-10-10 12:39:48 -05:00
Cameron Gutman 3844ea59de Allow mDNS traffic through the firewall for autodiscovery 2020-10-10 12:07:42 -05:00
Cameron Gutman a19b95f259 RFC6887 says PCP max packet size is 1100 bytes 2020-10-10 12:00:48 -05:00
Cameron Gutman ae81d4305d Improve success message with more information 2020-10-10 11:57:26 -05:00
Cameron Gutman 8066cf4be1 Avoid extra GameStream state prints when the state isn't changing 2020-10-10 11:37:42 -05:00
Cameron Gutman 021474cdd2 Version 5.4 2020-09-07 11:15:52 -07:00
Cameron Gutman 308cd0dd00 Use dynamically allocated buffer for GetAdaptersAddresses() 2020-09-07 10:14:54 -07:00
Cameron Gutman 83360d775b Ignore ICMP Port Unreachable messages during STUN 2020-09-06 15:12:16 -07:00
Cameron Gutman cdbaa0aff3 Version 5.3.1 2020-08-30 13:47:35 -07:00
Cameron Gutman 36ea86faaa Configure SCM to restart our service if it crashes 2020-08-29 22:43:41 -07:00
Cameron Gutman 8590a0813b Stop testing after the first IPv6 relay server 2020-08-28 18:46:56 -07:00
Cameron Gutman 51ae1c8770 Fix socket errors being clobbered by closesocket() 2020-08-28 18:46:36 -07:00
Cameron Gutman f1ca6a71f0 Version 5.3 2020-08-14 18:35:19 -07:00
Cameron Gutman ac92212464 Fix flip-flopped HTTP and HTTPS rule IDs 2020-08-14 17:57:45 -07:00
Cameron Gutman dbf43ac7a1 Don't attempt to relocate WoL port 9 2020-08-14 17:54:48 -07:00
Cameron Gutman 893aa76c9c Replace hardcoded constant with #define 2020-08-14 17:52:59 -07:00
Cameron Gutman 21d8c71a2c Log the internal port for the UPnP mappings 2020-08-14 17:51:06 -07:00
Cameron Gutman 41ef072c9b Validate the port number of loopback traffic 2020-08-14 17:48:55 -07:00
Cameron Gutman 53246bd4c5 Don't redirect stdout for standalone exe invocation 2020-08-14 17:48:14 -07:00
Cameron Gutman ac850e79d8 Add firewall rules for GameStream just in case GFE didn't 2020-08-12 20:54:34 -07:00
Cameron Gutman 944c8993e8 Elevate priorities for the UDP relay threads 2020-08-11 01:12:48 -07:00
Cameron Gutman b6508d9024 Remove superfluous select() call 2020-08-11 00:59:13 -07:00
28 changed files with 546 additions and 222 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
/* $Id: miniupnpc.h,v 1.53 2018/05/07 11:05:16 nanard Exp $ */ /* $Id: miniupnpc.h,v 1.55 2020/11/09 19:49:32 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab /* vim: tabstop=4 shiftwidth=4 noexpandtab
* Project: miniupnp * Project: miniupnp
* http://miniupnp.free.fr/ * http://miniupnp.free.fr/
@@ -20,7 +20,7 @@
#define UPNPDISCOVER_MEMORY_ERROR (-102) #define UPNPDISCOVER_MEMORY_ERROR (-102)
/* versions : */ /* versions : */
#define MINIUPNPC_VERSION "2.1" #define MINIUPNPC_VERSION "2.2.0"
#define MINIUPNPC_API_VERSION 17 #define MINIUPNPC_API_VERSION 17
/* Source port: /* Source port:
+12 -4
View File
@@ -1,8 +1,8 @@
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ /* $Id: upnpdev.h,v 1.3 2020/05/29 15:57:42 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Web : http://miniupnp.free.fr/ * Web : http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2018 Thomas Bernard * copyright (c) 2005-2020 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENSE file. */ * provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED #ifndef UPNPDEV_H_INCLUDED
@@ -20,7 +20,15 @@ struct UPNPDev {
char * st; char * st;
char * usn; char * usn;
unsigned int scope_id; unsigned int scope_id;
char buffer[3]; #if defined(__STDC_VERSION) && __STDC_VERSION__ >= 199901L
/* C99 flexible array member */
char buffer[];
#elif defined(__GNUC__)
char buffer[0];
#else
/* Fallback to a hack */
char buffer[1];
#endif
}; };
/* freeUPNPDevlist() /* freeUPNPDevlist()
+7
View File
@@ -51,6 +51,13 @@ typedef unsigned short uint16_t;
#endif /* _WIN32 */ #endif /* _WIN32 */
#include "natpmp_declspec.h" #include "natpmp_declspec.h"
/* Set to 9 by https://tools.ietf.org/html/rfc6886#section-3.1 which leads to a
* maximum timeout of 127.75 seconds, due to the initial 250 ms timeout doubling
* each time, so we allow a compile-time modification here.*/
#ifndef NATPMP_MAX_RETRIES
#define NATPMP_MAX_RETRIES (9)
#endif
typedef struct { typedef struct {
int s; /* socket */ int s; /* socket */
in_addr_t gateway; /* default gateway (IPv4) */ in_addr_t gateway; /* default gateway (IPv4) */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+32 -1
View File
@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?define VCREDIST_VER = "14.28.29334" ?>
<?define VCREDIST_X86_SIZE = "14328440" ?>
<?define VCREDIST_X86_SHA1 = "17674FCC6CF3A2FFDC391BDCDE082AA936E37A89" ?>
<?define VCREDIST_X86_UPGRADE_CODE = "65E5BD06-6392-3027-8C26-853107D3CF1A" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"> xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle Name="Moonlight Internet Hosting Tool" Manufacturer="Moonlight Game Streaming Project" Version="!(bind.packageVersion.mish)" UpgradeCode="a2ce5056-1114-44b9-b79b-952ef46d3d50"> <Bundle Name="Moonlight Internet Hosting Tool" Manufacturer="Moonlight Game Streaming Project" Version="!(bind.packageVersion.mish)" UpgradeCode="a2ce5056-1114-44b9-b79b-952ef46d3d50">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense"> <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication <bal:WixStandardBootstrapperApplication
@@ -12,7 +19,31 @@
<WixVariable Id="WixUILicenseRtf" Value="" /> <WixVariable Id="WixUILicenseRtf" Value="" />
<util:ProductSearch Id="VCREDIST_142_x86"
UpgradeCode="$(var.VCREDIST_X86_UPGRADE_CODE)"
Result="version"
Variable="VCREDIST_142_x86" />
<Chain> <Chain>
<ExePackage Name="Microsoft Visual C++ 2015-2019 Redistributable - x86"
Cache="no"
Compressed="no"
PerMachine="yes"
Permanent="yes"
Vital="yes"
InstallCommand="/install /quiet /norestart"
DownloadUrl="https://moonlight-stream.org/downloads/vcredist/$(var.VCREDIST_VER)/vcredist_x86.exe"
DetectCondition="VCREDIST_142_x86 &gt;= v$(var.VCREDIST_VER)">
<RemotePayload Description="Microsoft Visual C++ 2015-2019 Redistributable - x86"
ProductName="Microsoft Visual C++ 2015-2019 Redistributable - x86"
Size="$(var.VCREDIST_X86_SIZE)"
Version="$(var.VCREDIST_VER).0"
Hash="$(var.VCREDIST_X86_SHA1)"/>
<!-- Newer version installed is fine -->
<ExitCode Value="1638" Behavior="success" />
</ExePackage>
<MsiPackage Id="mish" SourceFile="$(var.mish.TargetPath)" /> <MsiPackage Id="mish" SourceFile="$(var.mish.TargetPath)" />
<MsiPackage SourceFile="$(var.GSv6FwdSetup.TargetPath)" /> <MsiPackage SourceFile="$(var.GSv6FwdSetup.TargetPath)" />
</Chain> </Chain>
+4
View File
@@ -26,6 +26,10 @@
<HintPath>$(WixExtDir)\WixBalExtension.dll</HintPath> <HintPath>$(WixExtDir)\WixBalExtension.dll</HintPath>
<Name>WixBalExtension</Name> <Name>WixBalExtension</Name>
</WixExtension> </WixExtension>
<WixExtension Include="WixUtilExtension">
<HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
<Name>WixUtilExtension</Name>
</WixExtension>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\GS-IPv6-Forwarder\GSv6FwdSetup\GSv6FwdSetup.wixproj"> <ProjectReference Include="..\GS-IPv6-Forwarder\GSv6FwdSetup\GSv6FwdSetup.wixproj">
-20
View File
@@ -17,52 +17,32 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "GSv6FwdSetup", "GS-IPv6-For
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Debug|x64.ActiveCfg = Debug|x64
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Debug|x64.Build.0 = Debug|x64
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Debug|x86.ActiveCfg = Debug|Win32 {B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Debug|x86.ActiveCfg = Debug|Win32
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Debug|x86.Build.0 = Debug|Win32 {B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Debug|x86.Build.0 = Debug|Win32
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Release|x64.ActiveCfg = Release|x64
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Release|x64.Build.0 = Release|x64
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Release|x86.ActiveCfg = Release|Win32 {B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Release|x86.ActiveCfg = Release|Win32
{B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Release|x86.Build.0 = Release|Win32 {B71C4E7F-0D92-4E19-BBD2-D33F0EF879B1}.Release|x86.Build.0 = Release|Win32
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Debug|x64.ActiveCfg = Debug|x64
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Debug|x64.Build.0 = Debug|x64
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Debug|x86.ActiveCfg = Debug|Win32 {8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Debug|x86.ActiveCfg = Debug|Win32
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Debug|x86.Build.0 = Debug|Win32 {8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Debug|x86.Build.0 = Debug|Win32
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Release|x64.ActiveCfg = Release|x64
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Release|x64.Build.0 = Release|x64
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Release|x86.ActiveCfg = Release|Win32 {8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Release|x86.ActiveCfg = Release|Win32
{8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Release|x86.Build.0 = Release|Win32 {8F78D8D2-A837-489C-BAC5-81494C9CEF7A}.Release|x86.Build.0 = Release|Win32
{F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Debug|x64.ActiveCfg = Debug|x86
{F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Debug|x86.ActiveCfg = Debug|x86 {F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Debug|x86.ActiveCfg = Debug|x86
{F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Debug|x86.Build.0 = Debug|x86 {F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Debug|x86.Build.0 = Debug|x86
{F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Release|x64.ActiveCfg = Release|x86
{F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Release|x86.ActiveCfg = Release|x86 {F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Release|x86.ActiveCfg = Release|x86
{F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Release|x86.Build.0 = Release|x86 {F0DEE5F3-4B62-47A3-B00B-61C614C924FD}.Release|x86.Build.0 = Release|x86
{A2CE5056-1114-44B9-B79B-952EF46D3D50}.Debug|x64.ActiveCfg = Debug|x86
{A2CE5056-1114-44B9-B79B-952EF46D3D50}.Debug|x86.ActiveCfg = Debug|x86 {A2CE5056-1114-44B9-B79B-952EF46D3D50}.Debug|x86.ActiveCfg = Debug|x86
{A2CE5056-1114-44B9-B79B-952EF46D3D50}.Debug|x86.Build.0 = Debug|x86 {A2CE5056-1114-44B9-B79B-952EF46D3D50}.Debug|x86.Build.0 = Debug|x86
{A2CE5056-1114-44B9-B79B-952EF46D3D50}.Release|x64.ActiveCfg = Release|x86
{A2CE5056-1114-44B9-B79B-952EF46D3D50}.Release|x86.ActiveCfg = Release|x86 {A2CE5056-1114-44B9-B79B-952EF46D3D50}.Release|x86.ActiveCfg = Release|x86
{A2CE5056-1114-44B9-B79B-952EF46D3D50}.Release|x86.Build.0 = Release|x86 {A2CE5056-1114-44B9-B79B-952EF46D3D50}.Release|x86.Build.0 = Release|x86
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Debug|x64.ActiveCfg = Debug|x64
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Debug|x64.Build.0 = Debug|x64
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Debug|x86.ActiveCfg = Debug|Win32 {87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Debug|x86.ActiveCfg = Debug|Win32
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Debug|x86.Build.0 = Debug|Win32 {87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Debug|x86.Build.0 = Debug|Win32
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Release|x64.ActiveCfg = Release|x64
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Release|x64.Build.0 = Release|x64
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Release|x86.ActiveCfg = Release|Win32 {87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Release|x86.ActiveCfg = Release|Win32
{87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Release|x86.Build.0 = Release|Win32 {87DEAE49-7638-4CDB-88EB-054B1F3CB0D2}.Release|x86.Build.0 = Release|Win32
{F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Debug|x64.ActiveCfg = Debug|x86
{F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Debug|x86.ActiveCfg = Debug|x86 {F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Debug|x86.ActiveCfg = Debug|x86
{F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Debug|x86.Build.0 = Debug|x86 {F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Debug|x86.Build.0 = Debug|x86
{F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Release|x64.ActiveCfg = Release|x86
{F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Release|x86.ActiveCfg = Release|x86 {F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Release|x86.ActiveCfg = Release|x86
{F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Release|x86.Build.0 = Release|x86 {F8171B99-F5F9-4ABF-9FE5-6753539611AF}.Release|x86.Build.0 = Release|x86
EndGlobalSection EndGlobalSection
+49
View File
@@ -52,6 +52,12 @@
<Fragment> <Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component Id="MiniupnpcDll">
<File Source="$(var.miss.TargetDir)miniupnpc.dll" KeyPath="yes"/>
</Component>
<Component Id="LibnatpmpDll">
<File Source="$(var.miss.TargetDir)libnatpmp.dll" KeyPath="yes"/>
</Component>
<Component Id="MISS"> <Component Id="MISS">
<File Source="$(var.miss.TargetPath)" KeyPath="yes"> <File Source="$(var.miss.TargetPath)" KeyPath="yes">
<fire:FirewallException Id="MISSFwException" <fire:FirewallException Id="MISSFwException"
@@ -70,6 +76,7 @@
ErrorControl="ignore" ErrorControl="ignore"
Interactive="no"> Interactive="no">
<ServiceConfig DelayedAutoStart="no" OnInstall="yes" OnReinstall="yes" ServiceSid="unrestricted"/> <ServiceConfig DelayedAutoStart="no" OnInstall="yes" OnReinstall="yes" ServiceSid="unrestricted"/>
<util:ServiceConfig FirstFailureActionType="restart" SecondFailureActionType="restart" ThirdFailureActionType="restart" ResetPeriodInDays="1" RestartServiceDelayInSeconds="10"/>
</ServiceInstall> </ServiceInstall>
<ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="MISS" Wait="yes" /> <ServiceControl Id="StartService" Start="install" Stop="both" Remove="uninstall" Name="MISS" Wait="yes" />
</Component> </Component>
@@ -80,6 +87,48 @@
Name="Moonlight Internet Streaming Tester"/> Name="Moonlight Internet Streaming Tester"/>
</File> </File>
</Component> </Component>
<Component Id="GameStreamFirewallRules" Guid="{16CA2511-B533-46F8-8882-F8AEEFDFD7DF}" KeyPath="yes">
<fire:FirewallException Id="HttpsFwException"
Scope="any"
Port="47984"
Protocol="tcp"
Name="Moonlight - HTTPS"/>
<fire:FirewallException Id="HttpFwException"
Scope="any"
Port="47989"
Protocol="tcp"
Name="Moonlight - HTTP"/>
<fire:FirewallException Id="RtspFwException"
Scope="any"
Port="48010"
Protocol="tcp"
Name="Moonlight - RTSP"/>
<fire:FirewallException Id="VideoFwException"
Scope="any"
Port="47998"
Protocol="udp"
Name="Moonlight - Video"/>
<fire:FirewallException Id="ControlFwException"
Scope="any"
Port="47999"
Protocol="udp"
Name="Moonlight - Control"/>
<fire:FirewallException Id="AudioFwException"
Scope="any"
Port="48000"
Protocol="udp"
Name="Moonlight - Audio"/>
<fire:FirewallException Id="RtspuFwException"
Scope="any"
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="*"> <Component Id="Shortcuts" Guid="*">
<Shortcut Id="StartMenuShortcut" <Shortcut Id="StartMenuShortcut"
Name="Moonlight Internet Streaming Tester" Name="Moonlight Internet Streaming Tester"
+159 -75
View File
@@ -39,6 +39,7 @@ bool PCPMapPort(PSOCKADDR_STORAGE localAddr, int localAddrLen, PSOCKADDR_STORAGE
#define POLLING_DELAY_SEC 120 #define POLLING_DELAY_SEC 120
#define PORT_MAPPING_DURATION_SEC 3600 #define PORT_MAPPING_DURATION_SEC 3600
#define UPNP_DISCOVERY_DELAY_MS 5000 #define UPNP_DISCOVERY_DELAY_MS 5000
#define GAA_INITIAL_SIZE 8192
static struct port_entry { static struct port_entry {
int proto; int proto;
@@ -56,6 +57,9 @@ static struct port_entry {
static const int k_WolPorts[] = { 9, 47009 }; static const int k_WolPorts[] = { 9, 47009 };
static HANDLE s_StopEvent;
static CRITICAL_SECTION s_PortMappingUpdateLock;
bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const char* myAddr, int port, bool enable, bool indefinite, bool validationPass) bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const char* myAddr, int port, bool enable, bool indefinite, bool validationPass)
{ {
char intClient[16]; char intClient[16];
@@ -116,7 +120,7 @@ bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const
// Some routers change the description, so we can't check that here // Some routers change the description, so we can't check that here
if (!strcmp(intClient, myAddr)) { if (!strcmp(intClient, myAddr)) {
if (atoi(leaseDuration) == 0) { if (atoi(leaseDuration) == 0) {
printf("OK (Static)" NL); printf("OK (Static, Internal port: %s)" NL, intPort);
// If we have an existing permanent mapping, we can just leave it alone. // If we have an existing permanent mapping, we can just leave it alone.
if (enable) { if (enable) {
@@ -124,7 +128,7 @@ bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const
} }
} }
else { else {
printf("OK (%s seconds remaining)" NL, leaseDuration); printf("OK (%s seconds remaining, Internal port: %s)" NL, leaseDuration, intPort);
} }
// If we're just validating, we found an entry, so we're done. // If we're just validating, we found an entry, so we're done.
@@ -206,7 +210,7 @@ bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const
else if (indefinite) { else if (indefinite) {
printf("STATIC "); printf("STATIC ");
} }
if (err == 718 && proto == IPPROTO_UDP) { // ConflictInMappingEntry if (err == 718 && proto == IPPROTO_UDP && port >= 47000) { // ConflictInMappingEntry
// Some UPnP implementations incorrectly deduplicate on the internal port instead // Some UPnP implementations incorrectly deduplicate on the internal port instead
// of the external port, in violation of the UPnP IGD specification. Since GFE creates // of the external port, in violation of the UPnP IGD specification. Since GFE creates
// mappings on the same internal port as us, those routers break our mappings. To // mappings on the same internal port as us, those routers break our mappings. To
@@ -233,10 +237,7 @@ bool UPnPMapPort(struct UPNPUrls* urls, struct IGDdatas* data, int proto, const
bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength) bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
{ {
union { PIP_ADAPTER_ADDRESSES addresses;
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
ULONG error; ULONG error;
ULONG length; ULONG length;
PIP_ADAPTER_ADDRESSES currentAdapter; PIP_ADAPTER_ADDRESSES currentAdapter;
@@ -245,22 +246,34 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
inet_pton(AF_INET, lanAddressString, &targetAddress); inet_pton(AF_INET, lanAddressString, &targetAddress);
// Get a list of all interfaces with IPv4 addresses on the system addresses = NULL;
length = sizeof(buffer); length = GAA_INITIAL_SIZE;
error = GetAdaptersAddresses(AF_INET, do {
GAA_FLAG_SKIP_ANYCAST | free(addresses);
GAA_FLAG_SKIP_MULTICAST | addresses = (PIP_ADAPTER_ADDRESSES)malloc(length);
GAA_FLAG_SKIP_DNS_SERVER | if (addresses == NULL) {
GAA_FLAG_SKIP_FRIENDLY_NAME, printf("malloc(%u) failed" NL, length);
NULL, return false;
&addresses, }
&length);
// 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) { if (error != ERROR_SUCCESS) {
printf("GetAdaptersAddresses() failed: %d" NL, error); printf("GetAdaptersAddresses() failed: %d" NL, error);
free(addresses);
return false; return false;
} }
currentAdapter = &addresses; currentAdapter = addresses;
currentAddress = nullptr; currentAddress = nullptr;
while (currentAdapter != nullptr) { while (currentAdapter != nullptr) {
currentAddress = currentAdapter->FirstUnicastAddress; currentAddress = currentAdapter->FirstUnicastAddress;
@@ -271,6 +284,7 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
if (RtlEqualMemory(&currentAddrV4->sin_addr, &targetAddress, sizeof(targetAddress))) { if (RtlEqualMemory(&currentAddrV4->sin_addr, &targetAddress, sizeof(targetAddress))) {
*prefixLength = currentAddress->OnLinkPrefixLength; *prefixLength = currentAddress->OnLinkPrefixLength;
free(addresses);
return true; return true;
} }
@@ -281,6 +295,7 @@ bool GetIP4OnLinkPrefixLength(char* lanAddressString, int* prefixLength)
} }
printf("No adapter found with IPv4 address: %s" NL, lanAddressString); printf("No adapter found with IPv4 address: %s" NL, lanAddressString);
free(addresses);
return false; return false;
} }
@@ -304,10 +319,10 @@ bool UPnPHandleDeviceList(struct UPNPDev* list, bool enable, char* lanAddrOverri
return false; return false;
} }
else if (ret == 1) { else if (ret == 1) {
printf("Found a connected UPnP IGD" NL); printf("Found a connected UPnP IGD (%s)" NL, urls.rootdescURL);
} }
else if (ret == 2) { else if (ret == 2) {
printf("Found a disconnected UPnP IGD (!)" NL); printf("Found a disconnected (!) UPnP IGD (%s)" NL, urls.rootdescURL);
// Even if we are able to add forwarding entries, go ahead and try NAT-PMP // Even if we are able to add forwarding entries, go ahead and try NAT-PMP
success = false; success = false;
@@ -372,17 +387,21 @@ bool UPnPHandleDeviceList(struct UPNPDev* list, bool enable, char* lanAddrOverri
// Validate the rules are present and correct if they claimed to be added successfully // Validate the rules are present and correct if they claimed to be added successfully
if (success && enable) { if (success && enable) {
// Wait 10 seconds for the router state to quiesce // Wait 10 seconds for the router state to quiesce or the stop event to be set
printf("Waiting before UPnP port validation..."); printf("Waiting before UPnP port validation...");
Sleep(10000); if (WaitForSingleObject(s_StopEvent, 10000) == WAIT_TIMEOUT) {
printf("done" NL); printf("done" NL);
// Perform the validation pass (converting any now missing entries to permanent ones) // Perform the validation pass (converting any now missing entries to permanent ones)
for (int i = 0; i < ARRAYSIZE(k_Ports); i++) { for (int i = 0; i < ARRAYSIZE(k_Ports); i++) {
if (!UPnPMapPort(&urls, &data, k_Ports[i].proto, portMappingInternalAddress, k_Ports[i].port, enable, false, true)) { if (!UPnPMapPort(&urls, &data, k_Ports[i].proto, portMappingInternalAddress, k_Ports[i].port, enable, false, true)) {
success = false; success = false;
}
} }
} }
else {
printf("aborted" NL);
}
} }
FreeUPNPUrls(&urls); FreeUPNPUrls(&urls);
@@ -415,7 +434,7 @@ bool NATPMPMapPort(natpmp_t* natpmp, int proto, int port, bool enable, bool inde
lifetime = 604800; // 1 week lifetime = 604800; // 1 week
} }
else { else {
lifetime = 3600; lifetime = PORT_MAPPING_DURATION_SEC;
} }
printf("Updating NAT-PMP port mapping for %s %d...", proto == IPPROTO_TCP ? "TCP" : "UDP", port); printf("Updating NAT-PMP port mapping for %s %d...", proto == IPPROTO_TCP ? "TCP" : "UDP", port);
@@ -521,14 +540,8 @@ bool IsGameStreamEnabled()
printf("RegQueryValueExA() failed: %d" NL, error); printf("RegQueryValueExA() failed: %d" NL, error);
return false; return false;
} }
else if (!enabled) {
printf("GameStream is OFF!" NL); return enabled != 0;
return false;
}
else {
printf("GameStream is ON!" NL);
return true;
}
} }
void UpdatePortMappingsForTarget(bool enable, char* targetAddressIP4, char* internalAddressIP4, char* upstreamAddressIP4) void UpdatePortMappingsForTarget(bool enable, char* targetAddressIP4, char* internalAddressIP4, char* upstreamAddressIP4)
@@ -573,6 +586,12 @@ void UpdatePortMappingsForTarget(bool enable, char* targetAddressIP4, char* inte
ipv4Devs = getUPnPDevicesByAddress(addr); ipv4Devs = getUPnPDevicesByAddress(addr);
} }
// Abort if this is an add/update request and we're stopping
if (enable && WaitForSingleObject(s_StopEvent, 0) == WAIT_OBJECT_0) {
printf("Aborting port mapping update due to stop request" NL);
goto Exit;
}
// Use the delay of discovery to also allow the NAT-PMP endpoint time to respond // Use the delay of discovery to also allow the NAT-PMP endpoint time to respond
if (natPmpErr >= 0) { if (natPmpErr >= 0) {
natpmpresp_t response; natpmpresp_t response;
@@ -805,25 +824,28 @@ void NETIOAPI_API_ IpInterfaceChangeNotificationCallback(PVOID context, PMIB_IPI
SetEvent((HANDLE)context); SetEvent((HANDLE)context);
} }
void ResetLogFile() void ResetLogFile(bool standaloneExe)
{ {
char oldLogFilePath[MAX_PATH + 1];
char currentLogFilePath[MAX_PATH + 1];
char timeString[MAX_PATH + 1] = {}; char timeString[MAX_PATH + 1] = {};
SYSTEMTIME time; SYSTEMTIME time;
ExpandEnvironmentStringsA("%ProgramData%\\MISS\\miss-old.log", oldLogFilePath, sizeof(oldLogFilePath)); if (!standaloneExe) {
ExpandEnvironmentStringsA("%ProgramData%\\MISS\\miss-current.log", currentLogFilePath, sizeof(currentLogFilePath)); char oldLogFilePath[MAX_PATH + 1];
char currentLogFilePath[MAX_PATH + 1];
// Close the existing stdout handle. This is important because otherwise ExpandEnvironmentStringsA("%ProgramData%\\MISS\\miss-old.log", oldLogFilePath, sizeof(oldLogFilePath));
// it may still be open as stdout when we try to MoveFileEx below. ExpandEnvironmentStringsA("%ProgramData%\\MISS\\miss-current.log", currentLogFilePath, sizeof(currentLogFilePath));
fclose(stdout);
// Rotate the current to the old log file // Close the existing stdout handle. This is important because otherwise
MoveFileExA(currentLogFilePath, oldLogFilePath, MOVEFILE_REPLACE_EXISTING); // it may still be open as stdout when we try to MoveFileEx below.
fclose(stdout);
// Redirect stdout to this new file // Rotate the current to the old log file
freopen(currentLogFilePath, "w", stdout); MoveFileExA(currentLogFilePath, oldLogFilePath, MOVEFILE_REPLACE_EXISTING);
// Redirect stdout to this new file
freopen(currentLogFilePath, "w", stdout);
}
// Print a log header // Print a log header
printf("Moonlight Internet Streaming Service v" VER_VERSION_STR NL); printf("Moonlight Internet Streaming Service v" VER_VERSION_STR NL);
@@ -837,36 +859,59 @@ void ResetLogFile()
DWORD WINAPI GameStreamStateChangeThread(PVOID Context) DWORD WINAPI GameStreamStateChangeThread(PVOID Context)
{ {
HKEY key; HKEY key;
DWORD err;
// We're watching this key that way we can still detect GameStream turning on do {
// if GFE wasn't even installed when our service started // We're watching this key that way we can still detect GameStream turning on
DWORD err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\NVIDIA Corporation", 0, KEY_READ | KEY_WOW64_64KEY, &key); // if GFE wasn't even installed when our service started
if (err != ERROR_SUCCESS) { do {
printf("RegOpenKeyExA() failed: %d" NL, err); err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\NVIDIA Corporation", 0, KEY_READ | KEY_WOW64_64KEY, &key);
return err; 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 // Notify the main thread when the GameStream state changes
bool lastGameStreamState = IsGameStreamEnabled(); bool lastGameStreamState = IsGameStreamEnabled();
while ((err = RegNotifyChangeKeyValue(key, true, REG_NOTIFY_CHANGE_LAST_SET, nullptr, false)) == ERROR_SUCCESS) { while ((err = RegNotifyChangeKeyValue(key, true, REG_NOTIFY_CHANGE_LAST_SET, nullptr, false)) == ERROR_SUCCESS) {
bool currentGameStreamState = IsGameStreamEnabled(); bool currentGameStreamState = IsGameStreamEnabled();
if (lastGameStreamState != currentGameStreamState) { if (lastGameStreamState != currentGameStreamState) {
SetEvent((HANDLE)Context); 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; return err;
} }
int Run() int Initialize()
{
// Create the stop event
s_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (s_StopEvent == NULL) {
return GetLastError();
}
InitializeCriticalSection(&s_PortMappingUpdateLock);
return 0;
}
int Run(bool standaloneExe)
{ {
HANDLE ifaceChangeEvent = CreateEvent(nullptr, true, false, nullptr); HANDLE ifaceChangeEvent = CreateEvent(nullptr, true, false, nullptr);
HANDLE gsChangeEvent = CreateEvent(nullptr, true, false, nullptr); HANDLE gsChangeEvent = CreateEvent(nullptr, true, false, nullptr);
HANDLE events[2] = { ifaceChangeEvent, gsChangeEvent }; HANDLE events[3] = { ifaceChangeEvent, gsChangeEvent, s_StopEvent };
ResetLogFile(); ResetLogFile(standaloneExe);
// Bump the process priority class to above normal. The UDP relay threads will
// further raise their own thread priorities to avoid preemption by other activity.
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
// Create the UDP alternate port relays // Create the UDP alternate port relays
for (int i = 0; i < ARRAYSIZE(k_Ports); i++) { for (int i = 0; i < ARRAYSIZE(k_Ports); i++) {
@@ -885,7 +930,27 @@ int Run()
for (;;) { for (;;) {
ResetEvent(gsChangeEvent); ResetEvent(gsChangeEvent);
ResetEvent(ifaceChangeEvent); ResetEvent(ifaceChangeEvent);
UpdatePortMappings(IsGameStreamEnabled());
bool gameStreamEnabled = IsGameStreamEnabled();
if (gameStreamEnabled) {
printf("GameStream is ON!" NL);
}
else {
printf("GameStream is OFF!" NL);
}
// Acquire the mapping lock and update port mappings
if (TryEnterCriticalSection(&s_PortMappingUpdateLock)) {
// If the stop event is set, bail out now
if (WaitForSingleObject(s_StopEvent, 0) == WAIT_OBJECT_0) {
LeaveCriticalSection(&s_PortMappingUpdateLock);
return 0;
}
UpdatePortMappings(gameStreamEnabled);
LeaveCriticalSection(&s_PortMappingUpdateLock);
}
// Refresh when half the duration is expired or if an IP interface // Refresh when half the duration is expired or if an IP interface
// change event occurs. // change event occurs.
@@ -895,7 +960,7 @@ int Run()
ULONGLONG beforeSleepTime = GetTickCount64(); ULONGLONG beforeSleepTime = GetTickCount64();
DWORD ret = WaitForMultipleObjects(ARRAYSIZE(events), events, false, POLLING_DELAY_SEC * 1000); DWORD ret = WaitForMultipleObjects(ARRAYSIZE(events), events, false, POLLING_DELAY_SEC * 1000);
if (ret == WAIT_OBJECT_0) { if (ret == WAIT_OBJECT_0) {
ResetLogFile(); ResetLogFile(standaloneExe);
printf("Woke up for interface change notification after %lld seconds" NL, printf("Woke up for interface change notification after %lld seconds" NL,
(GetTickCount64() - beforeSleepTime) / 1000); (GetTickCount64() - beforeSleepTime) / 1000);
@@ -904,13 +969,17 @@ int Run()
Sleep(10000); Sleep(10000);
} }
else if (ret == WAIT_OBJECT_0 + 1) { else if (ret == WAIT_OBJECT_0 + 1) {
ResetLogFile(); ResetLogFile(standaloneExe);
printf("Woke up for GameStream state change notification after %lld seconds" NL, printf("Woke up for GameStream state change notification after %lld seconds" NL,
(GetTickCount64() - beforeSleepTime) / 1000); (GetTickCount64() - beforeSleepTime) / 1000);
} }
else if (ret == WAIT_OBJECT_0 + 2) {
printf("Woke up for stop notification" NL);
return 0;
}
else { else {
ResetLogFile(); ResetLogFile(standaloneExe);
printf("Woke up for periodic refresh" NL); printf("Woke up for periodic refresh" NL);
} }
@@ -930,14 +999,21 @@ HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpConte
return NO_ERROR; return NO_ERROR;
case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_STOP:
// Stop future port mapping updates
SetEvent(s_StopEvent);
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwControlsAccepted = 0; ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwWaitHint = 120 * 1000; // 2 minutes
SetServiceStatus(ServiceStatusHandle, &ServiceStatus); SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
// Remove existing port mappings
EnterCriticalSection(&s_PortMappingUpdateLock);
printf("Removing UPnP/NAT-PMP/PCP rules after service stop request\n"); printf("Removing UPnP/NAT-PMP/PCP rules after service stop request\n");
UpdatePortMappings(false); UpdatePortMappings(false);
LeaveCriticalSection(&s_PortMappingUpdateLock);
printf("The service is stopping\n"); printf("The service is stopping now\n");
ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus); SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
return NO_ERROR; return NO_ERROR;
@@ -959,6 +1035,14 @@ ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
return; return;
} }
err = Initialize();
if (err != 0) {
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = err;
SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
return;
}
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwWin32ExitCode = NO_ERROR; ServiceStatus.dwWin32ExitCode = NO_ERROR;
@@ -971,7 +1055,7 @@ ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
SetServiceStatus(ServiceStatusHandle, &ServiceStatus); SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
// Start the service // Start the service
err = Run(); err = Run(false);
if (err != 0) { if (err != 0) {
ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = err; ServiceStatus.dwWin32ExitCode = err;
@@ -994,8 +1078,8 @@ int main(int argc, char* argv[])
} }
if (argc == 2 && !strcmp(argv[1], "exe")) { if (argc == 2 && !strcmp(argv[1], "exe")) {
Run(); Initialize();
return 0; return Run(true);
} }
return StartServiceCtrlDispatcher(ServiceTable); return StartServiceCtrlDispatcher(ServiceTable);
+24 -2
View File
@@ -93,13 +93,19 @@
<PrecompiledHeaderFile> <PrecompiledHeaderFile>
</PrecompiledHeaderFile> </PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<ControlFlowGuard>Guard</ControlFlowGuard>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>..\libs\x86\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\x86\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<CETCompat>true</CETCompat>
</Link> </Link>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Debug\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
@@ -111,11 +117,17 @@
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile> <PrecompiledHeaderFile>
</PrecompiledHeaderFile> </PrecompiledHeaderFile>
<ControlFlowGuard>Guard</ControlFlowGuard>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<CETCompat>true</CETCompat>
</Link> </Link>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Debug\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
@@ -130,7 +142,8 @@
<PrecompiledHeaderFile> <PrecompiledHeaderFile>
</PrecompiledHeaderFile> </PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -138,7 +151,11 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>..\libs\x86\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\x86\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<CETCompat>true</CETCompat>
</Link> </Link>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Release\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
@@ -152,13 +169,18 @@
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile> <PrecompiledHeaderFile>
</PrecompiledHeaderFile> </PrecompiledHeaderFile>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<CETCompat>true</CETCompat>
</Link> </Link>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Release\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="miss.cpp" /> <ClCompile Include="miss.cpp" />
+1 -1
View File
@@ -118,7 +118,7 @@ bool PCPMapPort(PSOCKADDR_STORAGE localAddr, int localAddrLen, PSOCKADDR_STORAGE
int bytesRead; int bytesRead;
union { union {
PCP_MAP_RESPONSE hdr; PCP_MAP_RESPONSE hdr;
char buf[1024]; char buf[1100];
} resp; } resp;
int lifetime; int lifetime;
+20 -22
View File
@@ -19,34 +19,28 @@ WINAPI
UdpRelayThreadProc(LPVOID Context) UdpRelayThreadProc(LPVOID Context)
{ {
PUDP_TUPLE tuple = (PUDP_TUPLE)Context; PUDP_TUPLE tuple = (PUDP_TUPLE)Context;
fd_set fds; USHORT nboPort = htons(tuple->port);
int err;
SOCKADDR_IN lastRemoteAddr; SOCKADDR_IN lastRemoteAddr;
// Ensure the relay threads aren't preempted by games or other CPU intensive activity
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
RtlZeroMemory(&lastRemoteAddr, sizeof(lastRemoteAddr)); RtlZeroMemory(&lastRemoteAddr, sizeof(lastRemoteAddr));
for (;;) { for (;;) {
char buffer[4096]; char buffer[4096];
SOCKADDR_IN sourceAddr; SOCKADDR_IN sourceAddr;
int sourceAddrLen; int sourceAddrLen;
int recvLen;
FD_ZERO(&fds);
FD_SET(tuple->socket, &fds);
err = select(0, &fds, NULL, NULL, NULL);
if (err <= 0) {
break;
}
sourceAddrLen = sizeof(sourceAddr); sourceAddrLen = sizeof(sourceAddr);
err = recvfrom(tuple->socket, buffer, sizeof(buffer), 0, (PSOCKADDR)&sourceAddr, &sourceAddrLen); recvLen = recvfrom(tuple->socket, buffer, sizeof(buffer), 0, (PSOCKADDR)&sourceAddr, &sourceAddrLen);
if (err == SOCKET_ERROR) { if (recvLen == SOCKET_ERROR) {
continue; continue;
} }
SOCKADDR_IN destinationAddr; SOCKADDR_IN destinationAddr;
if (RtlEqualMemory(&sourceAddr.sin_addr, &in4addr_loopback, sizeof(sourceAddr.sin_addr))) { if (RtlEqualMemory(&sourceAddr.sin_addr, &in4addr_loopback, sizeof(sourceAddr.sin_addr)) && sourceAddr.sin_port == nboPort) {
// Traffic incoming from loopback interface - send it to the last remote address // Traffic incoming from loopback interface - send it to the last remote address
destinationAddr = lastRemoteAddr; destinationAddr = lastRemoteAddr;
} }
@@ -57,10 +51,10 @@ UdpRelayThreadProc(LPVOID Context)
// Send it to the normal port via the loopback adapter // Send it to the normal port via the loopback adapter
destinationAddr = sourceAddr; destinationAddr = sourceAddr;
destinationAddr.sin_addr = in4addr_loopback; destinationAddr.sin_addr = in4addr_loopback;
destinationAddr.sin_port = htons(tuple->port); destinationAddr.sin_port = nboPort;
} }
sendto(tuple->socket, buffer, err, 0, (PSOCKADDR)&destinationAddr, sizeof(destinationAddr)); sendto(tuple->socket, buffer, recvLen, 0, (PSOCKADDR)&destinationAddr, sizeof(destinationAddr));
} }
closesocket(tuple->socket); closesocket(tuple->socket);
@@ -74,11 +68,13 @@ int StartUdpRelay(unsigned short Port)
SOCKADDR_IN addr; SOCKADDR_IN addr;
HANDLE thread; HANDLE thread;
PUDP_TUPLE tuple; PUDP_TUPLE tuple;
int error;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
printf("socket() failed: %d\n", WSAGetLastError()); error = WSAGetLastError();
return WSAGetLastError(); printf("socket() failed: %d\n", error);
return error;
} }
// Bind to the alternate port // Bind to the alternate port
@@ -86,9 +82,10 @@ int StartUdpRelay(unsigned short Port)
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(Port + RELAY_PORT_OFFSET); addr.sin_port = htons(Port + RELAY_PORT_OFFSET);
if (bind(sock, (PSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) { if (bind(sock, (PSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) {
printf("bind() failed: %d\n", WSAGetLastError()); error = WSAGetLastError();
printf("bind() failed: %d\n", error);
closesocket(sock); closesocket(sock);
return WSAGetLastError(); return error;
} }
tuple = (PUDP_TUPLE)malloc(sizeof(*tuple)); tuple = (PUDP_TUPLE)malloc(sizeof(*tuple));
@@ -101,9 +98,10 @@ int StartUdpRelay(unsigned short Port)
thread = CreateThread(NULL, 0, UdpRelayThreadProc, tuple, 0, NULL); thread = CreateThread(NULL, 0, UdpRelayThreadProc, tuple, 0, NULL);
if (thread == NULL) { if (thread == NULL) {
printf("CreateThread() failed: %d\n", GetLastError()); error = GetLastError();
printf("CreateThread() failed: %d\n", error);
closesocket(sock); closesocket(sock);
return GetLastError(); return error;
} }
CloseHandle(thread); CloseHandle(thread);
+153 -50
View File
@@ -29,6 +29,8 @@
#define LOOPBACK_SERVER_PORT_OFFSET -10000 #define LOOPBACK_SERVER_PORT_OFFSET -10000
#define GAA_INITIAL_SIZE 8192
static struct port_entry { static struct port_entry {
int proto; int proto;
int port; int port;
@@ -400,12 +402,42 @@ bool IsZeroTierInstalled()
return true; return true;
} }
PIP_ADAPTER_ADDRESSES
AllocAndGetAdaptersAddresses(ULONG Family, ULONG Flags)
{
PIP_ADAPTER_ADDRESSES addresses;
ULONG length;
ULONG error;
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 NULL;
}
error = GetAdaptersAddresses(Family, Flags, NULL, addresses, &length);
} while (error == ERROR_BUFFER_OVERFLOW);
if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error);
free(addresses);
return NULL;
}
return addresses;
}
enum PortTestStatus { enum PortTestStatus {
PortTestOk, PortTestOk,
PortTestError, PortTestError,
PortTestUnknown PortTestUnknown
}; };
PortTestStatus TestPort(PSOCKADDR_STORAGE addr, int proto, int port, bool withServer, bool isLoopbackRelay) PortTestStatus TestPort(PSOCKADDR_STORAGE addr, PSOCKADDR_STORAGE localBindAddr, int proto, int port, bool withServer, bool isLoopbackRelay, bool mtuTest)
{ {
SOCKET clientSock = INVALID_SOCKET, serverSock = INVALID_SOCKET; SOCKET clientSock = INVALID_SOCKET, serverSock = INVALID_SOCKET;
int err; int err;
@@ -466,6 +498,21 @@ PortTestStatus TestPort(PSOCKADDR_STORAGE addr, int proto, int port, bool withSe
} }
} }
// Perform the explicit bind if a local address was provided
if (localBindAddr != nullptr) {
SOCKADDR_IN6 bind6;
int addrLen = localBindAddr->ss_family == AF_INET ?
sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6);
RtlCopyMemory(&bind6, localBindAddr, addrLen);
bind6.sin6_port = 0;
err = bind(clientSock, (struct sockaddr*)&bind6, addrLen);
if (err == SOCKET_ERROR) {
fprintf(LOG_OUT, "bind() failed: %d\n", WSAGetLastError());
}
}
ULONG nbIo = 1; ULONG nbIo = 1;
err = ioctlsocket(clientSock, FIONBIO, &nbIo); err = ioctlsocket(clientSock, FIONBIO, &nbIo);
if (err == SOCKET_ERROR) { if (err == SOCKET_ERROR) {
@@ -530,11 +577,14 @@ PortTestStatus TestPort(PSOCKADDR_STORAGE addr, int proto, int port, bool withSe
return err == 1 ? PortTestOk : PortTestError; return err == 1 ? PortTestOk : PortTestError;
} }
else { 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 // Send several test packets to ensure a random lost packet doesn't make the test fail
for (int i = 0; i < 5; i++) { 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) { if (err == SOCKET_ERROR) {
fprintf(LOG_OUT, "sendto() failed: %d\n", WSAGetLastError()); fprintf(LOG_OUT, "sendto() failed: %d\n", WSAGetLastError());
closesocket(clientSock); closesocket(clientSock);
@@ -668,7 +718,7 @@ Exit:
return result; return result;
} }
bool TestAllPorts(PSOCKADDR_STORAGE addr, char* portMsg, int portMsgLen, bool isLoopbackRelay, bool consolePrint, bool* allPortsFailed = nullptr) bool TestAllPorts(PSOCKADDR_STORAGE addr, PSOCKADDR_STORAGE localBindAddr, char* portMsg, int portMsgLen, bool isLoopbackRelay, bool consolePrint, bool* allPortsFailed = nullptr)
{ {
bool ret = true; bool ret = true;
@@ -685,9 +735,12 @@ bool TestAllPorts(PSOCKADDR_STORAGE addr, char* portMsg, int portMsgLen, bool is
k_Ports[i].port); k_Ports[i].port);
} }
if (!k_Ports[i].withServer) { if (!k_Ports[i].withServer && (localBindAddr == nullptr || localBindAddr->ss_family == AF_INET)) {
// Test using a real HTTP client if the port wasn't totally dead. // Test using a real HTTP client if the port wasn't totally dead.
// This is required to confirm functionality with the loopback relay. // This is required to confirm functionality with the loopback relay.
// NB: We can't do this with IPv6 because we're not guaranteed that our outbound traffic
// will go out on the correct local IPv6 address, preventing a response from making
// it back.
assert(k_Ports[i].proto == IPPROTO_TCP); assert(k_Ports[i].proto == IPPROTO_TCP);
fprintf(LOG_OUT, "Testing TCP %d with HTTP traffic...", k_Ports[i].port); fprintf(LOG_OUT, "Testing TCP %d with HTTP traffic...", k_Ports[i].port);
status = TestHttpPort(addr, k_Ports[i].port, isLoopbackRelay); status = TestHttpPort(addr, k_Ports[i].port, isLoopbackRelay);
@@ -696,7 +749,8 @@ bool TestAllPorts(PSOCKADDR_STORAGE addr, char* portMsg, int portMsgLen, bool is
fprintf(LOG_OUT, "Testing %s %d...", fprintf(LOG_OUT, "Testing %s %d...",
k_Ports[i].proto == IPPROTO_TCP ? "TCP" : "UDP", k_Ports[i].proto == IPPROTO_TCP ? "TCP" : "UDP",
k_Ports[i].port); k_Ports[i].port);
status = TestPort(addr, k_Ports[i].proto, k_Ports[i].port, k_Ports[i].withServer, isLoopbackRelay); status = TestPort(addr, localBindAddr, k_Ports[i].proto, k_Ports[i].port,
k_Ports[i].withServer, isLoopbackRelay, k_Ports[i].port == 47998);
} }
if (status != PortTestOk) { if (status != PortTestOk) {
@@ -855,6 +909,71 @@ bool FindLocalInterfaceIPAddress(int family, PSOCKADDR_STORAGE addr)
inet_ntop(AF_INET, &((struct sockaddr_in*)addr)->sin_addr, addrStr, sizeof(addrStr)); inet_ntop(AF_INET, &((struct sockaddr_in*)addr)->sin_addr, addrStr, sizeof(addrStr));
} }
else { else {
// There may be multiple IPv6 addresses on this interface, and chances are that the
// outbound address is a temporary IPv6 address which is not meant to receive traffic.
// Let's look up a suitable address by finding the correct interface and looking for
// an address with a non-random suffix.
PIP_ADAPTER_ADDRESSES addresses;
PIP_ADAPTER_ADDRESSES currentAdapter;
PIP_ADAPTER_UNICAST_ADDRESS currentAddress;
addresses = AllocAndGetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME);
if (addresses == NULL) {
return false;
}
// First, find the interface that owns the incoming address
currentAdapter = addresses;
while (currentAdapter != NULL) {
// Check if this interface has the IPv6 address we want
currentAddress = currentAdapter->FirstUnicastAddress;
while (currentAddress != NULL) {
if (currentAddress->Address.lpSockaddr->sa_family == AF_INET6) {
PSOCKADDR_IN6 ifaceAddrV6 = (PSOCKADDR_IN6)currentAddress->Address.lpSockaddr;
if (RtlEqualMemory(&((struct sockaddr_in6*)addr)->sin6_addr, &ifaceAddrV6->sin6_addr, sizeof(IN6_ADDR))) {
break;
}
}
currentAddress = currentAddress->Next;
}
if (currentAddress != NULL) {
// It does, bail out
break;
}
currentAdapter = currentAdapter->Next;
}
// Check if we found the incoming interface. If not, we'll
// just return the IP address as given from getsockname().
if (currentAdapter != NULL) {
// Now find a non-privacy/non-LL IPv6 address on this interface
currentAddress = currentAdapter->FirstUnicastAddress;
while (currentAddress != NULL) {
if (currentAddress->Address.lpSockaddr->sa_family == AF_INET6) {
// Exclude link-local and privacy addresses and deprecated addresses
PSOCKADDR_IN6 currentAddrV6 = (PSOCKADDR_IN6)currentAddress->Address.lpSockaddr;
if (currentAddrV6->sin6_scope_id == 0 &&
currentAddress->SuffixOrigin != IpSuffixOriginRandom &&
currentAddress->DadState != IpDadStateDeprecated) {
RtlCopyMemory(addr, currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength);
break;
}
}
currentAddress = currentAddress->Next;
}
}
free(addresses);
inet_ntop(AF_INET6, &((struct sockaddr_in6*)addr)->sin6_addr, addrStr, sizeof(addrStr)); inet_ntop(AF_INET6, &((struct sockaddr_in6*)addr)->sin6_addr, addrStr, sizeof(addrStr));
} }
fprintf(LOG_OUT, "%s\n", addrStr); fprintf(LOG_OUT, "%s\n", addrStr);
@@ -864,31 +983,21 @@ bool FindLocalInterfaceIPAddress(int family, PSOCKADDR_STORAGE addr)
bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr) bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
{ {
union { PIP_ADAPTER_ADDRESSES addresses;
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
ULONG error;
ULONG length;
PIP_ADAPTER_ADDRESSES currentAdapter; PIP_ADAPTER_ADDRESSES currentAdapter;
PIP_ADAPTER_UNICAST_ADDRESS currentAddress; PIP_ADAPTER_UNICAST_ADDRESS currentAddress;
// Get all IPv4 interfaces // Get all IPv4 interfaces
length = sizeof(buffer); addresses = AllocAndGetAdaptersAddresses(AF_INET,
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME, GAA_FLAG_SKIP_FRIENDLY_NAME);
NULL, if (addresses == nullptr) {
&addresses,
&length);
if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error);
return false; return false;
} }
currentAdapter = &addresses; currentAdapter = addresses;
while (currentAdapter != NULL) { while (currentAdapter != NULL) {
// Look for ones that correspond to a ZeroTier device // Look for ones that correspond to a ZeroTier device
if (wcsstr(currentAdapter->Description, L"ZeroTier")) { if (wcsstr(currentAdapter->Description, L"ZeroTier")) {
@@ -897,6 +1006,7 @@ bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
while (currentAddress != NULL) { while (currentAddress != NULL) {
if (currentAddress->Address.lpSockaddr->sa_family == AF_INET) { if (currentAddress->Address.lpSockaddr->sa_family == AF_INET) {
RtlCopyMemory(addr, currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength); RtlCopyMemory(addr, currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength);
free(addresses);
return true; return true;
} }
@@ -907,17 +1017,14 @@ bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
currentAdapter = currentAdapter->Next; currentAdapter = currentAdapter->Next;
} }
free(addresses);
return false; return false;
} }
bool FindDuplicateDefaultInterfaces(void) bool FindDuplicateDefaultInterfaces(void)
{ {
union { PIP_ADAPTER_ADDRESSES addresses;
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
ULONG error; ULONG error;
ULONG length;
MIB_IPFORWARDROW defaultRoute; MIB_IPFORWARDROW defaultRoute;
PIP_ADAPTER_ADDRESSES currentAdapter; PIP_ADAPTER_ADDRESSES currentAdapter;
DWORD matchingInterfaces = 0; DWORD matchingInterfaces = 0;
@@ -929,23 +1036,18 @@ bool FindDuplicateDefaultInterfaces(void)
} }
// Get all IPv4 interfaces // Get all IPv4 interfaces
length = sizeof(buffer); addresses = AllocAndGetAdaptersAddresses(AF_INET,
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_UNICAST |
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_INCLUDE_GATEWAYS |
GAA_FLAG_SKIP_FRIENDLY_NAME, GAA_FLAG_SKIP_FRIENDLY_NAME);
NULL, if (addresses == nullptr) {
&addresses,
&length);
if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", error);
return false; return false;
} }
currentAdapter = &addresses; currentAdapter = addresses;
while (currentAdapter != NULL) { while (currentAdapter != NULL) {
if (currentAdapter->OperStatus == IfOperStatusUp && if (currentAdapter->OperStatus == IfOperStatusUp &&
currentAdapter->FirstGatewayAddress != NULL && currentAdapter->FirstGatewayAddress != NULL &&
@@ -958,6 +1060,7 @@ bool FindDuplicateDefaultInterfaces(void)
currentAdapter = currentAdapter->Next; currentAdapter = currentAdapter->Next;
} }
free(addresses);
return matchingInterfaces > 1; return matchingInterfaces > 1;
} }
@@ -1002,7 +1105,7 @@ UPnPPortStatus UPnPCheckPort(struct UPNPUrls* urls, struct IGDdatas* data, int p
} }
else if (err == UPNPCOMMAND_SUCCESS) { else if (err == UPNPCOMMAND_SUCCESS) {
if (!strcmp(myAddr, intClient)) { if (!strcmp(myAddr, intClient)) {
fprintf(LOG_OUT, "OK\n"); fprintf(LOG_OUT, "OK (Internal port: %s)\n", intPort);
return OK; return OK;
} }
else { else {
@@ -1299,7 +1402,7 @@ int main(int argc, char* argv[])
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_addr = in4addr_loopback; sin.sin_addr = in4addr_loopback;
fprintf(LOG_OUT, "Testing GameStream ports via loopback\n"); fprintf(LOG_OUT, "Testing GameStream ports via loopback\n");
if (!TestAllPorts(&ss, portMsgBuf, sizeof(portMsgBuf), false, true)) { if (!TestAllPorts(&ss, nullptr, portMsgBuf, sizeof(portMsgBuf), false, true)) {
snprintf(msgBuf, sizeof(msgBuf), snprintf(msgBuf, sizeof(msgBuf),
"Local GameStream connectivity check failed.\n\nFirst, try reinstalling GeForce Experience. If that doesn't resolve the problem, try temporarily disabling your antivirus and firewall."); "Local GameStream connectivity check failed.\n\nFirst, try reinstalling GeForce Experience. If that doesn't resolve the problem, try temporarily disabling your antivirus and firewall.");
DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting"); DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting");
@@ -1333,7 +1436,7 @@ int main(int argc, char* argv[])
// Try to connect via ZeroTier address // Try to connect via ZeroTier address
fprintf(CONSOLE_OUT, "Testing GameStream connectivity using ZeroTier...\n"); fprintf(CONSOLE_OUT, "Testing GameStream connectivity using ZeroTier...\n");
fprintf(LOG_OUT, "Testing GameStream ports via ZeroTier\n"); fprintf(LOG_OUT, "Testing GameStream ports via ZeroTier\n");
if (!TestAllPorts(&ss, portMsgBuf, sizeof(portMsgBuf), false, true)) { if (!TestAllPorts(&ss, nullptr, portMsgBuf, sizeof(portMsgBuf), false, true)) {
snprintf(msgBuf, sizeof(msgBuf), snprintf(msgBuf, sizeof(msgBuf),
"ZeroTier connectivity check failed. This is almost always caused by a firewall on your computer blocking the connection.\n\nTry temporarily disabling your antivirus and firewall."); "ZeroTier connectivity check failed. This is almost always caused by a firewall on your computer blocking the connection.\n\nTry temporarily disabling your antivirus and firewall.");
DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting"); DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting");
@@ -1350,9 +1453,8 @@ int main(int argc, char* argv[])
} }
bool hasV4Connectivity, hasV6Connectivity; bool hasV4Connectivity, hasV6Connectivity;
SOCKADDR_STORAGE v4, v6;
{ {
SOCKADDR_STORAGE v4, v6;
hasV4Connectivity = FindLocalInterfaceIPAddress(AF_INET, &v4); hasV4Connectivity = FindLocalInterfaceIPAddress(AF_INET, &v4);
hasV6Connectivity = FindLocalInterfaceIPAddress(AF_INET6, &v6); hasV6Connectivity = FindLocalInterfaceIPAddress(AF_INET6, &v6);
@@ -1373,7 +1475,7 @@ int main(int argc, char* argv[])
// Try to connect via LAN address // Try to connect via LAN address
fprintf(LOG_OUT, "Testing GameStream ports via local network\n"); fprintf(LOG_OUT, "Testing GameStream ports via local network\n");
if (!TestAllPorts(&ss, portMsgBuf, sizeof(portMsgBuf), false, true)) { if (!TestAllPorts(&ss, nullptr, portMsgBuf, sizeof(portMsgBuf), false, true)) {
snprintf(msgBuf, sizeof(msgBuf), snprintf(msgBuf, sizeof(msgBuf),
"Local network GameStream connectivity check failed. This is almost always caused by a firewall on your computer blocking the connection.\n\nTry temporarily disabling your antivirus and firewall."); "Local network GameStream connectivity check failed. This is almost always caused by a firewall on your computer blocking the connection.\n\nTry temporarily disabling your antivirus and firewall.");
DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting"); DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting");
@@ -1399,7 +1501,7 @@ int main(int argc, char* argv[])
// We don't actually care about the outcome here but it's nice to have in logs // We don't actually care about the outcome here but it's nice to have in logs
// to determine whether solving the double NAT will actually make Moonlight work. // to determine whether solving the double NAT will actually make Moonlight work.
TestAllPorts((PSOCKADDR_STORAGE)&locallyReportedWanAddr, portMsgBuf, sizeof(portMsgBuf), false, false); TestAllPorts((PSOCKADDR_STORAGE)&locallyReportedWanAddr, &ss, portMsgBuf, sizeof(portMsgBuf), false, false);
fprintf(LOG_OUT, "Detected inconsistency between UPnP/NAT-PMP and STUN reported WAN addresses!\n"); fprintf(LOG_OUT, "Detected inconsistency between UPnP/NAT-PMP and STUN reported WAN addresses!\n");
} }
@@ -1438,11 +1540,13 @@ int main(int argc, char* argv[])
testServerWasReachable = true; testServerWasReachable = true;
if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, portMsgBuf, sizeof(portMsgBuf), true, true, &allPortsFailedOnV4)) { if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, &v4, portMsgBuf, sizeof(portMsgBuf), true, true, &allPortsFailedOnV4)) {
freeaddrinfo(result); freeaddrinfo(result);
snprintf(msgBuf, sizeof(msgBuf), "This PC is ready to host over the Internet!\n\n" 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" "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"
"If you can't, you can type the following address into Moonlight's Add PC dialog: %s", wanAddrStr); "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); DisplayMessage(msgBuf, nullptr, MpInfo);
return 0; return 0;
} }
@@ -1468,7 +1572,7 @@ int main(int argc, char* argv[])
// Pass the portMsgBuf only if we've detected an IPv6-only setup. Otherwise, we want to preserve // Pass the portMsgBuf only if we've detected an IPv6-only setup. Otherwise, we want to preserve
// the failing ports from the IPv4 to display in the error dialog. // the failing ports from the IPv4 to display in the error dialog.
if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, if (TestAllPorts((PSOCKADDR_STORAGE)current->ai_addr, &v6,
ss.ss_family == AF_INET6 ? portMsgBuf : NULL, ss.ss_family == AF_INET6 ? portMsgBuf : NULL,
ss.ss_family == AF_INET6 ? sizeof(portMsgBuf) : 0, true, true)) { ss.ss_family == AF_INET6 ? sizeof(portMsgBuf) : 0, true, true)) {
// We will terminate the test at the IPv6 limited connectivity warning in the following cases: // We will terminate the test at the IPv6 limited connectivity warning in the following cases:
@@ -1490,10 +1594,9 @@ int main(int argc, char* argv[])
return 0; return 0;
} }
} }
else {
// Tested against a working server and it failed // Tested against a IPv6 working server
break; break;
}
} }
} }
+24 -2
View File
@@ -93,16 +93,22 @@
<PrecompiledHeaderFile> <PrecompiledHeaderFile>
</PrecompiledHeaderFile> </PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<ControlFlowGuard>Guard</ControlFlowGuard>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>..\libs\x86\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\x86\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<CETCompat>true</CETCompat>
</Link> </Link>
<Manifest> <Manifest>
<AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles> <AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles>
</Manifest> </Manifest>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Debug\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
@@ -113,14 +119,20 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<ControlFlowGuard>Guard</ControlFlowGuard>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<CETCompat>true</CETCompat>
</Link> </Link>
<Manifest> <Manifest>
<AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles> <AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles>
</Manifest> </Manifest>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Debug\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
@@ -135,7 +147,8 @@
<PrecompiledHeaderFile> <PrecompiledHeaderFile>
</PrecompiledHeaderFile> </PrecompiledHeaderFile>
<AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\libs\include;..\libs\include\miniupnpc;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -143,10 +156,14 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>..\libs\x86\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\libs\x86\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<CETCompat>true</CETCompat>
</Link> </Link>
<Manifest> <Manifest>
<AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles> <AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles>
</Manifest> </Manifest>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Release\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
@@ -159,16 +176,21 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<ControlFlowGuard>Guard</ControlFlowGuard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<CETCompat>true</CETCompat>
</Link> </Link>
<Manifest> <Manifest>
<AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles> <AdditionalManifestFiles>mist.exe.manifest</AdditionalManifestFiles>
</Manifest> </Manifest>
<PostBuildEvent>
<Command>copy /Y "$(SolutionDir)libs\x86\Release\*" "$(TargetDir)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="mist.cpp" /> <ClCompile Include="mist.cpp" />
+56 -40
View File
@@ -45,15 +45,20 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
int i; int i;
int bytesRead; int bytesRead;
int err; int err;
bool ret;
PSTUN_ATTRIBUTE_HEADER attribute; PSTUN_ATTRIBUTE_HEADER attribute;
PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE ipv4Attrib; PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE ipv4Attrib;
struct addrinfo* result; struct addrinfo* result;
struct addrinfo hints; struct addrinfo hints;
struct sockaddr_in bindAddr;
union { union {
STUN_MESSAGE hdr; STUN_MESSAGE hdr;
char buf[1024]; char buf[1024];
} resp; } resp;
sock = INVALID_SOCKET;
ret = false;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_flags = AI_ADDRCONFIG; hints.ai_flags = AI_ADDRCONFIG;
@@ -68,18 +73,15 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol); sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
fprintf(LOG_OUT, "socket() failed: %d\n", WSAGetLastError()); fprintf(LOG_OUT, "socket() failed: %d\n", WSAGetLastError());
freeaddrinfo(result); goto Exit;
return false;
} }
struct sockaddr_in bindAddr = {}; bindAddr = {};
bindAddr.sin_family = hints.ai_family; bindAddr.sin_family = hints.ai_family;
bindAddr.sin_port = htons(localPort); bindAddr.sin_port = htons(localPort);
if (bind(sock, (struct sockaddr*)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) { if (bind(sock, (struct sockaddr*)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) {
fprintf(LOG_OUT, "bind() failed: %d\n", WSAGetLastError()); fprintf(LOG_OUT, "bind() failed: %d\n", WSAGetLastError());
closesocket(sock); goto Exit;
freeaddrinfo(result);
return false;
} }
reqMsg.messageType = htons(STUN_MESSAGE_BINDING_REQUEST); reqMsg.messageType = htons(STUN_MESSAGE_BINDING_REQUEST);
@@ -98,57 +100,60 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
} }
} }
fd_set fds; for (;;) {
FD_ZERO(&fds); fd_set fds;
FD_SET(sock, &fds); FD_ZERO(&fds);
FD_SET(sock, &fds);
struct timeval tv; struct timeval tv;
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
int selectRes = select(0, &fds, nullptr, nullptr, &tv); int selectRes = select(0, &fds, nullptr, nullptr, &tv);
if (selectRes == 0) { if (selectRes == 0) {
// Timeout - continue looping // Timeout - break to the enclosing loop
continue; 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());
closesocket(sock);
freeaddrinfo(result);
return false;
}
// Error handling is below
bytesRead = recvfrom(sock, resp.buf, sizeof(resp.buf), 0, NULL, NULL);
break;
} }
freeaddrinfo(result); RecvDone:
closesocket(sock);
if (bytesRead == 0) { if (bytesRead == 0) {
fprintf(LOG_OUT, "No response from STUN server\n"); fprintf(LOG_OUT, "No response from STUN server\n");
return false; goto Exit;
} }
else if (bytesRead == SOCKET_ERROR) { else if (bytesRead == SOCKET_ERROR) {
fprintf(LOG_OUT, "Failed to read STUN binding response: %d\n", WSAGetLastError()); fprintf(LOG_OUT, "Failed to read STUN binding response: %d\n", WSAGetLastError());
return false; goto Exit;
} }
else if (bytesRead < sizeof(resp.hdr)) { else if (bytesRead < sizeof(resp.hdr)) {
fprintf(LOG_OUT, "STUN message truncated: %d\n", bytesRead); fprintf(LOG_OUT, "STUN message truncated: %d\n", bytesRead);
return false; goto Exit;
} }
else if (htonl(resp.hdr.magicCookie) != STUN_MESSAGE_COOKIE) { else if (htonl(resp.hdr.magicCookie) != STUN_MESSAGE_COOKIE) {
fprintf(LOG_OUT, "Bad STUN cookie value: %x\n", htonl(resp.hdr.magicCookie)); fprintf(LOG_OUT, "Bad STUN cookie value: %x\n", htonl(resp.hdr.magicCookie));
return false; goto Exit;
} }
else if (memcmp(reqMsg.transactionId, resp.hdr.transactionId, sizeof(reqMsg.transactionId))) { else if (memcmp(reqMsg.transactionId, resp.hdr.transactionId, sizeof(reqMsg.transactionId))) {
fprintf(LOG_OUT, "STUN transaction ID mismatch\n"); fprintf(LOG_OUT, "STUN transaction ID mismatch\n");
return false; goto Exit;
} }
else if (htons(resp.hdr.messageType) != STUN_MESSAGE_BINDING_SUCCESS) { else if (htons(resp.hdr.messageType) != STUN_MESSAGE_BINDING_SUCCESS) {
fprintf(LOG_OUT, "STUN message type mismatch: %x\n", htons(resp.hdr.messageType)); fprintf(LOG_OUT, "STUN message type mismatch: %x\n", htons(resp.hdr.messageType));
return false; goto Exit;
} }
attribute = (PSTUN_ATTRIBUTE_HEADER)(&resp.hdr + 1); attribute = (PSTUN_ATTRIBUTE_HEADER)(&resp.hdr + 1);
@@ -156,7 +161,7 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
while (bytesRead > sizeof(*attribute)) { while (bytesRead > sizeof(*attribute)) {
if (bytesRead < sizeof(*attribute) + htons(attribute->length)) { if (bytesRead < sizeof(*attribute) + htons(attribute->length)) {
fprintf(LOG_OUT, "STUN attribute out of bounds: %d\n", htons(attribute->length)); fprintf(LOG_OUT, "STUN attribute out of bounds: %d\n", htons(attribute->length));
return false; goto Exit;
} }
// Mask off the comprehension bit // Mask off the comprehension bit
else if ((htons(attribute->type) & 0x7FFF) != STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS) { else if ((htons(attribute->type) & 0x7FFF) != STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS) {
@@ -169,11 +174,11 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
ipv4Attrib = (PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE)attribute; ipv4Attrib = (PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE)attribute;
if (htons(ipv4Attrib->hdr.length) != 8) { if (htons(ipv4Attrib->hdr.length) != 8) {
fprintf(LOG_OUT, "STUN address length mismatch: %d\n", htons(ipv4Attrib->hdr.length)); fprintf(LOG_OUT, "STUN address length mismatch: %d\n", htons(ipv4Attrib->hdr.length));
return false; goto Exit;
} }
else if (ipv4Attrib->addressFamily != 1) { else if (ipv4Attrib->addressFamily != 1) {
fprintf(LOG_OUT, "STUN address family mismatch: %x\n", ipv4Attrib->addressFamily); fprintf(LOG_OUT, "STUN address family mismatch: %x\n", ipv4Attrib->addressFamily);
return false; goto Exit;
} }
*wanAddr = {}; *wanAddr = {};
@@ -183,9 +188,20 @@ bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
wanAddr->sin_port = ipv4Attrib->port ^ (short)resp.hdr.magicCookie; wanAddr->sin_port = ipv4Attrib->port ^ (short)resp.hdr.magicCookie;
wanAddr->sin_addr.S_un.S_addr = ipv4Attrib->address ^ resp.hdr.magicCookie; wanAddr->sin_addr.S_un.S_addr = ipv4Attrib->address ^ resp.hdr.magicCookie;
return true; ret = true;
goto Exit;
} }
fprintf(LOG_OUT, "No XOR mapped address found in STUN response!\n"); fprintf(LOG_OUT, "No XOR mapped address found in STUN response!\n");
return false;
Exit:
if (sock != INVALID_SOCKET) {
closesocket(sock);
}
if (result != NULL) {
freeaddrinfo(result);
}
return ret;
} }
+2 -2
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#define VER_VERSION 5,2,0,0 #define VER_VERSION 5,5,2,0
#define VER_VERSION_STR "5.2.0.0" #define VER_VERSION_STR "5.5.2.0"
#define VER_COMPANYNAME_STR "Moonlight Game Streaming Project" #define VER_COMPANYNAME_STR "Moonlight Game Streaming Project"
#define VER_PRODUCTNAME_STR "Moonlight Internet Hosting Tool" #define VER_PRODUCTNAME_STR "Moonlight Internet Hosting Tool"