Compare commits

..
4 Commits
Author SHA1 Message Date
Cameron Gutman 09cd50b12a Version 4.2 2019-08-08 01:34:09 -07:00
Cameron Gutman d60eda6fa8 Update GS IPv6 Forwarder for release 2019-08-08 01:33:45 -07:00
Cameron Gutman cda9bc6be7 Add support for testing ZeroTier configurations 2019-08-08 01:31:09 -07:00
Cameron Gutman 0008fbbcdb Try all resolved STUN servers 2019-08-08 00:02:53 -07:00
5 changed files with 138 additions and 44 deletions
+106 -2
View File
@@ -211,6 +211,20 @@ bool IsGameStreamEnabled()
}
}
bool IsZeroTierInstalled()
{
DWORD error;
HKEY key;
error = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\ZeroTier, Inc.\\ZeroTier One", 0, KEY_READ | KEY_WOW64_32KEY, &key);
if (error != ERROR_SUCCESS) {
return false;
}
RegCloseKey(key);
return true;
}
enum PortTestStatus {
PortTestOk,
PortTestError,
@@ -554,6 +568,54 @@ bool FindLocalInterfaceIPAddress(int family, PSOCKADDR_STORAGE addr)
return true;
}
bool FindZeroTierInterfaceAddress(PSOCKADDR_STORAGE addr)
{
union {
IP_ADAPTER_ADDRESSES addresses;
char buffer[8192];
};
ULONG error;
ULONG length;
PIP_ADAPTER_ADDRESSES currentAdapter;
PIP_ADAPTER_UNICAST_ADDRESS currentAddress;
// Get all IPv4 interfaces
length = sizeof(buffer);
error = GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
&addresses,
&length);
if (error != ERROR_SUCCESS) {
fprintf(LOG_OUT, "GetAdaptersAddresses() failed: %d\n", WSAGetLastError());
return false;
}
currentAdapter = &addresses;
while (currentAdapter != NULL) {
// Look for ones that correspond to a ZeroTier device
if (wcsstr(currentAdapter->Description, L"ZeroTier")) {
// Check if this interface has the IP address we want
currentAddress = currentAdapter->FirstUnicastAddress;
while (currentAddress != NULL) {
if (currentAddress->Address.lpSockaddr->sa_family == AF_INET) {
RtlCopyMemory(addr, currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength);
return true;
}
currentAddress = currentAddress->Next;
}
}
currentAdapter = currentAdapter->Next;
}
return false;
}
enum UPnPPortStatus {
NOT_FOUND,
OK,
@@ -732,7 +794,7 @@ bool CheckWANAccess(PSOCKADDR_IN wanAddr, PSOCKADDR_IN reportedWanAddr, bool* fo
fprintf(LOG_OUT, "Detecting WAN IP address via STUN...");
fprintf(CONSOLE_OUT, "\tTesting STUN...\n");
if (!getExternalAddressPortIP4(IPPROTO_UDP, 0, wanAddr) && !getExternalAddressPortIP4(IPPROTO_TCP, 0, wanAddr)) {
if (!getExternalAddressPortIP4(0, wanAddr)) {
DisplayMessage("Unable to determine your public IP address. Please check your Internet connection or try again in a few minutes.");
return false;
}
@@ -844,6 +906,49 @@ int main(int argc, char* argv[])
DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting");
return -1;
}
// We do a special limited test pass for ZeroTier
if (IsZeroTierInstalled()) {
fprintf(LOG_OUT, "Found ZeroTier installed\n");
if (!FindZeroTierInterfaceAddress(&ss)) {
DisplayMessage("ZeroTier appears to be installed on this PC, but it's not connected to a network.\n\n"
"If you are trying to host with ZeroTier, connect to your ZeroTier network and restart this test.\n\n"
"If not, click OK and this test will continue assuming you aren't using ZeroTier.",
"https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide#zerotier", MpInfo, false);
}
else {
char zeroTierAddrStr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sin.sin_addr, zeroTierAddrStr, sizeof(zeroTierAddrStr));
fprintf(LOG_OUT, "Found ZeroTier connected with address: %s\n", zeroTierAddrStr);
if (strstr(zeroTierAddrStr, "169.254.")) {
DisplayMessage("ZeroTier is active, but this PC has not been authorized to connect to your ZeroTier network.\n\n"
"Make sure you check the Auth checkbox for all network members on the ZeroTier Networks webpage.",
"https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide#zerotier");
return -1;
}
// Try to connect via ZeroTier address
fprintf(CONSOLE_OUT, "Testing GameStream connectivity using ZeroTier...\n");
fprintf(LOG_OUT, "Testing GameStream ports via ZeroTier\n");
if (!TestAllPorts(&ss, portMsgBuf, sizeof(portMsgBuf), false, true)) {
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.");
DisplayMessage(msgBuf, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting");
return -1;
}
// If we get here, our testing is complete for ZeroTier
snprintf(msgBuf, sizeof(msgBuf), "This PC is ready to host over the Internet with ZeroTier!\n\n"
"Don't forget to connect to your ZeroTier network on your client before streaming over the Internet.\n\n"
"After connecting ZeroTier, type following address into Moonlight's Add PC dialog: %s", zeroTierAddrStr);
DisplayMessage(msgBuf, nullptr, MpInfo);
return 0;
}
}
if (!FindLocalInterfaceIPAddress(AF_INET, &ss) && !FindLocalInterfaceIPAddress(AF_INET6, &ss)) {
DisplayMessage("Unable to perform GameStream connectivity check. Please check your Internet connection and try again.");
@@ -861,7 +966,6 @@ int main(int argc, char* argv[])
return -1;
}
bool igdDisconnected;
SOCKADDR_IN locallyReportedWanAddr;
char wanAddrStr[INET_ADDRSTRLEN];
+3 -1
View File
@@ -7,6 +7,8 @@
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Windows.h>
#include <ws2tcpip.h>
#include <Iphlpapi.h>
#include <WinSock2.h>
#include "..\version.h"
@@ -14,4 +16,4 @@
#define CONSOLE_OUT stdout
#define LOG_OUT stderr
bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN wanAddr);
bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr);
+26 -38
View File
@@ -38,7 +38,7 @@ typedef struct _STUN_MESSAGE {
#pragma pack(pop)
bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN wanAddr)
bool getExternalAddressPortIP4(unsigned short localPort, PSOCKADDR_IN wanAddr)
{
SOCKET sock;
STUN_MESSAGE reqMsg;
@@ -46,32 +46,41 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN
int bytesRead;
int tries;
int timeout;
int err;
PSTUN_ATTRIBUTE_HEADER attribute;
PSTUN_MAPPED_IPV4_ADDRESS_ATTRIBUTE ipv4Attrib;
struct hostent *host;
struct addrinfo* result;
struct addrinfo hints;
union {
STUN_MESSAGE hdr;
char buf[1024];
} resp;
host = gethostbyname("stun.moonlight-stream.org");
if (host == nullptr) {
fprintf(LOG_OUT, "gethostbyname() failed: %d\n", WSAGetLastError());
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_flags = AI_ADDRCONFIG;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
err = getaddrinfo("stun.moonlight-stream.org", "3478", &hints, &result);
if (err != 0 || result == NULL) {
fprintf(LOG_OUT, "getaddrinfo() failed: %d\n", err);
return false;
}
sock = socket(AF_INET, proto == IPPROTO_TCP ? SOCK_STREAM : SOCK_DGRAM, proto);
sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
if (sock == INVALID_SOCKET) {
fprintf(LOG_OUT, "socket() failed: %d\n", WSAGetLastError());
freeaddrinfo(result);
return false;
}
struct sockaddr_in bindAddr = {};
bindAddr.sin_family = AF_INET;
bindAddr.sin_family = hints.ai_family;
bindAddr.sin_port = htons(localPort);
if (bind(sock, (struct sockaddr*)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) {
fprintf(LOG_OUT, "bind() failed: %d\n", WSAGetLastError());
closesocket(sock);
freeaddrinfo(result);
return false;
}
@@ -82,36 +91,13 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN
reqMsg.transactionId[i] = rand();
}
SOCKADDR_IN stunAddr = {};
stunAddr.sin_family = AF_INET;
stunAddr.sin_port = htons(STUN_PORT);
stunAddr.sin_addr = *(struct in_addr*)host->h_addr;
// We'll connect() even for UDP so we can use send()/recv() and share more code
if (connect(sock, (struct sockaddr*)&stunAddr, sizeof(stunAddr)) == SOCKET_ERROR) {
fprintf(LOG_OUT, "connect() failed: %d\n", WSAGetLastError());
closesocket(sock);
return false;
}
// For UDP, we'll do 3 iterations of 1 second each. For TCP,
// we'll do one iteration with a 3 second wait.
if (proto == IPPROTO_TCP) {
tries = 1;
timeout = STUN_RECV_TIMEOUT_SEC;
}
else {
tries = STUN_RECV_TIMEOUT_SEC;
timeout = 1;
}
bytesRead = 0;
for (i = 0; i < tries; i++) {
// Retransmit the request every second until the timeout elapses
if (send(sock, (char *)&reqMsg, sizeof(reqMsg), 0) == SOCKET_ERROR) {
fprintf(LOG_OUT, "send() failed: %d\n", WSAGetLastError());
closesocket(sock);
return false;
for (i = 0; i < STUN_RECV_TIMEOUT_SEC; i++) {
// Retransmit the request every second to all resolved IP addresses until the timeout elapses
for (struct addrinfo* current = result; current != NULL; current = current->ai_next) {
if (sendto(sock, (char*)&reqMsg, sizeof(reqMsg), 0, current->ai_addr, current->ai_addrlen) == SOCKET_ERROR) {
fprintf(LOG_OUT, "sendto() failed: %d\n", WSAGetLastError());
}
}
fd_set fds;
@@ -119,7 +105,7 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN
FD_SET(sock, &fds);
struct timeval tv;
tv.tv_sec = timeout;
tv.tv_sec = 1;
tv.tv_usec = 0;
int selectRes = select(0, &fds, nullptr, nullptr, &tv);
@@ -130,14 +116,16 @@ bool getExternalAddressPortIP4(int proto, unsigned short localPort, PSOCKADDR_IN
else if (selectRes == SOCKET_ERROR) {
fprintf(LOG_OUT, "select() failed: %d\n", WSAGetLastError());
closesocket(sock);
freeaddrinfo(result);
return false;
}
// Error handling is below
bytesRead = recv(sock, resp.buf, sizeof(resp.buf), 0);
bytesRead = recvfrom(sock, resp.buf, sizeof(resp.buf), 0, NULL, NULL);
break;
}
freeaddrinfo(result);
closesocket(sock);
if (bytesRead == 0) {
+2 -2
View File
@@ -1,7 +1,7 @@
#pragma once
#define VER_VERSION 4,1,0,0
#define VER_VERSION_STR "4.1.0.0"
#define VER_VERSION 4,2,0,0
#define VER_VERSION_STR "4.2.0.0"
#define VER_COMPANYNAME_STR "Moonlight Game Streaming Project"
#define VER_PRODUCTNAME_STR "Moonlight Internet Hosting Tool"