/*========================================================================== * * Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved. * * File: WSockSP.cpp * Content: Protocol-independent APIs for the DN Winsock SP * * * History: * Date By Reason * ==== == ====== * 10/26/98 jwo Created it. * 11/1/98 jwo Un-subclassed everything (moved it to this generic * file from IP and IPX specific ones * 03/22/20000 jtk Updated with changes to interface names * 04/22/00 mjn Allow all flags in DNSP_GetAddressInfo() * 08/06/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles. * 03/12/01 mjn Prevent enum responses from being indicated up after completion ***************************************************************************/ #include "dnwsocki.h" #undef DPF_SUBCOMP #define DPF_SUBCOMP DN_SUBCOMP_WSOCK //********************************************************************** // Constant definitions //********************************************************************** // // maximum bandwidth in bits per second // #define UNKNOWN_BANDWIDTH 0 //********************************************************************** // Macro definitions //********************************************************************** //********************************************************************** // Structure definitions //********************************************************************** //********************************************************************** // Variable definitions //********************************************************************** //********************************************************************** // Function prototypes //********************************************************************** //********************************************************************** // Function definitions //********************************************************************** //********************************************************************** /* * * DNSP_Initialize initializes the instance of the SP. It must be called * at least once before using any other functions. Further attempts * to initialize the SP are ignored. * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_Initialize" STDMETHODIMP DNSP_Initialize( IDP8ServiceProvider *pThis, SPINITIALIZEDATA *pData ) { HRESULT hr; CSPData *pSPData; SOCKET TestSocket; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pData); DNASSERT( pThis != NULL ); DNASSERT( pData != NULL ); // // initialize // hr = DPN_OK; TestSocket = INVALID_SOCKET; pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // prevent anyone else from messing with this interface // pSPData->Lock(); // // check interface state // switch ( pSPData->GetState() ) { // // uninitialized interface, we can initialize it // case SPSTATE_UNINITIALIZED: { break; } // // other state // case SPSTATE_INITIALIZED: case SPSTATE_CLOSING: default: { pSPData->Unlock(); hr = DPNERR_ALREADYINITIALIZED; DPFX(DPFPREP, 0, "Attempted to reinitialize interface!" ); DNASSERT( FALSE ); goto Exit; } } // // Before we get too far, check for the existance of this protocol by // attempting to create a socket. // switch ( pSPData->GetType() ) { case TYPE_IP: { TestSocket = p_socket( AF_INET, SOCK_DGRAM, IPPROTO_IP ); break; } case TYPE_IPX: { TestSocket = p_socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX ); break; } default: { DNASSERT( FALSE ); break; } } if ( TestSocket == INVALID_SOCKET ) { DPFX(DPFPREP, 1, "Creating %s socket failed, is that transport protocol installed?", (( pSPData->GetType() == TYPE_IP ) ? "IP" : "IPX")); hr = DPNERR_UNSUPPORTED; goto Failure; } // // remember our init data // pSPData->SetCallbackData( pData ); // // Success from here on in // IDP8SPCallback_AddRef( pSPData->DP8SPCallbackInterface() ); pSPData->SetState( SPSTATE_INITIALIZED ); pSPData->Unlock(); IDP8ServiceProvider_AddRef( pThis ); Exit: if ( TestSocket != INVALID_SOCKET ) { p_closesocket( TestSocket ); TestSocket = INVALID_SOCKET; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: pSPData->Unlock(); goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_Close is the opposite of Initialize. Call it when you're done * using the SP * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_Close" STDMETHODIMP DNSP_Close( IDP8ServiceProvider *pThis ) { HRESULT hr; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p)", pThis); DNASSERT( pThis != NULL ); // // initialize // hr = DPN_OK; pSPData = CSPData::SPDataFromCOMInterface( pThis ); switch ( pSPData->GetType() ) { case TYPE_IP: case TYPE_IPX: { pSPData->Shutdown(); IDP8ServiceProvider_Release( pThis ); break; } default: { DNASSERT( FALSE ); break; } } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_AddRef - increment reference count // // Entry: Pointer to interface // // Exit: New reference count // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_AddRef" STDMETHODIMP_(ULONG) DNSP_AddRef( IDP8ServiceProvider *pThis ) { CSPData * pSPData; ULONG ulResult; DPFX(DPFPREP, 2, "Parameters: (0x%p)", pThis); DNASSERT( pThis != NULL ); pSPData = CSPData::SPDataFromCOMInterface( pThis ); ulResult = pSPData->AddRef(); DPFX(DPFPREP, 2, "Returning: [0x%u]", ulResult); return ulResult; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_Release - decrement reference count // // Entry: Pointer to interface // // Exit: New reference count // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_Release" STDMETHODIMP_(ULONG) DNSP_Release( IDP8ServiceProvider *pThis ) { CSPData * pSPData; ULONG ulResult; DPFX(DPFPREP, 2, "Parameters: (0x%p)", pThis); DNASSERT( pThis != NULL ); pSPData = CSPData::SPDataFromCOMInterface( pThis ); ulResult = pSPData->DecRef(); DPFX(DPFPREP, 2, "Returning: [0x%u]", ulResult); return ulResult; } //********************************************************************** //********************************************************************** /* * * DNSP_EnumQuery sends out the * specified data to the specified address. If the SP is unable to * determine the address based on the input params, it checks to see * if it's allowed to put up a dialog querying the user for address * info. If it is, it queries the user for address info. * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_EnumQuery" STDMETHODIMP DNSP_EnumQuery( IDP8ServiceProvider *pThis, SPENUMQUERYDATA *pEnumQueryData) { HRESULT hr; HRESULT hTempResult; CEndpoint *pEndpoint; CCommandData *pCommand; BOOL fInterfaceReferenceAdded; BOOL fEndpointOpen; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumQueryData); DNASSERT( pThis != NULL ); DNASSERT( pEnumQueryData != NULL ); DNASSERT( ( pEnumQueryData->dwFlags & ~( DPNSPF_OKTOQUERY | DPNSPF_NOBROADCASTFALLBACK | DPNSPF_ADDITIONALMULTIPLEXADAPTERS ) ) == 0 ); DBG_CASSERT( sizeof( pEnumQueryData->dwRetryInterval ) == sizeof( DWORD ) ); // // Make sure someone isn't getting silly. // if ( g_fIgnoreEnums ) { DPFX(DPFPREP, 0, "Trying to initiate an enumeration when registry option to ignore all enums/response is set!"); DNASSERT( ! "Trying to initiate an enumeration when registry option to ignore all enums/response is set!" ); } // // initialize // hr = DPNERR_PENDING; pEndpoint = NULL; pCommand = NULL; fInterfaceReferenceAdded = FALSE; fEndpointOpen = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); DNASSERT( pSPData != NULL ); pEnumQueryData->hCommand = NULL; pEnumQueryData->dwCommandDescriptor = NULL_DESCRIPTOR; DumpAddress( 8, "Enum destination:", pEnumQueryData->pAddressHost ); DumpAddress( 8, "Enuming on device:", pEnumQueryData->pAddressDeviceInfo ); // // the user is attempting an operation that relies on the thread pool, lock // it down to prevent threads from being lost. // hTempResult = pSPData->GetThreadPool()->PreventThreadPoolReduction(); if ( hTempResult != DPN_OK ) { hr = hTempResult; DPFX(DPFPREP, 0, "Failed to prevent thread pool reduction!" ); goto Failure; } DNASSERT( pEnumQueryData->pAddressHost != NULL ); DNASSERT( pEnumQueryData->pAddressDeviceInfo != NULL ); // // check SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // provider is initialized case SPSTATE_INITIALIZED: { // // no problem // DNASSERT( hr == DPNERR_PENDING ); IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; break; } // provider is uninitialized case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "EnumQuery called on uninitialized SP!" ); break; } // provider is closing case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "EnumQuery called while SP closing!" ); break; } // unknown default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; break; } } pSPData->Unlock(); if ( hr != DPNERR_PENDING ) { goto Failure; } // // create a new endpoint // pEndpoint = pSPData->GetNewEndpoint(); if ( pEndpoint == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot create new endpoint in DNSP_EnumQuery!" ); goto Failure; } // // get new command and initialize it // pCommand = CreateCommand(); if ( pCommand == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot get command handle for DNSP_EnumQuery!" ); goto Failure; } DPFX(DPFPREP, 7, "(0x%p) Enum query command 0x%p created.", pSPData, pCommand); pEnumQueryData->hCommand = pCommand; pEnumQueryData->dwCommandDescriptor = pCommand->GetDescriptor(); pCommand->SetType( COMMAND_TYPE_ENUM_QUERY ); pCommand->SetState( COMMAND_STATE_PENDING ); pCommand->SetEndpoint( pEndpoint ); // // open endpoint with outgoing address // fEndpointOpen = TRUE; hr = pEndpoint->Open( ENDPOINT_TYPE_ENUM, pEnumQueryData->pAddressHost, NULL ); switch ( hr ) { // // Incomplete address passed in, query user for more information if // we're allowed. If we're on IPX (no dialog available), don't attempt // to display the dialog, skip to checking for broadcast fallback. // Since we don't have a complete address at this time, // don't bind this endpoint to the socket port! // case DPNERR_INCOMPLETEADDRESS: { if ( ( ( pEnumQueryData->dwFlags & DPNSPF_OKTOQUERY ) != 0 ) && ( pSPData->GetType() == TYPE_IP ) ) { // // Copy the connect data locally and start the dialog. When the // dialog completes, the connection will attempt to complete. // Since the dialog is being popped, this command is in progress, // not pending. // DNASSERT( pSPData != NULL ); pCommand->SetState( COMMAND_STATE_INPROGRESS ); hr = pEndpoint->CopyEnumQueryData( pEnumQueryData ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to copy enum query data before settings dialog!" ); DisplayDNError( 0, hr ); goto Failure; } // // Initialize the bind type. It will get changed to DEFAULT or SPECIFIC // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_UNKNOWN); hr = pEndpoint->ShowSettingsDialog( pSPData->GetThreadPool() ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Problem showing settings dialog for enum query!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; hr = DPNERR_PENDING; goto Exit; } else { if ( ( pEnumQueryData->dwFlags & DPNSPF_NOBROADCASTFALLBACK ) == 0 ) { // // we're OK, reset the destination address and reset the // function return to 'pending' // pEndpoint->ReinitializeWithBroadcast(); hr = DPNERR_PENDING; goto SubmitDelayedCommand; } else { goto Failure; } } break; } // // address conversion was fine, copy connect data and finish connection // on background thread. // case DPN_OK: { SubmitDelayedCommand: // // Copy enum data and submit job to finish off enum. // DNASSERT( pSPData != NULL ); hr = pEndpoint->CopyEnumQueryData( pEnumQueryData ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to copy enum query data before delayed command!" ); DisplayDNError( 0, hr ); goto Failure; } // // Initialize the bind type. It will get changed to DEFAULT or SPECIFIC // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_UNKNOWN); pEndpoint->AddRef(); hr = pSPData->GetThreadPool()->SubmitDelayedCommand( pEndpoint->EnumQueryJobCallback, pEndpoint->CancelEnumQueryJobCallback, pEndpoint ); if ( hr != DPN_OK ) { pEndpoint->DecRef(); DPFX(DPFPREP, 0, "Failed to set delayed enum query!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference // pEndpoint = NULL; hr = DPNERR_PENDING; goto Exit; break; } default: { // // this endpoint is screwed // DPFX(DPFPREP, 0, "Problem initializing endpoint in DNSP_EnumQuery!" ); DisplayDNError( 0, hr ); goto Failure; break; } } Exit: DNASSERT( pEndpoint == NULL ); if ( hr != DPNERR_PENDING ) { // this command cannot complete synchronously! DNASSERT( hr != DPN_OK ); DPFX(DPFPREP, 0, "Problem with DNSP_EnumQuery()" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: // // if there's an allocated command, clean up and then // return the command // if ( pCommand != NULL ) { pCommand->DecRef(); pCommand = NULL; pEnumQueryData->hCommand = NULL; pEnumQueryData->dwCommandDescriptor = NULL_DESCRIPTOR; } // // is there an endpoint to free? // if ( pEndpoint != NULL ) { if ( fEndpointOpen != FALSE ) { pEndpoint->Close( hr ); fEndpointOpen = FALSE; } pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint = NULL; } if ( fInterfaceReferenceAdded != FALSE ) { DNASSERT( pSPData != NULL ); IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_EnumRespond sends a response to an enum request by * sending the specified data to the address provided (on * unreliable transport). * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_EnumRespond" STDMETHODIMP DNSP_EnumRespond( IDP8ServiceProvider *pThis, SPENUMRESPONDDATA *pEnumRespondData ) { HRESULT hr; CEndpoint *pEndpoint; WRITE_IO_DATA_POOL_CONTEXT PoolContext; CWriteIOData *pWriteData; CSPData *pSPData; const ENDPOINT_ENUM_QUERY_CONTEXT *pEnumQueryContext; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumRespondData); DNASSERT( pThis != NULL ); DNASSERT( pEnumRespondData != NULL ); DNASSERT( pEnumRespondData->dwFlags == 0 ); // // initialize // hr = DPNERR_PENDING; DBG_CASSERT( OFFSETOF( ENDPOINT_ENUM_QUERY_CONTEXT, EnumQueryData ) == 0 ); pEnumQueryContext = reinterpret_cast( pEnumRespondData->pQuery ); pEndpoint = NULL; pWriteData = NULL; pEnumRespondData->hCommand = NULL; pEnumRespondData->dwCommandDescriptor = NULL_DESCRIPTOR; pSPData = CSPData::SPDataFromCOMInterface( pThis ); DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED ); IDP8ServiceProvider_AddRef( pThis ); // // check for valid endpoint // pEndpoint = pSPData->EndpointFromHandle( pEnumQueryContext->hEndpoint ); if ( pEndpoint == NULL ) { hr = DPNERR_INVALIDENDPOINT; DPFX(DPFPREP, 8, "Invalid endpoint handle in DNSP_EnumRespond" ); goto Failure; } // // no need to poke at the thread pool here to lock down threads because we // can only really be here if there's an enum and that enum locked down the // thread pool. // PoolContext.SPType = pSPData->GetType(); pWriteData = pSPData->GetThreadPool()->GetNewWriteIOData( &PoolContext ); if ( pWriteData == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot get new WRITE_IO_DATA for enum response!" ); goto Failure; } pWriteData->m_pCommand->SetType( COMMAND_TYPE_SEND ); pWriteData->m_pCommand->SetState( COMMAND_STATE_PENDING ); pWriteData->m_pCommand->SetEndpoint( pEndpoint ); pWriteData->m_pCommand->SetUserContext( pEnumRespondData->pvContext ); DNASSERT( pWriteData->m_SendCompleteAction == SEND_COMPLETE_ACTION_UNKNOWN ); pWriteData->m_SendCompleteAction = SEND_COMPLETE_ACTION_COMPLETE_COMMAND; pWriteData->m_uBufferCount = pEnumRespondData->dwBufferCount; pWriteData->m_pBuffers = pEnumRespondData->pBuffers; pWriteData->m_pDestinationSocketAddress = pEnumQueryContext->pReturnAddress; pEnumRespondData->hCommand = pWriteData->m_pCommand; pEnumRespondData->dwCommandDescriptor = pWriteData->m_pCommand->GetDescriptor(); // // send data // pEndpoint->SendEnumResponseData( pWriteData, pEnumQueryContext->dwEnumKey ); Exit: if ( pEndpoint != NULL ) { pEndpoint->DecCommandRef(); pEndpoint = NULL; } IDP8ServiceProvider_Release( pThis ); DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: if ( pWriteData != NULL ) { DNASSERT( pSPData != NULL ); pSPData->GetThreadPool()->ReturnWriteIOData( pWriteData ); pEnumRespondData->hCommand = NULL; pEnumRespondData->dwCommandDescriptor = NULL_DESCRIPTOR; pWriteData = NULL; } goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_Connect "connects" to the specified address. This doesn't * necessarily mean a real (TCP) connection is made. It could * just be a virtual UDP connection * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_Connect" STDMETHODIMP DNSP_Connect( IDP8ServiceProvider *pThis, SPCONNECTDATA *pConnectData ) { HRESULT hr; HRESULT hTempResult; CEndpoint *pEndpoint; CCommandData *pCommand; BOOL fInterfaceReferenceAdded; BOOL fEndpointOpen; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pConnectData); DNASSERT( pThis != NULL ); DNASSERT( pConnectData != NULL ); DNASSERT( pConnectData->pAddressHost != NULL ); DNASSERT( ( pConnectData->dwFlags & ~( DPNSPF_OKTOQUERY | DPNSPF_ADDITIONALMULTIPLEXADAPTERS ) ) == 0 ); // // initialize // hr = DPNERR_PENDING; pEndpoint = NULL; pCommand = NULL; fInterfaceReferenceAdded = FALSE; fEndpointOpen = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); pConnectData->hCommand = NULL; pConnectData->dwCommandDescriptor = NULL_DESCRIPTOR; DumpAddress( 8, "Connect destination:", pConnectData->pAddressHost ); DumpAddress( 8, "Connecting on device:", pConnectData->pAddressDeviceInfo ); // // the user is attempting an operation that relies on the thread pool, lock // it down to prevent threads from being lost. // hTempResult = pSPData->GetThreadPool()->PreventThreadPoolReduction(); if ( hTempResult != DPN_OK ) { hr = hTempResult; DPFX(DPFPREP, 0, "Failed to prevent thread pool reduction!" ); goto Failure; } DNASSERT( pConnectData->pAddressHost != NULL ); DNASSERT( pConnectData->pAddressDeviceInfo != NULL ); // // check SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // provider is initialized case SPSTATE_INITIALIZED: { // // no problem, add a reference and proceed // IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; DNASSERT( hr == DPNERR_PENDING ); break; } // provider is uninitialized case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "Connect called on uninitialized SP!" ); break; } // provider is closing case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "Connect called while SP closing!" ); break; } // unknown default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; break; } } pSPData->Unlock(); if ( hr != DPNERR_PENDING ) { DNASSERT( hr != DPN_OK ); goto Failure; } // // create a new endpoint // pEndpoint = pSPData->GetNewEndpoint(); if ( pEndpoint == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot create new endpoint in DNSP_Connect!" ); goto Failure; } // // get new command and initialize it // pCommand = CreateCommand(); if ( pCommand == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot get command handle for DNSP_Connect!" ); goto Failure; } DPFX(DPFPREP, 7, "(0x%p) Connect command 0x%p created.", pSPData, pCommand); pConnectData->hCommand = pCommand; pConnectData->dwCommandDescriptor = pCommand->GetDescriptor(); pCommand->SetType( COMMAND_TYPE_CONNECT ); pCommand->SetState( COMMAND_STATE_PENDING ); pCommand->SetEndpoint( pEndpoint ); // // open endpoint with outgoing address // fEndpointOpen = TRUE; hr = pEndpoint->Open( ENDPOINT_TYPE_CONNECT, pConnectData->pAddressHost, NULL ); switch ( hr ) { // // address conversion was fine, copy connect data and finish connection // on background thread. // case DPN_OK: { // // Copy connection data and submit job to finish off connection. // Since we're going to hand off this endpoint, add it to the // unbound list so we don't lose track of it. // DNASSERT( pSPData != NULL ); hr = pEndpoint->CopyConnectData( pConnectData ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to copy connect data before delayed command!" ); DisplayDNError( 0, hr ); goto Failure; } // // Initialize the bind type. It will get changed to DEFAULT or SPECIFIC // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_UNKNOWN); pEndpoint->AddRef(); hr = pSPData->GetThreadPool()->SubmitDelayedCommand( pEndpoint->ConnectJobCallback, pEndpoint->CancelConnectJobCallback, pEndpoint ); if ( hr != DPN_OK ) { pEndpoint->DecRef(); DPFX(DPFPREP, 0, "Failed to set delayed connect!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; hr = DPNERR_PENDING; goto Exit; break; } // // Incomplete address passed in, query user for more information if // we're allowed. Since we don't have a complete address at this time, // don't bind this endpoint to the socket port! // case DPNERR_INCOMPLETEADDRESS: { if ( ( pConnectData->dwFlags & DPNSPF_OKTOQUERY ) != 0 ) { // // Copy the connect data locally and start the dialog. When the // dialog completes, the connection will attempt to complete. // Since a dialog is being displayed, the command is in-progress, // not pending. However, you can't cancel the dialog once it's // displayed (the UI would suddenly disappear). // pCommand->SetState( COMMAND_STATE_INPROGRESS_CANNOT_CANCEL ); hr = pEndpoint->CopyConnectData( pConnectData ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to copy connect data before dialog!" ); DisplayDNError( 0, hr ); goto Failure; } // // Initialize the bind type. It will get changed to DEFAULT or SPECIFIC // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_UNKNOWN); hr = pEndpoint->ShowSettingsDialog( pSPData->GetThreadPool() ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Problem showing settings dialog for connect!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; hr = DPNERR_PENDING; goto Exit; } else { goto Failure; } break; } default: { DPFX(DPFPREP, 0, "Problem initializing endpoint in DNSP_Connect!" ); DisplayDNError( 0, hr ); goto Failure; break; } } Exit: DNASSERT( pEndpoint == NULL ); if ( hr != DPNERR_PENDING ) { // this command cannot complete synchronously! DNASSERT( hr != DPN_OK ); DPFX(DPFPREP, 0, "Problem with DNSP_Connect()" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: // // if there's an allocated command, clean up and then // return the command // if ( pCommand != NULL ) { pCommand->DecRef(); pCommand = NULL; pConnectData->hCommand = NULL; pConnectData->dwCommandDescriptor = NULL_DESCRIPTOR; } // // is there an endpoint to free? // if ( pEndpoint != NULL ) { if ( fEndpointOpen != FALSE ) { pEndpoint->Close( hr ); fEndpointOpen = FALSE; } pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint = NULL; } if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_Disconnect disconnects an active connection * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_Disconnect" STDMETHODIMP DNSP_Disconnect( IDP8ServiceProvider *pThis, SPDISCONNECTDATA *pDisconnectData ) { HRESULT hr; HRESULT hTempResult; CEndpoint *pEndpoint; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pDisconnectData); DNASSERT( pThis != NULL ); DNASSERT( pDisconnectData != NULL ); DNASSERT( pDisconnectData->dwFlags == 0 ); DNASSERT( pDisconnectData->hEndpoint != INVALID_HANDLE_VALUE ); DNASSERT( pDisconnectData->dwFlags == 0 ); // // initialize // hr = DPN_OK; pEndpoint = NULL; pDisconnectData->hCommand = NULL; pDisconnectData->dwCommandDescriptor = NULL_DESCRIPTOR; pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // no need to poke at the thread pool here because there was already a connect // issued and that connect should have locked down the thread pool. // // // check service provider state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized // case SPSTATE_INITIALIZED: { DNASSERT( hr == DPN_OK ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "Disconnect called on uninitialized SP!" ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "Disconnect called on closing SP!" ); break; } // // unknown // default: { hr = DPNERR_GENERIC; DNASSERT( FALSE ); break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Failure; } // // look up the endpoint and if it's found, close its handle // pEndpoint = pSPData->GetEndpointAndCloseHandle( pDisconnectData->hEndpoint ); if ( pEndpoint == NULL ) { hr = DPNERR_INVALIDENDPOINT; goto Failure; } hTempResult = pEndpoint->Disconnect( pDisconnectData->hEndpoint ); switch ( hTempResult ) { // // endpoint disconnected immediately // case DPNERR_PENDING: case DPN_OK: { break; } // // Other return. Since the disconnect didn't complete, we need // to unlock the endpoint. // default: { DPFX(DPFPREP, 0, "Error reported when attempting to disconnect endpoint in DNSP_Disconnect!" ); DisplayDNError( 0, hTempResult ); DNASSERT( FALSE ); break; } } Exit: // // remove outstanding reference from GetEndpointHandleAndClose() // if ( pEndpoint != NULL ) { pEndpoint->DecRef(); pEndpoint = NULL; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_Listen "listens" on the specified address/port. This doesn't * necessarily mean that a true TCP socket is used. It could just * be a UDP port that's opened for receiving packets * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_Listen" STDMETHODIMP DNSP_Listen( IDP8ServiceProvider *pThis, SPLISTENDATA *pListenData) { HRESULT hr; HRESULT hTempResult; CEndpoint *pEndpoint; CCommandData *pCommand; IDirectPlay8Address *pDeviceAddress; BOOL fInterfaceReferenceAdded; BOOL fEndpointOpen; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pListenData); DNASSERT( pThis != NULL ); DNASSERT( pListenData != NULL ); DNASSERT( ( pListenData->dwFlags & ~( DPNSPF_OKTOQUERY | DPNSPF_BINDLISTENTOGATEWAY ) ) == 0 ); // // initialize // hr = DPNERR_PENDING; pEndpoint = NULL; pCommand = NULL; // pLocalAddress = NULL; // pSocketPort = NULL; pDeviceAddress = NULL; fInterfaceReferenceAdded = FALSE; fEndpointOpen = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); pListenData->hCommand = NULL; pListenData->dwCommandDescriptor = NULL_DESCRIPTOR; DumpAddress( 8, "Listening on device:", pListenData->pAddressDeviceInfo ); // // the user is attempting an operation that relies on the thread pool, lock // it down to prevent threads from being lost. // hTempResult = pSPData->GetThreadPool()->PreventThreadPoolReduction(); if ( hTempResult != DPN_OK ) { hr = hTempResult; DPFX(DPFPREP, 0, "Failed to prevent thread pool reduction!" ); goto Failure; } // // AddRef the device address. // IDirectPlay8Address_AddRef(pListenData->pAddressDeviceInfo); pDeviceAddress = pListenData->pAddressDeviceInfo; // // check service provider state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized // case SPSTATE_INITIALIZED: { IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; DNASSERT( hr == DPNERR_PENDING ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "Listen called on uninitialized SP!" ); DNASSERT( FALSE ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "Listen called on closing SP!" ); DNASSERT( FALSE ); break; } // // unknown // default: { hr = DPNERR_GENERIC; DNASSERT( FALSE ); break; } } pSPData->Unlock(); if ( hr != DPNERR_PENDING ) { goto Failure; } // // create a new endpoint // pEndpoint = pSPData->GetNewEndpoint(); if ( pEndpoint == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot create new endpoint in DNSP_Listen!" ); goto Failure; } // // get new command and initialize it // pCommand = CreateCommand(); if ( pCommand == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot get command handle for DNSP_Listen!" ); goto Failure; } DPFX(DPFPREP, 7, "(0x%p) Listen command 0x%p created.", pSPData, pCommand); pListenData->hCommand = pCommand; pListenData->dwCommandDescriptor = pCommand->GetDescriptor(); pCommand->SetType( COMMAND_TYPE_LISTEN ); pCommand->SetState( COMMAND_STATE_PENDING ); pCommand->SetEndpoint( pEndpoint ); // // open endpoint with outgoing address // fEndpointOpen = TRUE; hr = pEndpoint->Open( ENDPOINT_TYPE_LISTEN, NULL, NULL ); switch ( hr ) { // // address conversion was fine, copy connect data and finish connection // on background thread. // case DPN_OK: { // // Copy listen data and submit job to finish off listen. // DNASSERT( pSPData != NULL ); hr = pEndpoint->CopyListenData( pListenData, pDeviceAddress ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to copy listen data before delayed command!" ); DisplayDNError( 0, hr ); goto Failure; } // // Initialize the bind type. // if ((pListenData->dwFlags & DPNSPF_BINDLISTENTOGATEWAY)) { // // This must always stay SPECIFIC_SHARED. // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_SPECIFIC_SHARED); } else { // // This will get changed to DEFAULT or SPECIFIC. // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_UNKNOWN); } pEndpoint->AddRef(); hr = pSPData->GetThreadPool()->SubmitDelayedCommand( pEndpoint->ListenJobCallback, pEndpoint->CancelListenJobCallback, pEndpoint ); if ( hr != DPN_OK ) { pEndpoint->DecRef(); DPFX(DPFPREP, 0, "Failed to set delayed listen!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; hr = DPNERR_PENDING; break; } // // Incomplete address passed in, query user for more information if // we're allowed. Since we don't have a complete address at this time, // don't bind this endpoint to the socket port! // case DPNERR_INCOMPLETEADDRESS: { if ( ( pListenData->dwFlags & DPNSPF_OKTOQUERY ) != 0 ) { // // Copy the listen data locally and start the dialog. When the // dialog completes, the connection will attempt to complete. // Since this endpoint is being handed off to another thread, // make sure it's in the unbound list. Since a dialog is being // displayed, the command state is in progress, not pending. // DNASSERT( pSPData != NULL ); hr = pEndpoint->CopyListenData( pListenData, pDeviceAddress ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Failed to copy listen data before dialog!" ); DisplayDNError( 0, hr ); goto Failure; } // // Initialize the bind type. // if ((pListenData->dwFlags & DPNSPF_BINDLISTENTOGATEWAY)) { // // This must always stay SPECIFIC_SHARED. // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_SPECIFIC_SHARED); } else { // // This will get changed to DEFAULT or SPECIFIC. // pEndpoint->SetCommandParametersGatewayBindType(GATEWAY_BIND_TYPE_UNKNOWN); } pCommand->SetState( COMMAND_STATE_INPROGRESS ); hr = pEndpoint->ShowSettingsDialog( pSPData->GetThreadPool() ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Problem showing settings dialog for listen!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; hr = DPNERR_PENDING; goto Exit; } else { goto Failure; } break; } default: { DPFX(DPFPREP, 0, "Problem initializing endpoint in DNSP_Listen!" ); DisplayDNError( 0, hr ); goto Failure; break; } } Exit: if ( pDeviceAddress != NULL ) { IDirectPlay8Address_Release( pDeviceAddress ); pDeviceAddress = NULL; } DNASSERT( pEndpoint == NULL ); if ( hr != DPNERR_PENDING ) { // this command cannot complete synchronously! DNASSERT( hr != DPN_OK ); DPFX(DPFPREP, 0, "Problem with DNSP_Listen()" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: // // if there's an allocated command, clean up and then // return the command // if ( pCommand != NULL ) { pCommand->DecRef(); pCommand = NULL; pListenData->hCommand = NULL; pListenData->dwCommandDescriptor = NULL_DESCRIPTOR; } // // is there an endpoint to free? // if ( pEndpoint != NULL ) { if ( fEndpointOpen != FALSE ) { pEndpoint->Close( hr ); fEndpointOpen = FALSE; } pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint = NULL; } // // clean up any outstanding references // if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_SendData sends data to the specified "player" * * This call MUST BE HIGHLY OPTIMIZED * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_SendData" STDMETHODIMP DNSP_SendData( IDP8ServiceProvider *pThis, SPSENDDATA *pSendData ) { HRESULT hr; CEndpoint *pEndpoint; WRITE_IO_DATA_POOL_CONTEXT PoolContext; CWriteIOData *pWriteData; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pSendData); DNASSERT( pThis != NULL ); DNASSERT( pSendData != NULL ); DNASSERT( pSendData->pBuffers != NULL ); DNASSERT( pSendData->dwBufferCount != 0 ); DNASSERT( pSendData->hEndpoint != INVALID_HANDLE_VALUE ); DNASSERT( pSendData->dwFlags == 0 ); // // initialize // hr = DPNERR_PENDING; pEndpoint = NULL; pSendData->hCommand = NULL; pSendData->dwCommandDescriptor = NULL_DESCRIPTOR; pWriteData = NULL; pSPData = CSPData::SPDataFromCOMInterface( pThis ); DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED ); // // No need to lock down the thread counts here because the user already has // a connect or something running or they wouldn't be calling this function. // That outstanding connect would have locked down the thread pool. // // // Attempt to grab the endpoint from the handle. If this succeeds, the // endpoint can send. // pEndpoint = pSPData->EndpointFromHandle( pSendData->hEndpoint ); if ( pEndpoint == NULL ) { hr = DPNERR_INVALIDHANDLE; DPFX(DPFPREP, 0, "Invalid endpoint handle on send!" ); goto Failure; } // // send data from pool // PoolContext.SPType = pSPData->GetType(); pWriteData = pSPData->GetThreadPool()->GetNewWriteIOData( &PoolContext ); if ( pWriteData == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Cannot get new write data from pool in SendData!" ); goto Failure; } DNASSERT( pWriteData->m_pCommand != NULL ); DNASSERT( pWriteData->SocketPort() == NULL ); // // set the command state and fill in the message information // pWriteData->m_pCommand->SetType( COMMAND_TYPE_SEND ); pWriteData->m_pCommand->SetState( COMMAND_STATE_PENDING ); pWriteData->m_pCommand->SetEndpoint( pEndpoint ); pWriteData->m_pCommand->SetUserContext( pSendData->pvContext ); DNASSERT( pWriteData->m_SendCompleteAction == SEND_COMPLETE_ACTION_UNKNOWN ); pWriteData->m_SendCompleteAction = SEND_COMPLETE_ACTION_COMPLETE_COMMAND; DNASSERT( pSendData->dwBufferCount != 0 ); pWriteData->m_uBufferCount = pSendData->dwBufferCount; pWriteData->m_pBuffers = pSendData->pBuffers; pWriteData->m_pDestinationSocketAddress = pEndpoint->GetRemoteAddressPointer(); pSendData->hCommand = pWriteData->m_pCommand; pSendData->dwCommandDescriptor = pWriteData->m_pCommand->GetDescriptor(); // // send data through the endpoint // pEndpoint->SendUserData( pWriteData ); Exit: if ( pEndpoint != NULL ) { pEndpoint->DecCommandRef(); pEndpoint = NULL; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: if ( pWriteData != NULL ) { pSPData->GetThreadPool()->ReturnWriteIOData( pWriteData ); DEBUG_ONLY( pWriteData = NULL ); } goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_CancelCommand cancels a command in progress * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_CancelCommand" STDMETHODIMP DNSP_CancelCommand( IDP8ServiceProvider *pThis, HANDLE hCommand, DWORD dwCommandDescriptor ) { HRESULT hr; CCommandData *pCommandData; BOOL fCommandLocked; BOOL fReferenceAdded; CSPData *pSPData; CEndpoint *pEndpoint; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p, %ld)", pThis, hCommand, dwCommandDescriptor); DNASSERT( pThis != NULL ); DNASSERT( hCommand != NULL ); DNASSERT( dwCommandDescriptor != NULL_DESCRIPTOR ); // // initialize // hr = DPN_OK; fCommandLocked = FALSE; fReferenceAdded = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // No need to lock the thread pool counts because there's already some outstanding // enum, connect or listen running that has done so. // // // check SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized // case SPSTATE_INITIALIZED: { IDP8ServiceProvider_AddRef( pThis ); fReferenceAdded = TRUE; break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "CancelCommand called on uninitialized SP!" ); DNASSERT( FALSE ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "CancelCommand called on closing SP!" ); DNASSERT( FALSE ); break; } // // unknown // default: { hr = DPNERR_GENERIC; DNASSERT( FALSE ); break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Exit; } pCommandData = static_cast( hCommand ); pCommandData->Lock(); fCommandLocked = TRUE; // // make sure the right command is being cancelled // if ( dwCommandDescriptor != pCommandData->GetDescriptor() ) { hr = DPNERR_INVALIDCOMMAND; DPFX(DPFPREP, 0, "Attempt to cancel command (0x%p) with mismatched command descriptor (%u != %u)!", hCommand, dwCommandDescriptor, pCommandData->GetDescriptor() ); goto Exit; } switch ( pCommandData->GetState() ) { // // unknown command state // case COMMAND_STATE_UNKNOWN: { hr = DPNERR_INVALIDCOMMAND; DNASSERT( FALSE ); break; } // // command is waiting to be processed, set command state to be cancelling // and wait for someone to pick it up // case COMMAND_STATE_PENDING: { DPFX(DPFPREP, 5, "Marking command 0x%p as cancelling.", pCommandData); pCommandData->SetState( COMMAND_STATE_CANCELLING ); break; } // // command in progress, and can't be cancelled // case COMMAND_STATE_INPROGRESS_CANNOT_CANCEL: { DPFX(DPFPREP, 1, "Cannot cancel command 0x%p.", pCommandData); hr = DPNERR_CANNOTCANCEL; break; } // // Command is already being cancelled. This is not a problem, but shouldn't // be happening for any endpoints other than connects. // case COMMAND_STATE_CANCELLING: { DNASSERT( pCommandData->GetEndpoint()->GetType() == ENDPOINT_TYPE_CONNECT ); DNASSERT( hr == DPN_OK ); break; } // // command is in progress, find out what type of command it is // case COMMAND_STATE_INPROGRESS: { switch ( pCommandData->GetType() ) { case COMMAND_TYPE_UNKNOWN: { // we should never be here DNASSERT( FALSE ); break; } case COMMAND_TYPE_CONNECT: case COMMAND_TYPE_LISTEN: { // // Set this command to the cancel state before we shut down // this endpoint. Make sure a reference is added to the // endpoint so it stays around for the cancel. // pCommandData->SetState( COMMAND_STATE_CANCELLING ); pEndpoint = pCommandData->GetEndpoint(); pEndpoint->AddRef(); DPFX(DPFPREP, 3, "Cancelling %s command 0x%p (endpoint 0x%p).", ((pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT) ? "connect" : "listen"), pCommandData, pEndpoint); pCommandData->Unlock(); fCommandLocked = FALSE; pEndpoint->Lock(); switch ( pEndpoint->GetState() ) { // // endpoint is already disconnecting, no action needs to be taken // case ENDPOINT_STATE_DISCONNECTING: { pEndpoint->Unlock(); pEndpoint->DecRef(); goto Exit; break; } // // Endpoint is connecting. Flag it as disconnecting and // add a reference so it doesn't disappear on us. // case ENDPOINT_STATE_ATTEMPTING_CONNECT: { DNASSERT(pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT); pEndpoint->SetState( ENDPOINT_STATE_DISCONNECTING ); break; } // // Endpoint has finished connecting. Report that the // command is uncancellable. Sorry Charlie, we missed // the window. // case ENDPOINT_STATE_CONNECT_CONNECTED: { DNASSERT(pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT); DPFX(DPFPREP, 1, "Cannot cancel connect command 0x%p (endpoint 0x%p) that's already (or is about to) complete.", pCommandData, pEndpoint); pEndpoint->Unlock(); pEndpoint->DecRef(); hr = DPNERR_CANNOTCANCEL; goto Exit; break; } // // Endpoint is listening. Flag it as disconnecting and // add a reference so it doesn't disappear on us // case ENDPOINT_STATE_LISTEN: { DNASSERT(pEndpoint->GetType() == ENDPOINT_TYPE_LISTEN); pEndpoint->SetState( ENDPOINT_STATE_DISCONNECTING ); break; } // // other state // default: { DNASSERT( FALSE ); break; } } pEndpoint->Unlock(); pEndpoint->Close( DPNERR_USERCANCEL ); pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint->DecRef(); break; } case COMMAND_TYPE_ENUM_QUERY: { pEndpoint = pCommandData->GetEndpoint(); DNASSERT( pEndpoint != NULL ); DPFX(DPFPREP, 3, "Cancelling enum query command 0x%p (endpoint 0x%p).", pCommandData, pEndpoint); pEndpoint->AddRef(); pCommandData->SetState( COMMAND_STATE_CANCELLING ); pCommandData->Unlock(); fCommandLocked = FALSE; pEndpoint->StopEnumCommand( DPNERR_USERCANCEL ); pEndpoint->DecRef(); break; } case COMMAND_TYPE_SEND: { // we should never be here DNASSERT( FALSE ); break; } default: { DNASSERT( FALSE ); break; } } break; } // // other command state // default: { DNASSERT( FALSE ); break; } } Exit: if ( fCommandLocked != FALSE ) { DNASSERT( pCommandData != NULL ); pCommandData->Unlock(); fCommandLocked = FALSE; } if ( fReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_GetCaps - get SP capabilities // // Entry: Pointer to DNSP interface // Pointer to caps data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_GetCaps" STDMETHODIMP DNSP_GetCaps( IDP8ServiceProvider *pThis, SPGETCAPSDATA *pCapsData ) { HRESULT hr; BOOL fInterfaceReferenceAdded; CSPData *pSPData; LONG iIOThreadCount; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pCapsData); DNASSERT( pThis != NULL ); DNASSERT( pCapsData != NULL ); DNASSERT( pCapsData->dwSize == sizeof( *pCapsData ) ); // // initialize // hr = DPN_OK; fInterfaceReferenceAdded = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // no need to tell thread pool to lock the thread count for this function. // // // validate SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized, add a reference and proceed // case SPSTATE_INITIALIZED: { IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; DNASSERT( hr == DPN_OK ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "AddToGroup called on uninitialized SP!" ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "AddToGroup called while SP closing!" ); break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Failure; } // // set flags // pCapsData->dwFlags = 0; pCapsData->dwFlags |= ( DPNSPCAPS_SUPPORTSDPNSRV | DPNSPCAPS_SUPPORTSBROADCAST | DPNSPCAPS_SUPPORTSALLADAPTERS ); // // set frame sizes // pCapsData->dwUserFrameSize = MAX_USER_PAYLOAD; pCapsData->dwEnumFrameSize = 1000; // // Set link speed, no need to check for endpoint because // the link speed cannot be determined. // pCapsData->dwLocalLinkSpeed = UNKNOWN_BANDWIDTH; hr = pSPData->GetThreadPool()->GetIOThreadCount( &iIOThreadCount ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "DNSP_GetCaps: Failed to get thread pool count!" ); DisplayDNError( 0, hr ); goto Failure; } pCapsData->dwIOThreadCount = iIOThreadCount; // // set enumeration defaults // pCapsData->dwDefaultEnumRetryCount = DEFAULT_ENUM_RETRY_COUNT; pCapsData->dwDefaultEnumRetryInterval = DEFAULT_ENUM_RETRY_INTERVAL; pCapsData->dwDefaultEnumTimeout = DEFAULT_ENUM_TIMEOUT; // // set buffering information // DNASSERT( g_dwWinsockReceiveBufferMultiplier <= UINT32_MAX ); pCapsData->dwBuffersPerThread = static_cast( g_dwWinsockReceiveBufferMultiplier ); pCapsData->dwSystemBufferSize = 8192; if ( g_fWinsockReceiveBufferSizeOverridden == FALSE ) { SOCKET TestSocket; TestSocket = INVALID_SOCKET; switch ( pSPData->GetType() ) { case TYPE_IP: { TestSocket = p_socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); break; } case TYPE_IPX: { TestSocket = p_socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX ); break; } default: { DNASSERT( FALSE ); break; } } if ( TestSocket != INVALID_SOCKET ) { INT iBufferSize; INT iBufferSizeSize; INT iWSAReturn; iBufferSizeSize = sizeof( iBufferSize ); iWSAReturn = p_getsockopt( TestSocket, // socket SOL_SOCKET, // socket level option SO_RCVBUF, // socket option reinterpret_cast( &iBufferSize ), // pointer to destination &iBufferSizeSize // pointer to destination size ); if ( iWSAReturn != SOCKET_ERROR ) { pCapsData->dwSystemBufferSize = iBufferSize; } else { DPFX(DPFPREP, 0, "Failed to get socket receive buffer options!" ); DisplayWinsockError( 0, iWSAReturn ); } p_closesocket( TestSocket ); TestSocket = INVALID_SOCKET; } } else { pCapsData->dwSystemBufferSize = g_iWinsockReceiveBufferSize; } Exit: if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_SetCaps - set SP capabilities // // Entry: Pointer to DNSP interface // Pointer to caps data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_SetCaps" STDMETHODIMP DNSP_SetCaps( IDP8ServiceProvider *pThis, SPSETCAPSDATA *pCapsData ) { HRESULT hr; BOOL fInterfaceReferenceAdded; CSPData *pSPData; CRegistry RegObject; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pCapsData); DNASSERT( pThis != NULL ); DNASSERT( pCapsData != NULL ); DNASSERT( pCapsData->dwSize == sizeof( *pCapsData ) ); // // initialize // hr = DPN_OK; fInterfaceReferenceAdded = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // no need to tell thread pool to lock the thread count for this function. // // // validate SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized, add a reference and proceed // case SPSTATE_INITIALIZED: { IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; DNASSERT( hr == DPN_OK ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "AddToGroup called on uninitialized SP!" ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "AddToGroup called while SP closing!" ); break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Failure; } // // validate caps // if ( pCapsData->dwBuffersPerThread == 0 ) { DPFX(DPFPREP, 0, "Failing SetCaps because dwBuffersPerThread == 0" ); hr = DPNERR_INVALIDPARAM; goto Failure; } // // change thread count // DNASSERT( pCapsData->dwIOThreadCount != 0 ); hr = pSPData->GetThreadPool()->SetIOThreadCount( pCapsData->dwIOThreadCount ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "DNSP_SetCaps: Failed to set thread pool count!" ); DisplayDNError( 0, hr ); goto Failure; } // // Only update the thread multiplier if there is a difference. Give precedence // to any values in the registry. // if ( pCapsData->dwBuffersPerThread > g_dwWinsockReceiveBufferMultiplier ) { BOOL fSetBufferMultiplier; DWORD dwDelta; fSetBufferMultiplier = FALSE; dwDelta = 0; if ( RegObject.Open( HKEY_LOCAL_MACHINE, g_RegistryBase ) != FALSE ) { DWORD dwRegBufferMultiplier; if ( RegObject.ReadDWORD( g_RegistryKeyReceiveBufferMultiplier, dwRegBufferMultiplier ) != FALSE ) { if ( dwRegBufferMultiplier > g_dwWinsockReceiveBufferMultiplier ) { fSetBufferMultiplier = TRUE; DNASSERT( g_dwWinsockReceiveBufferMultiplier <= UINT32_MAX ); dwDelta = dwRegBufferMultiplier - static_cast( g_dwWinsockReceiveBufferMultiplier ); g_dwWinsockReceiveBufferMultiplier = dwRegBufferMultiplier; } } else { fSetBufferMultiplier = TRUE; DNASSERT( g_dwWinsockReceiveBufferMultiplier <= UINT32_MAX ); dwDelta = pCapsData->dwBuffersPerThread - static_cast( g_dwWinsockReceiveBufferMultiplier ); g_dwWinsockReceiveBufferMultiplier = pCapsData->dwBuffersPerThread; } } else { fSetBufferMultiplier = TRUE; DNASSERT( g_dwWinsockReceiveBufferMultiplier <= UINT32_MAX ); dwDelta = pCapsData->dwBuffersPerThread - static_cast( g_dwWinsockReceiveBufferMultiplier ); g_dwWinsockReceiveBufferMultiplier = pCapsData->dwBuffersPerThread; } if ( fSetBufferMultiplier != FALSE ) { pSPData->IncreaseOutstandingReceivesOnAllSockets( dwDelta ); } } // // Set the receive buffer size. // DBG_CASSERT( sizeof( pCapsData->dwSystemBufferSize ) == sizeof( g_iWinsockReceiveBufferSize ) ); g_fWinsockReceiveBufferSizeOverridden = TRUE; g_iWinsockReceiveBufferSize = pCapsData->dwSystemBufferSize; pSPData->SetWinsockBufferSizeOnAllSockets( g_iWinsockReceiveBufferSize ); Exit: if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_ReturnReceiveBuffers - return receive buffers to pool // // Entry: Pointer to DNSP interface // Pointer to caps data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_ReturnReceiveBuffers" STDMETHODIMP DNSP_ReturnReceiveBuffers( IDP8ServiceProvider *pThis, SPRECEIVEDBUFFER *pReceivedBuffers ) { SPRECEIVEDBUFFER *pBuffers; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pReceivedBuffers); // // no need to tell thread pool to lock the thread count for this function. // DNASSERT( pThis != NULL ); DNASSERT( pReceivedBuffers != NULL ); pBuffers = pReceivedBuffers; while ( pBuffers != NULL ) { SPRECEIVEDBUFFER *pTemp; CReadIOData *pReadData; pTemp = pBuffers; pBuffers = pBuffers->pNext; pReadData = CReadIOData::ReadDataFromSPReceivedBuffer( pTemp ); DEBUG_ONLY( pReadData->m_fRetainedByHigherLayer = FALSE ); pReadData->DecRef(); } //DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); DPFX(DPFPREP, 2, "Returning: DPN_OK"); return DPN_OK; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_GetAddressInfo - get address information for an endpoint // // Entry: Pointer to DNSP Interface // Pointer to input data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_GetAddressInfo" STDMETHODIMP DNSP_GetAddressInfo( IDP8ServiceProvider *pThis, SPGETADDRESSINFODATA *pGetAddressInfoData ) { HRESULT hr; CEndpoint *pEndpoint; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pGetAddressInfoData); DNASSERT( pThis != NULL ); DNASSERT( pGetAddressInfoData != NULL ); DNASSERT( pGetAddressInfoData->hEndpoint != INVALID_HANDLE_VALUE ); DNASSERT( ( pGetAddressInfoData->Flags & ~( SP_GET_ADDRESS_INFO_LOCAL_ADAPTER | SP_GET_ADDRESS_INFO_REMOTE_HOST | SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES | SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS ) ) == 0 ); // // initialize // hr = DPN_OK; DBG_CASSERT( sizeof( pEndpoint ) == sizeof( pGetAddressInfoData->hEndpoint ) ); pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // no need to tell thread pool to lock the thread count for this function. // pEndpoint = pSPData->EndpointFromHandle( pGetAddressInfoData->hEndpoint ); if ( pEndpoint != NULL ) { switch ( pGetAddressInfoData->Flags ) { case SP_GET_ADDRESS_INFO_REMOTE_HOST: { pGetAddressInfoData->pAddress = pEndpoint->GetRemoteHostDP8Address(); break; } case SP_GET_ADDRESS_INFO_LOCAL_ADAPTER: { pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( SP_ADDRESS_TYPE_DEVICE_USE_ANY_PORT ); break; } case SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES: { pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( SP_ADDRESS_TYPE_HOST ); break; } case SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS: { pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( SP_ADDRESS_TYPE_PUBLIC_HOST_ADDRESS ); break; } default: { DNASSERT( FALSE ); break; } } pEndpoint->DecCommandRef(); pEndpoint = NULL; } else { hr = DPNERR_INVALIDENDPOINT; } if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Problem getting DNAddress from endpoint!" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_IsApplicationSupported - determine if this application is supported by this // SP. // // Entry: Pointer to DNSP Interface // Pointer to input data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_IsApplicationSupported" STDMETHODIMP DNSP_IsApplicationSupported( IDP8ServiceProvider *pThis, SPISAPPLICATIONSUPPORTEDDATA *pIsApplicationSupportedData ) { HRESULT hr; BOOL fInterfaceReferenceAdded; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pIsApplicationSupportedData); DNASSERT( pThis != NULL ); DNASSERT( pIsApplicationSupportedData != NULL ); DNASSERT( pIsApplicationSupportedData->pApplicationGuid != NULL ); DNASSERT( pIsApplicationSupportedData->dwFlags == 0 ); // // initialize, we support all applications with this SP // hr = DPN_OK; fInterfaceReferenceAdded = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // no need to tell thread pool to lock the thread count for this function. // // // validate SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized, add a reference and proceed // case SPSTATE_INITIALIZED: { IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; DNASSERT( hr == DPN_OK ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "AddToGroup called on uninitialized SP!" ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "AddToGroup called while SP closing!" ); break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Failure; } Exit: if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_EnumAdapters - get a list of adapters for this SP // // Entry: Pointer DNSP Interface // Pointer to input data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_EnumAdapters" STDMETHODIMP DNSP_EnumAdapters( IDP8ServiceProvider *pThis, SPENUMADAPTERSDATA *pEnumAdaptersData ) { HRESULT hr; CSocketAddress *pSPAddress; BOOL fInterfaceReferenceAdded; CSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumAdaptersData); DNASSERT( pThis != NULL ); DNASSERT( pEnumAdaptersData != NULL ); DNASSERT( ( pEnumAdaptersData->pAdapterData != NULL ) || ( pEnumAdaptersData->dwAdapterDataSize == 0 ) ); DNASSERT( pEnumAdaptersData->dwFlags == 0 ); // // initialize // hr = DPN_OK; pEnumAdaptersData->dwAdapterCount = 0; pSPAddress = NULL; fInterfaceReferenceAdded = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); // // no need to tell thread pool to lock the thread count for this function. // // // validate SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized, add a reference and proceed // case SPSTATE_INITIALIZED: { IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; DNASSERT( hr == DPN_OK ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "EnumAdapters called on uninitialized SP!" ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "EnumAdapters called while SP closing!" ); break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Failure; } // // get an SP address from the pool to perform conversions to GUIDs // pSPAddress = pSPData->GetNewAddress(); if ( pSPAddress == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Failed to get address for GUID conversions in DNSP_EnumAdapters!" ); goto Failure; } // // enumerate adapters // hr = pSPAddress->EnumAdapters( pEnumAdaptersData ); if ( hr != DPN_OK ) { if (hr == DPNERR_BUFFERTOOSMALL) { DPFX(DPFPREP, 1, "Buffer too small for enumerating adapters."); } else { DPFX(DPFPREP, 0, "Problem enumerating adapters (err = 0x%lx)!", hr); DisplayDNError( 0, hr ); } goto Failure; } Exit: if ( pSPAddress != NULL ) { pSPData->ReturnAddress( pSPAddress ); pSPAddress = NULL; } if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNSP_ProxyEnumQuery - proxy an enum query // // Entry: Pointer DNSP Interface // Pointer to input data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNSP_ProxyEnumQuery" STDMETHODIMP DNSP_ProxyEnumQuery( IDP8ServiceProvider *pThis, SPPROXYENUMQUERYDATA *pProxyEnumQueryData ) { HRESULT hr; BOOL fInterfaceReferenceAdded; CSPData *pSPData; WRITE_IO_DATA_POOL_CONTEXT PoolContext; CSocketAddress *pDestinationAddress; CSocketAddress *pReturnAddress; CWriteIOData *pWriteData; CEndpoint *pEndpoint; const ENDPOINT_ENUM_QUERY_CONTEXT *pEndpointEnumContext; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pProxyEnumQueryData); DNASSERT( pThis != NULL ); DNASSERT( pProxyEnumQueryData != NULL ); DNASSERT( pProxyEnumQueryData->dwFlags == 0 ); // // initialize // hr = DPN_OK; DBG_CASSERT( OFFSETOF( ENDPOINT_ENUM_QUERY_CONTEXT, EnumQueryData ) == 0 ); pEndpointEnumContext = reinterpret_cast( pProxyEnumQueryData->pIncomingQueryData ); fInterfaceReferenceAdded = FALSE; pSPData = CSPData::SPDataFromCOMInterface( pThis ); pDestinationAddress = NULL; pReturnAddress = NULL; pWriteData = NULL; pEndpoint = NULL; // // No need to tell thread pool to lock the thread count for this function // because there's already an outstanding enum that did. // // // validate SP state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized, add a reference and proceed // case SPSTATE_INITIALIZED: { IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; DNASSERT( hr == DPN_OK ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "ProxyEnumQuery called on uninitialized SP!" ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "ProxyEnumQuery called while SP closing!" ); break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Failure; } // // preallocate addresses // pDestinationAddress = pSPData->GetNewAddress(); if ( pDestinationAddress == NULL ) { hr = DPNERR_OUTOFMEMORY; goto Failure; } pReturnAddress = pSPData->GetNewAddress(); if ( pReturnAddress == NULL ) { hr = DPNERR_OUTOFMEMORY; goto Failure; } // // set the endpoint and send it along // pEndpoint = pSPData->EndpointFromHandle( pEndpointEnumContext->hEndpoint ); if ( pEndpoint != NULL ) { // // set destination address from the supplied data // hr = pDestinationAddress->SocketAddressFromDP8Address( pProxyEnumQueryData->pDestinationAdapter, SP_ADDRESS_TYPE_DEVICE_PROXIED_ENUM_TARGET ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "ProxyEnumQuery: Failed to convert target adapter address" ); goto Failure; } // // set return address from incoming enum query // DBG_CASSERT( sizeof( *pReturnAddress->GetWritableAddress() ) == sizeof( *( pEndpointEnumContext->pReturnAddress->GetAddress() ) ) ); memcpy( pReturnAddress->GetWritableAddress(), pEndpointEnumContext->pReturnAddress->GetAddress(), sizeof( *pReturnAddress->GetWritableAddress() ) ); // // get write data from pool // PoolContext.SPType = pSPData->GetType(); pWriteData = pSPData->GetThreadPool()->GetNewWriteIOData( &PoolContext ); if ( pWriteData == NULL ) { DPFX(DPFPREP, 0, "ProxyEnumQuery: Failed to get write data!" ); hr = DPNERR_OUTOFMEMORY; goto Failure; } // // a new address is allocated here and will be returned in the send complete // code // pWriteData->m_pDestinationSocketAddress = pDestinationAddress; // // Copy the input BUFFERDESC into the local buffers for sending proxied enum data. // The second local buffer is reserved for the SP to prepend data // pWriteData->m_pBuffers = &pWriteData->m_ProxyEnumSendBuffers[ 1 ]; DBG_CASSERT( sizeof( pWriteData->m_ProxyEnumSendBuffers[ 1 ] ) == sizeof( pProxyEnumQueryData->pIncomingQueryData->pReceivedData->BufferDesc ) ); memcpy( &pWriteData->m_ProxyEnumSendBuffers[ 1 ], &pProxyEnumQueryData->pIncomingQueryData->pReceivedData->BufferDesc, sizeof( pWriteData->m_ProxyEnumSendBuffers[ 1 ] ) ); pWriteData->m_uBufferCount = 1; // // add a reference to the original receive buffer to prevent it from going // away while the enum response send is pending // pWriteData->m_pProxiedEnumReceiveBuffer = CReadIOData::ReadDataFromSPReceivedBuffer( pProxyEnumQueryData->pIncomingQueryData->pReceivedData ); DNASSERT( pWriteData->m_pProxiedEnumReceiveBuffer != NULL ); pWriteData->m_pProxiedEnumReceiveBuffer->AddRef(); pWriteData->m_SendCompleteAction = SEND_COMPLETE_ACTION_PROXIED_ENUM_CLEANUP; pEndpoint->SendProxiedEnumData( pWriteData, pReturnAddress, pEndpointEnumContext->dwEnumKey ); pEndpoint->DecCommandRef(); } Exit: if ( pReturnAddress != NULL ) { pSPData->ReturnAddress( pReturnAddress ); pReturnAddress = NULL; } if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** /* * * DNSP_NotSupported is used for methods required to implement the * interface but that are not supported by this SP. * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNSP_NotSupported" STDMETHODIMP DNSP_NotSupported( IDP8ServiceProvider *pThis, PVOID pvParam ) { DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pvParam); DPFX(DPFPREP, 2, "Returning: [DPNERR_UNSUPPORTED]"); return DPNERR_UNSUPPORTED; } //**********************************************************************