windows-nt/Source/XPSP1/NT/net/tapi/skywalker/mspbase/dtevntsk.cpp
2020-09-26 16:20:57 +08:00

507 lines
11 KiB
C++

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
DTEvntSk.cpp
Abstract:
This module contains implementation of CPTEventSink.
Author:
vlade Nov 1999
--*/
#include "precomp.h"
#pragma hdrstop
CPTEventSink::CPTEventSink() :
m_pMSPStream(NULL)
{
LOG((MSP_TRACE, "CPTEventSink::CPTEventSink enter"));
LOG((MSP_TRACE, "CPTEventSink::CPTEventSink exit"));
}
CPTEventSink::~CPTEventSink()
{
LOG((MSP_TRACE, "CPTEventSink::~CPTEventSink enter"));
LOG((MSP_TRACE, "CPTEventSink::~CPTEventSink exit"));
};
// --- ITPluggableTerminalEventSnk ---
/*++
FireEvent
Parameters:
IN MSPEVENTITEM * pEventItem pointer to the structure that describes the
event. all the pointers contained in the structure must be addreffed by
the caller, and then released by the caller if FireEvent fails
FireEvent makes a (shallow) copy of the structure, so the caller can
delete the structure when the function returns
Returns:
S_OK - every thing was OK
E_FAIL & other - something was wrong
Description:
This method is called by the dynamic terminals to
signal a new event
--*/
STDMETHODIMP CPTEventSink::FireEvent(
IN const MSP_EVENT_INFO * pEventInfo
)
{
LOG((MSP_TRACE, "CPTEventSink::FireEvent enter"));
//
// make sure we got a good mspeventitem structure
//
if( MSPB_IsBadWritePtr( (void*)pEventInfo, sizeof( MSP_EVENT_INFO )))
{
LOG((MSP_ERROR, "CPTEventSink::FireEvent -"
"pEventItem is bad, returns E_POINTER"));
return E_POINTER;
}
//
// Create an MSPEVENTITEM
//
MSPEVENTITEM *pEventItem = AllocateEventItem();
if (NULL == pEventItem)
{
LOG((MSP_ERROR, "CPTEventSink::FireEvent -"
"failed to create MSPEVENTITEM. returning E_OUTOFMEMORY "));
return E_OUTOFMEMORY;
}
//
// make a shallow copy of the structure
//
pEventItem->MSPEventInfo = *pEventInfo;
Lock();
HRESULT hr = E_FAIL;
if (NULL != m_pMSPStream)
{
//
// nicely ask stream to process our event
//
LOG((MSP_TRACE, "CPTEventSink::FireEvent - passing event [%p] to the stream", pEventItem));
AsyncEventStruct *pAsyncEvent = new AsyncEventStruct;
if (NULL == pAsyncEvent)
{
LOG((MSP_ERROR,
"CPTEventSink::FireEvent - failed to allocate memory for AsyncEventStruct"));
hr = E_OUTOFMEMORY;
}
else
{
//
// stuff the structure with the addref'fed stream on which the
// event will be fired and the actual event to fire
//
ULONG ulRC = m_pMSPStream->AddRef();
if (1 == ulRC)
{
//
// this is a workaround for a timing window: the stream could
// be in its desctructor while we are doing the addref. this
// condition is very-vary rare, as the timing window is very
// narrow.
//
// the good thing is that stream destructor will not finish
// while we are here, because it will try to get event sink's
// critical section in its call to SetSinkStream() to set our
// stream pointer to NULL.
//
// so if we detect that the refcount after our addref is 1,
// that would mean that the stream is in (or is about to start
// executing its desctructor). in which case we should do
// nothing.
//
// cleanup and return a failure.
//
Unlock();
LOG((MSP_ERROR,
"CPTEventSink::FireEvent - stream is going away"));
delete pAsyncEvent;
pAsyncEvent = NULL;
FreeEventItem(pEventItem);
pEventItem = NULL;
return TAPI_E_INVALIDSTREAM;
}
pAsyncEvent->pMSPStream = m_pMSPStream;
pAsyncEvent->pEventItem = pEventItem;
//
// now use thread pool api to schedule the event for future async
// processing
//
BOOL bQueueSuccess = QueueUserWorkItem(
CPTEventSink::FireEventCallBack,
(void *)pAsyncEvent,
WT_EXECUTEDEFAULT);
if (!bQueueSuccess)
{
DWORD dwLastError = GetLastError();
LOG((MSP_ERROR,
"CPTEventSink::FireEvent - QueueUserWorkItem failed. LastError = %ld", dwLastError));
//
// undo the addref we did on the stream object. the event will
// be freed later
//
m_pMSPStream->Release();
//
// the event was not enqueued. delete now.
//
delete pAsyncEvent;
pAsyncEvent = NULL;
//
// map the code and bail out
//
hr = HRESULT_FROM_WIN32(dwLastError);
}
else
{
//
// log the event we have submitted, so we can match submission
// with processing from the log
//
LOG((MSP_TRACE,
"CPTEventSink::FireEvent - submitted event [%p]", pAsyncEvent));
hr = S_OK;
} // async event structure submitted
} // async event structure allocated
} // msp stream exists
else
{
hr = TAPI_E_INVALIDSTREAM;
LOG((MSP_ERROR,
"CPTEventSink::FireEvent - stream pointer is NULL"));
}
Unlock();
//
// if we don't have a stream, or if the stream refused to process the
// event, cleanup and return an error
//
if (FAILED(hr))
{
LOG((MSP_ERROR, "CPTEventSink::FireEvent - call to HandleStreamEvent failed. hr = 0x%08x", hr));
FreeEventItem(pEventItem);
return hr;
}
LOG((MSP_TRACE, "CPTEventSink::FireEvent - exit"));
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
//
// CPTEventSink::FireEventCallBack
//
// the callback function that is called by thread pool api to asyncronously to
// process events fired by the terminals.
//
// the argument should point to the structure that contains the pointer to the
// stream on which to fire the event and the pointer to the event to fire.
//
// the dll is guaranteed to not go away, since the structure passed in holds a
// reference to the stream object on which to process the event
//
// static
DWORD WINAPI CPTEventSink::FireEventCallBack(LPVOID lpParameter)
{
LOG((MSP_TRACE, "CPTEventSink::FireEventCallBack - enter. Argument [%p]",
lpParameter));
AsyncEventStruct *pEventStruct = (AsyncEventStruct *)lpParameter;
//
// make sure the structure is valid
//
if (IsBadReadPtr(pEventStruct, sizeof(AsyncEventStruct)))
{
//
// complain and exit. should not happen, unless there is a problem in
// thread pool api or memory corruption
//
LOG((MSP_ERROR,
"CPTEventSink::FireEventCallBack - Argument does not point to a valid AsyncEventStruct"));
return FALSE;
}
BOOL bBadDataPassedIn = FALSE;
//
// the structure contains an addref'fed stream pointer. extract it and
// make sure it is still valid
//
CMSPStream *pMSPStream = pEventStruct->pMSPStream;
if (IsBadReadPtr(pMSPStream, sizeof(CMSPStream)))
{
//
// should not happen, unless there is a problem in thread pool api or
// memory corruption, or someone is over-releasing the stream object
//
LOG((MSP_ERROR,
"CPTEventSink::FireEventCallBack - stream pointer is bad"));
pMSPStream = NULL;
bBadDataPassedIn = TRUE;
}
//
// the structure contains the event that we are tryint to fire.
// make sure the event we are about to fire is good.
//
MSPEVENTITEM *pEventItem = pEventStruct->pEventItem;
if (IsBadReadPtr(pEventItem, sizeof(MSPEVENTITEM)))
{
//
// should not happen, unless there is a problem in thread pool api or
// memory corruption, or we didn't check success of allocation when we
// created the event (which we did!)
//
LOG((MSP_ERROR,
"CPTEventSink::FireEventCallBack - event is bad"));
pEventItem = NULL;
bBadDataPassedIn = TRUE;
}
//
// bad stream or event structure?
//
if (bBadDataPassedIn)
{
//
// release the event if it was good.
//
if ( NULL != pEventItem)
{
FreeEventItem(pEventItem);
pEventItem = NULL;
}
//
// release the stream if it was good.
//
if (NULL != pMSPStream)
{
pMSPStream->Release();
pMSPStream = NULL;
}
//
// no need to keep the event structure itself, delete it
//
delete pEventStruct;
pEventStruct = NULL;
return FALSE;
}
//
// we have both the stream and the event, fire the event on the stream
//
HRESULT hr = pMSPStream->HandleSinkEvent(pEventItem);
//
// if HandleSinkEvent succeeded, pEventItem will be released by whoever
// will handle the event, otherwise we need to release eventitem here
//
if (FAILED(hr))
{
LOG((MSP_ERROR,
"CPTEventSink::FireEventCallBack - HandleSinkEvent not called or failed. hr = %lx",
hr));
FreeEventItem(pEventItem);
pEventItem = NULL;
}
//
// release the stream pointer that is a part of the structure --
// we don't want any reference leaks.
//
//
// note that the dll may go away at this point (if we are holding the last
// reference to the last object from the dll)
//
pMSPStream->Release();
pMSPStream = NULL;
//
// at this point we release the stream pointer and either submitted the
// event or freed it. we no longer need the event structure.
//
delete pEventStruct;
pEventStruct = NULL;
LOG((MSP_(hr), "CPTEventSink::FireEventCallBack - exit. hr = %lx", hr));
return SUCCEEDED(hr);
}
/*++
SetSinkStream
Parameters:
CMSPStream *pStream
the stream that will be processing our events, or NULL when no stream is
available to process our events
Returns:
S_OK -
Description:
this method is called by the stream that is going to process our events
when the stream is going away and is no longer available to process our
messages, it will call SetSinkStream with NULL.
--*/
HRESULT CPTEventSink::SetSinkStream( CMSPStream *pStream )
{
LOG((MSP_TRACE, "CPTEventSink::SetSinkStream - enter"));
Lock();
LOG((MSP_TRACE,
"CPTEventSink::SetSinkStream - replacing sink stream [%p] with [%p]",
m_pMSPStream, pStream));
//
// we don't keep a reference to the stream -- the stream keeps a reference
// to us. when the stream goes away, it will let us know.
//
m_pMSPStream = pStream;
Unlock();
LOG((MSP_TRACE, "CPTEventSink::SetSinkStream - exit"));
return S_OK;
}