Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2618 lines
59 KiB

/*==========================================================================
*
* 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<CModemCommandData*>( 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<ENDPOINT_ENUM_QUERY_CONTEXT*>( 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;
}
//**********************************************************************