windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/msg/multsend.cpp
2020-09-26 16:20:57 +08:00

166 lines
3.5 KiB
C++

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
#include "precomp.h"
#include <assert.h>
#include "multsend.h"
/*****************************************************************
CMsgMultiSendReceive - Implements the list of senders using a circular
list. This allows us to easily advance the current sender when
encountering failures. MultiSendReceive remembers the last good sender.
It will keep using this until it has a problem with it.
******************************************************************/
CMsgMultiSendReceive::~CMsgMultiSendReceive()
{
if ( m_pTail == NULL )
{
return;
}
SenderNode* pCurr = m_pTail->m_pNext;
while( pCurr != m_pTail )
{
SenderNode* pTmp = pCurr->m_pNext;
delete pCurr;
pCurr = pTmp;
}
delete m_pTail;
}
//
// Later, we could support flags that tell us where to add the sender.
// for now, we always add to the end of the list.
//
HRESULT CMsgMultiSendReceive::Add( DWORD dwFlags,
IWmiMessageSendReceive* pSndRcv)
{
ENTER_API_CALL
HRESULT hr;
SenderNode* pNew = new SenderNode;
if ( pNew == NULL )
{
return WBEM_E_OUT_OF_MEMORY;
}
pNew->m_pVal = pSndRcv;
CInCritSec ics(&m_cs);
if ( m_pTail != NULL )
{
pNew->m_pNext = m_pTail->m_pNext;
m_pTail->m_pNext = pNew;
}
else
{
m_pPrimary = pNew;
pNew->m_pNext = pNew;
}
//
// if the sender is also a multi sender, we handle things differently
// in the send logic.
//
if ( dwFlags & WMIMSG_FLAG_MULTISEND_TERMINATING_SENDER )
{
pNew->m_bTermSender = TRUE;
}
else
{
pNew->m_bTermSender = FALSE;
}
m_pTail = pNew;
return S_OK;
EXIT_API_CALL
}
//
// returns S_FALSE when succeeded but primary is not used.
//
HRESULT CMsgMultiSendReceive::SendReceive( PBYTE pData,
ULONG cData,
PBYTE pAuxData,
ULONG cAuxData,
DWORD dwFlags,
IUnknown* pCtx )
{
ENTER_API_CALL
HRESULT hr;
CInCritSec ics( &m_cs );
if ( m_pTail == NULL )
{
return S_OK;
}
HRESULT hrReturn = S_OK;
SenderNode* pCurr = m_pTail;
SenderNode* pTerm = m_pTail;
do
{
pCurr = pCurr->m_pNext;
hr = pCurr->m_pVal->SendReceive( pData,
cData,
pAuxData,
cAuxData,
dwFlags,
pCtx );
//
// on error we only observe the 'return immediately' flag if we are not
// calling another multi sender. This allows all the terminal primary
// senders to be tried first, before resorting to alternates.
//
if( SUCCEEDED(hr) ||
pCurr->m_bTermSender &&
dwFlags & WMIMSG_FLAG_MULTISEND_RETURN_IMMEDIATELY )
{
hrReturn = hr;
break;
}
else
{
m_pTail = m_pTail->m_pNext;
hrReturn = hr;
}
} while( pCurr != pTerm );
if ( hrReturn != S_OK )
{
return hrReturn;
}
return m_pTail->m_pNext == m_pPrimary ? S_OK : S_FALSE;
EXIT_API_CALL
}