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.

3776 lines
89 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. boot.cxx
  5. Abstract:
  6. Load balancing service
  7. Author:
  8. Philippe Choquier (phillich)
  9. --*/
  10. #define INITGUID
  11. extern "C" {
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. }
  16. #include <ole2.h>
  17. #include <windows.h>
  18. #include <winsock2.h>
  19. #include <olectl.h>
  20. #include <pdh.h>
  21. #pragma warning( disable:4200 )
  22. #include "pdhitype.h"
  23. #include "pdhidef.h"
  24. #include <pdhmsg.h>
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #include <time.h>
  28. #include <IisLb.h>
  29. #include <lbxbf.hxx>
  30. #include <lbcnfg.hxx>
  31. #include <bootimp.hxx>
  32. #include <IisLbs.hxx>
  33. #include <lbmsg.h>
  34. #include <dcomperm.h>
  35. #include <iisnatio.h>
  36. #include <pudebug.h>
  37. #if DBG
  38. #define _NOISY_DEBUG
  39. #endif
  40. #if defined(_NOISY_DEBUG)
  41. #define DEBUG_BUFFER char achE[128]
  42. #define DBG_PRINTF(a) sprintf a; OutputDebugString( achE )
  43. #define DBG_PUTS(a) OutputDebugString(a)
  44. #else
  45. #define DEBUG_BUFFER
  46. #define DBG_PRINTF(a)
  47. #define DBG_PUTS(a)
  48. #endif
  49. #define RETURNCODETOHRESULT(rc) \
  50. (((rc) < 0x10000) \
  51. ? HRESULT_FROM_WIN32(rc) \
  52. : (rc))
  53. #define DEFAULT_IP_PORT 80
  54. #define COLLECT_TIMEOUT 20 // in seconds
  55. #define SLEEP_INTERVAL 1000 // for server state query, in ms
  56. #define MAX_SLEEP (10*1000) // driver startup time, in ms
  57. typedef
  58. PDH_STATUS
  59. (__stdcall *PFN_OPEN_QUERY)(
  60. IN LPVOID pv,
  61. IN DWORD dwUserData,
  62. IN HQUERY *phQuery);
  63. //
  64. // Globals
  65. //
  66. DWORD g_dwRefCount = 0;
  67. DWORD g_dwComRegister;
  68. DWORD g_bInitialized = FALSE;
  69. HANDLE g_UserToKernelUpdateEvent;
  70. BOOL g_fStopUserToKernelThread = FALSE;
  71. HANDLE g_hUserToKernelThread = NULL;
  72. WSADATA g_WSAData;
  73. HMODULE g_hPdh;
  74. PFN_OPEN_QUERY g_pfnPdhOpenQuery = NULL;
  75. LPBYTE g_pAcl = NULL;
  76. DWORD g_dwPdhVersion = 0;
  77. CComputerPerfCounters g_PerfmonCounterList;
  78. CRITICAL_SECTION g_csPerfList;
  79. // guarantee structure integrity
  80. CRITICAL_SECTION g_csIpListCheckpoint;
  81. // for write access w/o modifying structure
  82. CRITICAL_SECTION g_csIpListUpdate;
  83. CRITICAL_SECTION g_csAcl;
  84. CRITICAL_SECTION g_csKernelThreadUpdate;
  85. CKernelIpMapHelper g_KernelIpMap;
  86. // set to TRUE if load in each server info is available load
  87. BOOL g_fNormalized = FALSE;
  88. CIPMap g_IpMap;
  89. GENERIC_MAPPING g_FileGenericMapping =
  90. {
  91. FILE_READ_DATA,
  92. FILE_WRITE_DATA,
  93. FILE_EXECUTE,
  94. FILE_ALL_ACCESS
  95. };
  96. //
  97. // Private prototypes
  98. //
  99. HRESULT InitOleSecurity(
  100. );
  101. BOOL
  102. LbAccessCheck(
  103. DWORD dwAccess
  104. );
  105. VOID
  106. FlushLbAccessCheck(
  107. );
  108. HRESULT
  109. SetLbDriverState(
  110. BOOL fStart
  111. );
  112. BOOL
  113. CheckQueryMachineStatus(
  114. HQUERY hQuery
  115. );
  116. /////
  117. BOOL
  118. IncludeServerName(
  119. LPWSTR pszPath
  120. )
  121. /*++
  122. Routine Description:
  123. Check if path includes server names
  124. Arguments:
  125. pszPath - UNC path
  126. Return Value:
  127. TRUE if path refers to server, otherwise FALSE
  128. --*/
  129. {
  130. return pszPath[0] == L'\\' && pszPath[1] == L'\\';
  131. }
  132. CIisLb::CIisLb(
  133. )
  134. /*++
  135. Routine Description:
  136. CIisLb constructor
  137. Arguments:
  138. None
  139. Return Value:
  140. Nothing
  141. --*/
  142. {
  143. m_dwRefCount = 0;
  144. }
  145. CIisLb::~CIisLb(
  146. )
  147. /*++
  148. Routine Description:
  149. CIisLb destructor
  150. Arguments:
  151. None
  152. Return Value:
  153. Nothing
  154. --*/
  155. {
  156. }
  157. HRESULT
  158. CIisLb::QueryInterface(
  159. REFIID riid,
  160. void **ppObject
  161. )
  162. /*++
  163. Routine Description:
  164. CIisLb QueryInterface
  165. Arguments:
  166. riid - Interface ID
  167. ppObject - updated with ptr to interface on success
  168. Return Value:
  169. status
  170. --*/
  171. {
  172. if (riid==IID_IUnknown || riid==IID_IMSIisLb) {
  173. *ppObject = (IMSIisLb *) this;
  174. }
  175. else {
  176. return E_NOINTERFACE;
  177. }
  178. AddRef();
  179. return NO_ERROR;
  180. }
  181. ULONG
  182. CIisLb::AddRef(
  183. )
  184. /*++
  185. Routine Description:
  186. CIisLb add reference to COM interface
  187. Arguments:
  188. None
  189. Return Value:
  190. reference count
  191. --*/
  192. {
  193. DWORD dwRefCount;
  194. InterlockedIncrement((long *)&g_dwRefCount);
  195. dwRefCount = InterlockedIncrement((long *)&m_dwRefCount);
  196. return dwRefCount;
  197. }
  198. ULONG
  199. CIisLb::Release(
  200. )
  201. /*++
  202. Routine Description:
  203. CIisLb release reference to COM interface
  204. delete object when reference count drops to zero
  205. Arguments:
  206. None
  207. Return Value:
  208. reference count
  209. --*/
  210. {
  211. DWORD dwRefCount;
  212. InterlockedDecrement((long *)&g_dwRefCount);
  213. dwRefCount = InterlockedDecrement((long *)&m_dwRefCount);
  214. if (dwRefCount == 0)
  215. {
  216. delete this;
  217. return 0;
  218. }
  219. return dwRefCount;
  220. }
  221. HRESULT STDMETHODCALLTYPE
  222. CIisLb::GetIpList(
  223. /*[in]*/ DWORD dwBufferSize,
  224. /*[out, size_is(dwBufferSize)]*/ unsigned char *pbBuffer,
  225. /*[out]*/ DWORD *pdwMDRequiredBufferSize )
  226. /*++
  227. Routine Description:
  228. Get the IP mapping list in a serialized format
  229. Arguments:
  230. dwBufferSize - size of pbBuffer
  231. pbBuffer - buffer updated with serialized IP mapping list
  232. pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
  233. Return Value:
  234. COM status
  235. will be Win32 error ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
  236. --*/
  237. {
  238. XBF xbf;
  239. BOOL fSt;
  240. EnterCriticalSection( &g_csIpListCheckpoint );
  241. fSt = g_IpMap.Serialize( &xbf );
  242. LeaveCriticalSection( &g_csIpListCheckpoint );
  243. if ( fSt )
  244. {
  245. *pdwMDRequiredBufferSize = xbf.GetUsed();
  246. if ( dwBufferSize < xbf.GetUsed() )
  247. {
  248. return RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  249. }
  250. memcpy( pbBuffer, xbf.GetBuff(), xbf.GetUsed() );
  251. return S_OK;
  252. }
  253. return E_FAIL;
  254. }
  255. HRESULT STDMETHODCALLTYPE
  256. CIisLb::SetIpList(
  257. /*[in]*/ DWORD dwBufferSize,
  258. /*[in, size_is(dwBufferSize)]*/ unsigned char *pbBuffer )
  259. /*++
  260. Routine Description:
  261. Set the IP mapping list from serialized format
  262. Arguments:
  263. dwBufferSize - size of pbBuffer
  264. pbBuffer - buffer containing serialized IP mapping list
  265. Return Value:
  266. COM status
  267. --*/
  268. {
  269. EnterCriticalSection( &g_csIpListCheckpoint );
  270. if ( g_IpMap.Unserialize( &pbBuffer, &dwBufferSize ) &&
  271. IpListToKernelConfig( &g_IpMap ) &&
  272. g_IpMap.Save( HKEY_LOCAL_MACHINE, IISLOADBAL_REGISTRY_KEY, IPLIST_REGISTRY_VALUE ) )
  273. {
  274. LeaveCriticalSection( &g_csIpListCheckpoint );
  275. //
  276. // update kernel configuration
  277. //
  278. SetEvent( g_UserToKernelUpdateEvent );
  279. return S_OK;
  280. }
  281. LeaveCriticalSection( &g_csIpListCheckpoint );
  282. return E_FAIL;
  283. }
  284. HRESULT STDMETHODCALLTYPE
  285. CIisLb::GetPerfmonCounters(
  286. /*[in]*/ DWORD dwBufferSize,
  287. /*[out, size_is(dwBufferSize)]*/ unsigned char *pbBuffer,
  288. /*[out]*/ DWORD *pdwMDRequiredBufferSize )
  289. /*++
  290. Routine Description:
  291. Get the perfmon counter list in a serialized format
  292. Arguments:
  293. dwBufferSize - size of pbBuffer
  294. pbBuffer - buffer updated with serialized perfmon counter list
  295. pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
  296. Return Value:
  297. COM status
  298. will be Win32 error ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
  299. --*/
  300. {
  301. XBF xbf;
  302. if ( KernelConfigToPerfmonCounters( &xbf ) )
  303. {
  304. *pdwMDRequiredBufferSize = xbf.GetUsed();
  305. if ( dwBufferSize < xbf.GetUsed() )
  306. {
  307. return RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  308. }
  309. memcpy( pbBuffer, xbf.GetBuff(), xbf.GetUsed() );
  310. return S_OK;
  311. }
  312. return E_FAIL;
  313. }
  314. HRESULT STDMETHODCALLTYPE
  315. CIisLb::SetPerfmonCounters(
  316. /*[in]*/ DWORD dwBufferSize,
  317. /*[in, size_is(dwBufferSize)]*/ unsigned char *pbBuffer )
  318. /*++
  319. Routine Description:
  320. Set the perfmon counter list from serialized format
  321. Arguments:
  322. dwBufferSize - size of pbBuffer
  323. pbBuffer - buffer containing serialized perfmon counter list
  324. Return Value:
  325. COM status
  326. --*/
  327. {
  328. CComputerPerfCounters PerfmonCounters;
  329. if ( PerfmonCounters.Unserialize( &pbBuffer, &dwBufferSize ) &&
  330. PerfmonCountersToKernelConfig( &PerfmonCounters ) &&
  331. PerfmonCounters.Save( HKEY_LOCAL_MACHINE, IISLOADBAL_REGISTRY_KEY, PERFMON_REGISTRY_VALUE ) )
  332. {
  333. return S_OK;
  334. }
  335. return E_FAIL;
  336. }
  337. HRESULT STDMETHODCALLTYPE CIisLb::GetStickyDuration(
  338. /*[out]*/ LPDWORD pdwStickyDuration )
  339. /*++
  340. Routine Description:
  341. Get the sticky binding duration ( public IP -> private IP )
  342. Arguments:
  343. pdwStickyDuration - updated with sticky mode duration
  344. Return Value:
  345. COM status
  346. --*/
  347. {
  348. *pdwStickyDuration = g_KernelIpMap.GetStickyDuration();
  349. return S_OK;
  350. }
  351. HRESULT STDMETHODCALLTYPE
  352. CIisLb::SetStickyDuration(
  353. /*[in]*/ DWORD dwStickyDuration )
  354. /*++
  355. Routine Description:
  356. Set the sticky binding duration ( public IP -> private IP )
  357. Arguments:
  358. dwStickyDuration - sticky mode duration
  359. Return Value:
  360. COM status
  361. --*/
  362. {
  363. XBF xbf;
  364. g_KernelIpMap.SetStickyDuration( dwStickyDuration );
  365. if ( Serialize( &xbf, (DWORD)dwStickyDuration ) &&
  366. SaveBlobToReg( HKEY_LOCAL_MACHINE, IISLOADBAL_REGISTRY_KEY, STICKY_REGISTRY_VALUE, &xbf ) )
  367. {
  368. return S_OK;
  369. }
  370. return E_FAIL;
  371. }
  372. HRESULT STDMETHODCALLTYPE
  373. CIisLb::GetIpEndpointList(
  374. /*[in]*/ DWORD dwBufferSize,
  375. /*[out, size_is(dwBufferSize)]*/ unsigned char *pbBuffer,
  376. /*[out]*/ DWORD *pdwMDRequiredBufferSize )
  377. /*++
  378. Routine Description:
  379. Get the IP endpoint list in a serialized format
  380. Arguments:
  381. dwBufferSize - size of pbBuffer
  382. pbBuffer - buffer updated with serialized IP mapping list
  383. pdwMDRequiredBufferSize - updated with required size if dwBufferSize too small
  384. Return Value:
  385. COM status
  386. will be Win32 error ERROR_INSUFFICIENT_BUFFER if dwBufferSize too small
  387. --*/
  388. {
  389. XBF xbf;
  390. CIpEndpointList ieEndpointList;
  391. if ( ieEndpointList.BuildListFromLocalhost() &&
  392. ieEndpointList.Serialize( &xbf ) )
  393. {
  394. *pdwMDRequiredBufferSize = xbf.GetUsed();
  395. if ( dwBufferSize < xbf.GetUsed() )
  396. {
  397. return RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER );
  398. }
  399. memcpy( pbBuffer, xbf.GetBuff(), xbf.GetUsed() );
  400. return S_OK;
  401. }
  402. return E_FAIL;
  403. }
  404. HRESULT STDMETHODCALLTYPE
  405. CIisLb::SetDriverState(
  406. /*[in]*/ DWORD dwState
  407. )
  408. /*++
  409. Routine Description:
  410. Set the driver state ( started or stopped )
  411. Arguments:
  412. dwState - either SERVICE_RUNNING to start or SERVICE_STOPPED to stop
  413. Return Value:
  414. COM status
  415. --*/
  416. {
  417. HRESULT hresReturn = S_OK;
  418. DWORD dwId;
  419. EnterCriticalSection( &g_csKernelThreadUpdate );
  420. if ( dwState == SERVICE_STOPPED )
  421. {
  422. if ( g_hUserToKernelThread )
  423. {
  424. g_fStopUserToKernelThread = TRUE;
  425. SetEvent( g_UserToKernelUpdateEvent );
  426. WaitForSingleObject( g_hUserToKernelThread, INFINITE );
  427. CloseHandle( g_hUserToKernelThread );
  428. g_hUserToKernelThread = NULL;
  429. }
  430. }
  431. else
  432. {
  433. if ( g_hUserToKernelThread == NULL )
  434. {
  435. if ( (g_UserToKernelUpdateEvent = CreateEvent(
  436. NULL,
  437. FALSE,
  438. FALSE,
  439. NULL )) == NULL ||
  440. (g_hUserToKernelThread = CreateThread(
  441. NULL,
  442. 0,
  443. (LPTHREAD_START_ROUTINE)UserToKernelThread,
  444. (LPVOID)g_UserToKernelUpdateEvent,
  445. 0,
  446. &dwId )) == NULL )
  447. {
  448. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  449. }
  450. }
  451. }
  452. LeaveCriticalSection( &g_csKernelThreadUpdate );
  453. return hresReturn;
  454. }
  455. CIisLbSrvFactory::CIisLbSrvFactory(
  456. )
  457. /*++
  458. Routine Description:
  459. CIisLbSrvFactory constructor
  460. Arguments:
  461. None
  462. Return Value:
  463. Nothing
  464. --*/
  465. {
  466. m_dwRefCount=0;
  467. }
  468. CIisLbSrvFactory::~CIisLbSrvFactory(
  469. )
  470. /*++
  471. Routine Description:
  472. CIisLbSrvFactory destructor
  473. Arguments:
  474. None
  475. Return Value:
  476. Nothing
  477. --*/
  478. {
  479. }
  480. HRESULT
  481. CIisLbSrvFactory::CreateInstance(
  482. IUnknown *pUnkOuter,
  483. REFIID riid,
  484. void ** ppObject)
  485. /*++
  486. Routine Description:
  487. Create instances of CIisLb
  488. Arguments:
  489. pUnkOuter - controling unknown
  490. riid - Interface ID in
  491. ppObject - updated with ptr to interface on success
  492. Return Value:
  493. COM status
  494. --*/
  495. {
  496. CIisLb* pBl;
  497. if (pUnkOuter != NULL) {
  498. return CLASS_E_NOAGGREGATION;
  499. }
  500. if ( !LbAccessCheck( FILE_READ_DATA ) ) {
  501. return RETURNCODETOHRESULT( GetLastError() );
  502. }
  503. FlushLbAccessCheck();
  504. if ( (pBl = new CIisLb) == NULL ) {
  505. return E_NOINTERFACE;
  506. }
  507. if (FAILED(pBl->QueryInterface(riid, ppObject))) {
  508. delete pBl;
  509. return E_NOINTERFACE;
  510. }
  511. return NO_ERROR;
  512. }
  513. HRESULT
  514. CIisLbSrvFactory::LockServer(
  515. BOOL fLock
  516. )
  517. /*++
  518. Routine Description:
  519. Lock COM DLL
  520. Arguments:
  521. fLock - TRUE to lock, FALSE to unlock
  522. Return Value:
  523. COM status
  524. --*/
  525. {
  526. if (fLock) {
  527. InterlockedIncrement((long *)&g_dwRefCount);
  528. }
  529. else {
  530. InterlockedDecrement((long *)&g_dwRefCount);
  531. }
  532. return NO_ERROR;
  533. }
  534. HRESULT
  535. CIisLbSrvFactory::QueryInterface(
  536. REFIID riid,
  537. void **ppObject
  538. )
  539. /*++
  540. Routine Description:
  541. CIisLbSrvFactory QueryInterface
  542. Arguments:
  543. riid - Interface ID
  544. ppObject - updated with ptr to interface on success
  545. Return Value:
  546. status
  547. --*/
  548. {
  549. if (riid==IID_IUnknown || riid == IID_IClassFactory) {
  550. *ppObject = (IClassFactory *) this;
  551. }
  552. else {
  553. return E_NOINTERFACE;
  554. }
  555. AddRef();
  556. return NO_ERROR;
  557. }
  558. ULONG
  559. CIisLbSrvFactory::AddRef(
  560. )
  561. /*++
  562. Routine Description:
  563. CIisLbSrvFactory add reference to COM interface
  564. Arguments:
  565. None
  566. Return Value:
  567. reference count
  568. --*/
  569. {
  570. DWORD dwRefCount;
  571. InterlockedIncrement((long *)&g_dwRefCount);
  572. dwRefCount = InterlockedIncrement((long *)&m_dwRefCount);
  573. return dwRefCount;
  574. }
  575. ULONG
  576. CIisLbSrvFactory::Release(
  577. )
  578. /*++
  579. Routine Description:
  580. CIisLbSrvFactory release reference to COM interface
  581. delete object when reference count drops to zero
  582. Arguments:
  583. None
  584. Return Value:
  585. reference count
  586. --*/
  587. {
  588. DWORD dwRefCount;
  589. InterlockedDecrement((long *)&g_dwRefCount);
  590. dwRefCount = InterlockedDecrement((long *)&m_dwRefCount);
  591. if (dwRefCount == 0)
  592. {
  593. delete this;
  594. }
  595. return dwRefCount;
  596. }
  597. STDAPI BootDllRegisterServer(
  598. )
  599. /*++
  600. Routine Description:
  601. Register COM objects
  602. Arguments:
  603. None
  604. Return Value:
  605. COM status
  606. --*/
  607. {
  608. HKEY hKeyCLSID, hKeyInproc32;
  609. HKEY hKeyIF, hKeyStub32;
  610. HKEY hKeyAppExe, hKeyAppID, hKeyTemp;
  611. DWORD dwDisposition;
  612. //
  613. // register AppExe
  614. //
  615. HRESULT hr;
  616. //
  617. // register CLSID
  618. //
  619. if (RegCreateKeyEx(HKEY_CLASSES_ROOT,
  620. TEXT("CLSID\\{a9da4430-65c5-11d1-a700-00a0c922e752}"),
  621. NULL, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  622. &hKeyCLSID, &dwDisposition)!=ERROR_SUCCESS) {
  623. return E_UNEXPECTED;
  624. }
  625. if (RegSetValueEx(hKeyCLSID, TEXT(""), NULL, REG_SZ, (BYTE*) TEXT("IIS load balancing configuration"), sizeof(TEXT("load balancing configuration")))!=ERROR_SUCCESS) {
  626. RegCloseKey(hKeyCLSID);
  627. return E_UNEXPECTED;
  628. }
  629. if (RegSetValueEx(hKeyCLSID, TEXT("AppID"), NULL, REG_SZ, (BYTE*) TEXT("{a9da4430-65c5-11d1-a700-00a0c922e752}"), sizeof(TEXT("{a9da4430-65c5-11d1-a700-00a0c922e752}")))!=ERROR_SUCCESS) {
  630. RegCloseKey(hKeyCLSID);
  631. return E_UNEXPECTED;
  632. }
  633. {
  634. if (RegSetValueEx(hKeyCLSID, TEXT("LocalService"), NULL, REG_SZ, (BYTE*) TEXT(SZSERVICENAME), sizeof(TEXT(SZSERVICENAME)))!=ERROR_SUCCESS) {
  635. RegCloseKey(hKeyCLSID);
  636. return E_UNEXPECTED;
  637. }
  638. }
  639. RegCloseKey(hKeyCLSID);
  640. //
  641. // AppID
  642. //
  643. //
  644. // register CLSID
  645. //
  646. if (RegCreateKeyEx(HKEY_CLASSES_ROOT,
  647. TEXT("AppID\\{a9da4430-65c5-11d1-a700-00a0c922e752}"),
  648. NULL, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  649. &hKeyCLSID, &dwDisposition)!=ERROR_SUCCESS) {
  650. return E_UNEXPECTED;
  651. }
  652. if (RegSetValueEx(hKeyCLSID, TEXT(""), NULL, REG_SZ, (BYTE*) TEXT("IIS load balancing configuration"), sizeof(TEXT("IIS load balancing configuration")))!=ERROR_SUCCESS) {
  653. RegCloseKey(hKeyCLSID);
  654. return E_UNEXPECTED;
  655. }
  656. {
  657. if (RegSetValueEx(hKeyCLSID, TEXT("LocalService"), NULL, REG_SZ, (BYTE*) TEXT(SZSERVICENAME), sizeof(TEXT(SZSERVICENAME)))!=ERROR_SUCCESS) {
  658. RegCloseKey(hKeyCLSID);
  659. return E_UNEXPECTED;
  660. }
  661. }
  662. RegCloseKey(hKeyCLSID);
  663. //
  664. // Assign ACL to CLSID ( a la dcomcnfg ) granting access only to admins, current user
  665. // and system
  666. //
  667. ChangeAppIDAccessACL( "{a9da4430-65c5-11d1-a700-00a0c922e752}",
  668. "administrators",
  669. TRUE,
  670. TRUE );
  671. //
  672. // Main Interface
  673. //
  674. if (RegCreateKeyEx(HKEY_CLASSES_ROOT,
  675. TEXT("CLSID\\{996d0030-65c5-11d1-a700-00a0c922e752}"),
  676. NULL, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  677. &hKeyCLSID, &dwDisposition)!=ERROR_SUCCESS) {
  678. return E_UNEXPECTED;
  679. }
  680. if (RegSetValueEx(hKeyCLSID, TEXT(""), NULL, REG_SZ, (BYTE*) TEXT(SZSERVICENAME), sizeof(TEXT(SZSERVICENAME)))!=ERROR_SUCCESS) {
  681. RegCloseKey(hKeyCLSID);
  682. return E_UNEXPECTED;
  683. }
  684. if (RegCreateKeyEx(hKeyCLSID,
  685. "InprocServer32",
  686. NULL, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  687. &hKeyInproc32, &dwDisposition)!=ERROR_SUCCESS) {
  688. RegCloseKey(hKeyCLSID);
  689. return E_UNEXPECTED;
  690. }
  691. if (RegSetValueEx(hKeyInproc32, TEXT(""), NULL, REG_SZ, (BYTE*) "IISLBP.DLL", sizeof(TEXT("IISLBP.DLL")))!=ERROR_SUCCESS) {
  692. RegCloseKey(hKeyInproc32);
  693. RegCloseKey(hKeyCLSID);
  694. return E_UNEXPECTED;
  695. }
  696. if (RegSetValueEx(hKeyInproc32, TEXT("ThreadingModel"), NULL, REG_SZ, (BYTE*) "Both", sizeof("Both")-1 )!=ERROR_SUCCESS) {
  697. RegCloseKey(hKeyInproc32);
  698. RegCloseKey(hKeyCLSID);
  699. return E_UNEXPECTED;
  700. }
  701. RegCloseKey(hKeyInproc32);
  702. RegCloseKey(hKeyCLSID);
  703. //
  704. // register Interfaces
  705. //
  706. //
  707. // Main Interface
  708. //
  709. if (RegCreateKeyEx(HKEY_CLASSES_ROOT,
  710. TEXT("Interface\\{996d0030-65c5-11d1-a700-00a0c922e752}"),
  711. NULL, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  712. &hKeyIF, &dwDisposition)!=ERROR_SUCCESS) {
  713. return E_UNEXPECTED;
  714. }
  715. if (RegSetValueEx(hKeyIF, TEXT(""), NULL, REG_SZ, (BYTE*) TEXT(SZSERVICENAME), sizeof(TEXT(SZSERVICENAME)))!=ERROR_SUCCESS) {
  716. RegCloseKey(hKeyIF);
  717. return E_UNEXPECTED;
  718. }
  719. if (RegCreateKeyEx(hKeyIF,
  720. "ProxyStubClsid32",
  721. NULL, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  722. &hKeyStub32, &dwDisposition)!=ERROR_SUCCESS) {
  723. RegCloseKey(hKeyIF);
  724. return E_UNEXPECTED;
  725. }
  726. if (RegSetValueEx(hKeyStub32, TEXT(""), NULL, REG_SZ, (BYTE*)"{996d0030-65c5-11d1-a700-00a0c922e752}", sizeof("{996d0030-65c5-11d1-a700-00a0c922e752}") )!=ERROR_SUCCESS) {
  727. RegCloseKey(hKeyStub32);
  728. RegCloseKey(hKeyIF);
  729. return E_UNEXPECTED;
  730. }
  731. RegCloseKey(hKeyStub32);
  732. RegCloseKey(hKeyIF);
  733. return S_OK;
  734. }
  735. STDAPI
  736. BootDllUnregisterServer(
  737. void
  738. )
  739. /*++
  740. Routine Description:
  741. Unregister COM objects
  742. Arguments:
  743. None
  744. Return Value:
  745. COM status
  746. --*/
  747. {
  748. //
  749. // register AppID
  750. //
  751. RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("AppID\\{a9da4430-65c5-11d1-a700-00a0c922e752}"));
  752. //
  753. // register CLSID
  754. //
  755. RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("CLSID\\{a9da4430-65c5-11d1-a700-00a0c922e752}"));
  756. //
  757. // Main Interfaces
  758. //
  759. RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("CLSID\\{996d0030-65c5-11d1-a700-00a0c922e752}\\InprocServer32"));
  760. RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("CLSID\\{996d0030-65c5-11d1-a700-00a0c922e752}"));
  761. //
  762. // deregister Interfaces
  763. //
  764. RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Interface\\{996d0030-65c5-11d1-a700-00a0c922e752}\\ProxyStubClsid32"));
  765. RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("Interface\\{996d0030-65c5-11d1-a700-00a0c922e752}"));
  766. return S_OK;
  767. }
  768. BOOL
  769. InitGlobals(
  770. )
  771. /*++
  772. Routine Description:
  773. Initialize globals variables
  774. Arguments:
  775. None
  776. Return Value:
  777. TRUE if success, otherwise FALSE
  778. --*/
  779. {
  780. INITIALIZE_CRITICAL_SECTION( &g_csPerfList );
  781. INITIALIZE_CRITICAL_SECTION( &g_csIpListCheckpoint );
  782. INITIALIZE_CRITICAL_SECTION( &g_csIpListUpdate );
  783. INITIALIZE_CRITICAL_SECTION( &g_csAcl );
  784. INITIALIZE_CRITICAL_SECTION( &g_csKernelThreadUpdate );
  785. //
  786. // NT4 uses PdhOpenQuery, NT5 has Ansi/Unicode versions only
  787. //
  788. if ( (g_hPdh = LoadLibrary( "pdh.dll" )) )
  789. {
  790. g_pfnPdhOpenQuery = (PFN_OPEN_QUERY)GetProcAddress( g_hPdh,
  791. "PdhOpenQuery" );
  792. if ( g_pfnPdhOpenQuery == NULL )
  793. {
  794. g_pfnPdhOpenQuery = (PFN_OPEN_QUERY)GetProcAddress( g_hPdh,
  795. "PdhOpenQueryA" );
  796. if ( g_pfnPdhOpenQuery == NULL )
  797. {
  798. FreeLibrary( g_hPdh );
  799. g_hPdh = NULL;
  800. }
  801. }
  802. }
  803. if ( g_pfnPdhOpenQuery == NULL )
  804. {
  805. WCHAR achErr[32];
  806. LPCWSTR pA[1];
  807. pA[0] = achErr;
  808. _itow( GetLastError(), achErr, 10 );
  809. ReportIisLbEvent( EVENTLOG_ERROR_TYPE,
  810. IISLB_EVENT_PDH_ACCESS_ERROR,
  811. 1,
  812. pA );
  813. }
  814. if ( g_pfnPdhOpenQuery == NULL ||
  815. !g_KernelIpMap.Init() )
  816. {
  817. DeleteCriticalSection( &g_csPerfList );
  818. DeleteCriticalSection( &g_csIpListCheckpoint );
  819. DeleteCriticalSection( &g_csIpListUpdate );
  820. DeleteCriticalSection( &g_csAcl );
  821. DeleteCriticalSection( &g_csKernelThreadUpdate );
  822. return FALSE;
  823. }
  824. PdhGetDllVersion( &g_dwPdhVersion );
  825. return TRUE;
  826. }
  827. BOOL
  828. TerminateGlobals(
  829. )
  830. /*++
  831. Routine Description:
  832. Terminate globals variables
  833. Arguments:
  834. None
  835. Return Value:
  836. TRUE if success, otherwise FALSE
  837. --*/
  838. {
  839. //
  840. // stop perfmon threads
  841. //
  842. EnterCriticalSection( &g_csIpListCheckpoint );
  843. while ( g_KernelIpMap.ServerCount() )
  844. {
  845. //
  846. // do no wait for perfmon thread to stop : timeout is 0
  847. //
  848. g_KernelIpMap.StopServerThread( 0, 0 );
  849. EnterCriticalSection( &g_csIpListUpdate );
  850. g_KernelIpMap.RemoveServer( 0 );
  851. LeaveCriticalSection( &g_csIpListUpdate );
  852. }
  853. LeaveCriticalSection( &g_csIpListCheckpoint );
  854. if ( g_pAcl != NULL )
  855. {
  856. LocalFree( g_pAcl );
  857. g_pAcl = NULL;
  858. }
  859. DeleteCriticalSection( &g_csAcl );
  860. DeleteCriticalSection( &g_csPerfList );
  861. DeleteCriticalSection( &g_csIpListCheckpoint );
  862. DeleteCriticalSection( &g_csIpListUpdate );
  863. DeleteCriticalSection( &g_csKernelThreadUpdate );
  864. FreeLibrary( g_hPdh );
  865. return TRUE;
  866. }
  867. BOOL
  868. InitComLb(
  869. )
  870. /*++
  871. Routine Description:
  872. Init COM interface support & user mode <> kernel communication
  873. Arguments:
  874. None
  875. Return Value:
  876. TRUE if success, otherwise FALSE
  877. --*/
  878. {
  879. HRESULT hr;
  880. BOOL bReturn = TRUE;
  881. DWORD dwId;
  882. DEBUG_BUFFER;
  883. if ( WSAStartup( MAKEWORD( 2, 0), &g_WSAData ) != 0 )
  884. {
  885. DBG_PUTS( "can't init WSA\n" );
  886. return FALSE;
  887. }
  888. CoInitializeEx( NULL, COINIT_MULTITHREADED );
  889. InitOleSecurity();
  890. DBG_PUTS("InitComLb");
  891. {
  892. CIisLbSrvFactory *pADMClassFactory = new CIisLbSrvFactory;
  893. if ( pADMClassFactory == NULL )
  894. {
  895. DBG_PUTS("InitComLb:OOM");
  896. CoUninitialize();
  897. bReturn = FALSE;
  898. }
  899. else {
  900. if ( !InitGlobals() )
  901. {
  902. DBG_PUTS("InitComLb:Init");
  903. CoUninitialize();
  904. bReturn = FALSE;
  905. }
  906. else
  907. {
  908. //
  909. // register the class-object with OLE
  910. //
  911. hr = CoRegisterClassObject(CLSID_MSIisLb, pADMClassFactory,
  912. CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &g_dwComRegister);
  913. if (FAILED(hr))
  914. {
  915. DBG_PRINTF(( achE, "InitComLb:CoRegisterClassObject %08x %d", hr, hr ));
  916. bReturn = FALSE;
  917. CoUninitialize();
  918. delete pADMClassFactory;
  919. TerminateGlobals();
  920. }
  921. else
  922. {
  923. //
  924. // register COM object
  925. //
  926. if ( (g_UserToKernelUpdateEvent = CreateEvent(
  927. NULL,
  928. FALSE,
  929. FALSE,
  930. NULL )) == NULL ||
  931. (g_hUserToKernelThread = CreateThread(
  932. NULL,
  933. 0,
  934. (LPTHREAD_START_ROUTINE)UserToKernelThread,
  935. (LPVOID)g_UserToKernelUpdateEvent,
  936. 0,
  937. &dwId )) == NULL )
  938. {
  939. DBG_PUTS("InitComLb:CreateEvent/CreateThread");
  940. CoRevokeClassObject( g_dwComRegister );
  941. CoUninitialize();
  942. TerminateGlobals();
  943. bReturn = FALSE;
  944. }
  945. else
  946. {
  947. g_bInitialized = TRUE;
  948. }
  949. }
  950. }
  951. }
  952. }
  953. return bReturn;
  954. }
  955. BOOL
  956. TerminateComLb(
  957. )
  958. /*++
  959. Routine Description:
  960. Terminate COM interface support & user mode <> kernel communication
  961. Arguments:
  962. None
  963. Return Value:
  964. TRUE if success, otherwise FALSE
  965. --*/
  966. {
  967. if (g_bInitialized)
  968. {
  969. g_bInitialized = FALSE;
  970. CoRevokeClassObject( g_dwComRegister );
  971. // Stop user<>kernel mode thread
  972. EnterCriticalSection( &g_csKernelThreadUpdate );
  973. if ( g_hUserToKernelThread )
  974. {
  975. g_fStopUserToKernelThread = TRUE;
  976. SetEvent( g_UserToKernelUpdateEvent );
  977. WaitForSingleObject( g_hUserToKernelThread, INFINITE );
  978. CloseHandle( g_hUserToKernelThread );
  979. g_hUserToKernelThread = NULL;
  980. }
  981. LeaveCriticalSection( &g_csKernelThreadUpdate );
  982. TerminateGlobals();
  983. CoUninitialize();
  984. WSACleanup();
  985. }
  986. return TRUE;
  987. }
  988. BOOL
  989. KernelConfigToIpList(
  990. XBF* pxbf
  991. )
  992. /*++
  993. Routine Description:
  994. Retrieve serialized IP mapping configuration from kernel mode configuration
  995. Arguments:
  996. pxbf - ptr to buffer updated with serialized configuration
  997. Return Value:
  998. TRUE if success, otherwise FALSE
  999. --*/
  1000. {
  1001. CIPMap IpMap;
  1002. CKernelIpEndpointEx*pIp;
  1003. UINT iPublic;
  1004. UINT iServ;
  1005. UINT iRef;
  1006. WCHAR achAddr[128];
  1007. EnterCriticalSection( &g_csIpListCheckpoint );
  1008. for ( iServ = 0 ;
  1009. iServ < g_KernelIpMap.ServerCount() ;
  1010. ++iServ )
  1011. {
  1012. IpMap.AddComputer( g_KernelIpMap.GetServerName(iServ) );
  1013. }
  1014. // update public IP addresses list
  1015. for ( iPublic = 0 ;
  1016. iPublic < g_KernelIpMap.PublicIpCount() ;
  1017. ++iPublic )
  1018. {
  1019. pIp = g_KernelIpMap.GetPublicIpPtr( iPublic );
  1020. if ( !g_KernelIpMap.IpEndpointToString( (CKernelIpEndpoint*)pIp, achAddr, sizeof(achAddr) ) ||
  1021. !IpMap.AddIpPublic( achAddr, L"", pIp->m_dwSticky, 0 ) )
  1022. {
  1023. LeaveCriticalSection( &g_csIpListCheckpoint );
  1024. return FALSE;
  1025. }
  1026. }
  1027. // update private IP address for each ( server, public IP ) pairs
  1028. for ( iServ = 0 ;
  1029. iServ < g_KernelIpMap.ServerCount() ;
  1030. ++iServ )
  1031. {
  1032. for ( iPublic = 0 ;
  1033. iPublic < g_KernelIpMap.PublicIpCount() ;
  1034. ++iPublic )
  1035. {
  1036. if ( (iRef = *g_KernelIpMap.GetPrivateIpRef( g_KernelIpMap.GetServerPtr( iServ ),
  1037. iPublic )) == (UINT)-1 )
  1038. {
  1039. if ( !IpMap.SetIpPrivate( iServ, iPublic, L"", L"" ) )
  1040. {
  1041. LeaveCriticalSection( &g_csIpListCheckpoint );
  1042. return FALSE;
  1043. }
  1044. }
  1045. else if ( !g_KernelIpMap.IpEndpointToString(
  1046. (CKernelIpEndpoint*)g_KernelIpMap.GetPrivateIpEndpoint( iRef ),
  1047. achAddr,
  1048. sizeof(achAddr) ) ||
  1049. !IpMap.SetIpPrivate( iServ, iPublic, achAddr, L"" ) )
  1050. {
  1051. LeaveCriticalSection( &g_csIpListCheckpoint );
  1052. return FALSE;
  1053. }
  1054. }
  1055. }
  1056. LeaveCriticalSection( &g_csIpListCheckpoint );
  1057. return IpMap.Serialize( pxbf );
  1058. }
  1059. BOOL
  1060. IpListToKernelConfig(
  1061. CIPMap* pIpMap
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Set kernel mode configuration from serialized IP mapping configuration
  1066. Arguments:
  1067. pIpMap - IP mapping configuration
  1068. Return Value:
  1069. TRUE if success, otherwise FALSE
  1070. --*/
  1071. {
  1072. BOOL fSt = TRUE;
  1073. LPBOOL pbToBeAdded = NULL;
  1074. LPBOOL pbToBeDeleted = NULL;
  1075. UINT iCurrent;
  1076. UINT iNew;
  1077. LPWSTR pCurrent;
  1078. LPWSTR pNew;
  1079. DEBUG_BUFFER;
  1080. EnterCriticalSection( &g_csIpListCheckpoint );
  1081. DBG_PRINTF(( achE, "%d servers", pIpMap->ComputerCount() ));
  1082. if ( (pbToBeAdded = (LPBOOL)LocalAlloc( LPTR, sizeof(BOOL)*pIpMap->ComputerCount())) == NULL ||
  1083. (pbToBeDeleted = (LPBOOL)LocalAlloc( LPTR, sizeof(BOOL)*g_KernelIpMap.ServerCount())) == NULL )
  1084. {
  1085. fSt = FALSE;
  1086. goto cleanup;
  1087. }
  1088. // update to be deleted list
  1089. for ( iCurrent = 0 ;
  1090. iCurrent < g_KernelIpMap.ServerCount() ;
  1091. ++iCurrent )
  1092. {
  1093. pbToBeDeleted[iCurrent] = TRUE;
  1094. pCurrent = g_KernelIpMap.GetServerName( iCurrent );
  1095. for ( iNew = 0 ;
  1096. iNew < pIpMap->ComputerCount() ;
  1097. ++iNew )
  1098. {
  1099. pIpMap->EnumComputer( iNew, &pNew );
  1100. if ( !_wcsicmp( pCurrent, pNew ) )
  1101. {
  1102. pbToBeDeleted[iCurrent] = FALSE;
  1103. break;
  1104. }
  1105. }
  1106. if ( pbToBeDeleted[iCurrent] )
  1107. {
  1108. //
  1109. // Not an error to be unable to stop thread : might be stuck doing RPC
  1110. // as computer name will be removed from list ( protected by g_csIpListUpdate )
  1111. // thread will not find computer and will eventually exit.
  1112. //
  1113. g_KernelIpMap.StopServerThread( iCurrent, STOP_PERFMON_THREAD_TIMEOUT );
  1114. EnterCriticalSection( &g_csIpListUpdate );
  1115. g_KernelIpMap.RemoveServer( iCurrent );
  1116. LeaveCriticalSection( &g_csIpListUpdate );
  1117. --iCurrent; // because iCurrent was deleted
  1118. }
  1119. }
  1120. // update to be added list
  1121. for ( iNew = 0 ;
  1122. iNew < pIpMap->ComputerCount() ;
  1123. ++iNew )
  1124. {
  1125. pbToBeAdded[iNew] = TRUE;
  1126. pIpMap->EnumComputer( iNew, &pNew );
  1127. for ( iCurrent = 0 ;
  1128. iCurrent < g_KernelIpMap.ServerCount() ;
  1129. ++iCurrent )
  1130. {
  1131. pCurrent = g_KernelIpMap.GetServerName( iCurrent );
  1132. if ( !_wcsicmp( pCurrent, pNew ) )
  1133. {
  1134. pbToBeAdded[iNew] = FALSE;
  1135. break;
  1136. }
  1137. }
  1138. if ( pbToBeAdded[iNew] )
  1139. {
  1140. EnterCriticalSection( &g_csIpListUpdate );
  1141. fSt = g_KernelIpMap.AddServer( pNew );
  1142. LeaveCriticalSection( &g_csIpListUpdate );
  1143. if ( !fSt )
  1144. {
  1145. break;
  1146. }
  1147. if ( !(fSt = g_KernelIpMap.StartServerThread( iCurrent )) )
  1148. {
  1149. break;
  1150. }
  1151. }
  1152. }
  1153. // update public IP list
  1154. if ( fSt )
  1155. {
  1156. EnterCriticalSection( &g_csIpListUpdate );
  1157. fSt = g_KernelIpMap.SetPublicIpList( pIpMap );
  1158. LeaveCriticalSection( &g_csIpListUpdate );
  1159. }
  1160. cleanup:
  1161. if ( pbToBeAdded )
  1162. {
  1163. LocalFree( pbToBeAdded );
  1164. }
  1165. if ( pbToBeDeleted )
  1166. {
  1167. LocalFree( pbToBeDeleted );
  1168. }
  1169. LeaveCriticalSection( &g_csIpListCheckpoint );
  1170. return fSt;
  1171. }
  1172. BOOL
  1173. KernelConfigToPerfmonCounters(
  1174. XBF* pxbf
  1175. )
  1176. /*++
  1177. Routine Description:
  1178. Retrieve serialized perfmon counters configuration from kernel mode configuration
  1179. Arguments:
  1180. pxbf - ptr to buffer updated with serialized configuration
  1181. Return Value:
  1182. TRUE if success, otherwise FALSE
  1183. --*/
  1184. {
  1185. BOOL fSt;
  1186. EnterCriticalSection( &g_csPerfList );
  1187. fSt = g_PerfmonCounterList.Serialize( pxbf );
  1188. LeaveCriticalSection( &g_csPerfList );
  1189. return fSt;
  1190. }
  1191. BOOL
  1192. PerfmonCountersToKernelConfig(
  1193. CComputerPerfCounters* pPerfmonCounters
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. Set kernel mode configuration from perfmon counters configuration
  1198. Arguments:
  1199. pPerfmonCounters - perfmon counters configuration
  1200. Return Value:
  1201. TRUE if success, otherwise FALSE
  1202. --*/
  1203. {
  1204. XBF xbf;
  1205. UINT iS;
  1206. EnterCriticalSection( &g_csPerfList );
  1207. if ( !pPerfmonCounters->Serialize( &xbf ) ||
  1208. !g_PerfmonCounterList.Unserialize( &xbf ) )
  1209. {
  1210. return FALSE;
  1211. }
  1212. LeaveCriticalSection( &g_csPerfList );
  1213. // refresh perf list for each computer
  1214. for ( iS = 0 ;
  1215. iS < g_KernelIpMap.ServerCount() ;
  1216. ++iS )
  1217. {
  1218. //
  1219. // if can't stop thread then do not restart it.
  1220. //
  1221. if ( !g_KernelIpMap.StopServerThread( iS, STOP_PERFMON_THREAD_TIMEOUT ) ||
  1222. !g_KernelIpMap.StartServerThread( iS ) )
  1223. {
  1224. continue;
  1225. }
  1226. }
  1227. return TRUE;
  1228. }
  1229. CKernelIpMapHelper::CKernelIpMapHelper(
  1230. )
  1231. /*++
  1232. Routine Description:
  1233. CKernelIpMapHelper constructor
  1234. Arguments:
  1235. None
  1236. Return Value:
  1237. Nothing
  1238. --*/
  1239. {
  1240. }
  1241. BOOL
  1242. CKernelIpMapHelper::Init(
  1243. )
  1244. /*++
  1245. Routine Description:
  1246. Initialize kernel configuration object
  1247. Arguments:
  1248. None
  1249. Return Value:
  1250. TRUE if success, otherwise FALSE
  1251. --*/
  1252. {
  1253. CComputerPerfCounters PerfmonCounters;
  1254. DWORD dwStickyDuration;
  1255. LPBYTE pB;
  1256. DWORD dwC;
  1257. XBF xbf;
  1258. DEBUG_BUFFER;
  1259. if ( (m_pKernelIpMap = (CKernelIpMap*)LocalAlloc( LMEM_FIXED, sizeof(CKernelIpMap) )) == NULL )
  1260. {
  1261. DBG_PUTS("InitComLb:OOM");
  1262. return FALSE;
  1263. }
  1264. m_pKernelIpMap->m_dwServerCount = 0;
  1265. m_pKernelIpMap->m_dwPublicIpCount = 0;
  1266. m_pKernelIpMap->m_dwPrivateIpCount = 0;
  1267. m_pKernelIpMap->m_dwStickyDuration = DEFAULT_STICKY_DURATION;
  1268. if ( g_IpMap.Load( HKEY_LOCAL_MACHINE,
  1269. IISLOADBAL_REGISTRY_KEY,
  1270. IPLIST_REGISTRY_VALUE ) )
  1271. {
  1272. if ( !IpListToKernelConfig( &g_IpMap ) )
  1273. {
  1274. DBG_PUTS("!IpListToKernelConfig");
  1275. return FALSE;
  1276. }
  1277. }
  1278. else if ( GetLastError() != ERROR_FILE_NOT_FOUND )
  1279. {
  1280. DBG_PRINTF(( achE, "Err read registry line %d : %08x %d\n", __LINE__, GetLastError(), GetLastError() ));
  1281. return FALSE;
  1282. }
  1283. if ( PerfmonCounters.Load( HKEY_LOCAL_MACHINE,
  1284. IISLOADBAL_REGISTRY_KEY,
  1285. PERFMON_REGISTRY_VALUE ) )
  1286. {
  1287. if ( !PerfmonCountersToKernelConfig( &PerfmonCounters ) )
  1288. {
  1289. DBG_PUTS("!IpListToKernelConfig");
  1290. return FALSE;
  1291. }
  1292. }
  1293. else if ( GetLastError() != ERROR_FILE_NOT_FOUND )
  1294. {
  1295. DBG_PRINTF(( achE, "Err read registry line %d : %08x %d\n", __LINE__, GetLastError(), GetLastError() ));
  1296. return FALSE;
  1297. }
  1298. if ( LoadBlobFromReg( HKEY_LOCAL_MACHINE,
  1299. IISLOADBAL_REGISTRY_KEY,
  1300. STICKY_REGISTRY_VALUE,
  1301. &xbf ) )
  1302. {
  1303. pB = xbf.GetBuff();
  1304. dwC = xbf.GetUsed();
  1305. if ( !Unserialize( &pB, &dwC, &dwStickyDuration ) )
  1306. {
  1307. DBG_PUTS("!SetStickyDuration");
  1308. return FALSE;
  1309. }
  1310. g_KernelIpMap.SetStickyDuration( dwStickyDuration );
  1311. }
  1312. else if ( GetLastError() != ERROR_FILE_NOT_FOUND )
  1313. {
  1314. DBG_PRINTF(( achE, "Err read registry line %d : %08x %d\n", __LINE__, GetLastError(), GetLastError() ));
  1315. return FALSE;
  1316. }
  1317. return TRUE;
  1318. }
  1319. BOOL
  1320. CKernelIpMapHelper::SetPublicIpList(
  1321. CIPMap* pIpMap
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. Update public IP list from CIPMap object
  1326. Arguments:
  1327. pIpMap - public -> private IP addresses mapping
  1328. Return Value:
  1329. TRUE if success, otherwise FALSE
  1330. --*/
  1331. {
  1332. UINT iNew;
  1333. LPWSTR pNewEntry;
  1334. CKernelIpEndpoint* pIp;
  1335. UINT cNewSize;
  1336. LPBYTE pNew;
  1337. UINT iP;
  1338. UINT iS;
  1339. CKernelServerDescription* pNewServer;
  1340. CKernelServerDescription* pOldServer;
  1341. CKernelIpEndpoint ieNew;
  1342. UINT iPrv;
  1343. LPWSTR pName;
  1344. DWORD dwSticky;
  1345. DWORD dwAttr;
  1346. DEBUG_BUFFER;
  1347. // build private IP list of unique private IP in pIpMap
  1348. // ( as array of CKernelIpEndpoint )
  1349. ResetPrivateIpList();
  1350. for ( iS = 0 ;
  1351. iS < ServerCount() ;
  1352. ++iS )
  1353. {
  1354. for ( iP = 0 ;
  1355. iP < pIpMap->IpPublicCount() ;
  1356. ++iP )
  1357. {
  1358. if ( !pIpMap->GetIpPrivate( iS, iP, &pNewEntry, &pName ) ||
  1359. !StringToIpEndpoint( pNewEntry, &ieNew ) )
  1360. {
  1361. return FALSE;
  1362. }
  1363. // do not add if private Ip address is NULL, i.e. invalid
  1364. if ( ieNew.m_dwIpAddress != 0 &&
  1365. !CheckAndAddPrivateIp( &ieNew, TRUE, NULL ) )
  1366. {
  1367. return FALSE;
  1368. }
  1369. }
  1370. }
  1371. // resize array
  1372. cNewSize = GetSize( ServerCount(), pIpMap->IpPublicCount(), PrivateIpListCount() );
  1373. DBG_PRINTF(( achE, "SetPublicIpList: SrvCount=%d pub=%d prv=%d sz=%d\n",
  1374. ServerCount(), pIpMap->IpPublicCount(), PrivateIpListCount(), cNewSize ));
  1375. if ( (pNew = (LPBYTE)LocalAlloc( LMEM_FIXED, cNewSize )) == NULL )
  1376. {
  1377. return FALSE;
  1378. }
  1379. *(CKernelIpMap*)pNew = *m_pKernelIpMap;
  1380. ((CKernelIpMap*)pNew)->m_dwPublicIpCount = pIpMap->IpPublicCount();
  1381. // store private IP list
  1382. for ( iP = 0 ;
  1383. EnumPrivateIpList( iP, &pIp ) ;
  1384. ++iP )
  1385. {
  1386. memcpy( GetPrivateIpEndpoint( iP, pNew ), pIp, sizeof(CKernelIpEndpoint) );
  1387. }
  1388. ((CKernelIpMap*)pNew)->m_dwPrivateIpCount = iP;
  1389. // load private IP addresses
  1390. for ( iS = 0 ;
  1391. iS < ServerCount() ;
  1392. ++iS )
  1393. {
  1394. pNewServer = GetServerPtr( iS, pNew, pIpMap->IpPublicCount(), PrivateIpListCount() );
  1395. pOldServer = GetServerPtr( iS );
  1396. memcpy( pNewServer, pOldServer, sizeof(CKernelServerDescription) );
  1397. for ( iP = 0 ;
  1398. iP < pIpMap->IpPublicCount() ;
  1399. ++iP )
  1400. {
  1401. // transcode private IP addr
  1402. if ( !pIpMap->GetIpPrivate( iS, iP, &pNewEntry, &pName ) ||
  1403. !StringToIpEndpoint( pNewEntry, &ieNew) )
  1404. {
  1405. return FALSE;
  1406. }
  1407. DBG_PRINTF(( achE, "(s=%d,i=%d) -> %ws, IP = %08x\n",
  1408. iS, iP, pNewEntry, ieNew.m_dwIpAddress ));
  1409. if ( ieNew.m_dwIpAddress == 0 )
  1410. {
  1411. // if no mapping then store as invalid index
  1412. iPrv = (UINT)-1;
  1413. }
  1414. else if ( !CheckAndAddPrivateIp( &ieNew, FALSE, &iPrv ) ||
  1415. iPrv == (UINT)-1 )
  1416. {
  1417. return FALSE;
  1418. }
  1419. *GetPrivateIpRef( pNewServer, iP ) = iPrv;
  1420. DBG_PRINTF(( achE, "pNew=%08x, pNewServer=%08x, IpRef(%d)=%08x : %u\n",
  1421. pNew, pNewServer, iP, GetPrivateIpRef( pNewServer, iP ), iPrv ));
  1422. }
  1423. }
  1424. LocalFree(m_pKernelIpMap);
  1425. m_pKernelIpMap = (CKernelIpMap*)pNew;
  1426. // store public ip addresses
  1427. for ( iNew = 0 ;
  1428. iNew < pIpMap->IpPublicCount() ;
  1429. ++iNew )
  1430. {
  1431. pIpMap->EnumIpPublic( iNew, &pNewEntry, &pName, &dwSticky, &dwAttr );
  1432. if ( !StringToIpEndpoint( pNewEntry, (CKernelIpEndpoint*)GetPublicIpPtr( iNew ) ) )
  1433. {
  1434. return FALSE;
  1435. }
  1436. GetPublicIpPtr( iNew )->m_dwSticky = dwSticky;
  1437. }
  1438. return TRUE;
  1439. }
  1440. BOOL
  1441. CKernelIpMapHelper::StringToIpEndpoint(
  1442. LPWSTR pNew,
  1443. CKernelIpEndpoint* pIp
  1444. )
  1445. /*++
  1446. Routine Description:
  1447. Convert string ( IP_ADDR:PORT_# ) to IP endpoint object ( sockaddr_in )
  1448. Arguments:
  1449. pNew - string representation of IP address + port #
  1450. pIp - updated with IP address + port # in sockaddr_in
  1451. Return Value:
  1452. TRUE if success, otherwise FALSE
  1453. --*/
  1454. {
  1455. SOCKADDR sockaddr;
  1456. int csockaddr;
  1457. LPWSTR pPort;
  1458. BOOL fSt = FALSE;
  1459. DEBUG_BUFFER;
  1460. if ( pPort = wcschr( pNew, L':' ) )
  1461. {
  1462. *pPort = L'\0';
  1463. csockaddr = sizeof(sockaddr);
  1464. if ( WSAStringToAddressW( pNew, AF_INET, NULL, &sockaddr, &csockaddr ) == 0 )
  1465. {
  1466. memcpy( &pIp->m_dwIpAddress,
  1467. &((sockaddr_in*)&sockaddr)->sin_addr,
  1468. sizeof(pIp->m_dwIpAddress) );
  1469. pIp->m_usPort = htons((u_short)_wtoi(pPort +1));
  1470. fSt = TRUE;
  1471. }
  1472. else
  1473. {
  1474. DBG_PRINTF(( achE, "WSAStringToAddress error: %d\n", WSAGetLastError() ));
  1475. }
  1476. *pPort = L':';
  1477. }
  1478. else if ( *pNew )
  1479. {
  1480. csockaddr = sizeof(sockaddr);
  1481. if ( WSAStringToAddressW( pNew, AF_INET, NULL, &sockaddr, &csockaddr ) == 0 )
  1482. {
  1483. memcpy( &pIp->m_dwIpAddress,
  1484. &((sockaddr_in*)&sockaddr)->sin_addr,
  1485. sizeof(pIp->m_dwIpAddress) );
  1486. pIp->m_usPort = htons(DEFAULT_IP_PORT);
  1487. fSt = TRUE;
  1488. }
  1489. else
  1490. {
  1491. DBG_PRINTF(( achE, "WSAStringToAddress error: %d\n", WSAGetLastError() ));
  1492. }
  1493. }
  1494. else
  1495. {
  1496. memset( &pIp->m_dwIpAddress,
  1497. '\0',
  1498. sizeof(pIp->m_dwIpAddress) );
  1499. pIp->m_usPort = 0;
  1500. fSt = TRUE;
  1501. }
  1502. return fSt;
  1503. }
  1504. BOOL
  1505. CKernelIpMapHelper::IpEndpointToString(
  1506. CKernelIpEndpoint* pIp,
  1507. LPWSTR pAddr,
  1508. DWORD cAddr
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. Convert IP endpoint object ( sockaddr_in ) to string ( IP_ADDR:PORT_# )
  1513. Arguments:
  1514. pIp - IP address + port # in sockaddr_in
  1515. pAddr - updated with string representation of IP address + port # on success
  1516. cAddr - size of pAddr on input
  1517. Return Value:
  1518. TRUE if success, otherwise FALSE
  1519. --*/
  1520. {
  1521. SOCKADDR sockaddr;
  1522. BOOL fSt = FALSE;
  1523. if ( pIp->m_dwIpAddress != 0 )
  1524. {
  1525. ((sockaddr_in*)&sockaddr)->sin_family = AF_INET;
  1526. memcpy( &((sockaddr_in*)&sockaddr)->sin_addr,
  1527. &pIp->m_dwIpAddress,
  1528. sizeof(pIp->m_dwIpAddress) );
  1529. ((sockaddr_in*)&sockaddr)->sin_port = pIp->m_usPort;
  1530. if ( WSAAddressToStringW( &sockaddr, sizeof(sockaddr), NULL, pAddr, &cAddr ) == 0 )
  1531. {
  1532. fSt = TRUE;
  1533. }
  1534. }
  1535. else
  1536. {
  1537. *pAddr = L'\0';
  1538. fSt = TRUE;
  1539. }
  1540. return fSt;
  1541. }
  1542. BOOL
  1543. CKernelIpMapHelper::AddServer(
  1544. LPWSTR pNewServer
  1545. )
  1546. /*++
  1547. Routine Description:
  1548. Add a server to kernel configuration
  1549. Arguments:
  1550. pNewServer - server name
  1551. Return Value:
  1552. TRUE if success, otherwise FALSE
  1553. --*/
  1554. {
  1555. LPBYTE pNew;
  1556. UINT cNewSize;
  1557. UINT iS;
  1558. DEBUG_BUFFER;
  1559. cNewSize = GetSize( ServerCount()+1, PublicIpCount(), PrivateIpCount() );
  1560. DBG_PRINTF(( achE, "cNewSize = %d", cNewSize ));
  1561. if ( (pNew = (LPBYTE)LocalAlloc( LMEM_FIXED, cNewSize )) == NULL )
  1562. {
  1563. return FALSE;
  1564. }
  1565. if ( m_ServerNames.AddEntry( pNewServer ) == INDEX_ERROR ||
  1566. m_PerfmonThreadHandle.AddPtr( NULL ) == INDEX_ERROR ||
  1567. m_PerfmonThreadStopEvent.AddPtr( NULL ) == INDEX_ERROR )
  1568. {
  1569. return FALSE;
  1570. }
  1571. // copy existing
  1572. memcpy( pNew, m_pKernelIpMap, GetSize(ServerCount(), PublicIpCount(), PrivateIpCount() ) );
  1573. DBG_PRINTF(( achE, "memcpy( %08x, %08x, %d", pNew, m_pKernelIpMap, GetSize(ServerCount(), PublicIpCount(), PrivateIpCount() ) ));
  1574. LocalFree(m_pKernelIpMap);
  1575. m_pKernelIpMap = (CKernelIpMap*)pNew;
  1576. // init new entry
  1577. memset( GetServerPtr( ServerCount() ), '\0', GetKernelServerDescriptionSize() );
  1578. DBG_PRINTF(( achE, "memset( %08x, %d", GetServerPtr( ServerCount() ), GetKernelServerDescriptionSize() ));
  1579. for ( iS = 0 ;
  1580. iS < LOADBAL_SAMPLES ;
  1581. ++iS )
  1582. {
  1583. GetServerPtr( ServerCount() )->m_flLoadAvail[iS] = 0;
  1584. }
  1585. DBG_PRINTF(( achE, "memset( %08x, %d", GetServerPtr( ServerCount() ), GetKernelServerDescriptionSize() ));
  1586. ++m_pKernelIpMap->m_dwServerCount;
  1587. DBG_PRINTF(( achE, "m_dwServerCount %d", m_pKernelIpMap->m_dwServerCount ));
  1588. return TRUE;
  1589. }
  1590. BOOL
  1591. CKernelIpMapHelper::RemoveServer(
  1592. UINT i
  1593. )
  1594. /*++
  1595. Routine Description:
  1596. Remove a server from kernel configuration
  1597. Arguments:
  1598. i - server index ( 0-based )
  1599. Return Value:
  1600. TRUE if success, otherwise FALSE
  1601. --*/
  1602. {
  1603. LPBYTE pNew;
  1604. UINT cNewSize;
  1605. if ( !m_ServerNames.DeleteEntry( i ) ||
  1606. !m_PerfmonThreadHandle.DeletePtr( i ) ||
  1607. !m_PerfmonThreadStopEvent.DeletePtr( i ) )
  1608. {
  1609. return FALSE;
  1610. }
  1611. // remove CKernelServerDescription entry
  1612. // do not reallocate storage ( SetPublicIpList() will typically be called after
  1613. // this function )
  1614. memmove( GetServerPtr(i),
  1615. GetServerPtr(i+1),
  1616. GetKernelServerDescriptionSize() * (ServerCount()-i-1) );
  1617. --m_pKernelIpMap->m_dwServerCount;
  1618. return TRUE;
  1619. }
  1620. BOOL
  1621. CKernelIpMapHelper::StopServerThread(
  1622. DWORD iServer,
  1623. DWORD dwTimeout
  1624. )
  1625. /*++
  1626. Routine Description:
  1627. Stop the thread monitoring perfmon counters for a specific server
  1628. Arguments:
  1629. iServer - server index ( 0-based )
  1630. Return Value:
  1631. TRUE if success, otherwise FALSE
  1632. --*/
  1633. {
  1634. BOOL fSt = FALSE;
  1635. // request thread to stop
  1636. if ( SetEvent( (HANDLE)m_PerfmonThreadStopEvent.GetPtr( iServer ) ) &&
  1637. WaitForSingleObject( (HANDLE)m_PerfmonThreadHandle.GetPtr( iServer ), dwTimeout ) == WAIT_OBJECT_0 )
  1638. {
  1639. fSt = TRUE;
  1640. }
  1641. // close thread handle
  1642. if ( (HANDLE)m_PerfmonThreadHandle.GetPtr( iServer ) )
  1643. {
  1644. CloseHandle( (HANDLE)m_PerfmonThreadHandle.GetPtr( iServer ) );
  1645. m_PerfmonThreadHandle.SetPtr( iServer, NULL );
  1646. }
  1647. m_PerfmonThreadStopEvent.SetPtr( iServer, NULL );
  1648. return fSt;
  1649. }
  1650. BOOL
  1651. CKernelIpMapHelper::StartServerThread(
  1652. DWORD iServer
  1653. )
  1654. /*++
  1655. Routine Description:
  1656. Start the thread monitoring perfmon counters for a specific server
  1657. Arguments:
  1658. iServer - server index ( 0-based )
  1659. Return Value:
  1660. TRUE if success, otherwise FALSE
  1661. --*/
  1662. {
  1663. CPerfmonThreadControlBlock* pCB = NULL;
  1664. HANDLE hThread;
  1665. DWORD dwId;
  1666. if ( pCB = new CPerfmonThreadControlBlock)
  1667. {
  1668. if ( ( pCB->m_hStopEvent = CreateEvent( NULL, TRUE, FALSE, NULL )) == NULL )
  1669. {
  1670. goto cleanup;
  1671. }
  1672. if ( !pCB->m_ServerName.Set( GetServerName( iServer ) ) )
  1673. {
  1674. goto cleanup;
  1675. }
  1676. GetServerPtr( iServer )->m_cNbSamplesAvail = 0;
  1677. GetServerPtr( iServer )->m_dwHeartbeat = UNAVAIL_HEARTBEAT;
  1678. if ( (hThread = CreateThread( NULL,
  1679. 0,
  1680. (LPTHREAD_START_ROUTINE)PermonThread,
  1681. (LPVOID)pCB,
  1682. 0,
  1683. &dwId )) == NULL )
  1684. {
  1685. goto cleanup;
  1686. }
  1687. m_PerfmonThreadHandle.SetPtr( iServer, (LPVOID)hThread );
  1688. m_PerfmonThreadStopEvent.SetPtr( iServer, (LPVOID)pCB->m_hStopEvent );
  1689. return TRUE;
  1690. }
  1691. cleanup:
  1692. if ( pCB )
  1693. {
  1694. if ( pCB->m_hStopEvent != NULL )
  1695. {
  1696. CloseHandle( pCB->m_hStopEvent );
  1697. }
  1698. delete pCB;
  1699. }
  1700. return FALSE;
  1701. }
  1702. extern "C" DWORD WINAPI
  1703. PermonThread(
  1704. LPVOID pV
  1705. )
  1706. /*++
  1707. Routine Description:
  1708. Thread monitoring perfmon counters for a specific server
  1709. update & reference g_KernelIpMap
  1710. reference g_csPerfList
  1711. Arguments:
  1712. pV - ptr to CPerfmonThreadControlBlock
  1713. This function will have to cleanup resources associated with this control
  1714. block on thread exit.
  1715. Return Value:
  1716. NT status
  1717. --*/
  1718. {
  1719. HQUERY hQuery;
  1720. PDH_STATUS pdhStatus;
  1721. CPtrXBF CounterArray;
  1722. CPtrXBF Weight;
  1723. DWORD dwWeight;
  1724. HCOUNTER hCounter;
  1725. LPWSTR pszPerfCounter;
  1726. LPDWORD pdwWeight = NULL;
  1727. UINT cComputerName;
  1728. CAllocString ComputerPlusPerfmonCounter;
  1729. UINT iPerf;
  1730. UINT iPerfName;
  1731. BOOL fCreatedCounters = FALSE;
  1732. UINT iServ;
  1733. UINT cPerf;
  1734. double dbAvail;
  1735. double dbAcc;
  1736. UINT cInst;
  1737. PDH_FMT_COUNTERVALUE fmtValue;
  1738. DWORD ctrType;
  1739. UINT iSample = 0;
  1740. CKernelServerDescription* pServerInfo;
  1741. LPWSTR pDel;
  1742. WCHAR ch;
  1743. WCHAR achInstance[32];
  1744. UINT iInstance;
  1745. DWORD dwZero;
  1746. DWORD dwSizeInstanceList;
  1747. WCHAR achInstanceList[3000];
  1748. LPWSTR pIns;
  1749. LPWSTR pszPerfServer;
  1750. time_t tStartCollect;
  1751. BOOL fNormalized = FALSE;
  1752. DEBUG_BUFFER;
  1753. CPerfmonThreadControlBlock* pCB = (CPerfmonThreadControlBlock*)pV;
  1754. cComputerName = wcslen( pCB->m_ServerName.Get() );
  1755. for ( ;
  1756. ;
  1757. )
  1758. {
  1759. // query counters
  1760. if ( !fCreatedCounters )
  1761. {
  1762. DBG_PRINTF(( achE, "%ws: create counters\n",
  1763. pCB->m_ServerName.Get() ));
  1764. if ( g_PerfmonCounterList.PerfCounterCount() == 0 )
  1765. {
  1766. goto waitnext;
  1767. }
  1768. pdhStatus = g_pfnPdhOpenQuery (0, 0, &hQuery);
  1769. if ( pdhStatus != ERROR_SUCCESS )
  1770. {
  1771. return pdhStatus;
  1772. }
  1773. #if 0
  1774. pdhStatus = PdhConnectMachineW( pCB->m_ServerName.Get() );
  1775. DBG_PRINTF(( achE, "%ws: connect to machine : %x\n",
  1776. pCB->m_ServerName.Get(), pdhStatus ));
  1777. #endif
  1778. CounterArray.Reset();
  1779. Weight.Reset();
  1780. EnterCriticalSection( &g_csPerfList );
  1781. for ( iPerfName = 0, iPerf = 0 ;
  1782. g_PerfmonCounterList.EnumPerfCounter( iPerfName, &pszPerfServer, &pszPerfCounter, &dwWeight ) ;
  1783. ++iPerfName )
  1784. {
  1785. // if server name was specified in perf counter list, check we are using
  1786. // this server
  1787. if ( pszPerfServer != NULL )
  1788. {
  1789. // skip possible leading "\\"
  1790. if ( *pszPerfServer == L'\\' )
  1791. {
  1792. pszPerfServer += (sizeof(L"\\\\") / sizeof(WCHAR)) -1;
  1793. }
  1794. if ( _wcsicmp( pszPerfServer, pCB->m_ServerName.Get() ) )
  1795. {
  1796. continue;
  1797. }
  1798. }
  1799. // combine computer name & perf name
  1800. ComputerPlusPerfmonCounter.Reset();
  1801. if ( !IncludeServerName( pszPerfCounter ) &&
  1802. (!ComputerPlusPerfmonCounter.Set( L"\\\\" ) ||
  1803. !ComputerPlusPerfmonCounter.Append( pCB->m_ServerName.Get() )) )
  1804. {
  1805. eallocname:
  1806. LeaveCriticalSection( &g_csPerfList );
  1807. return ERROR_NOT_ENOUGH_MEMORY;
  1808. }
  1809. //
  1810. // If this is a multi-instance object, we need to enumerate
  1811. // all instances. Each instance will be a separate counter, but all of the
  1812. // counters for a given object will be averaged before being added to the
  1813. // composite load.
  1814. //
  1815. if ( (pDel = wcschr( pszPerfCounter, L'(' )) &&
  1816. iswdigit( pDel[1] ) )
  1817. {
  1818. dwSizeInstanceList = sizeof(achInstanceList) / sizeof(WCHAR);
  1819. dwZero = 0;
  1820. *pDel = L'\0';
  1821. pdhStatus = PdhEnumObjectItemsW( NULL,
  1822. pCB->m_ServerName.Get(),
  1823. pszPerfCounter + 1,
  1824. NULL, // don't need Counter list
  1825. &dwZero,
  1826. achInstanceList,
  1827. &dwSizeInstanceList,
  1828. 100,
  1829. 0 );
  1830. if ( pdhStatus == ERROR_SUCCESS &&
  1831. dwSizeInstanceList )
  1832. {
  1833. for ( pIns = achInstanceList ;
  1834. *pIns;
  1835. pIns += wcslen( pIns ) + 1 )
  1836. {
  1837. //
  1838. // do not consider meta instances ( e.g. _Total )
  1839. //
  1840. if ( *pIns == '_' )
  1841. {
  1842. continue;
  1843. }
  1844. ComputerPlusPerfmonCounter.Reset();
  1845. //
  1846. // Add an instance
  1847. //
  1848. if ( !IncludeServerName( pszPerfCounter ) &&
  1849. (!ComputerPlusPerfmonCounter.Set( L"\\\\" ) ||
  1850. !ComputerPlusPerfmonCounter.Append( pCB->m_ServerName.Get() )) )
  1851. {
  1852. *pDel = L'(';
  1853. goto eallocname;
  1854. }
  1855. if ( !ComputerPlusPerfmonCounter.Append( pszPerfCounter ) ||
  1856. !ComputerPlusPerfmonCounter.Append( L"(" ) ||
  1857. !ComputerPlusPerfmonCounter.Append( pIns ) ||
  1858. !ComputerPlusPerfmonCounter.Append( wcschr(pDel+1,')') ) )
  1859. {
  1860. *pDel = L'(';
  1861. goto eallocname;
  1862. }
  1863. if ( (pdhStatus = PdhAddCounterW( hQuery,
  1864. ComputerPlusPerfmonCounter.Get(),
  1865. 0,
  1866. &hCounter )) != ERROR_SUCCESS )
  1867. {
  1868. DBG_PRINTF(( achE, "%ws: PdhAddCounterW %ws failed : %x\n",
  1869. pCB->m_ServerName.Get(),
  1870. ComputerPlusPerfmonCounter.Get(),
  1871. pdhStatus ));
  1872. break;
  1873. }
  1874. //
  1875. // All instances after 1st one will have dwWeight set to -1
  1876. //
  1877. if ( CounterArray.AddPtr( (LPVOID)hCounter ) == INDEX_ERROR ||
  1878. Weight.AddPtr( (LPVOID)dwWeight ) == INDEX_ERROR )
  1879. {
  1880. *pDel = L'(';
  1881. goto eallocname;
  1882. }
  1883. dwWeight = (DWORD)-1;
  1884. ++iPerf;
  1885. }
  1886. *pDel = L'(';
  1887. }
  1888. else
  1889. {
  1890. if ( pdhStatus == ERROR_SUCCESS )
  1891. {
  1892. pdhStatus = PDH_CSTATUS_NO_OBJECT;
  1893. }
  1894. // can't enumerate instances
  1895. *pDel = '(';
  1896. WCHAR achErr[32];
  1897. LPCWSTR pA[3];
  1898. pA[0] = pszPerfCounter;
  1899. pA[1] = pCB->m_ServerName.Get();
  1900. pA[2] = achErr;
  1901. _itow( pdhStatus, achErr, 10 );
  1902. ReportIisLbEvent( EVENTLOG_ERROR_TYPE,
  1903. IISLB_EVENT_COUNTER_ENUM_ERROR,
  1904. 1,
  1905. pA );
  1906. DBG_PRINTF(( achE, "%ws: PdhEnumObjectItemsW %ws failed : %x\n",
  1907. pCB->m_ServerName.Get(), pszPerfCounter, pdhStatus ));
  1908. break;
  1909. }
  1910. }
  1911. else
  1912. {
  1913. if ( !ComputerPlusPerfmonCounter.Append( pszPerfCounter ) )
  1914. {
  1915. goto eallocname;
  1916. }
  1917. if ( (pdhStatus = PdhAddCounterW( hQuery,
  1918. ComputerPlusPerfmonCounter.Get(),
  1919. 0,
  1920. &hCounter )) != ERROR_SUCCESS )
  1921. {
  1922. DBG_PRINTF(( achE, "%ws: PdhAddCounterW %ws failed : %x\n",
  1923. pCB->m_ServerName.Get(),
  1924. ComputerPlusPerfmonCounter.Get(),
  1925. pdhStatus ));
  1926. break;
  1927. }
  1928. if ( CounterArray.AddPtr( (LPVOID)hCounter ) == INDEX_ERROR ||
  1929. Weight.AddPtr( (LPVOID)dwWeight ) == INDEX_ERROR )
  1930. {
  1931. goto eallocname;
  1932. }
  1933. ++iPerf;
  1934. }
  1935. if ( pdhStatus != ERROR_SUCCESS )
  1936. {
  1937. break;
  1938. }
  1939. }
  1940. if ( pdhStatus == ERROR_SUCCESS )
  1941. {
  1942. fCreatedCounters = TRUE;
  1943. cPerf = iPerf;
  1944. DBG_PRINTF(( achE, "%ws: created counters = %d, perf count %d\n",
  1945. pCB->m_ServerName.Get(), fCreatedCounters, cPerf ));
  1946. }
  1947. else
  1948. {
  1949. CounterArray.Reset();
  1950. Weight.Reset();
  1951. PdhCloseQuery (hQuery);
  1952. }
  1953. LeaveCriticalSection( &g_csPerfList );
  1954. }
  1955. if ( fCreatedCounters )
  1956. {
  1957. tStartCollect = time( NULL );
  1958. pdhStatus = PdhCollectQueryData( hQuery );
  1959. if ( time(NULL) < tStartCollect + COLLECT_TIMEOUT &&
  1960. pdhStatus == ERROR_SUCCESS &&
  1961. CheckQueryMachineStatus( hQuery ) )
  1962. {
  1963. // build normalized load avail
  1964. dbAvail = 0;
  1965. for ( iPerf = 0 ;
  1966. iPerf < cPerf ;
  1967. )
  1968. {
  1969. dwWeight = (DWORD)Weight.GetPtr(iPerf); // BUGBUG64
  1970. for ( cInst = 0, dbAcc = 0 ;
  1971. ;
  1972. )
  1973. {
  1974. pdhStatus = PdhGetFormattedCounterValue(
  1975. (HCOUNTER)CounterArray.GetPtr(iPerf),
  1976. PDH_FMT_DOUBLE,
  1977. &ctrType,
  1978. &fmtValue );
  1979. if ( pdhStatus == ERROR_SUCCESS &&
  1980. fmtValue.CStatus == PDH_CSTATUS_VALID_DATA )
  1981. {
  1982. dbAcc += fmtValue.doubleValue;
  1983. ++cInst;
  1984. }
  1985. else
  1986. {
  1987. DBG_PRINTF(( achE, "%ws: failed format counter, status %x cstatus %x\n",
  1988. pCB->m_ServerName.Get(), pdhStatus, fmtValue.CStatus ));
  1989. goto err_acc_cnt;
  1990. }
  1991. //
  1992. // Loop for all instances of a given counter name
  1993. //
  1994. if ( ++iPerf == cPerf ||
  1995. (DWORD)Weight.GetPtr(iPerf) != (DWORD)-1 ) // BUGBUG64
  1996. {
  1997. break;
  1998. }
  1999. }
  2000. if (pdhStatus == ERROR_SUCCESS)
  2001. {
  2002. // add average of all instances
  2003. // if not an availability flag : in such a case the fact
  2004. // that we successfully read the counter is enough
  2005. if ( dwWeight == LB_WEIGHT_NORMALIZED_FLAG )
  2006. {
  2007. DBG_PRINTF(( achE, "%ws: raw normalized load is %f\n",
  2008. pCB->m_ServerName.Get(),
  2009. ((dbAcc/cInst)) ));
  2010. dbAvail += ((dbAcc/cInst));
  2011. fNormalized = TRUE;
  2012. }
  2013. else if ( dwWeight != LB_WEIGHT_AVAILABILITY_FLAG )
  2014. {
  2015. DBG_PRINTF(( achE, "%ws: raw load is %f weighted load is %f\n",
  2016. pCB->m_ServerName.Get(),
  2017. ((dbAcc/cInst)),
  2018. ((dbAcc/cInst)) * dwWeight ));
  2019. dbAvail += ((dbAcc/cInst)) * dwWeight;
  2020. }
  2021. }
  2022. }
  2023. }
  2024. else
  2025. {
  2026. // failed to access counters :
  2027. // force re-open
  2028. err_acc_cnt:
  2029. DBG_PRINTF(( achE, "%ws: failed to get counters, time %d, status %x\n",
  2030. pCB->m_ServerName.Get(), time(NULL) - tStartCollect, pdhStatus ));
  2031. if ( fCreatedCounters &&
  2032. cPerf )
  2033. {
  2034. WCHAR achErr[32];
  2035. LPCWSTR pA[2];
  2036. pA[0] = pCB->m_ServerName.Get();
  2037. pA[1] = achErr;
  2038. _itow( pdhStatus, achErr, 10 );
  2039. ReportIisLbEvent( EVENTLOG_ERROR_TYPE,
  2040. IISLB_EVENT_COUNTER_COLLECT_ERROR,
  2041. 2,
  2042. pA );
  2043. }
  2044. for ( iPerf = 0 ;
  2045. iPerf < cPerf ;
  2046. ++iPerf )
  2047. {
  2048. pdhStatus = PdhRemoveCounter( (HCOUNTER)CounterArray.GetPtr(iPerf) );
  2049. }
  2050. CounterArray.Reset();
  2051. Weight.Reset();
  2052. PdhCloseQuery( hQuery );
  2053. fCreatedCounters = FALSE;
  2054. dbAvail = 0;
  2055. }
  2056. }
  2057. else
  2058. {
  2059. dbAvail = 0;
  2060. }
  2061. // locate server name in list
  2062. EnterCriticalSection( &g_csIpListUpdate );
  2063. for ( iServ = 0 ;
  2064. iServ < g_KernelIpMap.ServerCount() &&
  2065. _wcsicmp( pCB->m_ServerName.Get(), g_KernelIpMap.GetServerName( iServ ) ) ;
  2066. ++iServ )
  2067. {
  2068. }
  2069. // update load
  2070. if ( iServ < g_KernelIpMap.ServerCount() )
  2071. {
  2072. pServerInfo = g_KernelIpMap.GetServerPtr( iServ );
  2073. g_fNormalized = fNormalized;
  2074. if ( fCreatedCounters )
  2075. {
  2076. DBG_PRINTF(( achE, "%ws: updated slot %d, %f counters\n", pCB->m_ServerName.Get(), iSample, dbAvail ));
  2077. pServerInfo->m_flLoadAvail[iSample] = (float)dbAvail;
  2078. if ( ++iSample == LOADBAL_SAMPLES )
  2079. {
  2080. iSample = 0;
  2081. }
  2082. if ( pServerInfo->m_cNbSamplesAvail < LOADBAL_SAMPLES )
  2083. {
  2084. ++pServerInfo->m_cNbSamplesAvail;
  2085. }
  2086. pServerInfo->m_dwHeartbeat = ~UNAVAIL_HEARTBEAT;
  2087. }
  2088. else
  2089. {
  2090. //
  2091. // No counter available. Reset count of available sample
  2092. //
  2093. pServerInfo->m_cNbSamplesAvail = 0;
  2094. iSample = 0;
  2095. pServerInfo->m_dwHeartbeat = UNAVAIL_HEARTBEAT;
  2096. }
  2097. }
  2098. else
  2099. {
  2100. // can't find computer : exit thread
  2101. LeaveCriticalSection( &g_csIpListUpdate );
  2102. break;
  2103. }
  2104. LeaveCriticalSection( &g_csIpListUpdate );
  2105. waitnext:
  2106. if ( WaitForSingleObject( pCB->m_hStopEvent, PERFMON_SLEEP_TIME ) == WAIT_OBJECT_0 )
  2107. {
  2108. // stop request
  2109. break;
  2110. }
  2111. }
  2112. // close counters
  2113. if ( fCreatedCounters )
  2114. {
  2115. PdhCloseQuery( hQuery );
  2116. }
  2117. CloseHandle( pCB->m_hStopEvent );
  2118. delete pCB;
  2119. return 0;
  2120. }
  2121. extern "C" DWORD WINAPI
  2122. UserToKernelThread(
  2123. LPVOID pV
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. Thread updating kernel mode info with user mode configuration
  2128. through IOCTL
  2129. Arguments:
  2130. pV - event handle set by caller to request this thread to stop
  2131. Return Value:
  2132. NT status
  2133. --*/
  2134. {
  2135. CKernelServerDescription* pS;
  2136. UINT iS;
  2137. UINT iL;
  2138. UINT iDup;
  2139. float flLoadAvail;
  2140. float flTotalLoadAvail;
  2141. BOOL fSt;
  2142. HANDLE hDevice;
  2143. DWORD dwOutBytes;
  2144. UINT cInitialRetries;
  2145. BOOL fSomeServUnavailable;
  2146. DWORD dwWaitTime;
  2147. IPREF iRef;
  2148. HANDLE hDriver;
  2149. DEBUG_BUFFER;
  2150. // open driver
  2151. SetLbDriverState( TRUE );
  2152. hDriver = CreateFile( "\\\\.\\" SZDRIVERNAME,
  2153. GENERIC_READ | GENERIC_WRITE,
  2154. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2155. 0,
  2156. OPEN_EXISTING,
  2157. 0,
  2158. 0 );
  2159. if ( hDriver == INVALID_HANDLE_VALUE )
  2160. {
  2161. WCHAR achErr[32];
  2162. LPCWSTR pA[1];
  2163. pA[0] = achErr;
  2164. _itow( GetLastError(), achErr, 10 );
  2165. DBG_PRINTF(( achE, "CreateFile to access driver %s failed: %u\n", SZDRIVERNAME, GetLastError() ));
  2166. ReportIisLbEvent( EVENTLOG_ERROR_TYPE,
  2167. IISLB_EVENT_DRIVEROPEN_ERROR,
  2168. 1,
  2169. pA );
  2170. goto cleanup;
  2171. }
  2172. cInitialRetries = 30;
  2173. for ( ;
  2174. ;
  2175. )
  2176. {
  2177. EnterCriticalSection( &g_csIpListCheckpoint );
  2178. //
  2179. // Compute average for all servers
  2180. //
  2181. for ( iS = 0, flTotalLoadAvail = 0 ;
  2182. iS < g_KernelIpMap.ServerCount() ;
  2183. ++iS )
  2184. {
  2185. pS = g_KernelIpMap.GetServerPtr( iS );
  2186. for ( iL = 0, flLoadAvail = 0 ;
  2187. iL < pS->m_cNbSamplesAvail ;
  2188. ++iL )
  2189. {
  2190. flLoadAvail += pS->m_flLoadAvail[iL];
  2191. }
  2192. pS->m_flLoadAvailAvg = iL ? (flLoadAvail / iL) : 0;
  2193. DBG_PRINTF(( achE, "%d: avg load is %f\n", iS, pS->m_flLoadAvailAvg ));
  2194. flTotalLoadAvail += pS->m_flLoadAvailAvg;
  2195. }
  2196. //
  2197. // Per Server Available load is Total / PerServerLoad
  2198. //
  2199. fSomeServUnavailable = FALSE;
  2200. for ( iS = 0;
  2201. iS < g_KernelIpMap.ServerCount() ;
  2202. ++iS )
  2203. {
  2204. pS = g_KernelIpMap.GetServerPtr( iS );
  2205. if( pS->m_dwHeartbeat == UNAVAIL_HEARTBEAT )
  2206. {
  2207. pS->m_flLoadAvailAvg = 0;
  2208. fSomeServUnavailable = TRUE;
  2209. }
  2210. else
  2211. {
  2212. if ( !g_fNormalized )
  2213. {
  2214. if ( pS->m_flLoadAvailAvg )
  2215. {
  2216. pS->m_flLoadAvailAvg = flTotalLoadAvail / pS->m_flLoadAvailAvg;
  2217. }
  2218. else
  2219. {
  2220. if ( flTotalLoadAvail )
  2221. {
  2222. pS->m_flLoadAvailAvg = flTotalLoadAvail;
  2223. }
  2224. else
  2225. {
  2226. //
  2227. // Total load is 0 : avail load should be !0 and identical
  2228. // on all servers.
  2229. //
  2230. pS->m_flLoadAvailAvg = LOADBAL_NORMALIZED_TOTAL;
  2231. }
  2232. }
  2233. }
  2234. }
  2235. DBG_PRINTF(( achE, "%d: avail load is %f\n", iS, pS->m_flLoadAvailAvg ));
  2236. }
  2237. //
  2238. // recompute total
  2239. //
  2240. flTotalLoadAvail = 0;
  2241. for ( iS = 0 ;
  2242. iS < g_KernelIpMap.ServerCount() ;
  2243. ++iS )
  2244. {
  2245. pS = g_KernelIpMap.GetServerPtr( iS );
  2246. flTotalLoadAvail += pS->m_flLoadAvailAvg;
  2247. if ( !(fSomeServUnavailable && cInitialRetries) )
  2248. {
  2249. pS->m_dwHeartbeat = UNAVAIL_HEARTBEAT;
  2250. }
  2251. }
  2252. //
  2253. // Normalize each server availability so that total availability is
  2254. // LOADBAL_NORMALIZED_TOTAL
  2255. //
  2256. for ( iS = 0;
  2257. iS < g_KernelIpMap.ServerCount() ;
  2258. ++iS )
  2259. {
  2260. pS = g_KernelIpMap.GetServerPtr( iS );
  2261. if ( flTotalLoadAvail )
  2262. {
  2263. pS->m_dwLoadAvail = (DWORD)((pS->m_flLoadAvailAvg * LOADBAL_NORMALIZED_TOTAL) / flTotalLoadAvail);
  2264. }
  2265. else
  2266. {
  2267. pS->m_dwLoadAvail = 0;
  2268. }
  2269. pS->m_LoadbalancedLoadAvail = pS->m_dwLoadAvail;
  2270. DBG_PRINTF(( achE, "Srv %d, available %d\n", iS, pS->m_dwLoadAvail ));
  2271. }
  2272. if ( fSomeServUnavailable &&
  2273. cInitialRetries )
  2274. {
  2275. dwWaitTime = 1000;
  2276. --cInitialRetries;
  2277. }
  2278. else
  2279. {
  2280. cInitialRetries = 0;
  2281. //
  2282. // set all prv IP index to 0
  2283. //
  2284. for ( iL = 0 ;
  2285. iL < g_KernelIpMap.PrivateIpCount() ;
  2286. ++iL )
  2287. {
  2288. g_KernelIpMap.GetPrivateIpEndpoint( iL )->m_dwRefCount = 0;
  2289. }
  2290. //
  2291. // scan all public IP addr:port. Set m_usUniquePort to port only once
  2292. // for each port used in public IP list
  2293. // i.e each port will be present only once in m_usUniquePort list
  2294. // needed so that driver knows if notify / unnotify request to NAT is needed
  2295. //
  2296. for ( iL = 0 ;
  2297. iL < g_KernelIpMap.PublicIpCount() ;
  2298. ++iL )
  2299. {
  2300. g_KernelIpMap.GetPublicIpPtr( iL )->m_usUniquePort =
  2301. g_KernelIpMap.GetPublicIpPtr( iL )->m_usPort;
  2302. for ( iDup = 0 ;
  2303. iDup < iL ;
  2304. ++iDup )
  2305. {
  2306. if ( g_KernelIpMap.GetPublicIpPtr( iL )->m_usPort ==
  2307. g_KernelIpMap.GetPublicIpPtr( iDup )->m_usPort )
  2308. {
  2309. g_KernelIpMap.GetPublicIpPtr( iL )->m_usUniquePort = 0;
  2310. break;
  2311. }
  2312. }
  2313. //
  2314. // m_dwNotifyPort is used by driver to build notify/unnotify list
  2315. //
  2316. g_KernelIpMap.GetPublicIpPtr( iL )->m_dwNotifyPort =
  2317. g_KernelIpMap.GetPublicIpPtr( iL )->m_usUniquePort;
  2318. g_KernelIpMap.GetPublicIpPtr( iL )->m_pvDirectorHandle = NULL;
  2319. }
  2320. //
  2321. // scan all pub / servers, inc count for prv if avail load != 0
  2322. // kernel will use it to check if prv IP in use
  2323. //
  2324. for ( iS = 0;
  2325. iS < g_KernelIpMap.ServerCount() ;
  2326. ++iS )
  2327. {
  2328. pS = g_KernelIpMap.GetServerPtr( iS );
  2329. if ( pS->m_dwLoadAvail )
  2330. {
  2331. for ( iL = 0 ;
  2332. iL < g_KernelIpMap.PublicIpCount() ;
  2333. ++iL )
  2334. {
  2335. iRef = *g_KernelIpMap.GetPrivateIpRef( pS, iL );
  2336. if ( iRef != -1 )
  2337. {
  2338. ++g_KernelIpMap.GetPrivateIpEndpoint( iRef )->m_dwRefCount;
  2339. }
  2340. }
  2341. }
  2342. }
  2343. // IOCTL to load balancing driver
  2344. fSt = DeviceIoControl( hDriver,
  2345. IOCTL_IISNATIO_SET_CONFIG,
  2346. g_KernelIpMap.GetBuffer(),
  2347. g_KernelIpMap.GetSize(),
  2348. NULL,
  2349. 0,
  2350. &dwOutBytes,
  2351. NULL );
  2352. if ( !fSt )
  2353. {
  2354. WCHAR achErr[32];
  2355. LPCWSTR pA[1];
  2356. pA[0] = achErr;
  2357. _itow( GetLastError(), achErr, 10 );
  2358. DBG_PRINTF(( achE, "IoCtl to access driver failed: %u\n", GetLastError() ));
  2359. ReportIisLbEvent( EVENTLOG_ERROR_TYPE,
  2360. IISLB_EVENT_IOCTL_ERROR,
  2361. 1,
  2362. pA );
  2363. LeaveCriticalSection( &g_csIpListCheckpoint );
  2364. break;
  2365. }
  2366. else
  2367. {
  2368. DBG_PRINTF(( achE, "IoCtl to access driver success\n" ));
  2369. }
  2370. dwWaitTime = USER_TO_KERNEL_INTERVAL;
  2371. }
  2372. LeaveCriticalSection( &g_csIpListCheckpoint );
  2373. if ( WaitForSingleObject( (HANDLE)pV, dwWaitTime ) == WAIT_OBJECT_0 &&
  2374. g_fStopUserToKernelThread )
  2375. {
  2376. break;
  2377. }
  2378. }
  2379. cleanup:
  2380. //close driver
  2381. if ( hDriver != INVALID_HANDLE_VALUE )
  2382. {
  2383. CloseHandle( hDriver );
  2384. }
  2385. SetLbDriverState( FALSE );
  2386. CloseHandle( (HANDLE)pV );
  2387. return 0;
  2388. }
  2389. BOOL
  2390. CKernelIpMapHelper::CheckAndAddPrivateIp(
  2391. CKernelIpEndpoint* pEndpoint,
  2392. BOOL fAddIfNotPresent,
  2393. LPUINT piFound
  2394. )
  2395. /*++
  2396. Routine Description:
  2397. look for IP Endpoint in private IP list, optionaly returns its index
  2398. optionaly add it to list if not found
  2399. Arguments:
  2400. pEndpoint - Endpoint to look for and optionaly add
  2401. fAddIfNotPresent - TRUE to add if endpoint not found in list
  2402. piFound - (optional, can be NULL ) updated with index if found, otherwise -1
  2403. Return Value:
  2404. TRUE if no error ( even if not found ), otherwise FALSE
  2405. --*/
  2406. {
  2407. UINT iLoop;
  2408. CKernelIpEndpoint* pLoopEndpoint;
  2409. for ( iLoop = 0 ;
  2410. EnumPrivateIpList( iLoop, &pLoopEndpoint ) ;
  2411. ++iLoop )
  2412. {
  2413. if ( !memcmp( pLoopEndpoint, pEndpoint, sizeof(CKernelIpEndpoint) ) )
  2414. {
  2415. if ( piFound )
  2416. {
  2417. *piFound = iLoop;
  2418. }
  2419. return TRUE;
  2420. }
  2421. }
  2422. if ( piFound )
  2423. {
  2424. *piFound = (UINT)-1;
  2425. }
  2426. if ( fAddIfNotPresent )
  2427. {
  2428. if ( !m_PrivateIpList.Append( (LPBYTE)pEndpoint, (DWORD)sizeof(CKernelIpEndpoint) ) )
  2429. {
  2430. return FALSE;
  2431. }
  2432. }
  2433. return TRUE;
  2434. }
  2435. BOOL
  2436. CKernelIpMapHelper::EnumPrivateIpList(
  2437. UINT iIndex,
  2438. CKernelIpEndpoint** ppEndpoint
  2439. )
  2440. /*++
  2441. Routine Description:
  2442. Enumerate endpoints in private IP list
  2443. Arguments:
  2444. iIndex - 0 based index
  2445. ppEndpoint - updated with read-only ptr to endpoint
  2446. Return Value:
  2447. TRUE if no error, otherwise FALSE ( end of list )
  2448. --*/
  2449. {
  2450. if ( iIndex < PrivateIpListCount() )
  2451. {
  2452. *ppEndpoint = (CKernelIpEndpoint*)(m_PrivateIpList.GetBuff()) + iIndex;
  2453. return TRUE;
  2454. }
  2455. return FALSE;
  2456. }
  2457. BOOL
  2458. ReportIisLbEvent(
  2459. WORD wType,
  2460. DWORD dwEventId,
  2461. WORD cNbStr,
  2462. LPCWSTR* pStr
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. Log an event based on type, ID and insertion strings
  2467. Arguments:
  2468. wType -- event type ( error, warning, information )
  2469. dwEventId -- event ID ( as defined by the .mc file )
  2470. cNbStr -- nbr of LPWSTR in the pStr array
  2471. pStr -- insertion strings
  2472. Returns:
  2473. TRUE if success, FALSE if failure
  2474. --*/
  2475. {
  2476. BOOL fSt = TRUE;
  2477. HANDLE hEventLog = NULL;
  2478. hEventLog = RegisterEventSourceW(NULL,L"IISLB");
  2479. if ( hEventLog != NULL )
  2480. {
  2481. if (!ReportEventW(hEventLog, // event log handle
  2482. wType, // event type
  2483. 0, // category zero
  2484. (DWORD) dwEventId, // event identifier
  2485. NULL, // no user security identifier
  2486. cNbStr, // count of substitution strings (may be no strings)
  2487. // less ProgName (argv[0]) and Event ID (argv[1])
  2488. 0, // no data
  2489. (LPCWSTR *) pStr, // address of string array
  2490. NULL)) // address of data
  2491. {
  2492. fSt = FALSE;
  2493. }
  2494. DeregisterEventSource( hEventLog );
  2495. }
  2496. else
  2497. {
  2498. fSt = FALSE;
  2499. }
  2500. return fSt;
  2501. }
  2502. /*===================================================================
  2503. InitOleSecurity
  2504. Setup for and call CoInitializeSecurity. This will avoid problems with
  2505. DCOM security on sites that have no default security.
  2506. Parameters:
  2507. None
  2508. Returns:
  2509. Retail -- Always returns NOERROR, failures are ignored.
  2510. Debug -- DBG_ASSERTs on error and returns error code
  2511. Side effects:
  2512. Sets desktop
  2513. ===================================================================*/
  2514. HRESULT InitOleSecurity(
  2515. )
  2516. {
  2517. HRESULT hr = NOERROR;
  2518. DWORD err;
  2519. hr = CoInitializeSecurity(
  2520. NULL,
  2521. -1,
  2522. NULL,
  2523. NULL,
  2524. RPC_C_AUTHN_LEVEL_CONNECT,
  2525. RPC_C_IMP_LEVEL_IDENTIFY,
  2526. NULL,
  2527. EOAC_NONE,
  2528. NULL );
  2529. if (SUCCEEDED(hr))
  2530. {
  2531. err = GetLastError();
  2532. hr = HRESULT_FROM_WIN32(err);
  2533. }
  2534. else
  2535. {
  2536. DBG_PUTS( "Failed to set OLE security\n" );
  2537. }
  2538. return(NOERROR);
  2539. }
  2540. BOOL
  2541. LbAccessCheck(
  2542. DWORD dwAccess
  2543. )
  2544. /*++
  2545. Routine Description:
  2546. Perform security access check
  2547. Arguments:
  2548. dwAccess - access type FILE_READ_DATA / FILE_WRITE_DATA
  2549. Returns:
  2550. TRUE on success, FALSE on failure
  2551. --*/
  2552. {
  2553. BOOL bReturn = TRUE;
  2554. HANDLE hAccTok = NULL;
  2555. DWORD dwRef;
  2556. LPBYTE pAcl;
  2557. HKEY registryKey;
  2558. DWORD valueType;
  2559. DWORD valueSize;
  2560. EnterCriticalSection( &g_csAcl );
  2561. if ( (pAcl = g_pAcl) == NULL )
  2562. {
  2563. if ( RegOpenKeyEx( HKEY_CLASSES_ROOT,
  2564. "APPID\\{a9da4430-65c5-11d1-a700-00a0c922e752}",
  2565. 0,
  2566. KEY_READ,
  2567. &registryKey ) == ERROR_SUCCESS )
  2568. {
  2569. valueSize = 0;
  2570. if ( RegQueryValueEx( registryKey,
  2571. "AccessPermission",
  2572. NULL,
  2573. &valueType,
  2574. NULL,
  2575. &valueSize ) == ERROR_SUCCESS &&
  2576. ( g_pAcl = (LPBYTE)LocalAlloc( LMEM_FIXED, valueSize )) != NULL )
  2577. {
  2578. if ( RegQueryValueEx( registryKey,
  2579. "AccessPermission",
  2580. NULL,
  2581. &valueType,
  2582. g_pAcl,
  2583. &valueSize ) != ERROR_SUCCESS )
  2584. {
  2585. LocalFree( g_pAcl );
  2586. g_pAcl = NULL;
  2587. }
  2588. else
  2589. {
  2590. pAcl = g_pAcl;
  2591. }
  2592. }
  2593. RegCloseKey( registryKey );
  2594. }
  2595. }
  2596. if ( pAcl )
  2597. {
  2598. IServerSecurity* pSec;
  2599. //
  2600. // test if already impersonated ( inprocess call w/o marshalling )
  2601. // If not call DCOM to retrieve security context & impersonate, then
  2602. // extract access token.
  2603. //
  2604. if ( OpenThreadToken( GetCurrentThread(),
  2605. TOKEN_ALL_ACCESS,
  2606. TRUE,
  2607. &hAccTok ) )
  2608. {
  2609. pSec = NULL;
  2610. }
  2611. else
  2612. {
  2613. if ( SUCCEEDED( CoGetCallContext( IID_IServerSecurity, (void**)&pSec ) ) )
  2614. {
  2615. pSec->ImpersonateClient();
  2616. if ( !OpenThreadToken( GetCurrentThread(),
  2617. TOKEN_EXECUTE|TOKEN_QUERY,
  2618. TRUE,
  2619. &hAccTok ) )
  2620. {
  2621. hAccTok = NULL;
  2622. }
  2623. }
  2624. else
  2625. {
  2626. pSec = NULL;
  2627. }
  2628. }
  2629. if ( hAccTok )
  2630. {
  2631. DWORD dwAcc;
  2632. //
  2633. // Protected properties require EXECUTE access rights instead of WRITE
  2634. //
  2635. if ( dwAccess & FILE_WRITE_DATA )
  2636. {
  2637. dwAcc = COM_RIGHTS_EXECUTE;
  2638. }
  2639. else
  2640. {
  2641. dwAcc = COM_RIGHTS_EXECUTE;
  2642. }
  2643. DWORD dwGrantedAccess;
  2644. BYTE PrivSet[400];
  2645. DWORD cbPrivilegeSet = sizeof(PrivSet);
  2646. BOOL fAccessGranted;
  2647. if ( !AccessCheck( pAcl,
  2648. hAccTok,
  2649. dwAcc,
  2650. &g_FileGenericMapping,
  2651. (PRIVILEGE_SET *) &PrivSet,
  2652. &cbPrivilegeSet,
  2653. &dwGrantedAccess,
  2654. &fAccessGranted ) ||
  2655. !fAccessGranted )
  2656. {
  2657. //
  2658. // If read access denied, retry with restricted read right
  2659. // only if not called from GetAll()
  2660. //
  2661. bReturn = FALSE;
  2662. }
  2663. CloseHandle( hAccTok );
  2664. }
  2665. else
  2666. {
  2667. //
  2668. // For now, assume failure to get IServerSecurity means we are
  2669. // in the SYSTEM context, so grant access.
  2670. //
  2671. bReturn = TRUE;
  2672. }
  2673. if ( pSec )
  2674. {
  2675. pSec->RevertToSelf();
  2676. pSec->Release();
  2677. }
  2678. }
  2679. else
  2680. {
  2681. //
  2682. // No ACL : access check succeed
  2683. //
  2684. bReturn = TRUE;
  2685. }
  2686. if ( !bReturn )
  2687. {
  2688. SetLastError( ERROR_ACCESS_DENIED );
  2689. }
  2690. LeaveCriticalSection( &g_csAcl );
  2691. return bReturn;
  2692. }
  2693. VOID
  2694. FlushLbAccessCheck(
  2695. )
  2696. /*++
  2697. Routine Description:
  2698. Flush access check ACL cache
  2699. Arguments:
  2700. None
  2701. Returns:
  2702. Nothing
  2703. --*/
  2704. {
  2705. EnterCriticalSection( &g_csAcl );
  2706. if ( g_pAcl != NULL )
  2707. {
  2708. LocalFree( g_pAcl );
  2709. g_pAcl = NULL;
  2710. }
  2711. LeaveCriticalSection( &g_csAcl );
  2712. }
  2713. HRESULT
  2714. WaitForServiceStatus(
  2715. SC_HANDLE schDependent,
  2716. DWORD dwDesiredServiceState
  2717. )
  2718. /*++
  2719. Routine Description:
  2720. Wait for status of specified service to match desired state
  2721. with MAX_SLEEP timeout
  2722. Arguments:
  2723. schDependent - service/driver to monitor
  2724. dwDesiredServiceState - service/driver state to wait for
  2725. Returns:
  2726. STATUS_SUCCESS if success, otherwise error status
  2727. --*/
  2728. {
  2729. DWORD dwSleepTotal = 0;
  2730. SERVICE_STATUS ssDependent;
  2731. DEBUG_BUFFER;
  2732. while ( dwSleepTotal < MAX_SLEEP )
  2733. {
  2734. if ( QueryServiceStatus( schDependent, &ssDependent ) )
  2735. {
  2736. if ( ssDependent.dwCurrentState == dwDesiredServiceState )
  2737. {
  2738. return S_OK;
  2739. }
  2740. else
  2741. {
  2742. //
  2743. // Still pending...
  2744. //
  2745. Sleep( SLEEP_INTERVAL );
  2746. dwSleepTotal += SLEEP_INTERVAL;
  2747. DBG_PRINTF(( achE, "WaitForServiceStatus sleep, state is %u waiting for %u",
  2748. ssDependent.dwCurrentState, dwDesiredServiceState ));
  2749. }
  2750. }
  2751. else
  2752. {
  2753. return RETURNCODETOHRESULT( GetLastError() );
  2754. }
  2755. }
  2756. return RETURNCODETOHRESULT( ERROR_SERVICE_REQUEST_TIMEOUT );
  2757. }
  2758. HRESULT
  2759. SetLbDriverState(
  2760. BOOL fStart
  2761. )
  2762. /*++
  2763. Routine Description:
  2764. Start/Stop Load balancing driver
  2765. Arguments:
  2766. fStart - TRUE to start driver, FALSE to stop
  2767. Returns:
  2768. STATUS_SUCCESS if success, otherwise error status
  2769. --*/
  2770. {
  2771. SC_HANDLE schSCM;
  2772. SC_HANDLE schDependent;
  2773. HRESULT hresReturn = S_OK;
  2774. SERVICE_STATUS ssDependent;
  2775. DEBUG_BUFFER;
  2776. schSCM = OpenSCManager( NULL,
  2777. NULL,
  2778. SC_MANAGER_ALL_ACCESS);
  2779. if ( schSCM == NULL )
  2780. {
  2781. hresReturn = RETURNCODETOHRESULT(GetLastError());
  2782. }
  2783. else
  2784. {
  2785. schDependent = OpenService( schSCM,
  2786. SZDRIVERNAME,
  2787. SERVICE_ALL_ACCESS );
  2788. if (schDependent != NULL)
  2789. {
  2790. if ( fStart )
  2791. {
  2792. if ( !StartService( schDependent, 0, NULL ) )
  2793. {
  2794. if ( GetLastError() != ERROR_SERVICE_ALREADY_RUNNING )
  2795. {
  2796. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  2797. DBG_PRINTF(( achE, "SetLbDriverState:StartService %u", GetLastError() ));
  2798. }
  2799. }
  2800. else
  2801. {
  2802. DBG_PRINTF(( achE, "SetLbDriverState:StartService success\n" ));
  2803. }
  2804. }
  2805. else
  2806. {
  2807. if ( ControlService( schDependent, SERVICE_CONTROL_STOP, &ssDependent ) ||
  2808. GetLastError() == ERROR_INVALID_SERVICE_CONTROL )
  2809. {
  2810. hresReturn = WaitForServiceStatus( schDependent, SERVICE_STOPPED );
  2811. }
  2812. else
  2813. {
  2814. if ( GetLastError() != ERROR_SERVICE_NOT_ACTIVE )
  2815. {
  2816. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  2817. DBG_PRINTF(( achE, "SetLbDriverState:ControlService %u", GetLastError() ));
  2818. }
  2819. }
  2820. CloseServiceHandle( schDependent );
  2821. }
  2822. }
  2823. else
  2824. {
  2825. hresReturn = RETURNCODETOHRESULT(GetLastError());
  2826. DBG_PRINTF(( achE, "SetLbDriverState:OpenService %u", GetLastError() ));
  2827. }
  2828. CloseServiceHandle( schSCM );
  2829. }
  2830. return hresReturn;
  2831. }
  2832. BOOL
  2833. CheckQueryMachineStatus(
  2834. HQUERY hQuery
  2835. )
  2836. /*++
  2837. Routine Description:
  2838. Check machine status in query
  2839. This is not the same as checking the result of PdhCollectQueryData() and CStatus
  2840. of each counter, as PDH library will attempt to reconnect before reporting an
  2841. invalid status, so 1st query after disconnect will give back success status.
  2842. Arguments:
  2843. hQuery - PDH query
  2844. Returns:
  2845. TRUE if all machine status OK, otherwise FALSE
  2846. --*/
  2847. {
  2848. PPDHI_QUERY_MACHINE pQMachine;
  2849. PPDHI_QUERY pQuery = (PPDHI_QUERY)hQuery;
  2850. DEBUG_BUFFER;
  2851. //
  2852. // Check that the structure is something we understand
  2853. //
  2854. if ( g_dwPdhVersion == ((DWORD)((PDH_CVERSION_WIN40) + 0x0003)) )
  2855. {
  2856. pQMachine = pQuery->pFirstQMachine;
  2857. while (pQMachine != NULL)
  2858. {
  2859. DBG_PRINTF(( achE, "Machine %ws status %x\n",
  2860. pQMachine->pMachine->szName,
  2861. pQMachine->pMachine->dwStatus ));
  2862. if ( pQMachine->pMachine->dwStatus != ERROR_SUCCESS )
  2863. {
  2864. return FALSE;
  2865. }
  2866. pQMachine = pQMachine->pNext;
  2867. }
  2868. }
  2869. return TRUE;
  2870. }