Source code of Windows XP (NT5)
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.

701 lines
17 KiB

  1. // Connection.cpp: implementation of the CConnection class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "ConnMgr.h"
  6. #include "Connection.h"
  7. #include "Ping.h"
  8. #include <process.h>
  9. #ifdef _DEBUG
  10. #undef THIS_FILE
  11. static char THIS_FILE[]=__FILE__;
  12. #define new DEBUG_NEW
  13. #endif
  14. //////////////////////////////////////////////////////////////////////
  15. // CConnection
  16. IMPLEMENT_DYNCREATE(CConnection,CObject)
  17. //////////////////////////////////////////////////////////////////////
  18. // Construction/Destruction
  19. //////////////////////////////////////////////////////////////////////
  20. CConnection::CConnection(BSTR bsMachineName, IWbemLocator* pIWbemLocator)
  21. {
  22. OutputDebugString(_T("CConnection::CConnection()\n"));
  23. ASSERT(pIWbemLocator);
  24. Init();
  25. m_bsMachineName = SysAllocString(bsMachineName);
  26. m_sNamespace.Format(_T("\\\\%s\\root\\cimv2\\MicrosoftHealthmonitor"),bsMachineName);
  27. m_pIWbemLocator = pIWbemLocator;
  28. m_pIWbemLocator->AddRef();
  29. StartMonitor();
  30. }
  31. CConnection::CConnection()
  32. {
  33. OutputDebugString(_T("CConnection::CConnection()\n"));
  34. Init();
  35. }
  36. CConnection::~CConnection()
  37. {
  38. OutputDebugString(_T("CConnection::~CConnection()\n"));
  39. // stop monitoring
  40. StopMonitor();
  41. RemoveAllEventEntries();
  42. if( m_pIWbemServices )
  43. {
  44. if (m_bAvailable)
  45. m_pIWbemServices->Release();
  46. m_pIWbemServices = NULL;
  47. }
  48. if (m_pIWbemLocator)
  49. {
  50. if (m_bAvailable)
  51. m_pIWbemLocator->Release();
  52. m_pIWbemLocator = NULL;
  53. }
  54. SysFreeString(m_bsMachineName);
  55. CloseHandle(m_threadData.m_hDie);
  56. CloseHandle(m_threadData.m_hDead);
  57. // zzz
  58. CloseHandle(m_hReadyToConnect);
  59. }
  60. //////////////////////////////////////////////////////////////////////
  61. // Initialize CConnection data members.
  62. //////////////////////////////////////////////////////////////////////
  63. void CConnection::Init()
  64. {
  65. OutputDebugString(_T("CConnection::Init()\n"));
  66. m_bAvailable = false;
  67. m_bFirstConnect = true;
  68. m_pIWbemServices = NULL;
  69. m_pIWbemLocator = NULL;
  70. m_dwPollInterval = 10000;
  71. m_bsMachineName = NULL;
  72. m_threadData.m_hDie = CreateEvent(NULL, TRUE, FALSE, NULL);
  73. m_threadData.m_hDead = CreateEvent(NULL, TRUE, FALSE, NULL);
  74. m_hrLastConnectResult = S_OK;
  75. //zzz
  76. m_hReadyToConnect = CreateEvent(NULL, TRUE, FALSE, NULL);
  77. }
  78. //////////////////////////////////////////////////////////////////////
  79. // Start/Stop Monitoring connection
  80. //////////////////////////////////////////////////////////////////////
  81. void CConnection::StartMonitor()
  82. {
  83. OutputDebugString(_T("CConnection::StartMonitor()\n"));
  84. m_threadData.m_bkptr = this;
  85. m_hThread = (HANDLE)_beginthreadex( NULL,
  86. 0,
  87. MonitorConnection,
  88. &m_threadData,
  89. 0,
  90. &m_threadID );
  91. if (!m_hThread)
  92. {
  93. OutputDebugString(_T("CConnection::StartMonitor() Error on _beginthreadex\n"));
  94. }
  95. }
  96. void CConnection::StopMonitor()
  97. {
  98. OutputDebugString(_T("CConnection::StopMonitor()\n"));
  99. // tell it to die now.
  100. SetEvent(m_threadData.m_hDie);
  101. // if connection is down just kill it.
  102. if (!m_bAvailable)
  103. {
  104. TerminateThread(m_hThread, 0);
  105. return;
  106. }
  107. // otherwise, give it a chance to die.
  108. if (WAIT_TIMEOUT ==
  109. WaitForSingleObject(m_threadData.m_hDead, m_dwPollInterval))
  110. {
  111. OutputDebugString(_T("CConnection::StartMonitor() Timed out - Killing thread.\n"));
  112. TerminateThread(m_hThread, 0);
  113. }
  114. }
  115. //////////////////////////////////////////////////////////////////////
  116. // Thread Func: Establish initial connection and check status.
  117. //////////////////////////////////////////////////////////////////////
  118. unsigned int __stdcall CConnection::MonitorConnection(void *pv)
  119. {
  120. OutputDebugString(_T("CConnection::MonitorNode() New Thread!\n"));
  121. struct threadData* pData = (struct threadData*)pv;
  122. HRESULT hRes = pData->m_bkptr->Connect(); // Try to connect first.
  123. if (FAILED(hRes))
  124. pData->m_bkptr->NotifyConsole(hRes);
  125. while (true)
  126. {
  127. if (WAIT_OBJECT_0 == WaitForSingleObject(pData->m_hDie,
  128. pData->m_bkptr->m_dwPollInterval) )
  129. {
  130. SetEvent(pData->m_hDead);
  131. break;
  132. }
  133. // Monitor Managed Node
  134. pData->m_bkptr->CheckConnection();
  135. }
  136. _endthreadex(0);
  137. return 0;
  138. }
  139. //////////////////////////////////////////////////////////////////////
  140. //////////////////////////////////////////////////////////////////////
  141. // Check connection status
  142. //////////////////////////////////////////////////////////////////////
  143. void CConnection::CheckConnection()
  144. {
  145. OutputDebugString(_T("CConnection::CheckNode()\n"));
  146. if (m_bAvailable) // Connection is available
  147. { // Check to see it is still valid.
  148. if (!PingMachine())
  149. { // Connection went down!
  150. OutputDebugString(_T("CConnection::CheckConnection()-Lost connection!\n"));
  151. m_hrLastConnectResult = WBEM_E_TRANSPORT_FAILURE;
  152. SetConnectionStatus(false);
  153. NotifyConsole(m_hrLastConnectResult);
  154. return;
  155. }
  156. // Now, check Wbem connection
  157. m_hrLastConnectResult = m_pIWbemServices->GetObject(0L,0L,0L,0L,0L);
  158. if (FAILED(m_hrLastConnectResult))
  159. {
  160. // Wbem connection is no longer valid!
  161. OutputDebugString(_T("CConnection::CheckConnection()-Lost wbem connection!\n"));
  162. SetConnectionStatus(false);
  163. NotifyConsole(m_hrLastConnectResult);
  164. }
  165. }
  166. else
  167. {
  168. // Try to re-establish connection
  169. Connect();
  170. }
  171. }
  172. //////////////////////////////////////////////////////////////////////
  173. // Connection operations
  174. //////////////////////////////////////////////////////////////////////
  175. HRESULT CConnection::Connect()
  176. {
  177. OutputDebugString(_T("CConnection::Connect()\n"));
  178. // zzz
  179. WaitForSingleObject(m_hReadyToConnect, INFINITE);
  180. m_hrLastConnectResult = WBEM_E_TRANSPORT_FAILURE;
  181. // can it be reached?
  182. if (!PingMachine())
  183. return m_hrLastConnectResult;
  184. // now, try to connect to namespace
  185. m_hrLastConnectResult = ConnectToNamespace();
  186. if (FAILED(m_hrLastConnectResult))
  187. return m_hrLastConnectResult;
  188. // is agent ready?
  189. if (FAILED(m_hrLastConnectResult = IsAgentReady()))
  190. return m_hrLastConnectResult;
  191. // is agent correct version ?
  192. if( FAILED(m_hrLastConnectResult = IsAgentCorrectVersion()) )
  193. return m_hrLastConnectResult;
  194. UnRegisterAllEvents();
  195. if (SUCCEEDED(m_hrLastConnectResult = RegisterAllEvents()))
  196. {
  197. SetConnectionStatus(true);
  198. NotifyConsole(m_hrLastConnectResult);
  199. }
  200. return m_hrLastConnectResult;
  201. }
  202. inline HRESULT CConnection::IsAgentReady()
  203. {
  204. // check to see if agent providers are ready to service external requests.
  205. if (!m_pIWbemServices)
  206. return WBEM_E_TRANSPORT_FAILURE;
  207. IEnumWbemClassObject* pEnumObj = NULL;
  208. // HMSystemStatus ready?
  209. BSTR bsName = SysAllocString(L"Microsoft_HMSystemStatus");
  210. HRESULT hRes = m_pIWbemServices->CreateInstanceEnum(bsName,
  211. WBEM_FLAG_SHALLOW,
  212. NULL,
  213. &pEnumObj);
  214. SysFreeString(bsName);
  215. if (FAILED(hRes))
  216. {
  217. CString sDebugString;
  218. sDebugString.Format(_T("IsAgentReady()-Agent is unavailable to deliver SystemStatus on %s. Operation failed with result=<%X>."), CString(m_bsMachineName), hRes);
  219. OutputDebugString(sDebugString);
  220. return hRes;
  221. }
  222. pEnumObj->Release();
  223. pEnumObj = NULL;
  224. /*
  225. // HMCatStatus ready?
  226. SysReAllocString(&bsName, L"HMCatStatus");
  227. hRes = m_pIWbemServices->CreateInstanceEnum(bsName,
  228. WBEM_FLAG_SHALLOW,
  229. NULL,
  230. &pEnumObj);
  231. SysFreeString(bsName);
  232. if (FAILED(hRes))
  233. return hRes;
  234. pEnumObj->Release();
  235. pEnumObj = NULL;
  236. // HMMachStatus ready?
  237. SysReAllocString(&bsName, L"HMMachStatus");
  238. hRes = m_pIWbemServices->CreateInstanceEnum(bsName,
  239. WBEM_FLAG_SHALLOW,
  240. NULL,
  241. &pEnumObj);
  242. SysFreeString(bsName);
  243. if (FAILED(hRes))
  244. return hRes;
  245. pEnumObj->Release();
  246. pEnumObj = NULL;
  247. */
  248. return S_OK;
  249. }
  250. inline HRESULT CConnection::IsAgentCorrectVersion()
  251. {
  252. // check to see if agent is correct version to service external requests.
  253. if (!m_pIWbemServices)
  254. return WBEM_E_TRANSPORT_FAILURE;
  255. IEnumWbemClassObject* pEnumObj = NULL;
  256. // HMVersion check
  257. // enumerate for HMVersion
  258. BSTR bsName = SysAllocString(L"Microsoft_HMVersion");
  259. HRESULT hRes = m_pIWbemServices->CreateInstanceEnum(bsName,
  260. WBEM_FLAG_SHALLOW,
  261. NULL,
  262. &pEnumObj);
  263. SysFreeString(bsName);
  264. if (FAILED(hRes))
  265. {
  266. CString sDebugString;
  267. sDebugString.Format(_T("IsAgentCorrectVersion()-Unable to enumerate for Microsoft_HMVersion on system %s. Operation failed with result=<%X>."), CString(m_bsMachineName), hRes);
  268. OutputDebugString(sDebugString);
  269. return hRes;
  270. }
  271. IWbemClassObject* pObject = NULL;
  272. ULONG uReturned = 0L;
  273. hRes = pEnumObj->Next(WBEM_INFINITE,1,&pObject,&uReturned);
  274. if( FAILED(hRes) || uReturned == 0L )
  275. {
  276. pEnumObj->Release();
  277. pEnumObj = NULL;
  278. CString sDebugString;
  279. sDebugString.Format(_T("IsAgentCorrectVersion()-Unable to enumerate for Microsoft_HMVersion on system %s. Operation failed with result=<%X>.\n"), CString(m_bsMachineName), hRes);
  280. OutputDebugString(sDebugString);
  281. return hRes;
  282. }
  283. VARIANT vPropValue;
  284. VariantInit(&vPropValue);
  285. bsName = SysAllocString(L"MajorVersion");
  286. hRes = pObject->Get(bsName, 0L, &vPropValue, NULL, NULL);
  287. SysFreeString(bsName);
  288. if( FAILED(hRes) )
  289. {
  290. pObject->Release();
  291. pEnumObj->Release();
  292. pEnumObj = NULL;
  293. CString sDebugString;
  294. sDebugString.Format(_T("IsAgentCorrectVersion()-Unable to enumerate for Microsoft_HMVersion on system %s. Operation failed with result=<%X>.\n"), CString(m_bsMachineName), hRes);
  295. OutputDebugString(sDebugString);
  296. return hRes;
  297. }
  298. CString sMajorVersion = V_BSTR(&vPropValue);
  299. VariantClear(&vPropValue);
  300. if( _ttoi(sMajorVersion) != SCHEMA_MAJOR_VERSION )
  301. {
  302. pObject->Release();
  303. pEnumObj->Release();
  304. hRes = E_NOTIMPL;
  305. CString sDebugString;
  306. sDebugString.Format(_T("IsAgentCorrectVersion()-Incorrect Agent version number on system %s.\n"), CString(m_bsMachineName));
  307. OutputDebugString(sDebugString);
  308. return hRes;
  309. }
  310. VariantInit(&vPropValue);
  311. bsName = SysAllocString(L"MinorVersion");
  312. hRes = pObject->Get(bsName, 0L, &vPropValue, NULL, NULL);
  313. SysFreeString(bsName);
  314. if( FAILED(hRes) )
  315. {
  316. pObject->Release();
  317. pEnumObj->Release();
  318. pEnumObj = NULL;
  319. CString sDebugString;
  320. sDebugString.Format(_T("IsAgentCorrectVersion()-Incorrect Agent version number on system %s.\n"), CString(m_bsMachineName));
  321. OutputDebugString(sDebugString);
  322. return hRes;
  323. }
  324. CString sMinorVersion = V_BSTR(&vPropValue);
  325. VariantClear(&vPropValue);
  326. if( _ttoi(sMinorVersion) != SCHEMA_MINOR_VERSION )
  327. {
  328. pObject->Release();
  329. pEnumObj->Release();
  330. hRes = E_NOTIMPL;
  331. CString sDebugString;
  332. sDebugString.Format(_T("IsAgentCorrectVersion()-Incorrect Agent version number on system %s.\n"), CString(m_bsMachineName));
  333. OutputDebugString(sDebugString);
  334. return hRes;
  335. }
  336. pObject->Release();
  337. pEnumObj->Release();
  338. pEnumObj = NULL;
  339. return hRes;
  340. }
  341. inline void CConnection::SetConnectionStatus(BOOL bFlag)
  342. {
  343. OutputDebugString(_T("CConnection::SetConnectionStatus()\n"));
  344. if (m_bAvailable != bFlag)
  345. {
  346. m_bAvailable = bFlag;
  347. }
  348. else
  349. OutputDebugString(_T("CConnection::SetConnectionStatus()-No change in Connection Status!\n"));
  350. }
  351. inline BOOL CConnection::PingMachine()
  352. {
  353. OutputDebugString(_T("CConnection::Ping()\n"));
  354. CPing Pong;
  355. unsigned long ulIP = Pong.ResolveName(m_bsMachineName);
  356. if (!Pong.Ping(ulIP,999))
  357. {
  358. CString sDebugString;
  359. sDebugString.Format(_T("PingMachine() failed on system %s.\n"), CString(m_bsMachineName));
  360. OutputDebugString(sDebugString);
  361. return false;
  362. }
  363. return true;
  364. }
  365. //////////////////////////////////////////////////////////////////////
  366. // Namespace operations
  367. //////////////////////////////////////////////////////////////////////
  368. inline HRESULT CConnection::ConnectToNamespace(BSTR bsNamespace /*= NULL*/)
  369. {
  370. OutputDebugString(_T("CConnection::ConnectToNamespace()\n"));
  371. if (m_pIWbemServices)
  372. {
  373. m_pIWbemServices->Release();
  374. // m_pIWbemServices = NULL();
  375. m_pIWbemServices = NULL;
  376. }
  377. HRESULT hRes;
  378. if( ! bsNamespace )
  379. {
  380. bsNamespace = m_sNamespace.AllocSysString();
  381. hRes = m_pIWbemLocator->ConnectServer(bsNamespace,0L,0L,0L,0L,0L,0L,&m_pIWbemServices);
  382. ::SysFreeString(bsNamespace);
  383. }
  384. else
  385. {
  386. hRes = m_pIWbemLocator->ConnectServer(bsNamespace,0L,0L,0L,0L,0L,0L,&m_pIWbemServices);
  387. }
  388. return hRes;
  389. }
  390. //////////////////////////////////////////////////////////////////////
  391. // Event Operations
  392. //////////////////////////////////////////////////////////////////////
  393. BOOL CConnection::AddEventEntry(const CString& sQuery, IWbemObjectSink*& pSink)
  394. {
  395. OutputDebugString(_T("CConnection::AddEventEntry()\n"));
  396. ASSERT(pSink);
  397. if( pSink == NULL )
  398. {
  399. OutputDebugString(_T("CConnection::AddEventEntry()-pSink is NULL. Failed.\n"));
  400. return false;
  401. }
  402. ASSERT(!sQuery.IsEmpty());
  403. if( sQuery.IsEmpty() )
  404. {
  405. OutputDebugString(_T("CConnection::AddEventEntry()-The query string passed is empty. Failed.\n"));
  406. return false;
  407. }
  408. // do not add duplicate event entry.
  409. for (int i = 0; i < m_EventConsumers.GetSize(); i++)
  410. {
  411. if (pSink == m_EventConsumers[i]->m_pSink &&
  412. sQuery == m_EventConsumers[i]->m_sQuery)
  413. return true;
  414. }
  415. CEventRegistrationEntry* pEntry = new CEventRegistrationEntry(sQuery, pSink);
  416. m_EventConsumers.Add(pEntry);
  417. if( m_bAvailable )
  418. {
  419. BSTR bsLang = SysAllocString(L"WQL");
  420. BSTR bsQuery = pEntry->m_sQuery.AllocSysString();
  421. HRESULT hr = m_pIWbemServices->ExecNotificationQueryAsync(bsLang,
  422. bsQuery,
  423. 0L,
  424. 0L,
  425. pEntry->m_pSink);
  426. ::SysFreeString(bsQuery);
  427. ::SysFreeString(bsLang);
  428. if (SUCCEEDED(hr))
  429. pEntry->m_bRegistered = true;
  430. }
  431. // zzz
  432. SetEvent(m_hReadyToConnect);
  433. return true;
  434. }
  435. BOOL CConnection::RemoveEventEntry(IWbemObjectSink*& pSink)
  436. {
  437. OutputDebugString(_T("CConnection::RemoveEventEntry()\n"));
  438. for( int i=0; i < m_EventConsumers.GetSize(); i++ )
  439. {
  440. if( pSink == m_EventConsumers[i]->m_pSink )
  441. {
  442. CEventRegistrationEntry* pEntry = m_EventConsumers[i];
  443. ASSERT(pEntry);
  444. ASSERT_VALID(pEntry);
  445. if (pEntry->m_bRegistered && m_pIWbemServices && m_bAvailable)
  446. {
  447. if (SUCCEEDED(m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink)))
  448. pEntry->m_bRegistered = false;
  449. }
  450. delete pEntry;
  451. m_EventConsumers.RemoveAt(i);
  452. return TRUE;
  453. }
  454. }
  455. return TRUE;
  456. }
  457. void CConnection::RemoveAllEventEntries()
  458. {
  459. OutputDebugString(_T("CConnection::RemoveAllEventEntries()\n"));
  460. HRESULT hr;
  461. for (int i=0; i < m_EventConsumers.GetSize(); i++)
  462. {
  463. CEventRegistrationEntry* pEntry = m_EventConsumers[i];
  464. ASSERT(pEntry);
  465. ASSERT_VALID(pEntry);
  466. if (pEntry->m_bRegistered && m_pIWbemServices && m_bAvailable)
  467. hr = m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink);
  468. delete pEntry;
  469. }
  470. m_EventConsumers.RemoveAll();
  471. }
  472. HRESULT CConnection::RegisterAllEvents()
  473. {
  474. OutputDebugString(_T("CConnection::RegisterAllEvents()\n"));
  475. // if there's no sink, return server too busy.
  476. if (!m_EventConsumers.GetSize())
  477. return WBEM_E_SERVER_TOO_BUSY;
  478. HRESULT hr = S_OK;
  479. int i = 0;
  480. BSTR bsLang = SysAllocString(L"WQL");
  481. for(i=0; i < m_EventConsumers.GetSize(); i++)
  482. {
  483. CEventRegistrationEntry* pEntry = m_EventConsumers[i];
  484. ASSERT(pEntry);
  485. ASSERT_VALID(pEntry);
  486. if( pEntry->m_eType != AsyncQuery )
  487. {
  488. BSTR bsQuery = pEntry->m_sQuery.AllocSysString();
  489. OutputDebugString(_T("\t"));
  490. OutputDebugString(pEntry->m_sQuery);
  491. OutputDebugString(_T("\n"));
  492. hr = m_pIWbemServices->ExecNotificationQueryAsync(bsLang,
  493. bsQuery,
  494. 0L,
  495. 0L,
  496. pEntry->m_pSink);
  497. ::SysFreeString(bsQuery);
  498. if (SUCCEEDED(hr))
  499. pEntry->m_bRegistered = true;
  500. else
  501. break;
  502. }
  503. else
  504. {
  505. pEntry->SendInstances(m_pIWbemServices,2);
  506. m_EventConsumers.RemoveAt(i);
  507. delete pEntry;
  508. }
  509. }
  510. ::SysFreeString(bsLang);
  511. // Cancel any succeeded calls????
  512. /*
  513. i--;
  514. if (FAILED(hr) && i >= 0)
  515. { // cancel succeeded calls
  516. while(i>=0)
  517. {
  518. CEventRegistrationEntry* pEntry = m_EventConsumers[i];
  519. ASSERT(pEntry);
  520. ASSERT_VALID(pEntry);
  521. if (pEntry->m_bRegistered)
  522. {
  523. HRESULT hRes = m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink);
  524. pEntry->m_bRegistered = false;
  525. }
  526. i--;
  527. }
  528. }
  529. */
  530. return hr;
  531. }
  532. void CConnection::UnRegisterAllEvents()
  533. {
  534. OutputDebugString(_T("CConnection::UnRegisterAllEvents()\n"));
  535. for (int i=0; i < m_EventConsumers.GetSize(); i++)
  536. {
  537. CEventRegistrationEntry* pEntry = m_EventConsumers[i];
  538. ASSERT(pEntry);
  539. ASSERT_VALID(pEntry);
  540. if (pEntry->m_bRegistered && pEntry->m_eType != AsyncQuery )
  541. {
  542. HRESULT hr = m_pIWbemServices->CancelAsyncCall(pEntry->m_pSink);
  543. pEntry->m_bRegistered = false;
  544. }
  545. }
  546. }
  547. //////////////////////////////////////////////////////////////////////
  548. // Console notification
  549. //////////////////////////////////////////////////////////////////////
  550. inline HRESULT CConnection::NotifyConsole(HRESULT hRes)
  551. {
  552. OutputDebugString(_T("CConnection::NotifyCosole()\n"));
  553. HRESULT hr = S_OK;
  554. // Set notify flag appropriately
  555. long lFlag = 0;
  556. if (hRes == S_OK)
  557. {
  558. if (m_bFirstConnect)
  559. {
  560. lFlag = 2;
  561. }
  562. else
  563. lFlag = 1;
  564. }
  565. for (int i=0; i < m_EventConsumers.GetSize(); i++)
  566. {
  567. CEventRegistrationEntry* pEntry = m_EventConsumers[i];
  568. ASSERT(pEntry);
  569. ASSERT_VALID(pEntry);
  570. // Notify console w/ connection status
  571. if (i == 0)
  572. hr = pEntry->NotifyConsole(lFlag, hRes);
  573. // If connection is bad, no need to continue
  574. if (hRes != S_OK)
  575. break;
  576. // Reset first connect flag
  577. if (SUCCEEDED(hr) && m_bFirstConnect)
  578. m_bFirstConnect = false;
  579. HRESULT hr2 = pEntry->SendInstances(m_pIWbemServices, lFlag);
  580. }
  581. return hRes;
  582. }