|
|
// Connection.cpp: implementation of the CConnection class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ConnMgr.h"
#include "Connection.h"
#include "Ping.h"
#include <process.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// CConnection
IMPLEMENT_DYNCREATE(CConnection,CObject)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CConnection::CConnection(BSTR bsMachineName, IWbemLocator* pIWbemLocator) { OutputDebugString(_T("CConnection::CConnection()\n")); ASSERT(pIWbemLocator);
Init(); m_bsMachineName = SysAllocString(bsMachineName); m_sNamespace.Format(_T("\\\\%s\\root\\cimv2\\MicrosoftHealthmonitor"),bsMachineName); m_pIWbemLocator = pIWbemLocator; m_pIWbemLocator->AddRef();
StartMonitor(); }
CConnection::CConnection() { OutputDebugString(_T("CConnection::CConnection()\n"));
Init(); }
CConnection::~CConnection() { OutputDebugString(_T("CConnection::~CConnection()\n")); // stop monitoring
StopMonitor();
RemoveAllEventEntries();
if( m_pIWbemServices ) { if (m_bAvailable) m_pIWbemServices->Release(); m_pIWbemServices = NULL; }
if (m_pIWbemLocator) { if (m_bAvailable) m_pIWbemLocator->Release(); m_pIWbemLocator = NULL; }
SysFreeString(m_bsMachineName);
CloseHandle(m_threadData.m_hDie); CloseHandle(m_threadData.m_hDead);
// zzz
CloseHandle(m_hReadyToConnect); }
//////////////////////////////////////////////////////////////////////
// Initialize CConnection data members.
//////////////////////////////////////////////////////////////////////
void CConnection::Init() { OutputDebugString(_T("CConnection::Init()\n")); m_bAvailable = false; m_bFirstConnect = true; m_pIWbemServices = NULL; m_pIWbemLocator = NULL; m_dwPollInterval = 10000; m_bsMachineName = NULL;
m_threadData.m_hDie = CreateEvent(NULL, TRUE, FALSE, NULL); m_threadData.m_hDead = CreateEvent(NULL, TRUE, FALSE, NULL); m_hrLastConnectResult = S_OK;
//zzz
m_hReadyToConnect = CreateEvent(NULL, TRUE, FALSE, NULL); }
//////////////////////////////////////////////////////////////////////
// Start/Stop Monitoring connection
//////////////////////////////////////////////////////////////////////
void CConnection::StartMonitor() { OutputDebugString(_T("CConnection::StartMonitor()\n"));
m_threadData.m_bkptr = this; m_hThread = (HANDLE)_beginthreadex( NULL, 0, MonitorConnection, &m_threadData, 0, &m_threadID ); if (!m_hThread) { OutputDebugString(_T("CConnection::StartMonitor() Error on _beginthreadex\n")); } }
void CConnection::StopMonitor() { OutputDebugString(_T("CConnection::StopMonitor()\n"));
// tell it to die now.
SetEvent(m_threadData.m_hDie);
// if connection is down just kill it.
if (!m_bAvailable) { TerminateThread(m_hThread, 0); return; }
// otherwise, give it a chance to die.
if (WAIT_TIMEOUT == WaitForSingleObject(m_threadData.m_hDead, m_dwPollInterval)) { OutputDebugString(_T("CConnection::StartMonitor() Timed out - Killing thread.\n")); TerminateThread(m_hThread, 0); } }
//////////////////////////////////////////////////////////////////////
// Thread Func: Establish initial connection and check status.
//////////////////////////////////////////////////////////////////////
unsigned int __stdcall CConnection::MonitorConnection(void *pv) { OutputDebugString(_T("CConnection::MonitorNode() New Thread!\n"));
struct threadData* pData = (struct threadData*)pv;
HRESULT hRes = pData->m_bkptr->Connect(); // Try to connect first.
if (FAILED(hRes)) pData->m_bkptr->NotifyConsole(hRes);
while (true) { if (WAIT_OBJECT_0 == WaitForSingleObject(pData->m_hDie, pData->m_bkptr->m_dwPollInterval) ) { SetEvent(pData->m_hDead); break; } // Monitor Managed Node
pData->m_bkptr->CheckConnection(); }
_endthreadex(0);
return 0; }
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Check connection status
//////////////////////////////////////////////////////////////////////
void CConnection::CheckConnection() { OutputDebugString(_T("CConnection::CheckNode()\n"));
if (m_bAvailable) // Connection is available
{ // Check to see it is still valid.
if (!PingMachine()) { // Connection went down!
OutputDebugString(_T("CConnection::CheckConnection()-Lost connection!\n")); m_hrLastConnectResult = WBEM_E_TRANSPORT_FAILURE; SetConnectionStatus(false); NotifyConsole(m_hrLastConnectResult); return; } // Now, check Wbem connection
m_hrLastConnectResult = m_pIWbemServices->GetObject(0L,0L,0L,0L,0L); if (FAILED(m_hrLastConnectResult)) { // Wbem connection is no longer valid!
OutputDebugString(_T("CConnection::CheckConnection()-Lost wbem connection!\n")); SetConnectionStatus(false); NotifyConsole(m_hrLastConnectResult); } } else { // Try to re-establish connection
Connect(); } }
//////////////////////////////////////////////////////////////////////
// Connection operations
//////////////////////////////////////////////////////////////////////
HRESULT CConnection::Connect() { OutputDebugString(_T("CConnection::Connect()\n"));
// zzz
WaitForSingleObject(m_hReadyToConnect, INFINITE);
m_hrLastConnectResult = WBEM_E_TRANSPORT_FAILURE;
// can it be reached?
if (!PingMachine()) return m_hrLastConnectResult;
// now, try to connect to namespace
m_hrLastConnectResult = ConnectToNamespace();
if (FAILED(m_hrLastConnectResult)) return m_hrLastConnectResult;
// is agent ready?
if (FAILED(m_hrLastConnectResult = IsAgentReady())) return m_hrLastConnectResult;
// is agent correct version ?
if( FAILED(m_hrLastConnectResult = IsAgentCorrectVersion()) ) return m_hrLastConnectResult;
UnRegisterAllEvents(); if (SUCCEEDED(m_hrLastConnectResult = RegisterAllEvents())) { SetConnectionStatus(true); NotifyConsole(m_hrLastConnectResult); }
return m_hrLastConnectResult; }
inline HRESULT CConnection::IsAgentReady() { // check to see if agent providers are ready to service external requests.
if (!m_pIWbemServices) return WBEM_E_TRANSPORT_FAILURE;
IEnumWbemClassObject* pEnumObj = NULL; // HMSystemStatus ready?
BSTR bsName = SysAllocString(L"Microsoft_HMSystemStatus"); HRESULT hRes = m_pIWbemServices->CreateInstanceEnum(bsName, WBEM_FLAG_SHALLOW, NULL, &pEnumObj); SysFreeString(bsName);
if (FAILED(hRes)) { CString sDebugString; sDebugString.Format(_T("IsAgentReady()-Agent is unavailable to deliver SystemStatus on %s. Operation failed with result=<%X>."), CString(m_bsMachineName), hRes); OutputDebugString(sDebugString); return hRes; }
pEnumObj->Release(); pEnumObj = NULL;
/*
// HMCatStatus ready?
SysReAllocString(&bsName, L"HMCatStatus"); hRes = m_pIWbemServices->CreateInstanceEnum(bsName, WBEM_FLAG_SHALLOW, NULL, &pEnumObj); SysFreeString(bsName);
if (FAILED(hRes)) return hRes;
pEnumObj->Release(); pEnumObj = NULL;
// HMMachStatus ready?
SysReAllocString(&bsName, L"HMMachStatus"); hRes = m_pIWbemServices->CreateInstanceEnum(bsName, WBEM_FLAG_SHALLOW, NULL, &pEnumObj); SysFreeString(bsName);
if (FAILED(hRes)) return hRes;
pEnumObj->Release(); pEnumObj = NULL; */
return S_OK; }
inline HRESULT CConnection::IsAgentCorrectVersion() { // check to see if agent is correct version to service external requests.
if (!m_pIWbemServices) return WBEM_E_TRANSPORT_FAILURE;
IEnumWbemClassObject* pEnumObj = NULL;
// HMVersion check
// enumerate for HMVersion
BSTR bsName = SysAllocString(L"Microsoft_HMVersion"); HRESULT hRes = m_pIWbemServices->CreateInstanceEnum(bsName, WBEM_FLAG_SHALLOW, NULL, &pEnumObj); SysFreeString(bsName);
if (FAILED(hRes)) { CString sDebugString; sDebugString.Format(_T("IsAgentCorrectVersion()-Unable to enumerate for Microsoft_HMVersion on system %s. Operation failed with result=<%X>."), CString(m_bsMachineName), hRes); OutputDebugString(sDebugString); return hRes; }
IWbemClassObject* pObject = NULL; ULONG uReturned = 0L;
hRes = pEnumObj->Next(WBEM_INFINITE,1,&pObject,&uReturned); if( FAILED(hRes) || uReturned == 0L ) { pEnumObj->Release(); pEnumObj = NULL; CString sDebugString; sDebugString.Format(_T("IsAgentCorrectVersion()-Unable to enumerate for Microsoft_HMVersion on system %s. Operation failed with result=<%X>.\n"), CString(m_bsMachineName), hRes); OutputDebugString(sDebugString); return hRes; }
VARIANT vPropValue; VariantInit(&vPropValue);
bsName = SysAllocString(L"MajorVersion");
hRes = pObject->Get(bsName, 0L, &vPropValue, NULL, NULL);
SysFreeString(bsName);
if( FAILED(hRes) ) { pObject->Release(); pEnumObj->Release(); pEnumObj = NULL; CString sDebugString; sDebugString.Format(_T("IsAgentCorrectVersion()-Unable to enumerate for Microsoft_HMVersion on system %s. Operation failed with result=<%X>.\n"), CString(m_bsMachineName), hRes); OutputDebugString(sDebugString); return hRes; }
CString sMajorVersion = V_BSTR(&vPropValue);
VariantClear(&vPropValue);
if( _ttoi(sMajorVersion) != SCHEMA_MAJOR_VERSION ) { pObject->Release(); pEnumObj->Release(); hRes = E_NOTIMPL; CString sDebugString; sDebugString.Format(_T("IsAgentCorrectVersion()-Incorrect Agent version number on system %s.\n"), CString(m_bsMachineName)); OutputDebugString(sDebugString); return hRes; }
VariantInit(&vPropValue);
bsName = SysAllocString(L"MinorVersion");
hRes = pObject->Get(bsName, 0L, &vPropValue, NULL, NULL);
SysFreeString(bsName);
if( FAILED(hRes) ) { pObject->Release(); pEnumObj->Release(); pEnumObj = NULL; CString sDebugString; sDebugString.Format(_T("IsAgentCorrectVersion()-Incorrect Agent version number on system %s.\n"), CString(m_bsMachineName)); OutputDebugString(sDebugString); return hRes; }
CString sMinorVersion = V_BSTR(&vPropValue);
VariantClear(&vPropValue);
if( _ttoi(sMinorVersion) != SCHEMA_MINOR_VERSION ) { pObject->Release(); pEnumObj->Release(); hRes = E_NOTIMPL; CString sDebugString; sDebugString.Format(_T("IsAgentCorrectVersion()-Incorrect Agent version number on system %s.\n"), CString(m_bsMachineName)); OutputDebugString(sDebugString); return hRes; }
pObject->Release(); pEnumObj->Release(); pEnumObj = NULL;
return hRes; }
inline void CConnection::SetConnectionStatus(BOOL bFlag) { OutputDebugString(_T("CConnection::SetConnectionStatus()\n")); if (m_bAvailable != bFlag) { m_bAvailable = bFlag; } else OutputDebugString(_T("CConnection::SetConnectionStatus()-No change in Connection Status!\n")); }
inline BOOL CConnection::PingMachine() { OutputDebugString(_T("CConnection::Ping()\n")); CPing Pong; unsigned long ulIP = Pong.ResolveName(m_bsMachineName); if (!Pong.Ping(ulIP,999)) { CString sDebugString; sDebugString.Format(_T("PingMachine() failed on system %s.\n"), CString(m_bsMachineName)); OutputDebugString(sDebugString); return false; }
return true; }
//////////////////////////////////////////////////////////////////////
// Namespace operations
//////////////////////////////////////////////////////////////////////
inline HRESULT CConnection::ConnectToNamespace(BSTR bsNamespace /*= NULL*/) { OutputDebugString(_T("CConnection::ConnectToNamespace()\n"));
if (m_pIWbemServices) { m_pIWbemServices->Release(); // m_pIWbemServices = NULL();
m_pIWbemServices = NULL; }
HRESULT hRes; if( ! bsNamespace ) { bsNamespace = m_sNamespace.AllocSysString(); hRes = m_pIWbemLocator->ConnectServer(bsNamespace,0L,0L,0L,0L,0L,0L,&m_pIWbemServices); ::SysFreeString(bsNamespace); } else { hRes = m_pIWbemLocator->ConnectServer(bsNamespace,0L,0L,0L,0L,0L,0L,&m_pIWbemServices); } return hRes; }
//////////////////////////////////////////////////////////////////////
// Event Operations
//////////////////////////////////////////////////////////////////////
BOOL CConnection::AddEventEntry(const CString& sQuery, IWbemObjectSink*& pSink) { OutputDebugString(_T("CConnection::AddEventEntry()\n"));
ASSERT(pSink); if( pSink == NULL ) { OutputDebugString(_T("CConnection::AddEventEntry()-pSink is NULL. Failed.\n")); return false; } ASSERT(!sQuery.IsEmpty()); if( sQuery.IsEmpty() ) { OutputDebugString(_T("CConnection::AddEventEntry()-The query string passed is empty. Failed.\n")); return false; }
// do not add duplicate event entry.
for (int i = 0; i < m_EventConsumers.GetSize(); i++) { if (pSink == m_EventConsumers[i]->m_pSink && sQuery == m_EventConsumers[i]->m_sQuery) return true; }
CEventRegistrationEntry* pEntry = new CEventRegistrationEntry(sQuery, pSink); m_EventConsumers.Add(pEntry);
if( m_bAvailable ) { BSTR bsLang = SysAllocString(L"WQL"); BSTR bsQuery = pEntry->m_sQuery.AllocSysString();
HRESULT hr = m_pIWbemServices->ExecNotificationQueryAsync(bsLang, bsQuery, 0L, 0L, pEntry->m_pSink); ::SysFreeString(bsQuery); ::SysFreeString(bsLang);
if (SUCCEEDED(hr)) pEntry->m_bRegistered = true; }
// zzz
SetEvent(m_hReadyToConnect); return true; }
BOOL CConnection::RemoveEventEntry(IWbemObjectSink*& pSink) { OutputDebugString(_T("CConnection::RemoveEventEntry()\n")); for( int i=0; i < m_EventConsumers.GetSize(); i++ ) { if( pSink == m_EventConsumers[i]->m_pSink ) { CEventRegistrationEntry* pEntry = m_EventConsumers[i]; ASSERT(pEntry); ASSERT_VALID(pEntry);
if (pEntry->m_bRegistered && m_pIWbemServices && m_bAvailable) { if (SUCCEEDED(m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink))) pEntry->m_bRegistered = false; } delete pEntry; m_EventConsumers.RemoveAt(i);
return TRUE; } } return TRUE; }
void CConnection::RemoveAllEventEntries() { OutputDebugString(_T("CConnection::RemoveAllEventEntries()\n")); HRESULT hr; for (int i=0; i < m_EventConsumers.GetSize(); i++) { CEventRegistrationEntry* pEntry = m_EventConsumers[i]; ASSERT(pEntry); ASSERT_VALID(pEntry);
if (pEntry->m_bRegistered && m_pIWbemServices && m_bAvailable) hr = m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink);
delete pEntry; } m_EventConsumers.RemoveAll(); }
HRESULT CConnection::RegisterAllEvents() { OutputDebugString(_T("CConnection::RegisterAllEvents()\n"));
// if there's no sink, return server too busy.
if (!m_EventConsumers.GetSize()) return WBEM_E_SERVER_TOO_BUSY;
HRESULT hr = S_OK; int i = 0; BSTR bsLang = SysAllocString(L"WQL"); for(i=0; i < m_EventConsumers.GetSize(); i++) { CEventRegistrationEntry* pEntry = m_EventConsumers[i]; ASSERT(pEntry); ASSERT_VALID(pEntry);
if( pEntry->m_eType != AsyncQuery ) { BSTR bsQuery = pEntry->m_sQuery.AllocSysString();
OutputDebugString(_T("\t")); OutputDebugString(pEntry->m_sQuery); OutputDebugString(_T("\n"));
hr = m_pIWbemServices->ExecNotificationQueryAsync(bsLang, bsQuery, 0L, 0L, pEntry->m_pSink); ::SysFreeString(bsQuery);
if (SUCCEEDED(hr)) pEntry->m_bRegistered = true; else break; } else { pEntry->SendInstances(m_pIWbemServices,2); m_EventConsumers.RemoveAt(i); delete pEntry; } } ::SysFreeString(bsLang); // Cancel any succeeded calls????
/*
i--; if (FAILED(hr) && i >= 0) { // cancel succeeded calls
while(i>=0) { CEventRegistrationEntry* pEntry = m_EventConsumers[i]; ASSERT(pEntry); ASSERT_VALID(pEntry); if (pEntry->m_bRegistered) { HRESULT hRes = m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink); pEntry->m_bRegistered = false; } i--; } } */ return hr; }
void CConnection::UnRegisterAllEvents() { OutputDebugString(_T("CConnection::UnRegisterAllEvents()\n"));
for (int i=0; i < m_EventConsumers.GetSize(); i++) { CEventRegistrationEntry* pEntry = m_EventConsumers[i]; ASSERT(pEntry); ASSERT_VALID(pEntry); if (pEntry->m_bRegistered && pEntry->m_eType != AsyncQuery ) { HRESULT hr = m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink); pEntry->m_bRegistered = false; } } } //////////////////////////////////////////////////////////////////////
// Console notification
//////////////////////////////////////////////////////////////////////
inline HRESULT CConnection::NotifyConsole(HRESULT hRes) { OutputDebugString(_T("CConnection::NotifyCosole()\n"));
HRESULT hr = S_OK; // Set notify flag appropriately
long lFlag = 0; if (hRes == S_OK) { if (m_bFirstConnect) { lFlag = 2; } else lFlag = 1; }
for (int i=0; i < m_EventConsumers.GetSize(); i++) { CEventRegistrationEntry* pEntry = m_EventConsumers[i]; ASSERT(pEntry); ASSERT_VALID(pEntry);
// Notify console w/ connection status
if (i == 0) hr = pEntry->NotifyConsole(lFlag, hRes);
// If connection is bad, no need to continue
if (hRes != S_OK) break; // Reset first connect flag
if (SUCCEEDED(hr) && m_bFirstConnect) m_bFirstConnect = false;
HRESULT hr2 = pEntry->SendInstances(m_pIWbemServices, lFlag); }
return hRes; }
|