/*========================================================================== * * Copyright (C) 1998-2000 Microsoft Corporation. All Rights Reserved. * * File: SerialSP.cpp * Content: Service provider serial interface functions * * * History: * Date By Reason * ==== == ====== * 12/03/98 jtk Created * 09/23/99 jtk Derived from ComCore.cpp ***************************************************************************/ #include "dnmdmi.h" //********************************************************************** // Constant definitions //********************************************************************** //********************************************************************** // Macro definitions //********************************************************************** //********************************************************************** // Structure definitions //********************************************************************** //********************************************************************** // Variable definitions //********************************************************************** //********************************************************************** // Function prototypes //********************************************************************** //********************************************************************** // Function definitions //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_AddRef - increment interface reference cound // // Entry: Pointer to interface // // Exit: Current interface reference count // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_AddRef" STDMETHODIMP_(ULONG) DNMODEMSP_AddRef( IDP8ServiceProvider *pThis ) { CModemSPData * pSPData; ULONG ulResult; DPFX(DPFPREP, 2, "Parameters: (0x%p)", pThis); DNASSERT( pThis != NULL ); pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); ulResult = pSPData->AddRef(); DPFX(DPFPREP, 2, "Returning: [0x%u]", ulResult); return ulResult; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_Release - release an interface // // Entry: Pointer to current interface // Desired interface ID // Pointer to pointer to new interface // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_Release" STDMETHODIMP_(ULONG) DNMODEMSP_Release( IDP8ServiceProvider *pThis ) { CModemSPData * pSPData; ULONG ulResult; DNASSERT( pThis != NULL ); pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); ulResult = pSPData->DecRef(); DPFX(DPFPREP, 2, "Returning: [0x%u]", ulResult); return ulResult; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_Initialize - initialize SP interface // // Entry: Pointer to interface // Pointer to initialization data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_Initialize" STDMETHODIMP DNMODEMSP_Initialize( IDP8ServiceProvider *pThis, SPINITIALIZEDATA *pData ) { HRESULT hr; CModemSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pData); DNASSERT( pThis != NULL ); DNASSERT( pData != NULL ); // // initialize // hr = DPN_OK; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); // // prevent anyone else from messing with this interface and bump up the reference // count // 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: { hr = DPNERR_ALREADYINITIALIZED; DPFX(DPFPREP, 0, "Attempted to reinitialize interface!" ); DNASSERT( FALSE ); goto Exit; } } // // before we get too far, check for the availablility of serial ports or // modems // switch ( pSPData->GetType() ) { case TYPE_SERIAL: { BOOL fPortAvailable[ MAX_DATA_PORTS ]; DWORD dwPortCount; hr = GenerateAvailableComPortList( fPortAvailable, ( LENGTHOF( fPortAvailable ) - 1 ), &dwPortCount ); if ( ( hr != DPN_OK ) || ( dwPortCount == 0 ) ) { hr = DPNERR_UNSUPPORTED; goto Failure; } break; } case TYPE_MODEM: { if ( pSPData->GetThreadPool()->TAPIAvailable() != FALSE ) { DWORD dwModemCount; DWORD dwModemNameDataSize; HRESULT hTempResult; // // Get count of available modems. If this call succeeds but there // are no modems returned, fail. // dwModemCount = 0; dwModemNameDataSize = 0; hTempResult = GenerateAvailableModemList( pSPData->GetThreadPool()->GetTAPIInfo(), &dwModemCount, NULL, &dwModemNameDataSize ); if ( ( hTempResult != DPNERR_BUFFERTOOSMALL ) && ( hTempResult != DPN_OK ) ) { hr = hTempResult; DPFX(DPFPREP, 0, "Failed to detect available modems!" ); DisplayDNError( 0, hr ); goto Failure; } if ( dwModemCount == 0 ) { DPFX(DPFPREP, 1, "No modems detected!" ); hr = DPNERR_UNSUPPORTED; goto Failure; } DNASSERT( hr == DPN_OK ); } else { DPFX(DPFPREP, 0, "TAPI not available!" ); hr = DPNERR_UNSUPPORTED; goto Failure; } break; } default: { DNASSERT( FALSE ); break; } } // // remember the init data // pSPData->SetCallbackData( pData ); // // Success from here on in // IDP8SPCallback_AddRef( pSPData->DP8SPCallbackInterface() ); pSPData->SetState( SPSTATE_INITIALIZED ); pSPData->Unlock(); IDP8ServiceProvider_AddRef( pThis ); Exit: DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: pSPData->Unlock(); goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_Close - close this instance of the service provier // // Entry: Pointer to the service provider to close // // Exit: Error Code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_Close" STDMETHODIMP DNMODEMSP_Close( IDP8ServiceProvider *pThis ) { HRESULT hr; CModemSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p)", pThis); DNASSERT( pThis != NULL ); // // initialize // hr = DPN_OK; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); switch ( pSPData->GetType() ) { case TYPE_SERIAL: case TYPE_MODEM: { // // release our ref to the DPlay callbacks // pSPData->Shutdown(); IDP8ServiceProvider_Release( pThis ); break; } default: { DNASSERT( FALSE ); break; } } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_Connect - start process to establish comport connection to a remote host // // Entry: Pointer to the service provider interface // Pointer to connection data // // Exit: Error Code // // Note: Any command handle allocated by this function is closed by the // endpoint. // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_Connect" STDMETHODIMP DNMODEMSP_Connect( IDP8ServiceProvider *pThis, SPCONNECTDATA *pConnectData ) { HRESULT hr; HRESULT hTempResult; CModemSPData *pSPData; CModemEndpoint *pEndpoint; CModemCommandData *pCommand; BOOL fEndpointOpen; GUID DeviceGUID; GUID guidnull; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pConnectData); DNASSERT( pThis != NULL ); DNASSERT( pConnectData != NULL ); DNASSERT( pConnectData->pAddressHost != NULL ); DNASSERT( pConnectData->pAddressDeviceInfo != NULL ); DNASSERT( ( pConnectData->dwFlags & ~( DPNSPF_OKTOQUERY ) ) == 0 ); DNASSERT( ( pConnectData->dwFlags & ~( DPNSPF_OKTOQUERY ) ) == 0 ); // // initialize // hr = DPNERR_PENDING; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); pEndpoint = NULL; pCommand = NULL; fEndpointOpen = FALSE; pConnectData->hCommand = NULL; pConnectData->dwCommandDescriptor = NULL_DESCRIPTOR; memset(&guidnull, 0, sizeof(guidnull)); // // 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; } // // validate state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized // case SPSTATE_INITIALIZED: { DNASSERT( hr == DPNERR_PENDING ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "DNMODEMSP_Connect called on uninitialized SP!" ); goto Failure; break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "DNMODEMSP_Connect called while SP closing!" ); goto Failure; break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; goto Failure; break; } } pSPData->Unlock(); if ( hr != DPNERR_PENDING ) { DNASSERT( hr != DPN_OK ); goto Failure; } // // check for invalid device ID // hTempResult = IDirectPlay8Address_GetDevice( pConnectData->pAddressDeviceInfo, &DeviceGUID ); switch ( hTempResult ) { // // there was a device ID, check against GUID_NULL // case DPN_OK: { if ( IsEqualCLSID( DeviceGUID, guidnull ) != FALSE ) { hr = DPNERR_ADDRESSING; DPFX(DPFPREP, 0, "GUID_NULL was specified as a serial/modem device!" ); goto Failure; } break; } // // no device address specified, not a problem // case DPNERR_DOESNOTEXIST: { break; } // // other, stop and figure out why we're here // default: { DNASSERT( FALSE ); hr = hTempResult; DPFX(DPFPREP, 0, "Failed to validate device address!" ); DisplayDNError( 0, hTempResult ); break; } } // // get endpoint for this connection // pEndpoint = pSPData->GetNewEndpoint(); if ( pEndpoint == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "DNMODEMSP_Connect: Cannot create new endpoint!" ); goto Failure; } // // get new command // pCommand = (CModemCommandData*)g_ModemCommandDataPool.Get(); if ( pCommand == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "DNMODEMSP_Connect: Cannot get command handle!" ); goto Failure; } // // initialize command // pConnectData->hCommand = pCommand; pConnectData->dwCommandDescriptor = pCommand->GetDescriptor(); pCommand->SetType( COMMAND_TYPE_CONNECT ); pCommand->SetState( COMMAND_STATE_PENDING ); pCommand->SetEndpoint( pEndpoint ); // // open this endpoint // hTempResult = pEndpoint->Open( pConnectData->pAddressHost, pConnectData->pAddressDeviceInfo, LINK_DIRECTION_OUTGOING, ENDPOINT_TYPE_CONNECT ); switch ( hTempResult ) { // // endpoint opened, no problem // case DPN_OK: { // // copy connect data and the submit background job // fEndpointOpen = TRUE; pEndpoint->CopyConnectData( pConnectData ); pEndpoint->AddRef(); hTempResult = pSPData->GetThreadPool()->SubmitDelayedCommand( pEndpoint->ConnectJobCallback, pEndpoint->CancelConnectJobCallback, pEndpoint ); if ( hTempResult != DPN_OK ) { pEndpoint->DecRef(); hr = hTempResult; 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; DNASSERT( hr == DPNERR_PENDING ); break; } // // not all of the addressing information was specifed, need to query user // case DPNERR_INCOMPLETEADDRESS: { #ifndef DPNBUILD_NOSPUI if ( ( pConnectData->dwFlags & DPNSPF_OKTOQUERY ) != 0 ) { // // copy connect data for future reference and then start the dialog // fEndpointOpen = TRUE; pEndpoint->CopyConnectData( pConnectData ); hTempResult = pEndpoint->ShowOutgoingSettingsDialog( pSPData->GetThreadPool() ); if ( hTempResult != DPN_OK ) { hr = hTempResult; DPFX(DPFPREP, 0, "DNMODEMSP_Connect: Problem showing settings dialog!" ); DisplayDNError( 0, hTempResult ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; DNASSERT( hr == DPNERR_PENDING ); goto Exit; } else #endif // !DPNBUILD_NOSPUI { hr = hTempResult; goto Failure; } break; } default: { hr = hTempResult; DPFX(DPFPREP, 0, "DNMODEMSP_Connect: Problem opening endpoint with host address!" ); DisplayDNError( 0, hTempResult ); 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 DNMODEMSP_Connect()" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: // // return any outstanding endpoint // if ( pEndpoint != NULL ) { if ( fEndpointOpen != FALSE ) { DNASSERT( ( hr != DPN_OK ) && ( hr != DPNERR_PENDING ) ); pEndpoint->Close( hr ); fEndpointOpen = FALSE; } pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint = NULL; } // // return any outstanding command // if ( pCommand != NULL ) { pCommand->DecRef(); pCommand = NULL; pConnectData->hCommand = NULL; pConnectData->dwCommandDescriptor = NULL_DESCRIPTOR; } goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_Disconnect - disconnect from a remote host // // Entry: Pointer to the service provider interface // Pointer to connection data // // Exit: Error Code // // Note: This command is considered final, there's no chance to cancel a // disconnect. // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_Disconnect" STDMETHODIMP DNMODEMSP_Disconnect( IDP8ServiceProvider *pThis, SPDISCONNECTDATA *pDisconnectData ) { HRESULT hr; HRESULT hTempResult; CModemEndpoint *pEndpoint; CModemSPData *pSPData; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pDisconnectData); DNASSERT( pThis != NULL ); DNASSERT( pDisconnectData != NULL ); DNASSERT( pDisconnectData->hEndpoint != INVALID_HANDLE_VALUE && pDisconnectData->hEndpoint != 0 ); DNASSERT( pDisconnectData->dwFlags == 0 ); // // initialize // hr = DPN_OK; pEndpoint = NULL; pDisconnectData->hCommand = NULL; pDisconnectData->dwCommandDescriptor = NULL_DESCRIPTOR; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); // // 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!" ); goto Failure; break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "Disconnect called on closing SP!" ); goto Failure; break; } // // unknown // default: { hr = DPNERR_GENERIC; DNASSERT( FALSE ); goto Failure; break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Failure; } // // look up the endpoint and if it's found, close its handle // pEndpoint = pSPData->GetEndpointAndCloseHandle( (DPNHANDLE)(DWORD_PTR)pDisconnectData->hEndpoint ); if ( pEndpoint == NULL ) { hr = DPNERR_INVALIDENDPOINT; goto Failure; } hTempResult = pEndpoint->Disconnect( (DPNHANDLE)(DWORD_PTR)pDisconnectData->hEndpoint ); switch ( hTempResult ) { // // endpoint disconnected immediately // 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 DNMODEMSP_Disconnect!" ); DisplayDNError( 0, hTempResult ); break; } } Exit: // // remove oustanding reference from GetEndpointHandleAndClose() // if ( pEndpoint != NULL ) { pEndpoint->DecRef(); pEndpoint = NULL; } if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Problem with DNMODEMSP_Disconnect()" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_Listen - start process to listen for comport connections // // Entry: Pointer to the service provider interface // Pointer to listen data // // Exit: Error Code // // Note: Any command handle allocated by this function is closed by the // endpoint. // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_Listen" STDMETHODIMP DNMODEMSP_Listen( IDP8ServiceProvider *pThis, SPLISTENDATA *pListenData ) { HRESULT hr; HRESULT hTempResult; CModemSPData *pSPData; CModemEndpoint *pEndpoint; CModemCommandData *pCommand; BOOL fEndpointOpen; BOOL fInterfaceReferenceAdded; GUID DeviceGUID; GUID guidnull; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pListenData); DNASSERT( pThis != NULL ); DNASSERT( pListenData != NULL ); DNASSERT( ( pListenData->dwFlags & ~( DPNSPF_OKTOQUERY | DPNSPF_BINDLISTENTOGATEWAY | DPNSPF_LISTEN_DISALLOWENUMS ) ) == 0 ); // // initialize // hr = DPNERR_PENDING; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); pEndpoint = NULL; pCommand = NULL; fEndpointOpen = FALSE; pListenData->hCommand = NULL; pListenData->dwCommandDescriptor = NULL_DESCRIPTOR; fInterfaceReferenceAdded = FALSE; memset(&guidnull, 0, sizeof(guidnull)); // // 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; } // // validate state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized // case SPSTATE_INITIALIZED: { DNASSERT( hr == DPNERR_PENDING ); IDP8ServiceProvider_AddRef( pThis ); fInterfaceReferenceAdded = TRUE; break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "DNMODEMSP_Listen called on uninitialized SP!" ); goto Failure; break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "DNMODEMSP_Listen called while SP closing!" ); goto Failure; break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; goto Failure; break; } } pSPData->Unlock(); if ( hr != DPNERR_PENDING ) { DNASSERT( hr != DPN_OK ); goto Failure; } // // check for invalid device ID // hTempResult = IDirectPlay8Address_GetDevice( pListenData->pAddressDeviceInfo, &DeviceGUID ); switch ( hTempResult ) { // // there was a device ID, check against GUID_NULL // case DPN_OK: { if ( IsEqualCLSID( DeviceGUID, guidnull ) != FALSE ) { hr = DPNERR_ADDRESSING; DPFX(DPFPREP, 0, "GUID_NULL was specified as a serial/modem device!" ); goto Failure; } break; } // // no device address specified, not a problem // case DPNERR_DOESNOTEXIST: { break; } // // other, stop and figure out why we're here // default: { DNASSERT( FALSE ); hr = hTempResult; DPFX(DPFPREP, 0, "Failed to validate device address!" ); DisplayDNError( 0, hTempResult ); break; } } // // get endpoint for this connection // pEndpoint = pSPData->GetNewEndpoint(); if ( pEndpoint == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "DNMODEMSP_Listen: Cannot create new endpoint!" ); goto Failure; } // // get new command // pCommand = (CModemCommandData*)g_ModemCommandDataPool.Get(); if ( pCommand == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "DNMODEMSP_Listen: Cannot get command handle!" ); goto Failure; } // // initialize command // pListenData->hCommand = pCommand; pListenData->dwCommandDescriptor = pCommand->GetDescriptor(); pCommand->SetType( COMMAND_TYPE_LISTEN ); pCommand->SetState( COMMAND_STATE_PENDING ); pCommand->SetEndpoint( pEndpoint ); // // open this endpoint // hTempResult = pEndpoint->Open( NULL, pListenData->pAddressDeviceInfo, LINK_DIRECTION_INCOMING, ENDPOINT_TYPE_LISTEN ); switch ( hTempResult ) { // // address conversion was fine, complete this command in the background // case DPN_OK: { // // copy connect data and the submit background job // fEndpointOpen = TRUE; pEndpoint->CopyListenData( pListenData ); pEndpoint->AddRef(); hTempResult = pSPData->GetThreadPool()->SubmitDelayedCommand( pEndpoint->ListenJobCallback, pEndpoint->CancelListenJobCallback, pEndpoint ); if ( hTempResult != DPN_OK ) { pEndpoint->DecRef(); hr = hTempResult; DPFX(DPFPREP, 0, "DNMODEMSP_Listen: Failed to submit delayed listen!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; DNASSERT( hr == DPNERR_PENDING ); break; } // // address was incomplete, display a dialog if we can, otherwise fail the command // case DPNERR_INCOMPLETEADDRESS: { if ( ( pListenData->dwFlags & DPNSPF_OKTOQUERY ) != 0 ) { // // copy connect data for future reference and then start the dialog // fEndpointOpen = TRUE; pEndpoint->CopyListenData( pListenData ); hTempResult = pEndpoint->ShowIncomingSettingsDialog( pSPData->GetThreadPool() ); if ( hTempResult != DPN_OK ) { hr = hTempResult; DPFX(DPFPREP, 0, "Problem showing settings dialog in DNMODEMSP_Listen!" ); DisplayDNError( 0, hTempResult ); goto Failure; } // // This endpoint has been handed off, clear the pointer to it. // There is no reference to remove because the command is // still pending. // pEndpoint = NULL; DNASSERT( hr == DPNERR_PENDING ); goto Exit; } else { hr = hTempResult; goto Failure; } break; } default: { hr = hTempResult; DPFX(DPFPREP, 0, "Problem initializing endpoint in DNMODEMSP_Listen!" ); DisplayDNError( 0, hTempResult ); 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 DNMODEMSP_Listen()" ); DisplayDNError( 0, hr ); } if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: // // return any outstanding endpoint // if ( pEndpoint != NULL ) { if ( fEndpointOpen != FALSE ) { DNASSERT( ( hr != DPN_OK ) && ( hr != DPNERR_PENDING ) ); pEndpoint->Close( hr ); fEndpointOpen = FALSE; } pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint = NULL; } // // return any outstanding command // if ( pCommand != NULL ) { pCommand->DecRef(); pCommand = NULL; pListenData->hCommand = NULL; pListenData->dwCommandDescriptor = NULL_DESCRIPTOR; } goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_EnumQuery - start process to enum comport connections // // Entry: Pointer to the service provider interface // Pointer to enum data // // Exit: Error Code // // Note: Any command handle allocated by this function is closed by the // endpoint. // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_EnumQuery" STDMETHODIMP DNMODEMSP_EnumQuery( IDP8ServiceProvider *pThis, SPENUMQUERYDATA *pEnumQueryData ) { HRESULT hr; HRESULT hTempResult; CModemSPData *pSPData; CModemEndpoint *pEndpoint; CModemCommandData *pCommand; BOOL fEndpointOpen; GUID DeviceGUID; GUID guidnull; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumQueryData); DNASSERT( pThis != NULL ); DNASSERT( pEnumQueryData != NULL ); DNASSERT( ( pEnumQueryData->dwFlags & ~( DPNSPF_OKTOQUERY ) ) == 0 ); // // initialize // hr = DPNERR_PENDING; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); pEndpoint = NULL; pCommand = NULL; fEndpointOpen = FALSE; pEnumQueryData->hCommand = NULL; pEnumQueryData->dwCommandDescriptor = NULL_DESCRIPTOR; memset(&guidnull, 0, sizeof(guidnull)); // // 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; } // // validate state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider is initialized // case SPSTATE_INITIALIZED: { DNASSERT( hr == DPNERR_PENDING ); break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "DNMODEMSP_EnumQuery called on uninitialized SP!" ); goto Failure; break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "DNMODEMSP_EnumQuery called while SP closing!" ); goto Failure; break; } // // unknown // default: { DNASSERT( FALSE ); hr = DPNERR_GENERIC; goto Failure; break; } } pSPData->Unlock(); if ( hr != DPNERR_PENDING ) { DNASSERT( hr != DPN_OK ); goto Failure; } // // check for invalid device ID // hTempResult = IDirectPlay8Address_GetDevice( pEnumQueryData->pAddressDeviceInfo, &DeviceGUID ); switch ( hTempResult ) { // // there was a device ID, check against GUID_NULL // case DPN_OK: { if ( IsEqualCLSID( DeviceGUID, guidnull ) != FALSE ) { hr = DPNERR_ADDRESSING; DPFX(DPFPREP, 0, "GUID_NULL was specified as a serial/modem device!" ); goto Failure; } break; } // // no device address specified, not a problem // case DPNERR_DOESNOTEXIST: { break; } // // other, stop and figure out why we're here // default: { DNASSERT( FALSE ); hr = hTempResult; DPFX(DPFPREP, 0, "Failed to validate device address!" ); DisplayDNError( 0, hTempResult ); break; } } // // get endpoint for this connection // pEndpoint = pSPData->GetNewEndpoint(); if ( pEndpoint == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "DNMODEMSP_EnumQuery: Cannot create new endpoint!" ); goto Failure; } // // get new command // pCommand = (CModemCommandData*)g_ModemCommandDataPool.Get(); if ( pCommand == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "DNMODEMSP_EnumQuery: Cannot get command handle!" ); goto Failure; } // // initialize command // pEnumQueryData->hCommand = pCommand; pEnumQueryData->dwCommandDescriptor = pCommand->GetDescriptor(); pCommand->SetType( COMMAND_TYPE_ENUM_QUERY ); pCommand->SetState( COMMAND_STATE_INPROGRESS ); pCommand->SetEndpoint( pEndpoint ); // // open this endpoint // hTempResult = pEndpoint->Open( pEnumQueryData->pAddressHost, pEnumQueryData->pAddressDeviceInfo, LINK_DIRECTION_OUTGOING, ENDPOINT_TYPE_ENUM ); switch ( hTempResult ) { // // address was incomplete, display a dialog if we can, otherwise fail the command // case DPNERR_INCOMPLETEADDRESS: { #ifndef DPNBUILD_NOSPUI if ( ( pEnumQueryData->dwFlags & DPNSPF_OKTOQUERY ) != 0 ) { // // copy connect data for future reference and then start the dialog // fEndpointOpen = TRUE; pEndpoint->CopyEnumQueryData( pEnumQueryData ); hTempResult = pEndpoint->ShowOutgoingSettingsDialog( pSPData->GetThreadPool() ); if ( hTempResult != DPN_OK ) { hr = hTempResult; DPFX(DPFPREP, 0, "DNMODEMSP_EnumQuery: Problem showing settings dialog!" ); DisplayDNError( 0, hTempResult ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; DNASSERT( hr == DPNERR_PENDING ); goto Exit; } else #endif // !DPNBUILD_NOSPUI { hr = hTempResult; goto Failure; } break; } // // address conversion was fine, complete this command in the background // case DPN_OK: { // // copy connect data and the submit background job // fEndpointOpen = TRUE; pEndpoint->CopyEnumQueryData( pEnumQueryData ); pEndpoint->AddRef(); hTempResult = pSPData->GetThreadPool()->SubmitDelayedCommand( pEndpoint->EnumQueryJobCallback, pEndpoint->CancelEnumQueryJobCallback, pEndpoint ); if ( hTempResult != DPN_OK ) { pEndpoint->DecRef(); hr = hTempResult; DPFX(DPFPREP, 0, "DNMODEMSP_EnumQuery: Failed to submit delayed connect!" ); DisplayDNError( 0, hr ); goto Failure; } // // this endpoint has been handed off, remove our reference to it // pEndpoint = NULL; DNASSERT( hr == DPNERR_PENDING ); break; } default: { hr = hTempResult; DPFX(DPFPREP, 0, "DNMODEMSP_EnumQuery: Problem initializing endpoint!" ); DisplayDNError( 0, hTempResult ); goto Failure; break; } } Exit: DNASSERT( pEndpoint == NULL ); if ( hr != DPNERR_PENDING ) { DNASSERT( hr != DPN_OK ); DPFX(DPFPREP, 0, "Problem with DNMODEMSP_EnumQuery" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: if ( pEndpoint != NULL ) { if ( fEndpointOpen != FALSE ) { DNASSERT( ( hr != DPN_OK ) && ( hr != DPNERR_PENDING ) ); pEndpoint->Close( hr ); fEndpointOpen = FALSE; } DNASSERT( FALSE ); pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint = NULL; } // // return any outstanding command // if ( pCommand != NULL ) { pCommand->DecRef(); pCommand = NULL; pEnumQueryData->hCommand = NULL; pEnumQueryData->dwCommandDescriptor = NULL_DESCRIPTOR; } goto Exit; } //********************************************************************** //********************************************************************** /* * * DNMODEMSP_SendData sends data to the specified "player" * * This call MUST BE HIGHLY OPTIMIZED * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_SendData" STDMETHODIMP DNMODEMSP_SendData( IDP8ServiceProvider *pThis, SPSENDDATA *pSendData ) { HRESULT hr; CModemEndpoint *pEndpoint; CModemWriteIOData *pWriteData; CModemSPData *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 && pSendData->hEndpoint != 0 ); DNASSERT( pSendData->dwFlags == 0 ); // // initialize // hr = DPNERR_PENDING; pEndpoint = NULL; pSendData->hCommand = NULL; pSendData->dwCommandDescriptor = NULL_DESCRIPTOR; pWriteData = NULL; pSPData = CModemSPData::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( (DPNHANDLE)(DWORD_PTR)pSendData->hEndpoint ); if ( pEndpoint == NULL ) { hr = DPNERR_INVALIDHANDLE; DPFX(DPFPREP, 0, "Invalid endpoint handle on send!" ); goto Failure; } // // send data from pool // pWriteData = pSPData->GetThreadPool()->CreateWriteIOData(); 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->DataPort() == 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; 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; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_CancelCommand - cancels a command in progress // // Entry: Pointer to the service provider interface // Handle of command // Command descriptor // // Exit: Error Code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_CancelCommand" STDMETHODIMP DNMODEMSP_CancelCommand( IDP8ServiceProvider *pThis, HANDLE hCommand, DWORD dwCommandDescriptor ) { HRESULT hr; CModemSPData *pSPData; CModemCommandData *pCommandData; BOOL fReferenceAdded; BOOL fCommandLocked; 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; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); pCommandData = NULL; fReferenceAdded = FALSE; fCommandLocked = FALSE; // // vlidate state // pSPData->Lock(); switch ( pSPData->GetState() ) { // // provider initialized // case SPSTATE_INITIALIZED: { DNASSERT( hr == DPN_OK ); IDP8ServiceProvider_AddRef( pThis ); fReferenceAdded = TRUE; break; } // // provider is uninitialized // case SPSTATE_UNINITIALIZED: { hr = DPNERR_UNINITIALIZED; DPFX(DPFPREP, 0, "Disconnect called on uninitialized SP!" ); DNASSERT( FALSE ); goto Exit; break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "Disconnect called on closing SP!" ); DNASSERT( FALSE ); goto Exit; break; } // // unknown // default: { hr = DPNERR_GENERIC; DNASSERT( FALSE ); goto Exit; break; } } pSPData->Unlock(); if ( hr != DPN_OK ) { goto Exit; } pCommandData = static_cast( hCommand ); pCommandData->Lock(); fCommandLocked = TRUE; // // this should never happen // if ( pCommandData->GetDescriptor() != dwCommandDescriptor ) { hr = DPNERR_INVALIDCOMMAND; DPFX(DPFPREP, 0, "Attempt to cancel command with mismatched command descriptor!" ); 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: { pCommandData->SetState( COMMAND_STATE_CANCELLING ); break; } // // command in progress, and can't be cancelled // case COMMAND_STATE_INPROGRESS_CANNOT_CANCEL: { hr = DPNERR_CANNOTCANCEL; break; } // // Command is already being cancelled. This is not a problem, but shouldn't // be happening. // case COMMAND_STATE_CANCELLING: { DNASSERT( hr == DPN_OK ); DNASSERT( FALSE ); 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 in this state! DNASSERT( FALSE ); break; } case COMMAND_TYPE_CONNECT: { // we should never be in this state! DNASSERT( FALSE ); break; } case COMMAND_TYPE_LISTEN: { CModemEndpoint *pEndpoint; // // set this command to the cancel state before we shut down // this endpoint // pCommandData->SetState( COMMAND_STATE_CANCELLING ); pCommandData->Unlock(); fCommandLocked = FALSE; pEndpoint = pCommandData->GetEndpoint(); pEndpoint->Lock(); switch ( pEndpoint->GetState() ) { // // endpoint is already disconnecting, no action needs to be taken // case ENDPOINT_STATE_DISCONNECTING: { pEndpoint->Unlock(); goto Exit; break; } // // Endpoint is listening. Flag it as Disconnecting and // add a reference so it doesn't disappear on us // case ENDPOINT_STATE_LISTENING: { pEndpoint->SetState( ENDPOINT_STATE_DISCONNECTING ); pEndpoint->AddRef(); break; } // // other state // default: { DNASSERT( FALSE ); break; } } pEndpoint->Unlock(); pEndpoint->Close( DPNERR_USERCANCEL ); pSPData->CloseEndpointHandle( pEndpoint ); pEndpoint->DecRef(); break; } // // Note: this code is duplicated in CModemEndpoint::ProcessTAPIMessage // case COMMAND_TYPE_ENUM_QUERY: { CModemEndpoint *pEndpoint; pEndpoint = pCommandData->GetEndpoint(); DNASSERT( pEndpoint != NULL ); pEndpoint->AddRef(); pCommandData->SetState( COMMAND_STATE_CANCELLING ); pCommandData->Unlock(); fCommandLocked = FALSE; pEndpoint->Lock(); pEndpoint->SetState( ENDPOINT_STATE_DISCONNECTING ); pEndpoint->Unlock(); 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; } if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Problem with DNMODEMSP_CancelCommand!" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_EnumRespond - send response to enumeration data // // Entry: Pointer to the service provider interface // Pointer to enum response data // // Exit: Error Code // // Note: This command is supposed to be fast. All initial error checking // will be ASSERTs so they go away in the retail build. // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_EnumRespond" STDMETHODIMP DNMODEMSP_EnumRespond( IDP8ServiceProvider *pThis, SPENUMRESPONDDATA *pEnumRespondData ) { HRESULT hr; CModemEndpoint *pEndpoint; CModemWriteIOData *pWriteData; CModemSPData *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; pEndpoint = NULL; pWriteData = NULL; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); DBG_CASSERT( OFFSETOF( ENDPOINT_ENUM_QUERY_CONTEXT, EnumQueryData ) == 0 ); pEnumQueryContext = reinterpret_cast( pEnumRespondData->pQuery ); pEnumRespondData->hCommand = NULL; pEnumRespondData->dwCommandDescriptor = NULL_DESCRIPTOR; DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED ); IDP8ServiceProvider_AddRef( pThis ); // // check for valid endpoint // pEndpoint = pSPData->EndpointFromHandle( (DPNHANDLE)(DWORD_PTR)pEnumQueryContext->hEndpoint ); if ( pEndpoint == NULL ) { DNASSERT( FALSE ); hr = DPNERR_INVALIDENDPOINT; DPFX(DPFPREP, 8, "Invalid endpoint handle in DNMODEMSP_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. // pWriteData = pSPData->GetThreadPool()->CreateWriteIOData(); 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; pEnumRespondData->hCommand = pWriteData->m_pCommand; pEnumRespondData->dwCommandDescriptor = pWriteData->m_pCommand->GetDescriptor(); // // send data // pEndpoint->SendEnumResponseData( pWriteData, pEnumQueryContext->uEnumRTTIndex ); 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; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_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 "DNMODEMSP_IsApplicationSupported" STDMETHODIMP DNMODEMSP_IsApplicationSupported( IDP8ServiceProvider *pThis, SPISAPPLICATIONSUPPORTEDDATA *pIsApplicationSupportedData ) { HRESULT hr; BOOL fInterfaceReferenceAdded; CModemSPData *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 = CModemSPData::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, "IsApplicationSupported called on uninitialized SP!" ); break; } // // provider is closing // case SPSTATE_CLOSING: { hr = DPNERR_ABORTED; DPFX(DPFPREP, 0, "IsApplicationSupported 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; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_GetCaps - get SP or endpoint capabilities // // Entry: Pointer to DirectPlay // Pointer to caps data to fill // // Exit: Error Code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_GetCaps" STDMETHODIMP DNMODEMSP_GetCaps( IDP8ServiceProvider *pThis, SPGETCAPSDATA *pCapsData ) { HRESULT hr; LONG iIOThreadCount; CModemSPData *pSPData = NULL; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pCapsData); DNASSERT( pThis != NULL ); DNASSERT( pCapsData != NULL ); DNASSERT( pCapsData->dwSize == sizeof( *pCapsData ) ); DNASSERT( pCapsData->hEndpoint == INVALID_HANDLE_VALUE ); // // initialize // hr = DPN_OK; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); // // there are no flags for this SP // pCapsData->dwFlags = 0; // // set frame sizes // pCapsData->dwUserFrameSize = MAX_USER_PAYLOAD; pCapsData->dwEnumFrameSize = 1000; // // get link speed // if ( pCapsData->hEndpoint != INVALID_HANDLE_VALUE ) { // TODO: MASONB: I see no path where this is ever used CModemEndpoint *pEndpoint; pEndpoint = pSPData->EndpointFromHandle( (DPNHANDLE)(DWORD_PTR)pCapsData->hEndpoint ); if ( pEndpoint != NULL ) { pCapsData->dwLocalLinkSpeed = pEndpoint->GetLinkSpeed(); pEndpoint->DecCommandRef(); } else { hr = DPNERR_INVALIDENDPOINT; DPFX(DPFPREP, 0, "Invalid endpoint specified to GetCaps()" ); goto Failure; } } else { pCapsData->dwLocalLinkSpeed = CBR_256000; } // // get IO thread count // hr = pSPData->GetThreadPool()->GetIOThreadCount( &iIOThreadCount ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "DNMODEMSP_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; pCapsData->dwBuffersPerThread = 1; pCapsData->dwSystemBufferSize = 0; Exit: DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_SetCaps - set SP capabilities // // Entry: Pointer to DirectPlay // Pointer to caps data to use // // Exit: Error Code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_SetCaps" STDMETHODIMP DNMODEMSP_SetCaps( IDP8ServiceProvider *pThis, SPSETCAPSDATA *pCapsData ) { HRESULT hr; BOOL fInterfaceReferenceAdded; CModemSPData *pSPData; 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 = CModemSPData::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, if requested // if (pCapsData->dwIOThreadCount != 0) { hr = pSPData->GetThreadPool()->SetIOThreadCount( pCapsData->dwIOThreadCount ); if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "DNMODEMSP_SetCaps: Failed to set thread pool count!" ); DisplayDNError( 0, hr ); goto Failure; } } Exit: if ( fInterfaceReferenceAdded != FALSE ) { IDP8ServiceProvider_Release( pThis ); fInterfaceReferenceAdded = FALSE; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_ReturnReceiveBuffers - return receive buffers to pool // // Entry: Pointer to DNSP interface // Pointer to caps data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_ReturnReceiveBuffers" STDMETHODIMP DNMODEMSP_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; CModemReadIOData *pReadData; pTemp = pBuffers; pBuffers = pBuffers->pNext; pReadData = CModemReadIOData::ReadDataFromSPReceivedBuffer( pTemp ); pReadData->DecRef(); } DPFX(DPFPREP, 2, "Returning: [DPN_OK]"); return DPN_OK; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_GetAddressInfo - get address information // // Entry: Pointer to service provider interface // Pointer to get address data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_GetAddressInfo" STDMETHODIMP DNMODEMSP_GetAddressInfo( IDP8ServiceProvider *pThis, SPGETADDRESSINFODATA *pGetAddressInfoData ) { HRESULT hr; CModemSPData *pSPData; CModemEndpoint *pEndpoint; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pGetAddressInfoData); DNASSERT( pThis != NULL ); DNASSERT( pGetAddressInfoData != NULL ); DNASSERT( pGetAddressInfoData->hEndpoint != INVALID_HANDLE_VALUE && pGetAddressInfoData->hEndpoint != 0 ); 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; pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); pGetAddressInfoData->pAddress = NULL; pEndpoint = pSPData->EndpointFromHandle( (DPNHANDLE)(DWORD_PTR)pGetAddressInfoData->hEndpoint ); if ( pEndpoint != NULL ) { switch ( pGetAddressInfoData->Flags ) { case SP_GET_ADDRESS_INFO_REMOTE_HOST: { pGetAddressInfoData->pAddress = pEndpoint->GetRemoteHostDP8Address(); break; } // // there is no concept of a 'public' address for this service provider so // all local addresses are the same // case SP_GET_ADDRESS_INFO_LOCAL_ADAPTER: { pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( ADDRESS_TYPE_LOCAL_ADAPTER ); break; } case SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS: case SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES: { pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( ADDRESS_TYPE_LOCAL_ADAPTER_HOST_FORMAT ); break; } default: { DNASSERT( FALSE ); break; } } pEndpoint->DecCommandRef(); pEndpoint = NULL; } else { hr = DPNERR_INVALIDENDPOINT; } if ( hr != DPN_OK ) { DPFX(DPFPREP, 0, "Problem getting DP8Address from endpoint!" ); DisplayDNError( 0, hr ); } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; } //********************************************************************** //********************************************************************** // ------------------------------ // DNMODEMSP_EnumAdapters - enumerate adapters for this SP // // Entry: Pointer to service provider interface // Pointer to enum adapters data // // Exit: Error code // ------------------------------ #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_EnumAdapters" STDMETHODIMP DNMODEMSP_EnumAdapters( IDP8ServiceProvider *pThis, SPENUMADAPTERSDATA *pEnumAdaptersData ) { HRESULT hr; CDataPort *pDataPort; DATA_PORT_POOL_CONTEXT DataPortPoolContext; DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumAdaptersData); DNASSERT( pThis != NULL ); DNASSERT( pEnumAdaptersData->dwFlags == 0 ); DNASSERT( ( pEnumAdaptersData->pAdapterData != NULL ) || ( pEnumAdaptersData->dwAdapterDataSize == 0 ) ); // // intialize // hr = DPN_OK; pDataPort = NULL; pEnumAdaptersData->dwAdapterCount = 0; DataPortPoolContext.pSPData = CModemSPData::SPDataFromCOMInterface( pThis ); pDataPort = CreateDataPort( &DataPortPoolContext ); if ( pDataPort == NULL ) { hr = DPNERR_OUTOFMEMORY; DPFX(DPFPREP, 0, "Problem getting new dataport!" ); goto Failure; } hr = pDataPort->EnumAdapters( pEnumAdaptersData ); if ( hr != DPN_OK ) { if (hr != DPNERR_BUFFERTOOSMALL) { DPFX(DPFPREP, 0, "Problem enumerating adapters!" ); DisplayDNError( 0, hr ); } else { DPFX(DPFPREP, 1, "Buffer too small to enumerate adapters." ); } goto Failure; } Exit: if ( pDataPort != NULL ) { pDataPort->DecRef(); pDataPort = NULL; } DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr); return hr; Failure: goto Exit; } //********************************************************************** //********************************************************************** /* * * DNMODEMSP_NotSupported is used for methods required to implement the * interface but that are not supported by this SP. * */ //********************************************************************** #undef DPF_MODNAME #define DPF_MODNAME "DNMODEMSP_NotSupported" STDMETHODIMP DNMODEMSP_NotSupported( IDP8ServiceProvider *pThis, PVOID pvParam ) { DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pvParam); DPFX(DPFPREP, 2, "Returning: [DPNERR_UNSUPPORTED]"); return DPNERR_UNSUPPORTED; } //**********************************************************************