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

4241 lines
112 KiB

/*==========================================================================
*
* Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
*
* File: Async.cpp
* Content: Async operation FPM routines
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 07/27/99 mjn Created
* 12/23/99 mjn Added HOST_MIGRATE functionality
* 12/28/99 mjn Moved Async Op stuff to Async.h
* 12/29/99 mjn Reformed DN_ASYNC_OP to use hParentOp instead of lpvUserContext
* 01/06/00 mjn Moved NameTable stuff to NameTable.h
* 01/07/00 mjn Handle NULL buffer descriptors during sends
* 01/09/00 mjn Transfer Application Description at connect
* 01/10/00 mjn Added support for DN_MSG_INTERNAL_UPDATE_APPLICATION_DESC
* 01/12/00 jtk Added simple code to handle enum and enum response messages.
* 01/11/00 mjn Moved AppDesc stuff to AppDesc.h
* Moved connect/disconnect stuff to Connect.h
* 01/14/00 mjn Added pvUserContext to DN_PerformListen
* 01/15/00 mjn Replaced DN_COUNT_BUFFER with CRefCountBuffer
* 01/16/00 mjn Moved User callback stuff to User.h
* 01/17/00 mjn Fixed ConnectToPeer function names
* 01/17/00 mjn Implemented send time
* 01/19/00 mjn Fixed Parent Op refCount bug in MultiSend
* 01/19/00 mjn Replaced DN_SYNC_EVENT with CSyncEvent
* 01/20/00 mjn Route NameTable operations through NameTable operation list
* 01/21/00 mjn Added DNProcessInternalOperation
* 01/23/00 mjn Added support for DN_MSG_INTERNAL_HOST_DESTROY_PLAYER
* 01/24/00 mjn Added support for DN_MSG_INTERNAL_NAMETABLE_VERSION
* and DN_MSG_INTERNAL_RESYNC_VERSION
* 01/25/00 mjn Added support for DN_MSG_INTERNAL_HOST_MIGRATE_COMPLETE
* 01/26/00 mjn Implemented NameTable re-sync at host migration
* 01/27/00 mjn Cleaned up switch/case statements
* 01/27/00 mjn Added support for retention of receive buffers
* 02/09/00 mjn Implemented DNSEND_COMPLETEONPROCESS
* 02/18/00 mjn Converted DNADDRESS to IDirectPlayAddress8
* 03/23/00 mjn Added phrSync and pvInternal
* 03/24/00 mjn Add guidSP to DN_ASYNC_OP
* 03/25/00 rmt Added code to unregister ourselves when listens are terminated
* 04/04/00 rmt Added check for DPNSVR disable before attempting to unregister
* 04/04/00 mjn Added DNProcessTerminateSession and related code
* 04/06/00 rmt Added code to complete nocopy voice sends
* 04/10/00 mjn Use CAsyncOp for CONNECTs, LISTENs and DISCONNECTs
* 04/11/00 mjn Use CAsyncOp for ENUMs
* 04/13/00 mjn Use Protocol Interface VTBL (replaces some functions)
* 04/14/00 mjn DNPerformListen performs synchronous LISTENs
* 04/16/00 mjn Use CAsyncOp for SENDs
* 04/17/00 mjn Replaced BUFFERDESC with DPN_BUFFER_DESC
* 04/17/00 mjn Added DNCompleteAsyncHandle
* 04/20/00 mjn DNPerformChildSend set's child op flags to the parent's op flags
* 04/21/00 mjn Added DNPerformDisconnect
* 04/23/00 mjn Optionally return child AsyncOp in DNPerformChildSend()
* mjn Removed DNSendCompleteOnProcess (better implementation)
* 04/24/00 mjn Added DNCreateUserHandle()
* 04/26/00 mjn Removed DN_ASYNC_OP and related functions
* 04/28/00 mjn Clear unused buffer descriptions in DN_SendTo()
* 05/02/00 mjn Keep a reference on the Connection during SEND's
* 05/05/00 mjn Return DPN_OK from DNReceiveCompleteOnProcess() to prevent holding the buffer
* 05/08/00 vpo Removed asserts when protocol returns non PENDING
* 06/05/00 mjn Removed assert in DNSendMessage
* 06/21/00 mjn Modified DNSendMessage() and DNCreateSendParent() to use protocol voice bit
* 06/24/00 mjn Added CONNECT completions and fixed DN_MSG_INTERNAL_CONNECT_FAILED processing
* mjn Added code to process DN_MSG_INTERNAL_INSTRUCTED_CONNECT_FAILED
* 07/02/00 mjn Added DNSendGroupMessage() *@@END_MSINTERNAL
* 07/05/00 mjn Removed references to DN_MSG_INTERNAL_ENUM_WITH_APPLICATION_GUID,DN_MSG_INTERNAL_ENUM,DN_MSG_INTERNAL_ENUM_RESPONSE
* 07/06/00 mjn Only use CONNECTED connections in group sends
* mjn Use SP handle instead of interface
* 07/10/00 mjn Added DNPerformEnumQuery()
* mjn Correctly flag parent ops in groups sends and added DPNIDs to async ops for better tracking
* 07/11/00 mjn Added fNoLoopBack to DNSendGroupMessage()
* mjn Added DNPerformNextEnumQuery(),DNPerformSPListen(),DNPerformNextListen(),DNEnumAdapterGuids(),DNPerformNextConnect()
* 07/20/00 mjn Fixed DN_TerminateAllListens() to better use locks
* mjn Fixed connect completions and added DNCompleteConnectOperation() and DNCompleteSendConnectInfo()
* mjn Changed DNPerformDisconnect() to take a CConnection and hEndPt
* mjn Revamped CONNECT process and associated refcounts
* 07/21/00 mjn Process DN_MSG_INTERNAL_CONNECT_ATTEMPT_FAILED
* 07/25/00 mjn Save result code on parent only if failure in DNCompleteSendConnectInfo()
* 07/26/00 mjn DNPerformSPListen() fails if no valid device adapters
* 07/26/00 mjn Fixed locking problem with CAsyncOp::MakeChild()
* 07/28/00 mjn Added code to track send queue info on CConnection
* 07/29/00 mjn Use DNUserConnectionTerminated() rather than DN_TerminateSession()
* mjn Added HRESULT to DNUserReturnBuffer()
* mjn Added fUseCachedCaps to DN_SPEnsureLoaded()
* 07/30/00 mjn Use DNUserTerminateSession() rather than DNUserConnectionTerminated()
* 07/31/00 mjn Removed DN_MSG_INTERNAL_HOST_DESTROY_PLAYER
* 07/31/00 mjn Change DN_MSG_INTERNAL_DELETE_PLAYER to DN_MSG_INTERNAL_DESTROY_PLAYER
* 08/02/00 mjn Added dwFlags to DNReceiveUserData()
* 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
* 08/05/00 mjn Added pParent to DNSendGroupMessage and DNSendMessage()
* mjn Ensure cancelled operations don't proceed
* mjn Added m_bilinkActiveList to CAsyncOp
* mjn Added fInternal to DNPerformChildSend()
* mjn Removed DN_TerminateAllListens()
* mjn Added DNProcessFailedRequest()
* mjn Added DNCompleteRequest()
* 08/07/00 mjn Added code to handle peer-peer integrity checking
* 08/08/00 mjn Perform LISTENs on worker thread in DNPerformNextListen()
* 08/14/00 mjn Handle failed LISTENs in DNPerformListen()
* 08/15/00 mjn Changed registration with DPNSVR
* mjn Allow NULL CConnection object pointer for DNPerformRequest()
* 08/20/00 mjn Removed fUseCachedCaps from DN_SPEnsureLoaded()
* 08/24/00 mjn Replace DN_NAMETABLE_OP with CNameTableOp
* mjn DN_MSG_INTERNAL_INSTRUCT_CONNECT gets routed through DNNTAddOperation() in DNProcessInternalOperation()
* 08/31/00 mjn Release DirectNetLock for failure cases in DNPerformRequest()
* 09/04/00 mjn Added CApplicationDesc
* 09/06/00 mjn Fixed register with DPNSVR problem
* 09/14/2000 rmt Bug #44625: DPLAY8: CORE: Multihomed machines cannot always be enumerated
* Moved registration to after point where listen completes.
* 09/14/00 mjn AddRef Protocol refcount when invoking protocol
* 09/21/00 mjn Allow NULL CConnection in DNPerformDisconnect()
* 09/23/00 mjn Added CSyncEvent to DN_LISTEN_OP_DATA
* 09/27/00 mjn Inform lobby of successfull connects from DNCompleteConnectOperation()
* 10/11/00 mjn Save protocol handle on AsyncOp earlier in DNPerformListen()
* mjn Clean up DirectNet object in failure cases in DNCompleteConnectToHost() and DNCompleteSendConnectInfo()
* 10/17/00 mjn Fixed clean up for unreachable players
* 12/11/00 mjn Added verification of internal messages
* 01/10/01 mjn DNCompleteUserConnect() cancels ENUMs with DPNERR_CONNECTING
* 01/22/01 mjn Set connection as INVALID in DNPerformDisconnect()
* 01/25/01 mjn Fixed 64-bit alignment problem in received messages
* 01/30/00 mjn Avoid sending requests during host migration in DNPerformRequest()
* 02/11/01 mjn Allow complete on process requests during host migration in DNPerformRequest()
* mjn Fixed CConnection::GetEndPt() to track calling thread
* 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's
* 04/05/01 mjn Added DPNID parameter to DNProcessHostMigration3()
* 04/11/01 mjn Propegate LISTEN flags from listen parents in DNPerformSPListen() and DNPerformListen()
* 04/13/01 mjn Add requests to the request list in DNPerformRequest()
* Remove requests from request list in DNCompleteSendRequest() and DNReceiveCompleteOnProcessReply()
* 05/07/01 vpo Whistler 384350: "DPLAY8: CORE: Messages from server can be indicated before connect completes"
* 05/11/01 mjn Ensure sends not canceled before storing protocol handle in DNSendMessage()
* 05/14/01 mjn Fix client error handling when completing connect if server not available
* 05/17/01 mjn Track number of threads performing NameTable operations
* 05/22/01 mjn Properly set DirectNetObject as CONNECTED for successful client connect
* 05/23/01 mjn Prevent LISTEN's from being cancelled before completing in DNPerformListen()
* 06/03/01 mjn Make DISCONNECT's children of failed connect's in DNPerformDisconnect()
* 06/08/01 mjn Disconnect connection to host if connect was rejected in DNConnectToHostFailed()
* 07/22/01 mjn Added DPNBUILD_NOHOSTMIGRATE compile flag
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dncorei.h"
#undef DPF_MODNAME
#define DPF_MODNAME "DNCreateUserHandle"
HRESULT DNCreateUserHandle(DIRECTNETOBJECT *const pdnObject,
CAsyncOp **const ppAsyncOp)
{
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
DPNHANDLE handle;
DPFX(DPFPREP, 6,"Parameters: ppAsyncOp [0x%p]",ppAsyncOp);
DNASSERT(pdnObject != NULL);
DNASSERT(ppAsyncOp != NULL);
pAsyncOp = NULL;
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_USER_HANDLE );
pAsyncOp->MakeParent();
if ((hResultCode = pdnObject->HandleTable.Create(pAsyncOp, &handle)) != DPN_OK)
{
DPFERR("Could not create Handle");
DisplayDNError(0,hResultCode);
goto Failure;
}
else
{
// Add a reference for the HandleTable
pAsyncOp->AddRef();
pAsyncOp->Lock();
pAsyncOp->SetHandle(handle);
pAsyncOp->Unlock();
}
pAsyncOp->AddRef();
*ppAsyncOp = pAsyncOp;
pAsyncOp->Release();
pAsyncOp = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx] (handle = 0x%p)",hResultCode,*ppAsyncOp);
return(hResultCode);
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
goto Exit;
}
#ifndef DPNBUILD_ONLYONEADAPTER
// DNEnumAdapterGuids
//
// Generate a list of adapter GUIDs for multiple ENUMs,LISTENs,CONNECTs
#undef DPF_MODNAME
#define DPF_MODNAME "DNEnumAdapterGuids"
HRESULT DNEnumAdapterGuids(DIRECTNETOBJECT *const pdnObject,
GUID *const pguidSP,
const DWORD dwMatchFlags,
GUID **const ppAdapterList,
DWORD *const pdwNumAdapters)
{
HRESULT hResultCode;
GUID *pguid;
DWORD dw;
DWORD dwAdapterBufferSize;
DWORD dwAdapterBufferCount;
DWORD dwNumAdapters;
void *pvAdapterBuffer;
void *pvBlock;
DPN_SERVICE_PROVIDER_INFO *pSPInfo;
DPFX(DPFPREP, 6,"Parameters: pguidSP [0x%p], dwMatchFlags [0x%x], ppAdapterList [0x%p], pdwNumAdapters [0x%p]",
pguidSP,dwMatchFlags,ppAdapterList,pdwNumAdapters);
DNASSERT(pdnObject != NULL);
DNASSERT(ppAdapterList != NULL);
DNASSERT(pdwNumAdapters != NULL);
pvBlock = NULL;
pvAdapterBuffer = NULL;
dwAdapterBufferSize = 0;
dwAdapterBufferCount = 0;
dwNumAdapters = 0;
hResultCode = DN_EnumAdapters( pdnObject,
0,
pguidSP,
NULL,
reinterpret_cast<DPN_SERVICE_PROVIDER_INFO*>(pvAdapterBuffer),
&dwAdapterBufferSize,
&dwAdapterBufferCount);
if ((hResultCode == DPNERR_BUFFERTOOSMALL) && (dwAdapterBufferSize > 0))
{
if ((pvAdapterBuffer = DNMalloc(dwAdapterBufferSize)) == NULL)
{
DPFERR("Could not allocate space for adapter list");
hResultCode = DPNERR_OUTOFMEMORY;
goto Failure;
}
if ((pvBlock = MemoryBlockAlloc(pdnObject,dwAdapterBufferCount * sizeof(GUID))) == NULL)
{
DPFERR("Could not allocate MemoryBlock");
hResultCode = DPNERR_OUTOFMEMORY;
goto Failure;
}
pguid = reinterpret_cast<GUID*>(pvBlock);
hResultCode = DN_EnumAdapters( pdnObject,
0,
pguidSP,
NULL,
reinterpret_cast<DPN_SERVICE_PROVIDER_INFO*>(pvAdapterBuffer),
&dwAdapterBufferSize,
&dwAdapterBufferCount);
if (hResultCode != DPN_OK)
{
DPFERR("Could not enumerate adapters");
DisplayDNError(0,hResultCode);
goto Failure;
}
DPFX(DPFPREP, 7,"dwAdapterBufferCount [%ld]",dwAdapterBufferCount);
pSPInfo = reinterpret_cast<DPN_SERVICE_PROVIDER_INFO*>(pvAdapterBuffer);
for ( dw = 0 ; dw < dwAdapterBufferCount ; dw++ )
{
static const GUID InvalidGuid = { 0 };
if (!memcmp(&InvalidGuid,&pSPInfo->guid,sizeof(GUID)))
{
DPFX(DPFPREP, 1,"Ignoring invalid adapter GUID %u.",dw);
pSPInfo++;
continue;
}
if ((dwMatchFlags != 0) && (! (pSPInfo->dwFlags & dwMatchFlags)))
{
DPFX(DPFPREP, 1,"Ignoring adapter %u with invalid flags (0x%x doesn't match 0x%x).",dw,pSPInfo->dwFlags,dwMatchFlags);
pSPInfo++;
continue;
}
memcpy(pguid,&pSPInfo->guid,sizeof(GUID));
pguid++;
dwNumAdapters++;
pSPInfo++;
}
DNFree(pvAdapterBuffer);
pvAdapterBuffer = NULL;
DPFX(DPFPREP, 7,"Number of adapters [%ld]",dwNumAdapters);
}
*pdwNumAdapters = dwNumAdapters;
*ppAdapterList = reinterpret_cast<GUID*>(pvBlock);
pvBlock = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pvBlock)
{
MemoryBlockFree(pdnObject,pvBlock);
pvBlock = NULL;
}
if (pvAdapterBuffer)
{
DNFree(pvAdapterBuffer);
pvAdapterBuffer = NULL;
}
goto Exit;
}
#endif // ! DPNBUILD_ONLYONEADAPTER
// DNPerformSPListen
//
// LISTEN on a particular SP
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformSPListen"
HRESULT DNPerformSPListen(DIRECTNETOBJECT *const pdnObject,
IDirectPlay8Address *const pDeviceAddr,
CAsyncOp *const pListenParent,
CAsyncOp **const ppParent)
{
HRESULT hResultCode;
CAsyncOp *pParent;
#ifndef DPNBUILD_ONLYONESP
GUID guidSP;
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
GUID guidAdapter;
BOOL fEnumAdapters;
DWORD dwMatchFlags;
#endif // ! DPNBUILD_ONLYONEADAPTER
DPN_SP_CAPS dnSPCaps;
CServiceProvider *pSP;
CSyncEvent *pSyncEvent;
DPFX(DPFPREP, 6,"Parameters: pDeviceAddr [0x%p], pListenParent [0x%p], ppParent [0x%p]",
pDeviceAddr,pListenParent,ppParent);
DNASSERT(pdnObject != NULL);
pParent = NULL;
pSP = NULL;
pSyncEvent = NULL;
#if ((defined(DPNBUILD_ONLYONESP)) && (defined(DPNBUILD_LIBINTERFACE)))
DNASSERT(pdnObject->pOnlySP != NULL);
pdnObject->pOnlySP->AddRef();
pSP = pdnObject->pOnlySP;
#else // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
#ifndef DPNBUILD_ONLYONESP
//
// Extract SP guid as we will probably need it
//
if ((hResultCode = IDirectPlay8Address_GetSP(pDeviceAddr,&guidSP)) != DPN_OK)
{
DPFERR("SP not specified in Device address");
DisplayDNError(0,hResultCode);
goto Failure;
}
#endif // ! DPNBUILD_ONLYONESP
//
// Ensure SP specified in Device address is loaded
//
hResultCode = DN_SPEnsureLoaded(pdnObject,
#ifndef DPNBUILD_ONLYONESP
&guidSP,
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_LIBINTERFACE
NULL,
#endif // ! DPNBUILD_LIBINTERFACE
&pSP);
if (hResultCode != DPN_OK)
{
DPFERR("Could not ensure SP is loaded!" );
DisplayDNError(0,hResultCode);
goto Failure;
}
#endif // ! DPNBUILD_ONLYONESP or ! DPNBUILD_LIBINTERFACE
//
// Get SP caps (to later see if we can ENUM on all adapters)
//
if ((hResultCode = DNGetActualSPCaps(pSP,&dnSPCaps)) != DPN_OK)
{
DPFERR("Could not get SP caps");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Create a parent op for LISTENs on this SP
//
if ((hResultCode = AsyncOpNew(pdnObject,&pParent)) != DPN_OK)
{
DPFERR("Could not create SP parent listen op");
DisplayDNError(0,hResultCode);
goto Failure;
}
pParent->SetOpType( pListenParent->GetOpType() );
pParent->SetCompletion( DNCompleteListen );
pParent->SetOpFlags( pListenParent->GetOpFlags() );
pParent->MakeParent();
if (pListenParent)
{
pListenParent->Lock();
if (pListenParent->IsCancelled())
{
pListenParent->Unlock();
pParent->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pParent->MakeChild( pListenParent );
pListenParent->Unlock();
}
//
// Set SP on parent
//
pParent->SetSP( pSP );
#ifndef DPNBUILD_ONLYONEADAPTER
//
// If there is no adapter specified in the device address,
// we will attempt to enum on each individual adapter if the SP supports it
//
fEnumAdapters = FALSE;
dwMatchFlags = 0;
if ((hResultCode = IDirectPlay8Address_GetDevice( pDeviceAddr, &guidAdapter )) != DPN_OK)
{
DPFX(DPFPREP,1,"Could not determine adapter");
DisplayDNError(1,hResultCode);
if (dnSPCaps.dwFlags & DPNSPCAPS_SUPPORTSALLADAPTERS)
{
DPFX(DPFPREP, 3,"SP supports ENUMing on all adapters");
fEnumAdapters = TRUE;
#ifndef DPNBUILD_NOMULTICAST
//
// For multicast listens where the user did not specify an adapter,
// let the SP tell us which of its devices would be the best to use.
//
if (pListenParent->GetOpType() == ASYNC_OP_LISTEN_MULTICAST)
{
dwMatchFlags = DPNSPINFO_DEFAULTMULTICASTDEVICE;
}
#endif // ! DPNBUILD_NOMULTICAST
}
}
#endif // ! DPNBUILD_ONLYONEADAPTER
pSP->Release();
pSP = NULL;
#ifndef DPNBUILD_ONLYONEADAPTER
if(fEnumAdapters)
{
DWORD dwNumAdapters;
GUID *pAdapterList = NULL;;
DN_LISTEN_OP_DATA *pListenOpData = NULL;
if ((hResultCode = DNEnumAdapterGuids( pdnObject,
&guidSP,
dwMatchFlags,
&pAdapterList,
&dwNumAdapters)) != DPN_OK)
{
DPFERR("Could not enum adapters for this SP");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (dwNumAdapters == 0)
{
DPFERR("No adapters were found for this SP");
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pListenOpData = pParent->GetLocalListenOpData();
pListenOpData->dwNumAdapters = dwNumAdapters;
pListenOpData->dwCurrentAdapter = 0;
pListenOpData->dwCompleteAdapters = 0;
//
// Choose first adapter for initial LISTEN call
//
if ((hResultCode = IDirectPlay8Address_SetDevice(pDeviceAddr,pAdapterList)) != DPN_OK)
{
DPFERR("Could not set device adapter");
DisplayDNError(0,hResultCode);
MemoryBlockFree(pdnObject,pAdapterList);
goto Failure;
}
pListenOpData->dwCurrentAdapter++;
pParent->SetOpData( pAdapterList );
pAdapterList = NULL;
//
// Create a SyncEvent for multiple LISTENs
//
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
{
DPFERR("Could not create SyncEvent");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pListenOpData->pSyncEvent = pSyncEvent;
pListenOpData = NULL;
}
#endif // ! DPNBUILD_ONLYONEADAPTER
hResultCode = DNPerformListen(pdnObject,pDeviceAddr,pParent);
if (hResultCode != DPNERR_PENDING)
{
DPFERR("Could not perform LISTEN");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// If there is a SyncEvent, wait for it to be set and then return it
//
if (pSyncEvent)
{
pSyncEvent->WaitForEvent();
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
//
// Save enum frame size
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if ((pdnObject->dwMaxFrameSize == 0) || (pdnObject->dwMaxFrameSize > (dnSPCaps.dwMaxEnumPayloadSize + sizeof(DN_ENUM_QUERY_PAYLOAD))))
{
pdnObject->dwMaxFrameSize = dnSPCaps.dwMaxEnumPayloadSize + sizeof(DN_ENUM_QUERY_PAYLOAD);
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (ppParent)
{
pParent->AddRef();
*ppParent = pParent;
}
pParent->Release();
pParent = NULL;
hResultCode = DPN_OK;
Exit:
DNASSERT( pParent == NULL );
DNASSERT( pSP == NULL );
DNASSERT( pSyncEvent == NULL );
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pParent)
{
pParent->Release();
pParent = NULL;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
if (pSyncEvent)
{
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
goto Exit;
}
// DNPerformListen
//
// IDirectPlayAddress8 *pDeviceInfo
// CAsyncOp *pParent
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformListen"
HRESULT DNPerformListen(DIRECTNETOBJECT *const pdnObject,
IDirectPlay8Address *const pDeviceInfo,
CAsyncOp *const pParent)
{
HANDLE hProtocol;
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
CSyncEvent *pSyncEvent;
HRESULT hrListen;
#ifdef DBG
TCHAR DP8ABuffer[512] = {0};
DWORD DP8ASize = 512;
#endif // DBG
DPFX(DPFPREP, 6,"Parameters: pDeviceInfo [0x%p], pParent [0x%p]",pDeviceInfo,pParent);
DNASSERT(pdnObject != NULL);
DNASSERT(pParent != NULL);
hProtocol = NULL;
pAsyncOp = NULL;
pSyncEvent = NULL;
// Try an initial check (might get lucky :)
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR("Not initialized");
return(DPNERR_UNINITIALIZED);
}
#ifdef DBG
IDirectPlay8Address_GetURL(pDeviceInfo,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 7,"Device Info [%s]",DP8ABuffer);
#endif // DBG
//
// Set up for LISTEN
//
// HRESULT
hrListen = DPNERR_GENERIC;
// SyncEvent
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
{
DPFERR("Could not create SyncEvent");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
//
// Async op for LISTEN
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pAsyncOp->SetOpType( pParent->GetOpType() );
pAsyncOp->SetSyncEvent(pSyncEvent);
pAsyncOp->SetResultPointer( &hrListen );
//
// We will set the LISTEN as not cancellable (part of our contract with the Protocol)
// We will set it as cancellable if the LISTEN completes successfully.
//
pAsyncOp->SetCannotCancel();
pParent->Lock();
if (pParent->IsCancelled())
{
pParent->Unlock();
pAsyncOp->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pAsyncOp->MakeChild(pParent);
pParent->Unlock();
//
// Add to active async op list
//
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.InsertBefore(&pdnObject->m_bilinkActiveList);
DNLeaveCriticalSection(&pdnObject->csActiveList);
//
// Perform LISTEN
//
pAsyncOp->AddRef();
hResultCode = DNPListen(pdnObject->pdnProtocolData,
pDeviceInfo,
pParent->GetSP()->GetHandle(),
pParent->GetOpFlags(),
static_cast<void*>(pAsyncOp),
pdnObject->ApplicationDesc.GetReservedData(),
pdnObject->ApplicationDesc.GetReservedDataSize(),
&hProtocol);
if (hResultCode != DPNERR_PENDING)
{
DPFERR("Could not Listen at Protocol layer !");
DisplayDNError(0,hResultCode);
pAsyncOp->Release();
goto Failure;
}
//
// Save Protocol handle
//
pAsyncOp->Lock();
if (pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
{
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->SetProtocolHandle(hProtocol);
pAsyncOp->Unlock();
//
// Wait for LISTEN to complete.
// DNPICompleteListen() will set pSyncEvent and hrListen.
// Clean up.
//
pSyncEvent->WaitForEvent();
pAsyncOp->SetSyncEvent(NULL);
pAsyncOp->SetResultPointer(NULL);
if (hrListen != DPN_OK)
{
DPFERR("LISTEN did not succeed");
DisplayDNError(0,hrListen);
hResultCode = hrListen;
goto Failure;
}
pAsyncOp->Release();
pAsyncOp = NULL;
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
//
// Flag object as LISTENing
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags |= DN_OBJECT_FLAG_LISTENING;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DNASSERT( hResultCode == DPNERR_PENDING );
hResultCode = DPNERR_PENDING;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pSyncEvent)
{
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
goto Exit;
}
#ifndef DPNBUILD_ONLYONEADAPTER
// DNPerformNextListen
//
// This will attempt to perform the next LISTEN if multiple adapters were requested
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformNextListen"
HRESULT DNPerformNextListen(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp,
IDirectPlay8Address *const pDeviceAddr)
{
HRESULT hResultCode;
CAsyncOp *pParent;
DPFX(DPFPREP, 6,"Parameters: pAsyncOp [0x%p], pDeviceAddr [0x%p]",pAsyncOp,pDeviceAddr);
pParent = NULL;
pAsyncOp->Lock();
if (pAsyncOp->GetParent())
{
pAsyncOp->GetParent()->AddRef();
pParent = pAsyncOp->GetParent();
}
pAsyncOp->Unlock();
//
// If there are any LISTENs left to perform, we will move on to the next one
//
if (pParent)
{
DN_LISTEN_OP_DATA *pListenOpData;
pListenOpData = pParent->GetLocalListenOpData();
if ((pListenOpData->dwCurrentAdapter < pListenOpData->dwNumAdapters) && pParent->GetOpData())
{
GUID *pguid;
CWorkerJob *pWorkerJob;
pguid = reinterpret_cast<GUID*>(pParent->GetOpData());
pguid += pListenOpData->dwCurrentAdapter;
if ((hResultCode = IDirectPlay8Address_SetDevice(pDeviceAddr,pguid)) != DPN_OK)
{
DPFERR("Could not set device for next adapter");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pListenOpData->dwCurrentAdapter++;
//
// Perform LISTEN on worker thread
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
{
DPFERR("Could not create WorkerJob");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pWorkerJob->SetJobType( WORKER_JOB_PERFORM_LISTEN );
pWorkerJob->SetAddress( pDeviceAddr );
pWorkerJob->SetAsyncOp( pParent );
DNQueueWorkerJob(pdnObject,pWorkerJob);
}
pParent->Release();
pParent = NULL;
}
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pParent)
{
pParent->Release();
pParent = NULL;
}
goto Exit;
}
#endif // ! DPNBUILD_ONLYONEADAPTER
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteListen"
void DNCompleteListen(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
#ifndef DPNBUILD_ONLYONEADAPTER
memset( pAsyncOp->GetLocalListenOpData(),0x00,sizeof(DN_LISTEN_OP_DATA) );
#endif // ! DPNBUILD_ONLYONEADAPTER
if (pAsyncOp->GetOpData() != NULL)
{
MemoryBlockFree(pdnObject,pAsyncOp->GetOpData());
pAsyncOp->SetOpData( NULL );
}
if (pAsyncOp->IsChild())
{
DNASSERT(pAsyncOp->GetParent() != NULL);
pAsyncOp->Orphan();
}
else
{
if (pAsyncOp->IsParent())
{
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_LISTENING);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
}
}
// DNPerformEnumQuery
//
// Initiate an ENUM and take care of the book keeping
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformEnumQuery"
HRESULT DNPerformEnumQuery(DIRECTNETOBJECT *const pdnObject,
IDirectPlay8Address *const pHost,
IDirectPlay8Address *const pDevice,
const HANDLE hSPHandle,
const DWORD dwFlags,
void *const pvContext,
CAsyncOp *const pParent)
{
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
HANDLE hProtocol;
DN_ENUM_QUERY_OP_DATA *pEnumQueryOpData;
DPFX(DPFPREP, 6,"Parameters: pHost [0x%p], pDevice [0x%p], hSPHandle [0x%p], dwFlags [0x%x], pvContext [0x%p], pParent [0x%p]",
pHost,pDevice,hSPHandle,dwFlags,pvContext,pParent);
DNASSERT(pdnObject != NULL);
DNASSERT(hSPHandle != NULL);
pAsyncOp = NULL;
//
// Create AsyncOp for ENUM
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_ENUM_QUERY );
pAsyncOp->SetResult( DPNERR_GENERIC );
pAsyncOp->SetCompletion( DNCompleteEnumQuery );
pAsyncOp->SetContext( pvContext );
DNASSERT(pParent != NULL);
pParent->Lock();
if (pParent->IsCancelled())
{
pParent->Unlock();
pAsyncOp->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pAsyncOp->MakeChild(pParent);
pParent->Unlock();
pEnumQueryOpData = pParent->GetLocalEnumQueryOpData();
//
// Add to active AsyncOp list
//
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.InsertBefore(&pdnObject->m_bilinkActiveList);
DNLeaveCriticalSection(&pdnObject->csActiveList);
//
// AddRef Protocol so that it won't go away until this completes
//
DNProtocolAddRef(pdnObject);
pAsyncOp->AddRef();
hResultCode = DNPEnumQuery(pdnObject->pdnProtocolData,
pHost,
pDevice,
hSPHandle,
&pEnumQueryOpData->BufferDesc[DN_ENUM_BUFFERDESC_QUERY_DN_PAYLOAD],
pEnumQueryOpData->dwBufferCount,
pEnumQueryOpData->dwRetryCount, // count of enumerations to send
pEnumQueryOpData->dwRetryInterval, // interval between enumerations
pEnumQueryOpData->dwTimeOut, // linger time after last enumeration is sent
dwFlags,
reinterpret_cast<void*>(pAsyncOp),
((pEnumQueryOpData->dwAppDescReservedDataSize > 0) ? pEnumQueryOpData->AppDescReservedData : NULL),
pEnumQueryOpData->dwAppDescReservedDataSize,
&hProtocol);
if ( hResultCode != DPNERR_PENDING )
{
DPFERR( "Failed to start enuming!" );
pAsyncOp->Release();
DNProtocolRelease(pdnObject);
goto Failure;
}
//
// Setup for proper clean-up
//
pAsyncOp->Lock();
if (pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
{
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->SetProtocolHandle( hProtocol );
pAsyncOp->Unlock();
pAsyncOp->Release();
pAsyncOp = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
pAsyncOp->Release();
pAsyncOp = NULL;
}
goto Exit;
}
// DNPerformNextEnumQuery
//
// This will attempt to perform the next ENUM if multiple adapters were requested
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformNextEnumQuery"
HRESULT DNPerformNextEnumQuery(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp,
IDirectPlay8Address *const pHostAddr,
IDirectPlay8Address *const pDeviceAddr)
{
HRESULT hResultCode;
CAsyncOp *pParent;
DPFX(DPFPREP, 6,"Parameters: pAsyncOp [0x%p], pHostAddr [0x%p], pDeviceAddr [0x%p]",pAsyncOp,pHostAddr,pDeviceAddr);
pParent = NULL;
pAsyncOp->Lock();
if (pAsyncOp->GetParent())
{
pAsyncOp->GetParent()->AddRef();
pParent = pAsyncOp->GetParent();
}
pAsyncOp->Unlock();
//
// If there are any ENUMs left to perform, we will move on to the next one
//
if (pParent)
{
#ifndef DPNBUILD_ONLYONEADAPTER
DN_ENUM_QUERY_OP_DATA *pEnumQueryOpData;
pEnumQueryOpData = pParent->GetLocalEnumQueryOpData();
if ((pEnumQueryOpData->dwCurrentAdapter < pEnumQueryOpData->dwNumAdapters) && pParent->GetOpData())
{
GUID *pguid;
DWORD dwMultiplexFlag;
pguid = reinterpret_cast<GUID*>(pParent->GetOpData());
pguid += pEnumQueryOpData->dwCurrentAdapter;
if ((hResultCode = IDirectPlay8Address_SetDevice(pDeviceAddr,pguid)) != DPN_OK)
{
DPFERR("Could not set device for next adapter");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pEnumQueryOpData->dwCurrentAdapter++;
if (pEnumQueryOpData->dwCurrentAdapter < pEnumQueryOpData->dwNumAdapters)
{
dwMultiplexFlag = DN_ENUMQUERYFLAGS_ADDITIONALMULTIPLEXADAPTERS;
}
else
{
dwMultiplexFlag = 0;
}
hResultCode = DNPerformEnumQuery( pdnObject,
pHostAddr,
pDeviceAddr,
pParent->GetSP()->GetHandle(),
pParent->GetOpFlags() | dwMultiplexFlag,
pParent->GetContext(),
pParent );
if (hResultCode != DPN_OK)
{
DPFERR("Could not start ENUM");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
#endif // ! DPNBUILD_ONLYONEADAPTER
pParent->Release();
pParent = NULL;
}
hResultCode = DPN_OK;
#ifndef DPNBUILD_ONLYONEADAPTER
Exit:
#endif // ! DPNBUILD_ONLYONEADAPTER
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
#ifndef DPNBUILD_ONLYONEADAPTER
Failure:
if (pParent)
{
pParent->Release();
pParent = NULL;
}
goto Exit;
#endif // ! DPNBUILD_ONLYONEADAPTER
}
// DNCompleteEnumQuery
//
// Completion for AsyncOps for EnumQuery.
// This will:
// - free up the EnumQuery memory block associated with this AsyncOp
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteEnumQuery"
void DNCompleteEnumQuery(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
memset(pAsyncOp->GetLocalEnumQueryOpData(),0x00,sizeof(DN_ENUM_QUERY_OP_DATA));
if (pAsyncOp->GetOpData())
{
MemoryBlockFree(pdnObject,pAsyncOp->GetOpData());
pAsyncOp->SetOpData( NULL );
}
if ( pAsyncOp->IsChild() )
{
DNASSERT(pAsyncOp->GetParent() != NULL);
pAsyncOp->GetParent()->Lock();
//
// Save HRESULT
//
if (pAsyncOp->GetParent()->GetResult() != DPN_OK)
{
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
}
//
// Release parent Handle if it exists
//
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pAsyncOp->GetParent()->GetHandle(), NULL )))
{
// Release the HandleTable reference
pAsyncOp->GetParent()->Release();
}
pAsyncOp->GetParent()->Unlock();
}
}
// DNCompleteEnumResponse
//
// Completion for AsyncOps for EnumResponse.
// This will:
// - generate a RETURN_BUFFER message if there was a user payload
// - free up the EnumResponse memory block associated with this AsyncOp
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteEnumResponse"
void DNCompleteEnumResponse(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DN_ENUM_RESPONSE_OP_DATA *pEnumResponseOpData;
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
pEnumResponseOpData = pAsyncOp->GetLocalEnumResponseOpData();
if (pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].pBufferData != NULL)
{
DNUserReturnBuffer( pdnObject,
DPN_OK,
pEnumResponseOpData->BufferDesc[DN_ENUM_BUFFERDESC_RESPONSE_USER_PAYLOAD].pBufferData,
pEnumResponseOpData->pvUserContext);
}
memset(pEnumResponseOpData,0x00,sizeof(DN_ENUM_RESPONSE_OP_DATA));
}
// DNPerformConnect
//
// Initiate a connection and take care of the book keeping (create handle).
//
// DPNID dpnid Target player (for ExistingPlayers connect calls)
// IDirectPlayAddress8 *pDeviceInfo (may be NULL - no connect performed)
// IDirectPlayAddress8 *pRemoteAddr (may be NULL - no connect performed)
// DWORD dwFlags CONNECT op flags
// CAsyncOp *pParent Parent Async Op (if it exists)
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformConnect"
HRESULT DNPerformConnect(DIRECTNETOBJECT *const pdnObject,
const DPNID dpnid,
IDirectPlay8Address *const pDeviceInfo,
IDirectPlay8Address *const pRemoteAddr,
CServiceProvider *const pSP,
const DWORD dwConnectFlags,
CAsyncOp *const pParent)
{
HANDLE hProtocol;
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
#ifdef DBG
TCHAR DP8ABuffer[512] = {0};
DWORD DP8ASize;
#endif // DBG
DPFX(DPFPREP, 6,"Parameters: dpnid [0x%p], pDeviceInfo [0x%p], pRemoteAddr [0x%p], dwConnectFlags [0x%lx], pParent [0x%p]",
dpnid,pDeviceInfo,pRemoteAddr,dwConnectFlags,pParent);
DNASSERT(pdnObject != NULL);
DNASSERT(pDeviceInfo != NULL);
DNASSERT(pRemoteAddr != NULL);
DNASSERT(pSP != NULL);
pAsyncOp = NULL;
#ifdef DBG
DP8ASize = 512;
IDirectPlay8Address_GetURL(pRemoteAddr,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 7,"Remote Address [%s]",DP8ABuffer);
DP8ASize = 512;
IDirectPlay8Address_GetURL(pDeviceInfo,DP8ABuffer,&DP8ASize);
DPFX(DPFPREP, 7,"Device Info [%s]",DP8ABuffer);
#endif // DBG
//
// Create AsyncOp for CONNECT
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pAsyncOp->SetDPNID( dpnid );
pAsyncOp->SetOpFlags( dwConnectFlags );
pAsyncOp->SetSP(pSP);
pAsyncOp->SetResult( DPNERR_NOCONNECTION );
pAsyncOp->SetCompletion( DNCompleteConnect );
if (pParent)
{
pAsyncOp->SetOpType( pParent->GetOpType() );
pParent->Lock();
if (pParent->IsCancelled())
{
pParent->Unlock();
pAsyncOp->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pAsyncOp->MakeChild(pParent);
pParent->Unlock();
}
else
{
//
// Assume it's a regular connect.
//
pAsyncOp->SetOpType( ASYNC_OP_CONNECT );
}
//
// Add to active async op list
//
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.InsertBefore(&pdnObject->m_bilinkActiveList);
DNLeaveCriticalSection(&pdnObject->csActiveList);
//
// AddRef Protocol so that it won't go away until this completes
//
DNProtocolAddRef(pdnObject);
//
// Perform CONNECT
//
DPFX(DPFPREP, 7,"Performing connect");
pAsyncOp->AddRef();
hResultCode = DNPConnect( pdnObject->pdnProtocolData,
pDeviceInfo,
pRemoteAddr,
pSP->GetHandle(),
dwConnectFlags,
pAsyncOp,
pdnObject->ApplicationDesc.GetReservedData(),
pdnObject->ApplicationDesc.GetReservedDataSize(),
&hProtocol);
if (hResultCode != DPNERR_PENDING)
{
DPFERR("Could not CONNECT");
DisplayDNError(0,hResultCode);
pAsyncOp->Release();
DNProtocolRelease(pdnObject);
goto Failure;
}
pAsyncOp->Lock();
if (pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
{
HRESULT hrCancel;
pAsyncOp->Unlock();
DPFX(DPFPREP, 7,"Operation marked for cancel");
if ((hrCancel = DNPCancelCommand(pdnObject->pdnProtocolData,hProtocol)) == DPN_OK)
{
//
// If the parent has DPN_OK, then another connect succeeded and we don't want to fail.
// This may happen in a dual (or more) adapter case.
//
if (pParent && pParent->GetResult() == DPN_OK)
{
hResultCode = DPN_OK;
}
else
{
hResultCode = DPNERR_USERCANCEL;
}
goto Failure;
}
DPFERR("Could not cancel operation");
DisplayDNError(0,hrCancel);
pAsyncOp->Lock();
}
pAsyncOp->SetProtocolHandle(hProtocol);
pAsyncOp->Unlock();
pAsyncOp->Release();
pAsyncOp = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
pAsyncOp->Release();
pAsyncOp = NULL;
}
goto Exit;
}
// DNPerformNextConnect
//
// This will attempt to perform the next CONNECT if multiple adapters were requested
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformNextConnect"
HRESULT DNPerformNextConnect(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp,
IDirectPlay8Address *const pHostAddr,
IDirectPlay8Address *const pDeviceAddr)
{
HRESULT hResultCode;
CAsyncOp *pParent;
DPFX(DPFPREP, 6,"Parameters: pAsyncOp [0x%p], pHostAddr [0x%p], pDeviceAddr [0x%p]",pAsyncOp,pHostAddr,pDeviceAddr);
pParent = NULL;
pAsyncOp->Lock();
if (pAsyncOp->GetParent())
{
pAsyncOp->GetParent()->AddRef();
pParent = pAsyncOp->GetParent();
}
pAsyncOp->Unlock();
//
// If there are any CONNECTs left to perform, we will move on to the next one
//
if (pParent)
{
#ifndef DPNBUILD_ONLYONEADAPTER
DN_CONNECT_OP_DATA *pConnectOpData;
pConnectOpData = pParent->GetLocalConnectOpData();
if ((pConnectOpData->dwCurrentAdapter < pConnectOpData->dwNumAdapters) && pParent->GetOpData())
{
GUID *pguid;
DWORD dwMultiplexFlag;
pguid = reinterpret_cast<GUID*>(pParent->GetOpData());
pguid += pConnectOpData->dwCurrentAdapter;
if ((hResultCode = IDirectPlay8Address_SetDevice(pDeviceAddr,pguid)) != DPN_OK)
{
DPFERR("Could not set device for next adapter");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pConnectOpData->dwCurrentAdapter++;
if (pConnectOpData->dwCurrentAdapter < pConnectOpData->dwNumAdapters)
{
dwMultiplexFlag = DN_CONNECTFLAGS_ADDITIONALMULTIPLEXADAPTERS;
}
else
{
dwMultiplexFlag = 0;
}
if ((hResultCode = DNPerformConnect(pdnObject,
NULL,
pDeviceAddr,
pHostAddr,
pParent->GetSP(),
pParent->GetOpFlags() | dwMultiplexFlag,
pParent)) != DPN_OK)
{
DPFERR("Could not perform CONNECT");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
#endif // ! DPNBUILD_ONLYONEADAPTER
pParent->Release();
pParent = NULL;
}
hResultCode = DPN_OK;
#ifndef DPNBUILD_ONLYONEADAPTER
Exit:
#endif // ! DPNBUILD_ONLYONEADAPTER
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
#ifndef DPNBUILD_ONLYONEADAPTER
Failure:
if (pParent)
{
pParent->Release();
pParent = NULL;
}
goto Exit;
#endif // ! DPNBUILD_ONLYONEADAPTER
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteConnect"
void DNCompleteConnect(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
//
// Save the result code on the parent if it hasn't already been set (DPN_OK or DPNERR_HOSTREJECTEDCONNECTION)
//
if (pAsyncOp->GetParent() && (pAsyncOp->GetResult() != DPNERR_NOCONNECTION))
{
pAsyncOp->GetParent()->Lock();
if ((pAsyncOp->GetParent()->GetResult() != DPN_OK)
&& (pAsyncOp->GetParent()->GetResult() != DPNERR_HOSTREJECTEDCONNECTION))
{
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
}
pAsyncOp->GetParent()->Unlock();
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteConnectToHost"
void DNCompleteConnectToHost(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
//
// Save the result code on the parent if there was a problem (this should be the connect operation parent)
//
if ((pAsyncOp->GetResult() != DPN_OK) && (pAsyncOp->GetResult() != DPNERR_NOCONNECTION))
{
if (pAsyncOp->GetParent())
{
pAsyncOp->GetParent()->Lock();
if ((pAsyncOp->GetParent()->GetResult() != DPN_OK) && (pAsyncOp->GetParent()->GetResult() != DPNERR_HOSTREJECTEDCONNECTION))
{
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
}
pAsyncOp->GetParent()->Unlock();
}
}
//
// Clean up DirectNet object if this fails
//
if (pAsyncOp->GetResult() != DPN_OK)
{
CAsyncOp *pConnectParent;
pConnectParent = NULL;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_CONNECTED
| DN_OBJECT_FLAG_CONNECTING
| DN_OBJECT_FLAG_HOST_CONNECTED));
if (pdnObject->pConnectParent)
{
pConnectParent = pdnObject->pConnectParent;
pdnObject->pConnectParent = NULL;
}
if( pdnObject->pIDP8ADevice )
{
IDirectPlay8Address_Release( pdnObject->pIDP8ADevice );
pdnObject->pIDP8ADevice = NULL;
}
if( pdnObject->pConnectAddress )
{
IDirectPlay8Address_Release( pdnObject->pConnectAddress );
pdnObject->pConnectAddress = NULL;
}
if( pdnObject->pConnectSP )
{
pdnObject->pConnectSP->Release();
pdnObject->pConnectSP = NULL;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pConnectParent)
{
pConnectParent->Release();
pConnectParent = NULL;
}
DNASSERT(pConnectParent == NULL);
}
//
// Clean up CONNECT op data
//
#ifndef DPNBUILD_ONLYONEADAPTER
memset( pAsyncOp->GetLocalConnectOpData(),0x00,sizeof(DN_CONNECT_OP_DATA) );
#endif // ! DPNBUILD_ONLYONEADAPTER
if (pAsyncOp->GetOpData() != NULL)
{
MemoryBlockFree(pdnObject,pAsyncOp->GetOpData());
pAsyncOp->SetOpData( NULL );
}
//
// Detach from parent
// I'm not sure why we need to do this !
//
DNASSERT(pAsyncOp->IsChild());
DNASSERT(pAsyncOp->GetParent());
pAsyncOp->Orphan();
}
//
// Completion for connect parent
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteConnectOperation"
void DNCompleteConnectOperation(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
//
// Save the result code on the parent (if it exists - it will be the CONNECT handle)
//
if (pAsyncOp->GetParent())
{
pAsyncOp->GetParent()->Lock();
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
pAsyncOp->GetParent()->SetRefCountBuffer( pAsyncOp->GetRefCountBuffer() );
pAsyncOp->GetParent()->Unlock();
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pAsyncOp->GetParent()->GetHandle(), NULL )))
{
// Release the HandleTable reference
pAsyncOp->GetParent()->Release();
}
}
//
// If the OpData of this AsyncOp is set it is a pointer to a RefCountBuffer pointer
// (sync connect call) and we will fill it in
//
if (pAsyncOp->GetOpData())
{
if (pAsyncOp->GetRefCountBuffer())
{
pAsyncOp->GetRefCountBuffer()->AddRef();
*(static_cast<CRefCountBuffer**>(pAsyncOp->GetOpData())) = pAsyncOp->GetRefCountBuffer();
}
pAsyncOp->SetOpData( NULL );
}
#ifndef DPNBUILD_NOLOBBY
//
// If this connect succeeded, we will inform the lobby
//
if (pAsyncOp->GetResult() == DPN_OK)
{
DNUpdateLobbyStatus(pdnObject,DPLSESSION_CONNECTED);
}
else
{
DNUpdateLobbyStatus(pdnObject,DPLSESSION_COULDNOTCONNECT);
}
#endif // ! DPNBUILD_NOLOBBY
//
// Clear DISCONNECTING flag (in case this was aborted)
//
DPFX(DPFPREP, 8,"Clearing DISCONNECTING flag");
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_DISCONNECTING);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
//
// Completion for connect handle given to user if Connect was called asynchronously
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteUserConnect"
void DNCompleteUserConnect(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
CNameTableEntry *pHostPlayer;
pHostPlayer = NULL;
//
// No longer connecting
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Clients need to release all sends from the server that are
// queued once the CONNECT_COMPLETE gets indicated.
// We prepare to do that now.
//
if ((pAsyncOp->GetResult() == DPN_OK) && (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT))
{
if (pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer ) == DPN_OK)
{
pHostPlayer->Lock();
pHostPlayer->MakeAvailable();
pHostPlayer->NotifyAddRef();
pHostPlayer->SetInUse();
pHostPlayer->Unlock();
//
// We are now connected
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
else
{
//
// If we couldn't get a reference on the server (host player),
// then either the server has disconnected, or we are being shut down.
// In either case, we should return an error
//
DPFX(DPFPREP, 0, "Couldn't get host player reference, failing CONNECT!");
pAsyncOp->SetResult( DPNERR_NOCONNECTION );
if (pAsyncOp->GetRefCountBuffer())
{
pAsyncOp->GetRefCountBuffer()->Release();
pAsyncOp->SetRefCountBuffer( NULL );
}
}
}
//
// Generate connect completion for player
//
DNUserConnectComplete( pdnObject,
pAsyncOp->GetHandle(),
pAsyncOp->GetContext(),
pAsyncOp->GetResult(),
pAsyncOp->GetRefCountBuffer() );
//
// Cancel ENUMs if the CONNECT succeeded and unload SP's
//
if (pAsyncOp->GetResult() == DPN_OK)
{
DNCancelActiveCommands(pdnObject,DN_CANCEL_FLAG_ENUM_QUERY,NULL,TRUE,DPNERR_CONNECTING);
#if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONESP)))
DN_SPReleaseAll(pdnObject);
#endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONESP
//
// Actually release queued messages if necessary
//
if (pHostPlayer != NULL)
{
pHostPlayer->PerformQueuedOperations();
pHostPlayer->Release();
pHostPlayer = NULL;
}
}
DNASSERT( pHostPlayer == NULL );
}
//
// Completion for NewPlayer sending connect data to the Host
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteSendConnectInfo"
void DNCompleteSendConnectInfo(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
//
// Update result of this send on the CONNECT operation parent
//
DNASSERT(pAsyncOp->GetParent() != NULL);
pAsyncOp->GetParent()->Lock();
if (pAsyncOp->GetResult() != DPN_OK)
{
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
//
// Clean up CONNECT response buffer from Host
//
if (pAsyncOp->GetParent()->GetRefCountBuffer())
{
pAsyncOp->GetParent()->GetRefCountBuffer()->Release();
pAsyncOp->GetParent()->SetRefCountBuffer( NULL );
}
}
pAsyncOp->GetParent()->Unlock();
//
// Clean up DirectNet object if this fails
//
if (pAsyncOp->GetResult() != DPN_OK)
{
CAsyncOp *pConnectParent;
pConnectParent = NULL;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_CONNECTED
| DN_OBJECT_FLAG_CONNECTING
| DN_OBJECT_FLAG_HOST_CONNECTED));
if (pdnObject->pConnectParent)
{
pConnectParent = pdnObject->pConnectParent;
pdnObject->pConnectParent = NULL;
}
if( pdnObject->pIDP8ADevice )
{
IDirectPlay8Address_Release( pdnObject->pIDP8ADevice );
pdnObject->pIDP8ADevice = NULL;
}
if( pdnObject->pConnectAddress )
{
IDirectPlay8Address_Release( pdnObject->pConnectAddress );
pdnObject->pConnectAddress = NULL;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pConnectParent)
{
pConnectParent->Release();
pConnectParent = NULL;
}
DNASSERT(pConnectParent == NULL);
}
//
// Clean up op data
//
if (pAsyncOp->GetOpData())
{
MemoryBlockFree(pdnObject,pAsyncOp->GetOpData());
pAsyncOp->SetOpData( NULL );
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformDisconnect"
HRESULT DNPerformDisconnect(DIRECTNETOBJECT *const pdnObject,
CConnection *const pConnection,
const HANDLE hEndPt,
const BOOL fImmediate)
{
HRESULT hResultCode;
HANDLE hProtocol;
CAsyncOp *pAsyncOp;
CAsyncOp *pConnectParent;
DWORD dwProtocolFlags;
DPFX(DPFPREP, 6,"Parameters: pConnection [0x%p], hEndPt [0x%lx], fImmediate [%d]",pConnection,hEndPt,fImmediate);
DNASSERT(pdnObject != NULL);
pAsyncOp = NULL;
pConnectParent = NULL;
dwProtocolFlags = 0;
if (hEndPt == NULL)
{
DPFERR("Ignoring NULL endpoint");
hResultCode = DPN_OK;
goto Failure;
}
//
// Create AsyncOp for this operation
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_DISCONNECT );
pAsyncOp->SetConnection( pConnection );
pAsyncOp->SetCannotCancel(); // Cannot cancel DISCONNECT's
//
// AddRef Protocol so that it won't go away until this completes
//
DNProtocolAddRef(pdnObject);
//
// If there is a connect parent op, and it's hResultCode is not DPN_OK,
// then a connect is failing for some reason, and to prevent it from
// completing before this disconnect is complete, we will set the connect parent
// as the parent of this disconnect.
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pConnectParent && (pdnObject->pConnectParent->GetResult() != DPN_OK))
{
pdnObject->pConnectParent->AddRef();
pConnectParent = pdnObject->pConnectParent;
}
if ((pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING_IMMEDIATE) || (fImmediate))
{
//
// If Close() was called with DPNCLOSE_IMMEDIATE then DN_OBJET_FLAG_CLOSING_IMMEDIATE will be set
// and all disconnects should be done in immediate mode
//
dwProtocolFlags |= DN_DISCONNECTFLAGS_IMMEDIATE;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pConnectParent)
{
pAsyncOp->MakeChild( pConnectParent );
pConnectParent->Release();
pConnectParent = NULL;
}
//
// Set connection as INVALID so that no other operations may use it anymore
//
pConnection->Lock();
pConnection->SetStatus( INVALID );
pConnection->Unlock();
//
// Perform DISCONNECT
//
pAsyncOp->AddRef();
hResultCode = DNPDisconnectEndPoint(pdnObject->pdnProtocolData,
hEndPt,
static_cast<void*>(pAsyncOp),
&hProtocol,
dwProtocolFlags);
if ((hResultCode != DPN_OK) && (hResultCode != DPNERR_PENDING))
{
DPFERR("Could not issue DISCONNECT");
DisplayDNError(0,hResultCode);
DNProtocolRelease(pdnObject);
pAsyncOp->Release();
goto Failure;
}
pAsyncOp->Lock();
pAsyncOp->SetProtocolHandle( hProtocol );
pAsyncOp->Unlock();
pAsyncOp->Release();
pAsyncOp = NULL;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pConnectParent)
{
pConnectParent->Release();
pConnectParent = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteAsyncHandle"
void DNCompleteAsyncHandle(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
DNUserAsyncComplete(pdnObject,
pAsyncOp->GetHandle(),
pAsyncOp->GetContext(),
pAsyncOp->GetResult() );
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteSendHandle"
void DNCompleteSendHandle(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
DNUserSendComplete( pdnObject,
pAsyncOp->GetHandle(),
pAsyncOp->GetContext(),
pAsyncOp->GetStartTime(),
pAsyncOp->GetResult(),
pAsyncOp->GetFirstFrameRTT(),
pAsyncOp->GetFirstFrameRetryCount());
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteSendAsyncOp"
void DNCompleteSendAsyncOp(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
//
// Update outstanding queue info - this is only performed on children or stand-alone ops (i.e. no parent)
//
if ( !pAsyncOp->IsParent() && (pAsyncOp->GetConnection() != NULL))
{
DN_SEND_OP_DATA *pSendOpData = NULL;
if (pAsyncOp->IsUseParentOpData())
{
if (pAsyncOp->IsChild() && pAsyncOp->GetParent())
{
pSendOpData = pAsyncOp->GetParent()->GetLocalSendOpData();
}
}
else
{
pSendOpData = pAsyncOp->GetLocalSendOpData();
}
if (pSendOpData && pSendOpData->dwMsgId == DN_MSG_USER_SEND)
{
DWORD dw;
DNASSERT( pAsyncOp->GetConnection() != NULL );
pAsyncOp->GetConnection()->Lock();
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
if (pAsyncOp->GetOpFlags() & DN_SENDFLAGS_HIGH_PRIORITY)
{
pAsyncOp->GetConnection()->RemoveFromHighQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
else if (pAsyncOp->GetOpFlags() & DN_SENDFLAGS_LOW_PRIORITY)
{
pAsyncOp->GetConnection()->RemoveFromLowQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
else
{
pAsyncOp->GetConnection()->RemoveFromNormalQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
}
pAsyncOp->GetConnection()->Unlock();
}
}
//
// Clean up
//
if (!pAsyncOp->IsUseParentOpData())
{
DN_SEND_OP_DATA *pSendOpData;
DWORD dw;
pSendOpData = pAsyncOp->GetLocalSendOpData();
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
pSendOpData->BufferDesc[dw].dwBufferSize = 0;
pSendOpData->BufferDesc[dw].pBufferData = NULL;
}
pSendOpData->dwMsgId = 0;
pSendOpData->dwNumBuffers = 0;
}
if ( pAsyncOp->IsChild() )
{
DNASSERT(pAsyncOp->GetParent() != NULL);
pAsyncOp->GetParent()->Lock();
//
// Save HRESULT. Overwrite the parent's error while it's not DPN_OK.
//
if (pAsyncOp->GetParent()->GetResult() != DPN_OK)
{
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
}
//
// Release parent Handle if it exists
//
if (pAsyncOp->GetParent()->GetOpType() == ASYNC_OP_USER_HANDLE)
{
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pAsyncOp->GetParent()->GetHandle(), NULL )))
{
// Release the HandleTable reference
pAsyncOp->GetParent()->Release();
}
}
pAsyncOp->GetParent()->Unlock();
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteRequest"
void DNCompleteRequest(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DWORD dw;
DN_SEND_OP_DATA *pSendOpData;
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
//
// Clean up op data
//
pSendOpData = pAsyncOp->GetLocalSendOpData();
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
pSendOpData->BufferDesc[dw].dwBufferSize = 0;
pSendOpData->BufferDesc[dw].pBufferData = NULL;
}
pSendOpData->dwMsgId = 0;
pSendOpData->dwNumBuffers = 0;
pSendOpData = NULL;
//
// If the parent exists, copy the result up, and then remove them from the HandleTable
//
if (pAsyncOp->GetParent() != NULL)
{
pAsyncOp->GetParent()->Lock();
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
pAsyncOp->GetParent()->Unlock();
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pAsyncOp->GetParent()->GetHandle(), NULL )))
{
// Release the HandleTable reference
pAsyncOp->GetParent()->Release();
}
}
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteSendRequest"
void DNCompleteSendRequest(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DNASSERT(pdnObject != NULL);
DNASSERT(pAsyncOp != NULL);
DNASSERT(pAsyncOp->GetParent() != NULL);
if (pAsyncOp->GetResult() != DPN_OK)
{
//
// If this operation was cancelled or was NOT internal (i.e. complete on process send)
// remove the parent (RequestChild) AsyncOp from the HandleTable and from the request list
//
if ((pAsyncOp->GetResult() == DPNERR_USERCANCEL) || !pAsyncOp->IsInternal())
{
DNASSERT(pAsyncOp->GetParent()->GetHandle() != 0);
DNASSERT(pAsyncOp->GetParent()->GetOpType() == ASYNC_OP_REQUEST);
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->GetParent()->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pAsyncOp->GetParent()->GetHandle(), NULL )))
{
// Release the HandleTable reference
pAsyncOp->GetParent()->Release();
}
}
}
else
{
//
// Mark this operation as PLAYERLOST. If we do get an operation complete message,
// this result will get overwritten.
//
pAsyncOp->GetParent()->Lock();
if (pAsyncOp->GetParent()->GetResult() == DPNERR_GENERIC)
{
pAsyncOp->GetParent()->SetResult( DPNERR_PLAYERLOST );
}
pAsyncOp->GetParent()->Unlock();
}
}
// DNSendMessage
//
// Send structured message to given endpoint. Internally generated sends have a header
// associated with them. The first few bytes of this header are a signature, indicating
// an internal message. User generated sends do not have a header, unless they contain
// the signature. In this case, the user message is escaped with a header indicating this.
//
// For internal sends:
// - Create message header (dwMsgId,dwParam1,dwParam2)
// - Send message header and supplied data buffer (lpBuffDesc)
// - Save Async Operation info to be unwound when send completes
// - If pdnCountBuffer is specified, pBuffDesc may or may not point to its contents.
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNSendMessage"
HRESULT DNSendMessage(DIRECTNETOBJECT *const pdnObject,
CConnection *const pConnection, // Connection to send to
const DWORD dwMsgId, // Message ID
const DPNID dpnidTarget, // Target of this send (may be NULL)
const DPN_BUFFER_DESC *const pdnBufferDesc, // Array of buffer desc's
const DWORD cBufferDesc, // Number of buffer desc's
CRefCountBuffer *const pRefCountBuffer, // RefCountBuffer (may be NULL)
const DWORD dwTimeOut, // Time out
const DWORD dwSendFlags, // Send flags
CAsyncOp *const pParent, // Parent of this send
CAsyncOp **const ppAsyncOp) // CAsyncOp created for this send
{
DWORD dw;
HANDLE hProtocol;
HRESULT hResultCode;
HANDLE hEndPt;
CAsyncOp *pAsyncOp;
DN_SEND_OP_DATA *pSendOpData;
CCallbackThread CallbackThread;
DWORD dwStart;
DPFX(DPFPREP, 6,"Parameters: pConnection [0x%p], dwMsgId [0x%x], dpnidTarget [0x%x], pdnBufferDesc [0x%p], cBufferDesc [%ld], pRefCountBuffer [0x%p], dwTimeOut [%ld], dwSendFlags [0x%lx], pParent [0x%p], ppAsyncOp [0x%p]",
pConnection,dwMsgId,dpnidTarget,pdnBufferDesc,cBufferDesc,pRefCountBuffer,dwTimeOut,dwSendFlags,pParent,ppAsyncOp);
DNASSERT(pdnObject != NULL);
DNASSERT(pConnection != NULL);
pAsyncOp = NULL;
pSendOpData = NULL;
CallbackThread.Initialize();
//
// Create AsyncOp for SEND
//
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_SEND );
pAsyncOp->SetDPNID( dpnidTarget );
pAsyncOp->SetRefCountBuffer( pRefCountBuffer );
pAsyncOp->SetStartTime( GETTIMESTAMP() );
if (dwMsgId & DN_MSG_INTERNAL)
{
//
// We have to set this early (before it's in the active list or a child) so that it won't
// be prematurely cancelled (before we get a chance to mark it INTERNAL).
//
pAsyncOp->SetInternal();
}
//
// Make child if parent was supplied
//
if (pParent)
{
pParent->Lock();
if (pParent->IsCancelled())
{
pParent->Unlock();
pAsyncOp->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pAsyncOp->MakeChild( pParent );
pParent->Unlock();
}
//
// Add to active async op list
//
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.InsertBefore(&pdnObject->m_bilinkActiveList);
DNLeaveCriticalSection(&pdnObject->csActiveList);
//
// Set-up SEND op data block
//
pSendOpData = pAsyncOp->GetLocalSendOpData();
pSendOpData->dwMsgId = dwMsgId;
if (dwMsgId & DN_MSG_INTERNAL)
{
#ifndef DPNBUILD_NOVOICE
if (dwMsgId == DN_MSG_INTERNAL_VOICE_SEND)
{
DNASSERT(pdnBufferDesc != NULL);
dwStart = 0;
pAsyncOp->SetOpFlags( dwSendFlags | DN_SENDFLAGS_SET_USER_FLAG | DN_SENDFLAGS_SET_USER_FLAG_TWO | DN_SENDFLAGS_COALESCE );
}
else
#endif // DPNBUILD_NOVOICE
{
pSendOpData->BufferDesc[0].pBufferData = reinterpret_cast<BYTE*>( &(pSendOpData->dwMsgId) );
pSendOpData->BufferDesc[0].dwBufferSize = sizeof( DWORD );
dwStart = 1;
pAsyncOp->SetOpFlags( dwSendFlags | DN_SENDFLAGS_SET_USER_FLAG | DN_SENDFLAGS_COALESCE );
}
}
else
{
DNASSERT(pdnBufferDesc != NULL);
dwStart = 0;
pAsyncOp->SetOpFlags( dwSendFlags );
}
for ( dw = 0 ; dw < cBufferDesc ; dw++ )
{
pSendOpData->BufferDesc[dwStart+dw].pBufferData = pdnBufferDesc[dw].pBufferData;
pSendOpData->BufferDesc[dwStart+dw].dwBufferSize = pdnBufferDesc[dw].dwBufferSize;
}
pSendOpData->dwNumBuffers = cBufferDesc + dwStart;
if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
{
DPFERR("Could not get end point from connection");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_CONNECTIONLOST; // re-map this
goto Failure;
}
pAsyncOp->SetConnection( pConnection );
if (hEndPt == NULL) // Message for local player - Put on local message queue
{
//
// INTERNAL Message
//
DPFX(DPFPREP, 5,"INTERNAL Message");
//
// AddRef Protocol as SendComplete will release this reference
//
DNProtocolAddRef(pdnObject);
pAsyncOp->AddRef();
hResultCode = DNWTSendInternal( pdnObject,
pAsyncOp );
pConnection->ReleaseEndPt(&CallbackThread);
DNASSERT( hResultCode == DPNERR_PENDING );
}
else
{
//
// EXTERNAL Message
//
DPFX(DPFPREP, 5,"EXTERNAL Message");
//
// AddRef Protocol so that it won't go away until this completes
//
DNProtocolAddRef(pdnObject);
pAsyncOp->AddRef();
hResultCode = DNPSendData( pdnObject->pdnProtocolData,
hEndPt,
pSendOpData->dwNumBuffers,
&pSendOpData->BufferDesc[0],
dwTimeOut,
pAsyncOp->GetOpFlags(),
reinterpret_cast<void*>(pAsyncOp),
&hProtocol);
pConnection->ReleaseEndPt(&CallbackThread);
if (hResultCode != DPNERR_PENDING)
{
if (hResultCode != DPN_OK)
{
DPFERR("Could not send data");
DisplayDNError(0,hResultCode);
}
pAsyncOp->Release();
DNProtocolRelease(pdnObject);
goto Failure;
}
pAsyncOp->Lock();
if (pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
{
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->SetProtocolHandle( hProtocol );
pAsyncOp->Unlock();
}
DNASSERT( hResultCode == DPNERR_PENDING );
//
// Update outstanding queue info for USER sends (now guaranteed to be cleaned up by the completion)
// and set completion
//
if (!(dwMsgId & DN_MSG_INTERNAL))
{
pConnection->Lock();
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
if (dwSendFlags & DN_SENDFLAGS_HIGH_PRIORITY)
{
pConnection->AddToHighQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
else if (dwSendFlags & DN_SENDFLAGS_LOW_PRIORITY)
{
pConnection->AddToLowQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
else
{
pConnection->AddToNormalQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
}
pConnection->Unlock();
}
pAsyncOp->SetCompletion( DNCompleteSendAsyncOp );
pSendOpData = NULL;
if (ppAsyncOp != NULL)
{
pAsyncOp->AddRef();
*ppAsyncOp = pAsyncOp;
}
pAsyncOp->Release();
pAsyncOp = NULL;
Exit:
CallbackThread.Deinitialize();
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pSendOpData)
{
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
pSendOpData->BufferDesc[dw].dwBufferSize = 0;
pSendOpData->BufferDesc[dw].pBufferData = NULL;
}
pSendOpData->dwMsgId = 0;
pSendOpData->dwNumBuffers = 0;
pSendOpData = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNSendGroupMessage"
HRESULT DNSendGroupMessage(DIRECTNETOBJECT *const pdnObject,
CNameTableEntry *const pGroup,
const DWORD dwMsgId,
const DPN_BUFFER_DESC *const pdnBufferDesc,
const DWORD cBufferDesc,
CRefCountBuffer *const pRefCountBuffer,
const DWORD dwTimeOut,
const DWORD dwSendFlags,
const BOOL fNoLoopBack,
const BOOL fRequest,
CAsyncOp *const pParent,
CAsyncOp **const ppGroupSendParent)
{
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
CAsyncOp *pGroupSendParent;
CBilink *pBilink;
CConnection *pConnection;
CGroupConnection *pGroupConnection;
DN_GROUP_SEND_OP *pSendOp;
DN_GROUP_SEND_OP *pTemp;
DPNID dpnidLocalPlayer;
DPFX(DPFPREP, 4,"Parameters: pGroup [0x%p], dwMsgId [0x%lx], pdnBufferDesc [0x%p], pRefCountBuffer [0x%p], dwTimeOut [%ld], dwSendFlags [0x%lx], fNoLoopBack [%ld], fRequest [%ld], pParent [0x%p], ppGroupSendParent [0x%p]",
pGroup,dwMsgId,pdnBufferDesc,pRefCountBuffer,dwTimeOut,dwSendFlags,fNoLoopBack,fRequest,pParent,ppGroupSendParent);
DNASSERT(pdnObject != NULL);
DNASSERT(pGroup != NULL);
DNASSERT(ppGroupSendParent != NULL);
pAsyncOp = NULL;
pGroupSendParent = NULL;
pConnection = NULL;
pGroupConnection = NULL;
if (fNoLoopBack)
{
CNameTableEntry *pLocalPlayer;
pLocalPlayer = NULL;
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK)
{
DPFERR("Could not get local player reference");
DisplayDNError(0,hResultCode);
goto Failure;
}
dpnidLocalPlayer = pLocalPlayer->GetDPNID();
pLocalPlayer->Release();
pLocalPlayer = NULL;
}
else
{
dpnidLocalPlayer = 0;
}
//
// Create group send target list
//
pSendOp = NULL;
pGroup->Lock();
pBilink = pGroup->m_bilinkConnections.GetNext();
while (pBilink != &pGroup->m_bilinkConnections)
{
pGroupConnection = CONTAINING_OBJECT(pBilink,CGroupConnection,m_bilink);
if ((hResultCode = pGroupConnection->GetConnectionRef( &pConnection )) == DPN_OK)
{
//
// We will only use CONNECTED connections (not CONNECTING,DISCONNECTING, or INVALID ones)
//
if (pConnection->IsConnected())
{
if ((!fNoLoopBack) || (pConnection->GetDPNID() != dpnidLocalPlayer))
{
//
// Save this connection
//
pTemp = static_cast<DN_GROUP_SEND_OP*>(MemoryBlockAlloc(pdnObject,sizeof(DN_GROUP_SEND_OP)));
if (pTemp == NULL)
{
pGroup->Unlock();
DPFERR("Could not create DN_GROUP_SEND_OP");
hResultCode = DPNERR_OUTOFMEMORY;
goto Failure;
}
pConnection->AddRef();
pTemp->pConnection = pConnection;
pTemp->pNext = pSendOp;
pSendOp = pTemp;
}
}
pConnection->Release();
pConnection = NULL;
}
pBilink = pBilink->GetNext();
}
pGroup->Unlock();
//
// Create group send parent
//
if ((hResultCode = DNCreateSendParent( pdnObject,
dwMsgId,
pdnBufferDesc,
cBufferDesc,
dwSendFlags,
&pGroupSendParent)) != DPN_OK)
{
DPFERR("Could not create SEND parent");
DisplayDNError(0,hResultCode);
goto Failure;
}
if (pRefCountBuffer)
{
pGroupSendParent->SetRefCountBuffer( pRefCountBuffer );
}
pGroupSendParent->SetDPNID( pGroup->GetDPNID() );
//
// Make child if parent specified
//
if (pParent)
{
pParent->Lock();
if (pParent->IsCancelled())
{
pParent->Unlock();
pGroupSendParent->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pGroupSendParent->MakeChild( pParent );
pParent->Unlock();
}
//
// Preset error code on send parent to DPNSUCCESS_NORECEIVERS
//
pGroupSendParent->Lock();
if (pGroupSendParent->GetResult() == DPNERR_GENERIC)
{
pGroupSendParent->SetResult( DPNSUCCESS_NOPLAYERSINGROUP );
}
pGroupSendParent->Unlock();
//
// Traverse send list and perform sends
//
while (pSendOp)
{
if (fRequest)
{
hResultCode = DNPerformRequest( pdnObject,
DN_MSG_INTERNAL_REQ_PROCESS_COMPLETION,
pdnBufferDesc,
pSendOp->pConnection,
pGroupSendParent,
&pAsyncOp);
}
else
{
hResultCode = DNPerformChildSend( pdnObject,
pGroupSendParent,
pSendOp->pConnection,
dwTimeOut,
&pAsyncOp,
FALSE);
}
if (pAsyncOp != NULL)
{
pAsyncOp->SetDPNID( pSendOp->pConnection->GetDPNID() );
pAsyncOp->Release();
pAsyncOp = NULL;
}
//
// Destroy old group send op
//
pTemp = pSendOp;
pSendOp = pSendOp->pNext;
pTemp->pConnection->Release();
pTemp->pConnection = NULL;
MemoryBlockFree(pdnObject,pTemp);
}
//
// Pass back group send parent
//
*ppGroupSendParent = pGroupSendParent;
pGroupSendParent = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pGroupSendParent)
{
pGroupSendParent->Release();
pGroupSendParent = NULL;
}
if (pConnection)
{
pConnection->Release();
pConnection = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNCreateSendParent"
HRESULT DNCreateSendParent(DIRECTNETOBJECT *const pdnObject,
const DWORD dwMsgId,
const DPN_BUFFER_DESC *const pdnBufferDesc,
const DWORD cBufferDesc,
const DWORD dwSendFlags,
CAsyncOp **const ppParent)
{
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
DN_SEND_OP_DATA *pSendOpData;
DWORD dwStart;
DWORD dw;
DPFX(DPFPREP, 4,"Parameters: dwMsgId [0x%lx], pdnBufferDesc [0x%p], cBufferDesc [%ld], dwSendFlags [0x%lx], ppParent [0x%p]",
dwMsgId,pdnBufferDesc,cBufferDesc,dwSendFlags,ppParent);
DNASSERT(pdnObject != NULL);
DNASSERT(ppParent != NULL);
pAsyncOp = NULL;
pSendOpData = NULL;
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_SEND );
pAsyncOp->MakeParent();
pSendOpData = pAsyncOp->GetLocalSendOpData();
pSendOpData->dwMsgId = dwMsgId;
if (dwMsgId & DN_MSG_INTERNAL)
{
#ifndef DPNBUILD_NOVOICE
if (dwMsgId == DN_MSG_INTERNAL_VOICE_SEND)
{
DNASSERT(pdnBufferDesc != NULL);
dwStart = 0;
pAsyncOp->SetOpFlags( dwSendFlags | DN_SENDFLAGS_SET_USER_FLAG | DN_SENDFLAGS_SET_USER_FLAG_TWO | DN_SENDFLAGS_COALESCE );
}
else
#endif // DPNBUILD_NOVOICE
{
pSendOpData->BufferDesc[0].pBufferData = reinterpret_cast<BYTE*>( &(pSendOpData->dwMsgId) );
pSendOpData->BufferDesc[0].dwBufferSize = sizeof( DWORD );
dwStart = 1;
pAsyncOp->SetOpFlags( dwSendFlags | DN_SENDFLAGS_SET_USER_FLAG | DN_SENDFLAGS_COALESCE );
}
}
else
{
DNASSERT(pdnBufferDesc != NULL);
dwStart = 0;
pAsyncOp->SetOpFlags( dwSendFlags );
}
for ( dw = 0 ; dw < cBufferDesc ; dw++ )
{
pSendOpData->BufferDesc[dwStart+dw].pBufferData = pdnBufferDesc[dw].pBufferData;
pSendOpData->BufferDesc[dwStart+dw].dwBufferSize = pdnBufferDesc[dw].dwBufferSize;
}
pSendOpData->dwNumBuffers = cBufferDesc + dwStart;
//
// Completion
//
pAsyncOp->SetCompletion( DNCompleteSendAsyncOp );
pSendOpData = NULL;
*ppParent = pAsyncOp;
pAsyncOp = NULL;
Exit:
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
if (pSendOpData)
{
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
pSendOpData->BufferDesc[dw].dwBufferSize = 0;
pSendOpData->BufferDesc[dw].pBufferData = NULL;
}
pSendOpData->dwMsgId = 0;
pSendOpData->dwNumBuffers = 0;
pSendOpData = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformChildSend"
HRESULT DNPerformChildSend(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pParent,
CConnection *const pConnection,
const DWORD dwTimeOut,
CAsyncOp **const ppChild,
const BOOL fInternal)
{
HRESULT hResultCode;
DWORD dw;
CAsyncOp *pAsyncOp;
DN_SEND_OP_DATA *pSendOpData;
HANDLE hEndPt;
HANDLE hProtocol;
CCallbackThread CallbackThread;
DPFX(DPFPREP, 4,"Parameters: pParent [0x%p], pConnection [0x%p], dwTimeOut [%ld]",
pParent,pConnection,dwTimeOut);
DNASSERT(pdnObject != NULL);
DNASSERT(pParent != NULL);
DNASSERT(pConnection != NULL);
pAsyncOp = NULL;
CallbackThread.Initialize();
if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
goto Failure;
}
pAsyncOp->SetOpType( ASYNC_OP_SEND );
pAsyncOp->SetCompletion( DNCompleteSendAsyncOp );
pAsyncOp->SetOpFlags( pParent->GetOpFlags() );
if (fInternal)
{
pAsyncOp->SetInternal();
}
pParent->Lock();
if (pParent->IsCancelled())
{
pParent->Unlock();
pAsyncOp->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pAsyncOp->MakeChild( pParent );
pParent->Unlock();
//
// Add to active async op list
//
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.InsertBefore(&pdnObject->m_bilinkActiveList);
DNLeaveCriticalSection(&pdnObject->csActiveList);
//
// Get parent's send op data block
//
pSendOpData = pParent->GetLocalSendOpData();
//
// Save connection and get end point
//
if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
{
DPFERR("Could not retrieve EndPt");
DisplayDNError(0,hResultCode);
goto Failure;
}
pAsyncOp->SetConnection( pConnection );
//
// Update outstanding queue info (now guaranteed to be cleaned up by the completion once UseParentOpData is set)
//
if (pSendOpData->dwMsgId == DN_MSG_USER_SEND)
{
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
pConnection->Lock();
if (pAsyncOp->GetOpFlags() & DN_SENDFLAGS_HIGH_PRIORITY)
{
pConnection->AddToHighQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
else if (pAsyncOp->GetOpFlags() & DN_SENDFLAGS_LOW_PRIORITY)
{
pConnection->AddToLowQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
else
{
pConnection->AddToNormalQueue( pSendOpData->BufferDesc[dw].dwBufferSize );
}
pConnection->Unlock();
}
}
pAsyncOp->SetUseParentOpData();
if (hEndPt == NULL)
{
//
// INTERNAL Message
//
DPFX(DPFPREP, 5,"INTERNAL Message");
//
// AddRef Protocol as SendComplete will release this reference
//
DNProtocolAddRef(pdnObject);
pAsyncOp->AddRef();
hResultCode = DNWTSendInternal( pdnObject,
pAsyncOp );
pConnection->ReleaseEndPt(&CallbackThread);
#pragma BUGBUG(minara, "Handle out-of-memory case correctly")
DNASSERT(hResultCode == DPNERR_PENDING);
}
else
{
//
// EXTERNAL Message
//
DPFX(DPFPREP, 5,"EXTERNAL Message");
//
// AddRef Protocol so that it won't go away until this completes
//
DNProtocolAddRef(pdnObject);
pAsyncOp->AddRef();
hResultCode = DNPSendData( pdnObject->pdnProtocolData,
hEndPt,
pSendOpData->dwNumBuffers,
&pSendOpData->BufferDesc[0],
dwTimeOut,
pParent->GetOpFlags(),
reinterpret_cast<void*>(pAsyncOp),
&hProtocol);
pConnection->ReleaseEndPt(&CallbackThread);
if (hResultCode != DPNERR_PENDING)
{
if (hResultCode != DPN_OK)
{
DPFERR("SEND failed at Protocol layer");
DisplayDNError(0,hResultCode);
}
pAsyncOp->Release();
DNProtocolRelease(pdnObject);
goto Failure;
}
pAsyncOp->Lock();
if (pAsyncOp->IsCancelled() && !pAsyncOp->IsComplete())
{
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->SetProtocolHandle( hProtocol );
pAsyncOp->Unlock();
}
//
// If the caller wants a reference on this operation, give it to them
//
if (ppChild != NULL)
{
pAsyncOp->AddRef();
*ppChild = pAsyncOp;
}
pAsyncOp->Release();
pAsyncOp = NULL;
Exit:
CallbackThread.Deinitialize();
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
pAsyncOp->Release();
pAsyncOp = NULL;
}
goto Exit;
}
// DN_ProcessInternalOperation
//
// Process an internal operation
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_ProcessInternalOperation"
HRESULT DNProcessInternalOperation(DIRECTNETOBJECT *const pdnObject,
const DWORD dwMsgId,
void *const pOpBuffer,
const DWORD dwOpBufferSize,
CConnection *const pConnection,
const HANDLE hProtocol,
CRefCountBuffer *const pRefCountBuffer)
{
HRESULT hResultCode;
CRefCountBuffer *pRCBuffer;
CWorkerJob *pWorkerJob;
BOOL fDecRunningOpCount;
DPFX(DPFPREP, 6,"Parameters: dwMsgId [0x%lx], pOpBuffer [0x%p], dwOpBufferSize [%ld], pConnection [0x%p], hProtocol [0x%p], pRefCountBuffer [0x%p]",
dwMsgId,pOpBuffer,dwOpBufferSize,pConnection,hProtocol,pRefCountBuffer);
hResultCode = DPN_OK;
pRCBuffer = NULL;
pWorkerJob = NULL;
fDecRunningOpCount = FALSE;
//
// We will track the number of running operations (i.e. threads running through this function).
// At the start of host migration, we will need to send the new host the latest name table version,
// so we will need to let running operations finish, before sending in the name table version.
// If another thread is waiting, we will not perform any operations (other than host migration)
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if ((pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING_WAIT) && (dwMsgId != DN_MSG_INTERNAL_HOST_MIGRATE))
{
DPFX(DPFPREP,7,"Already waiting for running operations - ignoring this operation");
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
hResultCode = DPN_OK;
goto Failure;
}
if (dwMsgId != DN_MSG_INTERNAL_HOST_MIGRATE)
{
pdnObject->dwRunningOpCount++;
fDecRunningOpCount = TRUE;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
switch(dwMsgId)
{
case DN_MSG_INTERNAL_PLAYER_CONNECT_INFO:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_PLAYER_CONNECT_INFO");
if (DNVerifyPlayerConnectInfo(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
//
// Perform validations and send name table to player
//
hResultCode = DNHostConnect1(pdnObject,pOpBuffer,dwOpBufferSize,pConnection);
hResultCode = DPN_OK; // Ignore return code
break;
}
case DN_MSG_INTERNAL_SEND_CONNECT_INFO:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_SEND_CONNECT_INFO");
if (DNVerifyConnectInfo(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
//
// We will pass this stage off to the worker thread since there is a threading
// issue, and we cannot keep the SP's thread which was passed up to here.
//
if ((hResultCode = RefCountBufferNew(pdnObject,dwOpBufferSize,MemoryBlockAlloc,MemoryBlockFree,&pRCBuffer)) != DPN_OK)
{
DPFERR("Could not allocate RefCountBuffer");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
hResultCode = DPN_OK;
goto Failure;
}
memcpy(pRCBuffer->GetBufferAddress(),pOpBuffer,dwOpBufferSize);
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK)
{
DPFERR("Could not create WorkerJob");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
hResultCode = DPN_OK;
goto Failure;
}
pWorkerJob->SetJobType( WORKER_JOB_INSTALL_NAMETABLE );
pWorkerJob->SetConnection( pConnection );
pWorkerJob->SetRefCountBuffer( pRCBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob);
pWorkerJob = NULL;
pRCBuffer->Release();
pRCBuffer = NULL;
break;
}
case DN_MSG_INTERNAL_ACK_CONNECT_INFO:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_ACK_CONNECT_INFO");
//
// No verification as there is no payload with this message
//
//
// Process connect info acknowledge by host
//
hResultCode = DNHostConnect2(pdnObject,pConnection); // Ignore errors
break;
}
case DN_MSG_INTERNAL_SEND_PLAYER_DNID:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_SEND_PLAYER_DNID");
if (DNVerifySendPlayerDPNID(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
//
// Send this player's DNID to the connecting player to enable name table entry
//
hResultCode = DNPlayerConnect1(pdnObject,pOpBuffer,pConnection); // Ignore errors
break;
}
case DN_MSG_INTERNAL_CONNECT_FAILED:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_CONNECT_FAILED");
if (DNVerifyConnectFailed(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
//
// Save reply buffer and clean up
//
DNConnectToHostFailed(pdnObject,pOpBuffer,dwOpBufferSize,pConnection);
hResultCode = DPN_OK;
break;
}
case DN_MSG_INTERNAL_INSTRUCT_CONNECT:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_INSTRUCT_CONNECT");
if (DNVerifyInstructConnect(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_INSTRUCT_CONNECT,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_INSTRUCTED_CONNECT_FAILED:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_INSTRUCTED_CONNECT_FAILED");
if (DNVerifyInstructedConnectFailed(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostDropPlayer( pdnObject,
pConnection->GetDPNID(),
pOpBuffer); // Ignore errors
break;
}
case DN_MSG_INTERNAL_CONNECT_ATTEMPT_FAILED:
{
UNALIGNED DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED *pInfo;
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_CONNECT_ATTEMPT_FAILED");
if (DNVerifyConnectAttemptFailed(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
pInfo = static_cast<DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED*>(pOpBuffer);
DPFX(DPFPREP, 7,"Player [0x%lx] could not connect to us",pInfo->dpnid);
hResultCode = DNAbortConnect(pdnObject,DPNERR_PLAYERNOTREACHABLE); // Ignore errors
break;
}
case DN_MSG_INTERNAL_NAMETABLE_VERSION:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_NAMETABLE_VERSION");
#ifndef DPNBUILD_NOHOSTMIGRATE
if (DNVerifyNameTableVersion(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTHostReceiveVersion(pdnObject,pConnection->GetDPNID(),pOpBuffer);
#else
DNASSERT(!"Should never get here!");
#endif // DPNBUILD_NOHOSTMIGRATE
break;
}
case DN_MSG_INTERNAL_RESYNC_VERSION:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_RESYNC_VERSION");
#ifndef DPNBUILD_NOHOSTMIGRATE
if (DNVerifyResyncVersion(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTPlayerResyncVersion(pdnObject,pOpBuffer);
#else
DNASSERT(!"Should never get here!");
#endif // DPNBUILD_NOHOSTMIGRATE
break;
}
case DN_MSG_INTERNAL_REQ_NAMETABLE_OP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_NAMETABLE_OP");
#ifndef DPNBUILD_NOHOSTMIGRATE
if (DNVerifyReqNameTableOp(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNProcessHostMigration2(pdnObject,pOpBuffer);
#else
DNASSERT(!"Should never get here!");
#endif // DPNBUILD_NOHOSTMIGRATE
break;
}
case DN_MSG_INTERNAL_ACK_NAMETABLE_OP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_ACK_NAMETABLE_OP");
#ifndef DPNBUILD_NOHOSTMIGRATE
if (DNVerifyAckNameTableOp(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNPerformHostMigration3(pdnObject,pOpBuffer);
#else
DNASSERT(!"Should never get here!");
#endif // DPNBUILD_NOHOSTMIGRATE
break;
}
case DN_MSG_INTERNAL_HOST_MIGRATE:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_HOST_MIGRATE");
#ifndef DPNBUILD_NOHOSTMIGRATE
if (DNVerifyHostMigrate(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNProcessHostMigration1(pdnObject,pOpBuffer);
#else
DNASSERT(!"Should never get here!");
#endif // DPNBUILD_NOHOSTMIGRATE
break;
}
case DN_MSG_INTERNAL_HOST_MIGRATE_COMPLETE:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_HOST_MIGRATE_COMPLETE");
#ifndef DPNBUILD_NOHOSTMIGRATE
//
// No verification as there is no payload with this message
//
hResultCode = DNProcessHostMigration3(pdnObject,pConnection->GetDPNID());
#else
DNASSERT(!"Should never get here!");
#endif // DPNBUILD_NOHOSTMIGRATE
break;
}
case DN_MSG_INTERNAL_UPDATE_APPLICATION_DESC:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_UPDATE_APPLICATION_DESC");
if (DNVerifyApplicationDescInfo(pOpBuffer,dwOpBufferSize,pOpBuffer) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNProcessUpdateAppDesc(pdnObject,static_cast<DPN_APPLICATION_DESC_INFO*>(pOpBuffer));
break;
}
case DN_MSG_INTERNAL_ADD_PLAYER:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_ADD_PLAYER");
if (DNVerifyNameTableEntryInfo(pOpBuffer,dwOpBufferSize,pOpBuffer) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_ADD_PLAYER,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_DESTROY_PLAYER:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_DESTROY_PLAYER");
if (DNVerifyDestroyPlayer(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_DESTROY_PLAYER,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_CREATE_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_CREATE_GROUP");
if (DNVerifyCreateGroup(pOpBuffer,dwOpBufferSize,pOpBuffer) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_CREATE_GROUP,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_DESTROY_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_DESTROY_GROUP");
if (DNVerifyDestroyGroup(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_DESTROY_GROUP,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_ADD_PLAYER_TO_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_ADD_PLAYER_TO_GROUP");
if (DNVerifyAddPlayerToGroup(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_ADD_PLAYER_TO_GROUP,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_DELETE_PLAYER_FROM_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_DELETE_PLAYER_FROM_GROUP");
if (DNVerifyDeletePlayerFromGroup(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_DELETE_PLAYER_FROM_GROUP,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_UPDATE_INFO:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_UPDATE_INFO");
if (DNVerifyUpdateInfo(pOpBuffer,dwOpBufferSize,pOpBuffer) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNNTAddOperation( pdnObject,
DN_MSG_INTERNAL_UPDATE_INFO,
pOpBuffer,
dwOpBufferSize,
hProtocol,
pConnection->GetSP());
break;
}
case DN_MSG_INTERNAL_REQ_CREATE_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_CREATE_GROUP");
if (DNVerifyReqCreateGroup(pOpBuffer,dwOpBufferSize,pOpBuffer) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostProcessRequest(pdnObject,DN_MSG_INTERNAL_REQ_CREATE_GROUP,
pOpBuffer,pConnection->GetDPNID());
break;
}
case DN_MSG_INTERNAL_REQ_DESTROY_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_DESTROY_GROUP");
if (DNVerifyReqDestroyGroup(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostProcessRequest(pdnObject,DN_MSG_INTERNAL_REQ_DESTROY_GROUP,
pOpBuffer,pConnection->GetDPNID());
break;
}
case DN_MSG_INTERNAL_REQ_ADD_PLAYER_TO_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_ADD_PLAYER_TO_GROUP");
if (DNVerifyReqAddPlayerToGroup(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostProcessRequest(pdnObject,
DN_MSG_INTERNAL_REQ_ADD_PLAYER_TO_GROUP,pOpBuffer,pConnection->GetDPNID());
break;
}
case DN_MSG_INTERNAL_REQ_DELETE_PLAYER_FROM_GROUP:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_DELETE_PLAYER_FROM_GROUP");
if (DNVerifyReqDeletePlayerFromGroup(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostProcessRequest(pdnObject,
DN_MSG_INTERNAL_REQ_DELETE_PLAYER_FROM_GROUP,pOpBuffer,pConnection->GetDPNID());
break;
}
case DN_MSG_INTERNAL_REQ_UPDATE_INFO:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_UPDATE_INFO");
if (DNVerifyReqUpdateInfo(pOpBuffer,dwOpBufferSize,pOpBuffer) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostProcessRequest(pdnObject,DN_MSG_INTERNAL_REQ_UPDATE_INFO,
pOpBuffer,pConnection->GetDPNID());
break;
}
#ifndef DPNBUILD_NOVOICE
case DN_MSG_INTERNAL_VOICE_SEND:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_VOICE_SEND");
hResultCode = Voice_Receive( pdnObject, pConnection->GetDPNID(), 0, pOpBuffer, dwOpBufferSize );
break;
}
#endif // DPNBUILD_NOVOICE
case DN_MSG_INTERNAL_BUFFER_IN_USE:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_BUFFER_IN_USE - INVALID !");
DNASSERT(FALSE);
break;
}
case DN_MSG_INTERNAL_REQUEST_FAILED:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQUEST_FAILED - INVALID !");
if (DNVerifyRequestFailed(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNProcessFailedRequest(pdnObject,pOpBuffer);
break;
}
case DN_MSG_INTERNAL_TERMINATE_SESSION:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_TERMINATE_SESSION");
if (DNVerifyTerminateSession(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNProcessTerminateSession(pdnObject,pOpBuffer,dwOpBufferSize);
break;
}
case DN_MSG_INTERNAL_REQ_PROCESS_COMPLETION:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_PROCESS_COMPLETION");
if (DNVerifyReqProcessCompletion(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
//
// Ensure requesting player in NameTable
//
hResultCode = DNReceiveCompleteOnProcess(pdnObject,pConnection,pOpBuffer,
dwOpBufferSize,hProtocol,pRefCountBuffer);
if (hResultCode != DPNERR_PENDING)
{
hResultCode = DPN_OK; // Ignore errors
}
break;
}
case DN_MSG_INTERNAL_PROCESS_COMPLETION:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_PROCESS_COMPLETION");
if (DNVerifyProcessCompletion(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNReceiveCompleteOnProcessReply(pdnObject,pOpBuffer,dwOpBufferSize);
break;
}
case DN_MSG_INTERNAL_REQ_INTEGRITY_CHECK:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_REQ_INTEGRITY_CHECK");
if (DNVerifyReqIntegrityCheck(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostProcessRequest(pdnObject,DN_MSG_INTERNAL_REQ_INTEGRITY_CHECK,
pOpBuffer,pConnection->GetDPNID());
hResultCode = DPN_OK;
break;
}
case DN_MSG_INTERNAL_INTEGRITY_CHECK:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_INTEGRITY_CHECK");
if (DNVerifyIntegrityCheck(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNProcessCheckIntegrity(pdnObject,pOpBuffer);
hResultCode = DPN_OK; // Ignore errors
break;
}
case DN_MSG_INTERNAL_INTEGRITY_CHECK_RESPONSE:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL_INTEGRITY_CHECK_RESPONSE");
if (DNVerifyIntegrityCheckResponse(pOpBuffer,dwOpBufferSize) != DPN_OK)
{
DPFERR("Invalid message - ignoring");
hResultCode = DPN_OK;
goto Failure;
}
hResultCode = DNHostFixIntegrity(pdnObject,pOpBuffer);
hResultCode = DPN_OK; // Ignore errors
break;
}
default:
{
DPFX(DPFPREP, 7,"Received: DN_MSG_INTERNAL (UNKNOWN!)");
DNASSERT(FALSE);
hResultCode = DPNERR_UNSUPPORTED;
break;
}
}
Exit:
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (fDecRunningOpCount)
{
pdnObject->dwRunningOpCount--;
}
if ((pdnObject->dwRunningOpCount == 0) && (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING_WAIT))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DNSetEvent(pdnObject->hRunningOpEvent);
}
else
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
}
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pRCBuffer)
{
pRCBuffer->Release();
pRCBuffer = NULL;
}
if (pWorkerJob)
{
pWorkerJob->ReturnSelfToPool();
pWorkerJob = NULL;
}
goto Exit;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DNPerformRequest"
HRESULT DNPerformRequest(DIRECTNETOBJECT *const pdnObject,
const DWORD dwMsgId,
const DPN_BUFFER_DESC *const pBufferDesc,
CConnection *const pConnection,
CAsyncOp *const pParent,
CAsyncOp **const ppRequest)
{
DWORD dwFlags;
HRESULT hResultCode;
BOOL fInternal;
BOOL fReleaseLock;
CAsyncOp *pRequest;
CAsyncOp *pSend;
CRefCountBuffer *pRefCountBuffer;
DN_SEND_OP_DATA *pSendOpData;
DPNHANDLE handle;
DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION *pMsg;
DPFX(DPFPREP, 6,"Parameters: dwMsgId [0x%lx], pBufferDesc [0x%p], pConnection [0x%p], pParent [0x%p], ppRequest [0x%p]",
dwMsgId,pBufferDesc,pConnection,pParent,ppRequest);
DNASSERT(pdnObject != NULL);
DNASSERT(pBufferDesc != NULL);
pRequest = NULL;
pSend = NULL;
pSendOpData = NULL;
pRefCountBuffer = NULL;
fReleaseLock = FALSE;
//
// Create RefCountBuffer for this operation
//
hResultCode = RefCountBufferNew(pdnObject,
pBufferDesc->dwBufferSize + sizeof(DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION),
MemoryBlockAlloc,
MemoryBlockFree,
&pRefCountBuffer);
if (hResultCode != DPN_OK)
{
DPFERR("Could not create RefCountBuffer");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION*>(pRefCountBuffer->GetBufferAddress());
memcpy(pMsg + 1,pBufferDesc->pBufferData,pBufferDesc->dwBufferSize);
//
// Keep DirectNetObject from vanishing under us !
//
if ((hResultCode = DNAddRefLock(pdnObject)) != DPN_OK)
{
DPFERR("Aborting request - object is closing");
hResultCode = DPN_OK;
goto Failure;
}
fReleaseLock = TRUE;
//
// Create REQUEST
//
if ((hResultCode = AsyncOpNew(pdnObject,&pRequest)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pRequest->SetOpType( ASYNC_OP_REQUEST );
if (pParent)
{
pParent->Lock();
if (pParent->IsCancelled())
{
pParent->Unlock();
pRequest->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pRequest->MakeChild( pParent );
pParent->Unlock();
}
pRequest->MakeParent();
pRequest->SetRefCountBuffer( pRefCountBuffer );
//
// Need a handle for this op (to be sent to the other side who will pass it back)
//
if ((hResultCode = pdnObject->HandleTable.Create(pRequest,&handle)) != DPN_OK)
{
DPFERR("Could not create handle for this operation");
DisplayDNError(0,hResultCode);
goto Failure;
}
else
{
// Add a reference for the HandleTable
pRequest->AddRef();
pRequest->Lock();
pRequest->SetHandle(handle);
pRequest->Unlock();
}
DNASSERT(pRequest->GetHandle() != 0);
//
// Set up SEND op data
//
pSendOpData = pRequest->GetLocalSendOpData();
pSendOpData->dwMsgId = dwMsgId;
pSendOpData->BufferDesc[0].pBufferData = reinterpret_cast<BYTE*>(&pSendOpData->dwMsgId);
pSendOpData->BufferDesc[0].dwBufferSize = sizeof(DWORD);
pSendOpData->BufferDesc[1].pBufferData = pRefCountBuffer->GetBufferAddress();
pSendOpData->BufferDesc[1].dwBufferSize = pRefCountBuffer->GetBufferSize();
pSendOpData->dwNumBuffers = 2;
#pragma TODO(vanceo, "This does not preserve non-sequential & coalesce flags when this is a COMPLETEONPROCESS send request")
pRequest->SetOpFlags( DN_SENDFLAGS_RELIABLE | DN_SENDFLAGS_SET_USER_FLAG );
pRequest->SetResult( DPNERR_PLAYERLOST );
pRequest->SetCompletion( DNCompleteRequest );
pSendOpData = NULL;
pMsg->hCompletionOp = pRequest->GetHandle();
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
//
// User messages sent with COMPLETE_ON_SEND should be allowed to be cancelled
//
if (dwMsgId == DN_MSG_INTERNAL_REQ_PROCESS_COMPLETION)
{
fInternal = FALSE;
}
else
{
fInternal = TRUE;
}
//
// We will always hand back the request, even if the send fails
//
if (ppRequest)
{
pRequest->AddRef();
*ppRequest = pRequest;
}
//
// Unlock DirectNetObject
//
DNDecRefLock(pdnObject);
fReleaseLock = FALSE;
//
// Add request to the request list
//
DNEnterCriticalSection(&pdnObject->csActiveList);
pRequest->m_bilinkActiveList.InsertBefore(&pdnObject->m_bilinkRequestList);
DNLeaveCriticalSection(&pdnObject->csActiveList);
//
// Avoid operations while host migration is taking place. This will get picked up
// after host migration, when completing outstanding operations
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
dwFlags = pdnObject->dwFlags;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (!(dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING) || !fInternal)
{
//
// SEND REQUEST
//
if (pConnection)
{
hResultCode = DNPerformChildSend( pdnObject,
pRequest,
pConnection,
0,
&pSend,
fInternal );
if (hResultCode != DPNERR_PENDING)
{
DPFERR("Could not perform child SEND");
DisplayDNError(0,hResultCode);
DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
goto Failure;
}
//
// Reset SEND AsyncOp to complete apropriately.
//
pSend->SetCompletion( DNCompleteSendRequest );
pSend->Release();
pSend = NULL;
}
}
pRequest->Release();
pRequest = NULL;
Exit:
DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (fReleaseLock)
{
DNDecRefLock(pdnObject);
fReleaseLock = FALSE;
}
if (pRequest)
{
pRequest->Release();
pRequest = NULL;
}
if (pSend)
{
pSend->Release();
pSend = NULL;
}
if (pRefCountBuffer)
{
pRefCountBuffer->Release();
pRefCountBuffer = NULL;
}
if (pSendOpData)
{
DWORD dw;
for ( dw = 0 ; dw < pSendOpData->dwNumBuffers ; dw++ )
{
pSendOpData->BufferDesc[dw].dwBufferSize = 0;
pSendOpData->BufferDesc[dw].pBufferData = NULL;
}
pSendOpData->dwMsgId = 0;
pSendOpData->dwNumBuffers = 0;
pSendOpData = NULL;
}
goto Exit;
}
// DNReceiveCompleteOnProcess
//
// Receive a CompleteOnProcess message
// Pass the message up to the application and then return a special completion message
#undef DPF_MODNAME
#define DPF_MODNAME "DNReceiveCompleteOnProcess"
HRESULT DNReceiveCompleteOnProcess(DIRECTNETOBJECT *const pdnObject,
CConnection *const pConnection,
void *const pBufferData,
const DWORD dwBufferSize,
const HANDLE hProtocol,
CRefCountBuffer *const pRefCountBuffer)
{
HRESULT hResultCode;
PVOID pvData;
DWORD dwDataSize;
UNALIGNED DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION *pReq;
DPFX(DPFPREP, 4,"Parameters: pConnection [0x%p], pBufferData [0x%p], dwBufferSize [%ld], hProtocol [0x%p], pRefCountBuffer [0x%p]",
pConnection,pBufferData,dwBufferSize,hProtocol,pRefCountBuffer);
DNASSERT(pdnObject != NULL);
DNASSERT(pConnection != NULL);
//
// Extract message
//
pReq = static_cast<DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION*>(pBufferData);
pvData = static_cast<void*>(pReq + 1);
dwDataSize = dwBufferSize - sizeof(DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION);
//
// Pass data to application
//
hResultCode = DNReceiveUserData(pdnObject,
pConnection,
static_cast<BYTE*>(pvData),
dwDataSize,
hProtocol,
pRefCountBuffer,
pReq->hCompletionOp,
0);
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DNReceiveCompleteOnProcessReply
//
// Receive a CompleteOnProcess COMPLETION message
// Complete the outstanding CompleteOnProcess operation
#undef DPF_MODNAME
#define DPF_MODNAME "DNReceiveCompleteOnProcessReply"
HRESULT DNReceiveCompleteOnProcessReply(DIRECTNETOBJECT *const pdnObject,
void *const pBufferData,
const DWORD dwBufferSize)
{
HRESULT hResultCode;
CAsyncOp *pAsyncOp;
UNALIGNED DN_INTERNAL_MESSAGE_PROCESS_COMPLETION *pMsg;
DPFX(DPFPREP, 4,"Parameters: pBufferData [0x%p], dwBufferSize [%ld]",pBufferData,dwBufferSize);
DNASSERT(pBufferData != NULL);
pAsyncOp = NULL;
pMsg = static_cast<DN_INTERNAL_MESSAGE_PROCESS_COMPLETION*>(pBufferData);
//
// Remove async op from HandleTable and from request list
//
DPFX(DPFPREP, 5,"Release completion operation [0x%lx]",pMsg->hCompletionOp);
if ((hResultCode = pdnObject->HandleTable.Destroy(pMsg->hCompletionOp,(PVOID*)&pAsyncOp)) != DPN_OK)
{
DPFERR("Could not find handle in HandleTable");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
DNASSERT(pAsyncOp->GetOpType() == ASYNC_OP_REQUEST);
DNEnterCriticalSection(&pdnObject->csActiveList);
pAsyncOp->m_bilinkActiveList.RemoveFromList();
DNLeaveCriticalSection(&pdnObject->csActiveList);
//
// Mark this operation as completing okay
//
pAsyncOp->SetResult( DPN_OK );
//
// This release should be the final release of the Request Child Async Op. and should
// DecRef the Request Parent Async Op.
//
pAsyncOp->Release();
pAsyncOp = NULL;
hResultCode = DPN_OK;
Exit:
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pAsyncOp)
{
pAsyncOp->Release();
pAsyncOp = NULL;
}
goto Exit;
}
// DNProcessTerminateSession
//
// Process a TERMINATE_SESSION message from the Host player
#undef DPF_MODNAME
#define DPF_MODNAME "DNProcessTerminateSession"
HRESULT DNProcessTerminateSession(DIRECTNETOBJECT *const pdnObject,
void *const pvBuffer,
const DWORD dwBufferSize)
{
HRESULT hResultCode;
void *pvTerminateData;
UNALIGNED DN_INTERNAL_MESSAGE_TERMINATE_SESSION *pMsg;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p], dwBufferSize [%ld]",pvBuffer,dwBufferSize);
DNASSERT(pdnObject != NULL);
DNASSERT(pvBuffer != NULL);
pMsg = static_cast<DN_INTERNAL_MESSAGE_TERMINATE_SESSION*>(pvBuffer);
if (pMsg->dwTerminateDataOffset)
{
pvTerminateData = static_cast<void*>(static_cast<BYTE*>(pvBuffer) + pMsg->dwTerminateDataOffset);
}
else
{
pvTerminateData = NULL;
}
//
// Inform user of termination
//
hResultCode = DNUserTerminateSession(pdnObject,DPNERR_HOSTTERMINATEDSESSION,pvTerminateData,pMsg->dwTerminateDataSize);
// Terminate session
hResultCode = DNTerminateSession(pdnObject,DPNERR_HOSTTERMINATEDSESSION);
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}