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

3128 lines
73 KiB
C++

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