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.
2944 lines
74 KiB
2944 lines
74 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1998-2002 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: Utils.cpp
|
|
* Content: Serial service provider utility functions
|
|
*
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 11/25/98 jtk Created
|
|
***************************************************************************/
|
|
|
|
#include "dnwsocki.h"
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// Constant definitions
|
|
//**********************************************************************
|
|
|
|
#define DEFAULT_THREADS_PER_PROCESSOR 3
|
|
|
|
#define REGSUBKEY_DPNATHELP_DIRECTPLAY8PRIORITY L"DirectPlay8Priority"
|
|
#define REGSUBKEY_DPNATHELP_DIRECTPLAY8INITFLAGS L"DirectPlay8InitFlags"
|
|
#define REGSUBKEY_DPNATHELP_GUID L"Guid"
|
|
|
|
|
|
//**********************************************************************
|
|
// Macro definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Structure definitions
|
|
//**********************************************************************
|
|
|
|
//**********************************************************************
|
|
// Variable definitions
|
|
//**********************************************************************
|
|
|
|
//
|
|
// global variables that are unique for the process
|
|
//
|
|
#ifndef DPNBUILD_ONLYONETHREAD
|
|
static DNCRITICAL_SECTION g_InterfaceGlobalsLock;
|
|
#endif // !DPNBUILD_ONLYONETHREAD
|
|
|
|
static volatile LONG g_iThreadPoolRefCount = 0;
|
|
static CThreadPool * g_pThreadPool = NULL;
|
|
|
|
|
|
static volatile LONG g_iWinsockRefCount = 0;
|
|
|
|
#ifndef DPNBUILD_NONATHELP
|
|
static volatile LONG g_iNATHelpRefCount = 0;
|
|
#endif // ! DPNBUILD_NONATHELP
|
|
|
|
#if ((defined(WINNT)) && (! defined(DPNBUILD_NOMULTICAST)))
|
|
static volatile LONG g_iMadcapRefCount = 0;
|
|
BYTE g_abClientID[MCAST_CLIENT_ID_LEN];
|
|
#endif // WINNT and not DPNBUILD_NOMULTICAST
|
|
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// Function prototypes
|
|
//**********************************************************************
|
|
#ifndef DPNBUILD_NOREGISTRY
|
|
static void ReadSettingsFromRegistry( void );
|
|
static BOOL BannedIPv4AddressCompareFunction( PVOID pvKey1, PVOID pvKey2 );
|
|
static DWORD BannedIPv4AddressHashFunction( PVOID pvKey, BYTE bBitDepth );
|
|
static void ReadBannedIPv4Addresses( CRegistry * pRegObject );
|
|
#endif // ! DPNBUILD_NOREGISTRY
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// Function definitions
|
|
//**********************************************************************
|
|
|
|
|
|
#if defined(WINCE) && !defined(_MAX_DRIVE)
|
|
//typedef signed char _TSCHAR;
|
|
#define _MAX_DRIVE 3 /* max. length of drive component */
|
|
#define _MAX_DIR 256 /* max. length of path component */
|
|
#define _MAX_FNAME 256 /* max. length of file name component */
|
|
#define _MAX_EXT 256 /* max. length of extension component */
|
|
|
|
void __cdecl _tsplitpath (
|
|
register const _TSCHAR *path,
|
|
_TSCHAR *drive,
|
|
_TSCHAR *dir,
|
|
_TSCHAR *fname,
|
|
_TSCHAR *ext
|
|
)
|
|
{
|
|
register _TSCHAR *p;
|
|
_TSCHAR *last_slash = NULL, *dot = NULL;
|
|
unsigned len;
|
|
|
|
/* we assume that the path argument has the following form, where any
|
|
* or all of the components may be missing.
|
|
*
|
|
* <drive><dir><fname><ext>
|
|
*
|
|
* and each of the components has the following expected form(s)
|
|
*
|
|
* drive:
|
|
* 0 to _MAX_DRIVE-1 characters, the last of which, if any, is a
|
|
* ':'
|
|
* dir:
|
|
* 0 to _MAX_DIR-1 characters in the form of an absolute path
|
|
* (leading '/' or '\') or relative path, the last of which, if
|
|
* any, must be a '/' or '\'. E.g -
|
|
* absolute path:
|
|
* \top\next\last\ ; or
|
|
* /top/next/last/
|
|
* relative path:
|
|
* top\next\last\ ; or
|
|
* top/next/last/
|
|
* Mixed use of '/' and '\' within a path is also tolerated
|
|
* fname:
|
|
* 0 to _MAX_FNAME-1 characters not including the '.' character
|
|
* ext:
|
|
* 0 to _MAX_EXT-1 characters where, if any, the first must be a
|
|
* '.'
|
|
*
|
|
*/
|
|
|
|
/* extract drive letter and :, if any */
|
|
|
|
if ((_tcslen(path) >= (_MAX_DRIVE - 2)) && (*(path + _MAX_DRIVE - 2) == _T(':'))) {
|
|
if (drive) {
|
|
_tcsncpy(drive, path, _MAX_DRIVE - 1);
|
|
*(drive + _MAX_DRIVE-1) = _T('\0');
|
|
}
|
|
path += _MAX_DRIVE - 1;
|
|
}
|
|
else if (drive) {
|
|
*drive = _T('\0');
|
|
}
|
|
|
|
/* extract path string, if any. Path now points to the first character
|
|
* of the path, if any, or the filename or extension, if no path was
|
|
* specified. Scan ahead for the last occurence, if any, of a '/' or
|
|
* '\' path separator character. If none is found, there is no path.
|
|
* We will also note the last '.' character found, if any, to aid in
|
|
* handling the extension.
|
|
*/
|
|
|
|
for (last_slash = NULL, p = (_TSCHAR *)path; *p; p++) {
|
|
#ifdef _MBCS
|
|
if (_ISLEADBYTE (*p))
|
|
p++;
|
|
else {
|
|
#endif /* _MBCS */
|
|
if (*p == _T('/') || *p == _T('\\'))
|
|
/* point to one beyond for later copy */
|
|
last_slash = p + 1;
|
|
else if (*p == _T('.'))
|
|
dot = p;
|
|
#ifdef _MBCS
|
|
}
|
|
#endif /* _MBCS */
|
|
}
|
|
|
|
if (last_slash) {
|
|
|
|
/* found a path - copy up through last_slash or max. characters
|
|
* allowed, whichever is smaller
|
|
*/
|
|
|
|
if (dir) {
|
|
len = __min(((char *)last_slash - (char *)path) / sizeof(_TSCHAR),
|
|
(_MAX_DIR - 1));
|
|
_tcsncpy(dir, path, len);
|
|
*(dir + len) = _T('\0');
|
|
}
|
|
path = last_slash;
|
|
}
|
|
else if (dir) {
|
|
|
|
/* no path found */
|
|
|
|
*dir = _T('\0');
|
|
}
|
|
|
|
/* extract file name and extension, if any. Path now points to the
|
|
* first character of the file name, if any, or the extension if no
|
|
* file name was given. Dot points to the '.' beginning the extension,
|
|
* if any.
|
|
*/
|
|
|
|
if (dot && (dot >= path)) {
|
|
/* found the marker for an extension - copy the file name up to
|
|
* the '.'.
|
|
*/
|
|
if (fname) {
|
|
len = __min(((char *)dot - (char *)path) / sizeof(_TSCHAR),
|
|
(_MAX_FNAME - 1));
|
|
_tcsncpy(fname, path, len);
|
|
*(fname + len) = _T('\0');
|
|
}
|
|
/* now we can get the extension - remember that p still points
|
|
* to the terminating nul character of path.
|
|
*/
|
|
if (ext) {
|
|
len = __min(((char *)p - (char *)dot) / sizeof(_TSCHAR),
|
|
(_MAX_EXT - 1));
|
|
_tcsncpy(ext, dot, len);
|
|
*(ext + len) = _T('\0');
|
|
}
|
|
}
|
|
else {
|
|
/* found no extension, give empty extension and copy rest of
|
|
* string into fname.
|
|
*/
|
|
if (fname) {
|
|
len = __min(((char *)p - (char *)path) / sizeof(_TSCHAR),
|
|
(_MAX_FNAME - 1));
|
|
_tcsncpy(fname, path, len);
|
|
*(fname + len) = _T('\0');
|
|
}
|
|
if (ext) {
|
|
*ext = _T('\0');
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // WINCE
|
|
|
|
|
|
|
|
#ifndef DPNBUILD_NOREGISTRY
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ReadSettingsFromRegistry - read custom registry keys
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ReadSettingsFromRegistry"
|
|
|
|
static void ReadSettingsFromRegistry( void )
|
|
{
|
|
CRegistry RegObject;
|
|
CRegistry RegObjectTemp;
|
|
CRegistry RegObjectAppEntry;
|
|
DWORD dwRegValue;
|
|
BOOL fGotPath;
|
|
WCHAR wszExePath[_MAX_PATH];
|
|
#ifndef UNICODE
|
|
char szExePath[_MAX_PATH];
|
|
#endif // !UNICODE
|
|
|
|
|
|
if ( RegObject.Open( HKEY_LOCAL_MACHINE, g_RegistryBase ) != FALSE )
|
|
{
|
|
//
|
|
// Find out the current process name.
|
|
//
|
|
#ifdef UNICODE
|
|
if (GetModuleFileName(NULL, wszExePath, _MAX_PATH) > 0)
|
|
{
|
|
DPFX(DPFPREP, 3, "Loading DLL in process: %ls", wszExePath);
|
|
_tsplitpath( wszExePath, NULL, NULL, wszExePath, NULL );
|
|
fGotPath = TRUE;
|
|
}
|
|
#else // ! UNICODE
|
|
if (GetModuleFileName(NULL, szExePath, _MAX_PATH) > 0)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Loading DLL in process: %hs", szExePath);
|
|
_tsplitpath( szExePath, NULL, NULL, szExePath, NULL );
|
|
|
|
dwRegValue = _MAX_PATH;
|
|
hr = STR_AnsiToWide(szExePath, -1, wszExePath, &dwRegValue );
|
|
if ( hr == DPN_OK )
|
|
{
|
|
//
|
|
// Successfully converted ANSI path to Wide characters.
|
|
//
|
|
fGotPath = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Couldn't convert ANSI path to Wide characters
|
|
//
|
|
fGotPath = FALSE;
|
|
}
|
|
}
|
|
#endif // ! UNICODE
|
|
else
|
|
{
|
|
//
|
|
// Couldn't get current process path.
|
|
//
|
|
fGotPath = FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// read receive buffer size
|
|
//
|
|
if ( RegObject.ReadDWORD( g_RegistryKeyReceiveBufferSize, &dwRegValue ) != FALSE )
|
|
{
|
|
g_fWinsockReceiveBufferSizeOverridden = TRUE;
|
|
g_iWinsockReceiveBufferSize = dwRegValue;
|
|
}
|
|
|
|
#ifndef DPNBUILD_ONLYONETHREAD
|
|
//
|
|
// read default threads
|
|
//
|
|
if ( RegObject.ReadDWORD( g_RegistryKeyThreadCount, &dwRegValue ) != FALSE )
|
|
{
|
|
g_iThreadCount = dwRegValue;
|
|
}
|
|
|
|
//
|
|
// if thread count is zero, use the 'default' for the system
|
|
//
|
|
if ( g_iThreadCount == 0 )
|
|
{
|
|
g_iThreadCount = DEFAULT_THREADS_PER_PROCESSOR;
|
|
|
|
#ifndef DPNBUILD_ONLYONEPROCESSOR
|
|
SYSTEM_INFO SystemInfo;
|
|
|
|
GetSystemInfo(&SystemInfo);
|
|
g_iThreadCount *= SystemInfo.dwNumberOfProcessors;
|
|
#endif // ! DPNBUILD_ONLYONEPROCESSOR
|
|
}
|
|
#endif // ! DPNBUILD_ONLYONETHREAD
|
|
|
|
#if ((! defined(DPNBUILD_NOWINSOCK2)) && (! defined(DPNBUILD_ONLYWINSOCK2)))
|
|
//
|
|
// Winsock2 9x option
|
|
//
|
|
if (RegObject.ReadDWORD( g_RegistryKeyWinsockVersion, &dwRegValue ))
|
|
{
|
|
switch (dwRegValue)
|
|
{
|
|
case 0:
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly using available Winsock version.");
|
|
g_dwWinsockVersion = dwRegValue;
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly using Winsock 1 only.");
|
|
g_dwWinsockVersion = dwRegValue;
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly using Winsock 2 (when available).");
|
|
g_dwWinsockVersion = dwRegValue;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid Winsock version setting (%u).", dwRegValue);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif // ! DPNBUILD_NOWINSOCK2 and ! DPNBUILD_ONLYWINSOCK2
|
|
|
|
|
|
#ifndef DPNBUILD_NONATHELP
|
|
//
|
|
// get global NAT traversal disablers, ignore registry reading error
|
|
//
|
|
if (RegObject.ReadBOOL( g_RegistryKeyDisableDPNHGatewaySupport, &g_fDisableDPNHGatewaySupport ))
|
|
{
|
|
if (g_fDisableDPNHGatewaySupport)
|
|
{
|
|
DPFX(DPFPREP, 1, "Disabling NAT Help gateway support.");
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly not disabling NAT Help gateway support.");
|
|
}
|
|
}
|
|
|
|
if (RegObject.ReadBOOL( g_RegistryKeyDisableDPNHFirewallSupport, &g_fDisableDPNHFirewallSupport ))
|
|
{
|
|
if (g_fDisableDPNHFirewallSupport)
|
|
{
|
|
DPFX(DPFPREP, 1, "Disabling NAT Help firewall support.");
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly not disabling NAT Help firewall support.");
|
|
}
|
|
}
|
|
#endif // DPNBUILD_NONATHELP
|
|
|
|
#if ((defined(WINNT)) && (! defined(DPNBUILD_NOMULTICAST)))
|
|
//
|
|
// get global MADCAP API disabler, ignore registry reading error
|
|
//
|
|
if (RegObject.ReadBOOL( g_RegistryKeyDisableMadcapSupport, &g_fDisableMadcapSupport ))
|
|
{
|
|
if (g_fDisableMadcapSupport)
|
|
{
|
|
DPFX(DPFPREP, 1, "Disabling MADCAP support.");
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly not disabling MADCAP support.");
|
|
}
|
|
}
|
|
#endif // WINNT and not DPNBUILD_NOMULTICAST
|
|
|
|
|
|
//
|
|
// If we have an app name, try opening the subkey and looking up the app
|
|
// to see if enums are disabled, whether we should disconnect based on
|
|
// ICMPs, and which IP protocol families to use.
|
|
//
|
|
if ( fGotPath )
|
|
{
|
|
if ( RegObjectTemp.Open( RegObject.GetHandle(), g_RegistryKeyAppsToIgnoreEnums, TRUE, FALSE ) )
|
|
{
|
|
RegObjectTemp.ReadBOOL( wszExePath, &g_fIgnoreEnums );
|
|
RegObjectTemp.Close();
|
|
|
|
if ( g_fIgnoreEnums )
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring all enumerations (app = %ls).", wszExePath);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 2, "Not ignoring all enumerations (app = %ls).", wszExePath);
|
|
}
|
|
}
|
|
|
|
if ( RegObjectTemp.Open( RegObject.GetHandle(), g_RegistryKeyAppsToDisconnectOnICMP, TRUE, FALSE ) )
|
|
{
|
|
RegObjectTemp.ReadBOOL( wszExePath, &g_fDisconnectOnICMP );
|
|
RegObjectTemp.Close();
|
|
|
|
if ( g_fDisconnectOnICMP )
|
|
{
|
|
DPFX(DPFPREP, 0, "Disconnecting upon receiving ICMP port not reachable messages (app = %ls).", wszExePath);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 2, "Not disconnecting upon receiving ICMP port not reachable messages (app = %ls).", wszExePath);
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef DPNBUILD_NONATHELP
|
|
if ( RegObjectTemp.Open( RegObject.GetHandle(), g_RegistryKeyTraversalModeSettings, TRUE, FALSE ) )
|
|
{
|
|
//
|
|
// Read the global default traversal mode.
|
|
//
|
|
if ( RegObjectTemp.ReadDWORD( g_RegistryKeyDefaultTraversalMode, &dwRegValue ) != FALSE )
|
|
{
|
|
switch (dwRegValue)
|
|
{
|
|
case DPNA_TRAVERSALMODE_NONE:
|
|
case DPNA_TRAVERSALMODE_PORTREQUIRED:
|
|
case DPNA_TRAVERSALMODE_PORTRECOMMENDED:
|
|
{
|
|
g_dwDefaultTraversalMode = dwRegValue;
|
|
DPFX(DPFPREP, 1, "Using global default traversal mode %u.",
|
|
g_dwDefaultTraversalMode);
|
|
break;
|
|
}
|
|
|
|
case (DPNA_TRAVERSALMODE_NONE | FORCE_TRAVERSALMODE_BIT):
|
|
case (DPNA_TRAVERSALMODE_PORTREQUIRED | FORCE_TRAVERSALMODE_BIT):
|
|
case (DPNA_TRAVERSALMODE_PORTRECOMMENDED | FORCE_TRAVERSALMODE_BIT):
|
|
{
|
|
g_dwDefaultTraversalMode = dwRegValue;
|
|
DPFX(DPFPREP, 1, "Forcing global traversal mode %u.",
|
|
g_dwDefaultTraversalMode);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid global default traversal mode (%u).",
|
|
dwRegValue);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Override with the per app setting.
|
|
//
|
|
if ( RegObjectTemp.ReadDWORD( wszExePath, &dwRegValue ) != FALSE )
|
|
{
|
|
switch (dwRegValue)
|
|
{
|
|
case DPNA_TRAVERSALMODE_NONE:
|
|
case DPNA_TRAVERSALMODE_PORTREQUIRED:
|
|
case DPNA_TRAVERSALMODE_PORTRECOMMENDED:
|
|
{
|
|
g_dwDefaultTraversalMode = dwRegValue;
|
|
DPFX(DPFPREP, 1, "Using default traversal mode %u (app = %ls).",
|
|
g_dwDefaultTraversalMode, wszExePath);
|
|
break;
|
|
}
|
|
|
|
case (DPNA_TRAVERSALMODE_NONE | FORCE_TRAVERSALMODE_BIT):
|
|
case (DPNA_TRAVERSALMODE_PORTREQUIRED | FORCE_TRAVERSALMODE_BIT):
|
|
case (DPNA_TRAVERSALMODE_PORTRECOMMENDED | FORCE_TRAVERSALMODE_BIT):
|
|
{
|
|
g_dwDefaultTraversalMode = dwRegValue;
|
|
DPFX(DPFPREP, 1, "Forcing traversal mode %u (app = %ls).",
|
|
g_dwDefaultTraversalMode, wszExePath);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid default traversal mode (%u, app %ls).",
|
|
dwRegValue, wszExePath);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RegObjectTemp.Close();
|
|
}
|
|
#endif // DPNBUILD_NONATHELP
|
|
|
|
|
|
#ifndef DPNBUILD_NOIPV6
|
|
if ( RegObjectTemp.Open( RegObject.GetHandle(), g_RegistryKeyIPAddressFamilySettings, TRUE, FALSE ) )
|
|
{
|
|
//
|
|
// Read the global IP address family setting.
|
|
//
|
|
if ( RegObjectTemp.ReadDWORD( g_RegistryKeyDefaultIPAddressFamily, &dwRegValue ) != FALSE )
|
|
{
|
|
switch (dwRegValue)
|
|
{
|
|
case PF_UNSPEC:
|
|
case PF_INET:
|
|
case PF_INET6:
|
|
{
|
|
g_iIPAddressFamily = dwRegValue;
|
|
DPFX(DPFPREP, 1, "Using IP address family %i global setting.",
|
|
g_iIPAddressFamily);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid IP address family global setting (%u).",
|
|
dwRegValue);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Override with the per app setting.
|
|
//
|
|
if ( RegObjectTemp.ReadDWORD( wszExePath, &dwRegValue ) != FALSE )
|
|
{
|
|
switch (dwRegValue)
|
|
{
|
|
case PF_UNSPEC:
|
|
case PF_INET:
|
|
case PF_INET6:
|
|
{
|
|
g_iIPAddressFamily = dwRegValue;
|
|
DPFX(DPFPREP, 1, "Using IP address family %i (app = %ls).",
|
|
g_iIPAddressFamily, wszExePath);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid IP address family setting (%u, app %ls).",
|
|
dwRegValue, wszExePath);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RegObjectTemp.Close();
|
|
}
|
|
#endif // ! DPNBUILD_NOIPV6
|
|
}
|
|
|
|
|
|
//
|
|
// Get the proxy support options, ignore registry reading error.
|
|
//
|
|
#ifndef DPNBUILD_NOWINSOCK2
|
|
if (RegObject.ReadBOOL( g_RegistryKeyDontAutoDetectProxyLSP, &g_fDontAutoDetectProxyLSP ))
|
|
{
|
|
if (g_fDontAutoDetectProxyLSP)
|
|
{
|
|
DPFX(DPFPREP, 1, "Not auto-detected ISA Proxy LSP.");
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly allowing auto-detection of ISA Proxy LSP.");
|
|
}
|
|
}
|
|
#endif // !DPNBUILD_NOWINSOCK2
|
|
if (RegObject.ReadBOOL( g_RegistryKeyTreatAllResponsesAsProxied, &g_fTreatAllResponsesAsProxied ))
|
|
{
|
|
if (g_fTreatAllResponsesAsProxied)
|
|
{
|
|
DPFX(DPFPREP, 1, "Treating all responses as proxied.");
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 1, "Explicitly not treating all responses as proxied.");
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// read MTU overrides
|
|
//
|
|
|
|
if ( RegObject.ReadDWORD( g_RegistryKeyMaxUserDataSize, &dwRegValue ) != FALSE )
|
|
{
|
|
if ((dwRegValue >= MIN_SEND_FRAME_SIZE) && (dwRegValue <= MAX_SEND_FRAME_SIZE))
|
|
{
|
|
//
|
|
// If the new user data size is smaller than the the default enum setting,
|
|
// shrink the enum size as well. It can be explicitly overridden below.
|
|
//
|
|
if (dwRegValue < g_dwMaxEnumDataSize)
|
|
{
|
|
g_dwMaxUserDataSize = dwRegValue;
|
|
g_dwMaxEnumDataSize = g_dwMaxUserDataSize - ENUM_PAYLOAD_HEADER_SIZE;
|
|
DPFX(DPFPREP, 1, "Max user data size is set to %u, assuming enum payload is %u.",
|
|
g_dwMaxUserDataSize, g_dwMaxEnumDataSize);
|
|
}
|
|
else
|
|
{
|
|
g_dwMaxUserDataSize = dwRegValue;
|
|
DPFX(DPFPREP, 1, "Max user data size is set to %u.",
|
|
g_dwMaxUserDataSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid max user data size setting (%u).",
|
|
dwRegValue);
|
|
}
|
|
}
|
|
|
|
if ( RegObject.ReadDWORD( g_RegistryKeyMaxEnumDataSize, &dwRegValue ) != FALSE )
|
|
{
|
|
if ((dwRegValue >= (MIN_SEND_FRAME_SIZE - ENUM_PAYLOAD_HEADER_SIZE)) &&
|
|
(dwRegValue <= (MAX_SEND_FRAME_SIZE - ENUM_PAYLOAD_HEADER_SIZE)))
|
|
{
|
|
DPFX(DPFPREP, 1, "Max user data size is set to %u.",
|
|
dwRegValue);
|
|
g_dwMaxEnumDataSize = dwRegValue;
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid max user data size setting (%u).",
|
|
dwRegValue);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// read default port range
|
|
//
|
|
|
|
if ( RegObject.ReadDWORD( g_RegistryKeyBaseDPlayPort, &dwRegValue ) != FALSE )
|
|
{
|
|
if (dwRegValue < (WORD_MAX - 100)) // cannot be 65435 or above
|
|
{
|
|
g_wBaseDPlayPort = (WORD) dwRegValue;
|
|
DPFX(DPFPREP, 1, "Base DPlay default port set to %u.",
|
|
g_wBaseDPlayPort);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid base DPlay default port setting (%u).",
|
|
dwRegValue);
|
|
}
|
|
}
|
|
|
|
if ( RegObject.ReadDWORD( g_RegistryKeyMaxDPlayPort, &dwRegValue ) != FALSE )
|
|
{
|
|
if (dwRegValue <= WORD_MAX) // cannot be greater than 65535
|
|
{
|
|
g_wMaxDPlayPort = (WORD) dwRegValue;
|
|
DPFX(DPFPREP, 1, "Max DPlay default port set to %u.",
|
|
g_wMaxDPlayPort);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid max DPlay default port setting (%u).",
|
|
dwRegValue);
|
|
}
|
|
}
|
|
|
|
if (g_wMaxDPlayPort <= g_wBaseDPlayPort)
|
|
{
|
|
DPFX(DPFPREP, 1, "Max DPlay default port %u is less than or equal to base %u, setting to %u.",
|
|
g_wMaxDPlayPort, g_wBaseDPlayPort, (g_wBaseDPlayPort + 100));
|
|
g_wMaxDPlayPort = g_wBaseDPlayPort + 100;
|
|
}
|
|
|
|
|
|
RegObject.Close();
|
|
}
|
|
|
|
#pragma TODO(vanceo, "Be able to read while session is still running")
|
|
if ( RegObject.Open( HKEY_LOCAL_MACHINE, g_RegistryBase, TRUE, FALSE ) != FALSE )
|
|
{
|
|
if ( RegObjectTemp.Open( RegObject.GetHandle(), g_RegistryKeyBannedIPv4Addresses, TRUE, FALSE ) )
|
|
{
|
|
DPFX(DPFPREP, 1, "Reading banned IPv4 addresses for all users.");
|
|
ReadBannedIPv4Addresses(&RegObjectTemp);
|
|
}
|
|
RegObject.Close();
|
|
}
|
|
|
|
if ( RegObject.Open( HKEY_CURRENT_USER, g_RegistryBase, TRUE, FALSE ) != FALSE )
|
|
{
|
|
if ( RegObjectTemp.Open( RegObject.GetHandle(), g_RegistryKeyBannedIPv4Addresses, TRUE, FALSE ) )
|
|
{
|
|
DPFX(DPFPREP, 1, "Reading banned IPv4 addresses for current user.");
|
|
ReadBannedIPv4Addresses(&RegObjectTemp);
|
|
}
|
|
RegObject.Close();
|
|
}
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// BannedIPv4AddressCompareFunction - compare against another address
|
|
//
|
|
// Entry: Addresses to compare
|
|
//
|
|
// Exit: Bool indicating equality of two addresses
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "BannedIPv4AddressCompareFunction"
|
|
|
|
static BOOL BannedIPv4AddressCompareFunction( PVOID pvKey1, PVOID pvKey2 )
|
|
{
|
|
DWORD dwAddr1;
|
|
DWORD dwAddr2;
|
|
|
|
dwAddr1 = (DWORD) ((DWORD_PTR) pvKey1);
|
|
dwAddr2 = (DWORD) ((DWORD_PTR) pvKey2);
|
|
|
|
if (dwAddr1 == dwAddr2)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// BannedIPv4AddressHashFunction - hash address to N bits
|
|
//
|
|
// Entry: Count of bits to hash to
|
|
//
|
|
// Exit: Hashed value
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "BannedIPv4AddressHashFunction"
|
|
|
|
static DWORD BannedIPv4AddressHashFunction( PVOID pvKey, BYTE bBitDepth )
|
|
{
|
|
DWORD dwReturn;
|
|
UINT_PTR Temp;
|
|
|
|
DNASSERT( bBitDepth != 0 );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
dwReturn = 0;
|
|
|
|
//
|
|
// hash IP address
|
|
//
|
|
Temp = (DWORD) ((DWORD_PTR) pvKey);
|
|
|
|
do
|
|
{
|
|
dwReturn ^= Temp & ( ( 1 << bBitDepth ) - 1 );
|
|
Temp >>= bBitDepth;
|
|
} while ( Temp != 0 );
|
|
|
|
return dwReturn;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// ReadBannedIPv4Addresses - reads in additional banned IPv4 addresses from the registry
|
|
//
|
|
// Entry: Pointer to registry object with values to read
|
|
//
|
|
// Exit: None
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "ReadBannedIPv4Addresses"
|
|
|
|
static void ReadBannedIPv4Addresses( CRegistry * pRegObject )
|
|
{
|
|
WCHAR wszIPAddress[16]; // nnn.nnn.nnn.nnn + NULL termination
|
|
char szIPAddress[16]; // nnn.nnn.nnn.nnn + NULL termination
|
|
DWORD dwSize;
|
|
DWORD dwIndex;
|
|
DWORD dwMask;
|
|
DWORD dwBit;
|
|
PVOID pvMask;
|
|
CSocketAddress SocketAddressTemp;
|
|
SOCKADDR_IN * psaddrinTemp;
|
|
|
|
|
|
memset(&SocketAddressTemp, 0, sizeof(SocketAddressTemp));
|
|
psaddrinTemp = (SOCKADDR_IN*) SocketAddressTemp.GetWritableAddress();
|
|
psaddrinTemp->sin_family = AF_INET;
|
|
psaddrinTemp->sin_port = 0xAAAA; // doesn't matter, just anything valid for IsValidUnicastAddress()
|
|
|
|
//
|
|
// Create the banned IPv4 addresses hash table, if we don't have it already.
|
|
//
|
|
if (g_pHashBannedIPv4Addresses == NULL)
|
|
{
|
|
g_pHashBannedIPv4Addresses = (CHashTable*) DNMalloc(sizeof(CHashTable));
|
|
if (g_pHashBannedIPv4Addresses == NULL)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't allocate banned IPv4 addresses hash table!");
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Initialize the banned address hash with 2 entries and grow by a factor of 2.
|
|
//
|
|
if (! g_pHashBannedIPv4Addresses->Initialize(1,
|
|
#ifndef DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
1,
|
|
#endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
BannedIPv4AddressCompareFunction,
|
|
BannedIPv4AddressHashFunction))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't initialize banned IPv4 addresses hash table!");
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
dwIndex = 0;
|
|
do
|
|
{
|
|
dwSize = 16;
|
|
if (! pRegObject->EnumValues( wszIPAddress, &dwSize, dwIndex ))
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Read the mask associated with the IP address.
|
|
//
|
|
if ( pRegObject->ReadDWORD(wszIPAddress, &dwMask))
|
|
{
|
|
//
|
|
// Convert the IP address string to binary.
|
|
//
|
|
if (STR_jkWideToAnsi(szIPAddress, wszIPAddress, 16) == DPN_OK)
|
|
{
|
|
//
|
|
// Convert the IP address string to binary.
|
|
//
|
|
psaddrinTemp->sin_addr.S_un.S_addr = inet_addr(szIPAddress);
|
|
if (SocketAddressTemp.IsValidUnicastAddress(FALSE))
|
|
{
|
|
//
|
|
// Find the first mask bit. We expect the network byte order of
|
|
// the IP address to be opposite of host byte order.
|
|
//
|
|
dwBit = 0x80000000;
|
|
while (! (dwBit & dwMask))
|
|
{
|
|
psaddrinTemp->sin_addr.S_un.S_addr &= ~dwBit;
|
|
dwBit >>= 1;
|
|
if (dwBit <= 0x80)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dwBit & dwMask)
|
|
{
|
|
//
|
|
// If the masked address is already in the hash, update the mask.
|
|
// This allows bans to be listed more than once.
|
|
//
|
|
if (g_pHashBannedIPv4Addresses->Find((PVOID) ((DWORD_PTR) psaddrinTemp->sin_addr.S_un.S_addr), &pvMask))
|
|
{
|
|
if (! g_pHashBannedIPv4Addresses->Remove((PVOID) ((DWORD_PTR) psaddrinTemp->sin_addr.S_un.S_addr)))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't remove masked IPv4 entry %u.%u.%u.%u from ban hash.",
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b1,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b2,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b3,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b4);
|
|
dwMask = dwBit;
|
|
}
|
|
else
|
|
{
|
|
dwMask = ((DWORD) ((DWORD_PTR) pvMask)) | dwBit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwMask = dwBit;
|
|
}
|
|
|
|
//
|
|
// Add (or readd) the masked address to the hash.
|
|
//
|
|
if (g_pHashBannedIPv4Addresses->Insert((PVOID) ((DWORD_PTR) psaddrinTemp->sin_addr.S_un.S_addr), (PVOID) ((DWORD_PTR) dwMask)))
|
|
{
|
|
g_dwBannedIPv4Masks |= dwBit;
|
|
DPFX(DPFPREP, 5, "Added (or readded) %ls (bits = 0x%08x, masked IPv4 entry %u.%u.%u.%u) to ban hash.",
|
|
wszIPAddress,
|
|
dwMask,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b1,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b2,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b3,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b4);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't add %ls (bits = 0x%08x, masked IPv4 entry %u.%u.%u.%u) to ban hash!",
|
|
wszIPAddress,
|
|
dwMask,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b1,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b2,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b3,
|
|
psaddrinTemp->sin_addr.S_un.S_un_b.s_b4);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid banned IPv4 entry \"%ls\" (mask = 0x%08x)!",
|
|
wszIPAddress, dwMask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring invalid banned IPv4 entry \"%ls\" (mask = 0x%08x)!",
|
|
wszIPAddress, dwMask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't convert banned IPv4 entry \"%ls\" (mask = 0x%08x) to ANSI!",
|
|
wszIPAddress, dwMask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't read banned IPv4 entry \"%ls\"!", wszIPAddress);
|
|
}
|
|
|
|
dwIndex++;
|
|
}
|
|
while (TRUE);
|
|
|
|
DPFX(DPFPREP, 2, "There are now a total of %u IPv4 addresses to ban, mask bits = 0x%08x.",
|
|
g_pHashBannedIPv4Addresses->GetEntryCount(),
|
|
g_dwBannedIPv4Masks);
|
|
|
|
Exit:
|
|
|
|
return;
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
#endif // ! DPNBUILD_NOREGISTRY
|
|
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// InitProcessGlobals - initialize the global items needed for the SP to operate
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// TRUE = success
|
|
// FALSE = failure
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitProcessGlobals"
|
|
|
|
BOOL InitProcessGlobals( void )
|
|
{
|
|
BOOL fReturn;
|
|
BOOL fCriticalSectionInitialized;
|
|
#ifdef _XBOX
|
|
BOOL fRefcountXnKeysInitted;
|
|
#endif // _XBOX
|
|
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
fReturn = TRUE;
|
|
fCriticalSectionInitialized = FALSE;
|
|
#ifdef _XBOX
|
|
fRefcountXnKeysInitted = FALSE;
|
|
#endif // _XBOX
|
|
|
|
|
|
#ifdef DBG
|
|
g_blDPNWSockCritSecsHeld.Initialize();
|
|
#endif // DBG
|
|
|
|
|
|
#ifndef DPNBUILD_NOREGISTRY
|
|
ReadSettingsFromRegistry();
|
|
#endif // ! DPNBUILD_NOREGISTRY
|
|
|
|
if ( DNInitializeCriticalSection( &g_InterfaceGlobalsLock ) == FALSE )
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
DebugSetCriticalSectionGroup( &g_InterfaceGlobalsLock, &g_blDPNWSockCritSecsHeld ); // separate dpnwsock CSes from the rest of DPlay's CSes
|
|
|
|
fCriticalSectionInitialized = TRUE;
|
|
|
|
|
|
if ( InitializePools() == FALSE )
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
|
|
#ifdef _XBOX
|
|
#pragma BUGBUG(vanceo, "Find way to retrieve value from XNet")
|
|
if ( InitializeRefcountXnKeys(4) == FALSE )
|
|
{
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
fRefcountXnKeysInitted = TRUE;
|
|
#endif // _XBOX
|
|
|
|
DNASSERT( g_pThreadPool == NULL );
|
|
|
|
|
|
Exit:
|
|
return fReturn;
|
|
|
|
Failure:
|
|
#ifdef _XBOX
|
|
if ( fRefcountXnKeysInitted )
|
|
{
|
|
CleanupRefcountXnKeys();
|
|
fRefcountXnKeysInitted = FALSE;
|
|
}
|
|
#endif // _XBOX
|
|
|
|
DeinitializePools();
|
|
|
|
if ( fCriticalSectionInitialized != FALSE )
|
|
{
|
|
DNDeleteCriticalSection( &g_InterfaceGlobalsLock );
|
|
fCriticalSectionInitialized = FALSE;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// DeinitProcessGlobals - deinitialize the global items
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DeinitProcessGlobals"
|
|
|
|
void DeinitProcessGlobals( void )
|
|
{
|
|
DNASSERT( g_pThreadPool == NULL );
|
|
DNASSERT( g_iThreadPoolRefCount == 0 );
|
|
|
|
#ifndef DPNBUILD_NOREGISTRY
|
|
if (g_pHashBannedIPv4Addresses != NULL)
|
|
{
|
|
g_pHashBannedIPv4Addresses->RemoveAll();
|
|
g_pHashBannedIPv4Addresses->Deinitialize();
|
|
DNFree(g_pHashBannedIPv4Addresses);
|
|
g_pHashBannedIPv4Addresses = NULL;
|
|
g_dwBannedIPv4Masks = 0;
|
|
}
|
|
#endif // ! DPNBUILD_NOREGISTRY
|
|
|
|
#ifdef _XBOX
|
|
CleanupRefcountXnKeys();
|
|
#endif // _XBOX
|
|
|
|
DeinitializePools();
|
|
DNDeleteCriticalSection( &g_InterfaceGlobalsLock );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// LoadWinsock - load Winsock module into memory
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Boolean indicating success
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "LoadWinsock"
|
|
|
|
BOOL LoadWinsock( void )
|
|
{
|
|
BOOL fReturn = TRUE;
|
|
int iResult;
|
|
|
|
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
if ( g_iWinsockRefCount == 0 )
|
|
{
|
|
//
|
|
// initialize the bindings to Winsock
|
|
//
|
|
iResult = DWSInitWinSock();
|
|
if ( iResult != 0 ) // failure
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem binding dynamic winsock function (err = %i)!", iResult );
|
|
fReturn = FALSE;
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 6, "Successfully bound dynamic WinSock functions." );
|
|
}
|
|
|
|
DNASSERT(g_iWinsockRefCount >= 0);
|
|
DNInterlockedIncrement( const_cast<LONG*>(&g_iWinsockRefCount) );
|
|
|
|
Exit:
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
return fReturn;
|
|
|
|
Failure:
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// UnloadWinsock - unload Winsock module
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "UnloadWinsock"
|
|
|
|
void UnloadWinsock( void )
|
|
{
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
DNASSERT(g_iWinsockRefCount > 0);
|
|
if ( DNInterlockedDecrement( const_cast<LONG*>(&g_iWinsockRefCount) ) == 0 )
|
|
{
|
|
DPFX(DPFPREP, 6, "Unbinding dynamic WinSock functions.");
|
|
DWSFreeWinSock();
|
|
}
|
|
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
#ifndef DPNBUILD_NONATHELP
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// LoadNATHelp - create and initialize NAT Help object(s)
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: TRUE if some objects were successfully loaded, FALSE otherwise
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "LoadNATHelp"
|
|
|
|
BOOL LoadNATHelp(void)
|
|
{
|
|
BOOL fReturn;
|
|
HRESULT hr;
|
|
#ifndef DPNBUILD_ONLYONENATHELP
|
|
CRegistry RegEntry;
|
|
CRegistry RegSubentry;
|
|
DWORD dwMaxKeyLen;
|
|
WCHAR * pwszKeyName = NULL;
|
|
DWORD dwEnumIndex;
|
|
DWORD dwKeyLen;
|
|
GUID guid;
|
|
#endif // ! DPNBUILD_ONLYONENATHELP
|
|
DWORD dwDirectPlay8Priority;
|
|
DWORD dwDirectPlay8InitFlags;
|
|
DWORD dwNumLoaded;
|
|
|
|
|
|
DNEnterCriticalSection(&g_InterfaceGlobalsLock);
|
|
|
|
if ( g_iNATHelpRefCount == 0 )
|
|
{
|
|
#ifndef DPNBUILD_ONLYONENATHELP
|
|
//
|
|
// Enumerate all the DirectPlayNAT Helpers.
|
|
//
|
|
if (! RegEntry.Open(HKEY_LOCAL_MACHINE, DIRECTPLAYNATHELP_REGKEY, TRUE, FALSE))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't open DirectPlayNATHelp registry key!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Find length of largest subkey.
|
|
//
|
|
if (!RegEntry.GetMaxKeyLen(&dwMaxKeyLen))
|
|
{
|
|
DPFERR("RegistryEntry.GetMaxKeyLen() failed!");
|
|
goto Failure;
|
|
}
|
|
|
|
dwMaxKeyLen++; // Null terminator
|
|
DPFX(DPFPREP, 9, "dwMaxKeyLen = %ld", dwMaxKeyLen);
|
|
|
|
pwszKeyName = (WCHAR*) DNMalloc(dwMaxKeyLen * sizeof(WCHAR));
|
|
if (pwszKeyName == NULL)
|
|
{
|
|
DPFERR("Allocating key name buffer failed!");
|
|
goto Failure;
|
|
}
|
|
#endif // ! DPNBUILD_ONLYONENATHELP
|
|
|
|
|
|
//
|
|
// Allocate an array to hold the helper objects.
|
|
//
|
|
g_papNATHelpObjects = (IDirectPlayNATHelp**) DNMalloc(MAX_NUM_DIRECTPLAYNATHELPERS * sizeof(IDirectPlayNATHelp*));
|
|
if (g_papNATHelpObjects == NULL)
|
|
{
|
|
DPFERR("DNMalloc() failed");
|
|
goto Failure;
|
|
}
|
|
ZeroMemory(g_papNATHelpObjects,
|
|
(MAX_NUM_DIRECTPLAYNATHELPERS * sizeof(IDirectPlayNATHelp*)));
|
|
|
|
|
|
#ifndef DPNBUILD_ONLYONENATHELP
|
|
dwEnumIndex = 0;
|
|
#endif // ! DPNBUILD_ONLYONENATHELP
|
|
dwNumLoaded = 0;
|
|
|
|
//
|
|
// Enumerate the DirectPlay NAT helpers.
|
|
//
|
|
do
|
|
{
|
|
#ifdef DPNBUILD_ONLYONENATHELP
|
|
WCHAR * pwszKeyName;
|
|
|
|
|
|
pwszKeyName = L"UPnP";
|
|
dwDirectPlay8Priority = 1;
|
|
dwDirectPlay8InitFlags = 0; // default UPnP flags
|
|
#else // ! DPNBUILD_ONLYONENATHELP
|
|
dwKeyLen = dwMaxKeyLen;
|
|
if (! RegEntry.EnumKeys(pwszKeyName, &dwKeyLen, dwEnumIndex))
|
|
{
|
|
break;
|
|
}
|
|
dwEnumIndex++;
|
|
|
|
|
|
DPFX(DPFPREP, 8, "%ld - %ls (%ld)", dwEnumIndex, pwszKeyName, dwKeyLen);
|
|
|
|
if (!RegSubentry.Open(RegEntry, pwszKeyName, TRUE, FALSE))
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't open subentry \"%ls\"! Skipping.", pwszKeyName);
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the DirectPlay8 priority
|
|
//
|
|
if (!RegSubentry.ReadDWORD(REGSUBKEY_DPNATHELP_DIRECTPLAY8PRIORITY, &dwDirectPlay8Priority))
|
|
{
|
|
DPFX(DPFPREP, 0, "RegSubentry.ReadDWORD \"%ls\\%ls\" failed! Skipping.",
|
|
pwszKeyName, REGSUBKEY_DPNATHELP_DIRECTPLAY8PRIORITY);
|
|
RegSubentry.Close();
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the DirectPlay8 initialization flags
|
|
//
|
|
if (!RegSubentry.ReadDWORD(REGSUBKEY_DPNATHELP_DIRECTPLAY8INITFLAGS, &dwDirectPlay8InitFlags))
|
|
{
|
|
DPFX(DPFPREP, 0, "RegSubentry.ReadDWORD \"%ls\\%ls\" failed! Defaulting to 0.",
|
|
pwszKeyName, REGSUBKEY_DPNATHELP_DIRECTPLAY8INITFLAGS);
|
|
dwDirectPlay8InitFlags = 0;
|
|
}
|
|
|
|
|
|
//
|
|
// Read the object's CLSID.
|
|
//
|
|
if (!RegSubentry.ReadGUID(REGSUBKEY_DPNATHELP_GUID, &guid))
|
|
{
|
|
DPFX(DPFPREP, 0,"RegSubentry.ReadGUID \"%ls\\%ls\" failed! Skipping.",
|
|
pwszKeyName, REGSUBKEY_DPNATHELP_GUID);
|
|
RegSubentry.Close();
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Close the subkey.
|
|
//
|
|
RegSubentry.Close();
|
|
|
|
|
|
//
|
|
// If this helper should be loaded, do so.
|
|
//
|
|
if (dwDirectPlay8Priority == 0)
|
|
{
|
|
DPFX(DPFPREP, 1, "DirectPlay NAT Helper \"%ls\" is not enabled for DirectPlay8.", pwszKeyName);
|
|
}
|
|
else
|
|
#endif // ! DPNBUILD_ONLYONENATHELP
|
|
{
|
|
#ifdef DPNBUILD_ONLYONENATHELP
|
|
//
|
|
// Try to create the NAT Help object. COM should have been
|
|
// initialized by now by someone else.
|
|
//
|
|
hr = COM_CoCreateInstance(CLSID_DirectPlayNATHelpUPnP,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDirectPlayNATHelp,
|
|
(LPVOID*) (&g_papNATHelpObjects[dwDirectPlay8Priority - 1]), FALSE);
|
|
#else // ! DPNBUILD_ONLYONENATHELP
|
|
//
|
|
// Make sure this priority is valid.
|
|
//
|
|
if (dwDirectPlay8Priority > MAX_NUM_DIRECTPLAYNATHELPERS)
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring DirectPlay NAT helper \"%ls\" with invalid priority level set too high (%u > %u).",
|
|
pwszKeyName, dwDirectPlay8Priority, MAX_NUM_DIRECTPLAYNATHELPERS);
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure this priority hasn't already been taken.
|
|
//
|
|
if (g_papNATHelpObjects[dwDirectPlay8Priority - 1] != NULL)
|
|
{
|
|
DPFX(DPFPREP, 0, "Ignoring DirectPlay NAT helper \"%ls\" with duplicate priority level %u (existing object = 0x%p).",
|
|
pwszKeyName, dwDirectPlay8Priority,
|
|
g_papNATHelpObjects[dwDirectPlay8Priority - 1]);
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Try to create the NAT Help object. COM should have been
|
|
// initialized by now by someone else.
|
|
//
|
|
hr = COM_CoCreateInstance(guid,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDirectPlayNATHelp,
|
|
(LPVOID*) (&g_papNATHelpObjects[dwDirectPlay8Priority - 1]), FALSE);
|
|
#endif // ! DPNBUILD_ONLYONENATHELP
|
|
if ( hr != S_OK )
|
|
{
|
|
DNASSERT( g_papNATHelpObjects[dwDirectPlay8Priority - 1] == NULL );
|
|
DPFX(DPFPREP, 0, "Failed to create \"%ls\" IDirectPlayNATHelp interface (error = 0x%lx)! Skipping.",
|
|
pwszKeyName, hr);
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize NAT Help.
|
|
//
|
|
|
|
#ifndef DPNBUILD_NOREGISTRY
|
|
DNASSERT((! g_fDisableDPNHGatewaySupport) || (! g_fDisableDPNHFirewallSupport));
|
|
|
|
if (g_fDisableDPNHGatewaySupport)
|
|
{
|
|
dwDirectPlay8InitFlags |= DPNHINITIALIZE_DISABLEGATEWAYSUPPORT;
|
|
}
|
|
|
|
if (g_fDisableDPNHFirewallSupport)
|
|
{
|
|
dwDirectPlay8InitFlags |= DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT;
|
|
}
|
|
#endif // ! DPNBUILD_NOREGISTRY
|
|
|
|
|
|
//
|
|
// Make sure the flags we're passing are valid.
|
|
//
|
|
if ((dwDirectPlay8InitFlags & (DPNHINITIALIZE_DISABLEGATEWAYSUPPORT | DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT)) == (DPNHINITIALIZE_DISABLEGATEWAYSUPPORT | DPNHINITIALIZE_DISABLELOCALFIREWALLSUPPORT))
|
|
{
|
|
DPFX(DPFPREP, 1, "Not loading NAT Help \"%ls\" because both DISABLEGATEWAYSUPPORT and DISABLELOCALFIREWALLSUPPORT would have been specified (priority = %u, flags = 0x%lx).",
|
|
pwszKeyName, dwDirectPlay8Priority, dwDirectPlay8InitFlags);
|
|
|
|
IDirectPlayNATHelp_Release(g_papNATHelpObjects[dwDirectPlay8Priority - 1]);
|
|
g_papNATHelpObjects[dwDirectPlay8Priority - 1] = NULL;
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
hr = IDirectPlayNATHelp_Initialize(g_papNATHelpObjects[dwDirectPlay8Priority - 1], dwDirectPlay8InitFlags);
|
|
if (hr != DPNH_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't initialize NAT Help \"%ls\" (error = 0x%lx)! Skipping.",
|
|
pwszKeyName, hr);
|
|
|
|
IDirectPlayNATHelp_Release(g_papNATHelpObjects[dwDirectPlay8Priority - 1]);
|
|
g_papNATHelpObjects[dwDirectPlay8Priority - 1] = NULL;
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
DPFX(DPFPREP, 8, "Initialized NAT Help \"%ls\" (priority = %u, flags = 0x%lx, object = 0x%p).",
|
|
pwszKeyName, dwDirectPlay8Priority, dwDirectPlay8InitFlags, g_papNATHelpObjects[dwDirectPlay8Priority - 1]);
|
|
|
|
dwNumLoaded++;
|
|
}
|
|
}
|
|
#ifdef DPNBUILD_ONLYONENATHELP
|
|
while (FALSE);
|
|
#else // ! DPNBUILD_ONLYONENATHELP
|
|
while (TRUE);
|
|
#endif // ! DPNBUILD_ONLYONENATHELP
|
|
|
|
|
|
//
|
|
// If we didn't load any NAT helper objects, free up the memory.
|
|
//
|
|
if (dwNumLoaded == 0)
|
|
{
|
|
DNFree(g_papNATHelpObjects);
|
|
g_papNATHelpObjects = NULL;
|
|
|
|
//
|
|
// We never got anything. Fail.
|
|
//
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
DPFX(DPFPREP, 8, "Loaded %u DirectPlay NAT Helper objects.", dwNumLoaded);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 8, "Already loaded NAT Help objects.");
|
|
}
|
|
|
|
//
|
|
// We have the interface globals lock, don't need DNInterlockedIncrement.
|
|
//
|
|
g_iNATHelpRefCount++;
|
|
|
|
//
|
|
// We succeeded.
|
|
//
|
|
fReturn = TRUE;
|
|
|
|
Exit:
|
|
|
|
DNLeaveCriticalSection(&g_InterfaceGlobalsLock);
|
|
|
|
#ifndef DPNBUILD_ONLYONENATHELP
|
|
if (pwszKeyName != NULL)
|
|
{
|
|
DNFree(pwszKeyName);
|
|
pwszKeyName = NULL;
|
|
}
|
|
#endif // ! DPNBUILD_ONLYONENATHELP
|
|
|
|
return fReturn;
|
|
|
|
Failure:
|
|
|
|
//
|
|
// We can only fail during the first initialize, so therefore we will never be freeing
|
|
// g_papNATHelpObjects when we didn't allocate it in this function.
|
|
//
|
|
if (g_papNATHelpObjects != NULL)
|
|
{
|
|
DNFree(g_papNATHelpObjects);
|
|
g_papNATHelpObjects = NULL;
|
|
}
|
|
|
|
fReturn = FALSE;
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// UnloadNATHelp - release the NAT Help object
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "UnloadNATHelp"
|
|
|
|
void UnloadNATHelp(void)
|
|
{
|
|
DWORD dwTemp;
|
|
|
|
|
|
DNEnterCriticalSection(&g_InterfaceGlobalsLock);
|
|
|
|
//
|
|
// We have the interface globals lock, don't need DNInterlockedDecrement.
|
|
//
|
|
DNASSERT(g_iNATHelpRefCount > 0);
|
|
g_iNATHelpRefCount--;
|
|
if (g_iNATHelpRefCount == 0 )
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DNASSERT(g_papNATHelpObjects != NULL);
|
|
for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
|
|
{
|
|
if (g_papNATHelpObjects[dwTemp] != NULL)
|
|
{
|
|
DPFX(DPFPREP, 8, "Closing NAT Help object priority %u (0x%p).",
|
|
dwTemp, g_papNATHelpObjects[dwTemp]);
|
|
|
|
hr = IDirectPlayNATHelp_Close(g_papNATHelpObjects[dwTemp], 0);
|
|
if (hr != DPNH_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Problem closing NAT Help object %u (error = 0x%lx), continuing.",
|
|
dwTemp, hr);
|
|
}
|
|
|
|
IDirectPlayNATHelp_Release(g_papNATHelpObjects[dwTemp]);
|
|
g_papNATHelpObjects[dwTemp] = NULL;
|
|
}
|
|
}
|
|
|
|
DNFree(g_papNATHelpObjects);
|
|
g_papNATHelpObjects = NULL;
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 8, "NAT Help object(s) still have %i references.",
|
|
g_iNATHelpRefCount);
|
|
}
|
|
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
}
|
|
//**********************************************************************
|
|
#endif // DPNBUILD_NONATHELP
|
|
|
|
|
|
|
|
#if ((defined(WINNT)) && (! defined(DPNBUILD_NOMULTICAST)))
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// LoadMADCAP - create and initialize MADCAP API
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: TRUE if the API was successfully loaded, FALSE otherwise
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "LoadMadcap"
|
|
|
|
BOOL LoadMadcap(void)
|
|
{
|
|
BOOL fReturn;
|
|
DWORD dwError;
|
|
DWORD dwMadcapVersion;
|
|
|
|
|
|
#ifndef DPNBUILD_NOREGISTRY
|
|
DNASSERT(! g_fDisableMadcapSupport);
|
|
#endif // ! DPNBUILD_NOREGISTRY
|
|
|
|
DNEnterCriticalSection(&g_InterfaceGlobalsLock);
|
|
|
|
if ( g_iMadcapRefCount == 0 )
|
|
{
|
|
//
|
|
// Initialize the MADCAP API.
|
|
//
|
|
dwMadcapVersion = MCAST_API_CURRENT_VERSION;
|
|
dwError = McastApiStartup(&dwMadcapVersion);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed starting MADCAP version %u (err = %u)!",
|
|
MCAST_API_CURRENT_VERSION, dwError);
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 5, "Using MADCAP version %u (supported version = %u).",
|
|
MCAST_API_CURRENT_VERSION, dwMadcapVersion);
|
|
|
|
|
|
//
|
|
// Create a unique client ID.
|
|
//
|
|
g_mcClientUid.ClientUID = g_abClientID;
|
|
g_mcClientUid.ClientUIDLength = sizeof(g_abClientID);
|
|
dwError = McastGenUID(&g_mcClientUid);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed creating MADCAP client ID (err = %u)!",
|
|
dwError);
|
|
goto Failure;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 8, "Already loaded MADCAP.");
|
|
}
|
|
|
|
//
|
|
// We have the interface globals lock, don't need DNInterlockedIncrement.
|
|
//
|
|
g_iMadcapRefCount++;
|
|
|
|
//
|
|
// We succeeded.
|
|
//
|
|
fReturn = TRUE;
|
|
|
|
Exit:
|
|
|
|
DNLeaveCriticalSection(&g_InterfaceGlobalsLock);
|
|
|
|
return fReturn;
|
|
|
|
Failure:
|
|
|
|
fReturn = FALSE;
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// UnloadMadcap - release the MADCAP interface
|
|
//
|
|
// Entry: Nothing
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "UnloadMadcap"
|
|
|
|
void UnloadMadcap(void)
|
|
{
|
|
DNEnterCriticalSection(&g_InterfaceGlobalsLock);
|
|
|
|
//
|
|
// We have the interface globals lock, don't need DNInterlockedDecrement.
|
|
//
|
|
DNASSERT(g_iMadcapRefCount > 0);
|
|
g_iMadcapRefCount--;
|
|
if (g_iMadcapRefCount == 0 )
|
|
{
|
|
DPFX(DPFPREP, 5, "Unloading MADCAP API.");
|
|
|
|
McastApiCleanup();
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 8, "MADCAP API still has %i references.",
|
|
g_iMadcapRefCount);
|
|
}
|
|
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
}
|
|
//**********************************************************************
|
|
#endif // WINNT and not DPNBUILD_NOMULTICAST
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// CreateSPData - create instance data for SP
|
|
//
|
|
// Entry: Pointer to pointer to SPData
|
|
// Interface type
|
|
// Pointer to COM interface vtable
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CreateSPData"
|
|
|
|
HRESULT CreateSPData( CSPData **const ppSPData,
|
|
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
|
|
const short sSPType,
|
|
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
|
|
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
const XDP8CREATE_PARAMS * const pDP8CreateParams,
|
|
#endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
IDP8ServiceProviderVtbl *const pVtbl )
|
|
{
|
|
HRESULT hr;
|
|
CSPData *pSPData;
|
|
|
|
|
|
DNASSERT( ppSPData != NULL );
|
|
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
DNASSERT( pDP8CreateParams != NULL );
|
|
#endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
DNASSERT( pVtbl != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
*ppSPData = NULL;
|
|
pSPData = NULL;
|
|
|
|
//
|
|
// create data
|
|
//
|
|
pSPData = (CSPData*) DNMalloc(sizeof(CSPData));
|
|
if ( pSPData == NULL )
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
DPFX(DPFPREP, 0, "Cannot create data for Winsock interface!" );
|
|
goto Failure;
|
|
}
|
|
|
|
hr = pSPData->Initialize( pVtbl
|
|
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
|
|
,sSPType
|
|
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
|
|
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
,pDP8CreateParams
|
|
#endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
);
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to intialize SP data!" );
|
|
DisplayDNError( 0, hr );
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 6, "Created SP Data object 0x%p.", pSPData);
|
|
|
|
pSPData->AddRef(); // reference is now 1
|
|
*ppSPData = pSPData;
|
|
|
|
Exit:
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
|
|
if ( pSPData != NULL )
|
|
{
|
|
DNFree(pSPData);
|
|
pSPData = NULL;
|
|
}
|
|
|
|
DPFX(DPFPREP, 0, "Problem with CreateSPData (err = 0x%lx)!", hr);
|
|
DisplayDNError( 0, hr );
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// InitializeInterfaceGlobals - perform global initialization for an interface.
|
|
//
|
|
// Entry: Pointer to SPData
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitializeInterfaceGlobals"
|
|
|
|
HRESULT InitializeInterfaceGlobals( CSPData *const pSPData )
|
|
{
|
|
HRESULT hr;
|
|
CThreadPool *pThreadPool;
|
|
|
|
|
|
DNASSERT( pSPData != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
pThreadPool = NULL;
|
|
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
if ( g_pThreadPool == NULL )
|
|
{
|
|
DNASSERT( g_iThreadPoolRefCount == 0 );
|
|
g_pThreadPool = (CThreadPool*)g_ThreadPoolPool.Get();
|
|
if ( g_pThreadPool != NULL )
|
|
{
|
|
hr = g_pThreadPool->Initialize();
|
|
if ( hr != DPN_OK )
|
|
{
|
|
DPFX(DPFPREP, 0, "Initializing thread pool failed (err = 0x%lx)!", hr);
|
|
g_ThreadPoolPool.Release(g_pThreadPool);
|
|
g_pThreadPool = NULL;
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
else
|
|
{
|
|
g_pThreadPool->AddRef();
|
|
g_iThreadPoolRefCount++;
|
|
pThreadPool = g_pThreadPool;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DNASSERT( g_iThreadPoolRefCount != 0 );
|
|
g_iThreadPoolRefCount++;
|
|
g_pThreadPool->AddRef();
|
|
pThreadPool = g_pThreadPool;
|
|
}
|
|
|
|
Exit:
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
pSPData->SetThreadPool( g_pThreadPool );
|
|
|
|
return hr;
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// DeinitializeInterfaceGlobals - deinitialize thread pool and Rsip
|
|
//
|
|
// Entry: Pointer to service provider
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DeinitializeInterfaceGlobals"
|
|
|
|
void DeinitializeInterfaceGlobals( CSPData *const pSPData )
|
|
{
|
|
CThreadPool *pThreadPool;
|
|
|
|
|
|
DNASSERT( pSPData != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
pThreadPool = NULL;
|
|
|
|
//
|
|
// Process as little as possible inside the lock. If any of the items
|
|
// need to be released, pointers to them will be set.
|
|
//
|
|
DNEnterCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
DNASSERT( g_pThreadPool != NULL );
|
|
DNASSERT( g_iThreadPoolRefCount != 0 );
|
|
DNASSERT( g_pThreadPool == pSPData->GetThreadPool() );
|
|
|
|
pThreadPool = pSPData->GetThreadPool();
|
|
|
|
//
|
|
// remove thread pool reference
|
|
//
|
|
DNASSERT( pThreadPool != NULL );
|
|
g_iThreadPoolRefCount--;
|
|
if ( g_iThreadPoolRefCount == 0 )
|
|
{
|
|
g_pThreadPool = NULL;
|
|
}
|
|
else
|
|
{
|
|
pThreadPool = NULL;
|
|
}
|
|
|
|
DNLeaveCriticalSection( &g_InterfaceGlobalsLock );
|
|
|
|
//
|
|
// The thread pool will be cleaned up when all of the outstanding interfaces
|
|
// close.
|
|
//
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
#ifndef DPNBUILD_NOIPV6
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// DNIpv6AddressToStringW - Stolen from RtlIpv6AddressToString
|
|
//
|
|
// Generates an IPv6 string literal corresponding to the address Addr.
|
|
// The shortened canonical forms are used (RFC 1884 etc).
|
|
// The basic string representation consists of 8 hex numbers
|
|
// separated by colons, with a couple embellishments:
|
|
// - a string of zero numbers (at most one) is replaced
|
|
// with a double-colon.
|
|
// - the last 32 bits are represented in IPv4-style dotted-octet notation
|
|
// if the address is a v4-compatible or ISATAP address.
|
|
//
|
|
// For example,
|
|
// ::
|
|
// ::1
|
|
// ::157.56.138.30
|
|
// ::ffff:156.56.136.75
|
|
// ff01::
|
|
// ff02::2
|
|
// 0:1:2:3:4:5:6:7
|
|
//
|
|
// Entry: S - Receives a pointer to the buffer in which to place the string literal
|
|
// Addr - Receives the IPv6 address
|
|
//
|
|
// Exit: Pointer to the null byte at the end of the string inserted.
|
|
// This can be used by the caller to easily append more information
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNIpv6AddressToStringW"
|
|
|
|
LPWSTR DNIpv6AddressToStringW(const struct in6_addr *Addr, LPWSTR S)
|
|
{
|
|
int maxFirst, maxLast;
|
|
int curFirst, curLast;
|
|
int i;
|
|
int endHex = 8;
|
|
|
|
// Check for IPv6-compatible, IPv4-mapped, and IPv4-translated
|
|
// addresses
|
|
if ((Addr->s6_words[0] == 0) && (Addr->s6_words[1] == 0) &&
|
|
(Addr->s6_words[2] == 0) && (Addr->s6_words[3] == 0) &&
|
|
(Addr->s6_words[6] != 0)) {
|
|
if ((Addr->s6_words[4] == 0) &&
|
|
((Addr->s6_words[5] == 0) || (Addr->s6_words[5] == 0xffff)))
|
|
{
|
|
// compatible or mapped
|
|
S += _stprintf(S, _T("::%hs%u.%u.%u.%u"),
|
|
Addr->s6_words[5] == 0 ? "" : "ffff:",
|
|
Addr->s6_bytes[12], Addr->s6_bytes[13],
|
|
Addr->s6_bytes[14], Addr->s6_bytes[15]);
|
|
return S;
|
|
}
|
|
else if ((Addr->s6_words[4] == 0xffff) && (Addr->s6_words[5] == 0)) {
|
|
// translated
|
|
S += _stprintf(S, _T("::ffff:0:%u.%u.%u.%u"),
|
|
Addr->s6_bytes[12], Addr->s6_bytes[13],
|
|
Addr->s6_bytes[14], Addr->s6_bytes[15]);
|
|
return S;
|
|
}
|
|
}
|
|
|
|
|
|
// Find largest contiguous substring of zeroes
|
|
// A substring is [First, Last), so it's empty if First == Last.
|
|
|
|
maxFirst = maxLast = 0;
|
|
curFirst = curLast = 0;
|
|
|
|
// ISATAP EUI64 starts with 00005EFE (or 02005EFE)...
|
|
if (((Addr->s6_words[4] & 0xfffd) == 0) && (Addr->s6_words[5] == 0xfe5e)) {
|
|
endHex = 6;
|
|
}
|
|
|
|
for (i = 0; i < endHex; i++) {
|
|
|
|
if (Addr->s6_words[i] == 0) {
|
|
// Extend current substring
|
|
curLast = i+1;
|
|
|
|
// Check if current is now largest
|
|
if (curLast - curFirst > maxLast - maxFirst) {
|
|
|
|
maxFirst = curFirst;
|
|
maxLast = curLast;
|
|
}
|
|
}
|
|
else {
|
|
// Start a new substring
|
|
curFirst = curLast = i+1;
|
|
}
|
|
}
|
|
|
|
// Ignore a substring of length 1.
|
|
if (maxLast - maxFirst <= 1)
|
|
maxFirst = maxLast = 0;
|
|
|
|
// Write colon-separated words.
|
|
// A double-colon takes the place of the longest string of zeroes.
|
|
// All zeroes is just "::".
|
|
|
|
for (i = 0; i < endHex; i++) {
|
|
|
|
// Skip over string of zeroes
|
|
if ((maxFirst <= i) && (i < maxLast)) {
|
|
|
|
S += _stprintf(S, _T("::"));
|
|
i = maxLast-1;
|
|
continue;
|
|
}
|
|
|
|
// Need colon separator if not at beginning
|
|
if ((i != 0) && (i != maxLast))
|
|
S += _stprintf(S, _T(":"));
|
|
|
|
S += _stprintf(S, _T("%x"), NTOHS(Addr->s6_words[i])); // swap bytes
|
|
}
|
|
|
|
if (endHex < 8) {
|
|
S += _stprintf(S, _T(":%u.%u.%u.%u"),
|
|
Addr->s6_bytes[12], Addr->s6_bytes[13],
|
|
Addr->s6_bytes[14], Addr->s6_bytes[15]);
|
|
}
|
|
|
|
return S;
|
|
}
|
|
|
|
#endif // ! DPNBUILD_NOIPV6
|
|
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// AddInfoToBuffer - add an adapter info/multicast scope info structure to a packed buffer
|
|
//
|
|
// Entry: Pointer to packed buffer
|
|
// Pointer to adapter/scope name
|
|
// Pointer to adapter/scope guid
|
|
//
|
|
// Exit: Error code
|
|
// ------------------------------
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "AddInfoToBuffer"
|
|
|
|
HRESULT AddInfoToBuffer( CPackedBuffer *const pPackedBuffer,
|
|
const WCHAR *const pwszInfoName,
|
|
const GUID *const pInfoGUID,
|
|
const DWORD dwFlags )
|
|
{
|
|
HRESULT hr;
|
|
DPN_SERVICE_PROVIDER_INFO AdapterInfo;
|
|
|
|
|
|
#ifndef DPNBUILD_NOMULTICAST
|
|
DBG_CASSERT( sizeof( DPN_SERVICE_PROVIDER_INFO ) == sizeof( DPN_MULTICAST_SCOPE_INFO ) );
|
|
DBG_CASSERT( OFFSETOF( DPN_SERVICE_PROVIDER_INFO, dwFlags ) == OFFSETOF( DPN_MULTICAST_SCOPE_INFO, dwFlags ) );
|
|
DBG_CASSERT( OFFSETOF( DPN_SERVICE_PROVIDER_INFO, guid ) == OFFSETOF( DPN_MULTICAST_SCOPE_INFO, guid ) );
|
|
DBG_CASSERT( OFFSETOF( DPN_SERVICE_PROVIDER_INFO, pwszName ) == OFFSETOF( DPN_MULTICAST_SCOPE_INFO, pwszName ) );
|
|
DBG_CASSERT( OFFSETOF( DPN_SERVICE_PROVIDER_INFO, pvReserved ) == OFFSETOF( DPN_MULTICAST_SCOPE_INFO, pvReserved ) );
|
|
DBG_CASSERT( OFFSETOF( DPN_SERVICE_PROVIDER_INFO, dwReserved ) == OFFSETOF( DPN_MULTICAST_SCOPE_INFO, dwReserved ) );
|
|
#endif // ! DPNBUILD_NOMULTICAST
|
|
|
|
DNASSERT( pPackedBuffer != NULL );
|
|
DNASSERT( pwszInfoName != NULL );
|
|
DNASSERT( pInfoGUID != NULL );
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = DPN_OK;
|
|
|
|
memset( &AdapterInfo, 0x00, sizeof( AdapterInfo ) );
|
|
AdapterInfo.dwFlags = dwFlags;
|
|
AdapterInfo.guid = *pInfoGUID;
|
|
|
|
hr = pPackedBuffer->AddWCHARStringToBack( pwszInfoName );
|
|
if ( ( hr != DPNERR_BUFFERTOOSMALL ) && ( hr != DPN_OK ) )
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to add info name to buffer!" );
|
|
goto Failure;
|
|
}
|
|
AdapterInfo.pwszName = static_cast<WCHAR*>( pPackedBuffer->GetTailAddress() );
|
|
|
|
hr = pPackedBuffer->AddToFront( &AdapterInfo, sizeof( AdapterInfo ) );
|
|
|
|
Exit:
|
|
return hr;
|
|
|
|
Failure:
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
|
|
#ifdef _XBOX
|
|
|
|
|
|
typedef struct _REFCOUNTXNKEY
|
|
{
|
|
LONG lRefCount;
|
|
XNKID xnkid;
|
|
XNKEY xnkey;
|
|
} REFCOUNTXNKEY;
|
|
|
|
REFCOUNTXNKEY * g_paRefcountXnKeys = NULL;
|
|
DWORD g_dwMaxNumRefcountXnKeys = 0;
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitializeRefcountXnKeys"
|
|
BOOL InitializeRefcountXnKeys(const DWORD dwKeyRegMax)
|
|
{
|
|
BOOL fResult;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (%u)", dwKeyRegMax);
|
|
DNASSERT(dwKeyRegMax != 0);
|
|
|
|
DNASSERT(g_paRefcountXnKeys == NULL);
|
|
|
|
g_paRefcountXnKeys = (REFCOUNTXNKEY*) DNMalloc(dwKeyRegMax * sizeof(REFCOUNTXNKEY));
|
|
if (g_paRefcountXnKeys == NULL)
|
|
{
|
|
g_dwMaxNumRefcountXnKeys = 0;
|
|
fResult = FALSE;
|
|
}
|
|
else
|
|
{
|
|
memset(g_paRefcountXnKeys, 0, (dwKeyRegMax * sizeof(REFCOUNTXNKEY)));
|
|
g_dwMaxNumRefcountXnKeys = dwKeyRegMax;
|
|
fResult = TRUE;
|
|
}
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", fResult);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CleanupRefcountXnKeys"
|
|
void WINAPI CleanupRefcountXnKeys(void)
|
|
{
|
|
#ifdef DBG
|
|
DWORD dwTemp;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Enter");
|
|
|
|
DNASSERT(g_paRefcountXnKeys != NULL);
|
|
|
|
for(dwTemp = 0; dwTemp < g_dwMaxNumRefcountXnKeys; dwTemp++)
|
|
{
|
|
DNASSERT(g_paRefcountXnKeys[dwTemp].lRefCount == 0);
|
|
}
|
|
#endif // DBG
|
|
|
|
DNFree(g_paRefcountXnKeys);
|
|
g_paRefcountXnKeys = NULL;
|
|
g_dwMaxNumRefcountXnKeys = 0;
|
|
|
|
DPFX(DPFPREP, 3, "Leave");
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "RegisterRefcountXnKey"
|
|
INT WINAPI RegisterRefcountXnKey(const XNKID * pxnkid, const XNKEY * pxnkey)
|
|
{
|
|
int iReturn;
|
|
DWORD dwTemp;
|
|
DWORD dwIndex = -1;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (0x%p, 0x%p)", pxnkid, pxnkey);
|
|
|
|
DNASSERT(pxnkid != NULL);
|
|
DNASSERT(pxnkey != NULL);
|
|
|
|
DNASSERT(g_paRefcountXnKeys != NULL);
|
|
|
|
for(dwTemp = 0; dwTemp < g_dwMaxNumRefcountXnKeys; dwTemp++)
|
|
{
|
|
if (g_paRefcountXnKeys[dwTemp].lRefCount > 0)
|
|
{
|
|
if (memcmp(pxnkid, &g_paRefcountXnKeys[dwTemp].xnkid, sizeof(XNKID)) == 0)
|
|
{
|
|
DPFX(DPFPREP, 1, "Key has already been registered.");
|
|
g_paRefcountXnKeys[dwTemp].lRefCount++;
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DNASSERT(g_paRefcountXnKeys[dwTemp].lRefCount == 0);
|
|
if (dwIndex == -1)
|
|
{
|
|
dwIndex = dwTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dwIndex == -1)
|
|
{
|
|
DPFX(DPFPREP, 0, "No more keys can be registered!");
|
|
DNASSERTX(! "No more keys can be registered!", 2);
|
|
iReturn = WSAENOBUFS;
|
|
goto Exit;
|
|
}
|
|
|
|
iReturn = XNetRegisterKey(pxnkid, pxnkey);
|
|
if (iReturn != 0)
|
|
{
|
|
DPFX(DPFPREP, 0, "Registering key failed!");
|
|
goto Exit;
|
|
}
|
|
|
|
DNASSERT(g_paRefcountXnKeys[dwIndex].lRefCount == 0);
|
|
g_paRefcountXnKeys[dwIndex].lRefCount = 1;
|
|
memcpy(&g_paRefcountXnKeys[dwIndex].xnkid, pxnkid, sizeof(XNKID));
|
|
memcpy(&g_paRefcountXnKeys[dwIndex].xnkey, pxnkey, sizeof(XNKEY));
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "UnregisterRefcountXnKey"
|
|
INT WINAPI UnregisterRefcountXnKey(const XNKID * pxnkid)
|
|
{
|
|
int iReturn;
|
|
DWORD dwTemp;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (0x%p)", pxnkid);
|
|
|
|
DNASSERT(pxnkid != NULL);
|
|
|
|
DNASSERT(g_paRefcountXnKeys != NULL);
|
|
|
|
for(dwTemp = 0; dwTemp < g_dwMaxNumRefcountXnKeys; dwTemp++)
|
|
{
|
|
if (g_paRefcountXnKeys[dwTemp].lRefCount > 0)
|
|
{
|
|
if (memcmp(pxnkid, &g_paRefcountXnKeys[dwTemp].xnkid, sizeof(XNKID)) == 0)
|
|
{
|
|
g_paRefcountXnKeys[dwTemp].lRefCount--;
|
|
if (g_paRefcountXnKeys[dwTemp].lRefCount == 0)
|
|
{
|
|
iReturn = XNetUnregisterKey(pxnkid);
|
|
if (iReturn != 0)
|
|
{
|
|
DPFX(DPFPREP, 0, "Unregistering key failed!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iReturn = 0;
|
|
}
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DNASSERT(g_paRefcountXnKeys[dwTemp].lRefCount == 0);
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, 0, "Key has not been registered!");
|
|
DNASSERTX(! "Key has not been registered!", 2);
|
|
iReturn = -1;
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef XBOX_ON_DESKTOP
|
|
|
|
typedef struct _SECURITYASSOCIATION
|
|
{
|
|
BOOL fInUse;
|
|
XNADDR xnaddr;
|
|
IN_ADDR inaddr;
|
|
} SECURITYASSOCIATION;
|
|
|
|
typedef struct _KEYENTRY
|
|
{
|
|
BOOL fInUse;
|
|
XNKID xnkid;
|
|
XNKEY xnkey;
|
|
SECURITYASSOCIATION * paSecurityAssociations;
|
|
} KEYENTRY;
|
|
|
|
KEYENTRY * g_paKeys = NULL;
|
|
DWORD g_dwMaxNumKeys = 0;
|
|
DWORD g_dwMaxNumAssociations = 0;
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetStartup"
|
|
INT WINAPI XNetStartup(const XNetStartupParams * pxnsp)
|
|
{
|
|
int iReturn;
|
|
XNetStartupParams StartupParamsCapped;
|
|
DWORD dwTemp;
|
|
|
|
|
|
#ifdef DBG
|
|
//DPFX(DPFPREP, 3, "Parameters: (0x%p)", pxnsp);
|
|
|
|
// Not using DNASSERT because DPlay may not be initted yet.
|
|
if (! (g_paKeys == NULL))
|
|
{
|
|
OutputDebugString("Assert failed (g_paKeys == NULL)\n");
|
|
DebugBreak();
|
|
}
|
|
#endif // DBG
|
|
|
|
if (pxnsp == NULL)
|
|
{
|
|
memset(&StartupParamsCapped, 0, sizeof(StartupParamsCapped));
|
|
}
|
|
else
|
|
{
|
|
memcpy(&StartupParamsCapped, pxnsp, sizeof(StartupParamsCapped));
|
|
}
|
|
|
|
if (StartupParamsCapped.cfgKeyRegMax == 0)
|
|
{
|
|
StartupParamsCapped.cfgKeyRegMax = 4;
|
|
}
|
|
|
|
if (StartupParamsCapped.cfgSecRegMax == 0)
|
|
{
|
|
StartupParamsCapped.cfgSecRegMax = 32;
|
|
}
|
|
|
|
|
|
// Not using DNMalloc because DPlay may not be initted yet.
|
|
g_paKeys = (KEYENTRY*) HeapAlloc(GetProcessHeap(), 0, StartupParamsCapped.cfgKeyRegMax * sizeof(KEYENTRY));
|
|
if (g_paKeys == NULL)
|
|
{
|
|
iReturn = -1;
|
|
goto Failure;
|
|
}
|
|
|
|
memset(g_paKeys, 0, (StartupParamsCapped.cfgKeyRegMax * sizeof(KEYENTRY)));
|
|
|
|
for(dwTemp = 0; dwTemp < StartupParamsCapped.cfgKeyRegMax; dwTemp++)
|
|
{
|
|
// Not using DNMalloc because DPlay may not be initted yet.
|
|
g_paKeys[dwTemp].paSecurityAssociations = (SECURITYASSOCIATION*) HeapAlloc(GetProcessHeap(), 0, StartupParamsCapped.cfgSecRegMax * sizeof(SECURITYASSOCIATION));
|
|
if (g_paKeys == NULL)
|
|
{
|
|
iReturn = -1;
|
|
goto Failure;
|
|
}
|
|
|
|
memset(g_paKeys[dwTemp].paSecurityAssociations, 0, (StartupParamsCapped.cfgSecRegMax * sizeof(SECURITYASSOCIATION)));
|
|
}
|
|
|
|
g_dwMaxNumKeys = StartupParamsCapped.cfgKeyRegMax;
|
|
g_dwMaxNumAssociations = StartupParamsCapped.cfgSecRegMax;
|
|
|
|
|
|
iReturn = 0;
|
|
|
|
|
|
Exit:
|
|
|
|
//DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
|
|
|
|
Failure:
|
|
|
|
if (g_paKeys != NULL)
|
|
{
|
|
for(dwTemp = 0; dwTemp < StartupParamsCapped.cfgKeyRegMax; dwTemp++)
|
|
{
|
|
if (g_paKeys[dwTemp].paSecurityAssociations != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, g_paKeys[dwTemp].paSecurityAssociations);
|
|
g_paKeys[dwTemp].paSecurityAssociations = NULL;
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, g_paKeys);
|
|
g_paKeys = NULL;
|
|
}
|
|
|
|
g_dwMaxNumKeys = 0;
|
|
g_dwMaxNumAssociations = 0;
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetCleanup"
|
|
INT WINAPI XNetCleanup(void)
|
|
{
|
|
int iReturn;
|
|
DWORD dwTemp;
|
|
|
|
|
|
#ifdef DBG
|
|
//DPFX(DPFPREP, 3, "Enter");
|
|
|
|
// Not using DNASSERT because DPlay may not be initted anymore.
|
|
if (! (g_paKeys != NULL))
|
|
{
|
|
OutputDebugString("Assert failed (g_paKeys != NULL)\n");
|
|
DebugBreak();
|
|
}
|
|
#endif // DBG
|
|
|
|
for(dwTemp = 0; dwTemp < g_dwMaxNumKeys; dwTemp++)
|
|
{
|
|
if (g_paKeys[dwTemp].paSecurityAssociations != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, g_paKeys[dwTemp].paSecurityAssociations);
|
|
g_paKeys[dwTemp].paSecurityAssociations = NULL;
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, g_paKeys);
|
|
g_paKeys = NULL;
|
|
|
|
g_dwMaxNumKeys = 0;
|
|
g_dwMaxNumAssociations = 0;
|
|
|
|
|
|
iReturn = 0;
|
|
|
|
//DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetRegisterKey"
|
|
INT WINAPI XNetRegisterKey(const XNKID * pxnkid, const XNKEY * pxnkey)
|
|
{
|
|
int iReturn;
|
|
DWORD dwTemp;
|
|
DWORD dwIndex = -1;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (0x%p, 0x%p)", pxnkid, pxnkey);
|
|
|
|
DNASSERT(pxnkid != NULL);
|
|
DNASSERT(pxnkey != NULL);
|
|
|
|
for(dwTemp = 0; dwTemp < g_dwMaxNumKeys; dwTemp++)
|
|
{
|
|
if (g_paKeys[dwTemp].fInUse)
|
|
{
|
|
if (memcmp(pxnkid, &g_paKeys[dwTemp].xnkid, sizeof(XNKID)) == 0)
|
|
{
|
|
DPFX(DPFPREP, 2, "Key has already been registered.");
|
|
iReturn = WSAEALREADY;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dwIndex == -1)
|
|
{
|
|
dwIndex = dwTemp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dwIndex == -1)
|
|
{
|
|
DPFX(DPFPREP, 0, "No more keys can be registered!");
|
|
iReturn = WSAENOBUFS;
|
|
goto Exit;
|
|
}
|
|
|
|
g_paKeys[dwIndex].fInUse = TRUE;
|
|
memcpy(&g_paKeys[dwIndex].xnkid, pxnkid, sizeof(XNKID));
|
|
memcpy(&g_paKeys[dwIndex].xnkey, pxnkey, sizeof(XNKEY));
|
|
iReturn = 0;
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetUnregisterKey"
|
|
INT WINAPI XNetUnregisterKey(const XNKID * pxnkid)
|
|
{
|
|
int iReturn;
|
|
DWORD dwTemp;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (0x%p)", pxnkid);
|
|
|
|
DNASSERT(pxnkid != NULL);
|
|
|
|
for(dwTemp = 0; dwTemp < g_dwMaxNumKeys; dwTemp++)
|
|
{
|
|
if (g_paKeys[dwTemp].fInUse)
|
|
{
|
|
if (memcmp(pxnkid, &g_paKeys[dwTemp].xnkid, sizeof(XNKID)) == 0)
|
|
{
|
|
g_paKeys[dwTemp].fInUse = FALSE;
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, 0, "Key has not been registered!");
|
|
DNASSERTX(! "Key has not been registered!", 2);
|
|
iReturn = -1;
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetXnAddrToInAddr"
|
|
INT WINAPI XNetXnAddrToInAddr(const XNADDR * pxna, const XNKID * pxnkid, IN_ADDR * pina)
|
|
{
|
|
int iReturn;
|
|
DWORD dwKey;
|
|
DWORD dwAssociation;
|
|
DWORD dwIndex;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (0x%p, 0x%p, 0x%p)", pxna, pxnkid, pina);
|
|
|
|
DNASSERT(pxna != NULL);
|
|
DNASSERT(pxnkid != NULL);
|
|
DNASSERT(pina != NULL);
|
|
|
|
for(dwKey = 0; dwKey < g_dwMaxNumKeys; dwKey++)
|
|
{
|
|
if ((g_paKeys[dwKey].fInUse) &&
|
|
(memcmp(pxnkid, &g_paKeys[dwKey].xnkid, sizeof(XNKID)) == 0))
|
|
{
|
|
dwIndex = -1;
|
|
|
|
for(dwAssociation = 0; dwAssociation < g_dwMaxNumAssociations; dwAssociation++)
|
|
{
|
|
if (g_paKeys[dwKey].paSecurityAssociations[dwAssociation].fInUse)
|
|
{
|
|
if (memcmp(pxna, &g_paKeys[dwKey].paSecurityAssociations[dwAssociation].xnaddr, sizeof(XNADDR)) == 0)
|
|
{
|
|
memcpy(pina, &g_paKeys[dwKey].paSecurityAssociations[dwAssociation].inaddr, sizeof(IN_ADDR));
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dwIndex == -1)
|
|
{
|
|
dwIndex = dwAssociation;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dwIndex == -1)
|
|
{
|
|
DPFX(DPFPREP, 0, "No more security associations can be made!");
|
|
iReturn = WSAENOBUFS;
|
|
goto Exit;
|
|
}
|
|
|
|
g_paKeys[dwKey].paSecurityAssociations[dwIndex].fInUse = TRUE;
|
|
memcpy(&g_paKeys[dwKey].paSecurityAssociations[dwIndex].xnaddr, pxna, sizeof(XNADDR));
|
|
DBG_CASSERT(sizeof(pxna->abEnet) > (sizeof(IN_ADDR) + 1));
|
|
memcpy(&g_paKeys[dwKey].paSecurityAssociations[dwIndex].inaddr, &pxna->abEnet[1], sizeof(IN_ADDR));
|
|
memcpy(pina, &g_paKeys[dwKey].paSecurityAssociations[dwIndex].inaddr, sizeof(IN_ADDR));
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, 0, "Key has not been registered!");
|
|
DNASSERTX(! "Key has not been registered!", 2);
|
|
iReturn = -1;
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetInAddrToXnAddr"
|
|
INT WINAPI XNetInAddrToXnAddr(const IN_ADDR ina, XNADDR * pxna, XNKID * pxnkid)
|
|
{
|
|
int iReturn;
|
|
DWORD dwKey;
|
|
DWORD dwAssociation;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (%u.%u.%u.%u, 0x%p, 0x%p)",
|
|
ina.S_un.S_un_b.s_b1, ina.S_un.S_un_b.s_b2, ina.S_un.S_un_b.s_b3, ina.S_un.S_un_b.s_b4, pxna, pxnkid);
|
|
|
|
//
|
|
// Special case the loopback address, that just means the title address.
|
|
//
|
|
if (ina.S_un.S_addr == IP_LOOPBACK_ADDRESS)
|
|
{
|
|
if (pxna != NULL)
|
|
{
|
|
iReturn = XNetGetTitleXnAddr(pxna);
|
|
DNASSERT((iReturn != XNET_GET_XNADDR_PENDING) && (iReturn != XNET_GET_XNADDR_NONE));
|
|
}
|
|
|
|
if (pxnkid != NULL)
|
|
{
|
|
memset(pxnkid, 0, sizeof(XNKID));
|
|
}
|
|
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
for(dwKey = 0; dwKey < g_dwMaxNumKeys; dwKey++)
|
|
{
|
|
if (g_paKeys[dwKey].fInUse)
|
|
{
|
|
for(dwAssociation = 0; dwAssociation < g_dwMaxNumAssociations; dwAssociation++)
|
|
{
|
|
if (g_paKeys[dwKey].paSecurityAssociations[dwAssociation].fInUse)
|
|
{
|
|
if (memcmp(&ina, &g_paKeys[dwKey].paSecurityAssociations[dwAssociation].inaddr, sizeof(IN_ADDR)) == 0)
|
|
{
|
|
if (pxna != NULL)
|
|
{
|
|
memcpy(pxna, &g_paKeys[dwKey].paSecurityAssociations[dwAssociation].xnaddr, sizeof(XNADDR));
|
|
}
|
|
|
|
if (pxnkid != NULL)
|
|
{
|
|
memcpy(pxnkid, &g_paKeys[dwKey].xnkid, sizeof(XNKID));
|
|
}
|
|
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, 0, "No security association for IN_ADDR specified!");
|
|
DNASSERTX(! "No security association for IN_ADDR specified!", 2);
|
|
iReturn = -1;
|
|
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetGetTitleXnAddr"
|
|
DWORD WINAPI XNetGetTitleXnAddr(XNADDR * pxna)
|
|
{
|
|
DWORD dwReturn;
|
|
char szBuffer[256];
|
|
PHOSTENT phostent;
|
|
IN_ADDR * pinaddr;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (0x%p)", pxna);
|
|
|
|
DNASSERT(pxna != NULL);
|
|
|
|
if (gethostname(szBuffer, sizeof(szBuffer)) == SOCKET_ERROR)
|
|
{
|
|
#ifdef DBG
|
|
dwReturn = WSAGetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to get host name into fixed size buffer (err = %i)!", dwReturn);
|
|
DisplayWinsockError(0, dwReturn);
|
|
#endif // DBG
|
|
dwReturn = XNET_GET_XNADDR_NONE;
|
|
goto Exit;
|
|
}
|
|
|
|
phostent = gethostbyname(szBuffer);
|
|
if (phostent == NULL)
|
|
{
|
|
#ifdef DBG
|
|
dwReturn = WSAGetLastError();
|
|
DPFX(DPFPREP, 0, "Failed to get host data (err = %i)!", dwReturn);
|
|
DisplayWinsockError(0, dwReturn);
|
|
#endif // DBG
|
|
dwReturn = XNET_GET_XNADDR_NONE;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
memset(pxna, 0, sizeof(XNADDR));
|
|
|
|
//
|
|
// We'll use the first address returned.
|
|
//
|
|
pinaddr = (IN_ADDR*) phostent->h_addr_list[0];
|
|
DNASSERT(pinaddr != NULL);
|
|
|
|
DBG_CASSERT(sizeof(pxna->abEnet) > (sizeof(IN_ADDR) + 1));
|
|
memset(&pxna->abEnet, 0xFF, sizeof(pxna->abEnet));
|
|
memcpy(&pxna->abEnet[1], pinaddr, sizeof(IN_ADDR));
|
|
|
|
memcpy(&pxna->ina, pinaddr, sizeof(IN_ADDR));
|
|
|
|
|
|
//
|
|
// Pretend it's always DHCP.
|
|
//
|
|
dwReturn = XNET_GET_XNADDR_DHCP;
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%u]", dwReturn);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetGetEthernetLinkStatus"
|
|
DWORD WINAPI XNetGetEthernetLinkStatus(void)
|
|
{
|
|
DWORD dwReturn;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Enter");
|
|
|
|
//
|
|
// Hard code an active 10 Mbit link.
|
|
//
|
|
dwReturn = XNET_ETHERNET_LINK_ACTIVE | XNET_ETHERNET_LINK_10MBPS;
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [0x%x]", dwReturn);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "XNetPrivCreateAssociation"
|
|
INT WINAPI XNetPrivCreateAssociation(const XNKID * pxnkid, const CSocketAddress * const pSocketAddress)
|
|
{
|
|
int iReturn;
|
|
SOCKADDR_IN * psockaddrin;
|
|
DWORD dwKey;
|
|
DWORD dwAssociation;
|
|
DWORD dwIndex;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "Parameters: (0x%p, 0x%p)", pxnkid, pSocketAddress);
|
|
|
|
DNASSERT(pxnkid != NULL);
|
|
DNASSERT(pSocketAddress != NULL);
|
|
DNASSERT(pSocketAddress->GetFamily() == AF_INET);
|
|
psockaddrin = (SOCKADDR_IN*) pSocketAddress->GetAddress();
|
|
|
|
for(dwKey = 0; dwKey < g_dwMaxNumKeys; dwKey++)
|
|
{
|
|
if ((g_paKeys[dwKey].fInUse) &&
|
|
(memcmp(pxnkid, &g_paKeys[dwKey].xnkid, sizeof(XNKID)) == 0))
|
|
{
|
|
dwIndex = -1;
|
|
|
|
for(dwAssociation = 0; dwAssociation < g_dwMaxNumAssociations; dwAssociation++)
|
|
{
|
|
if (g_paKeys[dwKey].paSecurityAssociations[dwAssociation].fInUse)
|
|
{
|
|
if (memcmp(&psockaddrin->sin_addr, &g_paKeys[dwKey].paSecurityAssociations[dwAssociation].xnaddr, sizeof(psockaddrin->sin_addr)) == 0)
|
|
{
|
|
DPFX(DPFPREP, 2, "Security association already made.");
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (dwIndex == -1)
|
|
{
|
|
dwIndex = dwAssociation;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dwIndex == -1)
|
|
{
|
|
DPFX(DPFPREP, 0, "No more security associations can be made!");
|
|
iReturn = WSAENOBUFS;
|
|
goto Exit;
|
|
}
|
|
|
|
g_paKeys[dwKey].paSecurityAssociations[dwIndex].fInUse = TRUE;
|
|
memset(&g_paKeys[dwKey].paSecurityAssociations[dwIndex].xnaddr, 0, sizeof(XNADDR));
|
|
memset(&g_paKeys[dwKey].paSecurityAssociations[dwIndex].xnaddr.abEnet, 0xFF,
|
|
sizeof(g_paKeys[dwKey].paSecurityAssociations[dwIndex].xnaddr.abEnet));
|
|
DBG_CASSERT(sizeof(g_paKeys[dwKey].paSecurityAssociations[dwIndex].xnaddr.abEnet) > (sizeof(IN_ADDR) + 1));
|
|
memcpy(&g_paKeys[dwKey].paSecurityAssociations[dwIndex].xnaddr.abEnet[1],
|
|
&psockaddrin->sin_addr, sizeof(IN_ADDR));
|
|
memcpy(&g_paKeys[dwKey].paSecurityAssociations[dwIndex].inaddr, &psockaddrin->sin_addr, sizeof(IN_ADDR));
|
|
iReturn = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, 0, "Key has not been registered!");
|
|
DNASSERTX(! "Key has not been registered!", 2);
|
|
iReturn = -1;
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "Returning: [%i]", iReturn);
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
|
|
#endif // XBOX_ON_DESKTOP
|
|
|
|
#endif // _XBOX
|
|
|