Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2413 lines
70 KiB

/*==========================================================================
*
* Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
*
* File: SPData.cpp
* Content: Global variables for the DNSerial service provider in class
* format.
*
*
* History:
* Date By Reason
* ==== == ======
* 03/15/99 jtk Dereived from Locals.cpp
* 01/10/2000 rmt Updated to build with Millennium build process
* 03/22/2000 jtk Updated with changes to interface names
***************************************************************************/
#include "dnwsocki.h"
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::Initialize - initialize
//
// Entry: SP type
// Pointer to SP COM vtable
//
// Exit: Error code
//
// Note: This function assumes that someone else is preventing reentry!
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::Initialize"
HRESULT CSPData::Initialize(
IDP8ServiceProviderVtbl *const pVtbl
#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
)
{
HRESULT hr;
BOOL fLockInitialized;
#ifndef DPNBUILD_LIBINTERFACE
BOOL fWinsockLoaded;
#endif // ! DPNBUILD_LIBINTERFACE
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
DWORD dwNumToAllocate;
DWORD dwAllocated;
READ_IO_DATA_POOL_CONTEXT ReadIODataPoolContext;
#endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p, 0x%p)", this, pVtbl, pDP8CreateParams);
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p, %u, 0x%p)", this, pVtbl, sSPType, pDP8CreateParams);
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
#else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p)", this, pVtbl);
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
DPFX(DPFPREP, 4, "(0x%p) Parameters:(0x%p, 0x%p, %u)", this, pVtbl, sSPType);
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
#endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
DNASSERT( pVtbl != NULL );
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
DNASSERT( pDP8CreateParams != NULL );
#endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
//
// initialize
//
hr = DPN_OK;
#ifndef DPNBUILD_LIBINTERFACE
fWinsockLoaded = FALSE;
#endif // ! DPNBUILD_LIBINTERFACE
fLockInitialized = FALSE;
m_lRefCount = 0;
m_lObjectRefCount = 0;
m_hShutdownEvent = NULL;
m_SPState = SPSTATE_UNINITIALIZED;
m_pThreadPool = NULL;
m_pSocketData = NULL;
m_Sig[0] = 'S';
m_Sig[1] = 'P';
m_Sig[2] = 'D';
m_Sig[3] = 'T';
memset( &m_InitData, 0x00, sizeof( m_InitData ) );
memset( &m_COMInterface, 0x00, sizeof( m_COMInterface ) );
#ifndef DPNBUILD_LIBINTERFACE
DNInterlockedIncrement( const_cast<LONG*>(&g_lOutstandingInterfaceCount) );
#endif // ! DPNBUILD_LIBINTERFACE
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
m_sSPType = sSPType;
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
DNASSERT( m_COMInterface.m_pCOMVtbl == NULL );
m_COMInterface.m_pCOMVtbl = pVtbl;
#ifndef DPNBUILD_LIBINTERFACE
//
// Attempt to load Winsock.
//
if ( LoadWinsock() == FALSE )
{
DPFX(DPFPREP, 0, "Failed to load winsock!" );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
fWinsockLoaded = TRUE;
#endif // ! DPNBUILD_LIBINTERFACE
//
// initialize internal critical sections
//
if ( DNInitializeCriticalSection( &m_Lock ) == FALSE )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Problem initializing main critical section!" );
goto Failure;
}
DebugSetCriticalSectionRecursionCount( &m_Lock, 0 );
DebugSetCriticalSectionGroup( &m_Lock, &g_blDPNWSockCritSecsHeld ); // separate dpnwsock CSes from the rest of DPlay's CSes
fLockInitialized = TRUE;
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
//
// Pre-allocate a socket data object.
//
dwNumToAllocate = 1;
dwAllocated = g_SocketDataPool.Preallocate(dwNumToAllocate, NULL);
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u requested socket data objects!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Allocate a couple addresses for each remote player (one for
// each receive plus one for the endpoint), and an address for
// a local listen endpoint.
// Also allocate an address per command since we frequently
// use temporary addresses (see below).
// And finally, include addresses for the pending receives (see
// below).
//
DNASSERT(pDP8CreateParams->dwMaxNumPlayers > 0);
dwNumToAllocate = (pDP8CreateParams->dwMaxNumPlayers - 1)
* (pDP8CreateParams->dwMaxReceivesPerPlayer + 1)
+ 1;
dwNumToAllocate += pDP8CreateParams->dwMaxNumPlayers
+ pDP8CreateParams->dwNumSimultaneousEnumHosts;
#pragma TODO(vanceo, "This represents outstanding receives; on multi-proc machines this would be multiplied by # CPUs")
dwNumToAllocate += 1;
dwNumToAllocate++; // include one to cover a receive that's being processed
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
dwAllocated = g_SocketAddressPool.Preallocate(dwNumToAllocate, NULL);
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
dwAllocated = g_SocketAddressPool.Preallocate(dwNumToAllocate, ((PVOID) ((DWORD_PTR) GetType())));
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u requested socket addresses!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Pre-allocate one socketport.
//
dwNumToAllocate = 1;
dwAllocated = g_SocketPortPool.Preallocate(dwNumToAllocate, (PVOID) pDP8CreateParams);
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u requested socket ports!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Allocate an endpoint for each remote player, plus one for a
// listen endpoint. If more simultaneous enums are expected than
// remote players, use that instead, and allow for the connect to
// be bound while the enumerations are still running.
//
dwNumToAllocate = pDP8CreateParams->dwMaxNumPlayers;
if (dwNumToAllocate <= pDP8CreateParams->dwNumSimultaneousEnumHosts)
{
dwNumToAllocate = pDP8CreateParams->dwNumSimultaneousEnumHosts + 1;
}
dwAllocated = g_EndpointPool.Preallocate(dwNumToAllocate, this);
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u requested endpoints!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Set the handle table size to hold all the endpoints.
//
hr = m_HandleTable.SetTableSize(dwNumToAllocate);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't set handle table size to %u entries!",
dwNumToAllocate);
goto Failure;
}
//
// Allocate a command for connects to each remote player, plus
// one for a listen endpoint.
// Add in one for each enum host operation.
//
dwNumToAllocate = pDP8CreateParams->dwMaxNumPlayers;
dwNumToAllocate += pDP8CreateParams->dwNumSimultaneousEnumHosts;
dwAllocated = g_CommandDataPool.Preallocate(dwNumToAllocate, NULL);
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u command data objects!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Allocate an endpoint command parameter object for each command.
//
dwAllocated = g_EndpointCommandParametersPool.Preallocate(dwNumToAllocate, NULL);
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u endpoint command parameter objects!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Pre-allocate two address objects for each command to support the
// address info indications.
//
hr = DNAddress_PreallocateInterfaces(dwNumToAllocate);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't pre-allocate %u address objects!",
dwNumToAllocate);
goto Failure;
}
#pragma TODO(vanceo, "This is located in DN_PopulateCorePools because m_pThreadPool isn't set at this point")
/*
//
// Pre-allocate per-CPU items for the threadpool. We want:
// + one work item for each command
// + one timer per enum hosts operation
// + one I/O operation per simultaneous read
//
#ifdef DPNBUILD_ONLYONEPROCESSOR
hr = IDirectPlay8ThreadPoolWork_Preallocate(m_pThreadPool->GetDPThreadPoolWork(),
dwNumToAllocate,
pDP8CreateParams->dwNumSimultaneousEnumHosts,
1,
0);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't pre-allocate %u work items, %u timers, or 1 I/O operation!",
dwNumToAllocate,
pDP8CreateParams->dwNumSimultaneousEnumHosts);
goto Failure;
}
#else // ! DPNBUILD_ONLYONEPROCESSOR
#pragma TODO(vanceo, "This would be multiplied by number of CPUs")
hr = IDirectPlay8ThreadPoolWork_Preallocate(m_pThreadPool->GetDPThreadPoolWork(),
dwNumToAllocate,
pDP8CreateParams->dwNumSimultaneousEnumHosts,
1,
0);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't pre-allocate %u work items, %u timers, or %u I/O operations!",
dwNumToAllocate,
pDP8CreateParams->dwNumSimultaneousEnumHosts,
1);
goto Failure;
}
#endif // ! DPNBUILD_ONLYONEPROCESSOR
*/
//
// Allocate a timer entry for each enum command.
//
dwNumToAllocate = pDP8CreateParams->dwNumSimultaneousEnumHosts;
dwAllocated = g_TimerEntryPool.Preallocate(dwNumToAllocate, NULL);
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u timer entries!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Allocate the desired number of receives.
// Include extras for the outstanding receives that haven't been
// completed by Winsock.
// See socket address preallocation above.
//
ReadIODataPoolContext.pThreadPool = NULL;
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
ReadIODataPoolContext.sSPType = GetType();
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
#ifndef DPNBUILD_ONLYONEPROCESSOR
ReadIODataPoolContext.dwCPU = -1; // unknown right now
#endif // ! DPNBUILD_ONLYONEPROCESSOR
dwNumToAllocate = (pDP8CreateParams->dwMaxNumPlayers - 1)
* pDP8CreateParams->dwMaxReceivesPerPlayer;
#pragma TODO(vanceo, "This would be multiplied by number of CPUs on multiproc machines")
dwNumToAllocate += 1;
dwNumToAllocate++; // include one to cover a receive that's being processed
dwAllocated = g_ReadIODataPool.Preallocate(dwNumToAllocate,
&ReadIODataPoolContext);
if (dwAllocated < dwNumToAllocate)
{
DPFX(DPFPREP, 0, "Only allocated %u of %u read I/O data buffers!",
dwAllocated, dwNumToAllocate);
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
#endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
Exit:
DPFX(DPFPREP, 4, "(0x%p) Return [0x%lx]", this, hr);
return hr;
Failure:
if ( fLockInitialized != FALSE )
{
DNDeleteCriticalSection( &m_Lock );
fLockInitialized = FALSE;
}
#ifndef DPNBUILD_LIBINTERFACE
if ( fWinsockLoaded != FALSE )
{
UnloadWinsock();
fWinsockLoaded = FALSE;
}
#endif // ! DPNBUILD_LIBINTERFACE
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
m_sSPType = 0;
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::Deinitialize - deinitialize
//
// Entry: Nothing
//
// Exit: Nothing
//
// Note: This function assumes that someone else is preventing reentry.
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::Deinitialize"
void CSPData::Deinitialize( void )
{
DPFX(DPFPREP, 4, "(0x%p) Enter", this );
#ifndef DPNBUILD_LIBINTERFACE
UnloadWinsock();
#endif // ! DPNBUILD_LIBINTERFACE
DNASSERT( m_pSocketData == NULL );
DNDeleteCriticalSection( &m_Lock );
SetState( SPSTATE_UNINITIALIZED );
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
m_sSPType = 0;
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
memset( &m_InitData, 0x00, sizeof( m_InitData ) );
memset( &m_COMInterface, 0x00, sizeof( m_COMInterface ) );
// The shutdown event and thread pool should have been closed in Shutdown.
DNASSERT( m_hShutdownEvent == NULL );
DNASSERT( GetThreadPool() == NULL );
DNASSERT( m_lRefCount == 0 );
DNASSERT( m_lObjectRefCount == 0 );
DNASSERT( m_hShutdownEvent == NULL );
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
DNASSERT( m_sSPType == 0 );
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
DNASSERT( m_SPState == SPSTATE_UNINITIALIZED );
DNASSERT( m_pThreadPool == NULL );
#ifndef DPNBUILD_LIBINTERFACE
DNInterlockedDecrement( const_cast<LONG*>(&g_lOutstandingInterfaceCount) );
#endif // ! DPNBUILD_LIBINTERFACE
DPFX(DPFPREP, 4, "(0x%p) Leave", this );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::Startup - start this set of SP data
//
// Entry: Pointer to initialization data
//
// Exit: Error
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::Startup"
HRESULT CSPData::Startup( SPINITIALIZEDATA *pInitializeData )
{
HRESULT hr;
SOCKET TestSocket;
BOOL fInterfaceGlobalsInitialized;
#ifdef DBG
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
TCHAR * ptszSocketType;
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
#endif // DBG
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pInitializeData);
//
// initialize
//
hr = DPN_OK;
TestSocket = INVALID_SOCKET;
fInterfaceGlobalsInitialized = FALSE;
//
// Before we get too far, check for the existance of this protocol by
// attempting to create a socket.
//
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
TestSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP );
if ( TestSocket == INVALID_SOCKET )
{
DPFX(DPFPREP, 1, "Creating IPv4 socket failed, is that transport protocol installed?");
hr = DPNERR_UNSUPPORTED;
goto Failure;
}
DPFX(DPFPREP, 3, "Successfully created IPv4 socket.");
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
switch (GetType())
{
#ifndef DPNBUILD_NOIPX
case AF_IPX:
{
#ifdef DBG
ptszSocketType = _T("IPX");
#endif // DBG
TestSocket = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
break;
}
#endif // ! DPNBUILD_NOIPX
case AF_INET:
{
#ifdef DBG
#ifdef DPNBUILD_NOIPV6
ptszSocketType = _T("IPv4");
#else // ! DPNBUILD_NOIPV6
ptszSocketType = _T("IPv4 or IPv6");
#endif // ! DPNBUILD_NOIPV6
#endif // DBG
DNASSERT(GetType() == AF_INET);
TestSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP );
#ifndef DPNBUILD_NOIPV6
if (TestSocket == INVALID_SOCKET )
{
TestSocket = socket( AF_INET6, SOCK_DGRAM, IPPROTO_IP );
}
#endif // ! DPNBUILD_NOIPV6
break;
}
default:
{
DNASSERT(FALSE);
break;
}
}
if ( TestSocket == INVALID_SOCKET )
{
DPFX(DPFPREP, 1, "Creating %s socket failed, are the necessary transport protocols installed?",
ptszSocketType);
hr = DPNERR_UNSUPPORTED;
goto Failure;
}
DPFX(DPFPREP, 3, "Successfully created %s socket.", ptszSocketType);
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
closesocket( TestSocket );
TestSocket = INVALID_SOCKET;
//
// attempt to initialize shutdown event
//
DNASSERT( m_hShutdownEvent == NULL );
m_hShutdownEvent = DNCreateEvent( NULL, // pointer to security (none)
TRUE, // manual reset
TRUE, // start signalled (so close can be called without any endpoints being created)
NULL // pointer to name (none)
);
if ( m_hShutdownEvent == NULL )
{
DWORD dwError;
dwError = GetLastError();
DPFX(DPFPREP, 0, "Failed to create event for shutting down spdata!" );
DisplayErrorCode( 0, dwError );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// get a thread pool
//
DNASSERT( m_pThreadPool == NULL );
hr = InitializeInterfaceGlobals( this );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to create thread pool!" );
DisplayDNError( 0, hr );
goto Failure;
}
fInterfaceGlobalsInitialized = TRUE;
//
// remember our init data
//
DNASSERT( pInitializeData != NULL );
DNASSERT( pInitializeData->dwFlags == SP_SESSION_TYPE_SERVER ||
pInitializeData->dwFlags == SP_SESSION_TYPE_CLIENT ||
pInitializeData->dwFlags == SP_SESSION_TYPE_PEER ||
pInitializeData->dwFlags == 0);
m_InitData.dwFlags = pInitializeData->dwFlags;
DNASSERT( pInitializeData->pIDP != NULL );
m_InitData.pIDP = pInitializeData->pIDP;
//
// Success from here on in
//
IDP8SPCallback_AddRef( DP8SPCallbackInterface() );
SetState( SPSTATE_INITIALIZED );
Exit:
DPFX(DPFPREP, 2, "(0x%p) Return [0x%lx]", this, hr);
return hr;
Failure:
if ( fInterfaceGlobalsInitialized != FALSE )
{
DeinitializeInterfaceGlobals( this );
fInterfaceGlobalsInitialized = FALSE;
}
if ( m_hShutdownEvent != NULL )
{
DNCloseHandle( m_hShutdownEvent );
m_hShutdownEvent = NULL;
}
goto Exit;
}
//**********************************************************************
// ------------------------------
// CSPData::Shutdown - shut down this set of SP data
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::Shutdown"
void CSPData::Shutdown( void )
{
HRESULT hr;
DPFX(DPFPREP, 2, "(0x%p) Enter", this);
//
// Unbind this interface from the globals. This will cause a closure of all
// of the I/O which will release endpoints, socket ports and then this data.
//
DNASSERT( GetThreadPool() != NULL );
DeinitializeInterfaceGlobals( this );
SetState( SPSTATE_CLOSING );
//
// Release the socket data, if we have any.
//
if ( m_pSocketData != NULL )
{
m_pSocketData->Release();
m_pSocketData = NULL;
}
DNASSERT( m_hShutdownEvent != NULL );
#ifdef DBG
#ifndef DPNBUILD_ONLYONEADAPTER
DebugPrintOutstandingAdapterEntries();
#endif // ! DPNBUILD_ONLYONEADAPTER
#endif // DBG
DPFX(DPFPREP, 3, "(0x%p) Waiting for shutdown event 0x%p.",
this, m_hShutdownEvent);
hr = IDirectPlay8ThreadPoolWork_WaitWhileWorking(m_pThreadPool->GetDPThreadPoolWork(),
HANDLE_FROM_DNHANDLE(m_hShutdownEvent),
0);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Failed to wait for shutdown event 0x%p (err = 0x%lx!",
m_hShutdownEvent, hr );
}
if ( DNCloseHandle( m_hShutdownEvent ) == FALSE )
{
DWORD dwError;
dwError = GetLastError();
DPFX(DPFPREP, 0, "Failed to close shutdown event 0x%p!", m_hShutdownEvent );
DisplayErrorCode( 0, dwError );
}
m_hShutdownEvent = NULL;
DNASSERT( GetThreadPool() != NULL );
GetThreadPool()->DecRef();
SetThreadPool( NULL );
if ( DP8SPCallbackInterface() != NULL)
{
IDP8SPCallback_Release( DP8SPCallbackInterface() );
memset( &m_InitData, 0x00, sizeof( m_InitData ) );
}
DPFX(DPFPREP, 2, "(0x%p) Leave", this);
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::BindEndpoint - bind an endpoint to a socket port
//
// Entry: Pointer to endpoint
// Pointer to IDirectPlay8Address for socket port
// Pointer to CSocketAddress for socket port
// Gateway bind type
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::BindEndpoint"
HRESULT CSPData::BindEndpoint( CEndpoint *const pEndpoint,
IDirectPlay8Address *const pDeviceAddress,
const CSocketAddress *const pSocketAddress,
const GATEWAY_BIND_TYPE GatewayBindType )
{
HRESULT hr;
CSocketAddress * pDeviceSocketAddress;
CSocketData * pSocketData;
CSocketPort * pSocketPort;
BOOL fSocketCreated;
BOOL fSocketDataLocked;
#ifndef DPNBUILD_ONLYONEADAPTER
BOOL fAdapterEntrySet;
CAdapterEntry * pAdapterEntry;
#endif // ! DPNBUILD_ONLYONEADAPTER
BOOL fSocketPortInActiveList;
BOOL fEndpointReferenceAdded;
CBilink * pBilink;
CBilink * pBilinkEndOfList;
GATEWAY_BIND_TYPE NewGatewayBindType;
#ifndef DPNBUILD_ONLYONEPROCESSOR
DWORD dwCPU;
#endif // ! DPNBUILD_ONLYONEPROCESSOR
#ifndef DPNBUILD_NOMULTICAST
BYTE bMulticastTTL;
#endif // ! DPNBUILD_NOMULTICAST
#if ((! defined(DPNBUILD_NOWINSOCK2)) || (! defined(DPNBUILD_NOREGISTRY)))
IDirectPlay8Address * pHostAddress;
#endif // ! DPNBUILD_NOWINSOCK2 or ! DPNBUILD_NOREGISTRY
DNASSERT( pEndpoint != NULL );
DNASSERT( ( pDeviceAddress != NULL ) || ( pSocketAddress != NULL ) );
DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%p, 0x%p, 0x%p, %i)",
this, pEndpoint, pDeviceAddress, pSocketAddress, GatewayBindType);
//
// initialize
//
hr = DPN_OK;
pDeviceSocketAddress = NULL;
pSocketData = NULL;
pSocketPort = NULL;
fSocketCreated = FALSE;
fSocketDataLocked = FALSE;
#ifndef DPNBUILD_ONLYONEADAPTER
fAdapterEntrySet = FALSE;
pAdapterEntry = NULL;
#endif // ! DPNBUILD_ONLYONEADAPTER
fSocketPortInActiveList = FALSE;
fEndpointReferenceAdded = FALSE;
//
// create and initialize a device address to be used for this socket port
//
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) GetType()));
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if ( pDeviceSocketAddress == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Failed to allocate address for new socket port!" );
goto Failure;
}
//
// Initialize the socket address with the provided base addresses.
//
if ( pDeviceAddress != NULL )
{
#if ((! defined(DPNBUILD_ONLYONEADAPTER)) || (! defined(DPNBUILD_ONLYONEPROCESSOR)))
DWORD dwComponentSize;
DWORD dwComponentType;
#endif // ! DPNBUILD_ONLYONEADAPTER or ! DPNBUILD_ONLYONEPROCESSOR
DNASSERT( pSocketAddress == NULL );
hr = pDeviceSocketAddress->SocketAddressFromDP8Address( pDeviceAddress,
#ifdef DPNBUILD_XNETSECURITY
NULL,
#endif // DPNBUILD_XNETSECURITY
#ifndef DPNBUILD_ONLYONETHREAD
FALSE,
#endif // DPNBUILD_ONLYONETHREAD
SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to parse device address!" );
DisplayDNError( 0, hr );
goto Failure;
}
#ifndef DPNBUILD_ONLYONEADAPTER
//
// If the device gave a specific port, it's possible that the address has
// our special "it's not actually a specific port" key (see
// CSocketPort::GetDP8BoundNetworkAddress).
//
if ( pDeviceSocketAddress->GetPort() != ANY_PORT )
{
DWORD dwSocketPortID;
dwComponentSize = sizeof(dwSocketPortID);
dwComponentType = 0;
hr = IDirectPlay8Address_GetComponentByName( pDeviceAddress, // interface
DPNA_PRIVATEKEY_PORT_NOT_SPECIFIC, // tag
&dwSocketPortID, // component buffer
&dwComponentSize, // component size
&dwComponentType // component type
);
if ( hr == DPN_OK )
{
//
// We found the component. Make sure it's the right size and type.
//
if (( dwComponentSize == sizeof(dwSocketPortID) ) && ( dwComponentType == DPNA_DATATYPE_DWORD ))
{
DPFX(DPFPREP, 3, "Found correctly formed private port-not-specific key (socketport ID = %u), ignoring port %u.",
dwSocketPortID, NTOHS(pDeviceSocketAddress->GetPort()) );
pDeviceSocketAddress->SetPort( ANY_PORT ) ;
}
else
{
//
// We are the only ones who should know about this key, so if it
// got there without being formed correctly, either someone is
// trying to imitate our address format, or it got corrupted.
// We'll just ignore it.
//
DPFX(DPFPREP, 0, "Private port-not-specific key exists, but doesn't match expected type (%u != %u) or size (%u != %u), is someone trying to get cute with device address 0x%p?!",
dwComponentSize, sizeof(dwSocketPortID),
dwComponentType, DPNA_DATATYPE_DWORD,
pDeviceAddress );
}
}
else
{
//
// The key is not there, it's the wrong size (too big for our buffer
// and returned BUFFERTOOSMALL), or something else bad happened.
// It doesn't matter. Carry on.
//
DPFX(DPFPREP, 8, "Could not get appropriate private port-not-specific key, error = 0x%lx, component size = %u, type = %u, continuing.",
hr, dwComponentSize, dwComponentType);
}
}
#endif // ! DPNBUILD_ONLYONEADAPTER
#ifndef DPNBUILD_ONLYONEPROCESSOR
//
// Try to retrieve the CPU component, if any.
//
dwComponentSize = sizeof(dwCPU);
dwComponentType = 0;
hr = IDirectPlay8Address_GetComponentByName( pDeviceAddress, // interface
DPNA_KEY_PROCESSOR, // tag
&dwCPU, // component buffer
&dwComponentSize, // component size
&dwComponentType // component type
);
if ( hr == DPN_OK )
{
SYSTEM_INFO SystemInfo;
//
// We found the component. Make sure it's the right size and type.
//
if (( dwComponentSize != sizeof(dwCPU) ) || ( dwComponentType != DPNA_DATATYPE_DWORD ))
{
DPFX(DPFPREP, 0, "Processor address component exists, but doesn't match expected type (%u != %u) or size (%u != %u)!",
dwComponentSize, sizeof(dwCPU),
dwComponentType, DPNA_DATATYPE_DWORD );
hr = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
//
// Make sure the processor is valid.
//
GetSystemInfo(&SystemInfo);
if ((dwCPU != -1) && (dwCPU >= SystemInfo.dwNumberOfProcessors))
{
DPFX(DPFPREP, 0, "Processor address component exists, but is not valid (%i)!",
dwCPU );
hr = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
if (dwCPU == -1)
{
DPFX(DPFPREP, 3, "Found correctly formed processor component, explicitly using any/all CPUs.");
}
else
{
DPFX(DPFPREP, 3, "Found correctly formed processor component, CPU = %i.",
dwCPU );
}
}
else
{
//
// The key is not there, it's the wrong size (too big for our buffer
// and returned BUFFERTOOSMALL), or something else bad happened.
// It doesn't matter, we'll just use any/all processors.
//
DPFX(DPFPREP, 8, "Could not get processor address component, error = 0x%lx, component size = %u, type = %u, using any CPU.",
hr, dwComponentSize, dwComponentType);
dwCPU = -1;
}
#endif // ! DPNBUILD_ONLYONEPROCESSOR
}
else
{
DNASSERT( pSocketAddress != NULL );
pDeviceSocketAddress->CopyAddressSettings( pSocketAddress );
#ifndef DPNBUILD_ONLYONEPROCESSOR
//
// Use any CPU.
//
dwCPU = -1;
#endif // ! DPNBUILD_ONLYONEPROCESSOR
}
#pragma BUGBUG(vanceo, "Find a way to organize and delay the munges (both here and in CSocketPort::BindEndpoint)")
#ifndef DPNBUILD_NONATHELP
//
// Munge the public address into a local alias, if there is one for the given device.
// It's OK for the device socket address to not have a port yet.
//
// Note that doing this causes all other multiplexed operations to use the munged
// result from this first adapter because we indicate the modified address info,
// not the original public address. The assumption is that the public address
// must be globally reachable, so if we munge it here, we should be the only
// adapter that can reach it locally, or if not, the other adapters should be able
// to reach it using the same local address.
//
if ( pEndpoint->GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE )
{
switch ( pEndpoint->GetType() )
{
case ENDPOINT_TYPE_CONNECT:
#ifndef DPNBUILD_NOMULTICAST
case ENDPOINT_TYPE_MULTICAST_RECEIVE:
#endif // ! DPNBUILD_NOMULTICAST
{
MungePublicAddress( pDeviceSocketAddress, pEndpoint->GetWritableRemoteAddressPointer(), FALSE );
break;
}
case ENDPOINT_TYPE_ENUM:
{
MungePublicAddress( pDeviceSocketAddress, pEndpoint->GetWritableRemoteAddressPointer(), TRUE );
break;
}
default:
{
break;
}
}
}
#endif // ! DPNBUILD_NONATHELP
#ifndef DPNBUILD_NOIPV6
//
// Munge/convert the IPv4 broadcast address to the IPv6 multicast enum
// address, and vice versa.
//
// Note that doing this causes all other multiplexed operations to use this first
// adapter because we indicate the modified address info, not the original
// broadcast address.
//
if ( pEndpoint->GetType() == ENDPOINT_TYPE_ENUM )
{
if ((pDeviceSocketAddress->GetFamily() == AF_INET6) &&
(pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() == AF_INET) &&
(((SOCKADDR_IN*) pEndpoint->GetWritableRemoteAddressPointer()->GetAddress())->sin_addr.S_un.S_addr == INADDR_BROADCAST))
{
SOCKADDR_IN6 saddrin6MulticastEnum;
memset(&saddrin6MulticastEnum, 0, sizeof(saddrin6MulticastEnum));
saddrin6MulticastEnum.sin6_family = AF_INET6;
memcpy(&saddrin6MulticastEnum.sin6_addr, &c_in6addrEnumMulticast, sizeof(saddrin6MulticastEnum.sin6_addr));
saddrin6MulticastEnum.sin6_port = pEndpoint->GetWritableRemoteAddressPointer()->GetPort();
pEndpoint->GetWritableRemoteAddressPointer()->SetFamilyProtocolAndSize(AF_INET6);
pEndpoint->GetWritableRemoteAddressPointer()->SetAddressFromSOCKADDR((SOCKADDR*) (&saddrin6MulticastEnum),
sizeof(saddrin6MulticastEnum));
DPFX(DPFPREP, 7, "Converting IPv4 broadcast address to IPv6 multicast enum address:");
DumpSocketAddress( 7, pEndpoint->GetWritableRemoteAddressPointer()->GetAddress(), pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() );
}
else if ((pDeviceSocketAddress->GetFamily() == AF_INET) &&
(pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() == AF_INET6) &&
(IN6_ADDR_EQUAL(&(((SOCKADDR_IN6*) pEndpoint->GetWritableRemoteAddressPointer()->GetAddress())->sin6_addr), &c_in6addrEnumMulticast)))
{
SOCKADDR_IN saddrinBroadcast;
memset(&saddrinBroadcast, 0, sizeof(saddrinBroadcast));
saddrinBroadcast.sin_family = AF_INET;
saddrinBroadcast.sin_addr.S_un.S_addr = INADDR_BROADCAST;
saddrinBroadcast.sin_port = pEndpoint->GetWritableRemoteAddressPointer()->GetPort();
pEndpoint->GetWritableRemoteAddressPointer()->SetFamilyProtocolAndSize(AF_INET);
pEndpoint->GetWritableRemoteAddressPointer()->SetAddressFromSOCKADDR((SOCKADDR*) (&saddrinBroadcast),
sizeof(saddrinBroadcast));
DPFX(DPFPREP, 7, "Converting IPv6 multicast enum address to IPv4 broadcast address:");
DumpSocketAddress( 7, pEndpoint->GetWritableRemoteAddressPointer()->GetAddress(), pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() );
}
}
//
// Mash in the appropriate IPv6 scope ID in case we don't have it.
//
if ((pDeviceSocketAddress->GetFamily() == AF_INET6) &&
(pEndpoint->GetWritableRemoteAddressPointer()->GetFamily() == AF_INET6))
{
SOCKADDR_IN6 * psaddrin6Device;
SOCKADDR_IN6 * psaddrin6Remote;
psaddrin6Device = (SOCKADDR_IN6*) (pDeviceSocketAddress->GetAddress());
psaddrin6Remote = (SOCKADDR_IN6*) (pEndpoint->GetWritableRemoteAddressPointer()->GetAddress());
psaddrin6Remote->sin6_scope_id = psaddrin6Device->sin6_scope_id;
}
#endif // ! DPNBUILD_NOIPV6
#ifndef DPNBUILD_NOMULTICAST
//
// If this is a multicast send endpoint, figure out what TTL we will
// be using.
//
if ( pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND )
{
GUID guidScope;
pEndpoint->GetScopeGuid( &guidScope );
if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_PRIVATE, sizeof(guidScope) ) == 0 )
{
bMulticastTTL = MULTICAST_TTL_PRIVATE;
}
else if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_LOCAL, sizeof(guidScope) ) == 0 )
{
bMulticastTTL = MULTICAST_TTL_LOCAL;
}
else if ( memcmp( &guidScope, &GUID_DP8MULTICASTSCOPE_GLOBAL, sizeof(guidScope) ) == 0 )
{
bMulticastTTL = MULTICAST_TTL_GLOBAL;
}
else
{
//
// Assume it's a valid MADCAP scope. Even on non-NT platforms
// where we don't know about MADCAP, we can still parse out the
// TTL value.
//
bMulticastTTL = CSocketAddress::GetScopeGuidTTL( &guidScope );
}
}
#endif // ! DPNBUILD_NOMULTICAST
//
// Get the socket port data. This shouldn't fail, because in order to have
// an open endpoint, we must have created the socket data.
//
pSocketData = GetSocketDataRef();
if (pSocketData == NULL)
{
DNASSERT(! "Couldn't retrieve socket data!");
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
pSocketData->Lock();
fSocketDataLocked = TRUE;
#ifndef DPNBUILD_ONLYONEADAPTER
//
// Find the base adapter entry for this network address. If none is found,
// create a new one. If a new one cannot be created, fail.
//
pBilink = pSocketData->GetAdapters()->GetNext();
while ( pBilink != pSocketData->GetAdapters() )
{
CAdapterEntry *pTempAdapterEntry;
pTempAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage( pBilink );
if ( pDeviceSocketAddress->CompareToBaseAddress( pTempAdapterEntry->BaseAddress() ) == 0 )
{
DPFX(DPFPREP, 5, "Found adapter for network address (0x%p).", pTempAdapterEntry );
DNASSERT( pAdapterEntry == NULL );
pTempAdapterEntry->AddRef();
pAdapterEntry = pTempAdapterEntry;
}
pBilink = pBilink->GetNext();
}
if ( pAdapterEntry == NULL )
{
pAdapterEntry = (CAdapterEntry*)g_AdapterEntryPool.Get();
if ( pAdapterEntry == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Failed to create a new adapter entry!" );
goto Failure;
}
pAdapterEntry->SetBaseAddress( pDeviceSocketAddress->GetAddress(), pDeviceSocketAddress->GetAddressSize() );
pAdapterEntry->AddToAdapterList( pSocketData->GetAdapters() );
}
#endif // ! DPNBUILD_ONLYONEADAPTER
//
// At this point we have a reference to an adapter entry that's also in
// m_ActiveAdapterList (which has a reference, too).
//
//
// if a specific port is not needed, check the list of active adapters for a matching
// base address and reuse that CSocketPort.
//
if ( pDeviceSocketAddress->GetPort() == ANY_PORT )
{
DPFX(DPFPREP, 8, "Device socket address 0x%p not mapped to a specific port, gateway bind type = %u.",
pDeviceSocketAddress, GatewayBindType);
//
// Convert the preliminary bind type to a real one, based on the fact that
// the caller allowed any port.
//
switch (GatewayBindType)
{
case GATEWAY_BIND_TYPE_UNKNOWN:
{
//
// Caller didn't know ahead of time how to bind.
// Since there's no port, we can let the gateway bind whatever it wants.
//
NewGatewayBindType = GATEWAY_BIND_TYPE_DEFAULT;
break;
}
case GATEWAY_BIND_TYPE_NONE:
{
//
// Caller didn't actually want to bind on gateway.
//
NewGatewayBindType = GatewayBindType;
break;
}
default:
{
//
// Some wacky value, or a type was somehow already chosen.
//
DNASSERT(FALSE);
NewGatewayBindType = GatewayBindType;
break;
}
}
}
else
{
DPFX(DPFPREP, 8, "Device socket address 0x%p specified port %u, gateway bind type = %u.",
pDeviceSocketAddress, NTOHS(pDeviceSocketAddress->GetPort()),
GatewayBindType);
//
// Convert the preliminary bind type to a real one, based on the fact that
// the caller gave us a port.
//
switch (GatewayBindType)
{
case GATEWAY_BIND_TYPE_UNKNOWN:
{
//
// Caller didn't know ahead of time how to bind.
// Since there's a port, it should be fixed on the gateway, too.
//
NewGatewayBindType = GATEWAY_BIND_TYPE_SPECIFIC;
break;
}
case GATEWAY_BIND_TYPE_SPECIFIC_SHARED:
{
//
// Caller wanted to bind to a specific port on the gateway,
// and it needs to be shared (DPNSVR).
//
NewGatewayBindType = GatewayBindType;
break;
}
case GATEWAY_BIND_TYPE_NONE:
{
//
// Caller didn't actually want to bind on gateway.
//
NewGatewayBindType = GatewayBindType;
break;
}
default:
{
//
// Some wacky value, or default/specific was somehow already chosen.
// That shouldn't happen.
//
DNASSERT(FALSE);
NewGatewayBindType = GatewayBindType;
break;
}
}
}
//
// Look for an existing socketport that's compatible with the specified endpoint.
//
#ifdef DPNBUILD_ONLYONEADAPTER
pBilinkEndOfList = pSocketData->GetSocketPorts();
#else // ! DPNBUILD_ONLYONEADAPTER
pBilinkEndOfList = pAdapterEntry->SocketPortList();
#endif // ! DPNBUILD_ONLYONEADAPTER
pBilink = pBilinkEndOfList->GetNext();
while ((pBilink != pBilinkEndOfList) && (pSocketPort == NULL))
{
pSocketPort = CSocketPort::SocketPortFromBilink( pBilink );
if ((pDeviceSocketAddress->GetPort() != ANY_PORT) &&
(pDeviceSocketAddress->GetPort() != pSocketPort->GetNetworkAddress()->GetPort()))
{
DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it is for a different port (%u <> %u).",
pSocketPort, NTOHS(pDeviceSocketAddress->GetPort()), NTOHS(pSocketPort->GetNetworkAddress()->GetPort()));
pSocketPort = NULL;
}
#ifndef DPNBUILD_ONLYONEPROCESSOR
else if ((dwCPU != -1) && (dwCPU != pSocketPort->GetCPU()))
{
DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it is for a different CPU (%u <> %u).",
pSocketPort, dwCPU, pSocketPort->GetCPU());
pSocketPort = NULL;
}
#endif // ! DPNBUILD_ONLYONEPROCESSOR
#ifndef DPNBUILD_NONATHELP
else if (pSocketPort->GetUserTraversalMode() != pEndpoint->GetUserTraversalMode())
{
DPFX(DPFPREP, 7, "Skipping socket port 0x%p because its traversal mode=%u but endpoint 0x%p traversal mode=%u.",
pSocketPort, pSocketPort->GetUserTraversalMode(), pEndpoint, pEndpoint->GetUserTraversalMode());
pSocketPort = NULL;
}
#endif // ! DPNBUILD_NONATHELP
else
{
switch (pEndpoint->GetType())
{
case ENDPOINT_TYPE_LISTEN:
#ifndef DPNBUILD_NOMULTICAST
case ENDPOINT_TYPE_MULTICAST_LISTEN:
#endif // ! DPNBUILD_NOMULTICAST
{
//
// If there's already a listen/multicast listen started on the socket port,
// we can't select it.
// NOTE: The socketport's endpoint data lock is not held while checking
// the listen endpoint handle! This should be fine because we're just
// doing "if exists" check. If the endpoint later gets removed, we will
// end up binding to a new socketport that might not have been
// necessary. If an endpoint gets added, BindEndpoint will notice and
// fail. Either way, we're not going to cause any crashes.
//
if (pSocketPort->GetListenEndpoint() != NULL)
{
DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it already has a listen/multicast listen (0x%p).",
pSocketPort, pSocketPort->GetListenEndpoint());
pSocketPort = NULL;
}
else
{
DPFX(DPFPREP, 6, "Picked socket port 0x%p for binding new listen/multicast listen.",
pSocketPort);
//
// Attempt to add a reference for the endpoint we're going to bind to
// this socket port. If it fails, the socket is in the process of being
// unbound, so we cannot use this socket port now. Move on to using
// other socket ports or creating a new one.
//
fEndpointReferenceAdded = pSocketPort->EndpointAddRef();
if (! fEndpointReferenceAdded)
{
DPFX(DPFPREP, 1, "Couldn't re-use existing socket port 0x%p for listen/multicast listen because it is unbinding, continuing.",
pSocketPort);
pSocketPort = NULL;
}
}
break;
}
case ENDPOINT_TYPE_CONNECT:
case ENDPOINT_TYPE_ENUM:
case ENDPOINT_TYPE_CONNECT_ON_LISTEN:
#ifndef DPNBUILD_NOMULTICAST
case ENDPOINT_TYPE_MULTICAST_RECEIVE:
#endif // ! DPNBUILD_NOMULTICAST
{
DPFX(DPFPREP, 6, "Picked socket port 0x%p for binding new connect or enum.",
pSocketPort);
//
// Attempt to add a reference for the endpoint we're going to bind to
// this socket port. If it fails, the socket is in the process of being
// unbound, so we cannot use this socket port now. Move on to using
// other socket ports or creating a new one.
//
fEndpointReferenceAdded = pSocketPort->EndpointAddRef();
if (! fEndpointReferenceAdded)
{
DPFX(DPFPREP, 1, "Couldn't re-use existing socket port 0x%p for connect/enum because it is unbinding, continuing.",
pSocketPort);
pSocketPort = NULL;
}
break;
}
#ifndef DPNBUILD_NOMULTICAST
case ENDPOINT_TYPE_MULTICAST_SEND:
{
//
// If this socketport has already had its multicast TTL value set, and
// it's not the same as what we're looking to use, we can't select it.
// NOTE: The socketport's endpoint data lock is not held while checking
// the multicast TTL setting.
//
if ((pSocketPort->GetMulticastTTL() != 0) &&
(pSocketPort->GetMulticastTTL() != bMulticastTTL))
{
DPFX(DPFPREP, 7, "Skipping socket port 0x%p because it already has a different multicast TTL setting (%u != %u).",
pSocketPort, pSocketPort->GetMulticastTTL(), bMulticastTTL);
pSocketPort = NULL;
}
else
{
DPFX(DPFPREP, 6, "Picked socket port 0x%p for binding new multicast send.",
pSocketPort);
//
// Attempt to add a reference for the endpoint we're going to bind to
// this socket port. If it fails, the socket is in the process of being
// unbound, so we cannot use this socket port now. Move on to using
// other socket ports or creating a new one.
//
fEndpointReferenceAdded = pSocketPort->EndpointAddRef();
if (! fEndpointReferenceAdded)
{
DPFX(DPFPREP, 1, "Couldn't re-use existing socket port 0x%p for multicast send because it is unbinding, continuing.",
pSocketPort);
pSocketPort = NULL;
}
}
break;
}
#endif // ! DPNBUILD_NOMULTICAST
default:
{
DNASSERT(FALSE);
hr = DPNERR_INVALIDENDPOINT;
goto Failure;
break;
}
}
}
pBilink = pBilink->GetNext();
}
//
// If a socket port has not been found, attempt to create a new socket port,
// initialize it, and add it to the list (may result in a duplicate, see below).
// Whatever happens there will be a socket port to bind the endpoint to.
// Save the reference on the CSocketPort from the call to 'Create' until the
// socket port is removed from the active list.
//
//
if ( pSocketPort == NULL )
{
pSocketData->Unlock();
fSocketDataLocked = FALSE;
pSocketPort = (CSocketPort*)g_SocketPortPool.Get();
if ( pSocketPort == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Failed to create new socket port!" );
goto Failure;
}
pSocketPort->AddRef();
fSocketCreated = TRUE;
DPFX(DPFPREP, 6, "Created new socket port 0x%p.", pSocketPort);
//
// We don't need to add a reference for the endpoint we're going to
// bind since new socket ports should already have the endpoint
// reference added before it comes out of the pool. We can't assert
// that because we don't have access to the refcount variables.
//
//DNASSERT( pSocketPort->m_iRefCount == 1 );
//DNASSERT( pSocketPort->m_iEndpointRefCount == 1 );
fEndpointReferenceAdded = TRUE;
hr = pSocketPort->Initialize( pSocketData, m_pThreadPool, pDeviceSocketAddress );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to initialize new socket port!" );
DisplayDNError( 0, hr );
goto Failure;
}
pDeviceSocketAddress = NULL;
#ifndef DPNBUILD_ONLYONEADAPTER
pAdapterEntry->AddRef();
pSocketPort->SetAdapterEntry( pAdapterEntry );
fAdapterEntrySet = TRUE;
#endif // ! DPNBUILD_ONLYONEADAPTER
#ifndef DPNBUILD_NONATHELP
pSocketPort->SetUserTraversalMode(pEndpoint->GetUserTraversalMode());
#endif // ! DPNBUILD_NONATHELP
#ifdef DPNBUILD_ONLYONEPROCESSOR
hr = pSocketPort->BindToNetwork( NewGatewayBindType );
#else // ! DPNBUILD_ONLYONEPROCESSOR
hr = pSocketPort->BindToNetwork( dwCPU, NewGatewayBindType );
#endif // ! DPNBUILD_ONLYONEPROCESSOR
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to bind new socket port to network!" );
DisplayDNError( 0, hr );
goto Failure;
}
pSocketData->Lock();
fSocketDataLocked = TRUE;
//
// The only way to get here is to have the socket bound to the
// network. The socket can't be bound twice, if there was a
// race to bind the socket, Winsock would have decided which
// thread lost and failed 'BindToNetwork'.
//
// However, the order in which sockets are marked as unusable
// and then pulled from the active list is such that there could
// still be an unbinding socketport with this same address in the
// list.
//
#ifdef DBG
CSocketPort *pDuplicateSocket;
if ( pSocketData->FindSocketPort( pSocketPort->GetNetworkAddress(), &pDuplicateSocket ) )
{
DPFX(DPFPREP, 1, "Socketport with same address still exists in list (0x%p).",
pDuplicateSocket);
DumpSocketAddress( 1, pSocketPort->GetNetworkAddress()->GetAddress(), pSocketPort->GetNetworkAddress()->GetFamily() );
DNASSERT( pDuplicateSocket->GetSocket() == INVALID_SOCKET );
}
#endif // DBG
#ifdef DPNBUILD_ONLYONEADAPTER
pSocketPort->AddToActiveList( pSocketData->GetSocketPorts() );
#else // ! DPNBUILD_ONLYONEADAPTER
pSocketPort->AddToActiveList( pAdapterEntry->SocketPortList() );
#endif // ! DPNBUILD_ONLYONEADAPTER
fSocketPortInActiveList = TRUE;
}
DNASSERT( pSocketPort != NULL );
DNASSERT( fEndpointReferenceAdded );
#if ((! defined(DPNBUILD_NOWINSOCK2)) || (! defined(DPNBUILD_NOREGISTRY)))
//
// Munge the public address into a local alias, if there is one for the given device.
// It's OK for the device socket address to not have a port yet.
//
// Note that doing this causes all other multiplexed operations to use the munged
// result from this first adapter because we indicate the modified address info,
// not the original proxied address.
//
switch ( pEndpoint->GetType() )
{
case ENDPOINT_TYPE_CONNECT:
#ifndef DPNBUILD_NOMULTICAST
case ENDPOINT_TYPE_MULTICAST_RECEIVE:
#endif // ! DPNBUILD_NOMULTICAST
{
pHostAddress = pEndpoint->GetCommandParameters()->PendingCommandData.ConnectData.pAddressHost;
DNASSERT( pHostAddress != NULL );
pEndpoint->MungeProxiedAddress( pSocketPort, pHostAddress, FALSE );
break;
}
case ENDPOINT_TYPE_ENUM:
{
pHostAddress = pEndpoint->GetCommandParameters()->PendingCommandData.EnumQueryData.pAddressHost;
DNASSERT( pHostAddress != NULL );
pEndpoint->MungeProxiedAddress( pSocketPort, pHostAddress, TRUE );
break;
}
default:
{
break;
}
}
#endif // ! DPNBUILD_NOWINSOCK2 or ! DPNBUILD_NOREGISTRY
//
// bind the endpoint to whatever socketport we have
//
hr = pSocketPort->BindEndpoint( pEndpoint, NewGatewayBindType );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to bind endpoint!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
#ifndef DPNBUILD_ONLYONEADAPTER
if (pAdapterEntry != NULL)
{
pAdapterEntry->DecRef();
pAdapterEntry = NULL;
}
#endif // ! DPNBUILD_ONLYONEADAPTER
if ( pSocketData != NULL )
{
if ( fSocketDataLocked != FALSE )
{
pSocketData->Unlock();
fSocketDataLocked = FALSE;
}
pSocketData->Release();
pSocketData = NULL;
}
if ( pDeviceSocketAddress != NULL )
{
g_SocketAddressPool.Release( pDeviceSocketAddress );
pDeviceSocketAddress = NULL;
}
DPFX(DPFPREP, 6, "(0x%p) Return [0x%lx]", this, hr);
return hr;
Failure:
//
// If we're failing and cleanup will require removal of some resources.
// This requires the socket port data lock.
//
if ( ( pSocketData != NULL ) && ( fSocketDataLocked == FALSE ) )
{
pSocketData->Lock();
fSocketDataLocked = TRUE;
}
if ( pSocketPort != NULL )
{
if ( fEndpointReferenceAdded != FALSE )
{
pSocketPort->EndpointDecRef();
fEndpointReferenceAdded = FALSE;
}
#ifndef DPNBUILD_ONLYONEADAPTER
if (fAdapterEntrySet)
{
pSocketPort->SetAdapterEntry( NULL );
pAdapterEntry->DecRef();
fAdapterEntrySet = FALSE;
}
#endif // ! DPNBUILD_ONLYONEADAPTER
if ( fSocketPortInActiveList != FALSE )
{
pSocketPort->RemoveFromActiveList();
fSocketPortInActiveList = FALSE;
}
if ( fSocketCreated != FALSE )
{
pSocketPort->DecRef();
fSocketCreated = FALSE;
pSocketPort = NULL;
}
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::UnbindEndpoint - unbind an endpoint from a socket port
//
// Entry: Pointer to endpoint
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::UnbindEndpoint"
void CSPData::UnbindEndpoint( CEndpoint *const pEndpoint )
{
CSocketData * pSocketData;
CSocketPort * pSocketPort;
BOOL fCleanUpSocketPort;
#ifndef DPNBUILD_ONLYONEADAPTER
CAdapterEntry * pAdapterEntry;
#endif // ! DPNBUILD_ONLYONEADAPTER
DNASSERT( pEndpoint != NULL );
DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%p)", this, pEndpoint);
//
// initialize
//
pSocketData = GetSocketData();
DNASSERT( pSocketData != NULL );
pSocketPort = pEndpoint->GetSocketPort();
DNASSERT( pSocketPort != NULL );
fCleanUpSocketPort = FALSE;
pSocketPort->UnbindEndpoint( pEndpoint );
if ( pSocketPort->EndpointDecRef() == 0 )
{
fCleanUpSocketPort = TRUE;
pSocketData->Lock();
pSocketPort->RemoveFromActiveList();
#ifndef DPNBUILD_ONLYONEADAPTER
pAdapterEntry = pSocketPort->GetAdapterEntry();
DNASSERT( pAdapterEntry != NULL );
pSocketPort->SetAdapterEntry( NULL );
pAdapterEntry->DecRef();
#endif // ! DPNBUILD_ONLYONEADAPTER
pSocketData->Unlock();
}
if ( fCleanUpSocketPort != FALSE )
{
pSocketPort->DecRef();
fCleanUpSocketPort = FALSE;
}
DPFX(DPFPREP, 6, "(0x%p) Leave", this);
}
//**********************************************************************
#ifndef DPNBUILD_NOMULTICAST
//**********************************************************************
// ------------------------------
// CSPData::GetEndpointFromAddress - retrieves an endpoint handle and context given addressing info
//
// Entry: Pointer to host address
// Pointer to device address
// Place to store endpoint handle
// Place to store user context
//
// Exit: Error
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::GetEndpointFromAddress"
HRESULT CSPData::GetEndpointFromAddress( IDirectPlay8Address *const pHostAddress,
IDirectPlay8Address *const pDeviceAddress,
HANDLE * phEndpoint,
PVOID * ppvEndpointContext )
{
HRESULT hr;
CSocketAddress * pDeviceSocketAddress;
CSocketAddress * pHostSocketAddress;
CSocketData * pSocketData;
BOOL fSocketDataLocked;
CSocketPort * pSocketPort;
CEndpoint * pEndpoint;
//
// initialize
//
hr = DPN_OK;
pHostSocketAddress = NULL;
pDeviceSocketAddress = NULL;
pSocketData = NULL;
fSocketDataLocked = FALSE;
pSocketPort = NULL;
pEndpoint = NULL;
//
// Get SP addresses from the pool to perform conversions.
//
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
pHostSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
pHostSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) GetType()));
pDeviceSocketAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) GetType()));
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if ((pHostSocketAddress == NULL) || (pDeviceSocketAddress == NULL))
{
DPFX(DPFPREP, 0, "Failed to get addresses for conversions!" );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// Convert the device address.
//
hr = pDeviceSocketAddress->SocketAddressFromDP8Address(pDeviceAddress,
#ifdef DPNBUILD_XNETSECURITY
NULL,
#endif // DPNBUILD_XNETSECURITY
#ifndef DPNBUILD_ONLYONETHREAD
FALSE,
#endif // DPNBUILD_ONLYONETHREAD
SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't get socket address from device DP8 address (err = 0x%lx)!", hr);
hr = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
//
// Convert the host address.
//
hr = pHostSocketAddress->SocketAddressFromDP8Address(pHostAddress,
#ifdef DPNBUILD_XNETSECURITY
NULL,
#endif // DPNBUILD_XNETSECURITY
#ifndef DPNBUILD_ONLYONETHREAD
FALSE,
#endif // DPNBUILD_ONLYONETHREAD
SP_ADDRESS_TYPE_HOST);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't get socket address from host DP8 address (err = 0x%lx)!", hr);
hr = DPNERR_INVALIDHOSTADDRESS;
goto Failure;
}
#ifndef DPNBUILD_NONATHELP
//
// Make sure we have the local version of the host, as reported by NAT Help.
//
MungePublicAddress(pDeviceSocketAddress, pHostSocketAddress, FALSE);
#endif // ! DPNBUILD_NONATHELP
//
// Get the socket port data.
//
pSocketData = GetSocketDataRef();
if (pSocketData == NULL)
{
DPFX(DPFPREP, 0, "Couldn't retrieve socket data!");
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
pSocketData->Lock();
fSocketDataLocked = TRUE;
//
// Look up the socket port for the given address.
//
if (! (pSocketData->FindSocketPort(pDeviceSocketAddress, &pSocketPort)))
{
DPFX(DPFPREP, 0, "Couldn't find socket port for given device address (err = 0x%lx)!", hr);
hr = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pSocketPort->AddRef();
pSocketData->Unlock();
fSocketDataLocked = FALSE;
//
// Locate the connect endpoint for the host address.
//
pSocketPort->ReadLockEndpointData();
if (pSocketPort->FindConnectEndpoint(pHostSocketAddress, &pEndpoint))
{
(*phEndpoint) = (HANDLE) pEndpoint;
(*ppvEndpointContext) = pEndpoint->GetUserEndpointContext();
}
else
{
DPFX(DPFPREP, 0, "Couldn't find endpoint for given host address!");
hr = DPNERR_INVALIDHOSTADDRESS;
//
// Drop through...
//
}
pSocketPort->UnlockEndpointData();
Exit:
if (pSocketPort != NULL)
{
pSocketPort->DecRef();
pSocketPort = NULL;
}
if (pSocketData != NULL)
{
if (fSocketDataLocked)
{
pSocketData->Unlock();
fSocketDataLocked = FALSE;
}
pSocketData->Release();
pSocketData = NULL;
}
if (pHostSocketAddress != NULL)
{
g_SocketAddressPool.Release( pHostSocketAddress );
pHostSocketAddress = NULL;
}
if (pDeviceSocketAddress != NULL)
{
g_SocketAddressPool.Release( pDeviceSocketAddress );
pDeviceSocketAddress = NULL;
}
DPFX(DPFPREP, 6, "Returning: [0x%lx] (handle = 0x%p, context = 0x%p",
hr, (*phEndpoint), (*ppvEndpointContext));
return hr;
Failure:
goto Exit;
}
//**********************************************************************
#endif // ! DPNBUILD_NOMULTICAST
//**********************************************************************
// ------------------------------
// CSPData::GetNewEndpoint - get a new endpoint
//
// Entry: Nothing
//
// Exit: Pointer to new endpoint
// NULL = out of memory
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::GetNewEndpoint"
CEndpoint *CSPData::GetNewEndpoint( void )
{
CEndpoint *pEndpoint;
pEndpoint = (CEndpoint*)g_EndpointPool.Get( this );
if ( pEndpoint == NULL )
{
DPFX(DPFPREP, 0, "Failed to create endpoint!" );
}
// NOTE: Endpoints are returned with one CommandRef and one regular Ref.
return pEndpoint;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::EndpointFromHandle - get endpoint from handle
//
// Entry: Handle
//
// Exit: Pointer to endpoint
// NULL = invalid handle
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::EndpointFromHandle"
CEndpoint *CSPData::EndpointFromHandle( const HANDLE hEndpoint )
{
CEndpoint *pEndpoint;
BOOL fGotCommandRef;
pEndpoint = (CEndpoint*) hEndpoint;
DNASSERT( pEndpoint->IsValid() );
fGotCommandRef = pEndpoint->AddCommandRef();
DNASSERT( fGotCommandRef );
return pEndpoint;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::CloseEndpointHandle - close endpoint handle
//
// Entry: Poiner to endpoint
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::CloseEndpointHandle"
void CSPData::CloseEndpointHandle( CEndpoint *const pEndpoint )
{
pEndpoint->DecCommandRef();
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::GetEndpointAndCloseHandle - get endpoint from handle and close the
// handle
//
// Entry: Handle
//
// Exit: Pointer to endpoint (it needs a call to 'DecCommandRef' when done)
// NULL = invalid handle
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::GetEndpointAndCloseHandle"
CEndpoint *CSPData::GetEndpointAndCloseHandle( const HANDLE hEndpoint )
{
CEndpoint *pEndpoint;
pEndpoint = (CEndpoint*) hEndpoint;
DNASSERT( pEndpoint->IsValid() );
pEndpoint->AddRef();
return pEndpoint;
}
//**********************************************************************
#ifndef DPNBUILD_NONATHELP
//**********************************************************************
// ------------------------------
// CSPData::MungePublicAddress - get a public socket address' local alias, if any
// it also converts the IPv6 loopback address to the device address
//
// Entry: Pointer to device address
// Pointer to public address to munge
// Whether it's an enum or not
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::MungePublicAddress"
void CSPData::MungePublicAddress( const CSocketAddress * const pDeviceBaseAddress, CSocketAddress * const pPublicAddress, const BOOL fEnum )
{
HRESULT hr = DPNHERR_NOMAPPING;
SOCKADDR SocketAddress;
DWORD dwTemp;
DNASSERT( pDeviceBaseAddress != NULL );
DNASSERT( pPublicAddress != NULL );
DNASSERT( m_pThreadPool != NULL );
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
if ( m_pThreadPool->IsNATHelpLoaded() )
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if (( pDeviceBaseAddress->GetFamily() == AF_INET ) &&
( pPublicAddress->GetFamily() == AF_INET ) &&
( m_pThreadPool->IsNATHelpLoaded() ))
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
{
//
// Don't bother looking up the broadcast address, that's a waste of
// time.
//
if (((SOCKADDR_IN*) pPublicAddress->GetAddress())->sin_addr.S_un.S_addr == INADDR_BROADCAST)
{
//
// This had better be an enum, you can't connect to the broadcast
// address.
//
DNASSERT(fEnum);
DPFX(DPFPREP, 8, "Not attempting to lookup alias for broadcast address." );
}
else
{
DBG_CASSERT( sizeof( SocketAddress ) == sizeof( *pPublicAddress->GetAddress() ) );
//
// Start by copying the
//
for(dwTemp = 0; dwTemp < MAX_NUM_DIRECTPLAYNATHELPERS; dwTemp++)
{
if (g_papNATHelpObjects[dwTemp] != NULL)
{
//
// IDirectPlayNATHelp::GetCaps had better have been called with the
// DPNHGETCAPS_UPDATESERVERSTATUS flag at least once prior to this.
// See CThreadPool::EnsureNATHelpLoaded
//
hr = IDirectPlayNATHelp_QueryAddress( g_papNATHelpObjects[dwTemp],
pDeviceBaseAddress->GetAddress(),
pPublicAddress->GetAddress(),
&SocketAddress,
sizeof(SocketAddress),
(DPNHQUERYADDRESS_CACHEFOUND | DPNHQUERYADDRESS_CACHENOTFOUND) );
if ( hr == DPNH_OK )
{
//
// There is a local alias for the address.
//
//
// Bad news:
// The PAST protocol can only return one address, but the SHARED
// UDP LISTENER extension which allows multiple machines to listen
// on the same fixed port. Someone querying for the local alias
// for that address will only get the first person to register the
// shared port, which may not be the machine desired.
//
// Good news:
// Only DPNSVR uses SHARED UDP LISTENERs, and thus it only happens
// with enums on DPNSVRs port. Further, it only affects a person
// behind the same ICS machine. So we can workaround this by
// detecting an enum attempt on the public address and DPNSVR port,
// and instead of using the single address returned by PAST, use
// the broadcast address. Since anyone registered with the ICS
// server would have to be local, broadcasting should find the same
// servers (and technically more, but that shouldn't matter).
//
// So:
// If the address has a local alias, and it's the DPNSVR port
// (which is the only one that can be shared), and its an enum,
// broadcast instead.
//
if ((fEnum) && (((SOCKADDR_IN*) pPublicAddress->GetAddress())->sin_port == HTONS(DPNA_DPNSVR_PORT)))
{
((SOCKADDR_IN*) pPublicAddress->GetAddress())->sin_addr.S_un.S_addr = INADDR_BROADCAST;
DPFX(DPFPREP, 7, "Address for enum has local alias (via object %u), but is on DPNSVR's shared fixed port, substituting broadcast address instead:",
dwTemp );
DumpSocketAddress( 7, pPublicAddress->GetAddress(), pPublicAddress->GetFamily() );
}
else
{
pPublicAddress->SetAddressFromSOCKADDR( &SocketAddress, sizeof( SocketAddress ) );
DPFX(DPFPREP, 7, "Object %u had mapping, modified address is now:", dwTemp );
DumpSocketAddress( 7, pPublicAddress->GetAddress(), pPublicAddress->GetFamily() );
}
//
// Stop searching.
//
break;
}
DPFX(DPFPREP, 8, "Address was not modified by object %u (err = 0x%lx).",
dwTemp, hr );
}
else
{
//
// No DPNATHelp object in this slot.
//
}
} // end for (each DPNATHelp object)
//
// If no object touched it, remember that.
//
if (hr != DPNH_OK)
{
DPFX(DPFPREP, 7, "Address was not modified by any objects:" );
DumpSocketAddress( 7, pPublicAddress->GetAddress(), pPublicAddress->GetFamily() );
}
}
}
else
{
DPFX(DPFPREP, 7, "NAT Help not loaded or not necessary, not modifying address." );
}
}
//**********************************************************************
#endif // !DPNBUILD_NONATHELP
#ifndef WINCE
//**********************************************************************
// ------------------------------
// CSPData::SetWinsockBufferSizeOnAllSockets - set buffer size on all sockets
//
// Entry: New buffer size
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::SetWinsockBufferSizeOnAllSockets"
void CSPData::SetWinsockBufferSizeOnAllSockets( const INT iBufferSize )
{
CSocketData *pSocketData;
#ifndef DPNBUILD_ONLYONEADAPTER
CAdapterEntry *pAdapterEntry;
CBilink *pAdapterEntryLink;
#endif // ! DPNBUILD_ONLYONEADAPTER
CBilink *pSocketPortList;
CBilink *pBilinkSocketPortListEnd;
CSocketPort *pSocketPort;
//
// Don't use GetSocketDataRef to retrieve the socket data because
// this is just a caps setting. We don't want to create the socket
// data object if it didn't exist.
//
Lock();
if (m_pSocketData != NULL)
{
m_pSocketData->AddRef();
pSocketData = m_pSocketData;
Unlock();
pSocketData->Lock();
#ifndef DPNBUILD_ONLYONEADAPTER
pAdapterEntryLink = pSocketData->GetAdapters()->GetNext();
while ( pAdapterEntryLink != pSocketData->GetAdapters() )
#endif // ! DPNBUILD_ONLYONEADAPTER
{
#ifdef DPNBUILD_ONLYONEADAPTER
pBilinkSocketPortListEnd = pSocketData->GetSocketPorts();
#else // ! DPNBUILD_ONLYONEADAPTER
pAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage( pAdapterEntryLink );
pBilinkSocketPortListEnd = pAdapterEntry->SocketPortList();
#endif // ! DPNBUILD_ONLYONEADAPTER
pSocketPortList = pBilinkSocketPortListEnd->GetNext();
while ( pSocketPortList != pBilinkSocketPortListEnd )
{
pSocketPort = CSocketPort::SocketPortFromBilink( pSocketPortList );
pSocketPort->SetWinsockBufferSize( iBufferSize );
pSocketPortList = pSocketPortList->GetNext();
}
#ifndef DPNBUILD_ONLYONEADAPTER
pAdapterEntryLink = pAdapterEntryLink->GetNext();
#endif // ! DPNBUILD_ONLYONEADAPTER
}
pSocketData->Unlock();
pSocketData->Release();
pSocketData = NULL;
}
else
{
Unlock();
}
}
//**********************************************************************
#endif // ! WINCE
//**********************************************************************
// ------------------------------
// CSPData::DestroyThisObject - destroy this object
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::DestroyThisObject"
void CSPData::DestroyThisObject( void )
{
Deinitialize();
DNFree(this);
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::GetSocketDataRef - retrieves a referenced pointer to this interface's
// socket data object. If none has been created yet,
// allocate one (after which we cannot begin sharing
// the socket data with another interface object).
//
// Entry: Nothing
//
// Exit: Pointer to active socket data
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::GetSocketDataRef"
CSocketData * CSPData::GetSocketDataRef( void )
{
CSocketData * pSocketData;
DNEnterCriticalSection( &m_Lock );
if ( m_pSocketData == NULL )
{
pSocketData = (CSocketData*) g_SocketDataPool.Get( m_pThreadPool );
if ( pSocketData != NULL )
{
pSocketData->AddRef();
m_pSocketData = pSocketData;
}
}
else
{
m_pSocketData->AddRef();
pSocketData = m_pSocketData;
}
DNLeaveCriticalSection( &m_Lock );
return pSocketData;
}
#ifdef DBG
#ifndef DPNBUILD_ONLYONEADAPTER
//**********************************************************************
// ------------------------------
// CSPData::DebugPrintOutstandingAdapterEntries - print out all the outstanding adapter entries for this interface
//
// Entry: None
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::DebugPrintOutstandingAdapterEntries"
void CSPData::DebugPrintOutstandingAdapterEntries( void )
{
CSocketData * pSocketData;
CBilink * pBilink;
CAdapterEntry * pAdapterEntry;
//
// Don't use GetSocketDataRef to retrieve the socket data because
// this is just a debug print routine. We don't want to create the
// socket data object if it didn't exist.
//
Lock();
if (m_pSocketData != NULL)
{
m_pSocketData->AddRef();
pSocketData = m_pSocketData;
Unlock();
DPFX(DPFPREP, 4, "SP data 0x%p (socket data 0x%p) outstanding adapter entries:",
this, pSocketData);
pSocketData->Lock();
pBilink = pSocketData->GetAdapters()->GetNext();
while (pBilink != pSocketData->GetAdapters())
{
pAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage(pBilink);
pAdapterEntry->DebugPrintOutstandingSocketPorts();
pBilink = pBilink->GetNext();
}
pSocketData->Unlock();
pSocketData->Release();
pSocketData = NULL;
}
else
{
Unlock();
DPFX(DPFPREP, 4, "SP Data 0x%p does not have socket data.", this);
}
}
//**********************************************************************
#endif // ! DPNBUILD_ONLYONEADAPTER
#endif // DBG