/*========================================================================== * * 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(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(pvBlock); hResultCode = DN_EnumAdapters( pdnObject, 0, pguidSP, NULL, reinterpret_cast(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(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(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(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(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(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(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(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(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(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( &(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(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(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( &(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(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(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(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(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(&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(pBufferData); pvData = static_cast(pReq + 1); dwDataSize = dwBufferSize - sizeof(DN_INTERNAL_MESSAGE_REQ_PROCESS_COMPLETION); // // Pass data to application // hResultCode = DNReceiveUserData(pdnObject, pConnection, static_cast(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(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(pvBuffer); if (pMsg->dwTerminateDataOffset) { pvTerminateData = static_cast(static_cast(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); }