You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
11 KiB
415 lines
11 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 2001 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: nathelp.c
|
|
* Content: usage for nat helper DLL
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 02/22/2001 aarono Original
|
|
* 04/16/2001 vanceo Use one of the split DirectPlayNATHelp interfaces only.
|
|
*
|
|
* Notes:
|
|
*
|
|
***************************************************************************/
|
|
#define INITGUID
|
|
|
|
|
|
#define INCL_WINSOCK_API_TYPEDEFS 1 // includes winsock 2 fn proto's, for getprocaddress
|
|
#define FD_SETSIZE 1
|
|
#include <winsock2.h>
|
|
#include <initguid.h>
|
|
#include "dpsp.h"
|
|
#include "mmsystem.h"
|
|
#include "dphelp.h"
|
|
|
|
#if USE_NATHELP
|
|
#include "dpnathlp.h"
|
|
|
|
|
|
extern HRESULT GetNATHelpDLLFromRegistry(LPGUID lpguidSP, LPBYTE lpszNATHelpDLL, DWORD cbszNATHelpDLL);
|
|
|
|
|
|
HMODULE g_hNatHelp = NULL; // module handle for dpnhxxx.dll
|
|
DPNHHANDLE g_hNatHelpUDP = 0;
|
|
IDirectPlayNATHelp *g_pINatHelp=NULL; // interface pointer for IDirectPlayNATHelp object
|
|
DPNHCAPS g_NatHelpCaps;
|
|
|
|
BOOL natGetCapsUpdate(VOID)
|
|
{
|
|
HRESULT hr;
|
|
//
|
|
// Get Nat Capabilities - may block for a second.
|
|
//
|
|
|
|
memset(&g_NatHelpCaps,0,sizeof(DPNHCAPS));
|
|
g_NatHelpCaps.dwSize=sizeof(DPNHCAPS);
|
|
hr=IDirectPlayNATHelp_GetCaps(g_pINatHelp, &g_NatHelpCaps, DPNHGETCAPS_UPDATESERVERSTATUS);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
DPF(0,"NatHelp failed to GetCaps, hr=%x\n",hr);
|
|
return FALSE;
|
|
}
|
|
|
|
if (hr == DPNHSUCCESS_ADDRESSESCHANGED)
|
|
{
|
|
DPF(1,"NAT Help reports addresses changed.");
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
/*=============================================================================
|
|
|
|
natInit - Initialize nat helper i/f
|
|
|
|
Description:
|
|
|
|
|
|
Parameters:
|
|
|
|
pgd - Service Provider's global data blob for this instance
|
|
|
|
Return Values:
|
|
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
BOOL natInit(VOID)
|
|
{
|
|
HRESULT hr;
|
|
char szNATHelpPath[256];
|
|
PFN_DIRECTPLAYNATHELPCREATE pfnNatHelpCreate = NULL;
|
|
char *apszNATHelps[3];
|
|
HMODULE ahNatHelps[3];
|
|
IDirectPlayNATHelp *apINatHelps[3];
|
|
DPNHCAPS adpnhcNatHelpCaps[3];
|
|
DWORD dwNumNatHelps = 0;
|
|
DWORD dwCurrentNatHelp;
|
|
|
|
|
|
memset(ahNatHelps, 0, sizeof(ahNatHelps));
|
|
memset(apINatHelps, 0, sizeof(apINatHelps));
|
|
|
|
//
|
|
// See if there's a registry setting.
|
|
//
|
|
hr = GetNATHelpDLLFromRegistry((LPGUID) (&DPSPGUID_TCPIP), szNATHelpPath, 256);
|
|
if (hr == S_OK)
|
|
{
|
|
DPF(1, "Got NAT Help DLL \"%s\" from registry.\n", szNATHelpPath);
|
|
apszNATHelps[dwNumNatHelps++] = szNATHelpPath;
|
|
}
|
|
else
|
|
{
|
|
DPF(4, "Couldn't get NAT Help DLL from registry, hr=%x.\n", hr);
|
|
}
|
|
|
|
//
|
|
// Add the default entries if the registry didn't already specify them.
|
|
//
|
|
if (_strnicmp(szNATHelpPath + strlen(szNATHelpPath) - strlen("dpnhupnp.dll"), "dpnhupnp.dll", strlen("dpnhupnp.dll")) != 0)
|
|
{
|
|
apszNATHelps[dwNumNatHelps++] = "dpnhupnp.dll";
|
|
}
|
|
if (_strnicmp(szNATHelpPath + strlen(szNATHelpPath) - strlen("dpnhpast.dll"), "dpnhpast.dll", strlen("dpnhpast.dll")) != 0)
|
|
{
|
|
apszNATHelps[dwNumNatHelps++] = "dpnhpast.dll";
|
|
}
|
|
|
|
//
|
|
// Loop through the registry specified and default NAT Helpers and attempt
|
|
// to load them.
|
|
//
|
|
for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
|
|
{
|
|
g_hNatHelp = LoadLibrary(apszNATHelps[dwCurrentNatHelp]);
|
|
if (g_hNatHelp != NULL)
|
|
{
|
|
pfnNatHelpCreate = (PFN_DIRECTPLAYNATHELPCREATE) GetProcAddress(g_hNatHelp,
|
|
"DirectPlayNATHelpCreate");
|
|
if (pfnNatHelpCreate != NULL)
|
|
{
|
|
hr = pfnNatHelpCreate(&IID_IDirectPlayNATHelp, (void **) (&g_pINatHelp));
|
|
if (hr == DP_OK)
|
|
{
|
|
//
|
|
// Initialize the NAT Helper interface.
|
|
//
|
|
hr = IDirectPlayNATHelp_Initialize(g_pINatHelp, 0);
|
|
if (hr == DP_OK)
|
|
{
|
|
//
|
|
// Get the capabilities. If it succeeds, remember the information and move on.
|
|
//
|
|
if (natGetCapsUpdate())
|
|
{
|
|
DPF(3, "Successfully retrieved caps for NAT Help \"%s\", flags = 0x%x.",
|
|
apszNATHelps[dwCurrentNatHelp], g_NatHelpCaps.dwFlags);
|
|
ahNatHelps[dwCurrentNatHelp] = g_hNatHelp;
|
|
g_hNatHelp = NULL;
|
|
apINatHelps[dwCurrentNatHelp] = g_pINatHelp;
|
|
g_pINatHelp = NULL;
|
|
memcpy(&adpnhcNatHelpCaps[dwCurrentNatHelp], &g_NatHelpCaps, sizeof(DPNHCAPS));
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
DPF(0, "Couldn't get NAT Help \"%s\" caps, hr=%x!", apszNATHelps[dwCurrentNatHelp], hr);
|
|
}
|
|
|
|
IDirectPlayNATHelp_Close(g_pINatHelp, 0);
|
|
}
|
|
else
|
|
{
|
|
DPF(0, "NAT Help \"%s\" failed to initialize, hr=%x!", apszNATHelps[dwCurrentNatHelp], hr);
|
|
}
|
|
|
|
IDirectPlayNATHelp_Release(g_pINatHelp);
|
|
g_pINatHelp = NULL;
|
|
}
|
|
else
|
|
{
|
|
DPF(0, "Couldn't create NAT Help \"%s\" interface, hr = %x!", apszNATHelps[dwCurrentNatHelp], hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF(0, "Couldn't get NAT Help DLL \"%s\" entry point!", apszNATHelps[dwCurrentNatHelp]);
|
|
}
|
|
|
|
FreeLibrary(g_hNatHelp);
|
|
g_hNatHelp = NULL;
|
|
}
|
|
else
|
|
{
|
|
DPF(0, "Couldn't load NAT Help DLL \"%s\"!", apszNATHelps[dwCurrentNatHelp]);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Now go through and pick the first helper that detected a NAT.
|
|
//
|
|
for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
|
|
{
|
|
if ((apINatHelps[dwCurrentNatHelp] != NULL) &&
|
|
(adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags & DPNHCAPSFLAG_GATEWAYPRESENT))
|
|
{
|
|
DPF(2, "Gateway detected by NAT Help \"%s\", flags = 0x%x.",
|
|
apszNATHelps[dwCurrentNatHelp], adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags);
|
|
g_hNatHelp = ahNatHelps[dwCurrentNatHelp];
|
|
ahNatHelps[dwCurrentNatHelp] = NULL;
|
|
g_pINatHelp = apINatHelps[dwCurrentNatHelp];
|
|
apINatHelps[dwCurrentNatHelp] = NULL;
|
|
memcpy(&g_NatHelpCaps, &adpnhcNatHelpCaps[dwCurrentNatHelp], sizeof(DPNHCAPS));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we didn't get a helper that way, pick the first one that detected a firewall.
|
|
//
|
|
if (g_pINatHelp != NULL)
|
|
{
|
|
for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
|
|
{
|
|
if ((apINatHelps[dwCurrentNatHelp] != NULL) &&
|
|
(adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags & DPNHCAPSFLAG_LOCALFIREWALLPRESENT))
|
|
{
|
|
DPF(2, "Firewall detected by NAT Help \"%s\", flags = 0x%x.",
|
|
apszNATHelps[dwCurrentNatHelp], adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags);
|
|
g_hNatHelp = ahNatHelps[dwCurrentNatHelp];
|
|
ahNatHelps[dwCurrentNatHelp] = NULL;
|
|
g_pINatHelp = apINatHelps[dwCurrentNatHelp];
|
|
apINatHelps[dwCurrentNatHelp] = NULL;
|
|
memcpy(&g_NatHelpCaps, &adpnhcNatHelpCaps[dwCurrentNatHelp], sizeof(DPNHCAPS));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now go through and release all the other NAT helpers, or pick the first one that
|
|
// successfully loaded if we didn't pick one already.
|
|
//
|
|
for(dwCurrentNatHelp = 0; dwCurrentNatHelp < dwNumNatHelps; dwCurrentNatHelp++)
|
|
{
|
|
if (apINatHelps[dwCurrentNatHelp] != NULL)
|
|
{
|
|
if (g_pINatHelp == NULL)
|
|
{
|
|
DPF(2, "Using first loaded NAT Help \"%s\", flags = 0x%x.",
|
|
apszNATHelps[dwCurrentNatHelp], adpnhcNatHelpCaps[dwCurrentNatHelp].dwFlags);
|
|
g_hNatHelp = ahNatHelps[dwCurrentNatHelp];
|
|
ahNatHelps[dwCurrentNatHelp] = NULL;
|
|
g_pINatHelp = apINatHelps[dwCurrentNatHelp];
|
|
apINatHelps[dwCurrentNatHelp] = NULL;
|
|
memcpy(&g_NatHelpCaps, &adpnhcNatHelpCaps[dwCurrentNatHelp], sizeof(DPNHCAPS));
|
|
}
|
|
else
|
|
{
|
|
IDirectPlayNATHelp_Close(apINatHelps[dwCurrentNatHelp], 0);
|
|
IDirectPlayNATHelp_Release(apINatHelps[dwCurrentNatHelp]);
|
|
apINatHelps[dwCurrentNatHelp] = NULL;
|
|
FreeLibrary(ahNatHelps[dwCurrentNatHelp]);
|
|
ahNatHelps[dwCurrentNatHelp] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_pINatHelp == NULL)
|
|
{
|
|
DPF(1, "No NAT Help loaded.");
|
|
g_NatHelpCaps.dwRecommendedGetCapsInterval = INFINITE;
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (! (g_NatHelpCaps.dwFlags & DPNHCAPSFLAG_PUBLICADDRESSAVAILABLE))
|
|
{
|
|
DPF(1, "NAT Help loaded, no NAT/firewall detected, or it doesn't currently have a public address (flags = 0x%x).",
|
|
g_NatHelpCaps.dwFlags);
|
|
}
|
|
#endif // DEBUG
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*=============================================================================
|
|
|
|
natFini - Shut down NATHELP support
|
|
|
|
|
|
Description:
|
|
|
|
|
|
Parameters:
|
|
|
|
pgd - Service Provider's global data blob for this instance
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
VOID natFini(VOID)
|
|
{
|
|
|
|
// natDeregisterPorts(pgd); - vance says we don't need to do this.
|
|
if(g_pINatHelp)
|
|
{
|
|
IDirectPlayNATHelp_Close(g_pINatHelp, 0);
|
|
g_hNatHelpUDP = 0;
|
|
IDirectPlayNATHelp_Release(g_pINatHelp);
|
|
g_pINatHelp=NULL;
|
|
}
|
|
|
|
if(g_hNatHelp)
|
|
{
|
|
FreeLibrary(g_hNatHelp);
|
|
g_hNatHelp=NULL;
|
|
}
|
|
|
|
}
|
|
|
|
/*=============================================================================
|
|
|
|
natRegisterUDPPort - Get a port mapping.
|
|
|
|
|
|
Description:
|
|
|
|
Map the shared port
|
|
|
|
Parameters:
|
|
|
|
pgd - Service Provider's global data blob for this instance
|
|
|
|
Return Values:
|
|
|
|
None.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
HRESULT natRegisterUDPPort(WORD port)
|
|
{
|
|
SOCKADDR_IN sockaddr_in, sockaddr_inpublic;
|
|
DWORD dwFlags, dwSize;
|
|
DPNHHANDLE hPortMapping;
|
|
HRESULT hr;
|
|
|
|
|
|
if (!g_hNatHelpUDP)
|
|
{
|
|
memset(&sockaddr_in , 0 ,sizeof(sockaddr_in));
|
|
sockaddr_in.sin_family = AF_INET;
|
|
sockaddr_in.sin_addr.S_un.S_addr= INADDR_ANY;
|
|
sockaddr_in.sin_port = port; // port is already in network byte order
|
|
|
|
dwFlags = DPNHREGISTERPORTS_SHAREDPORTS|DPNHREGISTERPORTS_FIXEDPORTS;
|
|
|
|
hr = IDirectPlayNATHelp_RegisterPorts(g_pINatHelp, (SOCKADDR *)&sockaddr_in, sizeof(sockaddr_in), 1, 15*60000, &hPortMapping, dwFlags);
|
|
if (hr != DPNH_OK)
|
|
{
|
|
DPF(0,"NATHelp_RegisterPorts failed, hr=%x",hr);
|
|
hr = DPERR_GENERIC;
|
|
}
|
|
else
|
|
{
|
|
dwSize=sizeof(sockaddr_inpublic);
|
|
hr = IDirectPlayNATHelp_GetRegisteredAddresses(g_pINatHelp, hPortMapping, (SOCKADDR *)&sockaddr_inpublic, &dwSize, NULL, NULL, 0);
|
|
switch (hr)
|
|
{
|
|
case DPNH_OK:
|
|
{
|
|
DEBUGPRINTADDR(2, "NATHelp successfully mapped port to ", (SOCKADDR *)&sockaddr_inpublic);
|
|
|
|
g_hNatHelpUDP = hPortMapping;
|
|
|
|
//hr = DP_OK;
|
|
break;
|
|
}
|
|
|
|
case DPNHERR_PORTUNAVAILABLE:
|
|
{
|
|
DPF(0, "NATHelp reported port %u is unavailable!",
|
|
MAKEWORD(HIBYTE(port), LOBYTE(port)));
|
|
|
|
hr = IDirectPlayNATHelp_DeregisterPorts(g_pINatHelp, hPortMapping, 0);
|
|
if (hr != DP_OK)
|
|
{
|
|
DPF(0,"NATHelp_DeregisterPorts PAST returned 0x%lx\n",hr);
|
|
}
|
|
|
|
hr = DPNHERR_PORTUNAVAILABLE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPF(1, "NATHelp couldn't map port %u, (err = 0x%lx).",
|
|
MAKEWORD(HIBYTE(port), LOBYTE(port)),
|
|
hr);
|
|
|
|
g_hNatHelpUDP = hPortMapping;
|
|
|
|
hr = DPERR_GENERIC;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPF(1, "Already registered port with NAT Help, not registering %u.",
|
|
MAKEWORD(HIBYTE(port), LOBYTE(port)));
|
|
hr = DP_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
#endif
|