|
|
/*==========================================================================
* * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved. * * File: Connect.cpp * Content: DNET connection routines *@@BEGIN_MSINTERNAL * History: * Date By Reason * ==== == ====== * 09/01/99 mjn Created * 12/23/99 mjn Hand all NameTable update sends from Host to worker thread * 12/23/99 mjn Fixed Host and AllPlayers short-cut pointer use * 12/28/99 mjn Moved Async Op stuff to Async.h * 12/29/99 mjn Reformed DN_ASYNC_OP to use hParentOp instead of lpvUserContext * 12/29/99 mjn Turned off Instance GUID verification - TODO - turn back on ! * 01/06/00 mjn Moved NameTable stuff to NameTable.h * 01/07/00 mjn Moved Misc Functions to DNMisc.h * 01/07/00 mjn DNHostVerifyConnect ensures connection to Host player only * 01/08/00 mjn Failed connection returns HRESULT and buffer from Host * 01/08/00 mjn Added group owner to NameTable * 01/08/00 mjn Changed DNERR_INVALIDHOST to DNERR_NOTHOST * 01/08/00 mjn Removed unused connection info * 01/09/00 mjn Transfer Application Description at connect * 01/10/00 mjn Fixed Application Description usage * 01/11/00 mjn Use CPackedBuffers instead of DN_ENUM_BUFFER_INFOs * 01/13/00 mjn Removed DIRECTNETOBJECT from Pack/UnpackApplicationDesc * 01/14/00 mjn Removed pvUserContext from DN_NAMETABLE_ENTRY * 01/14/00 mjn Added password to DN_APPLICATION_DESC_PACKED_INFO * 01/15/00 mjn Replaced DN_COUNT_BUFFER with CRefCountBuffer * 01/16/00 mjn Moved User callback stuff to User.h * 01/17/00 mjn Fixed ConnectToPeer function names * 01/18/00 mjn Moved Pack/UnpackNameTableInfo to NameTable.cpp * 01/24/00 mjn Replaced on-wire message pointers to offsets * 02/01/00 mjn Implement Player/Group context values * 03/23/00 mjn Set player context through Connect * 03/24/00 mjn Set player context through INDICATE_CONNECT notification * 04/03/00 mjn Verify DNET version on connect * 04/09/00 mjn Modified Connect process to use CAsyncOp * 04/16/00 mjn DNSendMessage() uses CAsyncOp * 04/18/00 mjn CConnection tracks connection status better * mjn Fixed player count problem * mjn Return connect user reply buffer * 04/19/00 mjn Fixed DNConnectToHost2 to set DirectNet object flags to CONNECTED * mjn Update NameTable operations to use DN_WORKER_JOB_SEND_NAMETABLE_OPERATION * 04/20/00 mjn Host queries for connecting players' address if not specified * 05/03/00 mjn Prevent unrequired RETURN_BUFFER message when CONNECT fails on Host player * 05/03/00 mjn Use GetHostPlayerRef() rather than GetHostPlayer() * 05/08/00 mjn Host sets connecting player's Connection as soon as player entry created * 05/09/00 mjn Fixed New Player connection sequence to send NAMETABLE_ACK earlier * 05/23/00 mjn Added DNConnectToPeerFailed() * 06/14/00 mjn Added DNGetLocalAddress() * 06/19/00 mjn Fixed connect process to better handle ALL_ADAPTERS case * 06/22/00 mjn NameTable::UnpackNameTableInfo() returns local players DPNID * mjn Replace CConnection::MakeConnecting(),MakeConnected() with SetStatus() * 06/24/00 mjn Added DNHostDropPlayer() to handle failed existing player connects to new players * 06/25/00 mjn Added code to update lobby when DISCONNECTED * 06/26/00 mjn Indicate COULDNOTCONNECT to lobby if connect to Host fails * 06/27/00 rmt Added abstraction for COM_Co(Un)Initialize * mjn Host will attempt to determine connecting player's address if not specified in connect block * 07/05/00 mjn More robust handling of disconnecting joining players during connection process * 07/06/00 mjn More connect fixes * 07/20/00 mjn The CONNECT process was revamped - new completions, asyncop structure, messages * mjn Better error handling for shutdown in DNHostVerifyConnect() * mjn Fixed up DNHostDropPlayer() to inform NewPlayer of drop * 07/21/00 mjn Added code to handle unreachable players during connect process * 07/22/00 mjn Extract connecting player's DNET version * 07/25/00 mjn Update connect parent async op's result at end of DNConnectToHost2() * 07/27/00 mjn Fixed locking problem with CAsyncOp::MakeChild() * 07/29/00 mjn Save connection in DNConnectToHost1() on connect parent for better clean up * 07/30/00 mjn Renamed DNGetLocalAddress() to DNGetLocalDeviceAddress() * 07/31/00 mjn Added hrReason to DNTerminateSession() * mjn Added dwDestroyReason to DNHostDisconnect() * 08/02/00 mjn Removed unused code * 08/05/00 RichGr IA64: Use %p format specifier in DPFs for 32/64-bit pointers and handles. * 08/05/00 rmt Bug #41356 - DPLAY8: CORE: Connections refused by DPlay leak address objects * 08/05/00 mjn Added pParent to DNSendGroupMessage and DNSendMessage() * 08/06/00 mjn Added CWorkerJob * 08/08/00 mjn Mark groups created after CREATE_GROUP * 08/15/00 rmt Bug #42506 - DPLAY8: LOBBY: Automatic connection settings not being sent * 08/25/00 mjn Perform queued NameTable operations in DNConnectToHost2() * 08/28/00 mjn Only compare major version numbers in DNHostVerifyConnect() * 09/04/00 mjn Added CApplicationDesc * 09/05/00 mjn Set NameTable DPNID mask when connecting * 09/13/00 mjn Perform queued operations after creating group in DNConnectToHost2() * 09/17/00 mjn Split CNameTable.m_bilinkEntries into m_bilinkPlayers and m_bilinkGroups * 09/26/00 mjn Removed locking from CNameTable::SetVersion() and CNameTable::GetNewVersion() * 09/27/00 mjn ACK nametable to Host after creating groups and local and host players * 10/11/00 mjn Fixed up DNAbortConnect() and use it instead of DNConnectToHostFailed() * 10/17/00 mjn Fixed clean up for unreachable players * 01/25/01 mjn Fixed 64-bit alignment problem in received messages * 02/12/01 mjn Fixed CConnection::GetEndPt() to track calling thread * 03/30/01 mjn Changes to prevent multiple loading/unloading of SP's * 04/05/01 mjn Call DNHostDisconnect() with DPNDESTROYPLAYERREASON_NORMAL in DNHostConnect1() * 05/07/01 vpo Whistler 384350: "DPLAY8: CORE: Messages from server can be indicated before connect completes" * 05/22/01 mjn Properly set DirectNetObject as CONNECTED for successful client connect * 06/03/01 mjn Don't clean up connect parent from DirectNetObject in DNAbortConnect() (will be done in DNTerminateSession()) * 06/08/01 mjn Disconnect connection in DNConnectToHostFailed() * 06/25/01 mjn Use connect address for host if missing when installing name table in DNConnectToHost2() * 07/24/01 mjn Added DPNBUILD_NOSERVER compile flag *@@END_MSINTERNAL * ***************************************************************************/
#include "dncorei.h"
//
// Accept a connection from a NewPlayer as the Host in peer-to-peer, or as the Server in
// Client-Server modes.
//
// The connection process is a multi part affair, requiring a bit of
// synchronization between the Host and the NewPlayer.
//
// In the first part:
// The Host waits for the NewPlayer to send player game info
// The Host verifies that everything is in order
// If everything is okay:
// The Host assigns the NewPlayer a DNID,
// Adds the NewPlayer to the Host's NameTable,
// Sends the NameTable to the NewPlayer,
// Sends an ADD_PLAYER message to existing players to add NewPlayer to their NameTable's
// Otherwise:
// Inform NewPlayer that connection process failed
//
// In the second part:
// The Host awaits confirmation from the NewPlayer that the table was received AND installed.
// The Host instructs existing players to connect to the NewPlayer
//
// DNHostConnect1
//
// Called once the connecting player has sent his player info.
//
// - Verify NewPlayer and application info
// - Assign a DNID to NewPlayer
// - Add NewPlayer to Host's NameTable
// - Send Name table to NewPlayer
// - Send ADD_PLAYER message to existing players
//
// LPVOID lpvData Player and application info
// DWORD dwBufferSize Size of player and application info
// HANDLE hEndPt End point handle
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostConnect1"
HRESULT DNHostConnect1(DIRECTNETOBJECT *const pdnObject, const PVOID pvBuffer, const DWORD dwBufferSize, CConnection *const pConnection) { HRESULT hResultCode; UNALIGNED WCHAR *pwszName; UNALIGNED WCHAR *pwszPassword; PVOID pvData; PVOID pvConnectData; UNALIGNED DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO *pInfo; CNameTableEntry *pNTEntry; CNameTableEntry *pAllPlayersGroup; CPackedBuffer packedBuffer; CRefCountBuffer *pRefCountBuffer; CWorkerJob *pWorkerJob; IDirectPlay8Address *pAddress; CPackedBuffer PackedBuffer; void *pvPlayerContext; BOOL bPlayerVerified; BOOL fDisconnect; HANDLE hEndPt; void *pvReplyBuffer; DWORD dwReplyBufferSize; void *pvReplyBufferContext; CCallbackThread CallbackThread; #ifdef DBG
TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p], dwBufferSize [%ld], pConnection [0x%p]",pvBuffer,dwBufferSize,pConnection);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL); DNASSERT(pConnection != NULL);
pAddress = NULL; pRefCountBuffer = NULL; pNTEntry = NULL; pAllPlayersGroup = NULL; pWorkerJob = NULL; bPlayerVerified = FALSE; pvReplyBuffer = NULL; dwReplyBufferSize = 0; pvReplyBufferContext = NULL; CallbackThread.Initialize();
//
// Extract player and application info
//
pInfo = static_cast<DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO*>(pvBuffer); if (pInfo->dwNameOffset) { pwszName = reinterpret_cast<UNALIGNED WCHAR*>(static_cast<BYTE*>(pvBuffer) + pInfo->dwNameOffset); } else { pwszName = NULL; }
if (pInfo->dwPasswordOffset) { pwszPassword = reinterpret_cast<UNALIGNED WCHAR*>(static_cast<BYTE*>(pvBuffer) + pInfo->dwPasswordOffset); } else { pwszPassword = NULL; }
if (pInfo->dwDataOffset) { pvData = static_cast<void*>(static_cast<BYTE*>(pvBuffer) + pInfo->dwDataOffset); } else { pvData = NULL; }
if (pInfo->dwConnectDataOffset) { pvConnectData = (PVOID)((char *)pvBuffer + pInfo->dwConnectDataOffset); } else { pvConnectData = NULL; }
if (pInfo->dwURLOffset) { #ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address, reinterpret_cast<void**>(&pAddress)); #else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, reinterpret_cast<void**>(&pAddress), FALSE); #endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK) { DPFERR("Could not create IDirectPlay8Address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); return(hResultCode); }
DPFX(DPFPREP, 5,"Connecting Player URL [%hs]",static_cast<char*>(pvBuffer) + pInfo->dwURLOffset); if ((hResultCode = IDirectPlay8Address_BuildFromURLA( pAddress, static_cast<char*>(pvBuffer) + pInfo->dwURLOffset )) != DPN_OK) { DPFERR("Could not build IDirectPlay8Address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } } else { DPFX(DPFPREP, 5,"No address URL specified - Host will have to determine it"); if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK) { DPFERR("Could not retrieve EndPoint from Connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
hResultCode = DNGetClearAddress(pdnObject,hEndPt,&pAddress,TRUE);
pConnection->ReleaseEndPt(&CallbackThread);
if (hResultCode != DPN_OK) { DPFERR("Could not determine Clear Address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } #ifdef DBG
DP8ASize = 512; IDirectPlay8Address_GetURL(pAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 5,"Remote Address [%s]",DP8ABuffer); #endif // DBG
}
#ifdef DBG
if (pwszName != NULL) { if ((((DWORD_PTR) pwszName) % sizeof (WCHAR)) == 0) { DPFX(DPFPREP, 5,"Connecting Player: Name [%ls], Data Size [%ld], Connect Data Size [%ld]", pwszName,pInfo->dwDataSize,pInfo->dwConnectDataSize); } else { DPFX(DPFPREP, 5,"Connecting Player: Name [unaligned_name], Data Size [%ld], Connect Data Size [%ld]", pInfo->dwDataSize,pInfo->dwConnectDataSize); } } else { DPFX(DPFPREP, 5,"Connecting Player: No name, Data Size [%ld], Connect Data Size [%ld]", pInfo->dwDataSize,pInfo->dwConnectDataSize); } #endif // DBG
//
// Avoid alignment errors
//
GUID guidApplication; GUID guidInstance; guidApplication = pInfo->guidApplication; guidInstance = pInfo->guidInstance;
//
// Ensure this connect is valid
//
if ((hResultCode = DNHostVerifyConnect( pdnObject, pConnection, pInfo->dwFlags, pInfo->dwDNETVersion, pwszPassword, &guidApplication, &guidInstance, pvConnectData, pInfo->dwConnectDataSize, pAddress, &pvPlayerContext, &pvReplyBuffer, &dwReplyBufferSize, &pvReplyBufferContext)) != DPN_OK) { DPFX(DPFPREP, 5,"Connect failed, hResultCode = [0x%lx]",hResultCode);
//
// Disconnect this connection. We will also remove it from the indicated list.
//
DNEnterCriticalSection(&pdnObject->csConnectionList); if (!pConnection->m_bilinkIndicated.IsEmpty()) { pConnection->Release(); } pConnection->m_bilinkIndicated.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csConnectionList);
pConnection->Disconnect(); // Terminate this connection
hResultCode = DPN_OK; // We handled everything okay !
goto Failure; // For clean up
}
bPlayerVerified = TRUE;
//
// I am assuming that the player count has been updated by HostVerifyConnect.
// That means that until we flag the connection as CONNECTed, we will manually
// have to decrement it.
//
//
// Create player entry
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pNTEntry)) != DPN_OK) { DPFERR("Could not get new NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// This function takes the lock internally
pNTEntry->UpdateEntryInfo( pwszName, pInfo->dwNameSize, pvData, pInfo->dwDataSize, DPNINFO_NAME | DPNINFO_DATA, FALSE);
pNTEntry->SetDNETVersion( pInfo->dwDNETVersion ); if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { pNTEntry->MakePeer(); } else { pNTEntry->MakeClient(); }
if (pvPlayerContext) { pNTEntry->SetContext(pvPlayerContext); } pNTEntry->StartConnecting(); pNTEntry->SetIndicated(); pNTEntry->NotifyAddRef(); pNTEntry->SetAddress(pAddress); IDirectPlay8Address_Release(pAddress); pAddress = NULL;
//
// Add player to NameTable
//
if ((hResultCode = pdnObject->NameTable.AddEntry(pNTEntry)) != DPN_OK) { pdnObject->NameTable.Unlock(); DPFERR("Could not add entry to NameTable"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Set up connection
// The connection should be "CONNECTING" or a disconnect has been issued since the NewPlayer sent
// their connect info. Once the DPNID is set on the connection, the standard disconnect handler
// will take care of clean up. If the DPNID is NOT set on the connection, the disconnect code
// will just release the connection, without cleaning up the NameTable or the NameTableEntry.
// Since the NameTable version may have changed since the NewPlayer was added, we will need to
// delete the player from the NameTable (and generate a new version number). We will flag this
// case, and just send out the DELETE_PLAYER message after sending out the ADD_PLAYER
//
pConnection->Lock(); if (pConnection->IsConnecting()) { pConnection->SetStatus( CONNECTED ); fDisconnect = FALSE; } else { DPFX(DPFPREP, 5,"NewPlayer has disconnected while joining - send out ADD_PLAYER and then DELETE_PLAYER"); fDisconnect = TRUE; } pConnection->SetDPNID( pNTEntry->GetDPNID() ); pNTEntry->SetConnection( pConnection ); pConnection->Unlock();
//
// Now that this connection is part of the NameTableEntry, remove it from the indicated list.
//
DNEnterCriticalSection(&pdnObject->csConnectionList); if (!pConnection->m_bilinkIndicated.IsEmpty()) { pConnection->Release(); } pConnection->m_bilinkIndicated.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csConnectionList);
//
// Send name table to player
//
if (!fDisconnect) { hResultCode = DNSendConnectInfo(pdnObject,pNTEntry,pConnection,pvReplyBuffer,dwReplyBufferSize); if (hResultCode != DPN_OK && hResultCode != DPNERR_PENDING) { DPFERR("Could not send name table to player"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); #pragma TODO(minara,"Clean up here")
goto Failure; } } if (pvReplyBuffer) { DNUserReturnBuffer(pdnObject,DPN_OK,pvReplyBuffer,pvReplyBufferContext); pvReplyBuffer = NULL; dwReplyBufferSize = 0; pvReplyBufferContext = NULL; }
//
// Setup name table entry to be passed to other players
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { packedBuffer.Initialize(NULL,0); if ((hResultCode = pNTEntry->PackEntryInfo(&packedBuffer)) != DPNERR_BUFFERTOOSMALL) { DPFERR("Unknown error encountered trying to pack NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((hResultCode = RefCountBufferNew(pdnObject,packedBuffer.GetSizeRequired(),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create new RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); if ((hResultCode = pNTEntry->PackEntryInfo(&packedBuffer)) != DPN_OK) { DPFERR("Could not pack NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
//
// Send ADD_PLAYER messages to other players (with lower versions)
//
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create worker thread job (add player)"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_ADD_PLAYER ); pWorkerJob->SetSendNameTableOperationVersion( pNTEntry->GetVersion() ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
//
// If we were in the process of disconnecting, we will need to clean up now
//
if (fDisconnect) { DNHostDisconnect(pdnObject,pNTEntry->GetDPNID(),DPNDESTROYPLAYERREASON_NORMAL); }
pNTEntry->Release(); pNTEntry = NULL;
// Now, wait for synchronization (player has loaded name table)
hResultCode = DPN_OK;
Exit: CallbackThread.Deinitialize(); DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pvReplyBuffer) { //
// Return buffer to HostPlayer
//
DNUserReturnBuffer(pdnObject,DPN_OK,pvReplyBuffer,pvReplyBufferContext); pvReplyBuffer = NULL; dwReplyBufferSize = 0; pvReplyBufferContext = NULL; } if (bPlayerVerified) { pdnObject->ApplicationDesc.DecPlayerCount(); } if (pAddress) { IDirectPlay8Address_Release(pAddress); pAddress = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pAllPlayersGroup) { pAllPlayersGroup->Release(); pAllPlayersGroup = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
goto Exit; }
// DNHostConnect2
//
// Mark player as "available" in NameTable
// Send INSTRUCT_CONNECT messages to the existing players to add new player
//
// CConnection *pConnection Connection for connecting player
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostConnect2"
HRESULT DNHostConnect2(DIRECTNETOBJECT *const pdnObject, CConnection *const pConnection) { HRESULT hResultCode; DPNID dpnid; CRefCountBuffer *pRefCountBuffer; CNameTableEntry *pNTEntry; CWorkerJob *pWorkerJob; DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT *pInfo;
DPFX(DPFPREP, 4,"Parameters: pConnection [0x%p]",pConnection);
DNASSERT(pdnObject != NULL); DNASSERT(pConnection != NULL);
pRefCountBuffer = NULL; pNTEntry = NULL; pWorkerJob = NULL;
pConnection->Lock(); dpnid = pConnection->GetDPNID(); pConnection->Unlock();
pdnObject->NameTable.PopulateConnection(pConnection);
//
// Instruct existing players to connect to NewPlayer
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { DPFX(DPFPREP, 5,"Instruct existing players to connect to NewPlayer [0x%lx]",dpnid);
// Need version number of this player
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find player in nametable"); DisplayDNError(0,hResultCode); // DNASSERT(FALSE);
goto Failure; }
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not create CountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT*>(pRefCountBuffer->GetBufferAddress()); pInfo->dpnid = dpnid;
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.GetNewVersion( &pInfo->dwVersion ); pdnObject->NameTable.Unlock(); pInfo->dwVersionNotUsed = 0;
if ((hResultCode = WorkerJobNew(pdnObject,&pWorkerJob)) != DPN_OK) { DPFERR("Could not create worker thread job (add player)"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pWorkerJob->SetJobType( WORKER_JOB_SEND_NAMETABLE_OPERATION ); pWorkerJob->SetSendNameTableOperationMsgId( DN_MSG_INTERNAL_INSTRUCT_CONNECT ); pWorkerJob->SetSendNameTableOperationVersion( pInfo->dwVersion ); pWorkerJob->SetSendNameTableOperationDPNIDExclude( 0 ); pWorkerJob->SetRefCountBuffer( pRefCountBuffer );
DNQueueWorkerJob(pdnObject,pWorkerJob); pWorkerJob = NULL;
pNTEntry->Release(); pNTEntry = NULL;
pRefCountBuffer->Release(); pRefCountBuffer = NULL; } hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
// DNHostVerifyConnect
//
// Host connection verification. Ensure that the player connecting meets ALL criteria
// including:
// correct mode (client/server or peer/peer)
// correct instance guid
// correct application (if specified)
// correct password (if specified)
// correct user spec (through call-back)
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostVerifyConnect"
HRESULT DNHostVerifyConnect(DIRECTNETOBJECT *const pdnObject, CConnection *const pConnection, const DWORD dwFlags, const DWORD dwDNETVersion, UNALIGNED WCHAR *const pwszPassword, GUID *const pguidApplication, GUID *const pguidInstance, PVOID const pvConnectData, const DWORD dwConnectDataSize, IDirectPlay8Address *const pAddress, void **const ppvPlayerContext, void **const ppvReplyBuffer, DWORD *const pdwReplyBufferSize, void **const ppvReplyBufferContext) { HRESULT hResultCode; HRESULT hrFailure; PVOID pvReplyData; DWORD dwReplyDataSize; PVOID pvReplyContext; DWORD dwBufferSize; HANDLE hEndPt; CNameTableEntry *pLocalPlayer; CRefCountBuffer *pRefCountBuffer; CPackedBuffer packedBuffer; IDirectPlay8Address *pDevice; DN_INTERNAL_MESSAGE_CONNECT_FAILED *pInfo; BOOL fDecPlayerCount; CCallbackThread CallbackThread; GUID guidnull; #ifdef DBG
TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG
DPFX(DPFPREP, 6,"Parameters: dwFlags [0x%lx], dwDPlay8Version [0x%lx], pwszPassword [0x%p], pguidApplication [0x%p], pguidInstance [0x%p], pvConnectData [0x%p], dwConnectDataSize [%ld]", dwFlags,dwDNETVersion,pwszPassword,pguidApplication,pguidInstance,pvConnectData,dwConnectDataSize);
DNASSERT(pdnObject != NULL); DNASSERT(ppvReplyBuffer != NULL); DNASSERT(pdwReplyBufferSize != NULL); DNASSERT(ppvReplyBufferContext != NULL);
pLocalPlayer = NULL; pRefCountBuffer = NULL; pvReplyData = NULL; dwReplyDataSize = 0; pvReplyContext = NULL; pDevice = NULL; fDecPlayerCount = FALSE; memset(&guidnull, 0, sizeof(guidnull)); CallbackThread.Initialize();
//
// Ensure we're not closing or host migrating
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & DN_OBJECT_FLAG_CLOSING) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); hResultCode = DPNERR_ALREADYCLOSING; goto CleanUp; } if (pdnObject->dwFlags & DN_OBJECT_FLAG_HOST_MIGRATING) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); hResultCode = DPNERR_NOTHOST; goto Failure; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Ensure we are the Host
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Connection received by non-host player"); hResultCode = DPNERR_NOTHOST; goto Failure; } if (!pLocalPlayer->IsHost()) { DPFERR("Connection received by non-host player"); hResultCode = DPNERR_NOTHOST; goto Failure; } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Verify Mode
//
if ((pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) && !(dwFlags & DN_OBJECT_FLAG_PEER)) { DPFX(DPFPREP, 7,"Non peer player attempting connection to peer"); hResultCode = DPNERR_INVALIDINTERFACE; goto Failure; }
#ifndef DPNBUILD_NOSERVER
if ((pdnObject->dwFlags & DN_OBJECT_FLAG_SERVER) && !(dwFlags & DN_OBJECT_FLAG_CLIENT)) { DPFX(DPFPREP, 7,"Non client player attempting connection to server"); hResultCode = DPNERR_INVALIDINTERFACE; goto Failure; } #endif // DPNBUILD_NOSERVER
//
// Verify DNET version - we will only compare the high 16-bits (major number)
// - we will allow different low 16-bits (minor number)
//
if ((dwDNETVersion & 0xffff0000) != (DN_VERSION_CURRENT & 0xffff0000)) { DPFX(DPFPREP, 7,"Invalid DPlay8 version!"); hResultCode = DPNERR_INVALIDVERSION; goto Failure; }
//
// Validate instance GUID
//
if (pguidInstance && (*pguidInstance != guidnull)) { if (!pdnObject->ApplicationDesc.IsEqualInstanceGuid(pguidInstance)) { DPFERR("Invalid Instance GUID specified at connection"); hResultCode = DPNERR_INVALIDINSTANCE; goto Failure; } }
//
// Validate application (if specified)
//
if (pguidApplication && (*pguidApplication != guidnull)) { if (!pdnObject->ApplicationDesc.IsEqualApplicationGuid(pguidApplication)) { DPFERR("Invalid Application GUID specified at connection"); hResultCode = DPNERR_INVALIDAPPLICATION; goto Failure; } }
//
// Validate password
//
if (!pdnObject->ApplicationDesc.IsEqualPassword(pwszPassword)) { DPFERR("Incorrect password (required) specified at connection"); hResultCode = DPNERR_INVALIDPASSWORD; goto Failure; }
//
// Get device address this connection came in on
//
if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK) { DPFERR("Could not extract endpoint from CConnection"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_GENERIC; // Is there a better one ?
goto Failure; }
hResultCode = DNGetLocalDeviceAddress(pdnObject,hEndPt,&pDevice);
pConnection->ReleaseEndPt(&CallbackThread);
if (hResultCode != DPN_OK) { DPFERR("Could not determine local device address"); DisplayDNError(0,hResultCode); hResultCode = DPNERR_GENERIC; // Is there a better one ?
goto Failure; } #ifdef DBG
DP8ASize = 512; IDirectPlay8Address_GetURL(pDevice,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 5,"Local Device Address [%s]",DP8ABuffer); #endif // DBG
//
// Increment AppDesc count
//
hResultCode = pdnObject->ApplicationDesc.IncPlayerCount( TRUE ); if (hResultCode != DPN_OK) { DPFX(DPFPREP, 7,"Could not add player to game"); DisplayDNError(0,hResultCode); goto Failure; } fDecPlayerCount = TRUE; // only for error handling
//
// Validate user specified data (through call-back)
//
if (pvConnectData) {
DPFX(DPFPREP, 7,"dwConnectDataSize [%ld]",dwConnectDataSize); } else { DPFX(DPFPREP, 7,"No connect data given"); }
if ((hResultCode = DNUserIndicateConnect( pdnObject, pvConnectData, dwConnectDataSize, &pvReplyData, &dwReplyDataSize, &pvReplyContext, pAddress, pDevice, ppvPlayerContext)) != DPN_OK) { DPFERR("Application declined connection attempt"); hResultCode = DPNERR_HOSTREJECTEDCONNECTION; goto Failure; }
IDirectPlay8Address_Release(pDevice); pDevice = NULL;
//
// Save reply buffer
//
if ((pvReplyData) && (dwReplyDataSize != 0)) { *ppvReplyBuffer = pvReplyData; *pdwReplyBufferSize = dwReplyDataSize; *ppvReplyBufferContext = pvReplyContext; } else { *ppvReplyBuffer = NULL; *pdwReplyBufferSize = 0; *ppvReplyBufferContext = NULL; }
Exit:
CallbackThread.Deinitialize(); DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure:
if (fDecPlayerCount) { pdnObject->ApplicationDesc.DecPlayerCount(); }
//
// Send a message back to the connecting player that this failed
//
DPFX(DPFPREP, 7,"Connect failed [0x%lx]",hResultCode); hrFailure = hResultCode; if (pvReplyData == NULL) { dwReplyDataSize = 0; // basic validation
} dwBufferSize = sizeof(DN_INTERNAL_MESSAGE_CONNECT_FAILED) + dwReplyDataSize; DPFX(DPFPREP, 7,"Failure buffer is [%ld] bytes",dwBufferSize);
//
// Create and fill failure message buffer
//
if ((hResultCode = RefCountBufferNew(pdnObject,dwBufferSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); goto CleanUp; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); pInfo = reinterpret_cast<DN_INTERNAL_MESSAGE_CONNECT_FAILED*>(pRefCountBuffer->GetBufferAddress()); if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CONNECT_FAILED))) != DPN_OK) { DPFERR("Could not add header to message buffer"); DisplayDNError(0,hResultCode); goto CleanUp; } if (pvReplyData) { if ((hResultCode = packedBuffer.AddToBack(pvReplyData,dwReplyDataSize)) != DPN_OK) { DPFERR("Could not add reply to failure buffer"); DisplayDNError(0,hResultCode); goto CleanUp; } pInfo->dwReplyOffset = packedBuffer.GetTailOffset(); pInfo->dwReplySize = dwReplyDataSize; DNUserReturnBuffer(pdnObject,DPN_OK,pvReplyData,pvReplyContext); // Return buffer
} else { pInfo->dwReplyOffset = 0; pInfo->dwReplySize = 0; } pInfo->hResultCode = hrFailure;
//
// Send failure message
//
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_CONNECT_FAILED, NULL, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL);
pRefCountBuffer->Release(); pRefCountBuffer = NULL;
CleanUp: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pDevice) { IDirectPlay8Address_Release(pDevice); pDevice = NULL; } goto Exit; }
//
// DNHostDropPlayer
//
// An existing player in a peer-peer game could not connect to a NewPlayer and is informing the
// Host of this situation. As a result, the Host will drop inform the NewPlayer of this and then
// drop the NewPlayer from the game
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNHostDropPlayer"
HRESULT DNHostDropPlayer(DIRECTNETOBJECT *const pdnObject, const DPNID dpnid, // ExistingPlayer who could not connect to NewPlayer
void *const pvBuffer) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CNameTableEntry *pNTEntry; CConnection *pConnection; UNALIGNED DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED *pInfo; DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED *pMsg;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p]",pvBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL);
pRefCountBuffer = NULL; pNTEntry = NULL; pConnection = NULL;
pInfo = static_cast<DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED*>(pvBuffer); DPFX(DPFPREP, 5,"Connection to [0x%lx] failed",pInfo->dpnid);
//
// Get connection for NewPlayer
//
if ((hResultCode = pdnObject->NameTable.FindEntry(pInfo->dpnid,&pNTEntry)) != DPN_OK) { DPFERR("NewPlayer no longer in NameTable - not to worry"); hResultCode = DPN_OK; goto Failure; } if ((hResultCode = pNTEntry->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Connection for NewPlayer no longer valid - not to worry"); hResultCode = DPN_OK; goto Failure; } pNTEntry->Release(); pNTEntry = NULL;
//
// Send message to NewPlayer informing them of which existing player could not connect to them
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not allocate RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_CONNECT_ATTEMPT_FAILED*>(pRefCountBuffer->GetBufferAddress()); pMsg->dpnid = dpnid; hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_CONNECT_ATTEMPT_FAILED, pInfo->dpnid, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL); if (hResultCode != DPNERR_PENDING) { DPFERR("Could not send message to NewPlayer - assume he is gone or going"); DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
hResultCode = DPN_OK; goto Failure; } pRefCountBuffer->Release(); pRefCountBuffer = NULL;
//
// We will just drop (or at least attempt to drop) the connection
//
pConnection->Disconnect(); pConnection->Release(); pConnection = NULL;
hResultCode = DNHostDisconnect(pdnObject,pInfo->dpnid,DPNDESTROYPLAYERREASON_HOSTDESTROYEDPLAYER);
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } goto Exit; }
//
// Perform a connection to a host player (either host in peer-to-peer or server in client-server).
// This processes the handshaking of the name table between the host and the player.
// The first step is to send the player and application info to the host for verification
// The second step is to receive and process the name table from the host
// The last step is to wait for connections from other players and populate the name table
// It assumes that the connection to the host has already been initiated.
//
// DNPrepareConnectInfo
//
// Prepare the connection info block which will be sent to the Host player once a connection
// has been established.
#undef DPF_MODNAME
#define DPF_MODNAME "DNPrepareConnectInfo"
HRESULT DNPrepareConnectInfo(DIRECTNETOBJECT *const pdnObject, CConnection *const pConnection, CRefCountBuffer **const ppRefCountBuffer) { HRESULT hResultCode; DWORD dwSize; DWORD dwPasswordSize; DWORD dwAddressSize; HANDLE hEndPt; CRefCountBuffer *pRefCountBuffer; CPackedBuffer packedBuffer; IDirectPlay8Address *pAddress; DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO *pInfo; CCallbackThread CallbackThread; #ifdef DBG
TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG
DPFX(DPFPREP, 4,"Parameters: pConnection [0x%p], ppRefCountBuffer [0x%p]",pConnection,ppRefCountBuffer);
DNASSERT(pdnObject != NULL); DNASSERT(pConnection != NULL); DNASSERT(ppRefCountBuffer != NULL);
pRefCountBuffer = NULL; pAddress = NULL; dwAddressSize = 0; CallbackThread.Initialize();
//
// Get clear address
//
dwAddressSize = 0; if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) == DPN_OK) { if ((hResultCode = DNGetClearAddress(pdnObject,hEndPt,&pAddress,FALSE)) == DPN_OK) { if (pAddress != NULL) { // Get address URL size
IDirectPlay8Address_GetURL(pAddress,NULL,&dwAddressSize); DNASSERT(dwAddressSize != 0); #ifdef DBG
DP8ASize = 512; IDirectPlay8Address_GetURL(pAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 5,"Remote Address [%s]",DP8ABuffer); #endif // DBG
} } pConnection->ReleaseEndPt(&CallbackThread); }
// Determine total size of connection info buffer
if (pdnObject->ApplicationDesc.GetPassword() != NULL) dwPasswordSize = (wcslen(pdnObject->ApplicationDesc.GetPassword()) + 1) * sizeof(WCHAR); else dwPasswordSize = 0;
DNASSERT(pdnObject->NameTable.GetDefaultPlayer() != NULL);
dwSize = sizeof(DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO) + pdnObject->dwConnectDataSize + dwAddressSize + dwPasswordSize + pdnObject->NameTable.GetDefaultPlayer()->GetDataSize() + pdnObject->NameTable.GetDefaultPlayer()->GetNameSize();
// Allocate connection info buffer
DPFX(DPFPREP, 7,"Need to allocate [%ld] bytes",dwSize); if ((hResultCode = RefCountBufferNew(pdnObject,dwSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not allocate space for connection info"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize()); pInfo = static_cast<DN_INTERNAL_MESSAGE_PLAYER_CONNECT_INFO*>(packedBuffer.GetHeadAddress());
// Type of interface
#ifndef DPNBUILD_NOSERVER
pInfo->dwFlags = pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER | DN_OBJECT_FLAG_CLIENT | DN_OBJECT_FLAG_SERVER); #else
pInfo->dwFlags = pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER | DN_OBJECT_FLAG_CLIENT); #endif // DPNBUILD_NOSERVER
// Version of DIRECTNET
pInfo->dwDNETVersion = DN_VERSION_CURRENT;
// Name
if (pdnObject->NameTable.GetDefaultPlayer()->GetNameSize()) { if ((hResultCode = packedBuffer.AddToBack(pdnObject->NameTable.GetDefaultPlayer()->GetName(), pdnObject->NameTable.GetDefaultPlayer()->GetNameSize())) != DPN_OK) { DPFERR("Could not add name to connection buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pInfo->dwNameOffset = packedBuffer.GetTailOffset(); pInfo->dwNameSize = pdnObject->NameTable.GetDefaultPlayer()->GetNameSize(); } else { pInfo->dwNameOffset = 0; pInfo->dwNameSize = 0; }
// Player data
if (pdnObject->NameTable.GetDefaultPlayer()->GetData() && pdnObject->NameTable.GetDefaultPlayer()->GetDataSize()) { if ((hResultCode = packedBuffer.AddToBack(pdnObject->NameTable.GetDefaultPlayer()->GetData(), pdnObject->NameTable.GetDefaultPlayer()->GetDataSize())) != DPN_OK) { DPFERR("Could not add connect data to connection buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pInfo->dwDataOffset = packedBuffer.GetTailOffset(); pInfo->dwDataSize = pdnObject->NameTable.GetDefaultPlayer()->GetDataSize(); } else { pInfo->dwDataOffset = 0; pInfo->dwDataSize = 0; }
// Password
if (dwPasswordSize) { if ((hResultCode = packedBuffer.AddToBack(pdnObject->ApplicationDesc.GetPassword(),dwPasswordSize)) != DPN_OK) { DPFERR("Could not add password to connection buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pInfo->dwPasswordOffset = packedBuffer.GetTailOffset(); pInfo->dwPasswordSize = dwPasswordSize; } else { pInfo->dwPasswordOffset = 0; pInfo->dwPasswordSize = 0; }
// Connect data
if (pdnObject->pvConnectData) { if ((hResultCode = packedBuffer.AddToBack(pdnObject->pvConnectData,pdnObject->dwConnectDataSize)) != DPN_OK) { DPFERR("Could not add connect data to connection buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pInfo->dwConnectDataOffset = packedBuffer.GetTailOffset(); pInfo->dwConnectDataSize = pdnObject->dwConnectDataSize; } else { pInfo->dwConnectDataOffset = 0; pInfo->dwConnectDataSize = 0; }
// Clear address URL
if (dwAddressSize) { if ((hResultCode = packedBuffer.AddToBack(NULL,dwAddressSize)) != DPN_OK) { DPFERR("Could not add address URL to connection buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((hResultCode = IDirectPlay8Address_GetURLA(pAddress, static_cast<char*>(packedBuffer.GetTailAddress()), &dwAddressSize)) != DPN_OK) { DPFERR("Could not get address URL"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pInfo->dwURLOffset = packedBuffer.GetTailOffset(); pInfo->dwURLSize = dwAddressSize; } else { pInfo->dwURLOffset = 0; pInfo->dwURLSize = 0; }
// Instance and appplication GUIDs
memcpy(&pInfo->guidInstance,pdnObject->ApplicationDesc.GetInstanceGuid(),sizeof(GUID)); memcpy(&pInfo->guidApplication,pdnObject->ApplicationDesc.GetApplicationGuid(),sizeof(GUID));
*ppRefCountBuffer = pRefCountBuffer; pRefCountBuffer = NULL;
if (pAddress) { IDirectPlay8Address_Release(pAddress); pAddress = NULL; }
hResultCode = DPN_OK;
Exit: CallbackThread.Deinitialize(); DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure:
if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pAddress) { IDirectPlay8Address_Release(pAddress); pAddress = NULL; }
goto Exit; }
// DNConnectToHost1
//
// After receiving protocol level connection acknowledgement, send player and application info
// CConnection *pConnection Connection to host
#undef DPF_MODNAME
#define DPF_MODNAME "DNConnectToHost1"
HRESULT DNConnectToHost1(DIRECTNETOBJECT *const pdnObject, CConnection *const pConnection) { HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; CAsyncOp *pAsyncOp; CAsyncOp *pConnectParent;
DPFX(DPFPREP, 4,"Parameters: pConnection [0x%p]",pConnection);
DNASSERT(pdnObject != NULL); DNASSERT(pConnection != NULL);
pRefCountBuffer = NULL; pAsyncOp = NULL; pConnectParent = NULL;
//
// Get connect parent (and make sure we're not closing)
// We will also store the CConnection on the connect parent for future clean up.
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) { DPFERR("Object is CLOSING or DISCONNECTING"); DNLeaveCriticalSection(&pdnObject->csDirectNetObject); pConnection->Disconnect(); hResultCode = DPN_OK; goto Failure; } DNASSERT(pdnObject->pConnectParent != NULL); pdnObject->pConnectParent->SetConnection( pConnection ); pdnObject->pConnectParent->AddRef(); pConnectParent = pdnObject->pConnectParent; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Prepare connect info
//
if ((hResultCode = DNPrepareConnectInfo(pdnObject,pConnection,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not prepare connect info"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } DNASSERT(pRefCountBuffer != NULL);
//
// Send connect info
//
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_PLAYER_CONNECT_INFO, 0, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, pConnectParent, &pAsyncOp);
if (hResultCode == DPNERR_PENDING) { pAsyncOp->SetCompletion( DNCompleteSendConnectInfo ); pAsyncOp->Release(); pAsyncOp = NULL;
hResultCode = DPN_OK; } else { //
// Save error code, clean up DirectNetObject and fail
//
DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
DNAbortConnect(pdnObject,hResultCode); }
pConnectParent->Release(); pConnectParent = NULL; pRefCountBuffer->Release(); pRefCountBuffer = NULL;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pConnectParent) { pConnectParent->Release(); pConnectParent = NULL; } goto Exit; }
// DN_ConnectToHost2
//
// Extract and install the host supplied name table
// Send name table acknowledgement to the host
// Propegate ADD_PLAYER messages to the application for host and local players
// Propegate CREATE_GROUP messages to the application for groups in the name table
//
// PVOID pvData NameTable buffer
// CConnection *pConnection Connection to host
#undef DPF_MODNAME
#define DPF_MODNAME "DNConnectToHost2"
HRESULT DNConnectToHost2(DIRECTNETOBJECT *const pdnObject, const PVOID pvData, CConnection *const pConnection) { HRESULT hResultCode; CNameTableEntry *pNTEntry; CNameTableEntry *pHostPlayer; CNameTableEntry *pLocalPlayer; CNameTableOp *pNTOp; CBilink *pBilink; DPNID dpnid; DWORD dwFlags; CConnection *pLocalConnection; BOOL fNotify; IDirectPlay8Address *pIDevice; IDirectPlay8Address *pIHost; CAsyncOp *pListenParent; CAsyncOp *pConnectParent; HANDLE hEndPt; CCallbackThread CallbackThread;
DPFX(DPFPREP, 4,"Parameters: pvData [0x%p], pConnection [0x%p]",pvData,pConnection);
DNASSERT(pdnObject != NULL); DNASSERT(pvData != NULL); DNASSERT(pConnection != NULL);
pNTEntry = NULL; pHostPlayer = NULL; pLocalPlayer = NULL; pLocalConnection = NULL; pIDevice = NULL; pIHost = NULL; pListenParent = NULL; pConnectParent = NULL; CallbackThread.Initialize();
//
// Initial try to catch a close
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); hResultCode = DPN_OK; goto Failure; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Extract application description and name table
//
if ((hResultCode = DNReceiveConnectInfo(pdnObject,pvData,pConnection,&dpnid)) != DPN_OK) { DPFERR("Could not extract name table passed by host"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Get Connection object for local player
//
if ((hResultCode = ConnectionNew(pdnObject,&pLocalConnection)) != DPN_OK) { DPFERR("Could not create new Connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
//
// Get Host and Local players
//
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHostPlayer )) != DPN_OK) { DPFERR("Could not find Host player"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not find Local player"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Ensure we have an address for the Host player
//
if (pHostPlayer->GetAddress() == NULL) { //
// Use connect address if it exists
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pConnectAddress) { IDirectPlay8Address_AddRef(pdnObject->pConnectAddress); pIHost = pdnObject->pConnectAddress; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pIHost == NULL) { //
// No connect address was specified, so we will query for the host's address
//
if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK) { DPFERR("Could not get end point from connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
hResultCode = DNGetClearAddress(pdnObject,hEndPt,&pIHost,TRUE);
pConnection->ReleaseEndPt(&CallbackThread);
if (hResultCode != DPN_OK) { DPFERR("Could not get clear address for Host player"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } } pHostPlayer->SetAddress(pIHost); IDirectPlay8Address_Release(pIHost); pIHost = NULL; }
//
// Start LISTENs for CONNECTs from existing players in Peer-Peer mode
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK) { DPFERR("Could not get end point from connection"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
hResultCode = DNGetLocalDeviceAddress(pdnObject,hEndPt,&pIDevice);
pConnection->ReleaseEndPt(&CallbackThread);
if (hResultCode != DPN_OK) { DPFERR("Could not get LISTEN address from endpoint"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// Parent Async Op
if ((hResultCode = AsyncOpNew(pdnObject,&pListenParent)) != DPN_OK) { DPFERR("Could not create AsyncOp"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pListenParent->SetOpType( ASYNC_OP_LISTEN ); pListenParent->MakeParent(); pListenParent->SetCompletion( DNCompleteListen ); dwFlags = DN_LISTENFLAGS_DISALLOWENUMS; if (pdnObject->ApplicationDesc.GetReservedDataSize() > 0) { dwFlags |= DN_LISTENFLAGS_SESSIONDATA; } if (pdnObject->ApplicationDesc.IsFastSigned()) { dwFlags|=DN_LISTENFLAGS_FASTSIGNED; } else if (pdnObject->ApplicationDesc.IsFullSigned()) { dwFlags|=DN_LISTENFLAGS_FULLSIGNED; } pListenParent->SetOpFlags( dwFlags );
// Perform child LISTEN
hResultCode = DNPerformSPListen(pdnObject, pIDevice, pListenParent, NULL); if (hResultCode != DPN_OK) { DPFERR("Could not perform child LISTEN"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// Store parent LISTEN on DirectNet object
#pragma BUGBUG( minara, "What if we are closing down and have already terminated all listens ?" )
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pListenParent->AddRef(); pdnObject->pListenParent = pListenParent; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pListenParent->Release(); pListenParent = NULL; IDirectPlay8Address_Release(pIDevice); pIDevice = NULL; }
//
// Indicate peer connected - we will perform this before notifying the host so that
// DN_OBJECT_FLAG_CONNECTED is set when existing player CONNECTs come in
//
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING)) { DNLeaveCriticalSection(&pdnObject->csDirectNetObject); #pragma TODO( minara, "Shut down listen" )
hResultCode = DPN_OK; goto Failure; } pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING); pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED; DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Inform application of groups and players.
// We will inform the application of
// - CREATE_GROUP
// - ADD_PLAYER (for Local and Host players)
// - ADD_PLAYER_TO_GROUP
//
pdnObject->NameTable.ReadLock(); pBilink = pdnObject->NameTable.m_bilinkGroups.GetNext(); while (pBilink != &pdnObject->NameTable.m_bilinkGroups) { pNTEntry = CONTAINING_OBJECT(pBilink,CNameTableEntry,m_bilinkEntries); pNTEntry->AddRef(); pdnObject->NameTable.Unlock();
fNotify = FALSE; pNTEntry->Lock(); if (!pNTEntry->IsAvailable() && !pNTEntry->IsDisconnecting() && !pNTEntry->IsAutoDestructGroup()) { pNTEntry->MakeAvailable(); pNTEntry->NotifyAddRef(); pNTEntry->NotifyAddRef(); pNTEntry->SetInUse(); fNotify = TRUE; } pNTEntry->Unlock();
if (fNotify) { DNASSERT(!pNTEntry->IsAllPlayersGroup()); DNUserCreateGroup(pdnObject,pNTEntry);
pNTEntry->PerformQueuedOperations();
pdnObject->NameTable.PopulateGroup( pNTEntry ); }
pNTEntry->Release(); pNTEntry = NULL;
pdnObject->NameTable.ReadLock(); if (pBilink->IsEmpty()) { pBilink = pdnObject->NameTable.m_bilinkGroups.GetNext(); } else { pBilink = pBilink->GetNext(); } } pNTEntry = NULL; pdnObject->NameTable.Unlock(); }
//
// We will pre-set the Host connection, so that any operation from the CREATE_PLAYER notification call-back
// for the local player will be able to find the Host player's connection (to send messages to). We will
// not, however, expose the Host player to the user yet.
//
pHostPlayer->Lock(); pHostPlayer->SetConnection( pConnection ); pHostPlayer->Unlock();
//
// Add Local player
//
pLocalConnection->SetStatus( CONNECTED ); pLocalConnection->SetEndPt(NULL); pLocalConnection->MakeLocal();
//
// Preset player context
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); DNASSERT(pdnObject->pConnectParent); if (pdnObject->pConnectParent) { pdnObject->pConnectParent->AddRef(); pConnectParent = pdnObject->pConnectParent; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if (pConnectParent) { pConnectParent->Lock(); if (pConnectParent->GetContext()) { pLocalPlayer->Lock(); pLocalPlayer->SetContext(pConnectParent->GetContext()); pLocalPlayer->Unlock(); } pConnectParent->SetResult( DPN_OK ); pConnectParent->Unlock(); pConnectParent->Release(); pConnectParent = NULL; }
#ifndef DPNBUILD_NOSERVER
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER|DN_OBJECT_FLAG_SERVER)) #else
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER)) #endif // DPNBUILD_NOSERVER
{ pdnObject->ApplicationDesc.IncPlayerCount( FALSE ); pLocalConnection->SetDPNID(pLocalPlayer->GetDPNID()); pdnObject->NameTable.PopulateConnection(pLocalConnection); } else { pLocalPlayer->Lock(); pLocalPlayer->SetConnection(pLocalConnection); pLocalPlayer->StopConnecting(); pLocalPlayer->MakeAvailable(); pLocalPlayer->Unlock();
pdnObject->NameTable.DecOutstandingConnections(); } pLocalConnection->Release(); pLocalConnection = NULL;
//
// Add Host player
//
#ifndef DPNBUILD_NOSERVER
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER|DN_OBJECT_FLAG_SERVER)) #else
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_PEER)) #endif // DPNBUILD_NOSERVER
{ pdnObject->ApplicationDesc.IncPlayerCount( FALSE );
//
// If we have lost the connection to the host player, we will abort the connect process
//
pConnection->Lock(); if (!pConnection->IsDisconnecting() && !pConnection->IsInvalid()) { pConnection->SetDPNID(pHostPlayer->GetDPNID()); pConnection->SetStatus( CONNECTED ); pConnection->Unlock(); pdnObject->NameTable.PopulateConnection(pConnection); } else { pConnection->Unlock(); DNAbortConnect(pdnObject,DPNERR_CONNECTIONLOST); goto Failure; } } else { pConnection->SetStatus( CONNECTED );
pHostPlayer->Lock(); pHostPlayer->StopConnecting();
//
// We won't make the host player available until after CONNECT_COMPLETE
// has been indicated and the callback has returned.
//
//pHostPlayer->MakeAvailable();
pHostPlayer->Unlock();
pdnObject->NameTable.DecOutstandingConnections(); }
pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Process any nametable operations that might have arrived
//
pdnObject->NameTable.ReadLock(); pBilink = pdnObject->NameTable.m_bilinkNameTableOps.GetNext(); while (pBilink != &pdnObject->NameTable.m_bilinkNameTableOps) { pNTOp = CONTAINING_OBJECT(pBilink,CNameTableOp,m_bilinkNameTableOps); if ((pNTOp->GetVersion() == (pdnObject->NameTable.GetVersion() + 1)) && !pNTOp->IsInUse()) { pNTOp->SetInUse(); pdnObject->NameTable.Unlock();
hResultCode = DNNTPerformOperation( pdnObject, pNTOp->GetMsgId(), pNTOp->GetRefCountBuffer()->GetBufferAddress() );
pdnObject->NameTable.ReadLock(); } else { //
// Once we find an operation that we won't perform, there is no point continuing
//
break; } pBilink = pBilink->GetNext(); } pdnObject->NameTable.Unlock();
//
// Send connect info acknowledgement to host
//
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_ACK_CONNECT_INFO, pHostPlayer->GetDPNID(), NULL, 0, NULL, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL); if (hResultCode != DPNERR_PENDING) { DNAbortConnect(pdnObject,hResultCode); goto Failure; }
pHostPlayer->Release(); pHostPlayer = NULL;
hResultCode = DPN_OK;
Exit: CallbackThread.Deinitialize(); DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pHostPlayer) { pHostPlayer->Release(); pHostPlayer = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pLocalConnection) { pLocalConnection->Release(); pLocalConnection = NULL; } if (pIDevice) { IDirectPlay8Address_Release(pIDevice); pIDevice = NULL; } if (pIHost) { IDirectPlay8Address_Release(pIHost); pIHost = NULL; } if (pListenParent) { pListenParent->Release(); pListenParent = NULL; } if (pConnectParent) { pConnectParent->Release(); pConnectParent = NULL; } goto Exit; }
// DNConnectToHostFailed
//
// Clean up if an attempt to connect to the HostPlayer fails
#undef DPF_MODNAME
#define DPF_MODNAME "DNConnectToHostFailed"
HRESULT DNConnectToHostFailed(DIRECTNETOBJECT *const pdnObject, PVOID const pvBuffer, const DWORD dwBufferSize, CConnection *const pConnection) { CAsyncOp *pConnectParent; HRESULT hResultCode; CRefCountBuffer *pRefCountBuffer; UNALIGNED DN_INTERNAL_MESSAGE_CONNECT_FAILED *pInfo;
DPFX(DPFPREP, 4,"Parameters: pvBuffer [0x%p], dwBufferSize [%ld], pConnection [0x%x]",pvBuffer,dwBufferSize,pConnection);
DNASSERT(pdnObject != NULL); DNASSERT(pvBuffer != NULL || dwBufferSize == 0);
pRefCountBuffer = NULL; pConnectParent = NULL;
if (pvBuffer != NULL) { pInfo = static_cast<DN_INTERNAL_MESSAGE_CONNECT_FAILED*>(pvBuffer); if ((pInfo->dwReplyOffset != 0) && (pInfo->dwReplySize != 0)) { //
// Extract reply buffer
//
if ((hResultCode = RefCountBufferNew(pdnObject,pInfo->dwReplySize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer - ignore and continue"); DisplayDNError(0,hResultCode); } else { memcpy( pRefCountBuffer->GetBufferAddress(), static_cast<BYTE*>(pvBuffer) + pInfo->dwReplyOffset, pInfo->dwReplySize ); } }
//
// Update connect operation parent with results
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); DNASSERT(pdnObject->pConnectParent); if (pdnObject->pConnectParent) { pdnObject->pConnectParent->Lock(); pdnObject->pConnectParent->SetResult( pInfo->hResultCode ); pdnObject->pConnectParent->SetRefCountBuffer( pRefCountBuffer ); pdnObject->pConnectParent->Unlock(); } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } DPFX(DPFPREP, 0,"ConnectToHostFailed: [0x%lx]",pInfo->hResultCode); }
//
// Release the reference on the connection since we will be dropping the link.
// We are safe releasing the connection here, since the protocol will prevent
// the Host's DISCONNECT from being passed up to us until after this thread
// has returned back down.
//
pConnection->Disconnect();
//
// Clean up DirectNetObject
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_HOST_CONNECTED)); if (pdnObject->pConnectParent) { pConnectParent = pdnObject->pConnectParent; pdnObject->pConnectParent = NULL; } if( pdnObject->pIDP8ADevice ) { IDirectPlay8Address_Release( pdnObject->pIDP8ADevice ); pdnObject->pIDP8ADevice = NULL; } if( pdnObject->pConnectAddress ) { IDirectPlay8Address_Release( pdnObject->pConnectAddress ); pdnObject->pConnectAddress = NULL; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pConnectParent) { pConnectParent->Release(); pConnectParent = NULL; }
DPFX(DPFPREP, 4,"Returning: DPN_OK"); return(DPN_OK); }
//
// DNAbortConnect
//
// Abort the CONNECT process by cleaning up the DirectNet object and terminating the session
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNAbortConnect"
HRESULT DNAbortConnect(DIRECTNETOBJECT *const pdnObject, const HRESULT hrConnect) { HRESULT hResultCode; CAsyncOp *pConnectParent;
DPFX(DPFPREP, 4,"Parameters: hrConnect [0x%lx]",hrConnect);
DNASSERT(pdnObject != NULL);
pConnectParent = NULL;
//
// Clean up DirectNetObject
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); pdnObject->dwFlags &= (~(DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_HOST_CONNECTED)); if (pdnObject->pConnectParent) { pdnObject->pConnectParent->AddRef(); pConnectParent = pdnObject->pConnectParent; }
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Set error code on connect operation completion
//
if (pConnectParent) { pConnectParent->Lock(); pConnectParent->SetResult( hrConnect ); pConnectParent->Unlock(); }
//
// Shut down
//
DNTerminateSession(pdnObject,DPN_OK);
if (pConnectParent) { pConnectParent->Release(); pConnectParent = NULL; }
hResultCode = DPN_OK;
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
// Player to player connection occurs at the direction of the host. (Peer-to-peer)
//
// Once a NewPlayer has connected to the host,
// The Host will send the NewPlayer's NameTable entry to all existing players
// Once the NewPlayer has installed the NameTable, it informs the host
// The Host will instruct the existing players to connect to the NewPlayer
//
// When an existing player establishes a connection with the NewPlayer
// The existing player send their DNID to the NewPlayer and an ADD_PLAYER to app
// The NewPlayer activates the connecting (existing) player and sends ADD_PLAYER to app
//
// DNPlayerConnect1
//
// Receive an existing player's DNID. This is called by the NewPlayer. If valid, send an
// ADD_PLAYER message to the application
#undef DPF_MODNAME
#define DPF_MODNAME "DNPlayerConnect1"
HRESULT DNPlayerConnect1(DIRECTNETOBJECT *const pdnObject, const PVOID pv, CConnection *const pConnection) { HRESULT hResultCode; CNameTableEntry *pPlayer; UNALIGNED DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID *pSend;
DPFX(DPFPREP, 4,"Parameters: pv [0x%p], pConnection [0x%p]",pv,pConnection);
DNASSERT(pdnObject != NULL); DNASSERT(pv != NULL); DNASSERT(pConnection != NULL);
pPlayer = NULL;
pSend = static_cast<DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID*>(pv); DNASSERT(pSend->dpnid != 0);
DPFX(DPFPREP, 5,"Player [0x%lx] has connected",pSend->dpnid);
if ((hResultCode = pdnObject->NameTable.FindEntry(pSend->dpnid,&pPlayer)) != DPN_OK) { DPFERR("Could not find connecting player!"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Increment players in session
//
pdnObject->ApplicationDesc.IncPlayerCount( FALSE );
// Associate DNID with player's connection
pConnection->Lock(); pConnection->SetDPNID(pSend->dpnid); pConnection->SetStatus( CONNECTED ); pConnection->Unlock();
// Populate connection
pdnObject->NameTable.PopulateConnection(pConnection);
//
// Now that this connection is part of a NameTableEntry, remove it from the indicated list
//
DNEnterCriticalSection(&pdnObject->csConnectionList); if (!pConnection->m_bilinkIndicated.IsEmpty()) { pConnection->Release(); } pConnection->m_bilinkIndicated.RemoveFromList(); DNLeaveCriticalSection(&pdnObject->csConnectionList);
pPlayer->Release(); pPlayer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pPlayer) { pPlayer->Release(); pPlayer = NULL; } goto Exit; }
// DNConnectToPeer1
//
// Accept the NameTable entry of the NewPlayer from the Host, and add it to the local
// NameTable. The Host will later provide an INSTRUCT_CONNECT message later.
#undef DPF_MODNAME
#define DPF_MODNAME "DNConnectToPeer1"
HRESULT DNConnectToPeer1(DIRECTNETOBJECT *const pdnObject, PVOID const pv) { HRESULT hResultCode; DN_NAMETABLE_ENTRY_INFO *pdnNTEInfo; CNameTableEntry *pNTEntry; // DWORD dwVersion;
DPFX(DPFPREP, 4,"Parameters: pv [0x%p]",pv);
DNASSERT(pdnObject != NULL); DNASSERT(pv != NULL);
pNTEntry = NULL;
//
// Create and unpack new entry
//
if ((hResultCode = NameTableEntryNew(pdnObject,&pNTEntry)) != DPN_OK) { DPFERR("Could not create new NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pdnNTEInfo = static_cast<DN_NAMETABLE_ENTRY_INFO*>(pv); DPFX(DPFPREP, 5,"New player DNID [0x%lx] - installing NameTable entry",pdnNTEInfo->dpnid); DPFX(DPFPREP, 5,"Connecting Player URL [%hs]",static_cast<char*>(pv) + pdnNTEInfo->dwURLOffset); if ((hResultCode = pNTEntry->UnpackEntryInfo(pdnNTEInfo,static_cast<BYTE*>(pv))) != DPN_OK) { DPFERR("Could not unpack NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pNTEntry->StartConnecting();
//
// Add entry to NameTable
//
if ((hResultCode = pdnObject->NameTable.InsertEntry(pNTEntry)) != DPN_OK) { DPFERR("Could not insert NameTableEntry into NameTable"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
//
// Update NameTableVersion
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pdnNTEInfo->dwVersion ); pdnObject->NameTable.Unlock();
pNTEntry->Release(); pNTEntry = NULL;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } goto Exit; }
// DNConnectToPeer2
//
// Perform a connection to the NewPlayer (as instructed by Host).
// Once this connection has completed (DNConnectToPeer2) send this player's DNID
#undef DPF_MODNAME
#define DPF_MODNAME "DNConnectToPeer2"
HRESULT DNConnectToPeer2(DIRECTNETOBJECT *const pdnObject, PVOID const pv) { HRESULT hResultCode; CNameTableEntry *pNTEntry; CNameTableEntry *pLocalPlayer; UNALIGNED DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT *pInfo; CServiceProvider *pSP;
DPFX(DPFPREP, 4,"Parameters: pv [0x%p]", pv);
DNASSERT(pdnObject != NULL); DNASSERT(pv != NULL);
pNTEntry = NULL; pLocalPlayer = NULL; pSP = NULL;
pInfo = static_cast<DN_INTERNAL_MESSAGE_INSTRUCT_CONNECT*>(pv);
//
// Update NameTable version
//
pdnObject->NameTable.WriteLock(); pdnObject->NameTable.SetVersion( pInfo->dwVersion ); pdnObject->NameTable.Unlock();
//
// Determine if this is an instruction to connect to ourselves.
// If it is, don't do anything other than update the NameTable version
//
DPFX(DPFPREP, 5,"Instructed to connect to [0x%lx]",pInfo->dpnid); if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; } if (pLocalPlayer->GetDPNID() == pInfo->dpnid) { DPFX(DPFPREP, 5,"Ignoring instruction to connect to self"); hResultCode = DPN_OK; goto Failure; }
if ((hResultCode = pdnObject->NameTable.FindEntry(pInfo->dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
//
// We will not connect to older players. They will connect to us.
//
if (pNTEntry->GetVersion() < pLocalPlayer->GetVersion()) { DPFX(DPFPREP, 5,"Ignoring instruction to connect to older player"); hResultCode = DPN_OK; goto Failure; } pLocalPlayer->Release(); pLocalPlayer = NULL;
//
// Get SP (cached on DirectNet object from original Connect() to host)
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pConnectSP != NULL) { pdnObject->pConnectSP->AddRef(); pSP = pdnObject->pConnectSP; } DNLeaveCriticalSection(&pdnObject->csDirectNetObject); if (pSP == NULL) { DPFERR("Could not find connect SP on DirectNet object"); hResultCode = DPNERR_GENERIC; goto Failure; }
#ifndef DPNBUILD_ONLYONESP
//
// Force the correct service provider into the address.
//
GUID guidSP; pSP->GetGUID(&guidSP); if ((hResultCode = IDirectPlay8Address_SetSP(pNTEntry->GetAddress(), &guidSP)) != DPN_OK) { DPFERR("Could not force correct service provider into player address"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } #endif // ! DPNBUILD_ONLYONESP
// Connect to new player
DPFX(DPFPREP, 5,"Performing Connect"); DNASSERT(pdnObject->pIDP8ADevice != NULL); hResultCode = DNPerformConnect( pdnObject, pNTEntry->GetDPNID(), pdnObject->pIDP8ADevice, pNTEntry->GetAddress(), pSP, ((pdnObject->ApplicationDesc.GetReservedDataSize() > 0) ? DN_CONNECTFLAGS_SESSIONDATA : 0), NULL);
if (hResultCode == DPNERR_PENDING) { hResultCode = DPN_OK; }
pSP->Release(); pSP = NULL;
pNTEntry->Release(); pNTEntry = NULL;
Exit: DNASSERT( pSP == NULL );
DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pSP) { pSP->Release(); pSP = NULL; } goto Exit; }
// DNConnectToPeer3
//
// Finish the connection process to the NewPlayer.
// Once the connection has completed send this player's DNID to NewPlayer and propegate
// ADD_PLAYER message
#undef DPF_MODNAME
#define DPF_MODNAME "DNConnectToPeer3"
HRESULT DNConnectToPeer3(DIRECTNETOBJECT *const pdnObject, const DPNID dpnid, CConnection *const pConnection) { HRESULT hResultCode; CNameTableEntry *pNTEntry; CNameTableEntry *pLocalPlayer; CRefCountBuffer *pRefCountBuffer; DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID *pSend;
DPFX(DPFPREP, 4,"Parameters: dpnid [0x%lx], pConnection [0x%p]",dpnid,pConnection);
DNASSERT(dpnid != NULL); DNASSERT(pConnection != NULL);
pLocalPlayer = NULL; pNTEntry = NULL; pRefCountBuffer = NULL;
//
// increment players in session
//
pdnObject->ApplicationDesc.IncPlayerCount( FALSE );
// Associate DNID with player's end point handle
pConnection->Lock(); pConnection->SetDPNID(dpnid); pConnection->SetStatus( CONNECTED ); pConnection->Unlock();
//
// Get New Players's entry
//
if ((hResultCode = pdnObject->NameTable.FindEntry(dpnid,&pNTEntry)) != DPN_OK) { DPFERR("Could not find new player"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Get Local player's entry
//
if ((hResultCode = pdnObject->NameTable.GetLocalPlayerRef( &pLocalPlayer )) != DPN_OK) { DPFERR("Could not get local player reference"); DisplayDNError(0,hResultCode); goto Failure; }
// Setup buffer to pass local player's DNID
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID), MemoryBlockAlloc, MemoryBlockFree, &pRefCountBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not allocate buffer to send connecting player DPNID"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pSend = reinterpret_cast<DN_INTERNAL_MESSAGE_SEND_PLAYER_DPNID*>(pRefCountBuffer->GetBufferAddress()); pSend->dpnid = pLocalPlayer->GetDPNID();
pLocalPlayer->Release(); pLocalPlayer = NULL;
// Send player's DNID to new player
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_SEND_PLAYER_DNID, dpnid, pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL); if (hResultCode != DPNERR_PENDING) { DPFERR("Could not send connecting player DPNID"); DisplayDNError(0,hResultCode); DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
DNASSERT(FALSE); goto Failure; }
// Update NameTableEntry with Connection
pdnObject->NameTable.PopulateConnection(pConnection); pRefCountBuffer->Release(); pRefCountBuffer = NULL;
pNTEntry->Release(); pNTEntry = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pNTEntry) { pNTEntry->Release(); pNTEntry = NULL; } if (pLocalPlayer) { pLocalPlayer->Release(); pLocalPlayer = NULL; } if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
// DNConnectToPeerFailed
//
// An existing player could not connect to a NewPlayer.
// Send a message to the Host player that this connect attempt failed
#undef DPF_MODNAME
#define DPF_MODNAME "DNConnectToPeerFailed"
HRESULT DNConnectToPeerFailed(DIRECTNETOBJECT *const pdnObject, const DPNID dpnid) { HRESULT hResultCode; CNameTableEntry *pHost; CConnection *pConnection; CRefCountBuffer *pRCBuffer; DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED *pMsg;
DPFX(DPFPREP, 4,"Parameters: dpnid [0x%lx]",dpnid);
DNASSERT(pdnObject != NULL); DNASSERT(dpnid != 0);
pHost = NULL; pConnection = NULL; pRCBuffer = NULL;
if ((hResultCode = pdnObject->NameTable.GetHostPlayerRef( &pHost )) != DPN_OK) { DPFERR("Could not get Host player reference"); DisplayDNError(0,hResultCode); goto Failure; } if ((hResultCode = pHost->GetConnectionRef( &pConnection )) != DPN_OK) { DPFERR("Could not get Host Connection reference"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Create message
//
hResultCode = RefCountBufferNew(pdnObject, sizeof(DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED), MemoryBlockAlloc, MemoryBlockFree, &pRCBuffer); if (hResultCode != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); goto Failure; } pMsg = reinterpret_cast<DN_INTERNAL_MESSAGE_INSTRUCTED_CONNECT_FAILED*>(pRCBuffer->GetBufferAddress()); pMsg->dpnid = dpnid;
//
// Send message
//
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_INSTRUCTED_CONNECT_FAILED, pHost->GetDPNID(), pRCBuffer->BufferDescAddress(), 1, pRCBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL); if (hResultCode != DPNERR_PENDING) { DPFERR("Could not send CONNECT_FAILED message - maybe OUR connection is down !"); DisplayDNError(0,hResultCode); DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
goto Failure; }
//
// Clean up
//
pHost->Release(); pHost = NULL; pConnection->Release(); pConnection = NULL; pRCBuffer->Release(); pRCBuffer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 4,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pHost) { pHost->Release(); pHost = NULL; } if (pConnection) { pConnection->Release(); pConnection = NULL; } if (pRCBuffer) { pRCBuffer->Release(); pRCBuffer = NULL; } goto Exit; }
// DNSendConnectInfo
//
// Send connection info to a new player.
// This is the Host Applcation Description and the NameTable
// This uses an enumeration buffer.
// The format of the buffer is:
// <DN_INTERNAL_MESSAGE_CONNECT_INFO>
// <DN_APPLICATION_DESC>
// <DN_NAMETABLE_INFO>
// <DN_NAMETABLE_ENTRY_INFO>
// <DN_NAMETABLE_ENTRY_INFO>
// :
// <strings and data blocks>
//
// DNID dnId DNID of new player
#undef DPF_MODNAME
#define DPF_MODNAME "DNSendConnectInfo"
HRESULT DNSendConnectInfo(DIRECTNETOBJECT *const pdnObject, CNameTableEntry *const pNTEntry, CConnection *const pConnection, void *const pvReplyBuffer, const DWORD dwReplyBufferSize) { HRESULT hResultCode; CPackedBuffer packedBuffer; CRefCountBuffer *pRefCountBuffer; DN_INTERNAL_MESSAGE_CONNECT_INFO *pMsg;
DPFX(DPFPREP, 6,"Parameters: pNTEntry [0x%p], pConnection [0x%p], pvReplyBuffer [0x%p], dwReplyBufferSize [%ld]", pNTEntry,pConnection,pvReplyBuffer,dwReplyBufferSize);
DNASSERT(pdnObject != NULL); DNASSERT(pNTEntry != NULL);
pRefCountBuffer = NULL;
//
// Determine size of message
//
packedBuffer.Initialize(NULL,0); packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CONNECT_INFO)); packedBuffer.AddToBack(NULL,dwReplyBufferSize); pdnObject->ApplicationDesc.PackInfo(&packedBuffer, DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|DN_APPDESCINFO_FLAG_RESERVEDDATA| DN_APPDESCINFO_FLAG_APPRESERVEDDATA); pdnObject->NameTable.PackNameTable(pNTEntry,&packedBuffer);
//
// Create buffer
//
if ((hResultCode = RefCountBufferNew(pdnObject,packedBuffer.GetSizeRequired(),MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not allocate RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } packedBuffer.Initialize(pRefCountBuffer->GetBufferAddress(),pRefCountBuffer->GetBufferSize());
//
// Fill in buffer
//
pMsg = static_cast<DN_INTERNAL_MESSAGE_CONNECT_INFO*>(packedBuffer.GetHeadAddress()); if ((hResultCode = packedBuffer.AddToFront(NULL,sizeof(DN_INTERNAL_MESSAGE_CONNECT_INFO))) != DPN_OK) { DPFERR("Could not add CONNECT_INFO struct to packed buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((pvReplyBuffer) && (dwReplyBufferSize != 0)) { if ((hResultCode = packedBuffer.AddToBack(pvReplyBuffer,dwReplyBufferSize)) != DPN_OK) { DPFERR("Could not add reply buffer to packed buffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pMsg->dwReplyOffset = packedBuffer.GetTailOffset(); pMsg->dwReplySize = dwReplyBufferSize; } else { pMsg->dwReplyOffset = 0; pMsg->dwReplySize = 0; }
hResultCode = pdnObject->ApplicationDesc.PackInfo(&packedBuffer, DN_APPDESCINFO_FLAG_SESSIONNAME|DN_APPDESCINFO_FLAG_PASSWORD|DN_APPDESCINFO_FLAG_RESERVEDDATA| DN_APPDESCINFO_FLAG_APPRESERVEDDATA); if (hResultCode != DPN_OK) { DPFERR("Could not pack ApplicationDesc"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } if ((hResultCode = pdnObject->NameTable.PackNameTable(pNTEntry,&packedBuffer)) != DPN_OK) { DPFERR("Could not pack NameTable"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; }
// Send the name table to target
hResultCode = DNSendMessage(pdnObject, pConnection, DN_MSG_INTERNAL_SEND_CONNECT_INFO, pNTEntry->GetDPNID(), pRefCountBuffer->BufferDescAddress(), 1, pRefCountBuffer, 0, DN_SENDFLAGS_RELIABLE, NULL, NULL); if (hResultCode != DPNERR_PENDING) { DPFERR("Could not send connect info to joining player"); DisplayDNError(0,hResultCode); DNASSERT(hResultCode != DPN_OK); // it was sent guaranteed, it should not return immediately
// DNASSERT(FALSE);
goto Failure; }
pRefCountBuffer->Release(); pRefCountBuffer = NULL;
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } goto Exit; }
// DNReceiveConnectInfo
//
// Receive connect info from the host/server player.
// This is the Application Description and the NameTable
// The name table is in an enum buffer, with relative pointer references which will have
// to be turned into absolutes. This process requires two passes of the buffer.
// The first pass will extract PLAYERS, and the second pass will extract groups.
//
// PVOID pvNTBuffer Pointer to name table enum buffer
// DWORD dwNumEntries Number of entries in the name table
#undef DPF_MODNAME
#define DPF_MODNAME "DNReceiveConnectInfo"
HRESULT DNReceiveConnectInfo(DIRECTNETOBJECT *const pdnObject, void *const pvBuffer, CConnection *const pHostConnection, DPNID *const pdpnid) { HRESULT hResultCode; void *pvReplyBuffer; DWORD dwReplyBufferSize; UNALIGNED DPN_APPLICATION_DESC_INFO *pdnAppDescInfo; UNALIGNED DN_NAMETABLE_INFO *pdnNTInfo; CRefCountBuffer *pRefCountBuffer; CAsyncOp *pConnect; UNALIGNED DN_INTERNAL_MESSAGE_CONNECT_INFO *pMsg;
DPFX(DPFPREP, 6,"Parameters: pvBuffer [0x%p], pHostConnection [0x%p], pdpnid [0x%p]", pvBuffer,pHostConnection,pdpnid);
DNASSERT(pdnObject != NULL); DNASSERT(pdpnid != NULL); DNASSERT(pvBuffer != NULL); DNASSERT(pHostConnection != NULL);
pRefCountBuffer = NULL; pConnect = NULL;
//
// Pull fixed structures from front of buffer
//
pMsg = static_cast<DN_INTERNAL_MESSAGE_CONNECT_INFO*>(pvBuffer); pdnAppDescInfo = reinterpret_cast<DPN_APPLICATION_DESC_INFO*>(pMsg + 1); pdnNTInfo = reinterpret_cast<DN_NAMETABLE_INFO*>(pdnAppDescInfo + 1);
//
// Extract reply buffer
//
dwReplyBufferSize = pMsg->dwReplySize; if (dwReplyBufferSize > 0) { pvReplyBuffer = static_cast<void*>(static_cast<BYTE*>(pvBuffer) + pMsg->dwReplyOffset); DPFX(DPFPREP, 7,"Reply Buffer [0x%p] [%ld]",pvReplyBuffer,dwReplyBufferSize); if ((hResultCode = RefCountBufferNew(pdnObject,dwReplyBufferSize,MemoryBlockAlloc,MemoryBlockFree,&pRefCountBuffer)) != DPN_OK) { DPFERR("Could not create RefCountBuffer"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } memcpy(pRefCountBuffer->GetBufferAddress(),pvReplyBuffer,dwReplyBufferSize); DNEnterCriticalSection(&pdnObject->csDirectNetObject); if (pdnObject->pConnectParent) { pdnObject->pConnectParent->AddRef(); pConnect = pdnObject->pConnectParent; pConnect->SetRefCountBuffer( pRefCountBuffer ); } DNLeaveCriticalSection(&pdnObject->csDirectNetObject); pRefCountBuffer->Release(); pRefCountBuffer = NULL; }
//
// Extract Application Description
//
DPFX(DPFPREP, 7,"Extracting Application Description"); hResultCode = pdnObject->ApplicationDesc.UnpackInfo(pdnAppDescInfo,pvBuffer,DN_APPDESCINFO_FLAG_SESSIONNAME | DN_APPDESCINFO_FLAG_PASSWORD | DN_APPDESCINFO_FLAG_RESERVEDDATA | DN_APPDESCINFO_FLAG_APPRESERVEDDATA); if (hResultCode != DPN_OK) { DPFERR("Could not unpack ApplicationDesc"); DisplayDNError(0,hResultCode); goto Failure; }
//
// Set player count (Host and LocalPlayer)
//
#pragma BUGBUG( minara,"What should happen here ?" )
// dnAppDesc.dwCurrentPlayers = 2;
//
// Extract NameTable
//
DPFX(DPFPREP, 7,"Extracting NameTable"); DPFX(DPFPREP, 7,"Set DPNID mask to [0x%lx]",pdnObject->ApplicationDesc.GetDPNIDMask()); pdnObject->NameTable.SetDPNIDMask( pdnObject->ApplicationDesc.GetDPNIDMask() ); if ((hResultCode = pdnObject->NameTable.UnpackNameTableInfo(pdnNTInfo,static_cast<BYTE*>(pvBuffer),pdpnid)) != DPN_OK) { DPFERR("Could not unpack NameTable"); DisplayDNError(0,hResultCode); goto Failure; }
if (pdnObject->dwFlags & DN_OBJECT_FLAG_PEER) { //
// Create ALL_PLAYERS group
//
CNameTableEntry *pAllPlayersGroup;
pAllPlayersGroup = NULL;
if ((hResultCode = NameTableEntryNew(pdnObject,&pAllPlayersGroup)) != DPN_OK) { DPFERR("Could not create NameTableEntry"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Failure; } pAllPlayersGroup->MakeGroup();
// This function takes the lock internally
pdnObject->NameTable.MakeAllPlayersGroup(pAllPlayersGroup); pAllPlayersGroup->Release(); pAllPlayersGroup = NULL;
DNASSERT(pAllPlayersGroup == NULL); }
if (pConnect) { pConnect->Release(); pConnect = NULL; }
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode);
Failure: if (pRefCountBuffer) { pRefCountBuffer->Release(); pRefCountBuffer = NULL; } if (pConnect) { pConnect->SetResult( hResultCode ); // Try and salvage something !
pConnect->Release(); pConnect = NULL; } goto Exit; }
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetClearAddress"
HRESULT DNGetClearAddress(DIRECTNETOBJECT *const pdnObject, const HANDLE hEndPt, IDirectPlay8Address **const ppAddress, const BOOL fPartner) { SPGETADDRESSINFODATA spInfoData; HRESULT hResultCode; #ifdef DBG
TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG
DPFX(DPFPREP, 6,"Parameters: hEndPt [0x%p], ppAddress [0x%p], fPartner [%ld]",hEndPt,ppAddress,fPartner);
DNASSERT(pdnObject != NULL); DNASSERT(hEndPt != NULL); DNASSERT(ppAddress != NULL);
if (fPartner) { spInfoData.Flags = SP_GET_ADDRESS_INFO_REMOTE_HOST; } else { spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_HOST_PUBLIC_ADDRESS; }
hResultCode = DNPCrackEndPointDescriptor(pdnObject->pdnProtocolData,hEndPt,&spInfoData); if (hResultCode != DPN_OK) { DPFERR("Unknown error from DNPCrackEndPointDescriptor"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Exit; } *ppAddress = spInfoData.pAddress; spInfoData.pAddress = NULL;
#ifdef DBG
if (*ppAddress) { DP8ASize = 512; IDirectPlay8Address_GetURL(*ppAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 5,"Remote Address [%s]",DP8ABuffer); } #endif // DBG
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
#undef DPF_MODNAME
#define DPF_MODNAME "DNGetLocalDeviceAddress"
HRESULT DNGetLocalDeviceAddress(DIRECTNETOBJECT *const pdnObject, const HANDLE hEndPt, IDirectPlay8Address **const ppAddress) { SPGETADDRESSINFODATA spInfoData; HRESULT hResultCode; #ifdef DBG
TCHAR DP8ABuffer[512] = {0}; DWORD DP8ASize; #endif // DBG
DPFX(DPFPREP, 6,"Parameters: hEndPt [0x%p], ppAddress [0x%p]",hEndPt,ppAddress);
DNASSERT(pdnObject != NULL); DNASSERT(hEndPt != NULL); DNASSERT(ppAddress != NULL);
spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
hResultCode = DNPCrackEndPointDescriptor(pdnObject->pdnProtocolData,hEndPt,&spInfoData); if (hResultCode != DPN_OK) { DPFERR("Unknown error from DNPCrackEndPointDescriptor"); DisplayDNError(0,hResultCode); DNASSERT(FALSE); goto Exit; } *ppAddress = spInfoData.pAddress; spInfoData.pAddress = NULL;
#ifdef DBG
if (*ppAddress) { DP8ASize = 512; IDirectPlay8Address_GetURL(*ppAddress,DP8ABuffer,&DP8ASize); DPFX(DPFPREP, 7,"Remote Address [%s]",DP8ABuffer); } #endif // DBG
hResultCode = DPN_OK;
Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); }
|