/*==========================================================================
 *
 *  Copyright (C) 2000 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
//**********************************************************************


//**********************************************************************
// ------------------------------
// DNPEnumQuery - enum sessions
//
// Entry:		Pointer to this interface
//				Pointer to device address
//				Pointer to host address
//				Pointer to user data buffers
//				Count of user data buffers
//				Retry count
//				Retry interval (milliseconds)
//				Timeout (milliseconds)
//				Command flags
//				Pointer to user context
//				Pointer to command handle destination
//
// Exit:		Boolean inficating whether the GUID is a serial GUID
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNPEnumQuery"

HRESULT DNPEnumQuery( PProtocolData pPData,
					  IDirectPlay8Address *const pHostAddress,
					  IDirectPlay8Address *const pDeviceAddress,
					  const HANDLE hSPHandle,
					  BUFFERDESC *const pBuffers,
					  const DWORD dwBufferCount,
					  const DWORD dwRetryCount,
					  const DWORD dwRetryInterval,
					  const DWORD dwTimeout,
					  const DWORD dwFlags,
					  void *const pUserContext,
					  HANDLE *const pCommandHandle )
{
	PSPD			pSPD;
	PMSD			pMSD;
	SPENUMQUERYDATA	EnumData;
	HRESULT			hr;

	DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], pHostAddr[%p], pDeviceAddr[%p], hSPHandle[%x], pBuffers[%p], dwBufferCount[%x], dwRetryCount[%x], dwRetryInterval[%x], dwTimeout[%x], dwFlags[%x], pUserContext[%p], pCommandHandle[%p]", pPData, pHostAddress, pDeviceAddress, hSPHandle, pBuffers, dwBufferCount, dwRetryCount, dwRetryInterval, dwTimeout, dwFlags, pUserContext, pCommandHandle);

	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 tho it
	if((pMSD = static_cast<PMSD>( MSDPool->Get(MSDPool) )) == NULL)
	{	
		DPFX(DPFPREP,0, "Failed to allocate MSD");
		Unlock(&pSPD->SPLock);
		return DPNERR_OUTOFMEMORY;				// .. isnt technically a message
	}

	pMSD->CommandID = COMMAND_ID_ENUM;
	pMSD->pSPD = pSPD;
	pMSD->Context = pUserContext;

	EnumData.pAddressHost = pHostAddress;
	EnumData.pAddressDeviceInfo = pDeviceAddress;
	EnumData.pBuffers = pBuffers;
	EnumData.dwBufferCount = dwBufferCount;
	EnumData.dwTimeout = dwTimeout;
	EnumData.dwRetryCount = dwRetryCount;
	EnumData.dwRetryInterval = dwRetryInterval;

	EnumData.dwFlags = 0;
	if ( ( dwFlags & DN_ENUMQUERYFLAGS_OKTOQUERYFORADDRESSING ) != 0 )
	{
		EnumData.dwFlags |= DPNSPF_OKTOQUERY;
	}

	if ( ( dwFlags & DN_ENUMQUERYFLAGS_NOBROADCASTFALLBACK ) != 0 )
	{
		EnumData.dwFlags |= DPNSPF_NOBROADCASTFALLBACK;
	}

	if ( ( dwFlags & DN_ENUMQUERYFLAGS_ADDITIONALMULTIPLEXADAPTERS ) != 0 )
	{
		EnumData.dwFlags |= DPNSPF_ADDITIONALMULTIPLEXADAPTERS;
	}

	EnumData.pvContext = pMSD;
	EnumData.hCommand = NULL;

	*pCommandHandle = pMSD;

#ifdef DEBUG
	Lock(&pSPD->SPLock);
	pMSD->blSPLinkage.InsertBefore( &pSPD->blMessageList);		// Dont support timeouts for Listen
	pMSD->ulMsgFlags1 |= MFLAGS_ONE_ON_GLOBAL_LIST;
	Unlock(&pSPD->SPLock);
#endif

	pMSD->ulMsgFlags1 |= MFLAGS_ONE_IN_SERVICE_PROVIDER;
	LOCK_MSD(pMSD, "SP Ref");											// AddRef for SP
	LOCK_MSD(pMSD, "Temp Ref");

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

		Lock(&pMSD->CommandLock);
		pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER);

#ifdef DEBUG
		Lock(&pSPD->SPLock);
		pMSD->blSPLinkage.RemoveFromList();					// knock this off the pending list
		pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
		Unlock(&pSPD->SPLock);
#endif

		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

		return hr;
	}

	Lock(&pMSD->CommandLock);

	pMSD->hCommand = EnumData.hCommand;			// retain SP command handle
	pMSD->dwCommandDesc = EnumData.dwCommandDescriptor;

	RELEASE_MSD(pMSD, "Temp Ref"); // Unlocks CommandLock

	DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning DPNERR_PENDING, pMSD[%p]", pMSD);
	return DPNERR_PENDING;
}
//**********************************************************************


//**********************************************************************
// ------------------------------
// DNPEnumRespond - respond to an enum query
//
// Entry:		Pointer to this interface
//				Handle of enum to respond to (pointer to SPIE_ENUMQUERY structure)
//				Pointer data buffers to send
//				Count of data buffers to send
//				Flags
//				User context for this operation
//				Pointer to command handle destination
//
// Exit:		Boolean inficating whether the GUID is a serial GUID
// ------------------------------
#undef DPF_MODNAME
#define DPF_MODNAME "DNPEnumRespond"

HRESULT DNPEnumRespond( PProtocolData pPData,
					    const HANDLE hSPHandle,
						const HANDLE hQueryHandle,				// handle of enum query being responded to
						BUFFERDESC *const pResponseBuffers,	
						const DWORD dwResponseBufferCount,
						const DWORD dwFlags,
						void *const pUserContext,
						HANDLE *const pCommandHandle )
{
	PSPD				pSPD;
	PMSD				pMSD;
	SPENUMRESPONDDATA	EnumRespondData;
	HRESULT				hr;

	DPFX(DPFPREP,DPF_CALLIN_LVL, "Parameters: pPData[%p], hSPHandle[%x], hQueryHandle[%x], pResponseBuffers[%p], dwResponseBufferCount[%x], dwFlags[%x], pUserContext[%p], pCommandHandle[%p]", pPData, hSPHandle, hQueryHandle, pResponseBuffers, dwResponseBufferCount, dwFlags, pUserContext, pCommandHandle);
	EnumRespondData.pQuery = static_cast<SPIE_QUERY*>( hQueryHandle );
	DNASSERT( EnumRespondData.pQuery != NULL );

	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 tho it
	if((pMSD = static_cast<PMSD>( MSDPool->Get(MSDPool) )) == NULL)
	{
		DPFX(DPFPREP,0, "Failed to allocate MSD");
		Unlock(&pSPD->SPLock);
		return DPNERR_OUTOFMEMORY;				// .. isnt technically a message
	}

	pMSD->CommandID = COMMAND_ID_ENUMRESP;
	pMSD->pSPD = pSPD;
	pMSD->Context = pUserContext;

	EnumRespondData.pBuffers = pResponseBuffers;
	EnumRespondData.dwBufferCount = dwResponseBufferCount;
	EnumRespondData.dwFlags = dwFlags;
	EnumRespondData.pvContext = pMSD;
	EnumRespondData.hCommand = NULL;

	*pCommandHandle = pMSD;

#ifdef DEBUG
	Lock(&pSPD->SPLock);
	pMSD->blSPLinkage.InsertBefore( &pSPD->blMessageList);
	pMSD->ulMsgFlags1 |= MFLAGS_ONE_ON_GLOBAL_LIST;
	Unlock(&pSPD->SPLock);
#endif

	pMSD->ulMsgFlags1 |= MFLAGS_ONE_IN_SERVICE_PROVIDER;
	LOCK_MSD(pMSD, "SP Ref");										// AddRef for SP
	LOCK_MSD(pMSD, "Temp Ref");

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

		Lock(&pMSD->CommandLock);
		pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_IN_SERVICE_PROVIDER);

#ifdef DEBUG
		Lock(&pSPD->SPLock);
		pMSD->blSPLinkage.RemoveFromList();					// knock this off the pending list
		pMSD->ulMsgFlags1 &= ~(MFLAGS_ONE_ON_GLOBAL_LIST);
		Unlock(&pSPD->SPLock);
#endif

		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

		return hr;
	}

	Lock(&pMSD->CommandLock);

	pMSD->hCommand = EnumRespondData.hCommand;				// retain SP command handle
	pMSD->dwCommandDesc = EnumRespondData.dwCommandDescriptor;

	RELEASE_MSD(pMSD, "Temp Ref"); // Unlocks CommandLock

	DPFX(DPFPREP,DPF_CALLIN_LVL, "Returning DPNERR_PENDING, pMSD[%p]", pMSD);
	return DPNERR_PENDING;
}
//**********************************************************************