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
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);
|
|
}
|
|
|