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

1552 lines
45 KiB

/*==========================================================================
*
* Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
*
* File: mcast.cpp
* Content: DirectPlay8 Mcast interface routines
*@@BEGIN_MSINTERNAL
* History:
* Date By Reason
* ==== == ======
* 10/08/01 vanceo Created
*@@END_MSINTERNAL
*
***************************************************************************/
#include "dncorei.h"
#ifndef DPNBUILD_NOMULTICAST
//**********************************************************************
// Constant definitions
//**********************************************************************
//**********************************************************************
// Macro definitions
//**********************************************************************
//**********************************************************************
// Structure definitions
//**********************************************************************
//**********************************************************************
// Variable definitions
//**********************************************************************
typedef STDMETHODIMP McastQueryInterface(IDirectPlay8Multicast *pInterface, DP8REFIID riid, LPVOID *ppvObj);
typedef STDMETHODIMP_(ULONG) McastAddRef(IDirectPlay8Multicast *pInterface);
typedef STDMETHODIMP_(ULONG) McastRelease(IDirectPlay8Multicast *pInterface);
typedef STDMETHODIMP McastInitialize(IDirectPlay8Multicast *pInterface, PVOID const pvUserContext, const PFNDPNMESSAGEHANDLER pfn, const DWORD dwFlags);
typedef STDMETHODIMP McastJoin(IDirectPlay8Multicast *pInterface, IDirectPlay8Address *const pGroupAddr, IUnknown *const pDeviceInfo, const DPN_SECURITY_DESC *const pdnSecurity, const DPN_SECURITY_CREDENTIALS *const pdnCredentials, void *const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags);
typedef STDMETHODIMP McastClose(IDirectPlay8Multicast *pInterface, const DWORD dwFlags);
typedef STDMETHODIMP McastCreateSenderContext(IDirectPlay8Multicast *pInterface, IDirectPlay8Address *const pSenderAddress, void *const pvSenderContext, const DWORD dwFlags);
typedef STDMETHODIMP McastDestroySenderContext(IDirectPlay8Multicast *pInterface, IDirectPlay8Address *const pSenderAddress, const DWORD dwFlags);
typedef STDMETHODIMP McastSend(IDirectPlay8Multicast *pInterface, const DPN_BUFFER_DESC *const prgBufferDesc,const DWORD cBufferDesc,const DWORD dwTimeOut, void *const pvAsyncContext, DPNHANDLE *const phAsyncHandle, const DWORD dwFlags);
typedef STDMETHODIMP McastGetGroupAddress(IDirectPlay8Multicast *pInterface, IDirectPlay8Address **const ppAddress, const DWORD dwFlags);
typedef STDMETHODIMP McastGetSendQueueInfo( IDirectPlay8Multicast *pInterface, DWORD *const lpdwNumMsgs, DWORD *const lpdwNumBytes, const DWORD dwFlags);
typedef STDMETHODIMP McastCancelAsyncOperation( IDirectPlay8Multicast *pInterface, const DPNHANDLE hAsyncHandle, const DWORD dwFlags);
typedef STDMETHODIMP McastReturnBuffer( IDirectPlay8Multicast *pInterface, const DPNHANDLE hBufferHandle,const DWORD dwFlags);
typedef STDMETHODIMP McastEnumServiceProviders( IDirectPlay8Multicast *pInterface, const GUID *const pguidServiceProvider, const GUID *const pguidApplication, DPN_SERVICE_PROVIDER_INFO *const pSPInfoBuffer, DWORD *const pcbEnumData, DWORD *const pcReturned, const DWORD dwFlags);
typedef STDMETHODIMP McastEnumMulticastScopes( IDirectPlay8Multicast *pInterface, const GUID *const pguidServiceProvider, const GUID *const pguidDevice, const GUID *const pguidApplication, DPN_MULTICAST_SCOPE_INFO *const pScopeInfoBuffer, PDWORD const pcbEnumData, PDWORD const pcReturned, const DWORD dwFlags);
typedef STDMETHODIMP McastGetSPCaps(IDirectPlay8Multicast *pInterface, const GUID * const pguidSP, DPN_SP_CAPS *const pdpspCaps,const DWORD dwFlags);
typedef STDMETHODIMP McastSetSPCaps(IDirectPlay8Multicast *pInterface, const GUID * const pguidSP, const DPN_SP_CAPS *const pdpspCaps, const DWORD dwFlags);
IDirectPlay8MulticastVtbl DNMcast_Vtbl =
{
(McastQueryInterface*) DN_QueryInterface,
(McastAddRef*) DN_AddRef,
(McastRelease*) DN_Release,
(McastInitialize*) DN_Initialize,
(McastJoin*) DN_Join,
(McastClose*) DN_Close,
(McastCreateSenderContext*) DN_CreateSenderContext,
(McastDestroySenderContext*) DN_DestroySenderContext,
(McastSend*) DN_Send,
(McastGetGroupAddress*) DN_GetGroupAddress,
(McastGetSendQueueInfo*) DN_GetHostSendQueueInfo,
(McastCancelAsyncOperation*) DN_CancelAsyncOperation,
(McastReturnBuffer*) DN_ReturnBuffer,
(McastEnumServiceProviders*) DN_EnumServiceProviders,
(McastEnumMulticastScopes*) DN_EnumMulticastScopes,
(McastGetSPCaps*) DN_GetSPCaps,
(McastSetSPCaps*) DN_SetSPCaps
};
//**********************************************************************
// Function prototypes
//**********************************************************************
//**********************************************************************
// Function definitions
//**********************************************************************
//
// Completion for join connect parent
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteJoinOperation"
void DNCompleteJoinOperation(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
CServiceProvider *pSP;
IDirectPlay8Address *pIDevice;
pSP = NULL;
pIDevice = NULL;
//
// Save the result code on the parent (if it exists - it will be the CONNECT handle)
//
if (pAsyncOp->GetParent())
{
pAsyncOp->GetParent()->Lock();
pAsyncOp->GetParent()->SetResult( pAsyncOp->GetResult() );
pAsyncOp->GetParent()->Unlock();
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pAsyncOp->GetParent()->GetHandle(), NULL )))
{
// Release the HandleTable reference
pAsyncOp->GetParent()->Release();
}
}
//
// Clear CONNECTING flag, and DISCONNECTING flag in case this was aborted.
// If the connect succeeded, set the CONNECTED flag.
//
DPFX(DPFPREP, 8,"Clearing CONNECTING and DISCONNECTING flags");
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= (~DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_DISCONNECTING);
if (pAsyncOp->GetResult() == DPN_OK)
{
pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTED;
}
else
{
//
// Clean up DirectNet object
//
pSP = pdnObject->pConnectSP;
pdnObject->pConnectSP = NULL;
pIDevice = pdnObject->pIDP8ADevice;
pdnObject->pIDP8ADevice = NULL;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pSP)
{
pSP->Release();
pSP = NULL;
}
if (pIDevice)
{
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
}
DNASSERT( pSP == NULL );
DNASSERT( pIDevice == NULL );
}
//
// Completion for join handle parent
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteUserJoin"
void DNCompleteUserJoin(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
DNUserJoinComplete( pdnObject,
pAsyncOp->GetHandle(),
pAsyncOp->GetContext(),
pAsyncOp->GetResult());
}
#undef DPF_MODNAME
#define DPF_MODNAME "DN_Join"
STDMETHODIMP DN_Join( IDirectPlay8Multicast *pInterface,
IDirectPlay8Address *const pGroupAddr,
IUnknown *const pDeviceInfo,
const DPN_SECURITY_DESC *const pdnSecurity,
const DPN_SECURITY_CREDENTIALS *const pdnCredentials,
void *const pvAsyncContext,
DPNHANDLE *const phAsyncHandle,
const DWORD dwFlags)
{
HRESULT hResultCode;
HRESULT volatile hrOperation;
DIRECTNETOBJECT *pdnObject;
IDirectPlay8Address *pIGroup;
IDirectPlay8Address *pIDevice;
#ifndef DPNBUILD_ONLYONESP
GUID guidSP;
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
GUID guidAdapter;
#endif // ! DPNBUILD_ONLYONEADAPTER
PVOID pvNewInterface;
DWORD dwListenFlags;
CAsyncOp *pListenParent;
CAsyncOp *pParent;
CAsyncOp *pAsyncOp;
CAsyncOp *pConnectParent;
CAsyncOp *pHandleParent;
CServiceProvider *pSP;
CSyncEvent *pSyncEvent;
HANDLE hEndpoint;
SPGETADDRESSINFODATA spInfoData;
// Variables used when device interface is a DIRECTNETOBJECT
DIRECTNETOBJECT *pdnDeviceObject;
CConnection *pExistingConnection;
CNameTableEntry *pNTEntry;
CServiceProvider *pShareSP;
IDP8ServiceProvider *pShareDP8ServiceProvider;
HANDLE hEndPt;
CCallbackThread CallbackThread;
CAsyncOp *pShareListenParent;
CBilink *pBilink;
CAsyncOp *pShareParent;
IDP8ServiceProvider *pLocalDP8ServiceProvider;
SPSHAREENDPOINTINFODATA spShareData;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pGroupAddr [0x%p], pDeviceInfo [0x%p], pdnSecurity [0x%p], pdnCredentials [0x%p], pvAsyncContext [0x%p], phAsyncHandle [0x%p], dwFlags [0x%lx]",
pInterface,pGroupAddr,pDeviceInfo,pdnSecurity,pdnCredentials,pvAsyncContext,phAsyncHandle,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateJoin( pInterface, pGroupAddr, pDeviceInfo,
pdnSecurity, pdnCredentials,
pvAsyncContext,phAsyncHandle,dwFlags ) ) )
{
DPFERR( "Error validating join params" );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
// Check to ensure not already connected/connecting
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING)
{
DPFERR( "Object is already connecting" );
DPF_RETURN(DPNERR_CONNECTING);
}
if (pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTED)
{
DPFERR( "Object is already connected" );
DPF_RETURN(DPNERR_ALREADYCONNECTED);
}
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING))
{
DPFERR( "Object is closing or disconnecting" );
DPF_RETURN(DPNERR_ALREADYCLOSING);
}
pIGroup = NULL;
pIDevice = NULL;
pvNewInterface = NULL;
pListenParent = NULL;
pParent = NULL;
pConnectParent = NULL;
pHandleParent = NULL;
pSP = NULL;
pSyncEvent = NULL;
pdnDeviceObject = NULL;
pExistingConnection = NULL;
pNTEntry = NULL;
pShareSP = NULL;
pShareDP8ServiceProvider = NULL;
CallbackThread.Deinitialize();
pShareListenParent = NULL;
pShareParent = NULL;
pLocalDP8ServiceProvider = NULL;
//
// Flag as CONNECTING to prevent other operations here
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTING | DN_OBJECT_FLAG_CONNECTED))
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
hResultCode = DPNERR_ALREADYCONNECTED;
goto Failure;
}
pdnObject->dwFlags |= DN_OBJECT_FLAG_CONNECTING;
// Adding local host flag
//pdnObject->dwFlags |= DN_OBJECT_FLAG_LOCALHOST;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Duplicate specified Group Address, or create a blank one if NULL
//
if (pGroupAddr != NULL)
{
if ((hResultCode = IDirectPlay8Address_Duplicate(pGroupAddr,&pIGroup)) != DPN_OK)
{
DPFERR("Could not duplicate group address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
}
else
{
#ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIGroup));
#else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIGroup),
FALSE);
#endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK)
{
DPFERR("Could not create Group Address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
}
//
// Generate a Device Address from the DPlay interface, or duplicate
// the user's. Start by finding out which type of interface it is.
//
if (((IDirectPlay8Peer_QueryInterface((IDirectPlay8Peer*) pDeviceInfo, IID_IDirectPlay8Peer, &pvNewInterface)) == S_OK) ||
#ifndef DPNBUILD_NOSERVER
((IDirectPlay8Server_QueryInterface((IDirectPlay8Server*) pDeviceInfo, IID_IDirectPlay8Server, &pvNewInterface)) == S_OK) ||
#endif // ! DPNBUILD_NOSERVER
((IDirectPlay8Client_QueryInterface((IDirectPlay8Client*) pDeviceInfo, IID_IDirectPlay8Client, &pvNewInterface)) == S_OK) ||
((IDirectPlay8Multicast_QueryInterface((IDirectPlay8Multicast*) pDeviceInfo, IID_IDirectPlay8Multicast, &pvNewInterface)) == S_OK))
{
//
// It's a DIRECTNETOBJECT.
//
pdnDeviceObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pvNewInterface);
DNEnterCriticalSection(&pdnDeviceObject->csDirectNetObject);
if (! (pdnDeviceObject->dwFlags & DN_OBJECT_FLAG_CONNECTED))
{
DPFERR("DirectPlay device object is not connected or hosting" );
DNLeaveCriticalSection(&pdnDeviceObject->csDirectNetObject);
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
DNLeaveCriticalSection(&pdnDeviceObject->csDirectNetObject);
//
// Get the host player's connection (if not a multicast object).
//
if (! (pdnDeviceObject->dwFlags & DN_OBJECT_FLAG_MULTICAST))
{
if ((hResultCode = pdnDeviceObject->NameTable.GetHostPlayerRef(&pNTEntry)) != DPN_OK)
{
DPFERR("Could not find device object's Host player");
DisplayDNError(0,hResultCode);
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
//
// If we're the host, then the name table entry won't have a valid
// connection object.
//
if (! pNTEntry->IsLocal())
{
hResultCode = pNTEntry->GetConnectionRef(&pExistingConnection);
if (hResultCode != DPN_OK)
{
DPFX(DPFPREP, 0, "Could not find device object's Host player (err = 0x%lx)! Ignoring.",
pdnDeviceObject, pExistingConnection);
DNASSERT(pExistingConnection == NULL);
}
}
pNTEntry->Release();
pNTEntry = NULL;
}
//
// If we got a connection, simply extract its device address.
// If we couldn't get the non-local host player's connection, we
// have to select the device a different way.
//
if (pExistingConnection != NULL)
{
if ((hResultCode = pExistingConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
{
DPFERR( "Couldn't retrieve host player's endpoint" );
DisplayDNError(0, hResultCode);
goto Failure;
}
spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
//
// Note that we are calling our Protocol object with the other
// interface's endpoint.
//
hResultCode = DNPCrackEndPointDescriptor(pdnObject->pdnProtocolData, hEndPt,&spInfoData);
if (hResultCode != DPN_OK)
{
DPFERR("Unknown error from DNPCrackEndPointDescriptor");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
pExistingConnection->ReleaseEndPt(&CallbackThread);
goto Failure;
}
pIDevice = spInfoData.pAddress;
spInfoData.pAddress = NULL;
pExistingConnection->ReleaseEndPt(&CallbackThread);
pShareSP = pExistingConnection->GetSP();
if (pShareSP == NULL)
{
DPFERR("Could not get host player connection's SP!");
DNASSERT(FALSE);
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pExistingConnection->Release();
pExistingConnection = NULL;
}
else
{
//
// Get the listen operation.
//
DNEnterCriticalSection(&pdnDeviceObject->csDirectNetObject);
if (pdnDeviceObject->pListenParent == NULL)
{
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
DPFERR("Could not find device object's listen parent operation!");
DNASSERT(FALSE);
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pdnDeviceObject->pListenParent->AddRef();
pShareListenParent = pdnDeviceObject->pListenParent;
DNLeaveCriticalSection(&pdnDeviceObject->csDirectNetObject);
//
// Get the first SP listen.
//
pShareListenParent->Lock();
pBilink = pShareListenParent->m_bilinkParent.GetNext();
if (pBilink == &pShareListenParent->m_bilinkParent)
{
DPFERR("Could not find device object's first listen operation!");
DNASSERT(FALSE);
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pShareParent = CONTAINING_OBJECT(pBilink,CAsyncOp,m_bilinkChildren);
pShareSP = pShareParent->GetSP();
if (pShareSP == NULL)
{
DPFERR("Could not get first listen operation's SP!");
DNASSERT(FALSE);
hResultCode = DPNERR_INVALIDDEVICEADDRESS;
goto Failure;
}
pShareSP->AddRef();
pShareListenParent->Unlock();
pShareListenParent->Release();
pShareListenParent = NULL;
#ifndef DPNBUILD_ONLYONESP
//
// Get the share SP's GUID.
//
pShareSP->GetGUID(&guidSP);
#endif // ! DPNBUILD_ONLYONESP
//
// Build a device address object.
//
#ifdef DPNBUILD_LIBINTERFACE
hResultCode = DP8ACF_CreateInstance(IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIDevice));
#else // ! DPNBUILD_LIBINTERFACE
hResultCode = COM_CoCreateInstance(CLSID_DirectPlay8Address,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address,
reinterpret_cast<void**>(&pIDevice),
FALSE);
#endif // ! DPNBUILD_LIBINTERFACE
if (hResultCode != S_OK)
{
DPFERR("Could not create Device Address");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
#ifndef DPNBUILD_ONLYONESP
if ((hResultCode = IDirectPlay8Address_SetSP(pIDevice,&guidSP)) != DPN_OK)
{
DPFERR("Could not set SP on Device Address");
DisplayDNError(0,hResultCode);
goto Failure;
}
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
//
// For multicast objects we can reuse the same device GUID, too,
// since we know there will be only one.
//
if (pdnDeviceObject->dwFlags & DN_OBJECT_FLAG_MULTICAST)
{
pShareParent->Lock();
DNASSERT(! pShareParent->IsCancelled());
DNASSERT(! pShareParent->m_bilinkParent.IsEmpty());
pAsyncOp = CONTAINING_OBJECT(pParent->m_bilinkParent.GetNext(),CAsyncOp,m_bilinkChildren);
pAsyncOp->Lock();
DNASSERT((! pAsyncOp->IsCancelled()) && (! pAsyncOp->IsComplete()));
DNASSERT(pAsyncOp->m_bilinkChildren.GetNext() == &pShareParent->m_bilinkParent);
hEndpoint = pAsyncOp->GetProtocolHandle();
pAsyncOp->Unlock();
pShareParent->Unlock();
spInfoData.hEndpoint = hEndpoint;
spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
//
// Note that we are calling our Protocol object with the other
// interface's endpoint.
//
if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData, spInfoData.hEndpoint,&spInfoData)) != DPN_OK)
{
DPFERR("Could not get LISTEN device address!");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
//
// Retrieve the device GUID from the listen address.
//
if ((hResultCode = IDirectPlay8Address_GetDevice(spInfoData.pAddress, &guidAdapter)) != DPN_OK)
{
DPFERR("Could not get adapter GUID!");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
IDirectPlay8Address_Release(spInfoData.pAddress);
spInfoData.pAddress = NULL;
goto Failure;
}
IDirectPlay8Address_Release(spInfoData.pAddress);
spInfoData.pAddress = NULL;
//
// Store the device GUID on our device address.
//
if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice, &guidAdapter)) != DPN_OK)
{
DPFERR("Could not set adapter GUID!");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
}
#endif // ! DPNBUILD_ONLYONEADAPTER
}
//
// Get the share SP's COM interface.
//
if ((hResultCode = pShareSP->GetInterfaceRef(&pShareDP8ServiceProvider)) != DPN_OK)
{
DPFERR("Could not get shared SP interface");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pShareSP->Release();
pShareSP = NULL;
//
// Load our own local instance of that SP.
//
hResultCode = DN_SPEnsureLoaded(pdnObject,
#ifndef DPNBUILD_ONLYONESP
&guidSP,
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_LIBINTERFACE
NULL,
#endif // ! DPNBUILD_LIBINTERFACE
&pSP);
if (hResultCode != DPN_OK)
{
DPFERR("Could not find or load SP");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Get the local SP's COM interface.
//
if ((hResultCode = pSP->GetInterfaceRef(&pLocalDP8ServiceProvider)) != DPN_OK)
{
DPFERR("Could not get local SP interface");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Tell our SP interface to get its endpoint information from the
// other interface's SP.
//
spShareData.pDP8ServiceProvider = pShareDP8ServiceProvider;
spShareData.dwFlags = 0;
hResultCode = IDP8ServiceProvider_ShareEndpointInfo(pLocalDP8ServiceProvider,
&spShareData);
if (hResultCode != DPN_OK)
{
DPFERR("Could not have SPs share endpoint info");
DisplayDNError(0,hResultCode);
goto Failure;
}
IDP8ServiceProvider_Release(pLocalDP8ServiceProvider);
pLocalDP8ServiceProvider = NULL;
IDP8ServiceProvider_Release(pShareDP8ServiceProvider);
pShareDP8ServiceProvider = NULL;
//
// Release the ref we held on the device object.
//
IDirectPlay8Peer_Release((IDirectPlay8Peer*) pvNewInterface); // all core objects have Release in same location in Vtbl
pvNewInterface = NULL;
}
else if ((IDirectPlay8Address_QueryInterface((IDirectPlay8Address*) pDeviceInfo, IID_IDirectPlay8Address, &pvNewInterface)) == S_OK)
{
//
// It's an address.
//
IDirectPlay8Address_Release((IDirectPlay8Address*) pvNewInterface);
pvNewInterface = NULL;
if ((hResultCode = IDirectPlay8Address_Duplicate(reinterpret_cast<IDirectPlay8Address*>(pDeviceInfo),&pIDevice)) != DPN_OK)
{
DPFERR("Could not duplicate device info");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
}
else
{
DPFERR( "Invalid device address, it must be an IDirectPlay8Peer, IDirectPlay8Server, IDirectPlay8Client, IDirectPlay8Multicast, or IDirectPlay8Address object" );
return( DPNERR_INVALIDDEVICEADDRESS );
}
#ifndef DPNBUILD_ONLYONESP
//
// If there is no SP on the group address, then steal it from the device address
//
if ((hResultCode = IDirectPlay8Address_GetSP(pIGroup,&guidSP)) != DPN_OK)
{
if ((hResultCode = IDirectPlay8Address_GetSP(pIDevice,&guidSP)) != DPN_OK)
{
DPFERR("Could not retrieve SP from Device Address");
DisplayDNError(0,hResultCode);
goto Failure;
}
if ((hResultCode = IDirectPlay8Address_SetSP(pIGroup,&guidSP)) != DPN_OK)
{
DPFERR("Could not set SP on Group Address");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
#endif // ! DPNBUILD_ONLYONESP
//
// Ensure SP is loaded, if we haven't already.
//
if (pSP == NULL)
{
hResultCode = DN_SPEnsureLoaded(pdnObject,
#ifndef DPNBUILD_ONLYONESP
&guidSP,
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_LIBINTERFACE
NULL,
#endif // ! DPNBUILD_LIBINTERFACE
&pSP);
if (hResultCode != DPN_OK)
{
DPFERR("Could not find or load SP");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
#ifndef DPNBUILD_ONLYONEADAPTER
//
// Multicast listen device addresses are formed by taking the adapter GUID from
// the user's device address, combined with the entire user specified group address.
// If there is no adapter, then we will pick the best one as reported by the service
// provider (that part occurs inside DNPerformSPListen).
//
if ((hResultCode = IDirectPlay8Address_GetDevice(pIDevice,&guidAdapter)) == DPN_OK)
{
if ((hResultCode = IDirectPlay8Address_SetDevice(pIGroup,&guidAdapter)) != DPN_OK)
{
DPFERR("Could not set SP on Group Address");
DisplayDNError(0,hResultCode);
goto Failure;
}
}
#endif // ! DPNBUILD_ONLYONEADAPTER
dwListenFlags = DN_LISTENFLAGS_MULTICAST;
if (dwFlags & DPNJOIN_ALLOWUNKNOWNSENDERS)
{
dwListenFlags |= DN_LISTENFLAGS_ALLOWUNKNOWNSENDERS;
}
//
// Start multicast listen
//
if ((hResultCode = AsyncOpNew(pdnObject,&pListenParent)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
goto Failure;
}
pListenParent->SetOpType( ASYNC_OP_LISTEN_MULTICAST );
pListenParent->SetOpFlags( dwListenFlags );
pListenParent->MakeParent();
pListenParent->SetCompletion( DNCompleteListen );
// See note above about why it's pIGroup instead of pIDevice.
if ((hResultCode = DNPerformSPListen(pdnObject,pIGroup,pListenParent,&pParent)) != DPN_OK)
{
DPFERR("Could not start LISTEN");
DisplayDNError(0,hResultCode);
goto Failure;
}
pListenParent->AddRef();
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->pListenParent = pListenParent;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pListenParent->Release();
pListenParent = NULL;
//
// Multicast send endpoints are created using the user specified device address for the
// device, and what the SP reports it's using for the multicast listen as the group
// address.
//
pParent->Lock();
DNASSERT(! pParent->IsCancelled());
DNASSERT(! pParent->m_bilinkParent.IsEmpty());
pAsyncOp = CONTAINING_OBJECT(pParent->m_bilinkParent.GetNext(),CAsyncOp,m_bilinkChildren);
pAsyncOp->Lock();
DNASSERT((! pAsyncOp->IsCancelled()) && (! pAsyncOp->IsComplete()));
DNASSERT(pAsyncOp->m_bilinkChildren.GetNext() == &pParent->m_bilinkParent);
hEndpoint = pAsyncOp->GetProtocolHandle();
pAsyncOp->Unlock();
pParent->Unlock();
spInfoData.hEndpoint = hEndpoint;
spInfoData.Flags = SP_GET_ADDRESS_INFO_MULTICAST_GROUP;
if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData, spInfoData.hEndpoint,&spInfoData)) != DPN_OK)
{
DPFERR("Could not get LISTEN multicast group address!");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
// Release the old group address and save this new one.
IDirectPlay8Address_Release(pIGroup);
pIGroup = spInfoData.pAddress;
spInfoData.pAddress = NULL;
//
// If the user did not specify an adapter GUID, we selected one and we need to
// copy that selection over to the connect operation's device address. If the user
// did specify an adapter GUID, then this DNPGetListenAddressInfo will just be
// echoing it back, so there's no harm in copying it in either case.
//
spInfoData.hEndpoint = hEndpoint;
spInfoData.Flags = SP_GET_ADDRESS_INFO_LOCAL_ADAPTER;
if ((hResultCode = DNPGetListenAddressInfo(pdnObject->pdnProtocolData, spInfoData.hEndpoint,&spInfoData)) != DPN_OK)
{
DPFERR("Could not get LISTEN device address!");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
#ifndef DPNBUILD_ONLYONEADAPTER
if ((hResultCode = IDirectPlay8Address_GetDevice(spInfoData.pAddress,&guidAdapter)) != DPN_OK)
{
DPFERR("Could not get LISTEN device GUID!");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
IDirectPlay8Address_Release(spInfoData.pAddress);
spInfoData.pAddress = NULL;
goto Failure;
}
if ((hResultCode = IDirectPlay8Address_SetDevice(pIDevice,&guidAdapter)) != DPN_OK)
{
DPFERR("Could not set CONNECT device GUID!");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
IDirectPlay8Address_Release(spInfoData.pAddress);
spInfoData.pAddress = NULL;
goto Failure;
}
#endif // ! DPNBUILD_ONLYONEADAPTER
//
// Keep device address and connect SP on DirectNet object
//
pSP->AddRef();
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->pIDP8ADevice = spInfoData.pAddress; // Transfering reference
spInfoData.pAddress = NULL;
pdnObject->pConnectSP = pSP;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
pParent->Release();
pParent = NULL;
//
// Create parent async op, which will be released when the ENTIRE connection is finished
//
if ((hResultCode = AsyncOpNew(pdnObject,&pConnectParent)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pConnectParent->SetOpType( ASYNC_OP_CONNECT_MULTICAST_SEND );
pConnectParent->MakeParent();
pConnectParent->SetResult( DPNERR_NOCONNECTION );
pConnectParent->SetCompletion( DNCompleteJoinOperation );
// pConnectParent->SetReserved(1);
if (dwFlags & DPNCONNECT_SYNC)
{
DPFX(DPFPREP, 5,"Sync operation - create sync event");
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
{
DPFERR("Could not create synchronization event");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pConnectParent->SetSyncEvent( pSyncEvent );
pConnectParent->SetResultPointer( &hrOperation );
}
else
{
DPFX(DPFPREP, 5,"Async operation - create handle parent");
if ((hResultCode = DNCreateUserHandle(pdnObject,&pHandleParent)) != DPN_OK)
{
DPFERR("Could not create handle parent");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
goto Failure;
}
pHandleParent->SetContext( pvAsyncContext );
pHandleParent->Lock();
if (pHandleParent->IsCancelled())
{
pHandleParent->Unlock();
pConnectParent->SetResult( DPNERR_USERCANCEL );
hResultCode = DPNERR_USERCANCEL;
goto Failure;
}
pConnectParent->MakeChild( pHandleParent );
pHandleParent->Unlock();
}
hResultCode = DNPerformConnect(pdnObject,
0,
pIDevice,
pIGroup,
pSP,
DN_CONNECTFLAGS_MULTICAST_SEND,
pConnectParent);
if (hResultCode != DPN_OK)
{
DPFERR("Could not start CONNECT");
goto Failure;
}
pConnectParent->Release();
pConnectParent = NULL;
pSP->Release();
pSP = NULL;
if (pIGroup)
{
IDirectPlay8Address_Release(pIGroup);
pIGroup = NULL;
}
if (pIDevice)
{
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
}
if (dwFlags & DPNCONNECT_SYNC)
{
if ((hResultCode = pSyncEvent->WaitForEvent()) != DPN_OK)
{
DPFERR("DNSyncEventWait() terminated bizarrely");
DNASSERT(FALSE);
}
else
{
hResultCode = hrOperation;
}
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
else
{
pHandleParent->SetCompletion( DNCompleteUserJoin );
if (phAsyncHandle)
{
*phAsyncHandle = pHandleParent->GetHandle();
}
pHandleParent->Release();
pHandleParent = NULL;
hResultCode = DPNERR_PENDING;
}
Exit:
CallbackThread.Deinitialize();
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pIGroup)
{
IDirectPlay8Address_Release(pIGroup);
pIGroup = NULL;
}
if (pIDevice)
{
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
}
if (pExistingConnection != NULL)
{
pExistingConnection->Release();
pExistingConnection = NULL;
}
if (pShareListenParent != NULL)
{
pShareListenParent->Unlock();
pShareListenParent->Release();
pShareListenParent = NULL;
}
if (pShareSP != NULL)
{
pShareSP->Release();
pShareSP = NULL;
}
if (pShareDP8ServiceProvider != NULL)
{
IDP8ServiceProvider_Release(pShareDP8ServiceProvider);
pShareDP8ServiceProvider = NULL;
}
if (pLocalDP8ServiceProvider != NULL)
{
IDP8ServiceProvider_Release(pLocalDP8ServiceProvider);
pLocalDP8ServiceProvider = NULL;
}
if (pvNewInterface != NULL)
{
// Even if it's not an address, the Vtbl should be the same.
IDirectPlay8Address_Release((IDirectPlay8Address*) pvNewInterface);
pvNewInterface = NULL;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
if (pListenParent)
{
pListenParent->Release();
pListenParent = NULL;
}
if (pListenParent)
{
pParent->Release();
pParent = NULL;
}
if (pConnectParent)
{
if (SUCCEEDED(pdnObject->HandleTable.Destroy( pConnectParent->GetHandle(), NULL )))
{
// Release the HandleTable reference
pConnectParent->Release();
}
pConnectParent->Release();
pConnectParent = NULL;
}
if (pHandleParent)
{
pHandleParent->Release();
pHandleParent = NULL;
}
if (pSyncEvent)
{
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pListenParent = pdnObject->pListenParent;
pdnObject->pListenParent = NULL;
pSP = pdnObject->pConnectSP;
pdnObject->pConnectSP = NULL;
pIDevice = pdnObject->pIDP8ADevice;
pdnObject->pIDP8ADevice = NULL;
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pListenParent)
{
DNCancelChildren(pdnObject,pListenParent);
pListenParent->Release();
pListenParent = NULL;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
if (pIDevice)
{
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
}
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
pdnObject->dwFlags &= ~(DN_OBJECT_FLAG_CONNECTING|DN_OBJECT_FLAG_CONNECTED|DN_OBJECT_FLAG_LOCALHOST);
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
goto Exit;
} // DN_Join
//
// Completion for create sender context
//
#undef DPF_MODNAME
#define DPF_MODNAME "DNCompleteCreateSenderContext"
void DNCompleteCreateSenderContext(DIRECTNETOBJECT *const pdnObject,
CAsyncOp *const pAsyncOp)
{
}
//
// Associate a context value with a given multicast sender's address
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_CreateSenderContext"
STDMETHODIMP DN_CreateSenderContext( IDirectPlay8Multicast *pInterface,
IDirectPlay8Address *const pSenderAddress,
void *const pvSenderContext,
const DWORD dwFlags )
{
HRESULT hResultCode;
PDIRECTNETOBJECT pdnObject;
IDirectPlay8Address *pIDevice;
CServiceProvider *pSP;
CAsyncOp *pConnectParent;
CSyncEvent *pSyncEvent;
HRESULT hrConnect;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pSenderAddress [0x%p], pvSenderContext [0x%p], dwFlags [0x%lx]",
pInterface,pSenderAddress,pvSenderContext,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateCreateSenderContext( pInterface, pSenderAddress,
pvSenderContext, dwFlags ) ) )
{
DPFERR( "Error validating params" );
DPF_RETURN(hResultCode);
}
}
#endif // DPNBUILD_NOPARAMVAL
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
{
DPFERR( "Object is not initialized" );
DPF_RETURN( DPNERR_UNINITIALIZED );
}
pIDevice = NULL;
pSP = NULL;
pConnectParent = NULL;
pSyncEvent = NULL;
#pragma BUGBUG( minara, "Need to ensure not closing" )
//
// Extract device and SP from DirectNet object
//
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
DNASSERT( pdnObject->pConnectSP != NULL );
DNASSERT( pdnObject->pIDP8ADevice != NULL );
if (pdnObject->pConnectSP)
{
pdnObject->pConnectSP->AddRef();
pSP = pdnObject->pConnectSP;
}
if (pdnObject->pIDP8ADevice)
{
IDirectPlay8Address_AddRef(pdnObject->pIDP8ADevice);
pIDevice = pdnObject->pIDP8ADevice;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pSP == NULL || pIDevice == NULL)
{
DPFERR("Invalid connect SP or device address");
hResultCode = DPNERR_GENERIC;
goto Failure;
}
//
// Create SyncEvent
//
if ((hResultCode = SyncEventNew(pdnObject,&pSyncEvent)) != DPN_OK)
{
DPFERR("Could not create SyncEvent");
goto Failure;
}
//
// Create AsyncOp parent
//
if ((hResultCode = AsyncOpNew(pdnObject,&pConnectParent)) != DPN_OK)
{
DPFERR("Could not create AsyncOp");
goto Failure;
}
pConnectParent->SetOpType( ASYNC_OP_CONNECT_MULTICAST_RECEIVE );
pConnectParent->SetSyncEvent( pSyncEvent );
pConnectParent->SetResultPointer( &hrConnect );
pConnectParent->SetContext( pvSenderContext );
//
// We will call connect on the Protocol to associate the sender's endpoint with a context
// This call to connect must be turned into a synchronous operation since this API call is synchronous
//
if ((hResultCode = DNPerformConnect(pdnObject,
0,
pIDevice,
pSenderAddress,
pSP,
DN_CONNECTFLAGS_MULTICAST_RECEIVE,
pConnectParent)) != DPN_OK)
{
DPFERR("Failed to connect");
DisplayDNError(0,hResultCode);
goto Failure;
}
//
// Release references and wait for completion
//
pConnectParent->SetCompletion( DNCompleteCreateSenderContext );
pConnectParent->Release();
pConnectParent = NULL;
pSP->Release();
pSP = NULL;
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
pSyncEvent->WaitForEvent();
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
if (hrConnect == DPN_OK)
{
DNUserCreateSenderContext(pdnObject,pvSenderContext);
}
hResultCode = hrConnect;
Exit:
DNASSERT( pIDevice == NULL );
DNASSERT( pSP == NULL );
DNASSERT( pConnectParent == NULL );
DNASSERT( pSyncEvent == NULL );
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
Failure:
if (pIDevice)
{
IDirectPlay8Address_Release(pIDevice);
pIDevice = NULL;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
if (pConnectParent)
{
pConnectParent->Release();
pConnectParent = NULL;
}
if (pSyncEvent)
{
pSyncEvent->ReturnSelfToPool();
pSyncEvent = NULL;
}
goto Exit;
} // DN_CreateSenderContext
//
// Removes a previously associated context value from a given multicast sender's address
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_DestroySenderContext"
STDMETHODIMP DN_DestroySenderContext( IDirectPlay8Multicast *pInterface,
IDirectPlay8Address *const pSenderAddress,
const DWORD dwFlags )
{
HRESULT hResultCode;
DIRECTNETOBJECT *pdnObject;
CServiceProvider *pSP;
CConnection *pConnection;
IDirectPlay8Address *pDevice;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pSenderAddress [0x%p], dwFlags [0x%lx]",
pInterface,pSenderAddress,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateDestroySenderContext( pInterface, pSenderAddress, dwFlags ) ) )
{
DPFERR( "Error validating params" );
DPF_RETURN(hResultCode);
}
}
#endif // DPNBUILD_NOPARAMVAL
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
{
DPFERR( "Object is not initialized" );
DPF_RETURN( DPNERR_UNINITIALIZED );
}
pSP = NULL;
pConnection = NULL;
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pIDP8ADevice)
{
IDirectPlay8Address_AddRef(pdnObject->pIDP8ADevice);
pDevice = pdnObject->pIDP8ADevice;
}
if (pdnObject->pConnectSP)
{
pdnObject->pConnectSP->AddRef();
pSP = pdnObject->pConnectSP;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
//
// Get endpoint from address
//
if ((hResultCode = DNPGetEndPointContextFromAddress(pdnObject->pdnProtocolData, pSP->GetHandle(),pSenderAddress,pDevice,reinterpret_cast<void**>(&pConnection))) == DPN_OK)
{
pConnection->AddRef();
pConnection->Disconnect();
pConnection->Release();
pConnection = NULL;
}
//
// Clean up
//
IDirectPlay8Address_Release(pDevice);
pDevice = NULL;
pSP->Release();
pSP = NULL;
hResultCode = DPN_OK;
DNASSERT( pSP == NULL );
DNASSERT( pConnection == NULL );
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
} // DN_DestroySenderContext
//
// Retrieves the current multicast group address
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_GetGroupAddress"
STDMETHODIMP DN_GetGroupAddress(IDirectPlay8Multicast *pInterface,
IDirectPlay8Address **const ppAddress,
const DWORD dwFlags)
{
HRESULT hResultCode;
DIRECTNETOBJECT *pdnObject;
CConnection *pConnection;
HANDLE hEndPt;
SPGETADDRESSINFODATA spInfoData;
CCallbackThread CallbackThread;
DPFX(DPFPREP, 2,"Parameters : pInterface [0x%p], ppAddress [0x%p], dwFlags [0x%lx]",
pInterface,ppAddress,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateGetGroupAddress( pInterface, ppAddress, dwFlags ) ) )
{
DPFX(DPFPREP, 0, "Error validating get group address info hr=[0x%lx]", hResultCode );
DPF_RETURN( hResultCode );
}
}
#endif // !DPNBUILD_NOPARAMVAL
// Check to ensure message handler registered
if (!(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED))
{
DPFERR( "Object is not initialized" );
DPF_RETURN(DPNERR_UNINITIALIZED);
}
if( pdnObject->dwFlags & DN_OBJECT_FLAG_CONNECTING )
{
DPFERR("Object is connecting / starting to host" );
DPF_RETURN(DPNERR_CONNECTING);
}
if ( !(pdnObject->dwFlags & (DN_OBJECT_FLAG_CONNECTED | DN_OBJECT_FLAG_CLOSING | DN_OBJECT_FLAG_DISCONNECTING) ) )
{
DPFERR("You must be connected / disconnecting to use this function" );
DPF_RETURN(DPNERR_NOCONNECTION);
}
CallbackThread.Initialize();
DNEnterCriticalSection(&pdnObject->csDirectNetObject);
if (pdnObject->pMulticastSend != NULL)
{
pdnObject->pMulticastSend->AddRef();
pConnection = pdnObject->pMulticastSend;
}
else
{
pConnection = NULL;
}
DNLeaveCriticalSection(&pdnObject->csDirectNetObject);
if (pConnection == NULL)
{
DPFERR( "Couldn't retrieve multicast send connection" );
hResultCode = DPNERR_INVALIDGROUP;
goto Failure;
}
//
// Get the remote multicast address address
//
if ((hResultCode = pConnection->GetEndPt(&hEndPt,&CallbackThread)) != DPN_OK)
{
DPFERR( "Couldn't retrieve multicast send endpoint" );
DisplayDNError(0, hResultCode);
goto Failure;
}
spInfoData.Flags = SP_GET_ADDRESS_INFO_MULTICAST_GROUP;
hResultCode = DNPCrackEndPointDescriptor(pdnObject->pdnProtocolData, hEndPt,&spInfoData);
if (hResultCode != DPN_OK)
{
DPFERR("Unknown error from DNPCrackEndPointDescriptor");
DisplayDNError(0,hResultCode);
DNASSERT(FALSE);
// Drop through...
}
pConnection->ReleaseEndPt(&CallbackThread);
pConnection->Release();
pConnection = NULL;
*ppAddress = spInfoData.pAddress;
spInfoData.pAddress = NULL;
Exit:
CallbackThread.Deinitialize();
DPF_RETURN(hResultCode);
Failure:
if (pConnection)
{
pConnection->Release();
pConnection = NULL;
}
goto Exit;
} // DN_GetGroupAddress
//
// Enumerate multicast scopes reported by SP
//
#undef DPF_MODNAME
#define DPF_MODNAME "DN_EnumMulticastScopes"
STDMETHODIMP DN_EnumMulticastScopes( IDirectPlay8Multicast *pInterface,
const GUID *const pguidServiceProvider,
const GUID *const pguidDevice,
const GUID *const pguidApplication,
DPN_MULTICAST_SCOPE_INFO *const pScopeInfoBuffer,
DWORD *const pcbEnumData,
DWORD *const pcReturned,
const DWORD dwFlags )
{
HRESULT hResultCode;
PDIRECTNETOBJECT pdnObject;
DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p], pguidServiceProvider [0x%p], pguidDevice [0x%p], pguidApplication [0x%p], pScopeInfoBuffer [0x%p], pcbEnumData [0x%p], pcReturned [0x%p], dwFlags [0x%lx]",
pInterface,pguidServiceProvider,pguidDevice,pguidApplication,pScopeInfoBuffer,pcbEnumData,pcReturned,dwFlags);
pdnObject = (DIRECTNETOBJECT*) GET_OBJECT_FROM_INTERFACE(pInterface);
DNASSERT(pdnObject != NULL);
#ifndef DPNBUILD_NOPARAMVAL
if( pdnObject->dwFlags & DN_OBJECT_FLAG_PARAMVALIDATION )
{
if( FAILED( hResultCode = DN_ValidateEnumMulticastScopes( pInterface, pguidServiceProvider, pguidDevice,
pguidApplication, pScopeInfoBuffer,
pcbEnumData, pcReturned, dwFlags ) ) )
{
DPFERR( "Error validating params" );
DPF_RETURN(hResultCode);
}
}
#endif // DPNBUILD_NOPARAMVAL
if( !(pdnObject->dwFlags & DN_OBJECT_FLAG_INITIALIZED) )
{
DPFERR( "Object is not initialized" );
DPF_RETURN( DPNERR_UNINITIALIZED );
}
hResultCode = DN_EnumMulticastScopes(pdnObject,
dwFlags,
#ifndef DPNBUILD_ONLYONESP
pguidServiceProvider,
#endif // ! DPNBUILD_ONLYONESP
#ifndef DPNBUILD_ONLYONEADAPTER
pguidDevice,
#endif // ! DPNBUILD_ONLYONEADAPTER
#ifndef DPNBUILD_LIBINTERFACE
pguidApplication,
#endif // ! DPNBUILD_LIBINTERFACE
pScopeInfoBuffer,
pcbEnumData,
pcReturned);
DPFX(DPFPREP, 3,"Set: *pcbEnumData [%ld], *pcReturned [%ld]",*pcbEnumData,*pcReturned);
DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode);
return(hResultCode);
} // DN_EnumMulticastScopes
#endif // ! DPNBUILD_NOMULTICAST