/*========================================================================== * * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved. * * File: MsgHandler.cpp * Content: DirectPlay Core/Protocol Interface *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 01/15/00 mjn Created * 01/27/00 mjn Added support for retention of receive buffers * 04/08/00 mjn Save SP with connections * 04/11/00 mjn Use CAsyncOp for ENUMs * 04/13/00 mjn Use Protocol Interface VTBL * 04/14/00 mjn DNPICompleteListen sets status and SyncEvent * 04/17/00 mjn DNPICompleteEnumQuery just sets return value of AsyncOp * 04/18/00 mjn CConnection tracks connection status better * 04/21/00 mjn Ensure that RECEIVEs are from a valid connection before passing up notifications * mjn Disconnect CONNECTing end points on errors * 04/22/00 mjn Consume notifications when closing or disconnecting. * 04/26/00 mjn Removed DN_ASYNC_OP and related functions * 05/23/00 mjn Call DNConnectToPeerFailed if ExistingPlayer connect to NewPlayer fails * 06/14/00 mjn Allow only one connection to Host in DNPICompleteConnect() * 06/21/00 mjn Modified DNSendMessage() and DNCreateSendParent() to use protocol voice bit * 06/22/00 mjn Fixed DNPIIndicateReceive() to properly handle voice messages * mjn Cleaned up DNPIIndicateConnectionTerminated() * 06/24/00 mjn Fixed DNPICompleteConnect() * 07/08/00 mjn Only signal protocol shutdown event if it exists * 07/11/00 mjn Fixed DNPIAddressInfoXXX() routines to ENUM,LISTEN,CONNECT multiple adapters with address info * 07/20/00 mjn Modified CONNECT process, cleaned up refcount problems * 07/24/00 mjn Decline EnumQueries if not host or if host is migrating * 07/28/00 mjn Added code to validate return value from DPNICompleteSend() * 07/29/00 mjn Fix calls to DNUserConnectionTerminated() * 07/30/00 mjn Use DNUserTerminateSession() rather than DNUserConnectionTerminated() * 07/31/00 mjn Added hrReason to DNTerminateSession() * mjn Added dwDestroyReason to DNHostDisconnect() * 08/02/00 mjn Pass received voice messages through DNReceiveUserData() * 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles. * 08/05/00 mjn Added m_bilinkActiveList to CAsyncOp * 08/15/00 mjn Call DNConnectToHostFailed() when connecting player's connection to host drops * 08/16/00 mjn Modified IndicateConnect() and CompleteConnect() to determine SP directly from AsyncOps * 08/23/00 mjn Unregister with DPNSVR when LISTENs terminate * 09/04/00 mjn Added CApplicationDesc * 09/06/00 mjn Fixed DNPIIndicateConnectionTerminated() to better handle disconnects from partially connected players * 09/14/00 mjn Release Protocol refcounts in completions * 09/21/00 mjn Disconnect duplicate connections to Host player in DNPICompleteConnect() * 09/29/00 mjn AddRef/Release locks in DNPIIndicateReceive() * 09/30/00 mjn AddRef/Release locks in DNPIIndicateEnumQuery(),DNPIIndicateEnumResponse() * 10/11/00 mjn Cancel outstanding CONNECTs if one succeeds * 10/17/00 mjn Fixed clean up for unreachable players * 02/08/01 mjn Wait for cancels in DNPICompleteXXX() * mjn Wait for endpoint users in DNPIIndicateConnectionTerminated() * 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's * 04/05/01 mjn Set destroy reason to DPNDESTROYPLAYERREASON_CONNECTIONLOST in DNPIIndicateConnectionTerminated() * 05/23/01 mjn Cancel LISTEN's that have been flagged as cancelled in DNPICompleteListen() * 06/03/01 mjn Orphan completed CONNECT's and DISCONNECT's * 06/25/01 mjn Don't unregister with DPNSVR in DNPICompleteListenTerminate() * 07/24/01 mjn Added DPNBUILD_NOSERVER compile flag *@@END_MSINTERNAL * ***************************************************************************/ #include "dncorei.h" #undef DPF_MODNAME #define DPF_MODNAME "DNPIIndicateEnumQuery" HRESULT DNPIIndicateEnumQuery(void *const pvUserContext, void *const pvEndPtContext, const HANDLE hCommand, void *const pvEnumQueryData, const DWORD dwEnumQueryDataSize) { HRESULT hResultCode; CAsyncOp *pAsyncOp; DIRECTNETOBJECT *pdnObject; CNameTableEntry *pLocalPlayer; BOOL fReleaseLock; DPFX(DPFPREP, 6,"Parameters: pvEndPtContext [0x%p], hCommand [0x%p], pvEnumQueryData [0x%p], dwEnumQueryDataSize [%ld]", pvEndPtContext,hCommand,pvEnumQueryData,dwEnumQueryDataSize); DNASSERT(pvUserContext != NULL); DNASSERT(pvEndPtContext != NULL); pLocalPlayer = NULL; fReleaseLock = FALSE; pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvEndPtContext); // // Prevent close while in this call-back // if ((hResultCode = DNAddRefLock(pdnObject)) != DPN_OK) { hResultCode = DPN_OK; goto Failure; } fReleaseLock = TRUE; // // Don't perform this if host migrating // DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); hResultCode = DPN_OK; goto Failure; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) == DPN_OK) { if (pLocalPlayer->IsHost()) { #pragma TODO(minara,"The protocol should ensure that the LISTEN does not complete until this call-back returns") #pragma TODO(minara,"As the context value (AsyncOp) needs to be valid !") DNProcessEnumQuery( pdnObject, pAsyncOp, reinterpret_cast( pvEnumQueryData ) ); } pLocalPlayer->Release(); pLocalPlayer = NULL; } hResultCode = DPN_OK; Exit: if (fReleaseLock) { DNDecRefLock(pdnObject); fReleaseLock = FALSE; } DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); Failure: if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } goto Exit; } #undef DPF_MODNAME #define DPF_MODNAME "DNPIIndicateEnumResponse" HRESULT DNPIIndicateEnumResponse(void *const pvUserContext, const HANDLE hCommand, void *const pvCommandContext, void *const pvEnumResponseData, const DWORD dwEnumResponseDataSize) { HRESULT hResultCode; CAsyncOp *pAsyncOp; DIRECTNETOBJECT *pdnObject; BOOL fReleaseLock; DPFX(DPFPREP, 6,"Parameters: hCommand [0x%p], pvCommandContext [0x%p], pvEnumResponseData [0x%p], dwEnumResponseDataSize [%ld]", hCommand,pvCommandContext,pvEnumResponseData,dwEnumResponseDataSize); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); fReleaseLock = FALSE; pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); // // Prevent close while in this call-back // if ((hResultCode = DNAddRefLock(pdnObject)) != DPN_OK) { hResultCode = DPN_OK; goto Failure; } fReleaseLock = TRUE; #pragma TODO(minara,"The protocol should ensure that the ENUM does not complete until this call-back returns") #pragma TODO(minara,"As the context value (AsyncOp) needs to be valid !") DNProcessEnumResponse( pdnObject, pAsyncOp, reinterpret_cast( pvEnumResponseData )); hResultCode = DPN_OK; Exit: if (fReleaseLock) { DNDecRefLock(pdnObject); fReleaseLock = FALSE; } DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); Failure: goto Exit; } // // When a new connection is indicated by the Protocol layer, we will perform some basic validation, // and then create a CConnection object for it // #undef DPF_MODNAME #define DPF_MODNAME "DNPIIndicateConnect" HRESULT DNPIIndicateConnect(void *const pvUserContext, void *const pvListenContext, const HANDLE hEndPt, void **const ppvEndPtContext) { HRESULT hResultCode; CConnection *pConnection; DIRECTNETOBJECT *pdnObject; #pragma TODO( minara, "Decline connections to non-hosting players and peers who are not expecting them") DPFX(DPFPREP, 6,"Parameters: pvListenContext [0x%p], hEndPt [0x%p], ppvEndPtContext [0x%p]", pvListenContext,hEndPt,ppvEndPtContext); DNASSERT(pvUserContext != NULL); DNASSERT(pvListenContext != NULL); pdnObject = static_cast(pvUserContext); pConnection = NULL; // // Allocate and set up a CConnection object and hand a reference to the Protocol // if ((hResultCode = ConnectionNew(pdnObject,&pConnection)) != DPN_OK) { DPFERR("Could not get new connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pConnection->SetStatus( CONNECTING ); pConnection->SetEndPt(hEndPt); DNASSERT( (static_cast(pvListenContext))->GetParent() != NULL); DNASSERT( (static_cast(pvListenContext))->GetParent()->GetSP() != NULL); pConnection->SetSP((static_cast(pvListenContext))->GetParent()->GetSP()); pConnection->AddRef(); *ppvEndPtContext = pConnection; if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) { DPFERR("CONNECT indicated while closing or disconnecting"); DNPerformDisconnect(pdnObject,pConnection,hEndPt,FALSE); goto Failure; } DNASSERT(pdnObject->NameTable.GetLocalPlayer() != NULL); if (pdnObject->NameTable.GetLocalPlayer()->IsHost()) { // This connect was detected by a host player DPFX(DPFPREP, 7,"Host received connection attempt"); // // Ensure we're not connecting (still in Host()) or drop the connection // if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING) { pConnection->Disconnect(); goto Failure; } } else { // This connect was detected by a peer player (should be expecting a connection) DPFX(DPFPREP, 7,"Non-Host player received connection attempt"); } // // Add this entry to the bilink of indicated connections. When we receive more info, // or this connection is terminated, we will remove this entry from the bilink. // This will enable us to clean up properly. // DNEnterCriticalSection(&pdnObject->csConnectionList); pConnection->AddRef(); pConnection->m_bilinkIndicated.InsertBefore(&pdnObject->m_bilinkIndicated); DNLeaveCriticalSection(&pdnObject->csConnectionList); pConnection->Release(); pConnection = NULL; hResultCode = DPN_OK; Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); Failure: if (pConnection) { pConnection->Release(); pConnection = NULL; } goto Exit; } #undef DPF_MODNAME #define DPF_MODNAME "DNPIIndicateDisconnect" HRESULT DNPIIndicateDisconnect(void *const pvUserContext, void *const pvEndPtContext) { HRESULT hResultCode; CConnection *pConnection; DIRECTNETOBJECT *pdnObject; CNameTableEntry *pNTEntry; DPFX(DPFPREP, 6,"Parameters: pvEndPtContext [0x%p]", pvEndPtContext); DNASSERT(pvUserContext != NULL); DNASSERT(pvEndPtContext != NULL); pdnObject = static_cast(pvUserContext); pConnection = static_cast(pvEndPtContext); // // Mark the connection as DISCONNECTing so that we don't use it any more // pConnection->Lock(); pConnection->SetStatus( DISCONNECTING ); pConnection->Unlock(); if (pConnection->GetDPNID() == 0) { if (pdnObject->NameTable.GetLocalPlayer() && pdnObject->NameTable.GetLocalPlayer()->IsHost()) { DPFX(DPFPREP, 7,"Joining player has issued a disconnect to Host (local) player"); } else { DPFX(DPFPREP, 7,"Host has issued a disconnect to Joining (local) player"); } } else { DNASSERT(!(pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT)); if (pdnObject->NameTable.GetLocalPlayer() && pdnObject->NameTable.GetLocalPlayer()->IsHost()) { DPFX(DPFPREP, 7,"Connected player has issued a disconnect to Host (local) player"); } else { DPFX(DPFPREP, 7,"Connected player has issued a disconnect to local player"); } // // Mark this player for normal destruction since they disconnected and are playing nice // if ((hResultCode = pdnObject->NameTable.FindEntry(pConnection->GetDPNID(),&pNTEntry)) == DPN_OK) { pNTEntry->Lock(); if (pNTEntry->GetDestroyReason() == 0) { pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_NORMAL ); } pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL; } } hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPIIndicateConnectionTerminated" HRESULT DNPIIndicateConnectionTerminated(void *const pvUserContext, void *const pvEndPtContext, const HRESULT hr) { HRESULT hResultCode; CConnection *pConnection; DIRECTNETOBJECT *pdnObject; BOOL fWasConnecting; CBilink *pBilink; DWORD dwCount; CSyncEvent *pSyncEvent; DPFX(DPFPREP, 6,"Parameters: pvEndPtContext [0x%p], hr [0x%lx]",pvEndPtContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvEndPtContext != NULL); pSyncEvent = NULL; pdnObject = static_cast(pvUserContext); pConnection = static_cast(pvEndPtContext); // // pConnection should still have at least 1 reference on it at this stage since // INDICATE_CONNECTION_TERMINATED is supposed to be the final release for it. // All outstanding SENDs and RECEIVEs should have already been processed. // // If there are any users of the endpoint, then we will need to wait for them // to be done with it. To do this, we will count the number of threads using // the endpoint (not including any occurances of THIS thread), and set the count // and an event on the Connection // fWasConnecting = FALSE; pConnection->Lock(); if (pConnection->IsConnecting()) { fWasConnecting = TRUE; } pConnection->SetStatus( INVALID ); dwCount = 0; pBilink = pConnection->m_bilinkCallbackThreads.GetNext(); while (pBilink != &pConnection->m_bilinkCallbackThreads) { if (!(CONTAINING_CALLBACKTHREAD(pBilink))->IsCurrentThread()) { dwCount++; } pBilink = pBilink->GetNext(); } if (dwCount != 0) { if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK) { DPFERR("Could not get sync event - ignore and continue (we will not wait!)"); dwCount = 0; } else { pConnection->SetThreadCount( dwCount ); pConnection->SetThreadEvent( pSyncEvent ); } } pConnection->Unlock(); if (dwCount) { DNASSERT(pSyncEvent != NULL); pSyncEvent->WaitForEvent(); pConnection->Lock(); pConnection->SetThreadEvent( NULL ); pConnection->Unlock(); pSyncEvent->ReturnSelfToPool(); pSyncEvent = NULL; } // // Remove this connection from the indicated connection list // DNEnterCriticalSection(&pdnObject->csConnectionList); if (!pConnection->m_bilinkIndicated.IsEmpty()) { pConnection->Release(); } pConnection->m_bilinkIndicated.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csConnectionList); // // If we are a client (in client server), and the server has disconnected from us, we have to shut down // if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLIENT) { if (fWasConnecting) { DPFX(DPFPREP, 7,"Server disconnected from local connecting client - failing connect"); } else { DPFX(DPFPREP, 7,"Server disconnected from local client - shutting down"); // // Only inform the user if they are IN the session // if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED) { DNUserTerminateSession(pdnObject,DPNERR_CONNECTIONLOST,NULL,0); } DNTerminateSession(pdnObject,DPNERR_CONNECTIONLOST); } } #ifndef DPNBUILD_NOSERVER else if (pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) { if (fWasConnecting || (pConnection->GetDPNID() == 0)) { DPFX(DPFPREP, 7,"Unconnected client has disconnected from server"); } else { CNameTableEntry *pNTEntry; DWORD dwReason; pNTEntry = NULL; // // If the destruction code has not been set, mark as CONNECTIONLOST // if ((hResultCode = pdnObject->NameTable.FindEntry(pConnection->GetDPNID(),&pNTEntry)) == DPN_OK) { pNTEntry->Lock(); if (pNTEntry->GetDestroyReason() == 0) { pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_CONNECTIONLOST ); } dwReason = pNTEntry->GetDestroyReason(); pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL; } else { dwReason = DPNDESTROYPLAYERREASON_CONNECTIONLOST; } DNHostDisconnect(pdnObject,pConnection->GetDPNID(),dwReason); } } #endif // DPNBUILD_NOSERVER else // DN_OBJECT_FLAG_PEER { DNASSERT( pdnObject->dwFlags & DN_OBJECT_FLAG_PEER ); if (fWasConnecting || (pConnection->GetDPNID() == 0)) { DPFX(DPFPREP, 7,"Unconnected peer has disconnected from local peer"); CAsyncOp *pConnectParent; pConnectParent = NULL; DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING) { 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); } else { CNameTableEntry *pNTEntry; CNameTableEntry *pLocalPlayer; DWORD dwReason; pNTEntry = NULL; pLocalPlayer = NULL; // // If the destruction code has not been set, mark as CONNECTIONLOST // if ((hResultCode = pdnObject->NameTable.FindEntry(pConnection->GetDPNID(),&pNTEntry)) == DPN_OK) { pNTEntry->Lock(); if (pNTEntry->GetDestroyReason() == 0) { pNTEntry->SetDestroyReason( DPNDESTROYPLAYERREASON_CONNECTIONLOST ); } dwReason = pNTEntry->GetDestroyReason(); pNTEntry->Unlock(); pNTEntry->Release(); pNTEntry = NULL; } else { dwReason = DPNDESTROYPLAYERREASON_CONNECTIONLOST; } // // Based on who we are, and who's disconnecting, we will have different behaviour // if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef(&pLocalPlayer)) == DPN_OK) { if (pLocalPlayer->IsHost()) { DPFX(DPFPREP, 7,"Connected peer has disconnected from Host"); DNHostDisconnect(pdnObject,pConnection->GetDPNID(),dwReason); } else { DPFX(DPFPREP, 7,"Peer has disconnected from non-Host peer"); DNPlayerDisconnectNew(pdnObject,pConnection->GetDPNID()); } pLocalPlayer->Release(); pLocalPlayer = NULL; } } } pConnection->Release(); pConnection = NULL; hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPIIndicateReceive" HRESULT DNPIIndicateReceive(void *const pvUserContext, void *const pvEndPtContext, void *const pvData, const DWORD dwDataSize, const HANDLE hBuffer, const DWORD dwFlags) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; void *pvInternalData; DWORD dwInternalDataSize; CConnection *pConnection; DWORD *pdwMsgId; BOOL fReleaseLock; DPFX(DPFPREP, 6,"Parameters: pvEndPtContext [0x%p], pvData [0x%p], dwDataSize [%ld], hBuffer [0x%p], dwFlags [0x%lx]", pvEndPtContext,pvData,dwDataSize,hBuffer,dwFlags); DNASSERT(pvUserContext != NULL); DNASSERT(pvEndPtContext != NULL); DNASSERT(pvData != NULL); DNASSERT(((DWORD_PTR) pvData & 3) == 0); // data should be DWORD aligned DNASSERT(dwDataSize != 0); DNASSERT(hBuffer != NULL); fReleaseLock = FALSE; pdnObject = static_cast(pvUserContext); pConnection = static_cast(pvEndPtContext); // // Prevent close while in this call-back // if ((hResultCode = DNAddRefLock(pdnObject)) != DPN_OK) { hResultCode = DPN_OK; goto Failure; } fReleaseLock = TRUE; // // Ensure that this is a valid connection // if (!pConnection->IsConnected() && !pConnection->IsConnecting()) { hResultCode = DPN_OK; goto Failure; } pConnection->AddRef(); if ((dwFlags & DN_SENDFLAGS_SET_USER_FLAG) && !(dwFlags & DN_SENDFLAGS_SET_USER_FLAG_TWO)) { // // Internal message // DPFX(DPFPREP, 7,"Received INTERNAL message"); DNASSERT(dwDataSize >= sizeof(DWORD)); pdwMsgId = static_cast(pvData); dwInternalDataSize = dwDataSize - sizeof(DWORD); if (dwInternalDataSize > 0) { pvInternalData = static_cast(static_cast(pvData) + sizeof(DWORD)); } else { pvInternalData = NULL; } hResultCode = DNProcessInternalOperation( pdnObject, *pdwMsgId, pvInternalData, dwInternalDataSize, pConnection, hBuffer, NULL ); } else { // // User or voice message // DPFX(DPFPREP, 7,"Received USER or Voice message"); hResultCode = DNReceiveUserData(pdnObject, pConnection, static_cast(pvData), dwDataSize, hBuffer, NULL, 0, dwFlags); } // // Only allow DPNERR_PENDING or DPN_OK // if (hResultCode != DPNERR_PENDING) { hResultCode = DPN_OK; } pConnection->Release(); pConnection = NULL; Exit: if (fReleaseLock) { DNDecRefLock(pdnObject); fReleaseLock = FALSE; } DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); Failure: goto Exit; } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteListen" HRESULT DNPICompleteListen(void *const pvUserContext, void **const ppvCommandContext, const HRESULT hr, const HANDLE hCommand) { HRESULT hResultCode; CAsyncOp *pAsyncOp; CAsyncOp *pParent; DIRECTNETOBJECT *pdnObject; DPFX(DPFPREP, 6,"Parameters: ppvCommandContext [0x%p], hr [0x%lx], hCommand [0x%p]", ppvCommandContext,hr,hCommand); DNASSERT(pvUserContext != NULL); DNASSERT(ppvCommandContext != NULL); DNASSERT(*ppvCommandContext != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(*ppvCommandContext); pParent = NULL; // // AddRef pAsyncOp to keep it around in case a CompleteListenTerminated is posted // pAsyncOp->AddRef(); pAsyncOp->Lock(); if (pAsyncOp->GetParent()) { pAsyncOp->GetParent()->AddRef(); pParent = pAsyncOp->GetParent(); } pAsyncOp->Unlock(); // // If the LISTEN was cancelled and has been started successfully, we will need to shut it down. // Otherwise, we will keep the result of the LISTEN attempt // DNASSERT(pAsyncOp->GetResultPointer() != NULL); if (hr == DPN_OK) { if (pAsyncOp->IsCancelled()) { HRESULT hrCancel; if ((hrCancel = DNPCancelCommand(pdnObject->pdnProtocolData,hCommand)) == DPN_OK) { *(pAsyncOp->GetResultPointer()) = DPNERR_USERCANCEL; } else { *(pAsyncOp->GetResultPointer()) = DPNERR_GENERIC; } } else { // // We probably don't have to lock pAsyncOp to clear the CANNOT_CANCEL, but better safe than sorry // pAsyncOp->Lock(); pAsyncOp->ClearCannotCancel(); pAsyncOp->SetResult( hr ); pAsyncOp->Unlock(); *(pAsyncOp->GetResultPointer()) = hr; } } else { *(pAsyncOp->GetResultPointer()) = hr; } // // Set SyncEvent // DNASSERT(pAsyncOp->GetSyncEvent() != NULL); pAsyncOp->GetSyncEvent()->Set(); // // If there was an SP parent, we will check to see if this is the last completion and then set the // parent's SP listen event (if it exists) // if (pParent) { #ifndef DPNBUILD_ONLYONEADAPTER DN_LISTEN_OP_DATA *pListenOpData; pListenOpData = pParent->GetLocalListenOpData(); if (pListenOpData->dwCompleteAdapters < pListenOpData->dwNumAdapters) { pListenOpData->dwCompleteAdapters++; if (pListenOpData->dwCompleteAdapters == pListenOpData->dwNumAdapters) { if (pListenOpData->pSyncEvent) { pListenOpData->pSyncEvent->Set(); pListenOpData->pSyncEvent = NULL; } } } #endif // ! DPNBUILD_ONLYONEADAPTER pParent->Release(); pParent = NULL; } // // Done with pAsyncOp - release reference taken earlier // pAsyncOp->Release(); hResultCode = DPN_OK; DNASSERT( pParent == NULL); DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteListenTerminate" HRESULT DNPICompleteListenTerminate(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr) { HRESULT hResultCode; CAsyncOp *pAsyncOp; DIRECTNETOBJECT *pdnObject; DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx]", pvCommandContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); // // Indicate complete and remove from active list // pAsyncOp->Lock(); DNASSERT(!pAsyncOp->IsComplete()); pAsyncOp->SetComplete(); pAsyncOp->Unlock(); DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOp->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList); DNASSERT(pAsyncOp->IsChild()); pAsyncOp->Orphan(); // // Ensure there are no cancels outstanding // DNWaitForCancel(pAsyncOp); pAsyncOp->Release(); pAsyncOp = NULL; hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteEnumQuery" HRESULT DNPICompleteEnumQuery(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr) { HRESULT hResultCode; CAsyncOp *pAsyncOp; DIRECTNETOBJECT *pdnObject; DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx]", pvCommandContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DNASSERT( pAsyncOp->GetOpType() == ASYNC_OP_ENUM_QUERY ); // // Indicate complete and remove from active list // pAsyncOp->Lock(); DNASSERT(!pAsyncOp->IsComplete()); pAsyncOp->SetComplete(); pAsyncOp->Unlock(); DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOp->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList); pAsyncOp->SetResult( hr ); pAsyncOp->Orphan(); // // Ensure there are no cancels outstanding // DNWaitForCancel(pAsyncOp); pAsyncOp->Release(); pAsyncOp = NULL; // // Release Protocol reference // DNProtocolRelease(pdnObject); hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteEnumResponse" HRESULT DNPICompleteEnumResponse(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr) { HRESULT hResultCode; CAsyncOp *pAsyncOp; DIRECTNETOBJECT *pdnObject; DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx]", pvCommandContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DNASSERT( pAsyncOp->GetOpType() == ASYNC_OP_ENUM_RESPONSE ); pAsyncOp->Lock(); DNASSERT(!pAsyncOp->IsComplete()); pAsyncOp->SetComplete(); pAsyncOp->Unlock(); if (pAsyncOp->IsChild()) { DNASSERT(FALSE); pAsyncOp->Orphan(); } if (SUCCEEDED(pdnObject->HandleTable.Destroy( pAsyncOp->GetHandle(), NULL ))) { // Release the HandleTable reference pAsyncOp->Release(); } pAsyncOp->SetResult( hr ); // // Ensure there are no cancels outstanding // DNWaitForCancel(pAsyncOp); pAsyncOp->Release(); pAsyncOp = NULL; // // Release protocol reference // DNProtocolRelease(pdnObject); hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteConnect" HRESULT DNPICompleteConnect(void *const pvUserContext, void *const pvCommandContext, const HRESULT hrProt, const HANDLE hEndPt, void **const ppvEndPtContext) { HRESULT hResultCode; HRESULT hr; CAsyncOp *pAsyncOp; CConnection *pConnection; DIRECTNETOBJECT *pdnObject; IDirectPlay8Address *pIDevice; DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hrProt [0x%lx], hEndPt [0x%p], ppvEndPtContext [0x%p]", pvCommandContext,hrProt,hEndPt,ppvEndPtContext); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); DNASSERT( (hrProt != DPN_OK) || (ppvEndPtContext != NULL) ); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DNASSERT( pAsyncOp->GetOpType() == ASYNC_OP_CONNECT ); pConnection = NULL; pIDevice = NULL; // // Re-map DPNERR_ABORTED (!) // if (hrProt == DPNERR_ABORTED) { hr = DPNERR_USERCANCEL; } else { hr = hrProt; } // // Indicate complete and remove from active list // pAsyncOp->Lock(); DNASSERT(!pAsyncOp->IsComplete()); pAsyncOp->SetComplete(); pAsyncOp->Unlock(); DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOp->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList); if (pAsyncOp->IsChild()) { pAsyncOp->Orphan(); } // // If there is a DPNID associated with this operation, then we are an ExistingPlayer // connecting with a NewPlayer. If there is no DPNID, then we are a NewPlayer connecting // to the Host. // if (pAsyncOp->GetDPNID()) { DPFX(DPFPREP, 7,"CONNECT completed for existing player connecting to NewPlayer"); // // We are an existing player attempting to CONNECT to a NewPlayer. // If this CONNECT failed, we must inform the Host // if (hr != DPN_OK) { DPFERR("Could not CONNECT to NewPlayer"); DisplayDNError(0,hr); DNConnectToPeerFailed(pdnObject,pAsyncOp->GetDPNID()); hResultCode = DPN_OK; goto Failure; } // // Allocate and set up a CConnection object and hand a reference to the Protocol // DNASSERT(pAsyncOp->GetSP() != NULL); if ((hResultCode = ConnectionNew(pdnObject,&pConnection)) != DPN_OK) { DPFERR("Could not get new connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pConnection->SetStatus( CONNECTING ); pConnection->SetEndPt(hEndPt); pConnection->SetSP(pAsyncOp->GetSP()); pConnection->AddRef(); *ppvEndPtContext = pConnection; // // Send this player's DNID to the connecting player to enable name table entry // if ((hResultCode = DNConnectToPeer3(pdnObject,pAsyncOp->GetDPNID(),pConnection)) != DPN_OK) { DPFERR("Could not connect to NewPlayer"); DisplayDNError(0,hr); DNPerformDisconnect(pdnObject,pConnection,hEndPt,FALSE); DNConnectToPeerFailed(pdnObject,pAsyncOp->GetDPNID()); goto Failure; } } else { DPFX(DPFPREP, 7,"CONNECT completed for NewPlayer connecting to Host"); // // We are the NewPlayer attempting to CONNECT to the Host. // // // If this CONNECT succeeded, we will cancell any other CONNECTs. // If this CONNECT failed, we will set the result code on the AsyncOp // and release it. // if (hr == DPN_OK) { CAsyncOp *pParent; pParent = NULL; pAsyncOp->Lock(); if (pAsyncOp->GetParent()) { pAsyncOp->GetParent()->AddRef(); pParent = pAsyncOp->GetParent(); } pAsyncOp->Unlock(); if (pParent) { DNCancelChildren(pdnObject,pParent); pParent->Release(); pParent = NULL; } DNASSERT(pParent == NULL); } else { DPFERR("Could not CONNECT to Host"); DisplayDNError(0,hr); pAsyncOp->SetResult( hr ); hResultCode = DPN_OK; goto Failure; } // // Allocate and set up a CConnection object and hand a reference to the Protocol // DNASSERT(pAsyncOp->GetSP() != NULL); if ((hResultCode = ConnectionNew(pdnObject,&pConnection)) != DPN_OK) { DPFERR("Could not get new connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pConnection->SetStatus( CONNECTING ); pConnection->SetEndPt(hEndPt); pConnection->SetSP(pAsyncOp->GetSP()); pConnection->AddRef(); *ppvEndPtContext = pConnection; // // Ensure that this is the first CONNECT to succeed. // If it isn't we will just drop the connection. // DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_CONNECTED) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); DPFERR("Connect already established - disconnecting"); DNPerformDisconnect(pdnObject,pConnection,hEndPt,FALSE); hResultCode = DPN_OK; goto Failure; } pdnObject->dwFlags |= DN_OBJECT_FLAG_HOST_CONNECTED; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); // rodtoll: Modifying so we always store this information so that when we update // lobby settings we return the device we actually connected on for clients /* // // For Peer-Peer, we will need the device address we connected on so that // we can CONNECT to new players later on. // if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) {*/ if ((hResultCode = DNGetLocalDeviceAddress(pdnObject,hEndPt,&pIDevice)) != DPN_OK) { DPFERR("Could not determine local address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); DNPerformDisconnect(pdnObject,pConnection,hEndPt,FALSE); goto Failure; } IDirectPlay8Address_AddRef(pIDevice); pdnObject->pIDP8ADevice = pIDevice; IDirectPlay8Address_Release(pIDevice); pIDevice = NULL; // } // // Send player and application info for NewPlayer connecting to Host // if ((hResultCode = DNConnectToHost1(pdnObject,pConnection)) != DPN_OK) { DPFERR("Could not CONNECT to Host"); DisplayDNError(0,hResultCode); DNPerformDisconnect(pdnObject,pConnection,hEndPt,FALSE); goto Failure; } } pAsyncOp->Lock(); pAsyncOp->SetResult( DPN_OK ); pAsyncOp->Unlock(); pConnection->Release(); pConnection = NULL; hResultCode = DPN_OK; Exit: // // Ensure there are no cancels outstanding // DNWaitForCancel(pAsyncOp); DNASSERT(pAsyncOp != NULL); pAsyncOp->Release(); pAsyncOp = NULL; // // Release protocol reference // DNProtocolRelease(pdnObject); DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); Failure: if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pIDevice) { IDirectPlay8Address_Release(pIDevice); pIDevice = NULL; } goto Exit; } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteDisconnect" HRESULT DNPICompleteDisconnect(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr) { HRESULT hResultCode; CAsyncOp *pAsyncOp; DIRECTNETOBJECT *pdnObject; DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx]", pvCommandContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DNASSERT( pAsyncOp->GetOpType() == ASYNC_OP_DISCONNECT ); pAsyncOp->Lock(); DNASSERT(!pAsyncOp->IsComplete()); pAsyncOp->SetComplete(); pAsyncOp->Unlock(); if (pAsyncOp->IsChild()) { pAsyncOp->Orphan(); } // // If this completed successfully, we can remove the reference on the connection held by the Protocol // if (hr == DPN_OK) { pAsyncOp->Lock(); if (pAsyncOp->GetConnection()) { pAsyncOp->GetConnection()->Release(); } pAsyncOp->Unlock(); } pAsyncOp->SetResult( hr ); // // Ensure there are no cancels outstanding // DNWaitForCancel(pAsyncOp); pAsyncOp->Release(); pAsyncOp = NULL; // // Release Protocol reference // DNProtocolRelease(pdnObject); hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteSend" HRESULT DNPICompleteSend(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr, DWORD dwFirstFrameRTT, DWORD dwFirstFrameRetryCount) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; CAsyncOp *pAsyncOp; DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx], dwFirstFrameRTT [%i], dwFirstFrameRetryCount [%u]", pvCommandContext,hr,dwFirstFrameRTT,dwFirstFrameRetryCount); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DNASSERT( pAsyncOp->GetOpType() == ASYNC_OP_SEND ); // // Indicate complete and remove from active list // pAsyncOp->Lock(); DNASSERT(!pAsyncOp->IsComplete()); pAsyncOp->SetComplete(); pAsyncOp->Unlock(); DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOp->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList); switch( hr ) { case DPN_OK: case DPNERR_ABORTED: #pragma TODO( minara, "remove DPNERR_ABORTED" ) case DPNERR_CONNECTIONLOST: case DPNERR_GENERIC: case DPNERR_OUTOFMEMORY: case DPNERR_TIMEDOUT: case DPNERR_USERCANCEL: { break; } default: { DNASSERT(FALSE); // unexpected return code ! break; } } if (pAsyncOp->IsChild()) { pAsyncOp->Orphan(); } pAsyncOp->SetResult( hr ); pAsyncOp->SetFirstFrameRTT( dwFirstFrameRTT ); pAsyncOp->SetFirstFrameRetryCount( dwFirstFrameRetryCount ); // // Ensure there are no cancels outstanding // DNWaitForCancel(pAsyncOp); pAsyncOp->Release(); pAsyncOp = NULL; // // Release Protocol reference // DNProtocolRelease(pdnObject); hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPIAddressInfoConnect" HRESULT DNPIAddressInfoConnect(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr, IDirectPlay8Address *const pHostAddress, IDirectPlay8Address *const pDeviceAddress ) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; CAsyncOp *pAsyncOp; #ifdef DBG TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx]", pvCommandContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); DNASSERT(pHostAddress != NULL); DNASSERT(pDeviceAddress != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DPFX(DPFPREP, 7,"hr [0x%lx]",hr); #ifdef DBG DP8ASize = 512; IDirectPlay8Address_GetURL(pHostAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 7,"Host address [%s]",DP8ABuffer); DP8ASize = 512; IDirectPlay8Address_GetURL(pDeviceAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 7,"Device address [%s]",DP8ABuffer); #endif // DBG hResultCode = DNPerformNextConnect(pdnObject,pAsyncOp,pHostAddress,pDeviceAddress); hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPIAddressInfoEnum" HRESULT DNPIAddressInfoEnum(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr, IDirectPlay8Address *const pHostAddress, IDirectPlay8Address *const pDeviceAddress ) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; CAsyncOp *pAsyncOp; #ifdef DBG TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx]", pvCommandContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); DNASSERT(pHostAddress != NULL); DNASSERT(pDeviceAddress != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DPFX(DPFPREP, 7,"hr [0x%lx]",hr); #ifdef DBG DP8ASize = 512; IDirectPlay8Address_GetURL(pHostAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 7,"Host address [%s]",DP8ABuffer); DP8ASize = 512; IDirectPlay8Address_GetURL(pDeviceAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 7,"Device address [%s]",DP8ABuffer); #endif // DBG // // Crack open next enum only if not closing // if ((hResultCode = DNAddRefLock(pdnObject)) == DPN_OK) { hResultCode = DNPerformNextEnumQuery(pdnObject,pAsyncOp,pHostAddress,pDeviceAddress); DNDecRefLock(pdnObject); } hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #undef DPF_MODNAME #define DPF_MODNAME "DNPIAddressInfoListen" HRESULT DNPIAddressInfoListen(void *const pvUserContext, void *const pvCommandContext, const HRESULT hr, IDirectPlay8Address *const pDeviceAddress ) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; CAsyncOp *pAsyncOp; #ifdef DBG TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hr [0x%lx]", pvCommandContext,hr); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); DNASSERT(pDeviceAddress != NULL); pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); #ifdef DBG DP8ASize = 512; IDirectPlay8Address_GetURL(pDeviceAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 7,"Device address [%s]",DP8ABuffer); #endif // DBG #ifndef DPNBUILD_ONLYONEADAPTER hResultCode = DNPerformNextListen(pdnObject,pAsyncOp,pDeviceAddress); #endif // ! DPNBUILD_ONLYONEADAPTER hResultCode = DPN_OK; DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); } #ifndef DPNBUILD_NOMULTICAST #undef DPF_MODNAME #define DPF_MODNAME "DNPIIndicateReceiveUnknownSender" HRESULT DNPIIndicateReceiveUnknownSender(void *const pvUserContext, void *const pvListenCommandContext, IDirectPlay8Address *const pSenderAddress, void *const pvData, const DWORD dwDataSize, const HANDLE hBuffer) { HRESULT hResultCode; DIRECTNETOBJECT *pdnObject; CAsyncOp *pAsyncOpListen; SPGETADDRESSINFODATA spInfoData; CAsyncOp *pAsyncOpReceive; DPNHANDLE hAsyncOpReceive; BOOL fReleaseLock; DPFX(DPFPREP, 6,"Parameters: pvListenCommandContext [0x%p], pSenderAddress [0x%p], pvData [0x%p], dwDataSize [%ld], hBuffer [0x%p]", pvListenCommandContext,pSenderAddress,pvData,dwDataSize,hBuffer); DNASSERT(pvUserContext != NULL); DNASSERT(pvListenCommandContext != NULL); DNASSERT(pSenderAddress != NULL); DNASSERT(pvData != NULL); DNASSERT(((DWORD_PTR) pvData & 3) == 0); // data should be DWORD aligned DNASSERT(dwDataSize != 0); DNASSERT(hBuffer != NULL); memset(&spInfoData, 0, sizeof(spInfoData)); fReleaseLock = FALSE; pAsyncOpReceive = NULL; hAsyncOpReceive = NULL; pdnObject = static_cast(pvUserContext); pAsyncOpListen = static_cast(pvListenCommandContext); // // Prevent close while in this call-back // if ((hResultCode = DNAddRefLock(pdnObject)) != DPN_OK) { DPFX(DPFPREP, 1, "Couldn't lock object (0x%lx), ignoring data.", hResultCode); hResultCode = DPN_OK; goto Failure; } fReleaseLock = TRUE; // // Ensure that this is a valid async op // if (pAsyncOpListen->GetOpType() != ASYNC_OP_LISTEN_MULTICAST) { DPFX(DPFPREP, 0, "Receiving data from unknown sender on non-listen-multicast operation (0x%p, type %u)!", pAsyncOpListen, pAsyncOpListen->GetOpType()); DNASSERTX(FALSE, 2); hResultCode = DPN_OK; goto Failure; } // // User or voice message // DPFX(DPFPREP, 7,"Received USER message from unknown sender"); spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER; if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData,pAsyncOpListen->GetProtocolHandle(),&spInfoData)) != DPN_OK) { DPFERR("Could not get LISTEN device address!"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } // // Create an AsyncOp for this receive // if ((hResultCode = AsyncOpNew(pdnObject,&pAsyncOpReceive)) != DPN_OK) { DPFERR("Could not create AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((hResultCode = pdnObject->HandleTable.Create(pAsyncOpReceive,&hAsyncOpReceive)) != DPN_OK) { DPFERR("Could not create Handle for AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } else { // Add a reference for the HandleTable pAsyncOpReceive->AddRef(); pAsyncOpReceive->Lock(); pAsyncOpReceive->SetHandle(hAsyncOpReceive); pAsyncOpReceive->Unlock(); } pAsyncOpReceive->SetOpType( ASYNC_OP_RECEIVE_BUFFER ); pAsyncOpReceive->SetSP( pAsyncOpListen->GetSP() ); // // Add buffer to list of active AsyncOp's // DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOpReceive->m_bilinkActiveList.InsertBefore(&pdnObject->m_bilinkActiveList); DNLeaveCriticalSection(&pdnObject->csActiveList); hResultCode = DNUserReceiveMulticast(pdnObject, NULL, pSenderAddress, spInfoData.pAddress, static_cast(pvData), dwDataSize, hAsyncOpReceive); if (hResultCode == DPNERR_PENDING) { pAsyncOpReceive->SetProtocolHandle( hBuffer ); pAsyncOpReceive->SetCompletion(DNCompleteReceiveBuffer); } else { DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOpReceive->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList); pAsyncOpReceive->Lock(); if (!pAsyncOpReceive->IsCancelled() && !pAsyncOpReceive->IsComplete()) { pAsyncOpReceive->SetComplete(); pAsyncOpReceive->Unlock(); if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOpReceive, NULL ))) { // Release the HandleTable reference pAsyncOpReceive->Release(); } hAsyncOpReceive = NULL; } else { pAsyncOpReceive->Unlock(); } // // Only allow DPNERR_PENDING or DPN_OK // hResultCode = DPN_OK; } IDirectPlay8Address_Release(spInfoData.pAddress); spInfoData.pAddress = NULL; DNDecRefLock(pdnObject); fReleaseLock = FALSE; pAsyncOpReceive->Release(); pAsyncOpReceive = NULL; Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); Failure: if (hAsyncOpReceive) { DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOpReceive->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList); if (SUCCEEDED(pdnObject->HandleTable.Destroy( hAsyncOpReceive, NULL ))) { // Release the HandleTable reference pAsyncOpReceive->Release(); } hAsyncOpReceive = 0; } if (pAsyncOpReceive) { pAsyncOpReceive->Release(); pAsyncOpReceive = NULL; } if (spInfoData.pAddress != NULL) { IDirectPlay8Address_Release(spInfoData.pAddress); spInfoData.pAddress = NULL; } if (fReleaseLock) { DNDecRefLock(pdnObject); fReleaseLock = FALSE; } goto Exit; } #undef DPF_MODNAME #define DPF_MODNAME "DNPICompleteMulticastConnect" HRESULT DNPICompleteMulticastConnect(void *const pvUserContext, void *const pvCommandContext, const HRESULT hrProt, const HANDLE hEndPt, void **const ppvEndPtContext) { HRESULT hResultCode; CAsyncOp *pAsyncOp; CAsyncOp *pConnectParent; CConnection *pConnection; DIRECTNETOBJECT *pdnObject; DPFX(DPFPREP, 6,"Parameters: pvCommandContext [0x%p], hrProt [0x%lx], hEndPt [0x%p]", pvCommandContext,hrProt,hEndPt); DNASSERT(pvUserContext != NULL); DNASSERT(pvCommandContext != NULL); pConnection = NULL; pdnObject = static_cast(pvUserContext); pAsyncOp = static_cast(pvCommandContext); DNASSERT( pAsyncOp->GetOpType() == ASYNC_OP_CONNECT_MULTICAST_SEND || pAsyncOp->GetOpType() == ASYNC_OP_CONNECT_MULTICAST_RECEIVE ); // // Indicate complete and remove from active list // pAsyncOp->Lock(); DNASSERT(!pAsyncOp->IsComplete()); pAsyncOp->SetComplete(); pAsyncOp->Unlock(); DNEnterCriticalSection(&pdnObject->csActiveList); pAsyncOp->m_bilinkActiveList.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csActiveList); // // Clear connect parent from DirectNet object // DNEnterCriticalSection(&pdnObject->csDirectNetObject); pConnectParent = pdnObject->pConnectParent; pdnObject->pConnectParent = NULL; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if (pConnectParent) { pConnectParent->Release(); pConnectParent = NULL; } // // Save multicast endpoint if this was successful // if (hrProt == DPN_OK) { // // Allocate and set up a CConnection object and hand a reference to the Protocol // DNASSERT(pAsyncOp->GetSP() != NULL); if ((hResultCode = ConnectionNew(pdnObject,&pConnection)) != DPN_OK) { DPFERR("Could not get new connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pConnection->SetStatus( CONNECTED ); pConnection->SetEndPt(hEndPt); pConnection->SetSP(pAsyncOp->GetSP()); pConnection->AddRef(); *ppvEndPtContext = pConnection; if (pAsyncOp->GetOpType() == ASYNC_OP_CONNECT_MULTICAST_SEND) { // // We will keep a reference on the connection object on the DirectNet object // pConnection->MakeMulticastSender(); DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->pMulticastSend = pConnection; pConnection = NULL; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); } else { // // We will keep a reference on the connection object in the list off the DirectNet object // pConnection->MakeMulticastReceiver(); if (pAsyncOp->GetParent()) { pConnection->SetContext( pAsyncOp->GetParent()->GetContext() ); } DNEnterCriticalSection(&pdnObject->csDirectNetObject); pConnection->m_bilinkMulticast.InsertBefore(&pdnObject->m_bilinkMulticast); pConnection = NULL; DNLeaveCriticalSection(&pdnObject->csDirectNetObject); } } if (pAsyncOp->IsChild()) { pAsyncOp->Orphan(); } pAsyncOp->Lock(); pAsyncOp->SetResult( hrProt ); pAsyncOp->Unlock(); hResultCode = DPN_OK; Exit: DNASSERT(pConnection == NULL); // // Ensure there are no cancels outstanding // DNWaitForCancel(pAsyncOp); DNASSERT(pAsyncOp != NULL); pAsyncOp->Release(); pAsyncOp = NULL; // // Release protocol reference // DNProtocolRelease(pdnObject); DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return( hResultCode ); Failure: if (pConnection) { pConnection->Release(); pConnection = NULL; } goto Exit; } #endif // DPNBUILD_NOMULTICAST #undef DPF_MODNAME #define DPF_MODNAME "DNProtocolAddRef" void DNProtocolAddRef(DIRECTNETOBJECT *const pdnObject) { LONG lRefCount; DPFX(DPFPREP, 8,"(0x%p) Parameters: (none)",pdnObject); lRefCount = DNInterlockedIncrement((LONG*)&pdnObject->lProtocolRefCount); DPFX(DPFPREP, 8,"(0x%p) Returning (lRefCount = [%ld])",pdnObject,lRefCount); } #undef DPF_MODNAME #define DPF_MODNAME "DNProtocolRelease" void DNProtocolRelease(DIRECTNETOBJECT *const pdnObject) { LONG lRefCount; DPFX(DPFPREP, 8,"(0x%p) Parameters: (none)",pdnObject); lRefCount = DNInterlockedDecrement((LONG*)&pdnObject->lProtocolRefCount); DNASSERT(lRefCount >= 0); if (lRefCount == 0) { DPFX(DPFPREP, 9,"Signalling protocol shutdown !"); if (pdnObject->hProtocolShutdownEvent) { pdnObject->hProtocolShutdownEvent->Set(); } } DPFX(DPFPREP, 8,"(0x%p) Returning (lRefCount = [%ld])",pdnObject,lRefCount); }