/*========================================================================== * * 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(&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(&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