2025-04-27 07:49:33 -04:00

2066 lines
54 KiB
C++

/*==========================================================================
*
* Copyright (C) 1999-2000 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/20000 rmt Updated to build with Millenium build process
* 03/22/20000 jtk Updated with changes to interface names
***************************************************************************/
#include "dnwsocki.h"
#undef DPF_SUBCOMP
#define DPF_SUBCOMP DN_SUBCOMP_WSOCK
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::CSPData - constructor
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::CSPData"
CSPData::CSPData():
m_lRefCount( 0 ),
m_lObjectRefCount( 0 ),
m_hShutdownEvent( NULL ),
m_SPType( TYPE_UNKNOWN ),
m_SPState( SPSTATE_UNINITIALIZED ),
m_pBroadcastAddress( NULL ),
m_pListenAddress( NULL ),
m_pGenericAddress( NULL ),
m_pThreadPool( NULL )
{
m_Sig[0] = 'S';
m_Sig[1] = 'P';
m_Sig[2] = 'D';
m_Sig[3] = 'T';
memset( &m_ClassID, 0x00, sizeof( m_ClassID ) );
memset( &m_InitData, 0x00, sizeof( m_InitData ) );
memset( &m_COMInterface, 0x00, sizeof( m_COMInterface ) );
memset( &m_Flags, 0x00, sizeof( m_Flags ) );
m_blActiveAdapterList.Initialize();
m_blPostponedEnums.Initialize();
m_blPostponedConnects.Initialize();
DNInterlockedIncrement( &g_lOutstandingInterfaceCount );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::~CSPData - destructor
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::~CSPData"
CSPData::~CSPData()
{
DNASSERT( m_lRefCount == 0 );
DNASSERT( m_lObjectRefCount == 0 );
DNASSERT( m_hShutdownEvent == NULL );
DNASSERT( m_SPType == TYPE_UNKNOWN );
DNASSERT( m_SPState == SPSTATE_UNINITIALIZED );
DNASSERT( m_pThreadPool == NULL );
DNASSERT( m_ActiveSocketPortList.IsEmpty() != FALSE );
DNASSERT( m_Flags.fWinsockLoaded == FALSE );
DNASSERT( m_Flags.fHandleTableInitialized == FALSE );
DNASSERT( m_Flags.fLockInitialized == FALSE );
DNASSERT( m_Flags.fSocketPortDataLockInitialized == FALSE );
DNASSERT( m_Flags.fSocketPortListInitialized == FALSE );
DNASSERT( m_Flags.fInterfaceGlobalsInitialized == FALSE );
DNASSERT( m_Flags.fDefaultAddressesBuilt == FALSE );
DNASSERT( m_blActiveAdapterList.IsEmpty() );
DNASSERT( m_blPostponedEnums.IsEmpty() );
DNASSERT( m_blPostponedConnects.IsEmpty() );
DNInterlockedDecrement( &g_lOutstandingInterfaceCount );
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::Initialize - initialize
//
// Entry: Class ID
// 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( const CLSID *const pClassID,
const SP_TYPE SPType,
IDP8ServiceProviderVtbl *const pVtbl )
{
HRESULT hr;
DNASSERT( pClassID != NULL );
DNASSERT( pVtbl != NULL );
//
// initialize
//
hr = DPN_OK;
DNASSERT( m_lRefCount == 1 );
DNASSERT( m_lObjectRefCount == 0 );
DNASSERT( GetType() == TYPE_UNKNOWN );
m_SPType = SPType;
DBG_CASSERT( sizeof( m_ClassID ) == sizeof( *pClassID ) );
memcpy( &m_ClassID, pClassID, sizeof( m_ClassID ) );
DNASSERT( m_COMInterface.m_pCOMVtbl == NULL );
m_COMInterface.m_pCOMVtbl = pVtbl;
//
// attempt to initialize shutdown event
//
DNASSERT( m_hShutdownEvent == NULL );
m_hShutdownEvent = CreateEvent( 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 );
}
//
// Attempt to load Winsock.
//
DNASSERT( m_Flags.fWinsockLoaded == FALSE );
if ( LoadWinsock() == FALSE )
{
DPFX(DPFPREP, 0, "Failed to load winsock!" );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
m_Flags.fWinsockLoaded = TRUE;
DNASSERT( m_Flags.fLockInitialized == FALSE );
DNASSERT( m_Flags.fSocketPortDataLockInitialized == FALSE );
DNASSERT( m_Flags.fSocketPortListInitialized == FALSE );
DNASSERT( m_Flags.fInterfaceGlobalsInitialized == FALSE );
DNASSERT( m_Flags.fDefaultAddressesBuilt == FALSE );
hr = m_HandleTable.Initialize();
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to initialize handle table!" );
DisplayDNError( 0, hr );
goto Failure;
}
m_Flags.fHandleTableInitialized = TRUE;
//
// 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 );
m_Flags.fLockInitialized = TRUE;
if ( DNInitializeCriticalSection( &m_SocketPortDataLock ) == FALSE )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Problem initializing SocketPortDataLock critical section!" );
goto Failure;
}
DebugSetCriticalSectionRecursionCount( &m_SocketPortDataLock, 0 );
m_Flags.fSocketPortDataLockInitialized = TRUE;
//
// initialize hash table for socket ports with 64 etries and a multiplier of 32
//
if ( m_ActiveSocketPortList.Initialize( 6, 5 ) == FALSE )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Could not initialize socket port list!" );
goto Failure;
}
m_Flags.fSocketPortListInitialized = TRUE;
//
// 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;
}
m_Flags.fInterfaceGlobalsInitialized = TRUE;
//
// build default addresses
//
hr = BuildDefaultAddresses();
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Problem building default addresses!" );
DisplayDNError( 0, hr );
goto Failure;
}
m_Flags.fDefaultAddressesBuilt = TRUE;
Exit:
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Problem with CSPData::Initialize" );
DisplayDNError( 0, hr );
}
return hr;
Failure:
if ( m_Flags.fWinsockLoaded != FALSE )
{
UnloadWinsock();
m_Flags.fWinsockLoaded = FALSE;
}
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 )
{
BOOL fLooping;
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.
//
if ( m_Flags.fInterfaceGlobalsInitialized != FALSE )
{
this->CancelPostponedCommands();
DeinitializeInterfaceGlobals( this );
DNASSERT( GetThreadPool() != NULL );
m_Flags.fInterfaceGlobalsInitialized = FALSE;
}
SetState( SPSTATE_CLOSING );
DNASSERT( m_hShutdownEvent != NULL );
#ifdef DEBUG
m_pThreadPool->DebugPrintOutstandingReads();
m_pThreadPool->DebugPrintOutstandingWrites();
#endif // DEBUG
#if (defined(WIN95) || defined(DEBUG))
DPFX(DPFPREP, 3, "(0x%p) Waiting for shutdown event 0x%p (with timeout).",
this, m_hShutdownEvent);
#else // ! WIN95
DPFX(DPFPREP, 3, "(0x%p) Waiting for shutdown event 0x%p.",
this, m_hShutdownEvent);
#endif // ! WIN95
fLooping = TRUE;
while ( fLooping != FALSE )
{
//
// On 9x, always wake up every 5 seconds to kick the receive thread (see
// comment below). On NT, only wake up every 5 seconds in debug, and
// only do so to print out a warning.
//
#if (defined(WIN95) || defined(DEBUG))
switch ( WaitForSingleObjectEx( m_hShutdownEvent, 5000, TRUE ) )
#else // ! WIN95
switch ( WaitForSingleObjectEx( m_hShutdownEvent, INFINITE, TRUE ) )
#endif // ! WIN95
{
case WAIT_OBJECT_0:
{
fLooping = FALSE;
break;
}
case WAIT_IO_COMPLETION:
{
DPFX(DPFPREP, 1, "Ignoring I/O completion, continuing to wait.");
break;
}
#ifdef WIN95
case WAIT_TIMEOUT:
{
//
// If we're using the Win9x code path, kick the receive event. This is
// because (as far as I can tell) there are cases where receives complete
// but don't trigger this event when shutting down the socket. When that
// occurs, the read I/O data completion isn't picked up and we sit here
// waiting for references to go away.
// Ideally, this issue would be reinvestigated in the future, but for now,
// the workaround is to ping the event. It's harmless if all the receives
// actually did complete, plus if everything goes well, we won't even get
// here.
//
DPFX(DPFPREP, 2, "(0x%p) Still waiting for shutdown event 0x%p, kicking receive event 0x%p.",
this, m_pThreadPool->GetWinsock2ReceiveCompleteEvent(), m_hShutdownEvent);
#ifdef DEBUG
m_pThreadPool->DebugPrintOutstandingReads();
m_pThreadPool->DebugPrintOutstandingWrites();
#endif // DEBUG
//
// Ignore error.
//
SetEvent(m_pThreadPool->GetWinsock2ReceiveCompleteEvent());
break;
}
#else // ! WIN95
#ifdef DEBUG
case WAIT_TIMEOUT:
{
//
// Print a warning to the log about why we're still sitting here.
//
DPFX(DPFPREP, 2, "(0x%p) Still waiting for shutdown event 0x%p.",
this, m_hShutdownEvent);
m_pThreadPool->DebugPrintOutstandingReads();
m_pThreadPool->DebugPrintOutstandingWrites();
break;
}
#endif // DEBUG
#endif // ! WIN95
default:
{
DNASSERT( FALSE );
break;
}
}
}
if ( CloseHandle( m_hShutdownEvent ) == FALSE )
{
DWORD dwError;
dwError = GetLastError();
DPFX(DPFPREP, 0, "Failed to close shutdown event!" );
DisplayErrorCode( 0, dwError );
}
m_hShutdownEvent = NULL;
if ( DP8SPCallbackInterface() != NULL)
{
IDP8SPCallback_Release( DP8SPCallbackInterface() );
memset( &m_InitData, 0x00, sizeof( m_InitData ) );
}
DPFX(DPFPREP, 2, "(0x%p) Leave", this);
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// 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, 6, "(0x%p) Enter", this );
if ( m_Flags.fDefaultAddressesBuilt != FALSE )
{
FreeDefaultAddresses();
m_Flags.fDefaultAddressesBuilt = FALSE;
}
//
// release our reference to the global SP objects
//
if ( m_Flags.fInterfaceGlobalsInitialized != FALSE )
{
DeinitializeInterfaceGlobals( this );
DNASSERT( GetThreadPool() != NULL );
m_Flags.fInterfaceGlobalsInitialized = FALSE;
}
//
// clean up lists and pools
//
if ( m_Flags.fSocketPortListInitialized != FALSE )
{
if ( m_ActiveSocketPortList.IsEmpty() == FALSE )
{
CSocketPort *pSocketPort;
DPFX(DPFPREP, 1, "Attempt to close interface with active connections!" );
//
// All of the threads have stopped so we could force close the socket ports
// by cancelling all IO requests and unbinding all endpoints.
// However, all of the endpoints should be gone by now.
//
DNASSERT(! m_ActiveSocketPortList.RemoveLastEntry(&pSocketPort));
}
m_ActiveSocketPortList.Deinitialize();
m_Flags.fSocketPortListInitialized = FALSE;
}
if ( m_Flags.fSocketPortDataLockInitialized != FALSE )
{
DNDeleteCriticalSection( &m_SocketPortDataLock );
m_Flags.fSocketPortDataLockInitialized = FALSE;
}
if ( m_Flags.fLockInitialized != FALSE )
{
DNDeleteCriticalSection( &m_Lock );
m_Flags.fLockInitialized = FALSE;
}
if ( m_Flags.fHandleTableInitialized != FALSE )
{
m_HandleTable.Deinitialize();
m_Flags.fHandleTableInitialized = FALSE;
}
SetState( SPSTATE_UNINITIALIZED );
m_SPType = TYPE_UNKNOWN;
memset( &m_ClassID, 0x00, sizeof( m_ClassID ) );
memset( &m_InitData, 0x00, sizeof( m_InitData ) );
memset( &m_COMInterface, 0x00, sizeof( m_COMInterface ) );
DPFX(DPFPREP, 6, "(0x%p) Leave", this );
if ( GetThreadPool() != NULL )
{
GetThreadPool()->DecRef();
SetThreadPool( NULL );
}
if ( m_hShutdownEvent != NULL )
{
if ( CloseHandle( m_hShutdownEvent ) == FALSE )
{
DWORD dwError;
dwError = GetLastError();
DPFX(DPFPREP, 0, "Failed to close shutdown handle!" );
DisplayErrorCode( 0, dwError );
}
m_hShutdownEvent = NULL;
}
return;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::SetCallbackData - set data for SP callbacks to application
//
// Entry: Pointer to initialization data
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::SetCallbackData"
void CSPData::SetCallbackData( const SPINITIALIZEDATA *const pInitData )
{
DNASSERT( pInitData != NULL );
DNASSERT( pInitData->dwFlags == 0 );
m_InitData.dwFlags = pInitData->dwFlags;
DNASSERT( pInitData->pIDP != NULL );
m_InitData.pIDP = pInitData->pIDP;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// 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;
CSocketPort * pSocketPort;
BOOL fSocketCreated;
BOOL fSocketPortDataLocked;
BOOL fSocketPortInActiveList;
BOOL fBindReferenceAdded;
CBilink * pAdapterBilink;
CAdapterEntry * pAdapterEntry;
GATEWAY_BIND_TYPE NewGatewayBindType;
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;
pSocketPort = NULL;
fSocketCreated = FALSE;
fSocketPortDataLocked = FALSE;
fSocketPortInActiveList = FALSE;
fBindReferenceAdded = FALSE;
pAdapterEntry = NULL;
//
// create and initialize a device address to be used for this socket port
//
pDeviceSocketAddress = GetNewAddress();
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 )
{
DNASSERT( pSocketAddress == NULL );
hr = pDeviceSocketAddress->SocketAddressFromDP8Address( pDeviceAddress, SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to parse device address!" );
DisplayDNError( 0, hr );
goto Failure;
}
}
else
{
DNASSERT( pSocketAddress != NULL );
pDeviceSocketAddress->CopyAddressSettings( pSocketAddress );
}
//
// 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.
//
switch ( pEndpoint->GetType() )
{
case ENDPOINT_TYPE_CONNECT:
{
this->MungePublicAddress( pDeviceSocketAddress, pEndpoint->GetWritableRemoteAddressPointer(), FALSE );
break;
}
case ENDPOINT_TYPE_ENUM:
{
this->MungePublicAddress( pDeviceSocketAddress, pEndpoint->GetWritableRemoteAddressPointer(), TRUE );
break;
}
default:
{
break;
}
}
LockSocketPortData();
fSocketPortDataLocked = TRUE;
//
// 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.
//
pAdapterBilink = m_blActiveAdapterList.GetNext();
while ( pAdapterBilink != &m_blActiveAdapterList )
{
CAdapterEntry *pTempAdapterEntry;
pTempAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage( pAdapterBilink );
if ( pDeviceSocketAddress->CompareToBaseAddress( pTempAdapterEntry->BaseAddress() ) == 0 )
{
DPFX(DPFPREP, 5, "Found adapter for network address (0x%p).", pTempAdapterEntry );
DNASSERT( pAdapterEntry == NULL );
pTempAdapterEntry->AddRef();
pAdapterEntry = pTempAdapterEntry;
}
pAdapterBilink = pAdapterBilink->GetNext();
}
if ( pAdapterEntry == NULL )
{
pAdapterEntry = CreateAdapterEntry();
if ( pAdapterEntry == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Failed to create a new adapter entry!" );
goto Failure;
}
pAdapterEntry->SetBaseAddress( pDeviceSocketAddress->GetAddress() );
pAdapterEntry->AddToAdapterList( &m_blActiveAdapterList );
}
//
// At this point we have a reference to an adapter entry that's also in
// m_ActiveAdapterList (which has a reference, too).
//
//
// 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 ( ( pDeviceAddress != NULL ) &&
( pDeviceSocketAddress->GetPort() != ANY_PORT ) )
{
DWORD dwSocketPortID;
DWORD dwComponentSize;
DWORD dwComponentType;
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, p_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);
}
}
//
// 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;
}
}
if ( pAdapterEntry->SocketPortList()->IsEmpty() == FALSE )
{
pSocketPort = CSocketPort::SocketPortFromBilink( pAdapterEntry->SocketPortList()->GetNext() );
DNASSERT( pSocketPort != NULL );
DPFX(DPFPREP, 6, "Picked socket port 0x%p for binding.",
pSocketPort);
}
}
else
{
DPFX(DPFPREP, 8, "Device socket address 0x%p specified port %u, gateway bind type = %u.",
pDeviceSocketAddress, p_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;
}
}
}
//
// If a socket port has not been found, attempt to look it up by network
// address. If that fails, attempt to create a new socket port.
//
if ( pSocketPort == NULL )
{
if ( m_ActiveSocketPortList.Find( pDeviceSocketAddress, &pSocketPort ) == FALSE )
{
CSocketPort *pDuplicateSocket;
//
// No socket port found. Create a new one, initialize it and attempt
// to add it to the list (may result in a duplicate). 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.
//
UnlockSocketPortData();
fSocketPortDataLocked = FALSE;
pDuplicateSocket = NULL;
DNASSERT( pSocketPort == NULL );
pSocketPort = CreateSocketPort();
if ( pSocketPort == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Failed to create new socket port!" );
goto Failure;
}
fSocketCreated = TRUE;
DPFX(DPFPREP, 6, "Created new socket port 0x%p.", pSocketPort);
hr = pSocketPort->Initialize( this, pDeviceSocketAddress );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to initialize new socket port!" );
DisplayDNError( 0, hr );
goto Failure;
}
pDeviceSocketAddress = NULL;
pAdapterEntry->AddRef();
pSocketPort->SetAdapterEntry( pAdapterEntry );
#ifdef WINNT
hr = pSocketPort->BindToNetwork( GetThreadPool()->GetIOCompletionPort(), NewGatewayBindType );
#else // WIN95
hr = pSocketPort->BindToNetwork( NULL, NewGatewayBindType );
#endif
if ( hr != DPN_OK )
{
pSocketPort->SetAdapterEntry( NULL );
pAdapterEntry->DecRef();
DPFX(DPFPREP, 0, "Failed to bind new socket port to network!" );
DisplayDNError( 0, hr );
goto Failure;
}
LockSocketPortData();
fSocketPortDataLocked = 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'.
//
DNASSERT( m_ActiveSocketPortList.Find( pSocketPort->GetNetworkAddress(), &pDuplicateSocket ) == FALSE );
if ( m_ActiveSocketPortList.Insert( pSocketPort->GetNetworkAddress(), pSocketPort ) == FALSE )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Could not add new socket port to list!" );
goto Failure;
}
pSocketPort->AddToActiveList( pAdapterEntry->SocketPortList() );
fSocketPortInActiveList = TRUE;
}
else
{
DPFX(DPFPREP, 6, "Found matching socket port 0x%p.", pSocketPort);
}
}
//
// bind the endpoint to whatever socketport we have
//
DNASSERT( pSocketPort != NULL );
pSocketPort->EndpointAddRef();
fBindReferenceAdded = TRUE;
hr = pSocketPort->BindEndpoint( pEndpoint, NewGatewayBindType );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to bind endpoint!" );
DisplayDNError( 0, hr );
goto Failure;
}
Exit:
if ( fSocketPortDataLocked != FALSE )
{
UnlockSocketPortData();
fSocketPortDataLocked = FALSE;
}
if ( pDeviceSocketAddress != NULL )
{
ReturnAddress( pDeviceSocketAddress );
pDeviceSocketAddress = NULL;
}
if (pAdapterEntry != NULL)
{
pAdapterEntry->DecRef();
pAdapterEntry = 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 ( fSocketPortDataLocked == FALSE )
{
LockSocketPortData();
fSocketPortDataLocked = TRUE;
}
if ( pSocketPort != NULL )
{
if ( fBindReferenceAdded != FALSE )
{
pSocketPort->EndpointDecRef();
fBindReferenceAdded = FALSE;
}
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 )
{
CSocketPort * pSocketPort;
BOOL fCleanUpSocketPortAndAdapterEntry;
CAdapterEntry * pAdapterEntry;
DNASSERT( pEndpoint != NULL );
DPFX(DPFPREP, 6, "(0x%p) Parameters: (0x%p)", this, pEndpoint);
//
// initialize
//
pSocketPort = pEndpoint->GetSocketPort();
DNASSERT( pSocketPort != NULL );
fCleanUpSocketPortAndAdapterEntry = FALSE;
LockSocketPortData();
pSocketPort->UnbindEndpoint( pEndpoint );
if ( pSocketPort->EndpointDecRef() == 0 )
{
fCleanUpSocketPortAndAdapterEntry = TRUE;
DNASSERT( pSocketPort->GetNetworkAddress() != NULL );
m_ActiveSocketPortList.Remove( pSocketPort->GetNetworkAddress() );
pSocketPort->RemoveFromActiveList();
pAdapterEntry = pSocketPort->GetAdapterEntry();
DNASSERT( pAdapterEntry != NULL );
pSocketPort->SetAdapterEntry( NULL );
}
UnlockSocketPortData();
if ( fCleanUpSocketPortAndAdapterEntry != FALSE )
{
pSocketPort->DecRef();
pAdapterEntry->DecRef();
fCleanUpSocketPortAndAdapterEntry = FALSE;
}
DPFX(DPFPREP, 6, "(0x%p) Leave", this);
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// 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 )
{
HRESULT hTempResult;
CEndpoint *pEndpoint;
HANDLE hEndpoint;
ENDPOINT_POOL_CONTEXT PoolContext;
//
// initialize
//
pEndpoint = NULL;
hEndpoint = INVALID_HANDLE_VALUE;
memset( &PoolContext, 0x00, sizeof( PoolContext ) );
PoolContext.pSPData = this;
//
// NOTE: This doesn't work properly on Windows 95. From MSDN:
// "the return value is positive, but it is not necessarily equal to the result."
// All endpoints will probably get an ID of 1 on that platform.
//
PoolContext.dwEndpointID = (DWORD) DNInterlockedIncrement((LONG*) (&g_dwCurrentEndpointID));
switch ( GetType() )
{
case TYPE_IP:
{
pEndpoint = CreateIPEndpoint( &PoolContext );
break;
}
case TYPE_IPX:
{
pEndpoint = CreateIPXEndpoint( &PoolContext );
break;
}
default:
{
DNASSERT( FALSE );
break;
}
}
if ( pEndpoint == NULL )
{
DPFX(DPFPREP, 0, "Failed to create endpoint!" );
goto Failure;
}
m_HandleTable.Lock();
hTempResult = m_HandleTable.CreateHandle( &hEndpoint, pEndpoint );
m_HandleTable.Unlock();
if ( hTempResult != DPN_OK )
{
DNASSERT( hEndpoint == INVALID_HANDLE_VALUE );
DPFX(DPFPREP, 0, "Failed to create endpoint handle!" );
DisplayDNError( 0, hTempResult );
goto Failure;
}
pEndpoint->SetHandle( hEndpoint );
pEndpoint->AddCommandRef();
pEndpoint->DecRef();
Exit:
return pEndpoint;
Failure:
if ( hEndpoint != INVALID_HANDLE_VALUE )
{
m_HandleTable.Lock();
m_HandleTable.InvalidateHandle( hEndpoint );
m_HandleTable.Unlock();
hEndpoint = INVALID_HANDLE_VALUE;
}
if ( pEndpoint != NULL )
{
pEndpoint->DecRef();
pEndpoint = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// 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;
pEndpoint = NULL;
m_HandleTable.Lock();
pEndpoint = static_cast<CEndpoint*>( m_HandleTable.GetAssociatedData( hEndpoint ) );
if ( pEndpoint != NULL )
{
pEndpoint->AddCommandRef();
}
m_HandleTable.Unlock();
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 )
{
HANDLE Handle;
BOOL fCloseReturn;
DNASSERT( pEndpoint != NULL );
Handle = pEndpoint->GetHandle();
m_HandleTable.Lock();
fCloseReturn = m_HandleTable.InvalidateHandle( Handle );
m_HandleTable.Unlock();
if ( fCloseReturn != FALSE )
{
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;
BOOL fCloseReturn;
//
// initialize
//
pEndpoint = NULL;
fCloseReturn = FALSE;
m_HandleTable.Lock();
pEndpoint = static_cast<CEndpoint*>( m_HandleTable.GetAssociatedData( hEndpoint ) );
if ( pEndpoint != NULL )
{
pEndpoint->AddRef();
pEndpoint->AddCommandRef();
fCloseReturn = m_HandleTable.InvalidateHandle( hEndpoint );
DNASSERT( fCloseReturn != FALSE );
}
m_HandleTable.Unlock();
if ( pEndpoint != NULL )
{
pEndpoint->DecCommandRef();
}
return pEndpoint;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::MungePublicAddress - get a public socket address' local alias, if any
//
// 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( this->m_pThreadPool != NULL );
if (( this->GetType() == TYPE_IP ) && ( this->m_pThreadPool->IsNATHelpLoaded() ))
{
//
// 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::PreventThreadPoolReduction
//
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 == p_ntohs(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." );
}
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::SetBufferSizeOnAllSockets - 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 )
{
CBilink *pAdapterEntryLink;
LockSocketPortData();
pAdapterEntryLink = m_blActiveAdapterList.GetNext();
while ( pAdapterEntryLink != &m_blActiveAdapterList )
{
CAdapterEntry *pAdapterEntry;
CBilink *pSocketPortList;
pAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage( pAdapterEntryLink );
pSocketPortList = pAdapterEntry->SocketPortList()->GetNext();
while ( pSocketPortList != pAdapterEntry->SocketPortList() )
{
CSocketPort *pSocketPort;
pSocketPort = CSocketPort::SocketPortFromBilink( pSocketPortList );
pSocketPort->SetWinsockBufferSize( iBufferSize );
pSocketPortList = pSocketPortList->GetNext();
}
pAdapterEntryLink = pAdapterEntryLink->GetNext();
}
UnlockSocketPortData();
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::IncreaseOutstandingReceivesOnAllSockets - increase the number of outstanding receives
//
// Entry: Delta to increase outstanding receives by
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::IncreaseOutstandingReceivesOnAllSockets"
void CSPData::IncreaseOutstandingReceivesOnAllSockets( const DWORD dwDelta )
{
CBilink *pAdapterEntryLink;
LONG lIOThreadCount;
LockSocketPortData();
if ( m_pThreadPool->GetIOThreadCount( &lIOThreadCount ) != DPN_OK )
{
DNASSERT( FALSE );
}
pAdapterEntryLink = m_blActiveAdapterList.GetNext();
while ( pAdapterEntryLink != &m_blActiveAdapterList )
{
CAdapterEntry *pAdapterEntry;
CBilink *pSocketPortList;
pAdapterEntry = CAdapterEntry::AdapterEntryFromAdapterLinkage( pAdapterEntryLink );
pSocketPortList = pAdapterEntry->SocketPortList()->GetNext();
while ( pSocketPortList != pAdapterEntry->SocketPortList() )
{
CSocketPort *pSocketPort;
pSocketPort = CSocketPort::SocketPortFromBilink( pSocketPortList );
pSocketPort->IncreaseOutstandingReceives( dwDelta * lIOThreadCount );
pSocketPortList = pSocketPortList->GetNext();
}
pAdapterEntryLink = pAdapterEntryLink->GetNext();
}
UnlockSocketPortData();
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::CancelPostponedCommands - closes any endpoints whose connect/enum
// commands haven't already completed or are
// not in the process of completing
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::CancelPostponedCommands"
void CSPData::CancelPostponedCommands( void )
{
CBilink blEnumsToComplete;
CBilink blConnectsToComplete;
CBilink * pBilink;
CCommandData * pCommand;
CEndpoint * pEndpoint;
blEnumsToComplete.Initialize();
blConnectsToComplete.Initialize();
this->LockSocketPortData();
pBilink = m_blPostponedEnums.GetNext();
while ( pBilink != &m_blPostponedEnums )
{
pCommand = CCommandData::CommandFromPostponedListBilink( pBilink );
pBilink = pBilink->GetNext();
pEndpoint = pCommand->GetEndpoint();
DNASSERT(pEndpoint != NULL);
pCommand->Lock();
if ((pCommand->GetState() == COMMAND_STATE_INPROGRESS) ||
(pCommand->GetState() == COMMAND_STATE_CANCELLING))
{
DPFX(DPFPREP, 6, "Enum 0x%p (state %i, endpoint 0x%p) needs to be cancelled.",
pCommand, pCommand->GetState(), pEndpoint);
//
// Mark the command as cancelling just in case someone tries to cancel
// it now.
//
pCommand->SetState(COMMAND_STATE_CANCELLING);
//
// Pull the endpoint from the multiplex list so no other associated enum
// command will find it.
//
pEndpoint->RemoveFromMultiplexList();
//
// Pull the command from the postponed list.
//
pCommand->RemoveFromPostponedList();
//
// Put it on the list of items we need to complete.
//
pCommand->AddToPostponedList(&blEnumsToComplete);
}
else
{
//
// If it's on the list but not marked as in-progress or cancelling, then
// someone else should be indicating the completion.
//
DPFX(DPFPREP, 1, "Enum 0x%p (endpoint 0x%p) is in progress and will complete later.",
pCommand, pEndpoint);
DNASSERT(pCommand->GetState() == COMMAND_STATE_INPROGRESS_CANNOT_CANCEL);
}
pCommand->Unlock();
}
pBilink = m_blPostponedConnects.GetNext();
while ( pBilink != &m_blPostponedConnects )
{
pCommand = CCommandData::CommandFromPostponedListBilink( pBilink );
pBilink = pBilink->GetNext();
pEndpoint = pCommand->GetEndpoint();
DNASSERT(pEndpoint != NULL);
pCommand->Lock();
if ((pCommand->GetState() == COMMAND_STATE_INPROGRESS) ||
(pCommand->GetState() == COMMAND_STATE_CANCELLING))
{
DPFX(DPFPREP, 6, "Connect 0x%p (state %i, endpoint 0x%p) needs to be cancelled.",
pCommand, pCommand->GetState(), pEndpoint);
//
// Mark the command as cancelling just in case someone tries to cancel
// it now.
//
pCommand->SetState(COMMAND_STATE_CANCELLING);
//
// Pull the endpoint from the multiplex list so no other associated connect
// command will find it.
//
pEndpoint->RemoveFromMultiplexList();
//
// Pull the command from the postponed list.
//
pCommand->RemoveFromPostponedList();
//
// Put it on the list of items we need to complete.
//
pCommand->AddToPostponedList(&blConnectsToComplete);
}
else
{
//
// If it's on the list but not marked as in-progress or cancelling, then
// someone else should be indicating the completion.
//
DPFX(DPFPREP, 1, "Connect 0x%p (endpoint 0x%p) is in progress and will complete later.",
pCommand, pEndpoint);
DNASSERT(pCommand->GetState() == COMMAND_STATE_INPROGRESS_CANNOT_CANCEL);
}
pCommand->Unlock();
}
//
// Now loop through all the enums we need to complete.
//
while ( ! blEnumsToComplete.IsEmpty() )
{
pBilink = blEnumsToComplete.GetNext();
pCommand = CCommandData::CommandFromPostponedListBilink( pBilink );
pBilink = pBilink->GetNext();
pEndpoint = pCommand->GetEndpoint();
DNASSERT(pEndpoint != NULL);
//
// Pull the command from the completion list.
//
pCommand->RemoveFromPostponedList();
//
// Drop the socket port lock. It's safe since we pulled everything we
// need off of the list that needs protection.
//
this->UnlockSocketPortData();
//
// Cancel it.
//
DPFX(DPFPREP, 1, "Stopping endpoint 0x%p enum command 0x%p with USERCANCEL.",
pEndpoint, pCommand);
pEndpoint->StopEnumCommand( DPNERR_USERCANCEL );
//
// Retake the socket port lock and go to next item.
//
this->LockSocketPortData();
}
//
// Now loop through all the connects we need to complete.
//
while ( ! blConnectsToComplete.IsEmpty() )
{
pBilink = blConnectsToComplete.GetNext();
pCommand = CCommandData::CommandFromPostponedListBilink( pBilink );
pBilink = pBilink->GetNext();
pEndpoint = pCommand->GetEndpoint();
DNASSERT(pEndpoint != NULL);
//
// Pull the command from the completion list.
//
pCommand->RemoveFromPostponedList();
//
// Drop the socket port lock. It's safe since we pulled everything we
// need off of the list that needs protection.
//
this->UnlockSocketPortData();
//
// Complete it (by closing this endpoint).
//
DPFX(DPFPREP, 1, "Closing endpoint 0x%p (connect command 0x%p) with USERCANCEL.",
pEndpoint, pCommand);
pEndpoint->Close( DPNERR_USERCANCEL );
this->CloseEndpointHandle( pEndpoint );
//
// Retake the socket port lock and go to next item.
//
this->LockSocketPortData();
}
this->UnlockSocketPortData();
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::BuildDefaultAddresses - construct default addresses
//
// Entry: Nothing
//
// Exit: Nothing
//
// Notes: This function is initializing with default values that should always
// work. If this function asserts, fix it!
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::BuildDefaultAddresses"
HRESULT CSPData::BuildDefaultAddresses( void )
{
HRESULT hr;
CSocketAddress *pSPAddress;
//
// initialize
//
hr = DPN_OK;
//
// create appropriate address
//
pSPAddress = GetNewAddress();
if ( pSPAddress == NULL )
{
DPFX(DPFPREP, 0, "Failed to get address when building default addresses!" );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// query for broadcast address
//
DNASSERT( m_pBroadcastAddress == NULL );
m_pBroadcastAddress = pSPAddress->CreateBroadcastAddress();
if ( m_pBroadcastAddress == NULL )
{
DPFX(DPFPREP, 0, "Failed to create template for broadcast address." );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// query for listen address
//
DNASSERT( m_pListenAddress == NULL );
m_pListenAddress = pSPAddress->CreateListenAddress();
if ( m_pListenAddress == NULL )
{
DPFX(DPFPREP, 0, "Failed to create template for listen address." );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// query for generic address
//
DNASSERT( m_pGenericAddress == NULL );
m_pGenericAddress = pSPAddress->CreateGenericAddress();
if ( m_pGenericAddress == NULL )
{
DPFX(DPFPREP, 0, "Failed to create template for generic address." );
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
Exit:
if ( pSPAddress != NULL )
{
ReturnAddress( pSPAddress );
pSPAddress = NULL;
}
return hr;
Failure:
if ( m_pGenericAddress != NULL )
{
IDirectPlay8Address_Release( m_pGenericAddress );
m_pGenericAddress = NULL;
}
if ( m_pListenAddress != NULL )
{
IDirectPlay8Address_Release( m_pListenAddress );
m_pListenAddress = NULL;
}
if ( m_pBroadcastAddress != NULL )
{
IDirectPlay8Address_Release( m_pBroadcastAddress );
m_pBroadcastAddress = NULL;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::FreeDefaultAddresses - free default addresses
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::FreeDefaultAddresses"
void CSPData::FreeDefaultAddresses( void )
{
if ( m_pBroadcastAddress != NULL )
{
IDirectPlay8Address_Release( m_pBroadcastAddress );
m_pBroadcastAddress = NULL;
}
if ( m_pListenAddress != NULL )
{
IDirectPlay8Address_Release( m_pListenAddress );
m_pListenAddress = NULL;
}
if ( m_pGenericAddress != NULL )
{
IDirectPlay8Address_Release( m_pGenericAddress );
m_pGenericAddress = NULL;
}
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::DestroyThisObject - destroy this object
//
// Entry: Nothing
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::DestroyThisObject"
void CSPData::DestroyThisObject( void )
{
if ( m_Flags.fWinsockLoaded != FALSE )
{
UnloadWinsock();
m_Flags.fWinsockLoaded = FALSE;
}
Deinitialize();
delete this; // maybe a little too extreme......
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::GetNewAddress - get a new address
//
// Entry: Nothing
//
// Exit: Pointer to new address
// NULL = out of memory
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::GetNewAddress"
CSocketAddress *CSPData::GetNewAddress( void )
{
CSocketAddress *pReturn;
pReturn = NULL;
switch ( GetType() )
{
case TYPE_IP:
{
pReturn = CreateIPAddress();
break;
}
case TYPE_IPX:
{
pReturn = CreateIPXAddress();
break;
}
default:
{
DNASSERT( FALSE );
break;
}
}
return pReturn;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// CSPData::ReturnAddress - return address to list
//
// Entry: Poiner to address
//
// Exit: Nothing
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "CSPData::ReturnAddress"
void CSPData::ReturnAddress( CSocketAddress *const pAddress )
{
DNASSERT( pAddress != NULL );
pAddress->Reset();
switch ( GetType() )
{
case TYPE_IP:
{
ReturnIPAddress( static_cast<CIPAddress*>( pAddress ) );
break;
}
case TYPE_IPX:
{
ReturnIPXAddress( static_cast<CIPXAddress*>( pAddress ) );
break;
}
default:
{
DNASSERT( FALSE );
break;
}
}
}
//**********************************************************************