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.
970 lines
24 KiB
970 lines
24 KiB
// Connection.cpp
|
|
|
|
#include "precomp.h"
|
|
#include "Connection.h"
|
|
#include "Event.h"
|
|
|
|
#include "Transport.h"
|
|
#include "NamedPipe.h"
|
|
|
|
#include "NCDefs.h"
|
|
#include "dutils.h"
|
|
|
|
#define DEF_BATCH_BUFFER_SIZE 131072
|
|
#define DEF_SEND_LATENCY 1000
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSink
|
|
|
|
CSink::CSink()
|
|
{
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
CSink::~CSink()
|
|
{
|
|
// Make sure none of the still alive events are referencing us.
|
|
{
|
|
CInCritSec cs(&m_cs);
|
|
|
|
for (CEventListIterator event = m_listEvents.begin();
|
|
event != m_listEvents.end(); event++)
|
|
{
|
|
CEvent *pEvent = *event;
|
|
|
|
pEvent->m_pSink = NULL;
|
|
}
|
|
}
|
|
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
BOOL CSink::Init(
|
|
CConnection *pConnection,
|
|
DWORD dwSinkID,
|
|
LPVOID pUserData,
|
|
LPEVENT_SOURCE_CALLBACK pCallback)
|
|
{
|
|
m_pConnection = pConnection;
|
|
m_dwSinkID = dwSinkID;
|
|
m_pUserData = pUserData;
|
|
m_pCallback = pCallback;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CSink::AddEvent(CEvent *pEvent)
|
|
{
|
|
CInCritSec cs(&m_cs);
|
|
|
|
m_listEvents.push_back(pEvent);
|
|
}
|
|
|
|
void CSink::RemoveEvent(CEvent *pEvent)
|
|
{
|
|
CInCritSec cs(&m_cs);
|
|
|
|
m_listEvents.remove(pEvent);
|
|
}
|
|
|
|
void CSink::ResetEventBufferLayoutSent()
|
|
{
|
|
CInCritSec cs(&m_cs);
|
|
|
|
for (CEventListIterator i = m_listEvents.begin();
|
|
i != m_listEvents.end(); i++)
|
|
{
|
|
CEvent *pEvent = *i;
|
|
|
|
pEvent->ResetLayoutSent();
|
|
pEvent->SetEnabled(FALSE);
|
|
}
|
|
}
|
|
|
|
void CSink::EnableAndDisableEvents()
|
|
{
|
|
// For each event, set its enabled value.
|
|
for (CEventListIterator i = m_listEvents.begin();
|
|
i != m_listEvents.end();
|
|
i++)
|
|
{
|
|
CEvent *pEvent = *i;
|
|
|
|
EnableEventUsingList(pEvent);
|
|
}
|
|
}
|
|
|
|
void CSink::AddToEnabledEventList(CBuffer *pBuffer)
|
|
{
|
|
DWORD dwLen;
|
|
DWORD dwNumEnabled = pBuffer->ReadDWORD();
|
|
|
|
// Add the event names to our enabled map.
|
|
for( DWORD i=0; i < dwNumEnabled; i++ )
|
|
{
|
|
LPCWSTR szCurrentEvent = pBuffer->ReadAlignedLenString(&dwLen);
|
|
m_mapEnabledEvents[szCurrentEvent] = 1;
|
|
TRACE("Enabled: %S", szCurrentEvent);
|
|
}
|
|
|
|
EnableAndDisableEvents();
|
|
}
|
|
|
|
void CSink::RemoveFromEnabledEventList(CBuffer *pBuffer)
|
|
{
|
|
DWORD dwLen;
|
|
DWORD dwNumDisabled = pBuffer->ReadDWORD();
|
|
|
|
// Add the event names to our enabled map.
|
|
for( DWORD i=0; i < dwNumDisabled; i++ )
|
|
{
|
|
LPCWSTR szCurrentEvent = pBuffer->ReadAlignedLenString(&dwLen);
|
|
m_mapEnabledEvents.erase(szCurrentEvent);
|
|
TRACE("Disabled: %S", szCurrentEvent);
|
|
}
|
|
|
|
EnableAndDisableEvents();
|
|
}
|
|
|
|
BOOL CSink::IsEventClassEnabled(LPCWSTR szEventClass)
|
|
{
|
|
BOOL bEnable;
|
|
WCHAR szTempClassName[256];
|
|
|
|
if (szEventClass)
|
|
{
|
|
StringCchCopyW(szTempClassName, 256, szEventClass);
|
|
_wcsupr(szTempClassName);
|
|
|
|
bEnable =
|
|
m_mapEnabledEvents.find(szTempClassName) != m_mapEnabledEvents.end();
|
|
}
|
|
else
|
|
bEnable = FALSE;
|
|
|
|
return bEnable;
|
|
}
|
|
|
|
void CSink::EnableEventUsingList(CEvent *pEvent)
|
|
{
|
|
BOOL bEnable;
|
|
bEnable = IsEventClassEnabled(pEvent->GetClassName());
|
|
pEvent->SetEnabled(bEnable);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CConnection
|
|
|
|
CConnection::CConnection(BOOL bBatchSend, DWORD dwBatchBufferSize,
|
|
DWORD dwMaxSendLatency) :
|
|
m_bDone(FALSE),
|
|
m_bUseBatchSend(bBatchSend),
|
|
m_dwSendLatency(dwMaxSendLatency ? dwMaxSendLatency : DEF_SEND_LATENCY),
|
|
m_heventBufferNotFull(NULL),
|
|
m_heventBufferFull(NULL),
|
|
m_heventEventsPending(NULL),
|
|
m_heventDone(NULL),
|
|
m_hthreadSend(NULL),
|
|
m_pTransport(NULL),
|
|
m_hthreadWMIInit(NULL),
|
|
m_heventWMIInit(NULL),
|
|
m_bWMIResync(TRUE),
|
|
m_dwNextSinkID(1)
|
|
{
|
|
if (bBatchSend)
|
|
{
|
|
if (dwBatchBufferSize == 0)
|
|
dwBatchBufferSize = DEF_BATCH_BUFFER_SIZE;
|
|
|
|
m_bufferSend.Reset(dwBatchBufferSize);
|
|
}
|
|
else
|
|
m_bufferSend.Reset(DEF_BATCH_BUFFER_SIZE);
|
|
}
|
|
|
|
CConnection::~CConnection()
|
|
{
|
|
Deinit();
|
|
}
|
|
|
|
void CConnection::GetBaseName(LPCWSTR szName, LPWSTR szBase)
|
|
{
|
|
StringCchCopyW(szBase, MAX_PATH*2, szName);
|
|
_wcsupr(szBase);
|
|
|
|
// Get rid of the '\' chars since we can't use it in OS object names.
|
|
for (WCHAR *szCurrent = szBase; *szCurrent; szCurrent++)
|
|
{
|
|
if (*szCurrent == '\\')
|
|
*szCurrent = '/';
|
|
}
|
|
}
|
|
|
|
BOOL CConnection::Init(
|
|
LPCWSTR szNamespace,
|
|
LPCWSTR szProviderName,
|
|
LPVOID pUserData,
|
|
LPEVENT_SOURCE_CALLBACK pCallback)
|
|
{
|
|
if (!m_sinkMain.Init(this, 0, pUserData, pCallback))
|
|
return FALSE;
|
|
|
|
GetBaseName(szNamespace, m_szBaseNamespace);
|
|
GetBaseName(szProviderName, m_szBaseProviderName);
|
|
|
|
try
|
|
{
|
|
InitializeCriticalSection(&m_cs);
|
|
|
|
// The rest of these are for batch sending.
|
|
InitializeCriticalSection(&m_csBuffer);
|
|
}
|
|
catch(...)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_heventDone =
|
|
CreateEvent(
|
|
NULL,
|
|
TRUE,
|
|
FALSE,
|
|
NULL);
|
|
if(m_heventDone == NULL)
|
|
return FALSE;
|
|
|
|
m_heventBufferNotFull =
|
|
CreateEvent(
|
|
NULL,
|
|
TRUE,
|
|
TRUE,
|
|
NULL);
|
|
if(m_heventBufferNotFull == NULL)
|
|
return FALSE;
|
|
|
|
m_heventBufferFull =
|
|
CreateEvent(
|
|
NULL,
|
|
TRUE,
|
|
FALSE,
|
|
NULL);
|
|
if(m_heventBufferFull == NULL)
|
|
return FALSE;
|
|
|
|
m_heventEventsPending =
|
|
CreateEvent(
|
|
NULL,
|
|
TRUE,
|
|
FALSE,
|
|
NULL);
|
|
if(m_heventEventsPending == NULL)
|
|
return FALSE;
|
|
|
|
if(!StartWaitWMIInitThread())
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CConnection::StartWaitWMIInitThread()
|
|
{
|
|
TRACE("Entered StartWaitWMIInitThread.");
|
|
|
|
m_heventWMIInit =
|
|
OpenEventW(
|
|
SYNCHRONIZE,
|
|
FALSE,
|
|
WMI_INIT_EVENT_NAME);
|
|
|
|
if (!m_heventWMIInit)
|
|
{
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
DWORD dwSize;
|
|
|
|
if ( !ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
|
ESS_EVENT_SDDL, // security descriptor string
|
|
SDDL_REVISION_1, // revision level
|
|
&pSD, // SD
|
|
&dwSize) )
|
|
return FALSE;
|
|
|
|
SECURITY_ATTRIBUTES sa = { sizeof(sa), pSD, FALSE };
|
|
|
|
m_heventWMIInit =
|
|
CreateEventW(
|
|
&sa,
|
|
TRUE,
|
|
FALSE,
|
|
WMI_INIT_EVENT_NAME);
|
|
|
|
if (pSD)
|
|
LocalFree((HLOCAL) pSD);
|
|
|
|
if (!m_heventWMIInit)
|
|
{
|
|
TRACE("Couldn't create ESS ready event: %d", GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (WaitForSingleObject(m_heventWMIInit, 0) == 0)
|
|
{
|
|
TRACE("ESS event was already set, so going to init transport...");
|
|
|
|
if(!InitTransport())
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
DWORD dwID;
|
|
|
|
TRACE("Creating WaitWMIInitThreadProc thread.");
|
|
|
|
m_hthreadWMIInit =
|
|
CreateThread(
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) WaitWMIInitThreadProc,
|
|
this,
|
|
0,
|
|
&dwID);
|
|
|
|
if(m_hthreadWMIInit == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
|
|
|
|
BOOL CConnection::InitTransport()
|
|
{
|
|
if ( m_pTransport != NULL )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
TRACE("Entered InitTransport.");
|
|
|
|
try
|
|
{
|
|
m_pTransport = new CNamedPipeClient;
|
|
}
|
|
catch(...)
|
|
{
|
|
// this page intentionally left blank - m_pTransport will still be NULL.
|
|
}
|
|
|
|
BOOL bRet;
|
|
if (m_pTransport)
|
|
{
|
|
m_pTransport->SetConnection(this);
|
|
m_pTransport->Init(m_szBaseNamespace, m_szBaseProviderName);
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
bRet = FALSE;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
DWORD CConnection::WaitWMIInitThreadProc(CConnection *pThis)
|
|
{
|
|
try
|
|
{
|
|
TRACE("Entered WaitWMIInitThreadProc");
|
|
|
|
HANDLE hWait[2] = { pThis->m_heventDone, pThis->m_heventWMIInit };
|
|
DWORD dwWait;
|
|
|
|
dwWait = WaitForMultipleObjects(2, hWait, FALSE, INFINITE);
|
|
|
|
if (dwWait == 1)
|
|
{
|
|
TRACE("ESS event fired, going to init transport");
|
|
|
|
// If WMI is now ready, startup our transport.
|
|
pThis->InitTransport();
|
|
pThis->m_bWMIResync = FALSE;
|
|
}
|
|
else
|
|
{
|
|
TRACE("dwWait in WaitWMIInitThreadProc = %d", dwWait);
|
|
}
|
|
}
|
|
catch( CX_MemoryException )
|
|
{
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
BOOL CConnection::ResyncWithWMI()
|
|
{
|
|
m_bWMIResync = TRUE;
|
|
|
|
StopThreads();
|
|
|
|
ResetEvent( m_heventDone) ;
|
|
|
|
m_hthreadWMIInit = CreateThread(
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)WaitWMIInitThreadProc,
|
|
this,
|
|
0,
|
|
NULL );
|
|
|
|
return m_hthreadWMIInit != NULL ? TRUE : FALSE;
|
|
}
|
|
|
|
void CConnection::StopThreads()
|
|
{
|
|
if (m_hthreadSend)
|
|
{
|
|
BOOL bDoneSending;
|
|
|
|
do
|
|
{
|
|
Lock();
|
|
|
|
bDoneSending = m_bufferSend.GetUsedSize() == 0;
|
|
|
|
// If there's still stuff left to send, make sure it
|
|
// gets sent.
|
|
if (bDoneSending)
|
|
{
|
|
SetEvent(m_heventDone);
|
|
|
|
Unlock();
|
|
|
|
WaitForSingleObject(m_hthreadSend, INFINITE);
|
|
|
|
CloseHandle(m_hthreadSend);
|
|
m_hthreadSend = NULL;
|
|
}
|
|
else
|
|
{
|
|
SetEvent(m_heventBufferFull);
|
|
|
|
Unlock();
|
|
|
|
// Sleep a little to give the send thread a chance to do its
|
|
// thing.
|
|
Sleep(1);
|
|
}
|
|
|
|
} while (!bDoneSending);
|
|
}
|
|
|
|
if ( m_hthreadWMIInit != NULL )
|
|
{
|
|
SetEvent(m_heventDone);
|
|
WaitForSingleObject(m_hthreadWMIInit, INFINITE);
|
|
CloseHandle(m_hthreadWMIInit);
|
|
}
|
|
|
|
m_hthreadWMIInit = NULL;
|
|
m_hthreadSend = NULL;
|
|
}
|
|
|
|
void CConnection::Deinit()
|
|
{
|
|
m_bDone = TRUE;
|
|
|
|
StopThreads();
|
|
|
|
if (m_heventWMIInit)
|
|
CloseHandle(m_heventWMIInit);
|
|
|
|
CloseHandle(m_heventDone);
|
|
CloseHandle(m_heventBufferNotFull);
|
|
CloseHandle(m_heventBufferFull);
|
|
CloseHandle(m_heventEventsPending);
|
|
|
|
// Give the transport a chance to clean up.
|
|
if (m_pTransport)
|
|
m_pTransport->Deinit();
|
|
|
|
// Make sure no sinks are referencing us anymore.
|
|
for (CSinkMapIterator i = m_mapSink.begin();
|
|
i != m_mapSink.end();
|
|
i++)
|
|
{
|
|
CSink *pSink = (*i).second;
|
|
|
|
pSink->m_pConnection = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection(&m_csBuffer);
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
|
|
BOOL CConnection::StartSendThread()
|
|
{
|
|
DWORD dwID;
|
|
|
|
m_hthreadSend =
|
|
CreateThread(
|
|
NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE) SendThreadProc,
|
|
this,
|
|
0,
|
|
&dwID);
|
|
if(m_hthreadSend == NULL)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CConnection::SendMessagesOverTransport( PBYTE pData, DWORD cData )
|
|
{
|
|
CBuffer buffer( pData, cData );
|
|
|
|
//
|
|
// walk the messages until we hit our max message size for
|
|
// the transport. Keep doing this until no more messages.
|
|
//
|
|
|
|
PBYTE pTransportMsg = buffer.m_pBuffer;
|
|
DWORD cTransportMsg = 0;
|
|
|
|
while (!buffer.IsEOF())
|
|
{
|
|
_ASSERT( pTransportMsg != NULL );
|
|
_ASSERT( cTransportMsg < MAX_MSG_SIZE );
|
|
|
|
//
|
|
// process one message from the buffer
|
|
//
|
|
|
|
DWORD dwMsg = buffer.ReadDWORD();
|
|
|
|
if ( dwMsg != NC_SRVMSG_EVENT_LAYOUT &&
|
|
dwMsg != NC_SRVMSG_PREPPED_EVENT )
|
|
{
|
|
_ASSERT( FALSE );
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD cMsg = buffer.ReadDWORD();
|
|
|
|
if ( cMsg <= MAX_MSG_SIZE )
|
|
{
|
|
if ( cTransportMsg + cMsg >= MAX_MSG_SIZE )
|
|
{
|
|
//
|
|
// send what we have so far.
|
|
//
|
|
if ( !SendDataOverTransports( pTransportMsg, cTransportMsg ) )
|
|
return FALSE;
|
|
|
|
//
|
|
// set up new transport msg.
|
|
//
|
|
pTransportMsg = buffer.m_pCurrent - 8;
|
|
cTransportMsg = cMsg;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// add to transport msg
|
|
//
|
|
cTransportMsg += cMsg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// this means a mesage was too big to send. skip it.
|
|
//
|
|
}
|
|
|
|
buffer.m_pCurrent += cMsg - 8;
|
|
}
|
|
|
|
if ( cTransportMsg > 0 )
|
|
{
|
|
return SendDataOverTransports( pTransportMsg, cTransportMsg );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD WINAPI CConnection::SendThreadProc(CConnection *pThis)
|
|
{
|
|
try
|
|
{
|
|
HANDLE hWait[2] = { pThis->m_heventDone, pThis->m_heventEventsPending },
|
|
hwaitSendLatency[2] = { pThis->m_heventDone, pThis->m_heventBufferFull },
|
|
heventBufferNotFull = pThis->m_heventBufferNotFull;
|
|
DWORD dwSendLatency = pThis->m_dwSendLatency;
|
|
LPBYTE pData = pThis->m_bufferSend.m_pBuffer;
|
|
CBuffer *pBuffer = &pThis->m_bufferSend;
|
|
CRITICAL_SECTION *pCS = &pThis->m_csBuffer;
|
|
|
|
while (WaitForMultipleObjects(2, hWait, FALSE, INFINITE) != 0)
|
|
{
|
|
// If we have a send latency, wait for that time or until the send
|
|
// buffer is full. If the done event fires, get out.
|
|
if (dwSendLatency)
|
|
{
|
|
if (WaitForMultipleObjects(2, hwaitSendLatency, FALSE,
|
|
dwSendLatency) == 0)
|
|
break;
|
|
|
|
// Reset m_heventBufferFull.
|
|
ResetEvent(hwaitSendLatency[1]);
|
|
}
|
|
|
|
EnterCriticalSection(pCS);
|
|
|
|
pThis->SendMessagesOverTransport(
|
|
pData,
|
|
pBuffer->GetUsedSize());
|
|
|
|
pBuffer->Reset();
|
|
|
|
SetEvent(heventBufferNotFull);
|
|
|
|
// Reset m_heventEventsPending
|
|
ResetEvent(hWait[1]);
|
|
|
|
LeaveCriticalSection(pCS);
|
|
}
|
|
}
|
|
catch( CX_MemoryException )
|
|
{
|
|
return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//#define NO_SEND
|
|
|
|
BOOL CConnection::IndicateProvEnabled()
|
|
{
|
|
// Get out if we're already done.
|
|
if (m_bDone)
|
|
return TRUE;
|
|
|
|
CInCritSec cs(&m_cs);
|
|
|
|
// Tell the callback that the provider is now activated.
|
|
if (m_sinkMain.m_pCallback)
|
|
m_sinkMain.m_pCallback(
|
|
(HANDLE) this, ESM_START_SENDING_EVENTS, m_sinkMain.m_pUserData, NULL);
|
|
|
|
// Tell the server about us.
|
|
if(!SendInitInfo())
|
|
return FALSE;
|
|
|
|
|
|
// See if we've buffered any events while we were waiting for WMI to come
|
|
// up. If we did, send them on their way.
|
|
DWORD dwSize;
|
|
|
|
EnterCriticalSection(&m_csBuffer);
|
|
|
|
dwSize = m_bufferSend.GetUsedSize();
|
|
|
|
if (dwSize)
|
|
{
|
|
m_pTransport->SendData(m_bufferSend.m_pBuffer, dwSize);
|
|
m_bufferSend.Reset();
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csBuffer);
|
|
|
|
|
|
if (m_bUseBatchSend && m_hthreadSend == NULL)
|
|
return StartSendThread();
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
void CConnection::IndicateProvDisabled()
|
|
{
|
|
// Get out if we're already done.
|
|
if (m_bDone)
|
|
return;
|
|
|
|
CInCritSec cs(&m_cs);
|
|
|
|
for (CSinkMapIterator i = m_mapSink.begin();
|
|
i != m_mapSink.end();
|
|
i++)
|
|
{
|
|
CSink *pSink = (*i).second;
|
|
|
|
pSink->ResetEventBufferLayoutSent();
|
|
|
|
if (pSink->m_pCallback)
|
|
{
|
|
pSink->m_pCallback(
|
|
(HANDLE) pSink,
|
|
ESM_STOP_SENDING_EVENTS,
|
|
pSink->m_pUserData,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
// Tell the callback that the provider is now deactivated.
|
|
m_sinkMain.ResetEventBufferLayoutSent();
|
|
|
|
if (m_sinkMain.m_pCallback)
|
|
{
|
|
m_sinkMain.m_pCallback(
|
|
(HANDLE) &m_sinkMain,
|
|
ESM_STOP_SENDING_EVENTS,
|
|
m_sinkMain.m_pUserData,
|
|
NULL);
|
|
}
|
|
|
|
ResyncWithWMI();
|
|
}
|
|
|
|
BOOL CConnection::SendData(LPBYTE pBuffer, DWORD dwSize)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
// Make sure this event isn't too big.
|
|
if (dwSize > m_bufferSend.m_dwSize)
|
|
return FALSE;
|
|
|
|
if (m_bUseBatchSend || WaitingForWMIInit())
|
|
{
|
|
BOOL bContinue;
|
|
|
|
do
|
|
{
|
|
EnterCriticalSection(&m_csBuffer);
|
|
|
|
bContinue = FALSE;
|
|
|
|
// See if we have enough room to add our event.
|
|
if (dwSize <= m_bufferSend.GetUnusedSize())
|
|
{
|
|
BOOL bWasEmpty = m_bufferSend.GetUsedSize() == 0;
|
|
|
|
m_bufferSend.Write(pBuffer, dwSize);
|
|
|
|
if (bWasEmpty)
|
|
SetEvent(m_heventEventsPending);
|
|
|
|
LeaveCriticalSection(&m_csBuffer);
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// If we're not waiting for WMI to initialize, we just need to
|
|
// wait for the send thread to finish sending what's in our
|
|
// buffer.
|
|
if (!WaitingForWMIInit())
|
|
{
|
|
// Wake up the send latency thread if necessary.
|
|
if (m_dwSendLatency)
|
|
SetEvent(m_heventBufferFull);
|
|
|
|
// So we'll block until the send thread sets the event.
|
|
ResetEvent(m_heventBufferNotFull);
|
|
|
|
LeaveCriticalSection(&m_csBuffer);
|
|
|
|
WaitForSingleObject(m_heventBufferNotFull, INFINITE);
|
|
bContinue = TRUE;
|
|
}
|
|
// If we're still waiting for WMI to initialize but our buffer
|
|
// is full, drop it.
|
|
else
|
|
{
|
|
LeaveCriticalSection(&m_csBuffer);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
} // else from if (dwSize <= m_bufferSend.GetUnusedSize())
|
|
|
|
} while( bContinue );
|
|
}
|
|
else
|
|
{
|
|
bRet = SendDataOverTransports(pBuffer, dwSize);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL CConnection::SendDataOverTransports(LPBYTE pBuffer, DWORD dwSize)
|
|
{
|
|
if (m_pTransport->IsReady())
|
|
m_pTransport->SendData(pBuffer, dwSize);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CConnection::SendInitInfo()
|
|
{
|
|
BYTE cBuffer[sizeof(DWORD) * 2];
|
|
CBuffer buffer(cBuffer, sizeof(cBuffer), CBuffer::ALIGN_DWORD);
|
|
BOOL bRet;
|
|
|
|
buffer.Write((DWORD) NC_SRVMSG_CLIENT_INFO);
|
|
buffer.Write((DWORD) (m_bUseBatchSend ? m_bufferSend.m_dwSize : MAX_MSG_SIZE));
|
|
|
|
if(!m_pTransport->InitCallback())
|
|
return FALSE;
|
|
|
|
return m_pTransport->SendData(cBuffer, buffer.GetUsedSize());
|
|
}
|
|
|
|
HRESULT CConnection::ProcessMessage(LPBYTE pData, DWORD dwSize)
|
|
{
|
|
// Get out if we're already done.
|
|
if (m_bDone)
|
|
return S_OK;
|
|
|
|
if ( dwSize <= sizeof(DWORD)*2+sizeof(DWORD_PTR) )
|
|
return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
|
|
DWORD *pdwMsg = (DWORD*) pData;
|
|
DWORD *pdwSinkID = (DWORD*) (pdwMsg + 1);
|
|
|
|
DWORD_PTR dwMsgCookie;
|
|
memcpy( &dwMsgCookie, pdwMsg+2, sizeof(dwMsgCookie) );
|
|
|
|
LPBYTE pMsgBits = (LPBYTE)(pData+sizeof(DWORD)*2+sizeof(DWORD_PTR));
|
|
CBuffer buffer(pMsgBits, dwSize - sizeof(DWORD)*2 - sizeof(DWORD_PTR));
|
|
HRESULT hr = S_OK;
|
|
DWORD dwLen;
|
|
|
|
switch(*pdwMsg)
|
|
{
|
|
case NC_CLIMSG_ACCESS_CHECK_REQ:
|
|
{
|
|
ES_ACCESS_CHECK check;
|
|
|
|
check.szQueryLanguage = buffer.ReadAlignedLenString(&dwLen);
|
|
check.szQuery = buffer.ReadAlignedLenString(&dwLen);
|
|
check.dwSidLen = buffer.ReadDWORD();
|
|
|
|
if ( check.dwSidLen <= buffer.GetUnusedSize() )
|
|
{
|
|
if (check.dwSidLen != 0)
|
|
check.pSid = buffer.m_pCurrent;
|
|
else
|
|
check.pSid = NULL;
|
|
|
|
if (m_sinkMain.m_pCallback)
|
|
{
|
|
hr =
|
|
m_sinkMain.m_pCallback(
|
|
(HANDLE) &m_sinkMain,
|
|
ESM_ACCESS_CHECK,
|
|
m_sinkMain.m_pUserData,
|
|
&check);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
NC_SRVMSG_REPLY reply = { NC_SRVMSG_ACCESS_CHECK_REPLY,
|
|
hr, dwMsgCookie };
|
|
|
|
m_pTransport->SendMsgReply(&reply);
|
|
break;
|
|
}
|
|
|
|
case NC_CLIMSG_NEW_QUERY_REQ:
|
|
{
|
|
ES_NEW_QUERY query;
|
|
CSink *pSink = GetSink(*pdwSinkID);
|
|
|
|
if (pSink)
|
|
{
|
|
query.dwID = buffer.ReadDWORD();
|
|
query.szQueryLanguage = buffer.ReadAlignedLenString(&dwLen);
|
|
query.szQuery = buffer.ReadAlignedLenString(&dwLen);
|
|
|
|
// This is the list of event class names that are now
|
|
// enabled thanks to this query.
|
|
pSink->AddToEnabledEventList(&buffer);
|
|
|
|
if (pSink->m_pCallback)
|
|
{
|
|
hr =
|
|
pSink->m_pCallback(
|
|
(HANDLE) pSink, ESM_NEW_QUERY, pSink->m_pUserData, &query);
|
|
}
|
|
}
|
|
else
|
|
TRACE("Sink %d not found.", *pdwSinkID);
|
|
|
|
m_pTransport->SendMsgReply(NULL);
|
|
|
|
break;
|
|
}
|
|
|
|
case NC_CLIMSG_CANCEL_QUERY_REQ:
|
|
{
|
|
ES_CANCEL_QUERY query;
|
|
CSink *pSink = GetSink(*pdwSinkID);
|
|
|
|
if (pSink)
|
|
{
|
|
query.dwID = buffer.ReadDWORD();
|
|
|
|
// This is the list of event class names that are now
|
|
// disabled thanks to this query.
|
|
pSink->RemoveFromEnabledEventList(&buffer);
|
|
|
|
if (pSink->m_pCallback)
|
|
{
|
|
hr =
|
|
pSink->m_pCallback(
|
|
(HANDLE) pSink, ESM_CANCEL_QUERY, pSink->m_pUserData,
|
|
&query);
|
|
|
|
m_pTransport->SendMsgReply(NULL);
|
|
|
|
break;
|
|
}
|
|
else
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
TRACE("Sink %d not found.", *pdwSinkID);
|
|
|
|
break;
|
|
}
|
|
|
|
case NC_CLIMSG_PROVIDER_UNLOADING:
|
|
TRACE("Got the NC_CLIMSG_PROVIDER_UNLOADING message.");
|
|
|
|
// Give our named pipe client a chance to go see if it
|
|
// should deactivate itself (if the server doesn't need
|
|
// us anymore).
|
|
m_pTransport->SignalProviderDisabled();
|
|
|
|
hr = S_OK;
|
|
|
|
break;
|
|
|
|
default:
|
|
TRACE("Bad message from server!");
|
|
break;
|
|
} // switch(*(DWORD*)cBuffer)
|
|
|
|
return hr;
|
|
}
|
|
|
|
CSink *CConnection::GetSink(DWORD dwID)
|
|
{
|
|
return &m_sinkMain;
|
|
}
|