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
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
|