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
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
|
|
|