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.

556 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1998
  6. //
  7. // File: dcbufmgr.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include "dcbufmgr.h"
  12. #include "process.h"
  13. #ifdef _DEBUG
  14. #define new DEBUG_NEW
  15. #undef THIS_FILE
  16. static char THIS_FILE[] = __FILE__;
  17. #endif
  18. #define DSGETDCINFO_LEVEL_1 1
  19. unsigned __stdcall GetDCThreadFunc( void* lParam );
  20. //+---------------------------------------------------------------------------
  21. //
  22. // Function: CDCBufferManager::CDCBufferManager
  23. //
  24. // Synopsis: constructor
  25. //
  26. //----------------------------------------------------------------------------
  27. CDCBufferManager::CDCBufferManager(HWND hDlg) :
  28. m_cRef(0), m_hDlg(hDlg)
  29. {
  30. TRACE(_T("CDCBufferManager::CDCBufferManager, this=%x\n"), this);
  31. m_lContinue = 1;
  32. }
  33. //+---------------------------------------------------------------------------
  34. //
  35. // Function: CDCBufferManager::~CDCBufferManager
  36. //
  37. // Synopsis: destructor
  38. //
  39. //----------------------------------------------------------------------------
  40. CDCBufferManager::~CDCBufferManager()
  41. {
  42. TRACE(_T("CDCBufferManager::~CDCBufferManager, this=%x\n"), this);
  43. ASSERT(0 >= m_cRef);
  44. FreeBuffer();
  45. }
  46. //+---------------------------------------------------------------------------
  47. //
  48. // Function: CDCBufferManager::CreateInstance
  49. //
  50. // Synopsis: Create an instance of CDCBufferManager.
  51. //
  52. //----------------------------------------------------------------------------
  53. HRESULT
  54. CDCBufferManager::CreateInstance(
  55. IN HWND hDlg,
  56. OUT CDCBufferManager **ppDCBufferManager
  57. )
  58. {
  59. TRACE(_T("CDCBufferManager::CreateInstance, hDlg=%x\n"), hDlg);
  60. ASSERT(ppDCBufferManager);
  61. *ppDCBufferManager = new CDCBufferManager(hDlg);
  62. if ( !(*ppDCBufferManager) )
  63. return E_OUTOFMEMORY;
  64. (*ppDCBufferManager)->AddRef();
  65. return S_OK;
  66. }
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Function: CDCBufferManager::AddRef
  70. //
  71. // Synopsis: Increment reference count of this instance
  72. //
  73. //----------------------------------------------------------------------------
  74. LONG
  75. CDCBufferManager::AddRef()
  76. {
  77. TRACE(_T("CDCBufferManager::AddRef, this=%x, preValue=%d\n"), this, m_cRef);
  78. return InterlockedIncrement(&m_cRef);
  79. }
  80. //+---------------------------------------------------------------------------
  81. //
  82. // Function: CDCBufferManager::Release
  83. //
  84. // Synopsis: Decrement reference count of this instance.
  85. // When the reference count reaches 0, delete this instance.
  86. //
  87. //----------------------------------------------------------------------------
  88. LONG
  89. CDCBufferManager::Release()
  90. {
  91. TRACE(_T("CDCBufferManager::Release, this=%x, preValue=%d\n"), this, m_cRef);
  92. if (InterlockedDecrement(&m_cRef) <= 0)
  93. {
  94. delete this;
  95. return 0;
  96. }
  97. return m_cRef;
  98. }
  99. //+---------------------------------------------------------------------------
  100. //
  101. // Function: CDCBufferManager::SignalExit
  102. //
  103. // Synopsis: Called by the owner dialog to signal the related threads to exit.
  104. //
  105. //----------------------------------------------------------------------------
  106. void
  107. CDCBufferManager::SignalExit()
  108. {
  109. TRACE(_T("CDCBufferManager::SignalExit\n"));
  110. InterlockedExchange(&m_lContinue, FALSE);
  111. }
  112. //+---------------------------------------------------------------------------
  113. //
  114. // Function: CDCBufferManager::ShouldExit
  115. //
  116. // Synopsis: Threads are calling this function periodically to see
  117. // if the owner dialog signals them to exit.
  118. //
  119. //----------------------------------------------------------------------------
  120. BOOL
  121. CDCBufferManager::ShouldExit()
  122. {
  123. TRACE(_T("CDCBufferManager::ShouldExit %d\n"), !m_lContinue);
  124. return (!m_lContinue);
  125. }
  126. //+---------------------------------------------------------------------------
  127. //
  128. // Function: CDCBufferManager::LoadInfo
  129. //
  130. // Synopsis: The Owner dialog call it to get a pointer to the info of the specified domain.
  131. // The buffer consists of entries.
  132. // Each entry is in the form of (LPTSTR szDomainName, CDCSITEINFO* pEntry).
  133. //
  134. // LoadInfo() will first look up in the buffer.
  135. // If a valid entry is found, pass back pEntry to caller.
  136. // If an error entry is found, reset it (clear the error) and retry.
  137. // If an inprogress entry is found, do nothing. The caller will handle a THREAD_DONE later.
  138. // If no entry in the buffer, create a new entry, kick off a thread.
  139. //
  140. // When the owner dialog get THREAD_DONE message, the related entry
  141. // in the buffer should either be a valid entry or an error entry.
  142. //
  143. //----------------------------------------------------------------------------
  144. HRESULT
  145. CDCBufferManager::LoadInfo(
  146. IN PCTSTR pszDomainDnsName,
  147. OUT CDCSITEINFO **ppInfo
  148. )
  149. {
  150. ASSERT(pszDomainDnsName);
  151. ASSERT(*pszDomainDnsName);
  152. ASSERT(ppInfo);
  153. ASSERT(*ppInfo == NULL); // prevent memory leak
  154. TRACE(_T("CDCBufferManager::LoadInfo for %s\n"), pszDomainDnsName);
  155. BOOL bStartNewThread = FALSE;
  156. HRESULT hr = S_OK;
  157. PVOID ptr = NULL;
  158. CDCSITEINFO* pEntry = NULL;
  159. m_CriticalSection.Lock(); // Lock buffer
  160. if (m_map.Lookup(pszDomainDnsName, ptr))
  161. {
  162. //
  163. // Found an entry in the buffer.
  164. //
  165. if (ptr)
  166. {
  167. pEntry = (CDCSITEINFO*)ptr;
  168. switch (pEntry->GetEntryType())
  169. {
  170. case BUFFER_ENTRY_TYPE_VALID:
  171. // return the valid entry pointer
  172. *ppInfo = pEntry;
  173. break;
  174. case BUFFER_ENTRY_TYPE_ERROR:
  175. // kick off a thread to retry
  176. pEntry->ReSet();
  177. bStartNewThread = TRUE;
  178. break;
  179. case BUFFER_ENTRY_TYPE_INPROGRESS:
  180. // do nothing
  181. break;
  182. }
  183. }
  184. } else
  185. {
  186. //
  187. // not found in the buffer, need to start a new thread
  188. //
  189. bStartNewThread = TRUE;
  190. pEntry = new CDCSITEINFO();
  191. if (pEntry)
  192. m_map.SetAt(pszDomainDnsName, pEntry);
  193. else
  194. hr = E_OUTOFMEMORY;
  195. }
  196. if (SUCCEEDED(hr) && bStartNewThread)
  197. {
  198. hr = StartThread(pszDomainDnsName);
  199. if (FAILED(hr))
  200. {
  201. delete pEntry;
  202. m_map.RemoveKey(pszDomainDnsName);
  203. }
  204. }
  205. m_CriticalSection.Unlock(); // Unlock buffer
  206. return hr;
  207. }
  208. //+---------------------------------------------------------------------------
  209. //
  210. // Function: CDCBufferManager::AddInfo
  211. //
  212. // Synopsis: Called by the thread function to add one result to the buffer.
  213. // It will pass back the pointer to the entry in the 5th parameters.
  214. //
  215. //----------------------------------------------------------------------------
  216. HRESULT
  217. CDCBufferManager::AddInfo(
  218. IN PCTSTR pszDomainDnsName,
  219. IN DWORD cInfo,
  220. IN PVOID pDCInfo,
  221. IN HRESULT hr,
  222. OUT PVOID* ppv
  223. )
  224. {
  225. ASSERT(pszDomainDnsName);
  226. ASSERT(*pszDomainDnsName);
  227. ASSERT(ppv);
  228. ASSERT(*ppv == NULL); // prevent memory leak
  229. TRACE(_T("CDCBufferManager::AddInfo for %s, cInfo=%d, hr=%x\n"),
  230. pszDomainDnsName, cInfo, hr);
  231. PVOID p = NULL;
  232. m_CriticalSection.Lock(); // Lock buffer
  233. //
  234. // the entry must have been existed with a non-NULL pointer
  235. //
  236. m_map.Lookup(pszDomainDnsName, p);
  237. ASSERT(p);
  238. ((CDCSITEINFO*)p)->SetEntry(pszDomainDnsName, cInfo, pDCInfo, hr);
  239. m_CriticalSection.Unlock(); // Unlock buffer
  240. *ppv = p;
  241. return hr;
  242. }
  243. //+---------------------------------------------------------------------------
  244. //
  245. // Function: CDCBufferManager::FreeBuffer
  246. //
  247. // Synopsis: Clear m_map.
  248. // This member holds all the results returned by various threads
  249. // since the initialization of the owner dialog. Each one is
  250. // in the form of (DomainName ==> CDCSITEINFO*)
  251. //
  252. //----------------------------------------------------------------------------
  253. void
  254. CDCBufferManager::FreeBuffer()
  255. {
  256. CString csDomainDnsName;
  257. PVOID ptr = NULL;
  258. m_CriticalSection.Lock(); // Lock buffer
  259. for (POSITION pos = m_map.GetStartPosition(); pos; )
  260. {
  261. m_map.GetNextAssoc(pos, csDomainDnsName, ptr);
  262. if (ptr)
  263. delete ((CDCSITEINFO*)ptr);
  264. }
  265. m_map.RemoveAll();
  266. m_CriticalSection.Unlock(); // Unlock buffer
  267. }
  268. //+---------------------------------------------------------------------------
  269. //
  270. // Function: CDCBufferManager::ThreadReport
  271. //
  272. // Synopsis: Report THREAD_DONE to the owner dialog.
  273. //
  274. //----------------------------------------------------------------------------
  275. void
  276. CDCBufferManager::ThreadReport(
  277. IN PVOID ptr,
  278. IN HRESULT hr
  279. )
  280. {
  281. ASSERT(ptr);
  282. TRACE(_T("CDCBufferManager::ThreadReport ptr=%x, hr=%x\n"), ptr, hr);
  283. PostMessage(m_hDlg, WM_USER_GETDC_THREAD_DONE,
  284. reinterpret_cast<WPARAM>(ptr), hr);
  285. }
  286. /////////////////////////////////////////////////////////
  287. //
  288. // thread info structure
  289. typedef struct _GetDCThreadInfo
  290. {
  291. PTSTR pszDomainDnsName;
  292. CDCBufferManager *pDCBufferManager;
  293. } GETDCTHREADINFO;
  294. //+---------------------------------------------------------------------------
  295. //
  296. // Function: CDCBufferManager::StartThread
  297. //
  298. // Synopsis: Start a thread.
  299. //
  300. // Pass the following info to the thread function:
  301. //
  302. // pszDomainDnsName:
  303. // domain we need to get a list of DCs for.
  304. // pDCBufferManager:
  305. // the CDCBufferManager instance for the ThreadFunc to
  306. // add result to the buffer
  307. //
  308. //----------------------------------------------------------------------------
  309. HRESULT
  310. CDCBufferManager::StartThread(
  311. IN PCTSTR pszDomainDnsName
  312. )
  313. {
  314. ASSERT(pszDomainDnsName);
  315. ASSERT(*pszDomainDnsName);
  316. TRACE(_T("CDCBufferManager::StartThread for %s\n"), pszDomainDnsName);
  317. GETDCTHREADINFO *pThreadInfo = new GETDCTHREADINFO;
  318. if (!pThreadInfo)
  319. return E_OUTOFMEMORY;
  320. pThreadInfo->pszDomainDnsName = _tcsdup(pszDomainDnsName);
  321. if ( !(pThreadInfo->pszDomainDnsName) )
  322. {
  323. delete pThreadInfo;
  324. return E_OUTOFMEMORY;
  325. }
  326. pThreadInfo->pDCBufferManager = this;
  327. AddRef();
  328. unsigned threadID;
  329. HANDLE pThread = (HANDLE)_beginthreadex(
  330. NULL, //void *security,
  331. 0, //unsigned stack_size,
  332. &GetDCThreadFunc, //unsigned ( __stdcall *start_address )( void * ),
  333. (void *)pThreadInfo, //void *arglist,
  334. 0, //unsigned initflag,
  335. &threadID //unsigned *thrdaddr
  336. );
  337. if (!pThread)
  338. {
  339. free(pThreadInfo->pszDomainDnsName);
  340. delete pThreadInfo;
  341. Release();
  342. return E_FAIL;
  343. }
  344. return S_OK;
  345. }
  346. //+---------------------------------------------------------------------------
  347. //
  348. // Function: GetDCThreadFunc
  349. //
  350. // Synopsis: The GetDC Thread Function.
  351. // This function invokes DsGetDomainControllerInfo() to get a list
  352. // of DCs in the specified domain, and add them to the buffer of
  353. // CDCBufferManager instance.
  354. // This function regularly checks to see if the owner dialog signals
  355. // it to exit, if not, it will finish its normal operation and
  356. // post a THREAD_DONE message to the owner dialog.
  357. //
  358. //----------------------------------------------------------------------------
  359. unsigned __stdcall GetDCThreadFunc( void* lParam )
  360. {
  361. GETDCTHREADINFO *pThreadInfo = reinterpret_cast<GETDCTHREADINFO *>(lParam);
  362. ASSERT(pThreadInfo);
  363. ASSERT(pThreadInfo->pszDomainDnsName);
  364. ASSERT(*(pThreadInfo->pszDomainDnsName));
  365. ASSERT(pThreadInfo->pDCBufferManager);
  366. TRACE(_T("GetDCThreadFunc pszDomainDnsName=%s, pDCBufferManager=%x\n"),
  367. pThreadInfo->pszDomainDnsName, pThreadInfo->pDCBufferManager);
  368. //
  369. // retrieve information passed into this function
  370. //
  371. CString csDomain = pThreadInfo->pszDomainDnsName;
  372. CDCBufferManager *pDCBufferManager = pThreadInfo->pDCBufferManager;
  373. free(pThreadInfo->pszDomainDnsName);
  374. delete pThreadInfo;
  375. PVOID pEntry = NULL;
  376. DWORD cInfo = 0;
  377. PDS_DOMAIN_CONTROLLER_INFO_1 pInfo = NULL;
  378. DWORD dwErr = 0;
  379. HRESULT hr = S_OK;
  380. Smart_DsHandle shDs; // smart pointer, will Unbind automatically
  381. if (pDCBufferManager->ShouldExit())
  382. goto Thread_Exit;
  383. dwErr = DsBind(NULL, const_cast<LPTSTR>(static_cast<LPCTSTR>(csDomain)), &shDs);
  384. if (pDCBufferManager->ShouldExit())
  385. goto Thread_Exit;
  386. if (ERROR_SUCCESS != dwErr) {
  387. // DsBind() failed.
  388. // Add an error entry in the buffer.
  389. hr = HRESULT_FROM_WIN32(dwErr);
  390. pDCBufferManager->AddInfo(csDomain, 0, NULL, hr, &pEntry);
  391. goto Thread_Exit;
  392. }
  393. dwErr = DsGetDomainControllerInfo(
  394. shDs, // HANDLE hDs
  395. const_cast<LPTSTR>(static_cast<LPCTSTR>(csDomain)), // LPTSTR DomainName
  396. DSGETDCINFO_LEVEL_1, // DWORD InfoLevel
  397. &cInfo, // DWORD *pcOut
  398. reinterpret_cast<VOID **>(&pInfo) // VOID **ppInfo
  399. );
  400. if (pDCBufferManager->ShouldExit())
  401. {
  402. if ((ERROR_SUCCESS == dwErr) && pInfo)
  403. DsFreeDomainControllerInfo(DSGETDCINFO_LEVEL_1, cInfo, pInfo);
  404. goto Thread_Exit;
  405. }
  406. if (ERROR_SUCCESS != dwErr) {
  407. // DsGetDomainControllerInfo() failed.
  408. // Add an error entry in the buffer
  409. hr = HRESULT_FROM_WIN32(dwErr);
  410. pDCBufferManager->AddInfo(csDomain, 0, NULL, hr, &pEntry);
  411. goto Thread_Exit;
  412. }
  413. //
  414. // Add result to the buffer in CDCBufferManager
  415. //
  416. hr = pDCBufferManager->AddInfo(csDomain, cInfo, pInfo, S_OK, &pEntry);
  417. if (FAILED(hr))
  418. DsFreeDomainControllerInfo(DSGETDCINFO_LEVEL_1, cInfo, pInfo);
  419. Thread_Exit:
  420. if (FALSE == pDCBufferManager->ShouldExit())
  421. {
  422. //
  423. // report THREAD_DONE with the pointer to the entry
  424. //
  425. if (pEntry)
  426. pDCBufferManager->ThreadReport(pEntry, hr);
  427. }
  428. //
  429. // Decrement the reference count on the CDCBufferManager instance
  430. //
  431. pDCBufferManager->Release();
  432. return 0;
  433. }
  434. ///////////////////////////////////////////////
  435. // class CDCSITEINFO
  436. CDCSITEINFO::CDCSITEINFO()
  437. {
  438. m_csDomainName.Empty();
  439. m_cInfo = 0;
  440. m_pDCInfo = NULL;
  441. m_hr = S_OK;
  442. }
  443. CDCSITEINFO::~CDCSITEINFO()
  444. {
  445. if (m_pDCInfo)
  446. DsFreeDomainControllerInfo(DSGETDCINFO_LEVEL_1, m_cInfo, m_pDCInfo);
  447. }
  448. void
  449. CDCSITEINFO::SetEntry(LPCTSTR pszDomainName, DWORD cInfo, PVOID pDCInfo, HRESULT hr)
  450. {
  451. m_csDomainName = pszDomainName;
  452. m_cInfo = cInfo;
  453. m_pDCInfo = (PDS_DOMAIN_CONTROLLER_INFO_1)pDCInfo;
  454. m_hr = hr;
  455. }
  456. enum BUFFER_ENTRY_TYPE
  457. CDCSITEINFO::GetEntryType()
  458. {
  459. if (FAILED(m_hr))
  460. return BUFFER_ENTRY_TYPE_ERROR;
  461. if (m_cInfo == 0 || m_pDCInfo == NULL)
  462. return BUFFER_ENTRY_TYPE_INPROGRESS;
  463. return BUFFER_ENTRY_TYPE_VALID;
  464. }
  465. void
  466. CDCSITEINFO::ReSet()
  467. {
  468. ASSERT(GetEntryType() == BUFFER_ENTRY_TYPE_ERROR);
  469. m_hr = S_OK;
  470. ASSERT(GetEntryType() == BUFFER_ENTRY_TYPE_INPROGRESS);
  471. }