/*========================================================================== * * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved. * * File: Enum.cpp * Content: This file contains support enuming sessions. * * History: * Date By Reason * ==== == ====== * 01/10/00 jtk Created * 07/01/2000 masonb Assumed Ownership * ****************************************************************************/ #include "dnproti.h" //********************************************************************** // Constant definitions //********************************************************************** //********************************************************************** // Macro definitions //********************************************************************** //********************************************************************** // Structure definitions //********************************************************************** //********************************************************************** // Variable definitions //********************************************************************** //********************************************************************** // Function prototypes //********************************************************************** //********************************************************************** // Function definitions //********************************************************************** /* ** Send Enum Query ** ** This routine will send out a broadcast to everyone that can hear ** indicating this side's interest in finding listening connections. ** Interested connections will respond through IndicateEnumResponse. */ #undef DPF_MODNAME #define DPF_MODNAME "DNPEnumQuery" HRESULT DNPEnumQuery(HANDLE hProtocolData, IDirectPlay8Address* paHostAddress, IDirectPlay8Address* paDeviceAddress, HANDLE hSPHandle, BUFFERDESC* pBuffers, DWORD dwBufferCount, DWORD dwRetryCount, DWORD dwRetryInterval, DWORD dwTimeout, DWORD dwFlags, VOID* pvUserContext, VOID* pvSessionData, DWORD dwSessionDataSize, HANDLE* phEnumHandle) { ProtocolData* pPData; PSPD pSPD; PMSD pMSD; SPENUMQUERYDATA EnumData; HRESULT hr; #ifdef DBG ULONG ulAllowedFlags; #endif // DBG DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], paHostAddress[%p], paDeviceAddress[%p], hSPHandle[%p], pBuffers[%p], dwBufferCount[%x], dwRetryCount[%x], dwRetryInterval[%x], dwTimeout[%x], dwFlags[%x], pvUserContext[%p], pvSessionData[%p], dwSessionDataSize[%u], phEnumHandle[%p]", hProtocolData, paHostAddress, paDeviceAddress, hSPHandle, pBuffers, dwBufferCount, dwRetryCount, dwRetryInterval, dwTimeout, dwFlags, pvUserContext, pvSessionData, dwSessionDataSize, phEnumHandle); hr = DPNERR_PENDING; pPData = (ProtocolData*)hProtocolData; ASSERT_PPD(pPData); pSPD = (PSPD) hSPHandle; ASSERT_SPD(pSPD); // Core should not call any Protocol APIs after calling DNPRemoveServiceProvider ASSERT(!(pSPD->ulSPFlags & SPFLAGS_TERMINATING)); // We use an MSD to describe this Op even though it isn't technically a message if((pMSD = (PMSD)POOLALLOC(MEMID_ENUMQUERY_MSD, &MSDPool)) == NULL) { DPFX(DPFPREP,0, "Failed to allocate MSD"); hr = DPNERR_OUTOFMEMORY; goto Exit; } pMSD->CommandID = COMMAND_ID_ENUM; pMSD->pSPD = pSPD; pMSD->Context = pvUserContext; EnumData.pAddressHost = paHostAddress; EnumData.pAddressDeviceInfo = paDeviceAddress; EnumData.pBuffers = pBuffers; EnumData.dwBufferCount = dwBufferCount; EnumData.dwTimeout = dwTimeout; EnumData.dwRetryCount = dwRetryCount; EnumData.dwRetryInterval = dwRetryInterval; #ifdef DBG ulAllowedFlags = DN_ENUMQUERYFLAGS_NOBROADCASTFALLBACK | DN_ENUMQUERYFLAGS_SESSIONDATA; #ifndef DPNBUILD_NOSPUI ulAllowedFlags |= DN_ENUMQUERYFLAGS_OKTOQUERYFORADDRESSING; #endif // ! DPNBUILD_NOSPUI #ifndef DPNBUILD_ONLYONEADAPTER ulAllowedFlags |= DN_ENUMQUERYFLAGS_ADDITIONALMULTIPLEXADAPTERS; #endif // ! DPNBUILD_ONLYONEADAPTER DNASSERT( ( dwFlags & ~(ulAllowedFlags) ) == 0 ); #endif // DBG EnumData.dwFlags = 0; #ifndef DPNBUILD_NOSPUI if ( ( dwFlags & DN_ENUMQUERYFLAGS_OKTOQUERYFORADDRESSING ) != 0 ) { EnumData.dwFlags |= DPNSPF_OKTOQUERY; } #endif // ! DPNBUILD_NOSPUI if ( ( dwFlags & DN_ENUMQUERYFLAGS_NOBROADCASTFALLBACK ) != 0 ) { EnumData.dwFlags |= DPNSPF_NOBROADCASTFALLBACK; } #ifndef DPNBUILD_ONLYONEADAPTER if ( ( dwFlags & DN_ENUMQUERYFLAGS_ADDITIONALMULTIPLEXADAPTERS ) != 0 ) { EnumData.dwFlags |= DPNSPF_ADDITIONALMULTIPLEXADAPTERS; } #endif // ! DPNBUILD_ONLYONEADAPTER if ( ( dwFlags & DN_ENUMQUERYFLAGS_SESSIONDATA) != 0 ) { EnumData.dwFlags |= DPNSPF_SESSIONDATA; EnumData.pvSessionData = pvSessionData; EnumData.dwSessionDataSize = dwSessionDataSize; } EnumData.pvContext = pMSD; EnumData.hCommand = NULL; *phEnumHandle = pMSD; #ifdef DBG Lock(&pSPD->SPLock); pMSD->blSPLinkage.InsertBefore( &pSPD->blMessageList); // Dont support timeouts for Listen pMSD->ulMsgFlags1 |= MFLAGS_ONE_ON_GLOBAL_LIST; Unlock(&pSPD->SPLock); #endif // DBG pMSD->ulMsgFlags1 |= MFLAGS_ONE_IN_SERVICE_PROVIDER; LOCK_MSD(pMSD, "SP Ref"); // AddRef for SP LOCK_MSD(pMSD, "Temp Ref"); AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld); DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->EnumQuery, pSPD[%p], pMSD[%p]", pSPD, pMSD); /**/hr = IDP8ServiceProvider_EnumQuery(pSPD->IISPIntf, &EnumData); /** CALL SP **/ if(hr != DPNERR_PENDING) { // This should always Pend or else be in error DPFX(DPFPREP,1, "Calling SP->EnumQuery Failed, return is not DPNERR_PENDING, hr[%x], pMSD[%p], pSPD[%p]", hr, pMSD, pSPD); // DPNERR_PENDING is the only success code we accept ASSERT(FAILED(hr)); Lock(&pMSD->CommandLock); pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER); #ifdef DBG Lock(&pSPD->SPLock); pMSD->blSPLinkage.RemoveFromList(); // knock this off the pending list pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST); Unlock(&pSPD->SPLock); #endif // DBG DECREMENT_MSD(pMSD, "Temp Ref"); DECREMENT_MSD(pMSD, "SP Ref"); // release once for SP RELEASE_MSD(pMSD, "Release On Fail"); // release again to return resource goto Exit; } Lock(&pMSD->CommandLock); pMSD->hCommand = EnumData.hCommand; // retain SP command handle pMSD->dwCommandDesc = EnumData.dwCommandDescriptor; RELEASE_MSD(pMSD, "Temp Ref"); // Unlocks CommandLock Exit: DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x], pMSD[%p]", hr, pMSD); AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld); return hr; } /* ** Enum Respond ** ** This routine will send out a response to a received enum query. */ #undef DPF_MODNAME #define DPF_MODNAME "DNPEnumRespond" HRESULT DNPEnumRespond(HANDLE hProtocolData, HANDLE hSPHandle, HANDLE hQueryHandle, BUFFERDESC* pBuffers, DWORD dwBufferCount, DWORD dwFlags, VOID* pvUserContext, HANDLE* phEnumHandle) { ProtocolData* pPData; PSPD pSPD; PMSD pMSD; SPENUMRESPONDDATA EnumRespondData; HRESULT hr; DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: hProtocolData[%p], hSPHandle[%p], hQueryHandle[%p], pBuffers[%p], dwBufferCount[%x], dwFlags[%x], pvUserContext[%p], phEnumHandle[%p]", hProtocolData, hSPHandle, hQueryHandle, pBuffers, dwBufferCount, dwFlags, pvUserContext, phEnumHandle); hr = DPNERR_PENDING; pPData = (ProtocolData*)hProtocolData; ASSERT_PPD(pPData); pSPD = (PSPD)hSPHandle; ASSERT_SPD(pSPD); ASSERT(hQueryHandle); // Core should not call any Protocol APIs after calling DNPRemoveServiceProvider ASSERT(!(pSPD->ulSPFlags & SPFLAGS_TERMINATING)); // We use an MSD to describe this Op even though it isn't technically a message if((pMSD = (PMSD)POOLALLOC(MEMID_ENUMRESP_MSD, &MSDPool)) == NULL) { DPFX(DPFPREP,0, "Failed to allocate MSD"); hr = DPNERR_OUTOFMEMORY; goto Exit; } pMSD->CommandID = COMMAND_ID_ENUMRESP; pMSD->pSPD = pSPD; pMSD->Context = pvUserContext; EnumRespondData.pBuffers = pBuffers; EnumRespondData.dwBufferCount = dwBufferCount; EnumRespondData.dwFlags = dwFlags; EnumRespondData.pvContext = pMSD; EnumRespondData.hCommand = NULL; EnumRespondData.pQuery = (SPIE_QUERY*)hQueryHandle; *phEnumHandle = pMSD; #ifdef DBG Lock(&pSPD->SPLock); pMSD->blSPLinkage.InsertBefore( &pSPD->blMessageList); pMSD->ulMsgFlags1 |= MFLAGS_ONE_ON_GLOBAL_LIST; Unlock(&pSPD->SPLock); #endif // DBG pMSD->ulMsgFlags1 |= MFLAGS_ONE_IN_SERVICE_PROVIDER; LOCK_MSD(pMSD, "SP Ref"); // AddRef for SP LOCK_MSD(pMSD, "Temp Ref"); AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld); DPFX(DPFPREP,DPF_CALLOUT_LVL, "Calling SP->EnumRespond, pSPD[%p], pMSD[%p]", pSPD, pMSD); /**/hr = IDP8ServiceProvider_EnumRespond(pSPD->IISPIntf, &EnumRespondData); /** CALL SP **/ // This should always Pend or else be in error if(hr != DPNERR_PENDING) { DPFX(DPFPREP,1, "Calling SP->EnumRespond, return is not DPNERR_PENDING, hr[%x], pMSD[%p], pSPD[%p]", hr, pMSD, pSPD); // DPNERR_PENDING is the only success code we accept ASSERT(FAILED(hr)); Lock(&pMSD->CommandLock); pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER); #ifdef DBG Lock(&pSPD->SPLock); pMSD->blSPLinkage.RemoveFromList(); // knock this off the pending list pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST); Unlock(&pSPD->SPLock); #endif // DBG DECREMENT_MSD(pMSD, "Temp Ref"); DECREMENT_MSD(pMSD, "SP Ref"); // release once for SP RELEASE_MSD(pMSD, "Release On Non-Pend"); // release again to return resource goto Exit; } Lock(&pMSD->CommandLock); pMSD->hCommand = EnumRespondData.hCommand; // retain SP command handle pMSD->dwCommandDesc = EnumRespondData.dwCommandDescriptor; RELEASE_MSD(pMSD, "Temp Ref"); // Unlocks CommandLock Exit: DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning hr[%x], pMSD[%p]", hr, pMSD); AssertNoCriticalSectionsFromGroupTakenByThisThread(&g_blProtocolCritSecsHeld); return hr; } //**********************************************************************