Leaked source code of windows server 2003
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.

2608 lines
72 KiB

  1. //+------------------------------------------------------------
  2. //
  3. // Copyright (C) 1999, Microsoft Corporation
  4. //
  5. // File: cnfgmgr.cpp
  6. //
  7. // Contents: Implementation of the classes defined in cnfgmgr.h
  8. //
  9. // Classes:
  10. // CLdapCfgMgr
  11. // CLdapCfg
  12. // CLdapHost
  13. // CCfgConnectionCache
  14. // CCfgConnection
  15. //
  16. // Functions:
  17. //
  18. // History:
  19. // jstamerj 1999/06/16 14:41:45: Created.
  20. //
  21. //-------------------------------------------------------------
  22. #include "precomp.h"
  23. #include "cnfgmgr.h"
  24. //
  25. // Globals
  26. //
  27. CExShareLock CLdapServerCfg::m_listlock;
  28. LIST_ENTRY CLdapServerCfg::m_listhead;
  29. DWORD CLdapServerCfg::m_dwCostConnectedLocal = DEFAULT_COST_CONNECTED_LOCAL;
  30. DWORD CLdapServerCfg::m_dwCostConnectedRemote = DEFAULT_COST_CONNECTED_REMOTE;
  31. DWORD CLdapServerCfg::m_dwCostInitialLocal = DEFAULT_COST_INITIAL_LOCAL;
  32. DWORD CLdapServerCfg::m_dwCostInitialRemote = DEFAULT_COST_INITIAL_REMOTE;
  33. DWORD CLdapServerCfg::m_dwCostRetryLocal = DEFAULT_COST_RETRY_LOCAL;
  34. DWORD CLdapServerCfg::m_dwCostRetryRemote = DEFAULT_COST_RETRY_REMOTE;
  35. //+------------------------------------------------------------
  36. //
  37. // Function: CLdapCfgMgr::CLdapCfgMgr
  38. //
  39. // Synopsis: Initialize member data
  40. //
  41. // Arguments: Optional:
  42. // fAutomaticConfigUpdate: TRUE indicates that the object is to
  43. // periodicly automaticly update the list of
  44. // GCs.
  45. // FALSE disables this functionality
  46. //
  47. // bt: Default bindtype to use
  48. // pszAccount: Default account for LDAP bind
  49. // pszPassword: Password of above account
  50. // pszNamingContext: Naming context to use for all LDAP searches
  51. //
  52. // Returns: NOTHING
  53. //
  54. // History:
  55. // jstamerj 1999/06/16 14:42:39: Created.
  56. //
  57. //-------------------------------------------------------------
  58. CLdapCfgMgr::CLdapCfgMgr(
  59. ISMTPServerEx *pISMTPServerEx,
  60. BOOL fAutomaticConfigUpdate,
  61. ICategorizerParameters *pICatParams,
  62. LDAP_BIND_TYPE bt,
  63. LPSTR pszAccount,
  64. LPSTR pszPassword,
  65. LPSTR pszNamingContext) : m_LdapConnectionCache(pISMTPServerEx)
  66. {
  67. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::CLdapCfgMgr");
  68. m_dwSignature = SIGNATURE_CLDAPCFGMGR;
  69. m_pCLdapCfg = NULL;
  70. ZeroMemory(&m_ulLastUpdateTime, sizeof(m_ulLastUpdateTime));
  71. m_dwUpdateInProgress = FALSE;
  72. m_fAutomaticConfigUpdate = fAutomaticConfigUpdate;
  73. m_pISMTPServerEx = pISMTPServerEx;
  74. if(m_pISMTPServerEx)
  75. m_pISMTPServerEx->AddRef();
  76. //
  77. // Copy default
  78. //
  79. m_bt = bt;
  80. if(pszAccount)
  81. lstrcpyn(m_szAccount, pszAccount, sizeof(m_szAccount));
  82. else
  83. m_szAccount[0] = '\0';
  84. if(pszPassword)
  85. lstrcpyn(m_szPassword, pszPassword, sizeof(m_szPassword));
  86. else
  87. m_szPassword[0] = '\0';
  88. if(pszNamingContext)
  89. lstrcpyn(m_szNamingContext, pszNamingContext, sizeof(m_szNamingContext));
  90. else
  91. m_szNamingContext[0] = '\0';
  92. m_pICatParams = pICatParams;
  93. m_pICatParams->AddRef();
  94. m_LdapConnectionCache.AddRef();
  95. m_dwRebuildGCListMaxInterval = DEFAULT_REBUILD_GC_LIST_MAX_INTERVAL;
  96. m_dwRebuildGCListMaxFailures = DEFAULT_REBUILD_GC_LIST_MAX_FAILURES;
  97. m_dwRebuildGCListMinInterval = DEFAULT_REBUILD_GC_LIST_MIN_INTERVAL;
  98. InitializeFromRegistry();
  99. CatFunctLeaveEx((LPARAM)this);
  100. } // CLdapCfgMgr::CLdapCfgMgr
  101. //+----------------------------------------------------------------------------
  102. //
  103. // Function: CLdapCfgMgr::InitializeFromRegistry
  104. //
  105. // Synopsis: Helper function that looks up parameters from the registry.
  106. // Configurable parameters are:
  107. // REBUILD_GC_LIST_MAX_INTERVAL_VALUE
  108. // REBUILD_GC_LIST_MAX_FAILURES_VALUE
  109. // REBUILD_GC_LIST_MIN_INTERVAL_VALUE
  110. //
  111. // Arguments: None
  112. //
  113. // Returns: Nothing.
  114. //
  115. //-----------------------------------------------------------------------------
  116. VOID CLdapCfgMgr::InitializeFromRegistry()
  117. {
  118. HKEY hkey;
  119. DWORD dwErr, dwType, dwValue, cbValue;
  120. dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, REBUILD_GC_LIST_PARAMETERS_KEY, &hkey);
  121. if (dwErr == ERROR_SUCCESS) {
  122. cbValue = sizeof(dwValue);
  123. dwErr = RegQueryValueEx(
  124. hkey,
  125. REBUILD_GC_LIST_MAX_INTERVAL_VALUE,
  126. NULL,
  127. &dwType,
  128. (LPBYTE) &dwValue,
  129. &cbValue);
  130. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
  131. m_dwRebuildGCListMaxInterval = dwValue;
  132. }
  133. cbValue = sizeof(dwValue);
  134. dwErr = RegQueryValueEx(
  135. hkey,
  136. REBUILD_GC_LIST_MAX_FAILURES_VALUE,
  137. NULL,
  138. &dwType,
  139. (LPBYTE) &dwValue,
  140. &cbValue);
  141. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
  142. m_dwRebuildGCListMaxFailures = dwValue;
  143. }
  144. cbValue = sizeof(dwValue);
  145. dwErr = RegQueryValueEx(
  146. hkey,
  147. REBUILD_GC_LIST_MIN_INTERVAL_VALUE,
  148. NULL,
  149. &dwType,
  150. (LPBYTE) &dwValue,
  151. &cbValue);
  152. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD && dwValue > 0) {
  153. m_dwRebuildGCListMinInterval = dwValue;
  154. }
  155. RegCloseKey( hkey );
  156. }
  157. }
  158. //+------------------------------------------------------------
  159. //
  160. // Function: CLdapCfgMgr::~CLdapCfgMgr
  161. //
  162. // Synopsis: Release member data/pointers
  163. //
  164. // Arguments: NONE
  165. //
  166. // Returns: NOTHING
  167. //
  168. // History:
  169. // jstamerj 1999/06/16 14:44:28: Created.
  170. //
  171. //-------------------------------------------------------------
  172. CLdapCfgMgr::~CLdapCfgMgr()
  173. {
  174. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::~CLdapCfgMgr");
  175. if(m_pCLdapCfg) {
  176. //
  177. // Release it
  178. //
  179. m_pCLdapCfg->Release();
  180. m_pCLdapCfg = NULL;
  181. }
  182. if(m_pICatParams) {
  183. m_pICatParams->Release();
  184. m_pICatParams = NULL;
  185. }
  186. //
  187. // This will not return until all ldap connections have been released/destroyed
  188. //
  189. m_LdapConnectionCache.Release();
  190. if(m_pISMTPServerEx)
  191. m_pISMTPServerEx->Release();
  192. _ASSERT(m_dwSignature == SIGNATURE_CLDAPCFGMGR);
  193. m_dwSignature = SIGNATURE_CLDAPCFGMGR_INVALID;
  194. CatFunctLeaveEx((LPARAM)this);
  195. } // CLdapCfgMgr::~CLdapCfgMgr
  196. //+------------------------------------------------------------
  197. //
  198. // Function: CLdapCfgMgr::HrInit
  199. //
  200. // Synopsis: Initialize with a list of available GCs
  201. //
  202. // Arguments:
  203. // fRediscoverGCs: TRUE: pass in the force rediscovery flag to DsGetDcName
  204. // FALSE: Attempt to call DsGetDcName first without
  205. // passing in the force rediscovery flag.
  206. //
  207. // Returns:
  208. // S_OK: Success
  209. // error from NT5 (DsGetDcName)
  210. // CAT_E_NO_GC_SERVERS: THere are no GC servers available to build
  211. // the list of GCs
  212. //
  213. // History:
  214. // jstamerj 1999/06/16 14:48:11: Created.
  215. //
  216. //-------------------------------------------------------------
  217. HRESULT CLdapCfgMgr::HrInit(
  218. BOOL fRediscoverGCs)
  219. {
  220. HRESULT hr = S_OK;
  221. DWORD dwcServerConfig = 0;
  222. DWORD dwCount = 0;
  223. PLDAPSERVERCONFIG prgServerConfig = NULL;
  224. ICategorizerLdapConfig *pICatLdapConfigInterface = NULL;
  225. ICategorizerParametersEx *pIPhatCatParams = NULL;
  226. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrInit");
  227. if(m_pICatParams)
  228. {
  229. hr = m_pICatParams->QueryInterface(IID_ICategorizerParametersEx, (LPVOID *)&pIPhatCatParams);
  230. _ASSERT(SUCCEEDED(hr) && "Unable to get phatcatparams interface");
  231. pIPhatCatParams->GetLdapConfigInterface(&pICatLdapConfigInterface);
  232. }
  233. if(pICatLdapConfigInterface)
  234. {
  235. DebugTrace((LPARAM)this, "Getting GC list from sink supplied interface");
  236. //
  237. // Get GC servers from sink supplied interface
  238. //
  239. hr = HrGetGCServers(
  240. pICatLdapConfigInterface,
  241. m_bt,
  242. m_szAccount,
  243. m_szPassword,
  244. m_szNamingContext,
  245. &dwcServerConfig,
  246. &prgServerConfig);
  247. if(FAILED(hr))
  248. {
  249. ERROR_LOG("HrGetGCServers");
  250. hr = CAT_E_NO_GC_SERVERS;
  251. goto CLEANUP;
  252. }
  253. }
  254. else
  255. {
  256. DebugTrace((LPARAM)this, "Getting internal GC list");
  257. //
  258. // Build an array of server configs consisting of available GCs
  259. //
  260. hr = HrBuildGCServerArray(
  261. m_bt,
  262. m_szAccount,
  263. m_szPassword,
  264. m_szNamingContext,
  265. fRediscoverGCs,
  266. &dwcServerConfig,
  267. &prgServerConfig);
  268. if(FAILED(hr))
  269. {
  270. ERROR_LOG("HrBuildGCServerArray");
  271. if(fRediscoverGCs == FALSE)
  272. {
  273. //
  274. // Attempt to build the array again. This time, force
  275. // rediscovery of available GCs. This is expensive which is
  276. // why we initially try to find all available GCs without
  277. // forcing rediscovery.
  278. //
  279. hr = HrBuildGCServerArray(
  280. m_bt,
  281. m_szAccount,
  282. m_szPassword,
  283. m_szNamingContext,
  284. TRUE, // fRediscoverGCs
  285. &dwcServerConfig,
  286. &prgServerConfig);
  287. if(FAILED(hr))
  288. {
  289. ERROR_LOG("HrBuildGCServerArray - 2nd time");
  290. hr = CAT_E_NO_GC_SERVERS;
  291. goto CLEANUP;
  292. }
  293. }
  294. else
  295. {
  296. //
  297. // We already forced rediscovery and failed
  298. //
  299. hr = CAT_E_NO_GC_SERVERS;
  300. goto CLEANUP;
  301. }
  302. }
  303. }
  304. LogCnfgInit();
  305. for(dwCount = 0; dwCount < dwcServerConfig; dwCount++)
  306. {
  307. LogCnfgEntry(& (prgServerConfig[dwCount]));
  308. }
  309. if(dwcServerConfig == 0)
  310. {
  311. ErrorTrace((LPARAM)this, "No GC servers found.");
  312. ERROR_LOG("--dwcServerConfig == 0 --");
  313. hr = CAT_E_NO_GC_SERVERS;
  314. goto CLEANUP;
  315. }
  316. //
  317. // Call the other init function with the array
  318. //
  319. hr = HrInit(
  320. dwcServerConfig,
  321. prgServerConfig);
  322. ERROR_CLEANUP_LOG("HrInit");
  323. CLEANUP:
  324. if(pIPhatCatParams)
  325. pIPhatCatParams->Release();
  326. if(prgServerConfig != NULL)
  327. delete prgServerConfig;
  328. DebugTrace((LPARAM)this, "returning %08lx", hr);
  329. CatFunctLeaveEx((LPARAM)this);
  330. return hr;
  331. } // CLdapCfgMgr::HrInit
  332. //+------------------------------------------------------------
  333. //
  334. // Function: CLdapCfgMgr::HrGetGCServers
  335. //
  336. // Synopsis: Get the list of GCs from dsaccess.dll
  337. //
  338. // Arguments:
  339. // bt: Bind type to use for each server
  340. // pszAccount: Account to use for each server
  341. // pszPassword: password of above account
  342. // pszNamingContext: naming context to use for each server
  343. // fRediscoverGCs: Attempt to rediscover GCs -- this is expensive and should
  344. // only be TRUE after the function has failed once
  345. // pdwcServerConfig: Out parameter for the size of the array
  346. // pprgServerConfig: Out parameter for the array pointer -- this
  347. // should be free'd with the delete operator
  348. //
  349. // Returns:
  350. // S_OK: Success
  351. // E_OUTOFMEMORY
  352. // CAT_E_NO_GC_SERVERS: There are no available GC servers to build
  353. // the list of GCs
  354. // error from ntdsapi
  355. //
  356. // History:
  357. // jstamerj 1999/07/01 17:53:02: Created.
  358. //
  359. //-------------------------------------------------------------
  360. HRESULT CLdapCfgMgr::HrGetGCServers(
  361. IN ICategorizerLdapConfig *pICatLdapConfigInterface,
  362. IN LDAP_BIND_TYPE bt,
  363. IN LPSTR pszAccount,
  364. IN LPSTR pszPassword,
  365. IN LPSTR pszNamingContext,
  366. OUT DWORD *pdwcServerConfig,
  367. OUT PLDAPSERVERCONFIG *pprgServerConfig)
  368. {
  369. HRESULT hr = S_OK;
  370. DWORD dwNumGCs = 0;
  371. DWORD dwIdx = 0;
  372. IServersListInfo *pIServersList = NULL;
  373. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrBuildArrayFromDCInfo");
  374. _ASSERT(pdwcServerConfig);
  375. _ASSERT(pprgServerConfig);
  376. _ASSERT(m_pICatParams);
  377. *pdwcServerConfig = 0;
  378. hr = pICatLdapConfigInterface->GetGCServers(&pIServersList);
  379. if(FAILED(hr)) {
  380. ErrorTrace((LPARAM)this, "Unable to get the list of GC servers");
  381. //$$BUGBUG: Why are we asserting here?
  382. _ASSERT(0 && "Failed to get GC servers!");
  383. ERROR_LOG("pICatLdapConfigInterface->GetGCServers");
  384. goto CLEANUP;
  385. }
  386. hr = pIServersList->GetNumGC(&dwNumGCs);
  387. _ASSERT(SUCCEEDED(hr) && "GetNumGC should always succeed!");
  388. DebugTrace((LPARAM)this, "Got %d GCs", dwNumGCs);
  389. if(dwNumGCs == 0) {
  390. DebugTrace((LPARAM)this, "There are no GC servers");
  391. hr = CAT_E_NO_GC_SERVERS;
  392. ERROR_LOG("--dwNumGCs == 0 --");
  393. goto CLEANUP;
  394. }
  395. //
  396. // Allocate array
  397. //
  398. *pprgServerConfig = new LDAPSERVERCONFIG[dwNumGCs];
  399. if(*pprgServerConfig == NULL) {
  400. ErrorTrace((LPARAM)this, "Out of memory allocating array of %d LDAPSERVERCONFIGs", dwNumGCs);
  401. hr = E_OUTOFMEMORY;
  402. ERROR_LOG("new LDAPSERVERCONFIG[]");
  403. goto CLEANUP;
  404. }
  405. //
  406. // Fill in LDAPSERVERCONFIG structures
  407. //
  408. for(dwIdx = 0; dwIdx < dwNumGCs; dwIdx++) {
  409. PLDAPSERVERCONFIG pServerConfig;
  410. LPSTR pszName = NULL;
  411. pServerConfig = &((*pprgServerConfig)[dwIdx]);
  412. //
  413. // Copy bindtype, account, password, naming context
  414. //
  415. pServerConfig->bt = bt;
  416. if(pszNamingContext)
  417. lstrcpyn(pServerConfig->szNamingContext, pszNamingContext,
  418. sizeof(pServerConfig->szNamingContext));
  419. else
  420. pServerConfig->szNamingContext[0] = '\0';
  421. if(pszAccount)
  422. lstrcpyn(pServerConfig->szAccount, pszAccount,
  423. sizeof(pServerConfig->szAccount));
  424. else
  425. pServerConfig->szAccount[0] = '\0';
  426. if(pszPassword)
  427. lstrcpyn(pServerConfig->szPassword, pszPassword,
  428. sizeof(pServerConfig->szPassword));
  429. else
  430. pServerConfig->szPassword[0] = '\0';
  431. //
  432. // Initialize priority and TCP port
  433. //
  434. pServerConfig->pri = 0;
  435. hr = pIServersList->GetItem(
  436. dwIdx,
  437. &pServerConfig->dwPort,
  438. &pszName);
  439. //
  440. //$$BUGBUG: Why should this always succeed? It is a sink
  441. // supplied interface, isn't it? If the last call fails, we
  442. // will set *pdwcServerConfig below, but free the array.
  443. //
  444. _ASSERT(SUCCEEDED(hr) && "GetItem should always succeed");
  445. //
  446. // Copy the name
  447. //
  448. lstrcpyn(pServerConfig->szHost, pszName,
  449. sizeof(pServerConfig->szHost));
  450. DebugTrace((LPARAM)this, "GC: %s on Port: %d", pServerConfig->szHost, pServerConfig->dwPort);
  451. }
  452. //
  453. // Set the out parameter for the array size
  454. //
  455. *pdwcServerConfig = dwNumGCs;
  456. CLEANUP:
  457. if(FAILED(hr)) {
  458. //
  459. // Free the allocated array if we're failing
  460. //
  461. if(*pprgServerConfig) {
  462. delete *pprgServerConfig;
  463. *pprgServerConfig = NULL;
  464. }
  465. }
  466. if(pIServersList)
  467. pIServersList->Release();
  468. DebugTrace((LPARAM)this, "returning %08lx", hr);
  469. CatFunctLeaveEx((LPARAM)this);
  470. return hr;
  471. } // CLdapCfgMgr::HrBuildArrayFromDCInfo
  472. //+------------------------------------------------------------
  473. //
  474. // Function: CLdapCfgMgr::HrBuildGCServerArray
  475. //
  476. // Synopsis: Allocate/build an array of LDAPSERVERCONFIG structures --
  477. // one for each available GC
  478. //
  479. // Arguments:
  480. // bt: Bind type to use for each server
  481. // pszAccount: Account to use for each server
  482. // pszPassword: password of above account
  483. // pszNamingContext: naming context to use for each server
  484. // fRediscoverGCs: Attempt to rediscover GCs -- this is expensive and should
  485. // only be TRUE after the function has failed once
  486. // pdwcServerConfig: Out parameter for the size of the array
  487. // pprgServerConfig: Out parameter for the array pointer -- this
  488. // should be free'd with the delete operator
  489. //
  490. // Returns:
  491. // S_OK: Success
  492. // E_OUTOFMEMORY
  493. // CAT_E_NO_GC_SERVERS: There are no available GC servers to build
  494. // the list of GCs
  495. // error from ntdsapi
  496. //
  497. // History:
  498. // jstamerj 1999/07/01 17:53:02: Created.
  499. //
  500. //-------------------------------------------------------------
  501. HRESULT CLdapCfgMgr::HrBuildGCServerArray(
  502. IN LDAP_BIND_TYPE bt,
  503. IN LPSTR pszAccount,
  504. IN LPSTR pszPassword,
  505. IN LPSTR pszNamingContext,
  506. IN BOOL fRediscoverGCs,
  507. OUT DWORD *pdwcServerConfig,
  508. OUT PLDAPSERVERCONFIG *pprgServerConfig)
  509. {
  510. HRESULT hr = S_OK;
  511. DWORD dwErr;
  512. ULONG ulFlags;
  513. PDOMAIN_CONTROLLER_INFO pDCInfo = NULL;
  514. HANDLE hDS = INVALID_HANDLE_VALUE;
  515. DWORD cDSDCInfo;
  516. PDS_DOMAIN_CONTROLLER_INFO_2 prgDSDCInfo = NULL;
  517. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrBuildGCServerArray");
  518. //
  519. // Find one GC using DsGetDcName()
  520. //
  521. ulFlags = DS_DIRECTORY_SERVICE_REQUIRED | DS_GC_SERVER_REQUIRED;
  522. if(fRediscoverGCs)
  523. ulFlags |= DS_FORCE_REDISCOVERY;
  524. dwErr = DsGetDcName(
  525. NULL, // Computername to process this function -- local computer
  526. NULL, // Domainname -- primary domain of this computer
  527. NULL, // Domain GUID
  528. NULL, // Sitename -- site of this computer
  529. ulFlags, // Flags; we want a GC
  530. &pDCInfo); // Out parameter for the returned info
  531. hr = HRESULT_FROM_WIN32(dwErr);
  532. if(FAILED(hr)) {
  533. ERROR_LOG("DGetDcName");
  534. //
  535. // Map one error code
  536. //
  537. if(hr == HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN))
  538. hr = CAT_E_NO_GC_SERVERS;
  539. pDCInfo = NULL;
  540. goto CLEANUP;
  541. }
  542. DebugTrace((LPARAM)this, "Binding to DC %s",
  543. pDCInfo->DomainControllerName);
  544. //
  545. // Bind to the DC
  546. //
  547. dwErr = DsBind(
  548. pDCInfo->DomainControllerName, // DomainControllerAddress
  549. NULL, // DnsDomainName
  550. &hDS); // Out param -- handle to DS
  551. hr = HRESULT_FROM_WIN32(dwErr);
  552. if(FAILED(hr)) {
  553. ERROR_LOG("DsBind");
  554. hDS = INVALID_HANDLE_VALUE;
  555. goto CLEANUP;
  556. }
  557. //
  558. // Prefix says we need to check this case too
  559. //
  560. if ((NULL == hDS) || (INVALID_HANDLE_VALUE == hDS)) {
  561. FatalTrace((LPARAM)this, "DsBind returned invalid handle");
  562. hDS = INVALID_HANDLE_VALUE;
  563. hr = E_FAIL;
  564. ERROR_LOG("--DsBind returned invalid handle--");
  565. goto CLEANUP;
  566. }
  567. DebugTrace((LPARAM)this, "Finding all domain controllers for %s", pDCInfo->DomainName);
  568. //
  569. // Get information about all the domain controllers
  570. //
  571. dwErr = DsGetDomainControllerInfo(
  572. hDS, // Handle to the DS
  573. pDCInfo->DomainName, // Domain name -- use the same domain
  574. // as the GC found above
  575. 2, // Retrive struct version 2
  576. &cDSDCInfo, // Out param for array size
  577. (PVOID *) &prgDSDCInfo); // Out param for array ptr
  578. hr = HRESULT_FROM_WIN32(dwErr);
  579. if(FAILED(hr)) {
  580. ERROR_LOG("DsGetDomainControllerInfo");
  581. prgDSDCInfo = NULL;
  582. goto CLEANUP;
  583. }
  584. hr = HrBuildArrayFromDCInfo(
  585. bt,
  586. pszAccount,
  587. pszPassword,
  588. pszNamingContext,
  589. cDSDCInfo,
  590. prgDSDCInfo,
  591. pdwcServerConfig,
  592. pprgServerConfig);
  593. ERROR_CLEANUP_LOG("HrBuildArrayFromDCInfo");
  594. CLEANUP:
  595. if(prgDSDCInfo != NULL)
  596. DsFreeDomainControllerInfo(
  597. 2, // Free struct version 2
  598. cDSDCInfo, // size of array
  599. prgDSDCInfo); // array ptr
  600. if(hDS != INVALID_HANDLE_VALUE)
  601. DsUnBind(&hDS);
  602. if(pDCInfo != NULL)
  603. NetApiBufferFree(pDCInfo);
  604. DebugTrace((LPARAM)this, "returning %08lx", hr);
  605. CatFunctLeaveEx((LPARAM)this);
  606. return hr;
  607. } // CLdapCfgMgr::HrBuildGCServerArray
  608. //+------------------------------------------------------------
  609. //
  610. // Function: CLdapCfgMgr::HrBuildArrayFromDCInfo
  611. //
  612. // Synopsis: Allocate/build an array of LDAPSERVERCONFIG structures --
  613. // one for each available GC in the array
  614. //
  615. // Arguments:
  616. // bt: Bind type to use for each server
  617. // pszAccount: Account to use for each server
  618. // pszPassword: password of above account
  619. // pszNamingContext: naming context to use for each server
  620. // dwDSDCInfo: size of the prgDSDCInfo array
  621. // prgDSDCInfo: array of domain controller info structures
  622. // pdwcServerConfig: Out parameter for the size of the array
  623. // pprgServerConfig: Out parameter for the array pointer -- this
  624. // should be free'd with the delete operator
  625. //
  626. // Returns:
  627. // S_OK: Success
  628. // E_OUTOFMEMORY
  629. // CAT_E_NO_GC_SERVERS: There were no GCs in the array
  630. //
  631. // History:
  632. // jstamerj 1999/06/17 10:40:46: Created.
  633. //
  634. //-------------------------------------------------------------
  635. HRESULT CLdapCfgMgr::HrBuildArrayFromDCInfo(
  636. IN LDAP_BIND_TYPE bt,
  637. IN LPSTR pszAccount,
  638. IN LPSTR pszPassword,
  639. IN LPSTR pszNamingContext,
  640. IN DWORD dwcDSDCInfo,
  641. IN PDS_DOMAIN_CONTROLLER_INFO_2 prgDSDCInfo,
  642. OUT DWORD *pdwcServerConfig,
  643. OUT PLDAPSERVERCONFIG *pprgServerConfig)
  644. {
  645. HRESULT hr = S_OK;
  646. DWORD dwNumGCs = 0;
  647. DWORD dwSrcIdx;
  648. DWORD dwDestIdx;
  649. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrBuildArrayFromDCInfo");
  650. _ASSERT(pdwcServerConfig);
  651. _ASSERT(pprgServerConfig);
  652. for(dwSrcIdx = 0; dwSrcIdx < dwcDSDCInfo; dwSrcIdx++) {
  653. LPSTR pszName;
  654. pszName = SzConnectNameFromDomainControllerInfo(
  655. &(prgDSDCInfo[dwSrcIdx]));
  656. if(pszName == NULL) {
  657. ErrorTrace((LPARAM)this, "DC \"%s\" has no dns/netbios names",
  658. prgDSDCInfo[dwSrcIdx].ServerObjectName ?
  659. prgDSDCInfo[dwSrcIdx].ServerObjectName :
  660. "unknown");
  661. } else if(prgDSDCInfo[dwSrcIdx].fIsGc) {
  662. dwNumGCs++;
  663. DebugTrace((LPARAM)this, "Discovered GC #%d: %s",
  664. dwNumGCs, pszName);
  665. } else {
  666. DebugTrace((LPARAM)this, "Discarding non-GC: %s",
  667. pszName);
  668. }
  669. }
  670. //
  671. // Allocate array
  672. //
  673. *pprgServerConfig = new LDAPSERVERCONFIG[dwNumGCs];
  674. if(*pprgServerConfig == NULL) {
  675. ErrorTrace((LPARAM)this, "Out of memory alloacting array of %d LDAPSERVERCONFIGs", dwNumGCs);
  676. hr = E_OUTOFMEMORY;
  677. ERROR_LOG("new LDAPSERVERCONFIG[]");
  678. goto CLEANUP;
  679. }
  680. //
  681. // Fill in LDAPSERVERCONFIG structures
  682. //
  683. for(dwSrcIdx = 0, dwDestIdx = 0; dwSrcIdx < dwcDSDCInfo; dwSrcIdx++) {
  684. LPSTR pszName;
  685. pszName = SzConnectNameFromDomainControllerInfo(
  686. &(prgDSDCInfo[dwSrcIdx]));
  687. if((pszName != NULL) && (prgDSDCInfo[dwSrcIdx].fIsGc)) {
  688. PLDAPSERVERCONFIG pServerConfig;
  689. _ASSERT(dwDestIdx < dwNumGCs);
  690. pServerConfig = &((*pprgServerConfig)[dwDestIdx]);
  691. //
  692. // Copy bindtype, account, password, naming context
  693. //
  694. pServerConfig->bt = bt;
  695. if(pszNamingContext)
  696. lstrcpyn(pServerConfig->szNamingContext, pszNamingContext,
  697. sizeof(pServerConfig->szNamingContext));
  698. else
  699. pServerConfig->szNamingContext[0] = '\0';
  700. if(pszAccount)
  701. lstrcpyn(pServerConfig->szAccount, pszAccount,
  702. sizeof(pServerConfig->szAccount));
  703. else
  704. pServerConfig->szAccount[0] = '\0';
  705. if(pszPassword)
  706. lstrcpyn(pServerConfig->szPassword, pszPassword,
  707. sizeof(pServerConfig->szPassword));
  708. else
  709. pServerConfig->szPassword[0] = '\0';
  710. //
  711. // Initialize priority and TCP port
  712. //
  713. pServerConfig->pri = 0;
  714. pServerConfig->dwPort = LDAP_GC_PORT;
  715. //
  716. // Copy the name
  717. //
  718. lstrcpyn(pServerConfig->szHost, pszName,
  719. sizeof(pServerConfig->szHost));
  720. dwDestIdx++;
  721. }
  722. }
  723. //
  724. // Assert check -- we should have filled in the entire array
  725. //
  726. _ASSERT(dwDestIdx == dwNumGCs);
  727. //
  728. // Set the out parameter for the array size
  729. //
  730. *pdwcServerConfig = dwNumGCs;
  731. CLEANUP:
  732. if(FAILED(hr)) {
  733. //
  734. // Free the allocated array if we're failing
  735. //
  736. if(*pprgServerConfig) {
  737. delete *pprgServerConfig;
  738. *pprgServerConfig = NULL;
  739. }
  740. }
  741. DebugTrace((LPARAM)this, "returning %08lx", hr);
  742. CatFunctLeaveEx((LPARAM)this);
  743. return hr;
  744. } // CLdapCfgMgr::HrBuildArrayFromDCInfo
  745. //+------------------------------------------------------------
  746. //
  747. // Function: CLdapCfgMgr::HrInit
  748. //
  749. // Synopsis: Initialize given an array of LDAPSERVERCONFIG structs
  750. //
  751. // Arguments:
  752. // dwcServers: Size of the array
  753. // prgServerConfig: Array of LDAPSERVERCONFIG structs
  754. //
  755. // Returns:
  756. // S_OK: Success
  757. // E_OUTOFMEMORY
  758. //
  759. // History:
  760. // jstamerj 1999/06/17 12:32:11: Created.
  761. //
  762. //-------------------------------------------------------------
  763. HRESULT CLdapCfgMgr::HrInit(
  764. DWORD dwcServers,
  765. PLDAPSERVERCONFIG prgServerConfig)
  766. {
  767. HRESULT hr = S_OK;
  768. CLdapCfg *pCLdapCfgOld = NULL;
  769. CLdapCfg *pCLdapCfg = NULL;
  770. BOOL fHaveLock = FALSE;
  771. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrInit");
  772. pCLdapCfg = new (dwcServers) CLdapCfg(GetISMTPServerEx());
  773. if(pCLdapCfg == NULL) {
  774. hr = E_OUTOFMEMORY;
  775. ERROR_LOG("new CLdapCfg");
  776. goto CLEANUP;
  777. }
  778. //
  779. // Allow only one config change at a time
  780. //
  781. m_sharelock.ExclusiveLock();
  782. fHaveLock = TRUE;
  783. //
  784. // Grab the current m_pCLdapCfg into pCLdapCfgOld
  785. //
  786. pCLdapCfgOld = m_pCLdapCfg;
  787. hr = pCLdapCfg->HrInit(
  788. dwcServers,
  789. prgServerConfig,
  790. pCLdapCfgOld);
  791. ERROR_CLEANUP_LOG("pCLdapCfg->HrInit");
  792. //
  793. // Put the new configuration in place
  794. // Swap pointers
  795. //
  796. m_pCLdapCfg = pCLdapCfg;
  797. //
  798. // Set the last update time
  799. //
  800. GetSystemTimeAsFileTime((LPFILETIME)&m_ulLastUpdateTime);
  801. CLEANUP:
  802. if(fHaveLock)
  803. m_sharelock.ExclusiveUnlock();
  804. if(pCLdapCfgOld)
  805. pCLdapCfgOld->Release();
  806. DebugTrace((LPARAM)this, "returning %08lx", hr);
  807. CatFunctLeaveEx((LPARAM)this);
  808. return hr;
  809. } // CLdapCfgMgr::HrInit
  810. //+------------------------------------------------------------
  811. //
  812. // Function: CLdapCfgMgr::HrGetConnection
  813. //
  814. // Synopsis: Select/return a connection
  815. //
  816. // Arguments:
  817. // ppConn: Out parameter to receive ptr to connection
  818. //
  819. // Returns:
  820. // S_OK: Success
  821. // E_FAIL: not initialized
  822. // error from CLdapConnectionCache
  823. //
  824. // History:
  825. // jstamerj 1999/06/17 15:25:51: Created.
  826. //
  827. //-------------------------------------------------------------
  828. HRESULT CLdapCfgMgr::HrGetConnection(
  829. CCfgConnection **ppConn)
  830. {
  831. HRESULT hr = S_OK;
  832. CatFunctEnterEx((LPARAM)this, "CLdapCfgMgr::HrGetConnection");
  833. hr = HrUpdateConfigurationIfNecessary();
  834. ERROR_CLEANUP_LOG("HrUpdateConfigurationIfNecessary");
  835. m_sharelock.ShareLock();
  836. if(m_pCLdapCfg) {
  837. DWORD dwcAttempts = 0;
  838. do {
  839. dwcAttempts++;
  840. hr = m_pCLdapCfg->HrGetConnection(ppConn, &m_LdapConnectionCache);
  841. } while((hr == HRESULT_FROM_WIN32(ERROR_RETRY)) &&
  842. (dwcAttempts <= m_pCLdapCfg->DwNumServers()));
  843. //
  844. // If we retried DwNumServers() times and still couldn't get a
  845. // connection, fail with E_DBCONNECTION.
  846. //
  847. if(FAILED(hr))
  848. {
  849. ERROR_LOG("m_pCLdapCfg->HrGetConnection");
  850. if(hr == HRESULT_FROM_WIN32(ERROR_RETRY))
  851. hr = CAT_E_DBCONNECTION;
  852. }
  853. } else {
  854. hr = E_FAIL;
  855. _ASSERT(0 && "HrInit not called or did not succeed");
  856. }
  857. m_sharelock.ShareUnlock();
  858. CLEANUP:
  859. DebugTrace((LPARAM)this, "returning %08lx", hr);
  860. CatFunctLeaveEx((LPARAM)this);
  861. return hr;
  862. } // CLdapCfgMgr::HrGetConnection
  863. //+------------------------------------------------------------
  864. //
  865. // Function: CLdapCfgMgr::LogCnfgInit
  866. //
  867. // Synopsis: Log cnfgmgr init event
  868. //
  869. // Arguments: none
  870. //
  871. // Returns: Nothing
  872. //
  873. // History:
  874. // jstamerj 2001/12/13 00:57:18: Created.
  875. //
  876. //-------------------------------------------------------------
  877. VOID CLdapCfgMgr::LogCnfgInit()
  878. {
  879. CatLogEvent(
  880. GetISMTPServerEx(),
  881. CAT_EVENT_CNFGMGR_INIT,
  882. 0,
  883. NULL,
  884. S_OK,
  885. "",
  886. LOGEVENT_FLAG_ALWAYS,
  887. LOGEVENT_LEVEL_MEDIUM);
  888. }
  889. //+------------------------------------------------------------
  890. //
  891. // Function: CLdapCfgMgr::LogCnfgEntry
  892. //
  893. // Synopsis: Log cnfgmgr entry event
  894. //
  895. // Arguments: pConfig: entry to log
  896. //
  897. // Returns: Nothing
  898. //
  899. // History:
  900. // jstamerj 2001/12/13 00:57:30: Created.
  901. //
  902. //-------------------------------------------------------------
  903. VOID CLdapCfgMgr::LogCnfgEntry(
  904. PLDAPSERVERCONFIG pConfig)
  905. {
  906. LPCSTR rgSubStrings[6];
  907. CHAR szPort[16], szPri[16], szBindType[16];
  908. _snprintf(szPort, sizeof(szPort), "%d", pConfig->dwPort);
  909. _snprintf(szPri, sizeof(szPri), "%d", pConfig->pri);
  910. _snprintf(szBindType, sizeof(szBindType), "%d", pConfig->bt);
  911. rgSubStrings[0] = pConfig->szHost;
  912. rgSubStrings[1] = szPort;
  913. rgSubStrings[2] = szPri;
  914. rgSubStrings[3] = szBindType;
  915. rgSubStrings[4] = pConfig->szNamingContext;
  916. rgSubStrings[5] = pConfig->szAccount;
  917. CatLogEvent(
  918. GetISMTPServerEx(),
  919. CAT_EVENT_CNFGMGR_ENTRY,
  920. 6,
  921. rgSubStrings,
  922. S_OK,
  923. pConfig->szHost,
  924. LOGEVENT_FLAG_ALWAYS,
  925. LOGEVENT_LEVEL_MEDIUM);
  926. }
  927. //+------------------------------------------------------------
  928. //
  929. // Function: CLdapCfg::operator new
  930. //
  931. // Synopsis: Allocate memory for a CLdapCfg object
  932. //
  933. // Arguments:
  934. // size: size of C++ object
  935. // dwcServers: Number of servers in this configuration
  936. //
  937. // Returns:
  938. // void pointer to the new object
  939. //
  940. // History:
  941. // jstamerj 1999/06/17 13:40:56: Created.
  942. //
  943. //-------------------------------------------------------------
  944. void * CLdapCfg::operator new(
  945. size_t size,
  946. DWORD dwcServers)
  947. {
  948. CLdapCfg *pCLdapCfg;
  949. DWORD dwAllocatedSize;
  950. CatFunctEnterEx((LPARAM)0, "CLdapCfg::operator new");
  951. _ASSERT(size == sizeof(CLdapCfg));
  952. //
  953. // Allocate space fo the CLdapServerCfg * array contigously after
  954. // the memory for the C++ object
  955. //
  956. dwAllocatedSize = sizeof(CLdapCfg) + (dwcServers *
  957. sizeof(CLdapServerCfg));
  958. pCLdapCfg = (CLdapCfg *) new BYTE[dwAllocatedSize];
  959. if(pCLdapCfg) {
  960. pCLdapCfg->m_dwSignature = SIGNATURE_CLDAPCFG;
  961. pCLdapCfg->m_dwcServers = dwcServers;
  962. pCLdapCfg->m_prgpCLdapServerCfg = (CLdapServerCfg **) (pCLdapCfg + 1);
  963. }
  964. CatFunctLeaveEx((LPARAM)pCLdapCfg);
  965. return pCLdapCfg;
  966. } // CLdapCfg::operator new
  967. //+------------------------------------------------------------
  968. //
  969. // Function: CLdapCfg::CLdapCfg
  970. //
  971. // Synopsis: Initialize member data
  972. //
  973. // Arguments:
  974. //
  975. // Returns: NOTHING
  976. //
  977. // History:
  978. // jstamerj 1999/06/17 13:46:50: Created.
  979. //
  980. //-------------------------------------------------------------
  981. CLdapCfg::CLdapCfg(
  982. ISMTPServerEx *pISMTPServerEx)
  983. {
  984. CatFunctEnterEx((LPARAM)this, "CLdapCfg::CLdapCfg");
  985. //
  986. // signature and number of servers should be set by the new operator
  987. //
  988. _ASSERT(m_dwSignature == SIGNATURE_CLDAPCFG);
  989. //
  990. // Zero out the array of pointers to CLdapServerCfg objects
  991. //
  992. ZeroMemory(m_prgpCLdapServerCfg, m_dwcServers * sizeof(CLdapServerCfg *));
  993. m_dwInc = 0;
  994. m_dwcConnectionFailures = 0;
  995. m_pISMTPServerEx = pISMTPServerEx;
  996. if(m_pISMTPServerEx)
  997. m_pISMTPServerEx->AddRef();
  998. CatFunctLeaveEx((LPARAM)this);
  999. } // CLdapCfg::CLdapCfg
  1000. //+------------------------------------------------------------
  1001. //
  1002. // Function: CLdapCfg::~CLdapCfg
  1003. //
  1004. // Synopsis: Clean up
  1005. //
  1006. // Arguments: NONE
  1007. //
  1008. // Returns: NOTHING
  1009. //
  1010. // History:
  1011. // jstamerj 1999/06/17 14:47:25: Created.
  1012. //
  1013. //-------------------------------------------------------------
  1014. CLdapCfg::~CLdapCfg()
  1015. {
  1016. DWORD dwCount;
  1017. CatFunctEnterEx((LPARAM)this, "CLdapCfg::~CLdapCfg");
  1018. //
  1019. // Release all connections configurations
  1020. //
  1021. for(dwCount = 0; dwCount < m_dwcServers; dwCount++) {
  1022. CLdapServerCfg *pCLdapServerCfg;
  1023. pCLdapServerCfg = m_prgpCLdapServerCfg[dwCount];
  1024. m_prgpCLdapServerCfg[dwCount] = NULL;
  1025. if(pCLdapServerCfg)
  1026. pCLdapServerCfg->Release();
  1027. }
  1028. if(m_pISMTPServerEx)
  1029. m_pISMTPServerEx->Release();
  1030. _ASSERT(m_dwSignature == SIGNATURE_CLDAPCFG);
  1031. m_dwSignature = SIGNATURE_CLDAPCFG_INVALID;
  1032. CatFunctLeaveEx((LPARAM)this);
  1033. } // CLdapCfg::~CLdapCfg
  1034. //+------------------------------------------------------------
  1035. //
  1036. // Function: CLdapCfg::HrInit
  1037. //
  1038. // Synopsis: Initialize the configuration
  1039. //
  1040. // Arguments:
  1041. // dwcServers: Size of config array
  1042. // prgSeverConfig: LDAPSERVERCONFIG array
  1043. // pCLdapCfgOld: The previous configuration
  1044. //
  1045. // Returns:
  1046. // S_OK: Success
  1047. // E_OUTOFMEMORY
  1048. //
  1049. // History:
  1050. // jstamerj 1999/06/17 13:52:20: Created.
  1051. //
  1052. //-------------------------------------------------------------
  1053. HRESULT CLdapCfg::HrInit(
  1054. DWORD dwcServers,
  1055. PLDAPSERVERCONFIG prgServerConfig,
  1056. CLdapCfg *pCLdapCfgOld)
  1057. {
  1058. HRESULT hr = S_OK;
  1059. DWORD dwCount;
  1060. CatFunctEnterEx((LPARAM)this, "CLdapCfg::HrInit");
  1061. //
  1062. // m_dwcServers should be initialized by the new operator
  1063. //
  1064. _ASSERT(dwcServers == m_dwcServers);
  1065. m_sharelock.ExclusiveLock();
  1066. //
  1067. // Zero out the array of pointers to CLdapServerCfg objects
  1068. //
  1069. ZeroMemory(m_prgpCLdapServerCfg, m_dwcServers * sizeof(CLdapServerCfg *));
  1070. for(dwCount = 0; dwCount < m_dwcServers; dwCount++) {
  1071. DebugTrace((LPARAM)this, "GC list entry: %s (%u)", prgServerConfig[dwCount].szHost, prgServerConfig[dwCount].dwPort);
  1072. CLdapServerCfg *pServerCfg = NULL;
  1073. hr = CLdapServerCfg::GetServerCfg(
  1074. GetISMTPServerEx(),
  1075. &(prgServerConfig[dwCount]),
  1076. &pServerCfg);
  1077. ERROR_CLEANUP_LOG("CLdapServerCfg::GetServerCfg");
  1078. m_prgpCLdapServerCfg[dwCount] = pServerCfg;
  1079. }
  1080. ShuffleArray();
  1081. CLEANUP:
  1082. m_sharelock.ExclusiveUnlock();
  1083. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1084. CatFunctLeaveEx((LPARAM)this);
  1085. return hr;
  1086. } // CLdapCfg::HrInit
  1087. //+------------------------------------------------------------
  1088. //
  1089. // Function: CLdapCfg::HrGetConnection
  1090. //
  1091. // Synopsis: Select a connection and return it
  1092. //
  1093. // Arguments:
  1094. // ppConn: Set to a pointer to the selected connection
  1095. // pLdapConnectionCache: Cache to get connection from
  1096. //
  1097. // Returns:
  1098. // S_OK: Success
  1099. // E_FAIL: We are shutting down
  1100. // error from ldapconn
  1101. //
  1102. // History:
  1103. // jstamerj 1999/06/17 14:49:37: Created.
  1104. //
  1105. //-------------------------------------------------------------
  1106. HRESULT CLdapCfg::HrGetConnection(
  1107. CCfgConnection **ppConn,
  1108. CCfgConnectionCache *pLdapConnectionCache)
  1109. {
  1110. HRESULT hr = S_OK;
  1111. LDAPSERVERCOST Cost, BestCost;
  1112. DWORD dwCount;
  1113. CLdapServerCfg *pCLdapServerCfg = NULL;
  1114. BOOL fFirstServer = TRUE;
  1115. DWORD dwStart, dwCurrent;
  1116. CatFunctEnterEx((LPARAM)this, "CLdapCfg::HrGetConnection");
  1117. //
  1118. // Get the cost of the first connection
  1119. //
  1120. m_sharelock.ShareLock();
  1121. //
  1122. // Round robin where we start searching the array
  1123. // Do this so we will use connections with the same cost
  1124. // approximately the same amount of time.
  1125. //
  1126. dwStart = InterlockedIncrement((PLONG) &m_dwInc) % m_dwcServers;
  1127. for(dwCount = 0; dwCount < m_dwcServers; dwCount++) {
  1128. dwCurrent = (dwStart + dwCount) % m_dwcServers;
  1129. if(m_prgpCLdapServerCfg[dwCurrent]) {
  1130. m_prgpCLdapServerCfg[dwCurrent]->Cost(GetISMTPServerEx(), &Cost);
  1131. if(fFirstServer) {
  1132. pCLdapServerCfg = m_prgpCLdapServerCfg[dwCurrent];
  1133. fFirstServer = FALSE;
  1134. BestCost = Cost;
  1135. } else if(Cost < BestCost) {
  1136. pCLdapServerCfg = m_prgpCLdapServerCfg[dwCurrent];
  1137. BestCost = Cost;
  1138. }
  1139. }
  1140. }
  1141. if(pCLdapServerCfg == NULL) {
  1142. ErrorTrace((LPARAM)this, "HrGetConnection can not find any connections");
  1143. hr = E_FAIL;
  1144. _ASSERT(0 && "HrInit not called or did not succeed");
  1145. ERROR_LOG("--pCLdapServerCfg == NULL--");
  1146. goto CLEANUP;
  1147. }
  1148. if(BestCost >= COST_TOO_HIGH_TO_CONNECT) {
  1149. DebugTrace((LPARAM)this, "BestCost is too high to attempt connection");
  1150. hr = CAT_E_DBCONNECTION;
  1151. ERROR_LOG("-- BestCost >= COST_TOO_HIGH_TO_CONNECT --");
  1152. goto CLEANUP;
  1153. }
  1154. hr = pCLdapServerCfg->HrGetConnection(GetISMTPServerEx(), ppConn, pLdapConnectionCache);
  1155. // If we fail to connect to a GC --- there may be other GCs which
  1156. // are still up. Therefore we should try to connect to them (till
  1157. // we run out of GCs (BestCost >= COST_TOO_HIGH_TO_CONNECT)
  1158. if(FAILED(hr)) {
  1159. DebugTrace((LPARAM)this, "Failed to connect. hr = 0x%08x", hr);
  1160. ERROR_LOG("pCLdapServerCfg->HrGetConnection");
  1161. hr = HRESULT_FROM_WIN32(ERROR_RETRY);
  1162. }
  1163. CLEANUP:
  1164. m_sharelock.ShareUnlock();
  1165. if(FAILED(hr))
  1166. InterlockedIncrement((PLONG)&m_dwcConnectionFailures);
  1167. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1168. CatFunctLeaveEx((LPARAM)this);
  1169. return hr;
  1170. } // CLdapCfg::HrGetConnection
  1171. //+------------------------------------------------------------
  1172. //
  1173. // Function: CLdapCfg::ShuffleArray
  1174. //
  1175. // Synopsis: Randomize the order of the CLdapServerCfg array
  1176. //
  1177. // Arguments: NONE
  1178. //
  1179. // Returns: NOTHING
  1180. //
  1181. // History:
  1182. // jstamerj 1999/06/17 19:10:06: Created.
  1183. //
  1184. //-------------------------------------------------------------
  1185. VOID CLdapCfg::ShuffleArray()
  1186. {
  1187. DWORD dwCount;
  1188. DWORD dwSwap;
  1189. CLdapServerCfg *pTmp;
  1190. CatFunctEnterEx((LPARAM)this, "CLdapCfg::ShuffleArray");
  1191. srand((int)(GetCurrentThreadId() * time(NULL)));
  1192. for(dwCount = 0; dwCount < (m_dwcServers - 1); dwCount++) {
  1193. //
  1194. // Choose an integer between dwCount and m_dwcServers - 1
  1195. //
  1196. dwSwap = dwCount + (rand() % (m_dwcServers - dwCount));
  1197. //
  1198. // Swap pointers
  1199. //
  1200. pTmp = m_prgpCLdapServerCfg[dwCount];
  1201. m_prgpCLdapServerCfg[dwCount] = m_prgpCLdapServerCfg[dwSwap];
  1202. m_prgpCLdapServerCfg[dwSwap] = pTmp;
  1203. }
  1204. CatFunctLeaveEx((LPARAM)this);
  1205. } // CLdapCfg::ShuffleArray
  1206. //+------------------------------------------------------------
  1207. //
  1208. // Function: CLdapServerCfg::CLdapServerCfg
  1209. //
  1210. // Synopsis: Initialize member variables
  1211. //
  1212. // Arguments: NONE
  1213. //
  1214. // Returns: NOTHING
  1215. //
  1216. // History:
  1217. // jstamerj 1999/06/17 15:30:32: Created.
  1218. //
  1219. //-------------------------------------------------------------
  1220. CLdapServerCfg::CLdapServerCfg()
  1221. {
  1222. CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::CLdapServerCfg");
  1223. m_dwSignature = SIGNATURE_CLDAPSERVERCFG;
  1224. m_ServerConfig.dwPort = 0;
  1225. m_ServerConfig.pri = 0;
  1226. m_ServerConfig.bt = BIND_TYPE_NONE;
  1227. m_ServerConfig.szHost[0] = '\0';
  1228. m_ServerConfig.szNamingContext[0] = '\0';
  1229. m_ServerConfig.szAccount[0] = '\0';
  1230. m_ServerConfig.szPassword[0] = '\0';
  1231. m_connstate = CONN_STATE_INITIAL;
  1232. ZeroMemory(&m_ftLastStateUpdate, sizeof(m_ftLastStateUpdate));
  1233. m_dwcPendingSearches = 0;
  1234. m_lRefCount = 1;
  1235. m_fLocalServer = FALSE;
  1236. m_dwcCurrentConnectAttempts = 0;
  1237. m_dwcFailedConnectAttempts = 0;
  1238. CatFunctLeaveEx((LPARAM)this);
  1239. } // CLdapServerCfg::CLdapServerCfg
  1240. //+----------------------------------------------------------------------------
  1241. //
  1242. // Function: CLdapServerCfg::InitializeFromRegistry
  1243. //
  1244. // Synopsis: Helper function that looks up parameters from the registry.
  1245. // Configurable parameters are:
  1246. // GC_COST_CONNECTED_LOCAL
  1247. // GC_COST_CONNECTED_REMOTE
  1248. // GC_COST_INITIAL_LOCAL
  1249. // GC_COST_INITIAL_REMOTE
  1250. // GC_COST_RETRY_LOCAL
  1251. // GC_COST_RETRY_REMOTE
  1252. //
  1253. // Arguments: None
  1254. //
  1255. // Returns: Nothing.
  1256. //
  1257. //-----------------------------------------------------------------------------
  1258. VOID CLdapServerCfg::InitializeFromRegistry()
  1259. {
  1260. HKEY hkey;
  1261. DWORD dwErr, dwType, dwValue, cbValue;
  1262. dwErr = RegOpenKey(HKEY_LOCAL_MACHINE, GC_COST_PARAMETERS_KEY, &hkey);
  1263. if (dwErr == ERROR_SUCCESS) {
  1264. cbValue = sizeof(dwValue);
  1265. dwErr = RegQueryValueEx(
  1266. hkey,
  1267. GC_COST_CONNECTED_LOCAL_VALUE,
  1268. NULL,
  1269. &dwType,
  1270. (LPBYTE) &dwValue,
  1271. &cbValue);
  1272. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1273. m_dwCostConnectedLocal = dwValue;
  1274. }
  1275. cbValue = sizeof(dwValue);
  1276. dwErr = RegQueryValueEx(
  1277. hkey,
  1278. GC_COST_CONNECTED_REMOTE_VALUE,
  1279. NULL,
  1280. &dwType,
  1281. (LPBYTE) &dwValue,
  1282. &cbValue);
  1283. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1284. m_dwCostConnectedRemote = dwValue;
  1285. }
  1286. cbValue = sizeof(dwValue);
  1287. dwErr = RegQueryValueEx(
  1288. hkey,
  1289. GC_COST_INITIAL_LOCAL_VALUE,
  1290. NULL,
  1291. &dwType,
  1292. (LPBYTE) &dwValue,
  1293. &cbValue);
  1294. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1295. m_dwCostInitialLocal = dwValue;
  1296. }
  1297. cbValue = sizeof(dwValue);
  1298. dwErr = RegQueryValueEx(
  1299. hkey,
  1300. GC_COST_INITIAL_REMOTE_VALUE,
  1301. NULL,
  1302. &dwType,
  1303. (LPBYTE) &dwValue,
  1304. &cbValue);
  1305. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1306. m_dwCostInitialRemote = dwValue;
  1307. }
  1308. cbValue = sizeof(dwValue);
  1309. dwErr = RegQueryValueEx(
  1310. hkey,
  1311. GC_COST_RETRY_LOCAL_VALUE,
  1312. NULL,
  1313. &dwType,
  1314. (LPBYTE) &dwValue,
  1315. &cbValue);
  1316. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1317. m_dwCostRetryLocal = dwValue;
  1318. }
  1319. cbValue = sizeof(dwValue);
  1320. dwErr = RegQueryValueEx(
  1321. hkey,
  1322. GC_COST_RETRY_REMOTE_VALUE,
  1323. NULL,
  1324. &dwType,
  1325. (LPBYTE) &dwValue,
  1326. &cbValue);
  1327. if (dwErr == ERROR_SUCCESS && dwType == REG_DWORD) {
  1328. m_dwCostRetryRemote = dwValue;
  1329. }
  1330. RegCloseKey( hkey );
  1331. }
  1332. }
  1333. //+------------------------------------------------------------
  1334. //
  1335. // Function: CLdapServerCfg::~CLdapServerCfg
  1336. //
  1337. // Synopsis: object destructor. Check and invalidate signature
  1338. //
  1339. // Arguments: NONE
  1340. //
  1341. // Returns: NOTHING
  1342. //
  1343. // History:
  1344. // jstamerj 1999/06/22 11:09:03: Created.
  1345. //
  1346. //-------------------------------------------------------------
  1347. CLdapServerCfg::~CLdapServerCfg()
  1348. {
  1349. CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::~CLdapServerCfg");
  1350. _ASSERT(m_dwSignature == SIGNATURE_CLDAPSERVERCFG);
  1351. m_dwSignature = SIGNATURE_CLDAPSERVERCFG_INVALID;
  1352. CatFunctLeaveEx((LPARAM)this);
  1353. } // CLdapServerCfg::~CLdapServerCfg
  1354. //+------------------------------------------------------------
  1355. //
  1356. // Function: CLdapServerCfg::HrInit
  1357. //
  1358. // Synopsis: Initialize with the passed in config
  1359. //
  1360. // Arguments:
  1361. // pCLdapCfg: the cfg object to notify when servers go down
  1362. // pServerConfig: The server config struct to use
  1363. //
  1364. // Returns:
  1365. // S_OK: Success
  1366. //
  1367. // History:
  1368. // jstamerj 1999/06/17 15:43:25: Created.
  1369. //
  1370. //-------------------------------------------------------------
  1371. HRESULT CLdapServerCfg::HrInit(
  1372. PLDAPSERVERCONFIG pServerConfig)
  1373. {
  1374. HRESULT hr = S_OK;
  1375. CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::HrInit");
  1376. CopyMemory(&m_ServerConfig, pServerConfig, sizeof(m_ServerConfig));
  1377. //
  1378. // Check if this is the local computer
  1379. //
  1380. if(fIsLocalComputer(pServerConfig))
  1381. m_fLocalServer = TRUE;
  1382. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1383. CatFunctLeaveEx((LPARAM)this);
  1384. return hr;
  1385. } // CLdapServerCfg::HrInit
  1386. //+------------------------------------------------------------
  1387. //
  1388. // Function: CLdapServerCfg::fIsLocalComputer
  1389. //
  1390. // Synopsis: Determine if pServerConfig is the local computer or not
  1391. //
  1392. // Arguments:
  1393. // pServerConfig: the server config info structure
  1394. //
  1395. // Returns:
  1396. // TRUE: Server is the local computer
  1397. // FALSE: Sevrver is a remote computer
  1398. //
  1399. // History:
  1400. // jstamerj 1999/06/22 15:26:53: Created.
  1401. //
  1402. //-------------------------------------------------------------
  1403. BOOL CLdapServerCfg::fIsLocalComputer(
  1404. PLDAPSERVERCONFIG pServerConfig)
  1405. {
  1406. BOOL fLocal = FALSE;
  1407. DWORD dwSize;
  1408. CHAR szHost[CAT_MAX_DOMAIN];
  1409. CatFunctEnterEx((LPARAM)NULL, "CLdapServerCfg::fIsLocalComputer");
  1410. //
  1411. // Check the FQ name
  1412. //
  1413. dwSize = sizeof(szHost);
  1414. if(GetComputerNameEx(
  1415. ComputerNameDnsFullyQualified,
  1416. szHost,
  1417. &dwSize) &&
  1418. (lstrcmpi(szHost, pServerConfig->szHost) == 0)) {
  1419. fLocal = TRUE;
  1420. goto CLEANUP;
  1421. }
  1422. //
  1423. // Check the DNS name
  1424. //
  1425. dwSize = sizeof(szHost);
  1426. if(GetComputerNameEx(
  1427. ComputerNameDnsHostname,
  1428. szHost,
  1429. &dwSize) &&
  1430. (lstrcmpi(szHost, pServerConfig->szHost) == 0)) {
  1431. fLocal = TRUE;
  1432. goto CLEANUP;
  1433. }
  1434. //
  1435. // Check the netbios name
  1436. //
  1437. dwSize = sizeof(szHost);
  1438. if(GetComputerNameEx(
  1439. ComputerNameNetBIOS,
  1440. szHost,
  1441. &dwSize) &&
  1442. (lstrcmpi(szHost, pServerConfig->szHost) == 0)) {
  1443. fLocal = TRUE;
  1444. goto CLEANUP;
  1445. }
  1446. CLEANUP:
  1447. DebugTrace((LPARAM)NULL, "returning %08lx", fLocal);
  1448. CatFunctLeaveEx((LPARAM)NULL);
  1449. return fLocal;
  1450. } // CLdapServerCfg::fIsLocalComputer
  1451. //+------------------------------------------------------------
  1452. //
  1453. // Function: CLdapServerCfg::Cost
  1454. //
  1455. // Synopsis: Return the cost of choosing this connection
  1456. //
  1457. // Arguments:
  1458. // pCost: Cost sturcture to fill in
  1459. //
  1460. // Returns: NOTHING
  1461. //
  1462. // History:
  1463. // jstamerj 1999/06/17 16:08:23: Created.
  1464. //
  1465. //-------------------------------------------------------------
  1466. VOID CLdapServerCfg::Cost(
  1467. IN ISMTPServerEx *pISMTPServerEx,
  1468. OUT PLDAPSERVERCOST pCost)
  1469. {
  1470. BOOL fShareLock = FALSE;
  1471. CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::Cost");
  1472. //
  1473. // The smallest unit of cost is the number of pending searches.
  1474. // The next factor of cost is the connection state.
  1475. // States:
  1476. // Connected = + COST_CONNECTED
  1477. // Initially state (unconnected) = + COST_INITIAL
  1478. // Connection down = + COST_RETRY
  1479. // Connection recently went down = + COST_DOWN
  1480. //
  1481. // A configurable priority is always added to the cost.
  1482. // Also, COST_REMOTE is added to the cost of all non-local servers.
  1483. //
  1484. *pCost = m_ServerConfig.pri + m_dwcPendingSearches;
  1485. //
  1486. // Protect the connection state variables with a spinlock
  1487. //
  1488. m_sharelock.ShareLock();
  1489. fShareLock = TRUE;
  1490. switch(m_connstate) {
  1491. case CONN_STATE_INITIAL:
  1492. (*pCost) += (m_fLocalServer) ? m_dwCostInitialLocal : m_dwCostInitialRemote;
  1493. break;
  1494. case CONN_STATE_RETRY:
  1495. if(m_dwcCurrentConnectAttempts >= MAX_CONNECT_THREADS)
  1496. (*pCost) += COST_TOO_HIGH_TO_CONNECT;
  1497. else
  1498. (*pCost) += (m_fLocalServer) ? m_dwCostRetryLocal : m_dwCostRetryRemote;
  1499. break;
  1500. case CONN_STATE_DOWN:
  1501. //
  1502. // Check if the state should be changed to CONN_STATE_RETRY
  1503. //
  1504. if(fReadyForRetry()) {
  1505. (*pCost) += (m_fLocalServer) ? m_dwCostRetryLocal : m_dwCostRetryRemote;
  1506. //
  1507. // Change state
  1508. //
  1509. fShareLock = FALSE;
  1510. m_sharelock.ShareUnlock();
  1511. m_sharelock.ExclusiveLock();
  1512. //
  1513. // Double check in the exclusive lock
  1514. //
  1515. if((m_connstate == CONN_STATE_DOWN) &&
  1516. fReadyForRetry()) {
  1517. LogStateChangeEvent(
  1518. pISMTPServerEx,
  1519. CONN_STATE_RETRY,
  1520. m_ServerConfig.szHost,
  1521. m_ServerConfig.dwPort);
  1522. m_connstate = CONN_STATE_RETRY;
  1523. }
  1524. m_sharelock.ExclusiveUnlock();
  1525. } else {
  1526. //
  1527. // Server is probably still down (don't retry yet)
  1528. //
  1529. (*pCost) += (m_fLocalServer) ? COST_DOWN_LOCAL : COST_DOWN_REMOTE;
  1530. }
  1531. break;
  1532. case CONN_STATE_CONNECTED:
  1533. (*pCost) += (m_fLocalServer) ? m_dwCostConnectedLocal : m_dwCostConnectedRemote;
  1534. break;
  1535. default:
  1536. // Nothing to add
  1537. break;
  1538. }
  1539. if(fShareLock)
  1540. m_sharelock.ShareUnlock();
  1541. CatFunctLeaveEx((LPARAM)this);
  1542. } // CLdapServerCfg::Cost
  1543. //+------------------------------------------------------------
  1544. //
  1545. // Function: CLdapServerCfg::HrGetConnection
  1546. //
  1547. // Synopsis:
  1548. //
  1549. // Arguments:
  1550. //
  1551. // Returns:
  1552. // S_OK: Success
  1553. //
  1554. // History:
  1555. // jstamerj 1999/06/18 10:49:04: Created.
  1556. //
  1557. //-------------------------------------------------------------
  1558. HRESULT CLdapServerCfg::HrGetConnection(
  1559. ISMTPServerEx *pISMTPServerEx,
  1560. CCfgConnection **ppConn,
  1561. CCfgConnectionCache *pLdapConnectionCache)
  1562. {
  1563. HRESULT hr = S_OK;
  1564. DWORD dwcConnectAttempts = 0;
  1565. CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::HrGetConnection");
  1566. dwcConnectAttempts = (DWORD) InterlockedIncrement((PLONG) &m_dwcCurrentConnectAttempts);
  1567. m_sharelock.ShareLock();
  1568. if((m_connstate == CONN_STATE_RETRY) &&
  1569. (dwcConnectAttempts > MAX_CONNECT_THREADS)) {
  1570. m_sharelock.ShareUnlock();
  1571. ErrorTrace((LPARAM)this, "Over max connect thread limit");
  1572. hr = HRESULT_FROM_WIN32(ERROR_RETRY);
  1573. ERROR_LOG_STATIC(
  1574. "--over max connect thread limit--",
  1575. this,
  1576. pISMTPServerEx);
  1577. goto CLEANUP;
  1578. }
  1579. m_sharelock.ShareUnlock();
  1580. DebugTrace((LPARAM)this, "Attempting to connect to %s:%d",
  1581. m_ServerConfig.szHost,
  1582. m_ServerConfig.dwPort);
  1583. hr = pLdapConnectionCache->GetConnection(
  1584. ppConn,
  1585. &m_ServerConfig,
  1586. this);
  1587. ERROR_CLEANUP_LOG_STATIC(
  1588. "pLdapConnectionCache->GetConnection",
  1589. this,
  1590. pISMTPServerEx);
  1591. //
  1592. // CCfgConnection::Connect will update the connection state
  1593. //
  1594. CLEANUP:
  1595. InterlockedDecrement((PLONG) &m_dwcCurrentConnectAttempts);
  1596. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1597. CatFunctLeaveEx((LPARAM)this);
  1598. return hr;
  1599. } // CLdapServerCfg::HrGetConnection
  1600. //+------------------------------------------------------------
  1601. //
  1602. // Function: CLdapServerCfg::UpdateConnectionState
  1603. //
  1604. // Synopsis: Update the connection state.
  1605. //
  1606. // Arguments:
  1607. // pft: Time of update -- if this time is before the last update done,
  1608. // then this update will be ignored.
  1609. // If NULL, the function will assume the current time.
  1610. // connstate: The new connection state.
  1611. //
  1612. // Returns: NOTHING
  1613. //
  1614. // History:
  1615. // jstamerj 1999/06/18 13:22:25: Created.
  1616. //
  1617. //-------------------------------------------------------------
  1618. VOID CLdapServerCfg::UpdateConnectionState(
  1619. ISMTPServerEx *pISMTPServerEx,
  1620. ULARGE_INTEGER *pft_IN,
  1621. CONN_STATE connstate)
  1622. {
  1623. ULARGE_INTEGER ft, *pft;
  1624. CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::UpdateConnectionState");
  1625. if(pft_IN != NULL) {
  1626. pft = pft_IN;
  1627. } else {
  1628. ft = GetCurrentTime();
  1629. pft = &ft;
  1630. }
  1631. //
  1632. // Protect connection state variables with a sharelock
  1633. //
  1634. m_sharelock.ShareLock();
  1635. //
  1636. // If we have the latest information about the connection state,
  1637. // then update the state if the connection state changed.
  1638. // Also update m_ftLastStateUpdate to the latest ft when the
  1639. // connection state is down -- m_ftLastStateUpdate is assumed to
  1640. // be the last connection attempt time when connstate is down.
  1641. //
  1642. if( (pft->QuadPart > m_ftLastStateUpdate.QuadPart) &&
  1643. ((m_connstate != connstate) ||
  1644. (connstate == CONN_STATE_DOWN))) {
  1645. //
  1646. // We'd like to update the connection state
  1647. //
  1648. m_sharelock.ShareUnlock();
  1649. m_sharelock.ExclusiveLock();
  1650. //
  1651. // Double check
  1652. //
  1653. if( (pft->QuadPart > m_ftLastStateUpdate.QuadPart) &&
  1654. ((m_connstate != connstate) ||
  1655. (connstate == CONN_STATE_DOWN))) {
  1656. //
  1657. // Update
  1658. //
  1659. if(m_connstate != connstate) {
  1660. LogStateChangeEvent(
  1661. pISMTPServerEx,
  1662. connstate,
  1663. m_ServerConfig.szHost,
  1664. m_ServerConfig.dwPort);
  1665. }
  1666. m_ftLastStateUpdate = *pft;
  1667. m_connstate = connstate;
  1668. DebugTrace((LPARAM)this, "Updating state %d, conn %s:%d",
  1669. connstate,
  1670. m_ServerConfig.szHost,
  1671. m_ServerConfig.dwPort);
  1672. } else {
  1673. DebugTrace((LPARAM)this, "Ignoring state update %d, conn %s:%d",
  1674. connstate,
  1675. m_ServerConfig.szHost,
  1676. m_ServerConfig.dwPort);
  1677. }
  1678. m_sharelock.ExclusiveUnlock();
  1679. } else {
  1680. DebugTrace((LPARAM)this, "Ignoring state update %d, conn %s:%d",
  1681. connstate,
  1682. m_ServerConfig.szHost,
  1683. m_ServerConfig.dwPort);
  1684. m_sharelock.ShareUnlock();
  1685. }
  1686. CatFunctLeaveEx((LPARAM)this);
  1687. } // CLdapServerCfg::UpdateConnectionState
  1688. //+------------------------------------------------------------
  1689. //
  1690. // Function: CLdapServerCfg::GetServerCfg
  1691. //
  1692. // Synopsis: Find or Create a CLdapServerCfg object with the specified
  1693. // configuration.
  1694. //
  1695. // Arguments:
  1696. // pServerConfig: desired configuration
  1697. // pCLdapServerCfg: return pointer for the CLdapServerCfg object
  1698. //
  1699. // Returns:
  1700. // S_OK: Success
  1701. // E_OUTOFMEMORY
  1702. //
  1703. // History:
  1704. // jstamerj 1999/06/21 11:26:49: Created.
  1705. //
  1706. //-------------------------------------------------------------
  1707. HRESULT CLdapServerCfg::GetServerCfg(
  1708. IN ISMTPServerEx *pISMTPServerEx,
  1709. IN PLDAPSERVERCONFIG pServerConfig,
  1710. OUT CLdapServerCfg **ppCLdapServerCfg)
  1711. {
  1712. HRESULT hr = S_OK;
  1713. CLdapServerCfg *pCCfg;
  1714. CatFunctEnterEx((LPARAM)NULL, "CLdapServerCfg::GetServerCfg");
  1715. m_listlock.ShareLock();
  1716. pCCfg = FindServerCfg(pServerConfig);
  1717. if(pCCfg)
  1718. pCCfg->AddRef();
  1719. m_listlock.ShareUnlock();
  1720. if(pCCfg == NULL) {
  1721. //
  1722. // Check again for a server cfg object inside an exclusive
  1723. // lock
  1724. //
  1725. m_listlock.ExclusiveLock();
  1726. pCCfg = FindServerCfg(pServerConfig);
  1727. if(pCCfg) {
  1728. pCCfg->AddRef();
  1729. } else {
  1730. //
  1731. // Create a new object
  1732. //
  1733. pCCfg = new CLdapServerCfg();
  1734. if(pCCfg == NULL) {
  1735. hr = E_OUTOFMEMORY;
  1736. ERROR_LOG_STATIC(
  1737. "new CLdapServerCfg",
  1738. 0,
  1739. pISMTPServerEx);
  1740. } else {
  1741. hr = pCCfg->HrInit(pServerConfig);
  1742. if(FAILED(hr)) {
  1743. ERROR_LOG_STATIC(
  1744. "pCCfg->HrInit",
  1745. pCCfg,
  1746. pISMTPServerEx);
  1747. delete pCCfg;
  1748. pCCfg = NULL;
  1749. } else {
  1750. //
  1751. // Add to global list
  1752. //
  1753. InsertTailList(&m_listhead, &(pCCfg->m_le));
  1754. }
  1755. }
  1756. }
  1757. m_listlock.ExclusiveUnlock();
  1758. }
  1759. //
  1760. // Set out parameter
  1761. //
  1762. *ppCLdapServerCfg = pCCfg;
  1763. DebugTrace((LPARAM)NULL, "returning hr %08lx", hr);
  1764. CatFunctLeaveEx((LPARAM)NULL);
  1765. return hr;
  1766. } // CLdapServerCfg::GetServerCfg
  1767. //+------------------------------------------------------------
  1768. //
  1769. // Function: CLdapServerCfg::FindServerCfg
  1770. //
  1771. // Synopsis: Find a server cfg object that matches the
  1772. // LDAPSERVERCONFIG structure. Note, m_listlock must be
  1773. // locked when calling this function.
  1774. //
  1775. // Arguments:
  1776. // pServerConfig: pointer to the LDAPSERVERCONFIG struct
  1777. //
  1778. // Returns:
  1779. // NULL: there is no such server cfg object
  1780. // else, ptr to the found CLdapServerCfg object
  1781. //
  1782. // History:
  1783. // jstamerj 1999/06/21 10:43:23: Created.
  1784. //
  1785. //-------------------------------------------------------------
  1786. CLdapServerCfg * CLdapServerCfg::FindServerCfg(
  1787. PLDAPSERVERCONFIG pServerConfig)
  1788. {
  1789. CLdapServerCfg *pMatch = NULL;
  1790. PLIST_ENTRY ple;
  1791. CatFunctEnterEx((LPARAM)NULL, "CLdapServerCfg::FindServerCfg");
  1792. for(ple = m_listhead.Flink;
  1793. (ple != &m_listhead) && (pMatch == NULL);
  1794. ple = ple->Flink) {
  1795. CLdapServerCfg *pCandidate = NULL;
  1796. pCandidate = CONTAINING_RECORD(ple, CLdapServerCfg, m_le);
  1797. if(pCandidate->fMatch(
  1798. pServerConfig)) {
  1799. pMatch = pCandidate;
  1800. }
  1801. }
  1802. CatFunctLeaveEx((LPARAM)NULL);
  1803. return pMatch;
  1804. } // CLdapServerCfg::FindServerCfg
  1805. //+------------------------------------------------------------
  1806. //
  1807. // Function: CLdapServerCfg::fMatch
  1808. //
  1809. // Synopsis: Determine if this object matches the passed in config
  1810. //
  1811. // Arguments:
  1812. // pServerConfig: config to check against
  1813. //
  1814. // Returns:
  1815. // TRUE: match
  1816. // FALSE: no match
  1817. //
  1818. // History:
  1819. // jstamerj 1999/06/21 12:45:10: Created.
  1820. //
  1821. //-------------------------------------------------------------
  1822. BOOL CLdapServerCfg::fMatch(
  1823. PLDAPSERVERCONFIG pServerConfig)
  1824. {
  1825. BOOL fRet;
  1826. CatFunctEnterEx((LPARAM)this, "CLdapServerCfg::fMatch");
  1827. if((pServerConfig->dwPort != m_ServerConfig.dwPort) ||
  1828. (pServerConfig->bt != m_ServerConfig.bt) ||
  1829. (lstrcmpi(pServerConfig->szHost,
  1830. m_ServerConfig.szHost) != 0) ||
  1831. (lstrcmpi(pServerConfig->szNamingContext,
  1832. m_ServerConfig.szNamingContext) != 0) ||
  1833. (lstrcmpi(pServerConfig->szAccount,
  1834. m_ServerConfig.szAccount) != 0) ||
  1835. (lstrcmpi(pServerConfig->szPassword,
  1836. m_ServerConfig.szPassword) != 0)) {
  1837. fRet = FALSE;
  1838. } else {
  1839. fRet = TRUE;
  1840. }
  1841. DebugTrace((LPARAM)this, "returning %08lx", fRet);
  1842. CatFunctLeaveEx((LPARAM)this);
  1843. return fRet;
  1844. } // CLdapServerCfg::fMatch
  1845. //+------------------------------------------------------------
  1846. //
  1847. // Function: CLdapServerCfg::LogStateChangeEvent
  1848. //
  1849. // Synopsis: Log an eventlog for a state change event
  1850. //
  1851. // Arguments:
  1852. // pISMTPServerEx: interface for logging
  1853. // connstate: new connstate
  1854. // pszHost: host for connection
  1855. // dwPort: port of connection
  1856. //
  1857. // Returns: Nothing
  1858. //
  1859. // History:
  1860. // jstamerj 2001/12/13 01:43:13: Created.
  1861. //
  1862. //-------------------------------------------------------------
  1863. VOID CLdapServerCfg::LogStateChangeEvent(
  1864. IN ISMTPServerEx *pISMTPServerEx,
  1865. IN CONN_STATE connstate,
  1866. IN LPSTR pszHost,
  1867. IN DWORD dwPort)
  1868. {
  1869. DWORD idEvent = 0;
  1870. LPCSTR rgSubStrings[2];
  1871. CHAR szPort[16];
  1872. _snprintf(szPort, sizeof(szPort), "%d", dwPort);
  1873. rgSubStrings[0] = pszHost;
  1874. rgSubStrings[1] = szPort;
  1875. switch(connstate)
  1876. {
  1877. case CONN_STATE_CONNECTED:
  1878. idEvent = CAT_EVENT_CNFGMGR_CONNECTED;
  1879. break;
  1880. case CONN_STATE_DOWN:
  1881. idEvent = CAT_EVENT_CNFGMGR_DOWN;
  1882. break;
  1883. case CONN_STATE_RETRY:
  1884. idEvent = CAT_EVENT_CNFGMGR_RETRY;
  1885. break;
  1886. default:
  1887. break;
  1888. }
  1889. if(idEvent)
  1890. {
  1891. CatLogEvent(
  1892. pISMTPServerEx,
  1893. idEvent,
  1894. 2,
  1895. rgSubStrings,
  1896. S_OK,
  1897. pszHost,
  1898. LOGEVENT_FLAG_ALWAYS,
  1899. LOGEVENT_LEVEL_MEDIUM);
  1900. }
  1901. }
  1902. //+------------------------------------------------------------
  1903. //
  1904. // Function: CCfgConnection::Connect
  1905. //
  1906. // Synopsis: Cfg wrapper for the Connect call.
  1907. //
  1908. // Arguments: None
  1909. //
  1910. // Returns:
  1911. // S_OK: Success
  1912. // CAT_E_DBCONNECTION (or whatever CBatchLdapConnection::Connect returns)
  1913. //
  1914. // History:
  1915. // jstamerj 2000/04/13 17:44:43: Created.
  1916. //
  1917. //-------------------------------------------------------------
  1918. HRESULT CCfgConnection::Connect()
  1919. {
  1920. HRESULT hr = S_OK;
  1921. ULARGE_INTEGER ft;
  1922. CONN_STATE connstate;
  1923. CatFunctEnterEx((LPARAM)this, "CCfgConnection::Connect");
  1924. connstate = m_pCLdapServerCfg->CurrentState();
  1925. if(connstate == CONN_STATE_DOWN) {
  1926. DebugTrace((LPARAM)this, "Not connecting because %s:%d is down",
  1927. m_szHost, m_dwPort);
  1928. hr = CAT_E_DBCONNECTION;
  1929. ERROR_LOG("m_pCLdapServerCfg->CurrentState");
  1930. goto CLEANUP;
  1931. }
  1932. ft = m_pCLdapServerCfg->GetCurrentTime();
  1933. hr = CBatchLdapConnection::Connect();
  1934. if(FAILED(hr)) {
  1935. connstate = CONN_STATE_DOWN;
  1936. m_pCLdapServerCfg->IncrementFailedCount();
  1937. ERROR_LOG("CBatchLdapConnection::Connect");
  1938. } else {
  1939. connstate = CONN_STATE_CONNECTED;
  1940. m_pCLdapServerCfg->ResetFailedCount();
  1941. }
  1942. //
  1943. // Update the connection state while inside CLdapConnectionCache's
  1944. // lock. This will prevent a succeeding thread from attempting
  1945. // another connection to the GC right after CLdapConnectionCache
  1946. // releases its lock. Contact msanna for more details.
  1947. //
  1948. m_pCLdapServerCfg->UpdateConnectionState(
  1949. GetISMTPServerEx(), &ft, connstate);
  1950. CLEANUP:
  1951. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1952. CatFunctLeaveEx((LPARAM)this);
  1953. return hr;
  1954. } // CCfgConnection::Connect
  1955. //+------------------------------------------------------------
  1956. //
  1957. // Function: CCfgConnection::AsyncSearch
  1958. //
  1959. // Synopsis: Wrapper around AsyncSearch -- keep track of the # of
  1960. // pending searches and connection state.
  1961. //
  1962. // Arguments: See CLdapConnection::AsyncSearch
  1963. //
  1964. // Returns:
  1965. // Value returned from CLdapConnection::AsyncSearch
  1966. //
  1967. // History:
  1968. // jstamerj 1999/06/18 13:49:45: Created.
  1969. //
  1970. //-------------------------------------------------------------
  1971. HRESULT CCfgConnection::AsyncSearch(
  1972. LPCWSTR szBaseDN,
  1973. int nScope,
  1974. LPCWSTR szFilter,
  1975. LPCWSTR szAttributes[],
  1976. DWORD dwPageSize,
  1977. LPLDAPCOMPLETION fnCompletion,
  1978. LPVOID ctxCompletion)
  1979. {
  1980. HRESULT hr = S_OK;
  1981. CatFunctEnterEx((LPARAM)this, "CCfgConnection::AsyncSearch");
  1982. m_pCLdapServerCfg->IncrementPendingSearches();
  1983. hr = CBatchLdapConnection::AsyncSearch(
  1984. szBaseDN,
  1985. nScope,
  1986. szFilter,
  1987. szAttributes,
  1988. dwPageSize,
  1989. fnCompletion,
  1990. ctxCompletion);
  1991. if(FAILED(hr)) {
  1992. ERROR_LOG("CBatchLdapConnection::AsyncSearch");
  1993. m_pCLdapServerCfg->DecrementPendingSearches();
  1994. }
  1995. DebugTrace((LPARAM)this, "returning %08lx", hr);
  1996. CatFunctLeaveEx((LPARAM)this);
  1997. return hr;
  1998. } // CCfgConnection::AsyncSearch
  1999. //+------------------------------------------------------------
  2000. //
  2001. // Function: CCfgConnection::CallCompletion
  2002. //
  2003. // Synopsis: Wrapper around CLdapConnection::CallCompletion. Checks
  2004. // for server down errors and keeps track of pending searches.
  2005. //
  2006. // Arguments: See CLdapConnection::CallCompletion
  2007. //
  2008. // Returns: See CLdapConnection::CallCompletion
  2009. //
  2010. // History:
  2011. // jstamerj 1999/06/18 13:58:28: Created.
  2012. //
  2013. //-------------------------------------------------------------
  2014. VOID CCfgConnection::CallCompletion(
  2015. PPENDING_REQUEST preq,
  2016. PLDAPMessage pres,
  2017. HRESULT hrStatus,
  2018. BOOL fFinalCompletion)
  2019. {
  2020. CatFunctEnterEx((LPARAM)this, "CCfgConnection::CallCompletion");
  2021. //
  2022. // The user(s) of CLdapConnection normally try to get a new
  2023. // connection and reissue their search when AsyncSearch
  2024. // fails. When opening a new connection fails, CLdapServerCfg
  2025. // will be notified that the LDAP server is down. We do not
  2026. // want to call NotifyServerDown() here because the LDAP
  2027. // server may have just closed this connection due to idle
  2028. // time (the server may not actually be down).
  2029. //
  2030. if(fFinalCompletion) {
  2031. m_pCLdapServerCfg->DecrementPendingSearches();
  2032. }
  2033. CBatchLdapConnection::CallCompletion(
  2034. preq,
  2035. pres,
  2036. hrStatus,
  2037. fFinalCompletion);
  2038. CatFunctLeaveEx((LPARAM)this);
  2039. } // CCfgConnection::CallCompletion
  2040. //+------------------------------------------------------------
  2041. //
  2042. // Function: CCfgConnection::NotifyServerDown
  2043. //
  2044. // Synopsis: Notify the server config that this connection is down.
  2045. // If we already notified it, don't do so again.
  2046. //
  2047. // Arguments: NONE
  2048. //
  2049. // Returns: NOTHING
  2050. //
  2051. // History:
  2052. // jstamerj 1999/06/18 14:07:48: Created.
  2053. //
  2054. //-------------------------------------------------------------
  2055. VOID CCfgConnection::NotifyServerDown()
  2056. {
  2057. BOOL fNotify;
  2058. CatFunctEnterEx((LPARAM)this, "CCfgConnection::NotifyServerDown");
  2059. m_sharelock.ShareLock();
  2060. if(m_connstate == CONN_STATE_DOWN) {
  2061. //
  2062. // We already notified m_pCLdapServerCfg the server went
  2063. // down. Don't repeteadly call it
  2064. //
  2065. fNotify = FALSE;
  2066. m_sharelock.ShareUnlock();
  2067. } else {
  2068. m_sharelock.ShareUnlock();
  2069. m_sharelock.ExclusiveLock();
  2070. //
  2071. // Double check
  2072. //
  2073. if(m_connstate == CONN_STATE_DOWN) {
  2074. fNotify = FALSE;
  2075. } else {
  2076. m_connstate = CONN_STATE_DOWN;
  2077. fNotify = TRUE;
  2078. }
  2079. m_sharelock.ExclusiveUnlock();
  2080. }
  2081. if(fNotify)
  2082. m_pCLdapServerCfg->UpdateConnectionState(
  2083. GetISMTPServerEx(),
  2084. NULL, // Current time
  2085. CONN_STATE_DOWN);
  2086. CatFunctLeaveEx((LPARAM)this);
  2087. } // CCfgConnection::NotifyServerDown
  2088. //+------------------------------------------------------------
  2089. //
  2090. // Function: CatStoreInitGlobals
  2091. //
  2092. // Synopsis: This is called to initialize global variables in the
  2093. // store layer.
  2094. //
  2095. // Arguments: NONE
  2096. //
  2097. // Returns:
  2098. // S_OK: Success
  2099. //
  2100. // History:
  2101. // jstamerj 1999/06/22 11:03:53: Created.
  2102. //
  2103. //-------------------------------------------------------------
  2104. HRESULT CatStoreInitGlobals()
  2105. {
  2106. CatFunctEnterEx((LPARAM)NULL, "CatStoreInitGlobals");
  2107. CLdapServerCfg::GlobalInit();
  2108. CLdapConnection::GlobalInit();
  2109. CatFunctLeaveEx((LPARAM)NULL);
  2110. return S_OK;
  2111. } // CatStoreInitGlobals
  2112. //+------------------------------------------------------------
  2113. //
  2114. // Function: CatStoreDeinitGlobals
  2115. //
  2116. // Synopsis: Called to deinitialize store layer globals -- called once
  2117. // only when CatStoreInitGlobals succeeds
  2118. //
  2119. // Arguments: NONE
  2120. //
  2121. // Returns: NOTHING
  2122. //
  2123. // History:
  2124. // jstamerj 1999/06/22 11:05:44: Created.
  2125. //
  2126. //-------------------------------------------------------------
  2127. VOID CatStoreDeinitGlobals()
  2128. {
  2129. CatFunctEnterEx((LPARAM)NULL, "CatStoreDeinitGlobals");
  2130. //
  2131. // Nothing to do
  2132. //
  2133. CatFunctLeaveEx((LPARAM)NULL);
  2134. } // CatStoreDeinitGlobals
  2135. //+------------------------------------------------------------
  2136. //
  2137. // Function: CCfgConnectionCache::GetConnection
  2138. //
  2139. // Synopsis: Same as CLdapConnectionCache::GetConnection, except
  2140. // retrieves a CCfgConnection instead of a CLdapConnection.
  2141. //
  2142. // Arguments:
  2143. // ppConn: out parameter for new connection
  2144. // pServerConfig: desired configuration
  2145. // pCLdapServerConfig: Pointer to config object
  2146. //
  2147. // Returns:
  2148. // S_OK: Success
  2149. //
  2150. // History:
  2151. // jstamerj 1999/12/20 16:49:12: Created.
  2152. //
  2153. //-------------------------------------------------------------
  2154. HRESULT CCfgConnectionCache::GetConnection(
  2155. CCfgConnection **ppConn,
  2156. PLDAPSERVERCONFIG pServerConfig,
  2157. CLdapServerCfg *pCLdapServerConfig)
  2158. {
  2159. HRESULT hr = S_OK;
  2160. CatFunctEnterEx((LPARAM)this, "CCfgConnectionCache::GetConnection");
  2161. hr = CBatchLdapConnectionCache::GetConnection(
  2162. (CBatchLdapConnection **)ppConn,
  2163. pServerConfig->szHost,
  2164. pServerConfig->dwPort,
  2165. pServerConfig->szNamingContext,
  2166. pServerConfig->szAccount,
  2167. pServerConfig->szPassword,
  2168. pServerConfig->bt,
  2169. (PVOID) pCLdapServerConfig); // pCreateContext
  2170. if(FAILED(hr))
  2171. {
  2172. ERROR_LOG("CBatchldapConnection::GetConnection");
  2173. }
  2174. CatFunctLeaveEx((LPARAM)this);
  2175. return hr;
  2176. } // CCfgConnectionCache::GetConnection
  2177. //+------------------------------------------------------------
  2178. //
  2179. // Function: CCfgConnectionCache::CreateCachedLdapConnection
  2180. //
  2181. // Synopsis: Create a CCfgConnection (Called by GetConnection only)
  2182. //
  2183. // Arguments: See CLdapConnectionCache::CreateCachedLdapConnection
  2184. //
  2185. // Returns:
  2186. // Connection ptr if successfull.
  2187. // NULL if unsuccessfull.
  2188. //
  2189. // History:
  2190. // jstamerj 1999/12/20 16:57:49: Created.
  2191. //
  2192. //-------------------------------------------------------------
  2193. CCfgConnectionCache::CCachedLdapConnection * CCfgConnectionCache::CreateCachedLdapConnection(
  2194. LPSTR szHost,
  2195. DWORD dwPort,
  2196. LPSTR szNamingContext,
  2197. LPSTR szAccount,
  2198. LPSTR szPassword,
  2199. LDAP_BIND_TYPE bt,
  2200. PVOID pCreateContext)
  2201. {
  2202. HRESULT hr = S_OK;
  2203. CCfgConnection *pret;
  2204. CatFunctEnterEx((LPARAM)this, "CCfgConnectionCache::CreateCachedLdapConnection");
  2205. pret = new CCfgConnection(
  2206. szHost,
  2207. dwPort,
  2208. szNamingContext,
  2209. szAccount,
  2210. szPassword,
  2211. bt,
  2212. this,
  2213. (CLdapServerCfg *)pCreateContext);
  2214. if(pret) {
  2215. hr = pret->HrInitialize();
  2216. if(FAILED(hr)) {
  2217. ERROR_LOG("pret->HrInitialize");
  2218. pret->Release();
  2219. pret = NULL;
  2220. }
  2221. } else {
  2222. hr = E_OUTOFMEMORY;
  2223. ERROR_LOG("new CCfgConnection");
  2224. }
  2225. CatFunctLeaveEx((LPARAM)this);
  2226. return pret;
  2227. } // CCfgConnectionCache::CreateCachedLdapConnection