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.
629 lines
20 KiB
629 lines
20 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: Enum.cpp
|
|
* Content: Enumeration routines
|
|
*@@BEGIN_MSINTERNAL
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 04/10/00 mjn Created
|
|
* 04/17/00 mjn Fixed DNCompleteEnumQuery to clean up properly
|
|
* 04/18/00 mjn Return User Buffer in DNProcessEnumQuery
|
|
* 04/19/00 mjn Removed DPN_BUFFER_DESC from DPNMSG_ENUM_HOSTS_QUERY and DPNMSG_ENUM_HOSTS_RESPONSE structs
|
|
* 05/02/00 mjn Allow application to reject ENUM_QUERY's
|
|
* 06/25/00 mjn Fixed payload problem in DNProcessEnumQuery()
|
|
* 07/10/00 mjn Removed DNCompleteEnumQuery() and DNCompleteEnumResponse()
|
|
* 07/12/00 mjn Ensure connected before replying to ENUMs
|
|
* 07/29/00 mjn Verify enum responses sizes
|
|
* 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
|
|
* 08/05/00 mjn Ensure cancelled operations don't proceed
|
|
* 08/29/00 mjn Cancel EnumHosts if non-DPN_OK returned from response notification
|
|
* 09/04/00 mjn Added CApplicationDesc
|
|
* 09/14/00 mjn AddRef Protocol refcount when invoking protocol
|
|
* 01/22/01 mjn Add SP reference on AsyncOp in DNProcessEnumQuery()
|
|
* 01/25/01 mjn Fixed 64-bit alignment problem in received messages
|
|
* 03/13/01 mjn Don't copy user response buffer when responding to enums
|
|
*@@END_MSINTERNAL
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "dncorei.h"
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// DNProcessEnumQuery - process enum query
|
|
//
|
|
// Entry: Pointer to this DNet interface object
|
|
// Pointer to the associated listen operation
|
|
// Pointer to protocol's enum data
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNProcessEnumQuery"
|
|
|
|
void DNProcessEnumQuery(DIRECTNETOBJECT *const pdnObject,
|
|
CAsyncOp *const pListen,
|
|
const PROTOCOL_ENUM_DATA *const pEnumQueryData )
|
|
{
|
|
HRESULT hResultCode;
|
|
DPNMSG_ENUM_HOSTS_QUERY AppData;
|
|
CPackedBuffer PackedBuffer;
|
|
CRefCountBuffer *pRefCountBuffer;
|
|
CAsyncOp *pAsyncOp;
|
|
HANDLE hProtocol;
|
|
const DN_ENUM_QUERY_PAYLOAD *pEnumQueryPayload;
|
|
DN_ENUM_RESPONSE_OP_DATA *pEnumResponseOpData;
|
|
DN_ENUM_RESPONSE_PAYLOAD *pEnumResponsePayload;
|
|
DWORD dwPayloadOffset;
|
|
IDP8ServiceProvider *pIDP8SP;
|
|
SPGETCAPSDATA spGetCapsData;
|
|
CServiceProvider *pSP;
|
|
DWORD dwBufferCount;
|
|
BOOL fNeedToReturnBuffer;
|
|
|
|
DPFX(DPFPREP, 6,"Parameters: pListen [0x%p], pEnumQueryData [0x%p]",pListen,pEnumQueryData);
|
|
|
|
DNASSERT( pdnObject != NULL );
|
|
DNASSERT( pListen != NULL );
|
|
DNASSERT( pEnumQueryData != NULL );
|
|
|
|
pAsyncOp = NULL;
|
|
pRefCountBuffer = NULL;
|
|
pIDP8SP = NULL;
|
|
pSP = NULL;
|
|
fNeedToReturnBuffer = FALSE; // Is this needed ?
|
|
|
|
//
|
|
// Ensure we are in a position to reply to this message.
|
|
// We must be CONNECTED and not be HOST_MIGRATING
|
|
//
|
|
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
|
|
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) || (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING))
|
|
{
|
|
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
|
|
|
|
DPFX(DPFPREP, 7, "Not connected or host is migrating (object 0x%p flags = 0x%x), ignoring enum.", pdnObject, pdnObject->dwFlags);
|
|
goto Failure;
|
|
}
|
|
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
|
|
|
|
//
|
|
// Check to see if this message is for this game type. Since the application
|
|
// GUID cannot be changed while the session is running, there's no need to
|
|
// enter a critical section.
|
|
//
|
|
pEnumQueryPayload = reinterpret_cast<DN_ENUM_QUERY_PAYLOAD*>( pEnumQueryData->ReceivedData.pBufferData );
|
|
if ( pEnumQueryPayload == NULL )
|
|
{
|
|
//
|
|
// no enum payload (there needs to be at least one byte!)
|
|
//
|
|
DPFX(DPFPREP, 4, "No enum payload, object 0x%p ignoring enum.", pdnObject);
|
|
goto Failure;
|
|
}
|
|
|
|
dwPayloadOffset = 0;
|
|
switch ( pEnumQueryPayload->QueryType )
|
|
{
|
|
//
|
|
// an application guid was specified, make sure it matches this application's
|
|
// guid before further processing
|
|
//
|
|
case DN_ENUM_QUERY_WITH_APPLICATION_GUID:
|
|
{
|
|
if ( pEnumQueryData->ReceivedData.dwBufferSize < sizeof( DN_ENUM_QUERY_PAYLOAD ) )
|
|
{
|
|
DNASSERTX( ! "Received data too small to be valid enum query with application guid!", 2 );
|
|
goto Failure;
|
|
}
|
|
|
|
if ( !pdnObject->ApplicationDesc.IsEqualApplicationGuid( &pEnumQueryPayload->guidApplication ) )
|
|
{
|
|
#ifdef DBG
|
|
GUID guidApplication;
|
|
|
|
|
|
//
|
|
// GUID might not be aligned, so copy it to a temp variable
|
|
//
|
|
guidApplication = pEnumQueryPayload->guidApplication;
|
|
DPFX(DPFPREP, 7, "Application GUID {%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X} doesn't match, object 0x%p, ignoring enum.",
|
|
guidApplication.Data1,
|
|
guidApplication.Data2,
|
|
guidApplication.Data3,
|
|
guidApplication.Data4[0],
|
|
guidApplication.Data4[1],
|
|
guidApplication.Data4[2],
|
|
guidApplication.Data4[3],
|
|
guidApplication.Data4[4],
|
|
guidApplication.Data4[5],
|
|
guidApplication.Data4[6],
|
|
guidApplication.Data4[7],
|
|
pdnObject);
|
|
#endif // DBG
|
|
goto Failure;
|
|
}
|
|
|
|
dwPayloadOffset = sizeof( DN_ENUM_QUERY_PAYLOAD );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// no application guid was specified, continue processing
|
|
//
|
|
case DN_ENUM_QUERY_WITHOUT_APPLICATION_GUID:
|
|
{
|
|
if ( pEnumQueryData->ReceivedData.dwBufferSize < ( sizeof( DN_ENUM_QUERY_PAYLOAD ) - sizeof( GUID ) ) )
|
|
{
|
|
DNASSERTX( ! "Received data too small to be valid enum query without application guid!", 2 );
|
|
goto Failure;
|
|
}
|
|
|
|
dwPayloadOffset = sizeof( DN_ENUM_QUERY_PAYLOAD ) - sizeof( GUID );
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DNASSERTX( ! "Unrecognized enum query payload type!", 2 );
|
|
goto Failure;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// buld message structure, be nice and clear the user payload pointer if
|
|
// there is no payload
|
|
//
|
|
AppData.dwSize = sizeof( AppData );
|
|
AppData.pAddressSender = pEnumQueryData->pSenderAddress;
|
|
AppData.pAddressDevice = pEnumQueryData->pDeviceAddress;
|
|
|
|
DPFX(DPFPREP, 7,"AppData.pAddressSender: [0x%p]",AppData.pAddressSender);
|
|
DPFX(DPFPREP, 7,"AppData.pAddressDevice: [0x%p]",AppData.pAddressDevice);
|
|
|
|
if (pEnumQueryData->ReceivedData.dwBufferSize > dwPayloadOffset)
|
|
{
|
|
DNASSERT( pEnumQueryData->ReceivedData.pBufferData );
|
|
DNASSERT( pEnumQueryData->ReceivedData.dwBufferSize );
|
|
|
|
AppData.pvReceivedData = static_cast<void*>(static_cast<BYTE*>(pEnumQueryData->ReceivedData.pBufferData) + dwPayloadOffset);
|
|
AppData.dwReceivedDataSize = pEnumQueryData->ReceivedData.dwBufferSize - dwPayloadOffset;
|
|
}
|
|
else
|
|
{
|
|
AppData.pvReceivedData = NULL;
|
|
AppData.dwReceivedDataSize = 0;
|
|
}
|
|
|
|
//
|
|
// Response Info
|
|
//
|
|
AppData.pvResponseData = NULL;
|
|
AppData.dwResponseDataSize = 0;
|
|
AppData.pvResponseContext = NULL;
|
|
|
|
//
|
|
// Determine max size of response
|
|
// - Get SP interface from listen SP (listen's parent)
|
|
// - Get SP caps on the interface to determine the total available buffer size
|
|
// - Figure out what the DNET enum response size will be
|
|
// - Determine space available to user
|
|
//
|
|
DNASSERT(pListen->GetParent() != NULL);
|
|
DNASSERT(pListen->GetParent()->GetSP() != NULL);
|
|
pListen->GetParent()->GetSP()->AddRef();
|
|
pSP = pListen->GetParent()->GetSP();
|
|
if ((hResultCode = pSP->GetInterfaceRef( &pIDP8SP )) != DPN_OK)
|
|
{
|
|
DPFERR("Could not get ListenSP SP interface");
|
|
DisplayDNError(0,hResultCode);
|
|
DNASSERT(FALSE);
|
|
goto Failure;
|
|
}
|
|
memset( &spGetCapsData, 0x00, sizeof( SPGETCAPSDATA ) );
|
|
spGetCapsData.dwSize = sizeof( SPGETCAPSDATA );
|
|
spGetCapsData.hEndpoint = INVALID_HANDLE_VALUE;
|
|
if ((hResultCode = IDP8ServiceProvider_GetCaps( pIDP8SP, &spGetCapsData )) != DPN_OK)
|
|
{
|
|
DPFERR("Could not get SP caps");
|
|
DisplayDNError(0,hResultCode);
|
|
goto Failure;
|
|
}
|
|
IDP8ServiceProvider_Release( pIDP8SP );
|
|
pIDP8SP = NULL;
|
|
PackedBuffer.Initialize(NULL,0);
|
|
PackedBuffer.AddToFront(NULL,sizeof(DN_ENUM_RESPONSE_PAYLOAD));
|
|
pdnObject->ApplicationDesc.PackInfo(&PackedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
|
|
DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
|
|
AppData.dwMaxResponseDataSize = spGetCapsData.dwEnumFrameSize - PackedBuffer.GetSizeRequired();
|
|
|
|
//
|
|
// pass message to the user
|
|
//
|
|
hResultCode = DNUserEnumQuery(pdnObject,&AppData);
|
|
|
|
//
|
|
// Only ENUMs which are accepted get responded to
|
|
//
|
|
if (hResultCode != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 9, "EnumQuery rejected");
|
|
DisplayDNError(9, hResultCode);
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// get an async operation to track the progress of the response
|
|
//
|
|
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
|
|
{
|
|
DPFERR("Could not allocate Async Op struct for enum response");
|
|
DisplayDNError( 0, hResultCode );
|
|
DNASSERT( FALSE );
|
|
goto Failure;
|
|
}
|
|
pAsyncOp->SetOpType( ASYNC_OP_ENUM_RESPONSE );
|
|
|
|
//
|
|
// compute the size needed to pack up an application description with any
|
|
// user data and send it back
|
|
//
|
|
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
|
|
|
|
PackedBuffer.Initialize(NULL,0);
|
|
PackedBuffer.AddToFront(NULL,sizeof(DN_ENUM_RESPONSE_PAYLOAD));
|
|
hResultCode = pdnObject->ApplicationDesc.PackInfo(&PackedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|
|
|
DN_APPDESCINFO_FLAG_RESERVEDDATA|DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
|
|
DNASSERT( hResultCode == DPNERR_BUFFERTOOSMALL );
|
|
|
|
//
|
|
// Ensure this enum response will fit in SP enum frame - only indicate this if there was a response
|
|
//
|
|
if (((AppData.pvResponseData != NULL) && (AppData.dwResponseDataSize != 0)) &&
|
|
(PackedBuffer.GetSizeRequired() + AppData.dwResponseDataSize > spGetCapsData.dwEnumFrameSize))
|
|
{
|
|
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
|
|
DPFERR("Enum response is too large");
|
|
DNUserReturnBuffer(pdnObject,DPNERR_ENUMRESPONSETOOLARGE,AppData.pvResponseData,AppData.pvResponseContext);
|
|
goto Failure;
|
|
}
|
|
|
|
hResultCode = RefCountBufferNew(pdnObject,
|
|
PackedBuffer.GetSizeRequired(),
|
|
EnumReplyMemoryBlockAlloc,
|
|
EnumReplyMemoryBlockFree,
|
|
&pRefCountBuffer);
|
|
if ( hResultCode != DPN_OK )
|
|
{
|
|
DNASSERT( FALSE );
|
|
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
|
|
goto Failure;
|
|
}
|
|
PackedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),
|
|
pRefCountBuffer->GetBufferSize());
|
|
pEnumResponsePayload = static_cast<DN_ENUM_RESPONSE_PAYLOAD*>(PackedBuffer.GetHeadAddress());
|
|
hResultCode = PackedBuffer.AddToFront(NULL,sizeof(DN_ENUM_RESPONSE_PAYLOAD));
|
|
if (hResultCode != DPN_OK)
|
|
{
|
|
DNASSERT(FALSE);
|
|
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
|
|
goto Failure;
|
|
}
|
|
if ((AppData.pvResponseData != NULL) && (AppData.dwResponseDataSize != 0))
|
|
{
|
|
pEnumResponsePayload->dwResponseOffset = pRefCountBuffer->GetBufferSize();
|
|
pEnumResponsePayload->dwResponseSize = AppData.dwResponseDataSize;
|
|
}
|
|
else
|
|
{
|
|
pEnumResponsePayload->dwResponseOffset = 0;
|
|
pEnumResponsePayload->dwResponseSize = 0;
|
|
}
|
|
pdnObject->ApplicationDesc.PackInfo(&PackedBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_RESERVEDDATA|
|
|
DN_APPDESCINFO_FLAG_APPRESERVEDDATA);
|
|
if ( hResultCode != DPN_OK )
|
|
{
|
|
DNASSERT( FALSE );
|
|
goto Failure;
|
|
}
|
|
|
|
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
|
|
|
|
//
|
|
// build enum response and send it down to the protocol
|
|
//
|
|
pEnumResponseOpData = pAsyncOp->GetLocalEnumResponseOpData();
|
|
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_DN_PAYLOAD].pBufferData = pRefCountBuffer->GetBufferAddress();
|
|
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_DN_PAYLOAD].dwBufferSize = pRefCountBuffer->GetBufferSize();
|
|
|
|
pAsyncOp->SetCompletion( DNCompleteEnumResponse );
|
|
pAsyncOp->SetRefCountBuffer( pRefCountBuffer );
|
|
pRefCountBuffer->Release();
|
|
pRefCountBuffer = NULL;
|
|
|
|
if ((AppData.pvResponseData != NULL) && (AppData.dwResponseDataSize != 0))
|
|
{
|
|
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].pBufferData = static_cast<BYTE*>(AppData.pvResponseData);
|
|
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].dwBufferSize = AppData.dwResponseDataSize;
|
|
pEnumResponseOpData->pvUserContext = AppData.pvResponseContext;
|
|
dwBufferCount = DN_ENUM_BUFFERDESC_RESPONSE_COUNT;
|
|
}
|
|
else
|
|
{
|
|
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].pBufferData = NULL;
|
|
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].dwBufferSize = 0;
|
|
pEnumResponseOpData->pvUserContext = NULL;
|
|
dwBufferCount = DN_ENUM_BUFFERDESC_RESPONSE_COUNT - 1;
|
|
}
|
|
|
|
DNASSERT(pListen->GetParent() != NULL);
|
|
DNASSERT(pListen->GetParent()->GetSP() != NULL);
|
|
DNASSERT(pListen->GetParent()->GetSP()->GetHandle() != NULL);
|
|
|
|
//
|
|
// AddRef Protocol so that it won't go away until this completes
|
|
//
|
|
DNProtocolAddRef(pdnObject);
|
|
|
|
pAsyncOp->AddRef();
|
|
hResultCode = DNPEnumRespond( pdnObject->pdnProtocolData,
|
|
pListen->GetParent()->GetSP()->GetHandle(),
|
|
pEnumQueryData->hEnumQuery,
|
|
&pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_DN_PAYLOAD],
|
|
dwBufferCount,
|
|
0,
|
|
reinterpret_cast<void*>(pAsyncOp),
|
|
&hProtocol);
|
|
if ( hResultCode != DPNERR_PENDING )
|
|
{
|
|
pAsyncOp->Release();
|
|
DNProtocolRelease(pdnObject);
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Save Protocol Handle
|
|
//
|
|
pAsyncOp->Lock();
|
|
if (pAsyncOp->IsCancelled())
|
|
{
|
|
HRESULT hrCancel;
|
|
|
|
pAsyncOp->Unlock();
|
|
DPFX(DPFPREP, 7,"Operation marked for cancel");
|
|
if ((hrCancel = DNPCancelCommand(pdnObject->pdnProtocolData,hProtocol)) == DPN_OK)
|
|
{
|
|
hResultCode = DPNERR_USERCANCEL;
|
|
goto Failure;
|
|
}
|
|
DPFERR("Could not cancel operation");
|
|
DisplayDNError(0,hrCancel);
|
|
pAsyncOp->Lock();
|
|
}
|
|
pAsyncOp->SetSP( pSP );
|
|
pAsyncOp->SetProtocolHandle(hProtocol);
|
|
pAsyncOp->Unlock();
|
|
|
|
pAsyncOp->Release();
|
|
pAsyncOp = NULL;
|
|
|
|
pSP->Release();
|
|
pSP = NULL;
|
|
|
|
Exit:
|
|
DPFX(DPFPREP, 6,"Returning");
|
|
return;
|
|
|
|
Failure:
|
|
if (pAsyncOp)
|
|
{
|
|
pAsyncOp->Release();
|
|
pAsyncOp = NULL;
|
|
}
|
|
if (pRefCountBuffer)
|
|
{
|
|
pRefCountBuffer->Release();
|
|
pRefCountBuffer = NULL;
|
|
}
|
|
if (pIDP8SP)
|
|
{
|
|
IDP8ServiceProvider_Release(pIDP8SP);
|
|
pIDP8SP = NULL;
|
|
}
|
|
if (pSP)
|
|
{
|
|
pSP->Release();
|
|
pSP = NULL;
|
|
}
|
|
goto Exit;
|
|
}
|
|
//**********************************************************************
|
|
|
|
|
|
//**********************************************************************
|
|
// ------------------------------
|
|
// DNProcessEnumResponse - process response to enum query
|
|
//
|
|
// Entry: Pointer to this DNet interface object
|
|
// Pointer to the associated enum operation
|
|
// Pointer to protocol's enum response data
|
|
//
|
|
// Exit: Nothing
|
|
// ------------------------------
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DNProcessEnumResponse"
|
|
|
|
void DNProcessEnumResponse(DIRECTNETOBJECT *const pdnObject,
|
|
CAsyncOp *const pAsyncOp,
|
|
const PROTOCOL_ENUM_RESPONSE_DATA *const pEnumResponseData)
|
|
{
|
|
HRESULT hResultCode;
|
|
DPNMSG_ENUM_HOSTS_RESPONSE AppData;
|
|
BYTE *pWorkingItem;
|
|
UNALIGNED DN_ENUM_RESPONSE_PAYLOAD *pEnumResponsePayload;
|
|
DPN_APPLICATION_DESC dpnAppDesc;
|
|
UNALIGNED DPN_APPLICATION_DESC_INFO *pInfo;
|
|
BYTE AppDescReservedData[DPN_MAX_APPDESC_RESERVEDDATA_SIZE];
|
|
|
|
|
|
DNASSERT( pdnObject != NULL );
|
|
DNASSERT( pAsyncOp != NULL );
|
|
DNASSERT( pEnumResponseData != NULL );
|
|
|
|
pWorkingItem = pEnumResponseData->ReceivedData.pBufferData;
|
|
|
|
//
|
|
// Unpack the ENUM response.
|
|
// It will be in the following format:
|
|
// <UserResponseOffset>
|
|
// <UserResponseSize>
|
|
// <AppDescInfo>
|
|
//
|
|
|
|
//
|
|
// Verify buffer size
|
|
//
|
|
if (pEnumResponseData->ReceivedData.dwBufferSize < (sizeof(DN_ENUM_RESPONSE_PAYLOAD) + sizeof(DPN_APPLICATION_DESC_INFO)))
|
|
{
|
|
DPFERR("Received invalid enum response - buffer is smaller than minimum size");
|
|
goto Exit;
|
|
}
|
|
|
|
pEnumResponsePayload = reinterpret_cast<DN_ENUM_RESPONSE_PAYLOAD*>(pEnumResponseData->ReceivedData.pBufferData);
|
|
|
|
//
|
|
// Application Description
|
|
//
|
|
pInfo = reinterpret_cast<DPN_APPLICATION_DESC_INFO*>(pEnumResponsePayload + 1);
|
|
memset(&dpnAppDesc,0,sizeof(DPN_APPLICATION_DESC));
|
|
if (pInfo->dwSessionNameOffset)
|
|
{
|
|
if ((pInfo->dwSessionNameOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
|
|
(pInfo->dwSessionNameOffset+pInfo->dwSessionNameSize > pEnumResponseData->ReceivedData.dwBufferSize))
|
|
{
|
|
DPFERR("Received invalid enum response - session name is outside of buffer");
|
|
goto Exit;
|
|
}
|
|
dpnAppDesc.pwszSessionName = reinterpret_cast<WCHAR*>(pWorkingItem + pInfo->dwSessionNameOffset);
|
|
}
|
|
if (pInfo->dwReservedDataOffset)
|
|
{
|
|
if ((pInfo->dwReservedDataOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
|
|
(pInfo->dwReservedDataOffset+pInfo->dwReservedDataSize > pEnumResponseData->ReceivedData.dwBufferSize))
|
|
{
|
|
DPFERR("Received invalid enum response - reserved data is outside of buffer");
|
|
goto Exit;
|
|
}
|
|
dpnAppDesc.pvReservedData = static_cast<void*>(pWorkingItem + pInfo->dwReservedDataOffset);
|
|
dpnAppDesc.dwReservedDataSize = pInfo->dwReservedDataSize;
|
|
|
|
//
|
|
// If we understand the reserved data, we want to pad the buffer so the user doesn't
|
|
// assume the data is less than DPN_MAX_APPDESC_RESERVEDDATA_SIZE bytes long.
|
|
//
|
|
if ((dpnAppDesc.dwReservedDataSize == sizeof(SPSESSIONDATA_XNET)) &&
|
|
(*((DWORD*) dpnAppDesc.pvReservedData) == SPSESSIONDATAINFO_XNET))
|
|
{
|
|
SPSESSIONDATA_XNET * pSessionDataXNet;
|
|
|
|
|
|
pSessionDataXNet = (SPSESSIONDATA_XNET*) AppDescReservedData;
|
|
memcpy(pSessionDataXNet, dpnAppDesc.pvReservedData, dpnAppDesc.dwReservedDataSize);
|
|
memset((pSessionDataXNet + 1),
|
|
(((BYTE*) (&pSessionDataXNet->ullKeyID))[1] ^ ((BYTE*) (&pSessionDataXNet->guidKey))[2]),
|
|
(DPN_MAX_APPDESC_RESERVEDDATA_SIZE - sizeof(SPSESSIONDATA_XNET)));
|
|
dpnAppDesc.pvReservedData = AppDescReservedData;
|
|
dpnAppDesc.dwReservedDataSize = DPN_MAX_APPDESC_RESERVEDDATA_SIZE;
|
|
}
|
|
}
|
|
if (pInfo->dwApplicationReservedDataOffset)
|
|
{
|
|
if ((pInfo->dwApplicationReservedDataOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
|
|
(pInfo->dwApplicationReservedDataOffset+pInfo->dwApplicationReservedDataSize > pEnumResponseData->ReceivedData.dwBufferSize))
|
|
{
|
|
DPFERR("Received invalid enum response - application reserved data is outside of buffer");
|
|
goto Exit;
|
|
}
|
|
dpnAppDesc.pvApplicationReservedData = static_cast<void*>(pWorkingItem + pInfo->dwApplicationReservedDataOffset);
|
|
dpnAppDesc.dwApplicationReservedDataSize = pInfo->dwApplicationReservedDataSize;
|
|
}
|
|
dpnAppDesc.guidApplication = pInfo->guidApplication;
|
|
dpnAppDesc.guidInstance = pInfo->guidInstance;
|
|
dpnAppDesc.dwFlags = pInfo->dwFlags;
|
|
dpnAppDesc.dwCurrentPlayers = pInfo->dwCurrentPlayers;
|
|
dpnAppDesc.dwMaxPlayers = pInfo->dwMaxPlayers;
|
|
dpnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);
|
|
|
|
//
|
|
// Fill in AppData
|
|
//
|
|
AppData.dwSize = sizeof( AppData );
|
|
AppData.pAddressSender = pEnumResponseData->pSenderAddress;
|
|
AppData.pAddressDevice = pEnumResponseData->pDeviceAddress;
|
|
AppData.pApplicationDescription = &dpnAppDesc;
|
|
AppData.dwRoundTripLatencyMS = pEnumResponseData->dwRoundTripTime;
|
|
|
|
if (pEnumResponsePayload->dwResponseOffset)
|
|
{
|
|
if ((pEnumResponsePayload->dwResponseOffset > pEnumResponseData->ReceivedData.dwBufferSize) ||
|
|
(pEnumResponsePayload->dwResponseOffset+pEnumResponsePayload->dwResponseSize > pEnumResponseData->ReceivedData.dwBufferSize))
|
|
{
|
|
DPFERR("Received invalid enum response - response data is outside of buffer");
|
|
goto Exit;
|
|
}
|
|
AppData.pvResponseData = (pEnumResponseData->ReceivedData.pBufferData + pEnumResponsePayload->dwResponseOffset);
|
|
AppData.dwResponseDataSize = pEnumResponsePayload->dwResponseSize;
|
|
}
|
|
else
|
|
{
|
|
AppData.pvResponseData = NULL;
|
|
AppData.dwResponseDataSize = 0;
|
|
}
|
|
AppData.pvUserContext = pAsyncOp->GetContext();
|
|
|
|
//
|
|
// pass message to the user
|
|
//
|
|
hResultCode = DNUserEnumResponse(pdnObject,&AppData);
|
|
|
|
//
|
|
// Check to see if this is to be cancelled
|
|
//
|
|
if (hResultCode != DPN_OK)
|
|
{
|
|
CAsyncOp *pCancelOp = NULL;
|
|
|
|
//
|
|
// Get top level operation (may be async op handle)
|
|
//
|
|
pAsyncOp->Lock();
|
|
pCancelOp = pAsyncOp;
|
|
while (pCancelOp->IsChild())
|
|
{
|
|
DNASSERT(pCancelOp->GetParent() != NULL);
|
|
pCancelOp = pCancelOp->GetParent();
|
|
}
|
|
pCancelOp->AddRef();
|
|
pAsyncOp->Unlock();
|
|
|
|
//
|
|
// Cancel
|
|
//
|
|
DNCancelChildren(pdnObject,pCancelOp);
|
|
pCancelOp->Release();
|
|
pCancelOp = NULL;
|
|
}
|
|
|
|
Exit:
|
|
return;
|
|
}
|