windows-nt/Source/XPSP1/NT/multimedia/directx/dplay/dnet/lobby/dplconnect.cpp
2020-09-26 16:20:57 +08:00

1002 lines
28 KiB
C++

/*==========================================================================
*
* Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
*
* File: DPLConnect.cpp
* Content: DirectPlay Lobby Connection Functions
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 02/21/00 mjn Created
* 05/08/00 rmt Bug #33616 -- Does not run on Win9X
* 05/30/00 rmt Bug #35700 - ConnectApp(h), Release(h), Release(h) returns OK
* Added an additional release, handles were never getting destroyed
* 06/15/00 rmt Bug #33617 - Must provide method for providing automatic launch of DirectPlay instances
* 06/28/00 rmt Prefix Bug #38082
* 07/08/2000 rmt Bug #38725 - Need to provide method to detect if app was lobby launched
* rmt Bug #38757 - Callback messages for connections may return AFTER WaitForConnection returns
* rmt Bug #38755 - No way to specify player name in Connection Settings
* rmt Bug #38758 - DPLOBBY8.H has incorrect comments
* rmt Bug #38783 - pvUserApplicationContext is only partially implemented
* rmt Added DPLHANDLE_ALLCONNECTIONS and dwFlags (reserved field to couple of funcs).
* 08/05/2000 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles.
* 08/18/2000 rmt Bug #42751 - DPLOBBY8: Prohibit more than one lobby client or lobby app per process
* 08/30/2000 rmt Bug #171827 - Prefix Bug
* 01/04/2001 rodtoll WinBug #94200 - Remove BUGBUGs from Code.
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dnlobbyi.h"
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionNew"
HRESULT DPLConnectionNew(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
DPNHANDLE *const phConnect,
DPL_CONNECTION **const ppdplConnection)
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPNHANDLE handle;
DPFX(DPFPREP, 3,"Parameters: phConnect [0x%p], ppdplConnection [0x%p]",phConnect,ppdplConnection);
if( ppdplConnection == NULL )
{
DPFERR( "ppdplConnection param is NULL -- this should not happen" );
DNASSERT( FALSE );
return DPNERR_GENERIC;
}
// Create connection entry
if ((pdplConnection = static_cast<DPL_CONNECTION*>(DNMalloc(sizeof(DPL_CONNECTION)))) == NULL)
{
DPFERR("Could not allocate Connection entry");
return(DPNERR_OUTOFMEMORY);
}
// Create connection handle
if ((hResultCode = H_Create(&pdpLobbyObject->hsHandles,
static_cast<void*>(pdplConnection),&handle)) != DPN_OK)
{
DPFERR("Could not create Connection handle");
DisplayDNError(0,hResultCode);
DNFree(pdplConnection);
return(hResultCode);
}
// Create connect event
pdplConnection->hConnectEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
if (pdplConnection->hConnectEvent == NULL)
{
DPFERR("Could not create connection connect event");
H_Destroy(&pdpLobbyObject->hsHandles,handle);
DNFree(pdplConnection);
return(DPNERR_OUTOFMEMORY);
}
// Initialize entry
pdplConnection->hConnect = handle;
pdplConnection->dwTargetPID = 0;
pdplConnection->pSendQueue = NULL;
pdplConnection->lRefCount = 1;
pdplConnection->pConnectionSettings = NULL;
pdplConnection->pvConnectContext = NULL;
if (DNInitializeCriticalSection( &pdplConnection->csLock ) == FALSE)
{
DPFERR("Could not initialize connection CS");
CloseHandle(pdplConnection->hConnectEvent);
H_Destroy(&pdpLobbyObject->hsHandles,handle);
DNFree(pdplConnection);
return(DPNERR_OUTOFMEMORY);
}
*phConnect = handle;
if (ppdplConnection != NULL)
*ppdplConnection = pdplConnection;
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionFind"
HRESULT DPLConnectionFind(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnect,
DPL_CONNECTION **const ppdplConnection,
const BOOL bAddRef)
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPFX(DPFPREP, 3,"Parameters: hConnect [0x%lx], ppdplConnection [0x%p], bAddRef [%ld]",
hConnect,ppdplConnection,bAddRef);
DNASSERT(pdpLobbyObject != NULL);
DNASSERT(hConnect != NULL);
DNASSERT(ppdplConnection != NULL);
if ((hResultCode = H_Retrieve(&pdpLobbyObject->hsHandles,hConnect,
reinterpret_cast<void**>(&pdplConnection))) != DPN_OK)
{
DPFERR("Could not retrieve handle");
return(hResultCode);
}
if (bAddRef)
{
InterlockedIncrement(&pdplConnection->lRefCount);
}
*ppdplConnection = pdplConnection;
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DPLConnectionGetConnectSettings
//
// This function gets the connection settings attached to the specified connection.
//
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionGetConnectSettings"
HRESULT DPLConnectionGetConnectSettings( DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
DPNHANDLE const hConnect,
DPL_CONNECTION_SETTINGS * const pdplConnectSettings,
DWORD * const pdwDataSize )
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
hResultCode = DPLConnectionFind(pdpLobbyObject, hConnect, &pdplConnection, TRUE );
if( FAILED( hResultCode ) )
{
DPFERR( "Unable to find specified connection" );
return hResultCode;
}
// Grab lock to keep people from interfering.
DNEnterCriticalSection( &pdplConnection->csLock );
if( !pdplConnection->pConnectionSettings )
{
*pdwDataSize = 0;
hResultCode = DPNERR_DOESNOTEXIST;
goto GETCONNECTIONSETTINGS_EXIT;
}
hResultCode = pdplConnection->pConnectionSettings->CopyToBuffer( (BYTE *) pdplConnectSettings, pdwDataSize );
GETCONNECTIONSETTINGS_EXIT:
DNLeaveCriticalSection( &pdplConnection->csLock );
// Release this function's reference
DPLConnectionRelease( pdpLobbyObject, hConnect );
return hResultCode;
}
// DPLConnectionSetConnectSettings
//
// This function sets the connection settings attached to the specified connection.
//
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionSetConnectSettings"
HRESULT DPLConnectionSetConnectSettings(
DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnect,
CConnectionSettings * pConnectionSettings )
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
hResultCode = DPLConnectionFind(pdpLobbyObject, hConnect, &pdplConnection, TRUE );
if( FAILED( hResultCode ) )
{
DPFERR( "Unable to find specified connection" );
return hResultCode;
}
// Grab lock to prevent other people from interfering
DNEnterCriticalSection( &pdplConnection->csLock );
// Free old one if there is one
if( pdplConnection->pConnectionSettings )
{
delete pdplConnection->pConnectionSettings;
pdplConnection->pConnectionSettings = NULL;
}
pdplConnection->pConnectionSettings = pConnectionSettings;
hResultCode = DPN_OK;
DNLeaveCriticalSection( &pdplConnection->csLock );
DPLConnectionRelease( pdpLobbyObject, hConnect );
return DPN_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionGetContext"
HRESULT DPLConnectionGetContext(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnection,
PVOID *ppvConnectContext )
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
hResultCode = DPLConnectionFind(pdpLobbyObject, hConnection, &pdplConnection, TRUE );
if( FAILED( hResultCode ) )
{
*ppvConnectContext = NULL;
DPFERR( "Unable to find specified connection" );
return hResultCode;
}
// Set connection context for the found handle
DNEnterCriticalSection( &pdplConnection->csLock );
*ppvConnectContext = pdplConnection->pvConnectContext;
DNLeaveCriticalSection( &pdplConnection->csLock );
// Release our reference to the connection
DPLConnectionRelease( pdpLobbyObject, hConnection );
return DPN_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionSetContext"
HRESULT DPLConnectionSetContext(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnection,
PVOID pvConnectContext )
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
hResultCode = DPLConnectionFind(pdpLobbyObject, hConnection, &pdplConnection, TRUE );
if( FAILED( hResultCode ) )
{
DPFERR( "Unable to find specified connection" );
return hResultCode;
}
// Set connection context for the found handle
DNEnterCriticalSection( &pdplConnection->csLock );
pdplConnection->pvConnectContext = pvConnectContext;
DNLeaveCriticalSection( &pdplConnection->csLock );
// Release our reference to the connection
DPLConnectionRelease( pdpLobbyObject, hConnection );
return DPN_OK;
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionRelease"
HRESULT DPLConnectionRelease(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnect)
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
LONG lRefCount;
DPFX(DPFPREP, 3,"Parameters: hConnect [0x%lx]",hConnect);
if ((hResultCode = H_Retrieve(&pdpLobbyObject->hsHandles,hConnect,
reinterpret_cast<void**>(&pdplConnection))) != DPN_OK)
{
DPFERR("Could not retrieve connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
if (InterlockedDecrement(&pdplConnection->lRefCount) == 0)
{
H_Destroy(&pdpLobbyObject->hsHandles,hConnect);
DPFX(DPFPREP, 5,"Freeing object");
if (pdplConnection->pSendQueue)
{
pdplConnection->pSendQueue->Close();
delete pdplConnection->pSendQueue;
pdplConnection->pSendQueue = NULL;
delete pdplConnection->pConnectionSettings;
pdplConnection->pConnectionSettings = NULL;
DNDeleteCriticalSection( &pdplConnection->csLock );
}
CloseHandle(pdplConnection->hConnectEvent);
DNFree(pdplConnection);
}
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionConnect"
HRESULT DPLConnectionConnect(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnect,
const DWORD dwProcessId,
const BOOL fApplication )
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPFX(DPFPREP, 3,"Parameters: hConnect [0x%lx], dwProcessId [0x%lx]",
hConnect,dwProcessId);
DNASSERT(pdpLobbyObject != NULL);
DNASSERT(hConnect != NULL);
DNASSERT(dwProcessId != 0);
if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hConnect,&pdplConnection,TRUE)) != DPN_OK)
{
DPFERR("Could not find connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
pdplConnection->pSendQueue = new CMessageQueue;
if( !pdplConnection->pSendQueue )
{
DPFERR("Could not allocate queue out of memory");
DPLConnectionRelease(pdpLobbyObject,hConnect);
hResultCode = DPNERR_OUTOFMEMORY;
return(hResultCode);
}
hResultCode = pdplConnection->pSendQueue->Open(dwProcessId,
(fApplication) ? DPL_MSGQ_OBJECT_SUFFIX_APPLICATION : DPL_MSGQ_OBJECT_SUFFIX_CLIENT,
DPL_MSGQ_SIZE,
0, INFINITE);
if (hResultCode != DPN_OK)
{
DPFERR("Could not open message queue");
DisplayDNError(0,hResultCode);
delete pdplConnection->pSendQueue;
pdplConnection->pSendQueue = NULL;
DPLConnectionRelease(pdpLobbyObject,hConnect);
return(hResultCode);
}
// Ensure other side is still connected to MsgQ
if (!pdplConnection->pSendQueue->IsReceiving())
{
DPFERR("Application is not receiving");
pdplConnection->pSendQueue->Close();
delete pdplConnection->pSendQueue;
pdplConnection->pSendQueue = NULL;
DPLConnectionRelease(pdpLobbyObject,hConnect);
return(DPNERR_DOESNOTEXIST);
}
DPLConnectionRelease(pdpLobbyObject,hConnect);
return(hResultCode);
}
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionDisconnect"
HRESULT DPLConnectionDisconnect(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnect )
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPL_INTERNAL_MESSAGE_DISCONNECT Msg;
DPFX(DPFPREP, 3,"Parameters: hConnect [0x%lx]",hConnect);
DNASSERT(pdpLobbyObject != NULL);
DNASSERT(hConnect != NULL);
if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hConnect,&pdplConnection,TRUE)) != DPN_OK)
{
DPFERR("Could not find connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
Msg.dwMsgId = DPL_MSGID_INTERNAL_DISCONNECT;
Msg.dwPID = pdpLobbyObject->dwPID;
hResultCode = pdplConnection->pSendQueue->Send(reinterpret_cast<BYTE*>(&Msg),
sizeof(DPL_INTERNAL_MESSAGE_DISCONNECT),INFINITE,DPL_MSGQ_MSGFLAGS_USER1,0);
// Release the reference for the Find above
DPLConnectionRelease(pdpLobbyObject,hConnect);
// Release the interface's reference
DPLConnectionRelease(pdpLobbyObject,hConnect);
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DPLConnectionEnum
//
// Enumerate outstanding connections
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionEnum"
HRESULT DPLConnectionEnum(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
DPNHANDLE *const prghConnect,
DWORD *const pdwNum)
{
HRESULT hResultCode;
HRESULT hr;
DPFX(DPFPREP, 3,"Parameters: prghConnect [0x%p], pdwNum [0x%p]",prghConnect,pdwNum);
hr = H_Enum(&pdpLobbyObject->hsHandles,pdwNum,prghConnect);
if (hr == S_OK)
{
hResultCode = DPN_OK;
}
else if (hr == E_POINTER)
{
hResultCode = DPNERR_BUFFERTOOSMALL;
}
else
{
hResultCode = DPNERR_GENERIC;
}
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DPLConnectionSendREQ
//
// Send a request to connect to another process.
// We will provide the handle of the current Connection to the other side
// to send back as the SenderContext with messages to the local process
// so that we can easily lookup info.
// We will also provide the local PID so the other side can connect to us
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionSendREQ"
HRESULT DPLConnectionSendREQ(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnect,
const DWORD dwPID,
DPL_CONNECT_INFO *const pInfo)
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPL_INTERNAL_MESSAGE_CONNECT_REQ *pMsg = NULL;
DWORD dwSize;
CPackedBuffer PackedBuffer;
DWORD dwConnectSettingsSize;
CConnectionSettings *pConnectSettings = NULL;
PBYTE pbTmpBuffer = NULL;
DPFX(DPFPREP, 3,"Parameters: hConnect [0x%lx]",hConnect);
DNASSERT(pdpLobbyObject != NULL);
DNASSERT(hConnect != NULL);
if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hConnect,&pdplConnection,TRUE)) != DPN_OK)
{
DPFERR("Could not find connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
if (!pdplConnection->pSendQueue->IsReceiving())
{
DPFERR("Other side is not receiving");
DPLConnectionRelease(pdpLobbyObject,hConnect);
return(DPNERR_DOESNOTEXIST);
}
DNEnterCriticalSection( &pdplConnection->csLock );
if( pInfo->pdplConnectionSettings )
{
pConnectSettings = new CConnectionSettings();
if( !pConnectSettings )
{
DPFERR("Error allocating memory");
hResultCode = DPNERR_OUTOFMEMORY;
goto CONNECTREQ_EXIT;
}
hResultCode = pConnectSettings->InitializeAndCopy( pInfo->pdplConnectionSettings );
if( FAILED( hResultCode ) )
{
DPFX(DPFPREP, 0, "Error copying settings hr [0x%x]", hResultCode );
goto CONNECTREQ_EXIT;
}
}
PackedBuffer.Initialize( NULL, 0 );
// Determine size of message to send.
PackedBuffer.AddToFront(NULL,sizeof(DPL_INTERNAL_MESSAGE_CONNECT_REQ_HEADER));
// Add connect settings if they exist
if( pInfo->pdplConnectionSettings )
pConnectSettings->BuildWireStruct(&PackedBuffer);
// Add lobby connect data
PackedBuffer.AddToBack(NULL,pInfo->dwLobbyConnectDataSize);
pbTmpBuffer = new BYTE[PackedBuffer.GetSizeRequired()];
if( !pbTmpBuffer )
{
DPFERR("Error allocating memory" );
hResultCode = DPNERR_OUTOFMEMORY;
goto CONNECTREQ_EXIT;
}
pMsg = (DPL_INTERNAL_MESSAGE_CONNECT_REQ *) pbTmpBuffer;
PackedBuffer.Initialize( pMsg, PackedBuffer.GetSizeRequired() );
hResultCode = PackedBuffer.AddToFront( pMsg, sizeof( DPL_INTERNAL_MESSAGE_CONNECT_REQ_HEADER ) );
if( FAILED( hResultCode ) )
{
DPFX( DPFPREP, 0, "Internal error! hr [0x%x]", hResultCode );
goto CONNECTREQ_EXIT;
}
pMsg->dwMsgId = DPL_MSGID_INTERNAL_CONNECT_REQ;
pMsg->hSender = hConnect;
pMsg->dwSenderPID = dwPID;
if( pInfo->pdplConnectionSettings )
{
hResultCode = pConnectSettings->BuildWireStruct(&PackedBuffer);
if( FAILED( hResultCode ) )
{
DPFX( DPFPREP, 0, "Error building wire struct for settings hr [0x%x]", hResultCode );
goto CONNECTREQ_EXIT;
}
pMsg->dwConnectionSettingsSize = 1;
}
else
{
pMsg->dwConnectionSettingsSize = 0;
}
hResultCode = PackedBuffer.AddToBack(pInfo->pvLobbyConnectData, pInfo->dwLobbyConnectDataSize, FALSE);
if( FAILED( hResultCode ) )
{
DPFX( DPFPREP, 0, "Error adding connect data hr [0x%x]", hResultCode );
goto CONNECTREQ_EXIT;
}
pMsg->dwLobbyConnectDataOffset = PackedBuffer.GetTailOffset();
pMsg->dwLobbyConnectDataSize = pInfo->dwLobbyConnectDataSize;
hResultCode = DPLConnectionSetConnectSettings( pdpLobbyObject, hConnect,pConnectSettings );
if( FAILED( hResultCode ) )
{
DPFERR( "Could not set local copy of connection settings" );
goto CONNECTREQ_EXIT;
}
hResultCode = pdplConnection->pSendQueue->Send(reinterpret_cast<BYTE*>(pMsg),
PackedBuffer.GetSizeRequired(),
INFINITE,
DPL_MSGQ_MSGFLAGS_USER1,
0);
if (hResultCode != DPN_OK)
{
DPFERR("Could not send connect info");
goto CONNECTREQ_EXIT;
}
CONNECTREQ_EXIT:
DNLeaveCriticalSection( &pdplConnection->csLock );
if( pbTmpBuffer )
delete [] pbTmpBuffer;
DPLConnectionRelease(pdpLobbyObject,hConnect);
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
if( FAILED( hResultCode ) )
{
if( pConnectSettings )
delete pConnectSettings;
}
return(hResultCode);
}
// DPLConnectionReceiveREQ
//
// Receive a request to connect.
// Attempt to connect to the requesting process using the PID supplied.
// Keep the supplied SenderContext for future sends directed at that process.
// Send a connect acknowledge
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionReceiveREQ"
HRESULT DPLConnectionReceiveREQ(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
BYTE *const pBuffer)
{
HRESULT hResultCode;
DPNHANDLE handle;
DPL_CONNECTION *pdplConnection;
DPL_INTERNAL_MESSAGE_CONNECT_REQ *pMsg;
DPL_MESSAGE_CONNECT MsgConnect;
DPL_CONNECTION_SETTINGS *pSettingsBuffer = NULL;
DWORD dwSettingsBufferSize = 0;
BOOL fLobbyLaunching = FALSE;
CConnectionSettings *pConnectSettings = NULL;
BYTE *pbTmpBuffer = NULL;
DPFX(DPFPREP, 3,"Parameters: pBuffer [0x%p]",pBuffer);
DNASSERT(pdpLobbyObject != NULL);
DNASSERT(pBuffer != NULL);
pMsg = reinterpret_cast<DPL_INTERNAL_MESSAGE_CONNECT_REQ*>(pBuffer);
if ((hResultCode = DPLConnectionNew(pdpLobbyObject,&handle,&pdplConnection)) != DPN_OK)
{
DPFERR("Could not create new connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
if ((hResultCode = DPLConnectionConnect(pdpLobbyObject,handle,pMsg->dwSenderPID,FALSE)) != DPN_OK)
{
DPFERR("Could not perform requested connection");
goto CONNECTRECVREQ_ERROR;
}
pdplConnection->pSendQueue->SetSenderHandle(pMsg->hSender);
pdplConnection->dwTargetPID = pMsg->dwSenderPID;
if ((hResultCode = DPLConnectionSendACK(pdpLobbyObject,handle)) != DPN_OK)
{
DPFERR("Could not send connection acknowledge");
goto CONNECTRECVREQ_ERROR;
}
if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_MULTICONNECT)
{
DPFX(DPFPREP, 1, "Multiconnect flag specified, returning app to available status" );
pdpLobbyObject->pReceiveQueue->MakeAvailable();
}
if( pMsg->dwConnectionSettingsSize )
{
pConnectSettings = new CConnectionSettings();
if( !pConnectSettings )
{
DPFERR("Error allocating structure");
hResultCode = DPNERR_OUTOFMEMORY;
goto CONNECTRECVREQ_ERROR;
}
hResultCode = pConnectSettings->Initialize( &pMsg->dplConnectionSettings, (UNALIGNED BYTE *) pMsg );
if( FAILED( hResultCode ) )
{
DPFX( DPFPREP, 0, "Error copying connection settings from wire hr=[0x%x]", hResultCode );
goto CONNECTRECVREQ_ERROR;
}
}
// Update the local connection settings
hResultCode = DPLConnectionSetConnectSettings( pdpLobbyObject, handle, pConnectSettings );
if( FAILED( hResultCode ) )
{
DPFX( DPFPREP, 0, "Error setting connection settings from wire hr=[0x%x]", hResultCode );
goto CONNECTRECVREQ_ERROR;
}
// Indicate connection to application
MsgConnect.dwSize = sizeof(DPL_MESSAGE_CONNECT);
MsgConnect.hConnectId = handle;
if( pMsg->dwLobbyConnectDataSize )
{
// Got to copy the connect data locally to an aligned buffer to ensure alignment -- ack
pbTmpBuffer = new BYTE[pMsg->dwLobbyConnectDataSize];
if( !pbTmpBuffer )
{
DPFERR("Error allocating structure");
hResultCode = DPNERR_OUTOFMEMORY;
goto CONNECTRECVREQ_ERROR;
}
memcpy( pbTmpBuffer, pBuffer + pMsg->dwLobbyConnectDataOffset, pMsg->dwLobbyConnectDataSize );
MsgConnect.pvLobbyConnectData = pbTmpBuffer;
MsgConnect.dwLobbyConnectDataSize = pMsg->dwLobbyConnectDataSize;
}
else
{
MsgConnect.pvLobbyConnectData = NULL;
MsgConnect.dwLobbyConnectDataSize = 0;
}
MsgConnect.pvConnectionContext = NULL;
if( pConnectSettings )
{
MsgConnect.pdplConnectionSettings = pConnectSettings->GetConnectionSettings();
}
else
{
MsgConnect.pdplConnectionSettings = NULL;
}
// If we're lobby launching set the connect event before calling the message handler
// otherwise we may encounter deadlock then timeout if user blocks in callback
if( pdpLobbyObject->dwFlags & DPL_OBJECT_FLAG_LOOKINGFORLOBBYLAUNCH )
{
fLobbyLaunching = TRUE;
pdpLobbyObject->dpnhLaunchedConnection = handle;
}
hResultCode = (pdpLobbyObject->pfnMessageHandler)(pdpLobbyObject->pvUserContext,
DPL_MSGID_CONNECT,
reinterpret_cast<BYTE*>(&MsgConnect));
if( FAILED( hResultCode ) )
{
DPFX( DPFPREP, 0, "Error returned from user's callback -- ignoring hr [0x%x]", hResultCode );
}
// Set the context for this connection
DPLConnectionSetContext( pdpLobbyObject, handle, MsgConnect.pvConnectionContext );
if( pbTmpBuffer )
delete [] pbTmpBuffer;
// If we're looking for a lobby launch, set the dpnhLaunchedConnection to cache the connection handle
SetEvent(pdpLobbyObject->hConnectEvent);
DPFX(DPFPREP, 3,"Returning: [0x%lx]",DPN_OK);
return(DPN_OK);
CONNECTRECVREQ_ERROR:
if( pbTmpBuffer )
delete [] pbTmpBuffer;
if( pConnectSettings )
delete pConnectSettings;
DPLConnectionDisconnect(pdpLobbyObject,handle);
DPLConnectionRelease(pdpLobbyObject,handle);
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DPLConnectionSendACK
//
// Send a connect acknowledge.
// Provide the local handle for the connection to the other side for future
// sends to the local process
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionSendACK"
HRESULT DPLConnectionSendACK(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hConnect)
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPL_INTERNAL_MESSAGE_CONNECT_ACK Msg;
DPFX(DPFPREP, 3,"Parameters: hConnect [0x%lx]",hConnect);
DNASSERT(pdpLobbyObject != NULL);
DNASSERT(hConnect != NULL);
if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hConnect,&pdplConnection,TRUE)) != DPN_OK)
{
DPFERR("Could not find connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
Msg.dwMsgId = DPL_MSGID_INTERNAL_CONNECT_ACK;
Msg.hSender = hConnect;
hResultCode = pdplConnection->pSendQueue->Send(reinterpret_cast<BYTE*>(&Msg),
sizeof(DPL_INTERNAL_MESSAGE_CONNECT_ACK),
INFINITE,
DPL_MSGQ_MSGFLAGS_USER1,
0);
if (hResultCode != DPN_OK)
{
DPFERR("Could not send connection acknowledge");
DisplayDNError(0,hResultCode);
DPLConnectionRelease(pdpLobbyObject,hConnect);
return(hResultCode);
}
DPLConnectionRelease(pdpLobbyObject,hConnect);
hResultCode = DPN_OK;
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DPLConnectionReceiveACK
//
// Receive a connect acknowledge
// Keep the supplied SenderContext for future sends directed at that process.
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionReceiveACK"
HRESULT DPLConnectionReceiveACK(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hSender,
BYTE *const pBuffer)
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPL_INTERNAL_MESSAGE_CONNECT_ACK *pMsg;
DPFX(DPFPREP, 3,"Parameters: hSender [0x%lx], pBuffer [0x%p]",hSender,pBuffer);
DNASSERT(pdpLobbyObject != NULL);
DNASSERT(pBuffer != NULL);
pMsg = reinterpret_cast<DPL_INTERNAL_MESSAGE_CONNECT_ACK*>(pBuffer);
if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hSender,&pdplConnection,TRUE)) != DPN_OK)
{
DPFERR("Could not find sender's connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
pdplConnection->pSendQueue->SetSenderHandle(pMsg->hSender);
SetEvent(pdplConnection->hConnectEvent);
DPLConnectionRelease(pdpLobbyObject,hSender);
// Indicate that a connection was made by setting event
SetEvent(pdpLobbyObject->hConnectEvent);
hResultCode = DPN_OK;
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}
// DPLConnectionReceiveDisconnect
//
// Receive a disconnect
// Terminate the connection
#undef DPF_MODNAME
#define DPF_MODNAME "DPLConnectionReceiveDisconnect"
HRESULT DPLConnectionReceiveDisconnect(DIRECTPLAYLOBBYOBJECT *const pdpLobbyObject,
const DPNHANDLE hSender,
BYTE *const pBuffer,
const HRESULT hrDisconnectReason )
{
HRESULT hResultCode;
DPL_CONNECTION *pdplConnection;
DPL_MESSAGE_DISCONNECT MsgDisconnect;
DPFX(DPFPREP, 3,"Parameters: hSender [0x%lx]",hSender);
DNASSERT(pdpLobbyObject != NULL);
if ((hResultCode = DPLConnectionFind(pdpLobbyObject,hSender,&pdplConnection,TRUE)) != DPN_OK)
{
DPFERR("Could not find sender's connection");
DisplayDNError(0,hResultCode);
return(hResultCode);
}
// Indicate disconnect to user
MsgDisconnect.dwSize = sizeof(DPL_MESSAGE_DISCONNECT);
MsgDisconnect.hDisconnectId = hSender;
MsgDisconnect.hrReason = hrDisconnectReason;
// Return code is irrelevant, at this point we're going to indicate regardless
hResultCode = DPLConnectionGetContext( pdpLobbyObject, hSender, &MsgDisconnect.pvConnectionContext );
if( FAILED( hResultCode ) )
{
DPFX(DPFPREP, 0, "Error getting connection context for 0x%x hr=0x%x", hSender, hResultCode );
}
hResultCode = (pdpLobbyObject->pfnMessageHandler)(pdpLobbyObject->pvUserContext,
DPL_MSGID_DISCONNECT,
reinterpret_cast<BYTE*>(&MsgDisconnect));
// Fixed memory leak, DPLConnectionRelease will free the send queue
// pdplConnection->pSendQueue->Close();
// pdplConnection->pSendQueue = NULL;
DPLConnectionRelease(pdpLobbyObject,hSender);
DPLConnectionRelease(pdpLobbyObject,hSender);
hResultCode = DPN_OK;
DPFX(DPFPREP, 3,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
}