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

2006 lines
52 KiB

/*==========================================================================
*
* 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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<const PROTOCOL_ENUM_DATA*>( 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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<const PROTOCOL_ENUM_RESPONSE_DATA*>( 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<DIRECTNETOBJECT*>(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<CAsyncOp*>(pvListenContext))->GetParent() != NULL);
DNASSERT( (static_cast<CAsyncOp*>(pvListenContext))->GetParent()->GetSP() != NULL);
pConnection->SetSP((static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pConnection = static_cast<CConnection*>(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<DIRECTNETOBJECT*>(pvUserContext);
pConnection = static_cast<CConnection*>(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<DIRECTNETOBJECT*>(pvUserContext);
pConnection = static_cast<CConnection*>(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<DWORD*>(pvData);
dwInternalDataSize = dwDataSize - sizeof(DWORD);
if (dwInternalDataSize > 0)
{
pvInternalData = static_cast<void*>(static_cast<BYTE*>(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<BYTE*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(*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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOpListen = static_cast<CAsyncOp*>(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<BYTE*>(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<DIRECTNETOBJECT*>(pvUserContext);
pAsyncOp = static_cast<CAsyncOp*>(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);
}