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.
 
 
 
 
 
 

3810 lines
102 KiB

/*==========================================================================
*
* Copyright (C) 1998-2002 Microsoft Corporation. All Rights Reserved.
*
* File: WSockSP.cpp
* Content: Protocol-independent APIs for the DN Winsock SP
*
*
* History:
* Date By Reason
* ==== == ======
* 10/26/1998 jwo Created it.
* 11/1/1998 jwo Un-subclassed everything (moved it to this generic
* file from IP and IPX specific ones
* 03/22/2000 jtk Updated with changes to interface names
* 04/22/2000 mjn Allow all flags in DNSP_GetAddressInfo()
* 08/06/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
* 03/12/2001 mjn Prevent enum responses from being indicated up after completion
***************************************************************************/
#include "dnwsocki.h"
//**********************************************************************
// Constant definitions
//**********************************************************************
//
// maximum bandwidth in bits per second
//
#define UNKNOWN_BANDWIDTH 0
#define WAIT_FOR_CLOSE_TIMEOUT 30000 // milliseconds
#define ADDRESS_ENCODE_KEY 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;
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pData);
DNASSERT( pThis != NULL );
DNASSERT( pData != NULL );
//
// initialize
//
hr = DPN_OK;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
// Trust protocol to call us only in the uninitialized state
DNASSERT( pSPData->GetState() == SPSTATE_UNINITIALIZED );
//
// prevent anyone else from messing with this interface
//
pSPData->Lock();
hr = pSPData->Startup( pData );
if (hr != DPN_OK)
{
goto Failure;
}
pSPData->Unlock();
IDP8ServiceProvider_AddRef( pThis );
Exit:
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 );
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
pSPData->Shutdown();
IDP8ServiceProvider_Release( pThis );
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;
CEndpoint *pEndpoint;
CCommandData *pCommand;
BOOL fEndpointOpen;
CSPData *pSPData;
#ifndef DPNBUILD_NONATHELP
DWORD dwTraversalMode;
DWORD dwComponentSize;
DWORD dwComponentType;
#endif // ! DPNBUILD_NONATHELP
#ifdef DBG
DWORD dwAllowedFlags;
DWORD dwTotalBufferSize;
DWORD dwTemp;
#endif // DBG
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumQueryData);
DNASSERT( pThis != NULL );
DNASSERT( pEnumQueryData != NULL );
DNASSERT( pEnumQueryData->pAddressHost != NULL );
DNASSERT( pEnumQueryData->pAddressDeviceInfo != NULL );
#ifdef DBG
dwAllowedFlags = DPNSPF_NOBROADCASTFALLBACK | DPNSPF_SESSIONDATA;
#ifndef DPNBUILD_NOSPUI
dwAllowedFlags |= DPNSPF_OKTOQUERY;
#endif // ! DPNBUILD_NOSPUI
#ifndef DPNBUILD_ONLYONEADAPTER
dwAllowedFlags |= DPNSPF_ADDITIONALMULTIPLEXADAPTERS;
#endif // ! DPNBUILD_ONLYONEADAPTER
DNASSERT( ( pEnumQueryData->dwFlags & ~( dwAllowedFlags ) ) == 0 );
if ( pEnumQueryData->dwFlags & DPNSPF_SESSIONDATA )
{
DNASSERT( pEnumQueryData->pvSessionData!= NULL );
DNASSERT( pEnumQueryData->dwSessionDataSize > 0 );
}
#endif // DBG
DBG_CASSERT( sizeof( pEnumQueryData->dwRetryInterval ) == sizeof( DWORD ) );
#ifndef DPNBUILD_NOREGISTRY
//
// 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!" );
}
#endif // ! DPNBUILD_NOREGISTRY
//
// initialize
//
hr = DPNERR_PENDING;
pEndpoint = NULL;
pCommand = NULL;
fEndpointOpen = FALSE;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
DNASSERT( pSPData != NULL );
pEnumQueryData->hCommand = NULL;
pEnumQueryData->dwCommandDescriptor = NULL_DESCRIPTOR;
DumpAddress( 8, _T("Enum destination:"), pEnumQueryData->pAddressHost );
DumpAddress( 8, _T("Enuming on device:"), pEnumQueryData->pAddressDeviceInfo );
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// the user is attempting an operation that relies on the thread pool, lock
// it down to prevent threads from being lost. This also performs other
// first time initialization.
//
hr = pSPData->GetThreadPool()->PreventThreadPoolReduction();
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to prevent thread pool reduction!" );
goto Failure;
}
#ifdef DBG
//
// Make sure message is not too large.
//
dwTotalBufferSize = 0;
for(dwTemp = 0; dwTemp < pEnumQueryData->dwBufferCount; dwTemp++)
{
dwTotalBufferSize += pEnumQueryData->pBuffers[dwTemp].dwBufferSize;
}
#ifdef DPNBUILD_NOREGISTRY
DNASSERT(dwTotalBufferSize <= DEFAULT_MAX_ENUM_DATA_SIZE);
#else // ! DPNBUILD_NOREGISTRY
DNASSERT(dwTotalBufferSize <= g_dwMaxEnumDataSize);
#endif // ! DPNBUILD_NOREGISTRY
#endif // DBG
//
// create and new endpoint
//
pEndpoint = pSPData->GetNewEndpoint();
if ( pEndpoint == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Cannot create new endpoint in DNSP_EnumQuery!" );
goto Failure;
}
#ifndef DPNBUILD_NONATHELP
//
// We need to detect up front whether NAT traversal is disabled or not so we can optimize
// the Open call below.
//
dwComponentSize = sizeof(dwTraversalMode);
hr = IDirectPlay8Address_GetComponentByName(pEnumQueryData->pAddressDeviceInfo,
DPNA_KEY_TRAVERSALMODE,
&dwTraversalMode,
&dwComponentSize,
&dwComponentType);
if ( hr == DPN_OK )
{
//
// We found the component. Make sure it's the right size and type.
//
if ((dwComponentSize == sizeof(dwTraversalMode)) && (dwComponentType == DPNA_DATATYPE_DWORD))
{
switch (dwTraversalMode)
{
case DPNA_TRAVERSALMODE_NONE:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is NONE.");
break;
}
case DPNA_TRAVERSALMODE_PORTREQUIRED:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is PORTREQUIRED.");
break;
}
case DPNA_TRAVERSALMODE_PORTRECOMMENDED:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is PORTRECOMMENDED.");
break;
}
default:
{
DPFX(DPFPREP, 0, "Ignoring correctly formed traversal mode key with invalid value %u! Using default mode %u.",
dwTraversalMode, g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
break;
}
}
}
else
{
DPFX(DPFPREP, 0, "Traversal mode key exists, but doesn't match expected type (%u != %u) or size (%u != %u)! Using default mode %u.",
dwComponentSize, sizeof(dwTraversalMode),
dwComponentType, DPNA_DATATYPE_DWORD,
g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
}
}
else
{
//
// The key is not there, it's the wrong size (too big for our buffer
// and returned BUFFERTOOSMALL), or something else bad happened.
// It doesn't matter. Carry on.
//
DPFX(DPFPREP, 8, "Could not get traversal mode key, error = 0x%lx, component size = %u, type = %u, using default mode %u.",
hr, dwComponentSize, dwComponentType, g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
}
if (g_dwDefaultTraversalMode & FORCE_TRAVERSALMODE_BIT)
{
DPFX(DPFPREP, 1, "Forcing traversal mode %u.");
dwTraversalMode = g_dwDefaultTraversalMode & (~FORCE_TRAVERSALMODE_BIT);
}
pEndpoint->SetUserTraversalMode(dwTraversalMode);
#endif // ! DPNBUILD_NONATHELP
//
// get new command and initialize it
//
pCommand = (CCommandData*)g_CommandDataPool.Get();
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,
((pEnumQueryData->dwFlags & DPNSPF_SESSIONDATA) ? pEnumQueryData->pvSessionData: NULL),
((pEnumQueryData->dwFlags & DPNSPF_SESSIONDATA) ? pEnumQueryData->dwSessionDataSize : 0),
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:
{
#ifndef DPNBUILD_NOSPUI
if ( ( ( pEnumQueryData->dwFlags & DPNSPF_OKTOQUERY ) != 0 )
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
#ifdef DPNBUILD_NOIPV6
&& (( pSPData->GetType() == AF_INET6 ) || ( pSPData->GetType() == AF_INET ))
#else // ! DPNBUILD_NOIPV6
&& ( pSPData->GetType() == AF_INET )
#endif // ! DPNBUILD_NOIPV6
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
)
{
//
// 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;
}
#endif // !DPNBUILD_NOSPUI
if ( pEnumQueryData->dwFlags & DPNSPF_NOBROADCASTFALLBACK )
{
goto Failure;
}
//
// we're OK, we can use the broadcast address.
//
#if ((! defined(DPNBUILD_NONATHELP)) && (! defined(DPNBUILD_ONLYONETHREAD)))
//
// If NAT traversal is allowed, we may need to load and start
// NAT Help, which can block. Submit a blocking job. This
// will redetect the incomplete address and use broadcast (see
// CEndpoint::EnumQueryBlockingJob).
//
if ( pEndpoint->GetUserTraversalMode() != DPNA_TRAVERSALMODE_NONE )
{
goto SubmitBlockingJob;
}
#endif // ! DPNBUILD_NONATHELP and ! DPNBUILD_ONLYONETHREAD
//
// Mash in the broadcast address, but actually complete the
// enum on another thread.
//
pEndpoint->ReinitializeWithBroadcast();
goto SubmitDelayedCommand;
break;
}
#ifndef DPNBUILD_ONLYONETHREAD
//
// some blocking operation might occur, submit it to be run
// on a background thread.
//
case DPNERR_TIMEDOUT:
{
SubmitBlockingJob:
//
// 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 blocking job!" );
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()->SubmitBlockingJob( CEndpoint::EnumQueryBlockingJobWrapper,
pEndpoint );
if ( hr != DPN_OK )
{
pEndpoint->DecRef();
DPFX(DPFPREP, 0, "Failed to submit blocking enum query job!" );
DisplayDNError( 0, hr );
goto Failure;
}
//
// this endpoint has been handed off, remove our reference
//
pEndpoint = NULL;
hr = DPNERR_PENDING;
goto Exit;
}
#endif // ! DPNBUILD_ONLYONETHREAD
//
// 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();
#ifdef DPNBUILD_ONLYONEPROCESSOR
hr = pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::EnumQueryJobCallback,
pEndpoint );
#else // ! DPNBUILD_ONLYONEPROCESSOR
hr = pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
CEndpoint::EnumQueryJobCallback,
pEndpoint );
#endif // ! DPNBUILD_ONLYONEPROCESSOR
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;
}
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;
CSPData *pSPData;
const ENDPOINT_ENUM_QUERY_CONTEXT *pEnumQueryContext;
PREPEND_BUFFER PrependBuffer;
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumRespondData);
DNASSERT( pThis != NULL );
DNASSERT( pEnumRespondData != NULL );
DNASSERT( pEnumRespondData->dwFlags == 0 );
//
// initialize
//
DBG_CASSERT( OFFSETOF( ENDPOINT_ENUM_QUERY_CONTEXT, EnumQueryData ) == 0 );
pEnumQueryContext = reinterpret_cast<ENDPOINT_ENUM_QUERY_CONTEXT*>( pEnumRespondData->pQuery );
pEndpoint = NULL;
pEnumRespondData->hCommand = NULL;
pEnumRespondData->dwCommandDescriptor = NULL_DESCRIPTOR;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// 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.
//
DNASSERT( pEnumQueryContext->dwEnumKey <= WORD_MAX );
pEnumRespondData->pBuffers[-1].pBufferData = reinterpret_cast<BYTE*>( &PrependBuffer.EnumResponseDataHeader );
pEnumRespondData->pBuffers[-1].dwBufferSize = sizeof( PrependBuffer.EnumResponseDataHeader );
PrependBuffer.EnumResponseDataHeader.bSPLeadByte = SP_HEADER_LEAD_BYTE;
PrependBuffer.EnumResponseDataHeader.bSPCommandByte = ENUM_RESPONSE_DATA_KIND;
PrependBuffer.EnumResponseDataHeader.wEnumResponsePayload = static_cast<WORD>( pEnumQueryContext->dwEnumKey );
#ifdef DPNBUILD_XNETSECURITY
//
// Secure transport does not allow directed replies without having a
// security context established. We need to broadcast the reply.
//
if (pEndpoint->IsUsingXNetSecurity())
{
SOCKADDR_IN * psaddrin;
XNADDR xnaddr;
DWORD dwAddressType;
#pragma BUGBUG(vanceo, "Is it possible to have a security context? How can we tell? XNetInAddrToXnAddr failing?")
#pragma TODO(vanceo, "Cache title address?")
dwAddressType = XNetGetTitleXnAddr(&xnaddr);
if ((dwAddressType != XNET_GET_XNADDR_PENDING) &&
(dwAddressType != XNET_GET_XNADDR_NONE))
{
DNASSERT(pEnumQueryContext->pReturnAddress->GetFamily() == AF_INET);
psaddrin = (SOCKADDR_IN*) (pEnumQueryContext->pReturnAddress->GetWritableAddress());
psaddrin->sin_addr.S_un.S_addr = INADDR_BROADCAST;
pEnumRespondData->pBuffers[-1].dwBufferSize = sizeof( PrependBuffer.XNetSecEnumResponseDataHeader );
PrependBuffer.EnumResponseDataHeader.bSPCommandByte = XNETSEC_ENUM_RESPONSE_DATA_KIND;
memcpy(&PrependBuffer.XNetSecEnumResponseDataHeader.xnaddr,
&xnaddr,
sizeof(xnaddr));
}
else
{
DPFX(DPFPREP, 0, "Couldn't get XNAddr (type = %u)! Ignoring and trying to send unsecure response.",
dwAddressType);
}
}
#endif // DPNBUILD_XNETSECURITY
#ifdef DPNBUILD_ASYNCSPSENDS
pEndpoint->GetSocketPort()->SendData( (pEnumRespondData->pBuffers - 1),
(pEnumRespondData->dwBufferCount + 1),
pEnumQueryContext->pReturnAddress,
NULL );
#else // ! DPNBUILD_ASYNCSPSENDS
pEndpoint->GetSocketPort()->SendData( (pEnumRespondData->pBuffers - 1),
(pEnumRespondData->dwBufferCount + 1),
pEnumQueryContext->pReturnAddress );
#endif // ! DPNBUILD_ASYNCSPSENDS
// We can only return DPNERR_PENDING or failure, so we need to separately call the completion if
// we want to return DPN_OK.
DPFX(DPFPREP, 5, "Endpoint 0x%p completing command synchronously (result = DPN_OK, user context = 0x%p) to interface 0x%p.",
pEndpoint, pEnumRespondData->pvContext, pSPData->DP8SPCallbackInterface());
hr = IDP8SPCallback_CommandComplete( pSPData->DP8SPCallbackInterface(), // pointer to callbacks
NULL, // command handle
DPN_OK, // return
pEnumRespondData->pvContext // user cookie
);
DPFX(DPFPREP, 5, "Endpoint 0x%p returning from command complete [0x%lx].", pEndpoint, hr);
hr = DPNERR_PENDING;
pEndpoint->DecCommandRef();
pEndpoint = NULL;
Exit:
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
Failure:
if ( pEndpoint != NULL )
{
pEndpoint->DecCommandRef();
pEndpoint = 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;
CEndpoint *pEndpoint;
CCommandData *pCommand;
BOOL fEndpointOpen;
CSPData *pSPData;
#ifndef DPNBUILD_NONATHELP
DWORD dwTraversalMode;
DWORD dwComponentSize;
DWORD dwComponentType;
#endif // ! DPNBUILD_NONATHELP
#ifdef DBG
DWORD dwAllowedFlags;
#endif // DBG
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pConnectData);
DNASSERT( pThis != NULL );
DNASSERT( pConnectData != NULL );
DNASSERT( pConnectData->pAddressHost != NULL );
DNASSERT( pConnectData->pAddressDeviceInfo != NULL );
#ifdef DBG
dwAllowedFlags = DPNSPF_SESSIONDATA;
#ifndef DPNBUILD_NOSPUI
dwAllowedFlags |= DPNSPF_OKTOQUERY;
#endif // ! DPNBUILD_NOSPUI
#ifndef DPNBUILD_ONLYONEADAPTER
dwAllowedFlags |= DPNSPF_ADDITIONALMULTIPLEXADAPTERS;
#endif // ! DPNBUILD_ONLYONEADAPTER
#ifndef DPNBUILD_NOMULTICAST
dwAllowedFlags |= DPNSPF_CONNECT_MULTICAST_SEND | DPNSPF_CONNECT_MULTICAST_RECEIVE;
#endif // ! DPNBUILD_NOMULTICAST
DNASSERT( ( pConnectData->dwFlags & ~( dwAllowedFlags ) ) == 0 );
#ifndef DPNBUILD_NOMULTICAST
DNASSERT( !( ( pConnectData->dwFlags & DPNSPF_CONNECT_MULTICAST_SEND ) && ( pConnectData->dwFlags & DPNSPF_CONNECT_MULTICAST_RECEIVE ) ) );
#endif // ! DPNBUILD_NOMULTICAST
if ( pConnectData->dwFlags & DPNSPF_SESSIONDATA )
{
DNASSERT( pConnectData->pvSessionData != NULL );
DNASSERT( pConnectData->dwSessionDataSize > 0 );
}
#endif // DBG
//
// initialize
//
hr = DPNERR_PENDING;
pEndpoint = NULL;
pCommand = NULL;
fEndpointOpen = FALSE;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
pConnectData->hCommand = NULL;
pConnectData->dwCommandDescriptor = NULL_DESCRIPTOR;
// Trust protocol to call us only in the initialized state
DNASSERT(pSPData->GetState() == SPSTATE_INITIALIZED);
DumpAddress( 8, _T("Connect destination:"), pConnectData->pAddressHost );
DumpAddress( 8, _T("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. This also performs other
// first time initialization.
//
hr = pSPData->GetThreadPool()->PreventThreadPoolReduction();
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to prevent thread pool reduction!" );
goto Failure;
}
//
// create and new endpoint
//
pEndpoint = pSPData->GetNewEndpoint();
if ( pEndpoint == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Cannot create new endpoint in DNSP_Connect!" );
goto Failure;
}
#ifndef DPNBUILD_NONATHELP
//
// We need to detect up front whether NAT traversal is disabled or not so we can optimize
// the Open call below.
//
dwComponentSize = sizeof(dwTraversalMode);
hr = IDirectPlay8Address_GetComponentByName(pConnectData->pAddressDeviceInfo,
DPNA_KEY_TRAVERSALMODE,
&dwTraversalMode,
&dwComponentSize,
&dwComponentType);
if ( hr == DPN_OK )
{
//
// We found the component. Make sure it's the right size and type.
//
if ((dwComponentSize == sizeof(dwTraversalMode)) && (dwComponentType == DPNA_DATATYPE_DWORD))
{
switch (dwTraversalMode)
{
case DPNA_TRAVERSALMODE_NONE:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is NONE.");
break;
}
case DPNA_TRAVERSALMODE_PORTREQUIRED:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is PORTREQUIRED.");
break;
}
case DPNA_TRAVERSALMODE_PORTRECOMMENDED:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is PORTRECOMMENDED.");
break;
}
default:
{
DPFX(DPFPREP, 0, "Ignoring correctly formed traversal mode key with invalid value %u! Using default mode %u.",
dwTraversalMode, g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
break;
}
}
}
else
{
DPFX(DPFPREP, 0, "Traversal mode key exists, but doesn't match expected type (%u != %u) or size (%u != %u)! Using default mode %u.",
dwComponentSize, sizeof(dwTraversalMode),
dwComponentType, DPNA_DATATYPE_DWORD,
g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
}
}
else
{
//
// The key is not there, it's the wrong size (too big for our buffer
// and returned BUFFERTOOSMALL), or something else bad happened.
// It doesn't matter. Carry on.
//
DPFX(DPFPREP, 8, "Could not get traversal mode key, error = 0x%lx, component size = %u, type = %u, using default mode %u.",
hr, dwComponentSize, dwComponentType, g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
}
if (g_dwDefaultTraversalMode & FORCE_TRAVERSALMODE_BIT)
{
DPFX(DPFPREP, 1, "Forcing traversal mode %u.");
dwTraversalMode = g_dwDefaultTraversalMode & (~FORCE_TRAVERSALMODE_BIT);
}
pEndpoint->SetUserTraversalMode(dwTraversalMode);
#endif // ! DPNBUILD_NONATHELP
//
// get new command and initialize it
//
pCommand = (CCommandData*)g_CommandDataPool.Get();
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();
#ifndef DPNBUILD_NOMULTICAST
if ( pConnectData->dwFlags & DPNSPF_CONNECT_MULTICAST_SEND )
{
pCommand->SetType( COMMAND_TYPE_MULTICAST_SEND );
}
else if ( pConnectData->dwFlags & DPNSPF_CONNECT_MULTICAST_RECEIVE )
{
pCommand->SetType( COMMAND_TYPE_MULTICAST_RECEIVE );
}
else
#endif // ! DPNBUILD_NOMULTICAST
{
pCommand->SetType( COMMAND_TYPE_CONNECT );
}
pCommand->SetState( COMMAND_STATE_PENDING );
pCommand->SetEndpoint( pEndpoint );
//
// open endpoint with outgoing address
//
fEndpointOpen = TRUE;
#ifndef DPNBUILD_NOMULTICAST
if ( pConnectData->dwFlags & DPNSPF_CONNECT_MULTICAST_SEND )
{
hr = pEndpoint->Open( ENDPOINT_TYPE_MULTICAST_SEND,
pConnectData->pAddressHost,
((pConnectData->dwFlags & DPNSPF_SESSIONDATA) ? pConnectData->pvSessionData : NULL),
((pConnectData->dwFlags & DPNSPF_SESSIONDATA) ? pConnectData->dwSessionDataSize : 0),
NULL );
}
else if ( pConnectData->dwFlags & DPNSPF_CONNECT_MULTICAST_RECEIVE )
{
hr = pEndpoint->Open( ENDPOINT_TYPE_MULTICAST_RECEIVE,
pConnectData->pAddressHost,
((pConnectData->dwFlags & DPNSPF_SESSIONDATA) ? pConnectData->pvSessionData : NULL),
((pConnectData->dwFlags & DPNSPF_SESSIONDATA) ? pConnectData->dwSessionDataSize : 0),
NULL );
}
else
#endif // ! DPNBUILD_NOMULTICAST
{
hr = pEndpoint->Open( ENDPOINT_TYPE_CONNECT,
pConnectData->pAddressHost,
((pConnectData->dwFlags & DPNSPF_SESSIONDATA) ? pConnectData->pvSessionData : NULL),
((pConnectData->dwFlags & DPNSPF_SESSIONDATA) ? pConnectData->dwSessionDataSize : 0),
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.
//
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();
#ifdef DPNBUILD_ONLYONEPROCESSOR
hr = pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::ConnectJobCallback,
pEndpoint );
#else // ! DPNBUILD_ONLYONEPROCESSOR
hr = pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
CEndpoint::ConnectJobCallback,
pEndpoint );
#endif // ! DPNBUILD_ONLYONEPROCESSOR
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:
{
#ifndef DPNBUILD_NOSPUI
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
#endif // !DPNBUILD_NOSPUI
{
goto Failure;
}
break;
}
#ifndef DPNBUILD_ONLYONETHREAD
//
// some blocking operation might occur, submit it to be run
// on a background thread.
//
case DPNERR_TIMEDOUT:
{
//
// Copy connect data and submit job to finish off enum.
//
DNASSERT( pSPData != NULL );
hr = pEndpoint->CopyConnectData( pConnectData );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to copy connect data before blocking job!" );
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()->SubmitBlockingJob( CEndpoint::ConnectBlockingJobWrapper,
pEndpoint );
if ( hr != DPN_OK )
{
pEndpoint->DecRef();
DPFX(DPFPREP, 0, "Failed to submit blocking connect job!" );
DisplayDNError( 0, hr );
goto Failure;
}
//
// this endpoint has been handed off, remove our reference
//
pEndpoint = NULL;
hr = DPNERR_PENDING;
goto Exit;
}
#endif // ! DPNBUILD_ONLYONETHREAD
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;
}
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 && pDisconnectData->hEndpoint != 0 );
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.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// 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();
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;
CEndpoint *pEndpoint;
CCommandData *pCommand;
IDirectPlay8Address *pDeviceAddress;
BOOL fEndpointOpen;
CSPData *pSPData;
#ifndef DPNBUILD_NONATHELP
DWORD dwTraversalMode;
DWORD dwComponentSize;
DWORD dwComponentType;
#endif // ! DPNBUILD_NONATHELP
#ifdef DBG
DWORD dwAllowedFlags;
#endif // DBG
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pListenData);
DNASSERT( pThis != NULL );
DNASSERT( pListenData != NULL );
#ifdef DBG
dwAllowedFlags = DPNSPF_BINDLISTENTOGATEWAY | DPNSPF_LISTEN_DISALLOWENUMS | DPNSPF_SESSIONDATA;
#ifndef DPNBUILD_NOSPUI
dwAllowedFlags |= DPNSPF_OKTOQUERY;
#endif // ! DPNBUILD_NOSPUI
#ifndef DPNBUILD_NOMULTICAST
dwAllowedFlags |= DPNSPF_LISTEN_MULTICAST | DPNSPF_LISTEN_ALLOWUNKNOWNSENDERS;
#endif // ! DPNBUILD_NOMULTICAST
DNASSERT( ( pListenData->dwFlags & ~( dwAllowedFlags ) ) == 0 );
if ( pListenData->dwFlags & DPNSPF_SESSIONDATA )
{
DNASSERT( pListenData->pvSessionData!= NULL );
DNASSERT( pListenData->dwSessionDataSize > 0 );
}
#endif // DBG
//
// initialize
//
hr = DPNERR_PENDING;
pEndpoint = NULL;
pCommand = NULL;
pDeviceAddress = NULL;
fEndpointOpen = FALSE;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
pListenData->hCommand = NULL;
pListenData->dwCommandDescriptor = NULL_DESCRIPTOR;
DumpAddress( 8, _T("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. This also performs other
// first time initialization.
//
hr = pSPData->GetThreadPool()->PreventThreadPoolReduction();
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to prevent thread pool reduction!" );
goto Failure;
}
//
// AddRef the device address.
//
IDirectPlay8Address_AddRef(pListenData->pAddressDeviceInfo);
pDeviceAddress = pListenData->pAddressDeviceInfo;
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// create and new endpoint
//
pEndpoint = pSPData->GetNewEndpoint();
if ( pEndpoint == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Cannot create new endpoint in DNSP_Listen!" );
goto Failure;
}
#ifndef DPNBUILD_NONATHELP
//
// We need to detect up front whether NAT traversal is disabled or not so we can optimize
// the Open call below.
//
dwComponentSize = sizeof(dwTraversalMode);
hr = IDirectPlay8Address_GetComponentByName(pListenData->pAddressDeviceInfo,
DPNA_KEY_TRAVERSALMODE,
&dwTraversalMode,
&dwComponentSize,
&dwComponentType);
if ( hr == DPN_OK )
{
//
// We found the component. Make sure it's the right size and type.
//
if ((dwComponentSize == sizeof(dwTraversalMode)) && (dwComponentType == DPNA_DATATYPE_DWORD))
{
switch (dwTraversalMode)
{
case DPNA_TRAVERSALMODE_NONE:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is NONE.");
break;
}
case DPNA_TRAVERSALMODE_PORTREQUIRED:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is PORTREQUIRED.");
break;
}
case DPNA_TRAVERSALMODE_PORTRECOMMENDED:
{
DPFX(DPFPREP, 1, "Found traversal mode key, value is PORTRECOMMENDED.");
break;
}
default:
{
DPFX(DPFPREP, 0, "Ignoring correctly formed traversal mode key with invalid value %u! Using PORTRECOMMENDED.",
dwTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
break;
}
}
}
else
{
DPFX(DPFPREP, 0, "Traversal mode key exists, but doesn't match expected type (%u != %u) or size (%u != %u)! Using default mode %u.",
dwComponentSize, sizeof(dwTraversalMode),
dwComponentType, DPNA_DATATYPE_DWORD,
g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
}
}
else
{
//
// The key is not there, it's the wrong size (too big for our buffer
// and returned BUFFERTOOSMALL), or something else bad happened.
// It doesn't matter. Carry on.
//
DPFX(DPFPREP, 8, "Could not get traversal mode key, error = 0x%lx, component size = %u, type = %u, using default mode %u.",
hr, dwComponentSize, dwComponentType, g_dwDefaultTraversalMode);
dwTraversalMode = g_dwDefaultTraversalMode;
}
if (g_dwDefaultTraversalMode & FORCE_TRAVERSALMODE_BIT)
{
DPFX(DPFPREP, 1, "Forcing traversal mode %u.");
dwTraversalMode = g_dwDefaultTraversalMode & (~FORCE_TRAVERSALMODE_BIT);
}
pEndpoint->SetUserTraversalMode(dwTraversalMode);
#endif // ! DPNBUILD_NONATHELP
//
// get new command and initialize it
//
pCommand = (CCommandData*)g_CommandDataPool.Get();
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();
#ifndef DPNBUILD_NOMULTICAST
if (pListenData->dwFlags & DPNSPF_LISTEN_MULTICAST)
{
pCommand->SetType( COMMAND_TYPE_MULTICAST_LISTEN );
}
else
#endif // ! DPNBUILD_NOMULTICAST
{
pCommand->SetType( COMMAND_TYPE_LISTEN );
}
pCommand->SetState( COMMAND_STATE_PENDING );
pCommand->SetEndpoint( pEndpoint );
pCommand->SetUserContext( pListenData->pvContext );
//
// open endpoint with outgoing address
//
fEndpointOpen = TRUE;
#ifndef DPNBUILD_NOMULTICAST
if (pListenData->dwFlags & DPNSPF_LISTEN_MULTICAST)
{
//
// The device address should also contain the multicast address to be joined.
//
hr = pEndpoint->Open( ENDPOINT_TYPE_MULTICAST_LISTEN,
pDeviceAddress,
((pListenData->dwFlags & DPNSPF_SESSIONDATA) ? pListenData->pvSessionData : NULL),
((pListenData->dwFlags & DPNSPF_SESSIONDATA) ? pListenData->dwSessionDataSize : 0),
NULL );
}
else
#endif // ! DPNBUILD_NOMULTICAST
{
hr = pEndpoint->Open( ENDPOINT_TYPE_LISTEN,
NULL,
((pListenData->dwFlags & DPNSPF_SESSIONDATA) ? pListenData->pvSessionData : NULL),
((pListenData->dwFlags & DPNSPF_SESSIONDATA) ? pListenData->dwSessionDataSize : 0),
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();
#ifdef DPNBUILD_ONLYONEPROCESSOR
hr = pSPData->GetThreadPool()->SubmitDelayedCommand( CEndpoint::ListenJobCallback,
pEndpoint );
#else // ! DPNBUILD_ONLYONEPROCESSOR
hr = pSPData->GetThreadPool()->SubmitDelayedCommand( -1, // we don't know the CPU yet, so pick any
CEndpoint::ListenJobCallback,
pEndpoint );
#endif // ! DPNBUILD_ONLYONEPROCESSOR
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:
{
//
// This SP will never encounter the case where there's not enough
// information to start listening. Either the adapter GUID is there
// or not, and we won't know until CEndpoint::CompleteListen.
//
DNASSERT( FALSE );
#ifndef DPNBUILD_NOSPUI
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
#endif // !DPNBUILD_NOSPUI
{
goto Failure;
}
break;
}
#ifndef DPNBUILD_ONLYONETHREAD
//
// some blocking operation might occur, submit it to be run
// on a background thread.
//
case DPNERR_TIMEDOUT:
{
//
// Copy listen data and submit job to finish off enum.
//
DNASSERT( pSPData != NULL );
hr = pEndpoint->CopyListenData( pListenData, pDeviceAddress );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to copy listen data before blocking job!" );
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()->SubmitBlockingJob( CEndpoint::ListenBlockingJobWrapper,
pEndpoint );
if ( hr != DPN_OK )
{
pEndpoint->DecRef();
DPFX(DPFPREP, 0, "Failed to submit blocking listen job!" );
DisplayDNError( 0, hr );
goto Failure;
}
//
// this endpoint has been handed off, remove our reference
//
pEndpoint = NULL;
hr = DPNERR_PENDING;
goto Exit;
}
#endif // ! DPNBUILD_ONLYONETHREAD
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;
}
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;
CSPData *pSPData;
#ifdef DPNBUILD_ASYNCSPSENDS
CCommandData * pCommand = NULL;
OVERLAPPED * pOverlapped;
#endif // DPNBUILD_ASYNCSPSENDS
#ifdef DBG
DWORD dwTotalBufferSize;
DWORD dwTemp;
#endif // DBG
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
//
pEndpoint = NULL;
pSendData->hCommand = NULL;
pSendData->dwCommandDescriptor = NULL_DESCRIPTOR;
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;
}
#ifdef DBG
//
// Make sure message is not too large.
//
dwTotalBufferSize = 0;
for(dwTemp = 0; dwTemp < pSendData->dwBufferCount; dwTemp++)
{
dwTotalBufferSize += pSendData->pBuffers[dwTemp].dwBufferSize;
}
#pragma TODO(vanceo, "No direct way for application to retrieve, they think max is g_dwMaxEnumDataSize")
#ifdef DPNBUILD_NOREGISTRY
DNASSERT(dwTotalBufferSize <= DEFAULT_MAX_USER_DATA_SIZE);
#else // ! DPNBUILD_NOREGISTRY
DNASSERT(dwTotalBufferSize <= g_dwMaxUserDataSize);
#endif // ! DPNBUILD_NOREGISTRY
// Protocol guarantees that the first byte will never be zero
DNASSERT(pSendData->pBuffers[ 0 ].pBufferData[ 0 ] != SP_HEADER_LEAD_BYTE);
#endif // DBG
//
// Assume user data. There's no need to prepend a buffer because the
// receiving machine will realize that it's not a 'special' message and
// will default the contents to 'user data'.
//
#ifdef DPNBUILD_ASYNCSPSENDS
#ifdef DPNBUILD_NOWINSOCK2
This won't compile because we need the Winsock2 API to perform overlapped sends
#endif // DPNBUILD_NOWINSOCK2
#ifndef DPNBUILD_ONLYWINSOCK2
DNASSERT(pEndpoint->GetSocketPort() != NULL);
DNASSERT(pEndpoint->GetSocketPort()->GetNetworkAddress() != NULL);
if ( ( LOWORD( GetWinsockVersion() ) < 2 )
#ifndef DPNBUILD_NOIPX
|| ( pEndpoint->GetSocketPort()->GetNetworkAddress()->GetFamily() != AF_INET )
#endif // ! DPNBUILD_NOIPX
)
{
//
// We can't perform overlapped sends on Winsock < 2 or on 9x IPX.
//
pEndpoint->GetSocketPort()->SendData( pSendData->pBuffers,
pSendData->dwBufferCount,
pEndpoint->GetRemoteAddressPointer(),
NULL );
hr = DPN_OK;
pEndpoint->DecCommandRef();
}
else
#endif // ! DPNBUILD_ONLYWINSOCK2
{
//
// get new command and initialize it
//
pCommand = (CCommandData*)g_CommandDataPool.Get();
if ( pCommand == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Cannot get command handle!" );
goto Failure;
}
DPFX(DPFPREP, 8, "(0x%p) Send command 0x%p created.",
pSPData, pCommand);
pSendData->hCommand = pCommand;
pSendData->dwCommandDescriptor = pCommand->GetDescriptor();
pCommand->SetType( COMMAND_TYPE_SEND );
pCommand->SetState( COMMAND_STATE_INPROGRESS_CANNOT_CANCEL ); // can't cancel async sends
pCommand->SetEndpoint( pEndpoint );
pCommand->SetUserContext( pSendData->pvContext );
#ifdef DPNBUILD_ONLYONEPROCESSOR
hr = IDirectPlay8ThreadPoolWork_CreateOverlapped(pSPData->GetThreadPool()->GetDPThreadPoolWork(),
-1,
CEndpoint::CompleteAsyncSend,
pCommand,
&pOverlapped,
0);
#else // ! DPNBUILD_ONLYONEPROCESSOR
hr = IDirectPlay8ThreadPoolWork_CreateOverlapped(pSPData->GetThreadPool()->GetDPThreadPoolWork(),
pEndpoint->GetSocketPort()->GetCPU(),
CEndpoint::CompleteAsyncSend,
pCommand,
&pOverlapped,
0);
#endif // ! DPNBUILD_ONLYONEPROCESSOR
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't create overlapped structure!");
goto Failure;
}
pEndpoint->GetSocketPort()->SendData( pSendData->pBuffers,
pSendData->dwBufferCount,
pEndpoint->GetRemoteAddressPointer(),
pOverlapped );
//
// Whether the submission to Winsock succeeds or fails, it should still
// fill out the overlapped structure, so we will just let the async
// completion handler do everything.
//
hr = IDirectPlay8ThreadPoolWork_SubmitIoOperation(pSPData->GetThreadPool()->GetDPThreadPoolWork(),
pOverlapped,
0);
DNASSERT(hr == DPN_OK);
//
// Keep endpoint's command ref on send until send completes.
//
hr = DPNSUCCESS_PENDING;
}
#else // ! DPNBUILD_ASYNCSPSENDS
pEndpoint->GetSocketPort()->SendData( pSendData->pBuffers,
pSendData->dwBufferCount,
pEndpoint->GetRemoteAddressPointer() );
hr = DPN_OK;
pEndpoint->DecCommandRef();
#endif // ! DPNBUILD_ASYNCSPSENDS
pEndpoint = NULL;
Exit:
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
Failure:
#ifdef DPNBUILD_ASYNCSPSENDS
//
// if there's an allocated command, clean up and then
// return the command
//
if ( pCommand != NULL )
{
pCommand->DecRef();
pCommand = NULL;
pSendData->hCommand = NULL;
pSendData->dwCommandDescriptor = NULL_DESCRIPTOR;
}
#endif // DPNBUILD_ASYNCSPSENDS
if ( pEndpoint != NULL )
{
pEndpoint->DecCommandRef();
pEndpoint = 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;
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;
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.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
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:
{
DPFX(DPFPREP, 1, "Cancelled already cancelling command 0x%p.", pCommandData);
DNASSERT( pCommandData->GetEndpoint()->GetType() == ENDPOINT_TYPE_CONNECT );
DNASSERT( hr == DPN_OK );
break;
}
#ifndef DPNBUILD_ONLYONETHREAD
//
// A blocking operation is already failing, let it complete.
//
case COMMAND_STATE_FAILING:
{
DPFX(DPFPREP, 1, "Cancelled already failing command 0x%p.", pCommandData);
DNASSERT( hr == DPN_OK );
break;
}
#endif // ! DPNBUILD_ONLYONETHREAD
//
// command is in progress, find out what type of command it is
//
case COMMAND_STATE_INPROGRESS:
{
switch ( pCommandData->GetType() )
{
case COMMAND_TYPE_CONNECT:
case COMMAND_TYPE_LISTEN:
#ifndef DPNBUILD_NOMULTICAST
case COMMAND_TYPE_MULTICAST_LISTEN:
case COMMAND_TYPE_MULTICAST_SEND:
case COMMAND_TYPE_MULTICAST_RECEIVE:
#endif // ! DPNBUILD_NOMULTICAST
{
//
// 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 connect/listen/multicast command 0x%p (endpoint 0x%p).",
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:
{
DPFX(DPFPREP, 7, "Endpoint 0x%p already marked as disconnecting.",
pEndpoint);
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:
{
DPFX(DPFPREP, 7, "Endpoint 0x%p attempting to connect, marking as disconnecting.",
pEndpoint);
#ifdef DPNBUILD_NOMULTICAST
DNASSERT(pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT);
#else // ! DPNBUILD_NOMULTICAST
DNASSERT((pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT) || (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND) || (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_RECEIVE));
#endif // ! DPNBUILD_NOMULTICAST
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:
{
#ifdef DPNBUILD_NOMULTICAST
DNASSERT(pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT);
#else // ! DPNBUILD_NOMULTICAST
DNASSERT((pEndpoint->GetType() == ENDPOINT_TYPE_CONNECT) || (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_SEND) || (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_RECEIVE));
#endif // ! DPNBUILD_NOMULTICAST
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:
{
DPFX(DPFPREP, 7, "Endpoint 0x%p listening, marking as disconnecting.",
pEndpoint);
#ifdef DPNBUILD_NOMULTICAST
DNASSERT(pEndpoint->GetType() == ENDPOINT_TYPE_LISTEN);
#else // ! DPNBUILD_NOMULTICAST
DNASSERT((pEndpoint->GetType() == ENDPOINT_TYPE_LISTEN) || (pEndpoint->GetType() == ENDPOINT_TYPE_MULTICAST_LISTEN));
#endif // ! DPNBUILD_NOMULTICAST
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;
}
default:
{
DNASSERT( FALSE );
break;
}
}
break;
}
//
// other command state
//
default:
{
DNASSERT( FALSE );
break;
}
}
Exit:
if ( fCommandLocked != FALSE )
{
DNASSERT( pCommandData != NULL );
pCommandData->Unlock();
fCommandLocked = 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;
CSPData *pSPData;
#ifndef DPNBUILD_ONLYONETHREAD
LONG iIOThreadCount;
#endif // ! DPNBUILD_ONLYONETHREAD
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 = CSPData::SPDataFromCOMInterface( pThis );
//
// no need to tell thread pool to lock the thread count for this function.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// set flags
//
pCapsData->dwFlags = DPNSPCAPS_SUPPORTSDPNSRV |
DPNSPCAPS_SUPPORTSBROADCAST |
DPNSPCAPS_SUPPORTSALLADAPTERS;
#ifndef DPNBUILD_ONLYONETHREAD
pCapsData->dwFlags |= DPNSPCAPS_SUPPORTSTHREADPOOL;
#endif // ! DPNBUILD_ONLYONETHREAD
#ifndef DPNBUILD_NOMULTICAST
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
if (pSPData->GetType() != AF_IPX)
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
{
pCapsData->dwFlags |= DPNSPCAPS_SUPPORTSMULTICAST;
}
#endif // ! DPNBUILD_NOMULTICAST
//
// set frame sizes
//
#ifdef DPNBUILD_NOREGISTRY
pCapsData->dwUserFrameSize = DEFAULT_MAX_USER_DATA_SIZE;
pCapsData->dwEnumFrameSize = DEFAULT_MAX_ENUM_DATA_SIZE;
#else // ! DPNBUILD_NOREGISTRY
pCapsData->dwUserFrameSize = g_dwMaxUserDataSize;
pCapsData->dwEnumFrameSize = g_dwMaxEnumDataSize;
#endif // ! DPNBUILD_NOREGISTRY
//
// Set link speed, no need to check for endpoint because
// the link speed cannot be determined.
//
pCapsData->dwLocalLinkSpeed = UNKNOWN_BANDWIDTH;
#ifdef DPNBUILD_ONLYONETHREAD
pCapsData->dwIOThreadCount = 0;
#else // ! DPNBUILD_ONLYONETHREAD
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;
#endif // ! DPNBUILD_ONLYONETHREAD
//
// set enumeration defaults
//
pCapsData->dwDefaultEnumRetryCount = DEFAULT_ENUM_RETRY_COUNT;
pCapsData->dwDefaultEnumRetryInterval = DEFAULT_ENUM_RETRY_INTERVAL;
pCapsData->dwDefaultEnumTimeout = DEFAULT_ENUM_TIMEOUT;
//
// dwBuffersPerThread is ignored
//
pCapsData->dwBuffersPerThread = 1;
//
// set receive buffering information
//
pCapsData->dwSystemBufferSize = 8192;
if ( g_fWinsockReceiveBufferSizeOverridden == FALSE )
{
SOCKET TestSocket;
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
TestSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP );
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
switch (pSPData->GetType())
{
#ifndef DPNBUILD_NOIPV6
case AF_INET6:
{
TestSocket = socket( AF_INET6, SOCK_DGRAM, IPPROTO_IP );
break;
}
#endif // ! DPNBUILD_NOIPV6
#ifndef DPNBUILD_NOIPX
case AF_IPX:
{
TestSocket = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
break;
}
#endif // ! DPNBUILD_NOIPX
default:
{
DNASSERT(pSPData->GetType() == AF_INET);
TestSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP );
break;
}
}
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if ( TestSocket != INVALID_SOCKET )
{
INT iBufferSize;
INT iBufferSizeSize;
INT iWSAReturn;
iBufferSizeSize = sizeof( iBufferSize );
iWSAReturn = 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 );
}
closesocket( TestSocket );
TestSocket = INVALID_SOCKET;
}
}
else
{
pCapsData->dwSystemBufferSize = g_iWinsockReceiveBufferSize;
}
#ifndef DPNBUILD_ONLYONETHREAD
Exit:
#endif // !DPNBUILD_ONLYONETHREAD
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
#ifndef DPNBUILD_ONLYONETHREAD
Failure:
goto Exit;
#endif // !DPNBUILD_ONLYONETHREAD
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// 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;
CSPData *pSPData;
#ifndef DPNBUILD_NOREGISTRY
CRegistry RegObject;
#endif // ! DPNBUILD_NOREGISTRY
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;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
//
// no need to tell thread pool to lock the thread count for this function.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// validate caps
//
if ( pCapsData->dwBuffersPerThread == 0 )
{
DPFX(DPFPREP, 0, "Failing SetCaps because dwBuffersPerThread == 0" );
hr = DPNERR_INVALIDPARAM;
goto Failure;
}
#ifndef DPNBUILD_ONLYONETHREAD
//
// change thread count, if requested
//
if ( pCapsData->dwIOThreadCount != 0 )
{
hr = pSPData->GetThreadPool()->SetIOThreadCount( pCapsData->dwIOThreadCount );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "Failed to set thread pool count!" );
DisplayDNError( 0, hr );
goto Failure;
}
}
#endif // ! DPNBUILD_ONLYONETHREAD
//
// dwBuffersPerThread is ignored.
//
//
// Set the receive buffer size.
//
DBG_CASSERT( sizeof( pCapsData->dwSystemBufferSize ) == sizeof( g_iWinsockReceiveBufferSize ) );
g_fWinsockReceiveBufferSizeOverridden = TRUE;
g_iWinsockReceiveBufferSize = pCapsData->dwSystemBufferSize;
#ifndef WINCE
pSPData->SetWinsockBufferSizeOnAllSockets( g_iWinsockReceiveBufferSize );
#endif // ! WINCE
Exit:
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 && pGetAddressInfoData->hEndpoint != 0 );
#ifdef DPNBUILD_NOMULTICAST
DNASSERT( ( pGetAddressInfoData->Flags & ~( SP_GET_ADDRESS_INFO_LOCAL_ADAPTER |
SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES |
SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS |
SP_GET_ADDRESS_INFO_REMOTE_HOST ) ) == 0 );
#else // ! DPNBUILD_NOMULTICAST
DNASSERT( ( pGetAddressInfoData->Flags & ~( SP_GET_ADDRESS_INFO_LOCAL_ADAPTER |
SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES |
SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS |
SP_GET_ADDRESS_INFO_REMOTE_HOST |
SP_GET_ADDRESS_INFO_MULTICAST_GROUP ) ) == 0 );
#endif // ! DPNBUILD_NOMULTICAST
//
// initialize
//
hr = DPN_OK;
DBG_CASSERT( sizeof( pEndpoint ) == sizeof( pGetAddressInfoData->hEndpoint ) );
pSPData = CSPData::SPDataFromCOMInterface( pThis );
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// 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_LOCAL_ADAPTER:
{
pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( SP_ADDRESS_TYPE_DEVICE );
if (pGetAddressInfoData->pAddress == NULL)
{
DPFX(DPFPREP, 0, "Couldn't get local adapter device address!");
hr = DPNERR_OUTOFMEMORY;
}
break;
}
case SP_GET_ADDRESS_INFO_LISTEN_HOST_ADDRESSES:
{
pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( SP_ADDRESS_TYPE_HOST );
if (pGetAddressInfoData->pAddress == NULL)
{
DPFX(DPFPREP, 0, "Couldn't get local adapter host address!");
hr = DPNERR_OUTOFMEMORY;
}
break;
}
case SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS:
{
pGetAddressInfoData->pAddress = pEndpoint->GetLocalAdapterDP8Address( SP_ADDRESS_TYPE_PUBLIC_HOST_ADDRESS );
break;
}
case SP_GET_ADDRESS_INFO_REMOTE_HOST:
{
pGetAddressInfoData->pAddress = pEndpoint->GetRemoteHostDP8Address();
if (pGetAddressInfoData->pAddress == NULL)
{
DPFX(DPFPREP, 0, "Couldn't get remote host address!");
hr = DPNERR_OUTOFMEMORY;
}
break;
}
#ifndef DPNBUILD_NOMULTICAST
case SP_GET_ADDRESS_INFO_MULTICAST_GROUP:
{
pGetAddressInfoData->pAddress = pEndpoint->GetRemoteHostDP8Address();
//
// If we successfully got an address, add the multicast scope GUID.
//
if (pGetAddressInfoData->pAddress != NULL)
{
GUID guidScope;
pEndpoint->GetScopeGuid(&guidScope);
hr = IDirectPlay8Address_AddComponent(pGetAddressInfoData->pAddress,
DPNA_KEY_SCOPE,
&guidScope,
sizeof(guidScope),
DPNA_DATATYPE_GUID);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't add scope GUID component to address (err = 0x%lx)! Ignoring.", hr);
hr = DPN_OK;
}
}
else
{
DPFX(DPFPREP, 0, "Couldn't get multicast group address!");
hr = DPNERR_OUTOFMEMORY;
}
break;
}
#endif // ! DPNBUILD_NOMULTICAST
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_Update - update information/status of an endpoint
//
// Entry: Pointer to DNSP Interface
// Pointer to input data
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNSP_Update"
STDMETHODIMP DNSP_Update( IDP8ServiceProvider *pThis, SPUPDATEDATA *pUpdateData )
{
HRESULT hr;
CSPData *pSPData;
CEndpoint *pEndpoint;
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pUpdateData);
DNASSERT( pThis != NULL );
DNASSERT( pUpdateData != NULL );
pSPData = CSPData::SPDataFromCOMInterface( pThis );
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// no need to tell thread pool to lock the thread count for this function.
//
switch ( pUpdateData->UpdateType )
{
case SP_UPDATE_HOST_MIGRATE:
{
#ifdef DBG
DNASSERT( ( pUpdateData->hEndpoint != INVALID_HANDLE_VALUE ) && ( pUpdateData->hEndpoint != NULL ) );
DBG_CASSERT( sizeof( pEndpoint ) == sizeof( pUpdateData->hEndpoint ) );
pEndpoint = pSPData->EndpointFromHandle( pUpdateData->hEndpoint );
if (pEndpoint == NULL)
{
DPFX(DPFPREP, 0, "Host migrate endpoint 0x%p is invalid!", pEndpoint);
DNASSERT( FALSE );
hr = DPNERR_INVALIDENDPOINT;
break;
}
DNASSERT( pEndpoint->GetType() == ENDPOINT_TYPE_LISTEN );
DPFX(DPFPREP, 3, "Host migrated to listen endpoint 0x%p.", pEndpoint);
pEndpoint->DecCommandRef();
pEndpoint = NULL;
#endif // DBG
hr = DPN_OK;
break;
}
case SP_UPDATE_ALLOW_ENUMS:
case SP_UPDATE_DISALLOW_ENUMS:
{
DNASSERT( ( pUpdateData->hEndpoint != INVALID_HANDLE_VALUE ) && ( pUpdateData->hEndpoint != NULL ) );
DBG_CASSERT( sizeof( pEndpoint ) == sizeof( pUpdateData->hEndpoint ) );
pEndpoint = pSPData->EndpointFromHandle( pUpdateData->hEndpoint );
if (pEndpoint == NULL)
{
DPFX(DPFPREP, 0, "Allow/disallow enums endpoint 0x%p is invalid!", pEndpoint);
DNASSERT( FALSE );
hr = DPNERR_INVALIDENDPOINT;
break;
}
DNASSERT( pEndpoint->GetType() == ENDPOINT_TYPE_LISTEN );
if ( pUpdateData->UpdateType == SP_UPDATE_ALLOW_ENUMS )
{
DPFX(DPFPREP, 3, "Allowing enums on listen endpoint 0x%p.", pEndpoint);
pEndpoint->SetEnumsAllowedOnListen( TRUE, TRUE );
}
else
{
DPFX(DPFPREP, 3, "Disallowing enums on listen endpoint 0x%p.", pEndpoint);
pEndpoint->SetEnumsAllowedOnListen( FALSE, TRUE );
}
pEndpoint->DecCommandRef();
pEndpoint = NULL;
hr = DPN_OK;
break;
}
default:
{
DPFX(DPFPREP, 0, "Unsupported update type %u!", pUpdateData->UpdateType);
hr = DPNERR_UNSUPPORTED;
break;
}
}
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
}
//**********************************************************************
#ifndef DPNBUILD_LIBINTERFACE
//**********************************************************************
// ------------------------------
// 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 )
{
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
//
pSPData = CSPData::SPDataFromCOMInterface( pThis );
//
// no need to tell thread pool to lock the thread count for this function.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
DPFX(DPFPREP, 2, "Returning: DPN_OK");
return DPN_OK;
}
//**********************************************************************
#endif // ! DPNBUILD_LIBINTERFACE
#ifndef DPNBUILD_ONLYONEADAPTER
//**********************************************************************
// ------------------------------
// 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;
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;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
//
// no need to tell thread pool to lock the thread count for this function.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// get an SP address from the pool to perform conversions to GUIDs
//
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
pSPAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
pSPAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) pSPData->GetType()));
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
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 )
{
g_SocketAddressPool.Release( pSPAddress );
pSPAddress = NULL;
}
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
Failure:
goto Exit;
}
//**********************************************************************
#endif // ! DPNBUILD_ONLYONEADAPTER
#ifndef DPNBUILD_SINGLEPROCESS
//**********************************************************************
// ------------------------------
// 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;
CSPData *pSPData;
CSocketAddress *pDestinationAddress;
CSocketAddress *pReturnAddress;
CEndpoint *pEndpoint;
const ENDPOINT_ENUM_QUERY_CONTEXT *pEndpointEnumContext;
BUFFERDESC BufferDesc[2];
PREPEND_BUFFER PrependBuffer;
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 );
DNASSERT(pEndpointEnumContext->pReturnAddress != NULL);
pSPData = CSPData::SPDataFromCOMInterface( pThis );
pDestinationAddress = NULL;
pReturnAddress = 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.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// preallocate addresses
//
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
pDestinationAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
pDestinationAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) pEndpointEnumContext->pReturnAddress->GetFamily()));
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if ( pDestinationAddress == NULL )
{
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
pReturnAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
pReturnAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) pEndpointEnumContext->pReturnAddress->GetFamily()));
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if ( pReturnAddress == NULL )
{
hr = DPNERR_OUTOFMEMORY;
goto Failure;
}
//
// set the endpoint and send it along
//
pEndpoint = pSPData->EndpointFromHandle( pEndpointEnumContext->hEndpoint );
if ( pEndpoint == NULL )
{
hr = DPNERR_INVALIDENDPOINT;
DPFX(DPFPREP, 8, "Invalid endpoint handle in DNSP_ProxyEnumQuery" );
goto Failure;
}
//
// set destination address from the supplied data
//
hr = pDestinationAddress->SocketAddressFromDP8Address( pProxyEnumQueryData->pDestinationAdapter,
#ifdef DPNBUILD_XNETSECURITY
NULL,
#endif // DPNBUILD_XNETSECURITY
#ifndef DPNBUILD_ONLYONETHREAD
FALSE,
#endif // DPNBUILD_ONLYONETHREAD
SP_ADDRESS_TYPE_DEVICE );
if ( hr != DPN_OK )
{
DPFX(DPFPREP, 0, "ProxyEnumQuery: Failed to convert target adapter address" );
goto Failure;
}
//
// set return address from incoming enum query
//
memcpy( pReturnAddress->GetWritableAddress(),
pEndpointEnumContext->pReturnAddress->GetAddress(),
pEndpointEnumContext->pReturnAddress->GetAddressSize() );
DNASSERT(pProxyEnumQueryData->pIncomingQueryData->pReceivedData->pNext == NULL);
DNASSERT( pEndpointEnumContext->dwEnumKey <= WORD_MAX );
BufferDesc[0].pBufferData = reinterpret_cast<BYTE*>(&PrependBuffer.ProxiedEnumDataHeader);
BufferDesc[0].dwBufferSize = sizeof( PrependBuffer.ProxiedEnumDataHeader );
memcpy(&BufferDesc[1],
&pProxyEnumQueryData->pIncomingQueryData->pReceivedData->BufferDesc,
sizeof(BufferDesc[1]));
PrependBuffer.ProxiedEnumDataHeader.bSPLeadByte = SP_HEADER_LEAD_BYTE;
PrependBuffer.ProxiedEnumDataHeader.bSPCommandByte = PROXIED_ENUM_DATA_KIND;
PrependBuffer.ProxiedEnumDataHeader.wEnumKey = static_cast<WORD>( pEndpointEnumContext->dwEnumKey );
//
// We could save 2 bytes on IPX by only passing 14 bytes for the
// SOCKADDR structure but it's not worth it, especially since it's
// looping back in the local network stack. SOCKADDR structures are also
// 16 bytes so reducing the data passed to 14 bytes would destroy alignment.
//
// Note that if we're using the large IPv6 addresses, the IPX wasted space is
// larger, and IPv4 addresses will now waste some, too.
//
DBG_CASSERT( (sizeof( PrependBuffer.ProxiedEnumDataHeader.ReturnAddress ) % 4) == 0 );
memcpy( &PrependBuffer.ProxiedEnumDataHeader.ReturnAddress,
pReturnAddress->GetAddress(),
sizeof( PrependBuffer.ProxiedEnumDataHeader.ReturnAddress ) );
#ifdef DPNBUILD_ASYNCSPSENDS
pEndpoint->GetSocketPort()->SendData( BufferDesc, 2, pDestinationAddress, NULL );
#else // ! DPNBUILD_ASYNCSPSENDS
pEndpoint->GetSocketPort()->SendData( BufferDesc, 2, pDestinationAddress );
#endif // ! DPNBUILD_ASYNCSPSENDS
pEndpoint->DecCommandRef();
pEndpoint = NULL;
Exit:
if ( pReturnAddress != NULL )
{
g_SocketAddressPool.Release( pReturnAddress );
pReturnAddress = NULL;
}
if (pDestinationAddress != NULL )
{
g_SocketAddressPool.Release( pDestinationAddress );
pDestinationAddress = NULL;
}
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
Failure:
if (pEndpoint != NULL )
{
pEndpoint->DecCommandRef();
pEndpoint = NULL;
}
goto Exit;
}
//**********************************************************************
#endif // ! DPNBUILD_SINGLEPROCESS
//**********************************************************************
/*
*
* 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;
}
//**********************************************************************
#ifndef DPNBUILD_NOMULTICAST
//**********************************************************************
// ------------------------------
// DNSP_EnumMulticastScopes - get a list of multicast scopes for this SP
//
// Entry: Pointer DNSP Interface
// Pointer to input data
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNSP_EnumMulticastScopes"
STDMETHODIMP DNSP_EnumMulticastScopes( IDP8ServiceProvider *pThis, SPENUMMULTICASTSCOPESDATA *pEnumMulticastScopesData )
{
HRESULT hr;
CSPData *pSPData;
CSocketAddress *pSPAddress;
BOOL fUseMADCAP;
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pEnumMulticastScopesData);
DNASSERT( pThis != NULL );
DNASSERT( pEnumMulticastScopesData != NULL );
DNASSERT( pEnumMulticastScopesData->pguidAdapter != NULL );
DNASSERT( ( pEnumMulticastScopesData->pScopeData != NULL ) ||
( pEnumMulticastScopesData->dwScopeDataSize == 0 ) );
DNASSERT( pEnumMulticastScopesData->dwFlags == 0 );
//
// initialize
//
hr = DPN_OK;
pEnumMulticastScopesData->dwScopeCount = 0;
pSPAddress = NULL;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
//
// no need to tell thread pool to lock the thread count for this function.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// get an SP address from the pool to perform conversions to GUIDs
//
#if ((defined(DPNBUILD_NOIPV6)) && (defined(DPNBUILD_NOIPX)))
pSPAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) AF_INET));
#else // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
pSPAddress = (CSocketAddress*) g_SocketAddressPool.Get((PVOID) ((DWORD_PTR) pSPData->GetType()));
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
if ( pSPAddress == NULL )
{
hr = DPNERR_OUTOFMEMORY;
DPFX(DPFPREP, 0, "Failed to get address for GUID conversions in DNSP_EnumMulticastScopes!" );
goto Failure;
}
//
// enumerate adapters
//
#ifdef WINNT
fUseMADCAP = pSPData->GetThreadPool()->EnsureMadcapLoaded();
#else // ! WINNT
fUseMADCAP = FALSE;
#endif // ! WINNT
hr = pSPAddress->EnumMulticastScopes( pEnumMulticastScopesData, fUseMADCAP );
if ( hr != DPN_OK )
{
if (hr == DPNERR_BUFFERTOOSMALL)
{
DPFX(DPFPREP, 1, "Buffer too small for enumerating scopes.");
}
else
{
DPFX(DPFPREP, 0, "Problem enumerating scopes (err = 0x%lx)!", hr);
DisplayDNError( 0, hr );
}
goto Failure;
}
Exit:
if ( pSPAddress != NULL )
{
g_SocketAddressPool.Release( pSPAddress );
pSPAddress = NULL;
}
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
Failure:
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNSP_ShareEndpointInfo - get a list of multicast scopes for this SP
//
// Entry: Pointer DNSP Interface
// Pointer to input data
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNSP_ShareEndpointInfo"
STDMETHODIMP DNSP_ShareEndpointInfo( IDP8ServiceProvider *pThis, SPSHAREENDPOINTINFODATA *pShareEndpointInfoData )
{
HRESULT hr;
CSPData *pSPData;
CSPData *pSPDataShare;
BOOL fShareInterfaceReferenceAdded;
CSocketData *pSocketData;
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
short sShareSPType;
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pShareEndpointInfoData);
DNASSERT( pThis != NULL );
DNASSERT( pShareEndpointInfoData != NULL );
DNASSERT( pShareEndpointInfoData->pDP8ServiceProvider != NULL );
DNASSERT( pShareEndpointInfoData->dwFlags == 0 );
//
// initialize
//
hr = DPN_OK;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
pSPDataShare = CSPData::SPDataFromCOMInterface( pShareEndpointInfoData->pDP8ServiceProvider );
fShareInterfaceReferenceAdded = FALSE;
pSocketData = NULL;
//
// no need to tell thread pool to lock the thread count for this function.
//
//
// First, validate the source (shared) SP's state. We must assume it's a
// valid dpnwsock SP (CSPData::SPDataFromCOMInterface should assert if not),
// but we can make sure it has been initialized.
//
pSPDataShare->Lock();
switch ( pSPDataShare->GetState() )
{
//
// provider is initialized, add a reference and proceed
//
case SPSTATE_INITIALIZED:
{
IDP8ServiceProvider_AddRef( pShareEndpointInfoData->pDP8ServiceProvider );
fShareInterfaceReferenceAdded = TRUE;
DNASSERT( hr == DPN_OK );
break;
}
//
// provider is uninitialized
//
case SPSTATE_UNINITIALIZED:
{
hr = DPNERR_UNINITIALIZED;
DPFX(DPFPREP, 0, "ShareEndpointInfo called with uninitialized shared SP 0x%p!",
pSPDataShare );
break;
}
//
// provider is closing
//
case SPSTATE_CLOSING:
{
hr = DPNERR_ABORTED;
DPFX(DPFPREP, 0, "ShareEndpointInfo called with shared SP 0x%p that is closing!",
pSPDataShare );
break;
}
//
// unknown
//
default:
{
DPFX(DPFPREP, 0, "ShareEndpointInfo called with shared SP 0x%p in unrecognized state %u!",
pSPDataShare, pSPDataShare->GetState() );
DNASSERT( FALSE );
hr = DPNERR_GENERIC;
break;
}
}
pSPDataShare->Unlock();
if ( hr != DPN_OK )
{
goto Failure;
}
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
//
// We can also double check that it's not the wrong type (IP vs. IPX).
//
sShareSPType = pSPDataShare->GetType();
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
//
// Make sure the source SP has a valid socket data object, and get a
// reference to it. Don't create it if it didn't exist, though.
//
pSPDataShare->Lock();
pSocketData = pSPDataShare->GetSocketData();
if (pSocketData == NULL)
{
pSPDataShare->Unlock();
DPFX(DPFPREP, 0, "Cannot share endpoint info, shared SP has not created its own endpoint information yet!" );
hr = DPNERR_NOTREADY;
goto Failure;
}
pSocketData->AddRef();
pSPDataShare->Unlock();
IDP8ServiceProvider_Release( pShareEndpointInfoData->pDP8ServiceProvider );
fShareInterfaceReferenceAdded = FALSE;
//
// Validate the local SP's state
//
pSPData->Lock();
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
#if ((! defined(DPNBUILD_NOIPV6)) || (! defined(DPNBUILD_NOIPX)))
if (pSPData->GetType() != sShareSPType)
{
pSPData->Unlock();
DPFX(DPFPREP, 0, "ShareEndpointInfo called on different SP types (0x%p == state %u, 0x%p == state %u)!",
pSPData, pSPData->GetState(), pSPDataShare, pSPDataShare->GetState() );
hr = DPNERR_INVALIDINTERFACE;
goto Failure;
}
#endif // ! DPNBUILD_NOIPV6 or ! DPNBUILD_NOIPX
//
// If we're here, the provider is initialized and of the right type.
// Make sure we do not already have "endpoint info" of our own.
//
if (pSPData->GetSocketData() != NULL)
{
pSPData->Unlock();
DPFX(DPFPREP, 0, "Cannot share endpoint info, SP has already created its own endpoint information!" );
hr = DPNERR_ALREADYINITIALIZED;
goto Failure;
}
//
// Transfer the local reference to the SP data object.
//
pSPData->SetSocketData(pSocketData);
pSocketData = NULL;
pSPData->Unlock();
DNASSERT( hr == DPN_OK );
Exit:
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
Failure:
if ( pSocketData != NULL )
{
pSocketData->Release();
pSocketData = NULL;
}
if ( fShareInterfaceReferenceAdded != FALSE )
{
IDP8ServiceProvider_Release( pThis );
fShareInterfaceReferenceAdded = FALSE;
}
goto Exit;
}
//**********************************************************************
//**********************************************************************
// ------------------------------
// DNSP_GetEndpointByAddress - retrieves an endpoint, given its addressing information
//
// Entry: Pointer DNSP Interface
// Pointer to input data
//
// Exit: Error code
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNSP_GetEndpointByAddress"
STDMETHODIMP DNSP_GetEndpointByAddress( IDP8ServiceProvider* pThis, SPGETENDPOINTBYADDRESSDATA *pGetEndpointByAddressData )
{
HRESULT hr;
CSPData *pSPData;
DPFX(DPFPREP, 2, "Parameters: (0x%p, 0x%p)", pThis, pGetEndpointByAddressData);
DNASSERT( pThis != NULL );
DNASSERT( pGetEndpointByAddressData != NULL );
DNASSERT( pGetEndpointByAddressData->pAddressHost != NULL );
DNASSERT( pGetEndpointByAddressData->pAddressDeviceInfo != NULL );
DNASSERT( pGetEndpointByAddressData->dwFlags == 0 );
//
// initialize
//
hr = DPN_OK;
pSPData = CSPData::SPDataFromCOMInterface( pThis );
//
// no need to tell thread pool to lock the thread count for this function.
//
// Trust protocol to call us only in the initialized state
DNASSERT( pSPData->GetState() == SPSTATE_INITIALIZED );
//
// Look up the endpoint handle and context
//
hr = pSPData->GetEndpointFromAddress(pGetEndpointByAddressData->pAddressHost,
pGetEndpointByAddressData->pAddressDeviceInfo,
&pGetEndpointByAddressData->hEndpoint,
&pGetEndpointByAddressData->pvEndpointContext);
if (hr != DPN_OK)
{
DPFX(DPFPREP, 0, "Couldn't get endpoint from address (err = 0x%lx)!", hr);
goto Failure;
}
Exit:
DPFX(DPFPREP, 2, "Returning: [0x%lx]", hr);
return hr;
Failure:
goto Exit;
}
//**********************************************************************
#endif // ! DPNBUILD_NOMULTICAST