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.

3581 lines
102 KiB

  1. //***************************************************************************
  2. //
  3. // UPDATECFG.CPP
  4. //
  5. // Module:
  6. //
  7. // Purpose: Support for asynchronous NLB configuration updates
  8. // Contains the high-level code for executing and tracking the updates
  9. // The lower-level, NLB-specific work is implemented in
  10. // CFGUTILS.CPP
  11. //
  12. // Copyright (c)2001 Microsoft Corporation, All Rights Reserved
  13. //
  14. // History:
  15. //
  16. // 04/05/01 JosephJ Created
  17. //
  18. //***************************************************************************
  19. #include "private.h"
  20. #include "nlbmprov.h"
  21. #include "updatecfg.tmh"
  22. #define NLBUPD_REG_PENDING L"PendingOperation"
  23. #define NLBUPD_REG_COMPLETIONS L"Completions"
  24. #define NLBUPD_MAX_LOG_LENGTH 1024 // Max length in chars of a completion log entry
  25. //
  26. // For debugging only -- used to cause various locations to break into
  27. // the debugger.
  28. //
  29. BOOL g_DoBreaks;
  30. //
  31. // Static vars
  32. //
  33. CRITICAL_SECTION NlbConfigurationUpdate::s_Crit;
  34. LIST_ENTRY NlbConfigurationUpdate::s_listCurrentUpdates;
  35. BOOL NlbConfigurationUpdate::s_fStaticInitialized;
  36. BOOL NlbConfigurationUpdate::s_fInitialized;
  37. //
  38. // Local utility functions.
  39. //
  40. WBEMSTATUS
  41. update_cluster_config(
  42. PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg,
  43. PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfgNew
  44. );
  45. VOID
  46. CLocalLogger::Log(
  47. IN UINT ResourceID,
  48. // IN LPCWSTR FormatString,
  49. ...
  50. )
  51. {
  52. DWORD dwRet;
  53. WCHAR wszFormat[2048];
  54. WCHAR wszBuffer[2048];
  55. if (!LoadString(ghModule, ResourceID, wszFormat, ASIZE(wszFormat)-1))
  56. {
  57. TRACE_CRIT("LoadString returned 0, GetLastError() : 0x%x, Could not log message !!!", GetLastError());
  58. goto end;
  59. }
  60. va_list arglist;
  61. va_start (arglist, ResourceID);
  62. dwRet = FormatMessage(FORMAT_MESSAGE_FROM_STRING,
  63. wszFormat,
  64. 0, // Message Identifier - Ignored for FORMAT_MESSAGE_FROM_STRING
  65. 0, // Language Identifier
  66. wszBuffer,
  67. ASIZE(wszBuffer)-1,
  68. &arglist);
  69. va_end (arglist);
  70. if (dwRet==0)
  71. {
  72. TRACE_CRIT("FormatMessage returned error : %u, Could not log message !!!", dwRet);
  73. goto end;
  74. }
  75. UINT uLen = wcslen(wszBuffer)+1; // 1 for extra NULL
  76. if ((m_LogSize < (m_CurrentOffset+uLen)))
  77. {
  78. //
  79. // Not enough space -- we double the buffer + some extra
  80. // and copy over the old log.
  81. //
  82. UINT uNewSize = 2*m_LogSize+uLen+1024;
  83. WCHAR *pTmp = new WCHAR[uNewSize];
  84. if (pTmp == NULL)
  85. {
  86. goto end;
  87. }
  88. if (m_CurrentOffset!=0)
  89. {
  90. CopyMemory(pTmp, m_pszLog, m_CurrentOffset*sizeof(WCHAR));
  91. pTmp[m_CurrentOffset] = 0;
  92. }
  93. delete[] m_pszLog;
  94. m_pszLog = pTmp;
  95. m_LogSize = uNewSize;
  96. }
  97. //
  98. // Having made sure there is enough space, copy over the new stuff
  99. //
  100. CopyMemory(m_pszLog+m_CurrentOffset, wszBuffer, uLen*sizeof(WCHAR));
  101. m_CurrentOffset += (uLen-1); // -1 for ending NULL.
  102. end:
  103. return;
  104. }
  105. VOID
  106. NlbConfigurationUpdate::StaticInitialize(
  107. VOID
  108. )
  109. /*++
  110. --*/
  111. {
  112. ASSERT(!s_fStaticInitialized);
  113. TRACE_INFO("->%!FUNC!");
  114. InitializeCriticalSection(&s_Crit);
  115. InitializeListHead(&s_listCurrentUpdates);
  116. s_fStaticInitialized=TRUE;
  117. s_fInitialized=TRUE;
  118. TRACE_INFO("<-%!FUNC!");
  119. }
  120. VOID
  121. NlbConfigurationUpdate::StaticDeinitialize(
  122. VOID
  123. )
  124. /*++
  125. Must only be called after PrepareForDeinitialization is called.
  126. --*/
  127. {
  128. TRACE_INFO("->%!FUNC!");
  129. ASSERT(s_fStaticInitialized);
  130. sfn_Lock();
  131. if (s_fInitialized || !IsListEmpty(&s_listCurrentUpdates))
  132. {
  133. // Shouldn't get here (this means that
  134. // PrepareForDeinitialization is not called first).
  135. //
  136. ASSERT(!"s_fInitialized is true or update list is not empty");
  137. TRACE_CRIT("!FUNC!: FATAL -- this function called prematurely!");
  138. }
  139. s_fStaticInitialized = FALSE;
  140. s_fInitialized = FALSE;
  141. sfn_Unlock();
  142. DeleteCriticalSection(&s_Crit);
  143. TRACE_INFO("<-%!FUNC!");
  144. }
  145. VOID
  146. NlbConfigurationUpdate::PrepareForDeinitialization(
  147. VOID
  148. )
  149. //
  150. // Stop accepting new queries, wait for existing (pending) queries
  151. // to complete.
  152. //
  153. {
  154. TRACE_INFO("->%!FUNC!");
  155. //
  156. // Go through the list of updates, dereferencing any of them.
  157. //
  158. sfn_Lock();
  159. if (s_fInitialized)
  160. {
  161. TRACE_INFO("Deinitialize: Going to deref all update objects");
  162. s_fInitialized = FALSE;
  163. while (!IsListEmpty(&s_listCurrentUpdates))
  164. {
  165. LIST_ENTRY *pLink = RemoveHeadList(&s_listCurrentUpdates);
  166. HANDLE hThread = NULL;
  167. NlbConfigurationUpdate *pUpdate;
  168. pUpdate = CONTAINING_RECORD(
  169. pLink,
  170. NlbConfigurationUpdate,
  171. m_linkUpdates
  172. );
  173. hThread = pUpdate->m_hAsyncThread;
  174. if (hThread != NULL)
  175. {
  176. //
  177. // There is an async thread for this update object. We're going
  178. // to wait for it to exit. But we need to first get a duplicate
  179. // handle for ourself, because we're not going to be holding any
  180. // locks when we're doing the waiting, and we want to make sure
  181. // that the handle doesn't go away.
  182. //
  183. BOOL fRet;
  184. fRet = DuplicateHandle(
  185. GetCurrentProcess(),
  186. hThread,
  187. GetCurrentProcess(),
  188. &hThread, // overwritten with the duplicate handle
  189. 0,
  190. FALSE,
  191. DUPLICATE_SAME_ACCESS
  192. );
  193. if (!fRet)
  194. {
  195. TRACE_CRIT("Deinitialize: ERROR: couldn't duplicate handle");
  196. hThread=NULL;
  197. }
  198. }
  199. sfn_Unlock();
  200. //
  201. // Wait for the async thread (if any) for this process to exit
  202. //
  203. if (hThread != NULL)
  204. {
  205. TRACE_CRIT("Deinitialize: waiting for hThread 0x%p", hThread);
  206. WaitForSingleObject(hThread, INFINITE);
  207. TRACE_CRIT("Deinitialize: done waiting for hThread 0x%p", hThread);
  208. CloseHandle(hThread);
  209. }
  210. TRACE_INFO(
  211. L"Deinitialize: Dereferencing pUpdate(Guid=%ws)",
  212. pUpdate->m_szNicGuid);
  213. pUpdate->mfn_Dereference(); // Deref ref added when adding this
  214. // item to the global list.
  215. sfn_Lock();
  216. }
  217. }
  218. sfn_Unlock();
  219. TRACE_INFO("<-%!FUNC!");
  220. }
  221. BOOL
  222. NlbConfigurationUpdate::CanUnloadNow(
  223. VOID
  224. )
  225. {
  226. UINT uActiveCount = 0;
  227. TRACE_INFO("->%!FUNC!");
  228. //
  229. // Go through the list of updates, dereferencing any of them.
  230. //
  231. sfn_Lock();
  232. if (s_fInitialized)
  233. {
  234. //
  235. // Walk the list and check if any updates are ongoing -- these could
  236. // be synchronous or async updates.
  237. //
  238. LIST_ENTRY *pLink = s_listCurrentUpdates.Flink;
  239. while (pLink != & s_listCurrentUpdates)
  240. {
  241. NlbConfigurationUpdate *pUpdate;
  242. pUpdate = CONTAINING_RECORD(
  243. pLink,
  244. NlbConfigurationUpdate,
  245. m_linkUpdates
  246. );
  247. if (pUpdate->m_State == ACTIVE)
  248. {
  249. uActiveCount++;
  250. }
  251. pLink = pLink->Flink;
  252. }
  253. if (uActiveCount==0)
  254. {
  255. //
  256. // We don't have any updates pending: we can return TRUE.
  257. // But we first set the can-unload flag so that no new
  258. // updates can be created.
  259. //
  260. // Can't do this because we can still get called after returning
  261. // TRUE to CanUnloadNow :-(
  262. // s_fCanUnload = TRUE;
  263. }
  264. }
  265. sfn_Unlock();
  266. TRACE_INFO("<-%!FUNC!. uActiveCount=0x%lx", uActiveCount);
  267. return (uActiveCount==0);
  268. }
  269. WBEMSTATUS
  270. NlbConfigurationUpdate::GetConfiguration(
  271. IN LPCWSTR szNicGuid,
  272. OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCurrentCfg // must be zero'd out
  273. )
  274. //
  275. //
  276. //
  277. {
  278. // 2/13/02 JosephJ SECURITY BUGBUG:
  279. // Make sure that this function fails if user is not an admin.
  280. WBEMSTATUS Status = WBEM_NO_ERROR;
  281. NlbConfigurationUpdate *pUpdate = NULL;
  282. BOOL fNicNotFound = FALSE;
  283. TRACE_INFO(L"->%!FUNC!(Nic=%ws)", szNicGuid);
  284. //
  285. // Look for an update object for the specified NIC, creating one if
  286. // required.
  287. //
  288. Status = sfn_LookupUpdate(szNicGuid, TRUE, &pUpdate); // TRUE == Create
  289. if (FAILED(Status))
  290. {
  291. TRACE_CRIT(
  292. L"DoUpdate: Error looking up update object for NIC %ws",
  293. szNicGuid
  294. );
  295. pUpdate = NULL;
  296. if (Status == WBEM_E_NOT_FOUND)
  297. {
  298. fNicNotFound = TRUE;
  299. }
  300. goto end;
  301. }
  302. Status = pUpdate->mfn_GetCurrentClusterConfiguration(pCurrentCfg);
  303. end:
  304. if (pUpdate != NULL)
  305. {
  306. //
  307. // Dereference the temporary reference added by sfn_LookupUpdate on
  308. // our behalf.
  309. //
  310. pUpdate->mfn_Dereference();
  311. }
  312. //
  313. // We want to return WBEM_E_NOT_FOUND ONLY if we couldn't find
  314. // the specific NIC -- this is used by the provider to return
  315. // a very specific value to the client.
  316. //
  317. if (Status == WBEM_E_NOT_FOUND && !fNicNotFound)
  318. {
  319. Status = WBEM_E_FAILED;
  320. }
  321. TRACE_INFO(L"<-%!FUNC!(Nic=%ws) returns 0x%08lx", szNicGuid, (UINT) Status);
  322. return Status;
  323. }
  324. WBEMSTATUS
  325. NlbConfigurationUpdate::DoUpdate(
  326. IN LPCWSTR szNicGuid,
  327. IN LPCWSTR szClientDescription,
  328. IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pNewCfg,
  329. OUT UINT *pGeneration,
  330. OUT WCHAR **ppLog // free using delete operator.
  331. )
  332. //
  333. //
  334. //
  335. // Called to initiate update to a new cluster state on that NIC. This
  336. // could include moving from a NLB-bound state to the NLB-unbound state.
  337. // *pGeneration is used to reference this particular update request.
  338. //
  339. /*++
  340. Return Value:
  341. WBEM_S_PENDING Pending operation.
  342. --*/
  343. {
  344. WBEMSTATUS Status = WBEM_S_PENDING;
  345. NlbConfigurationUpdate *pUpdate = NULL;
  346. BOOL fImpersonating = TRUE; // we assume we're impersonating,
  347. // but in the case of "tprov -", wmi is not involved,
  348. // and we're not impersonating.
  349. TRACE_INFO(L"->%!FUNC!(Nic=%ws)", szNicGuid);
  350. *ppLog = NULL;
  351. //
  352. // Look for an update object for the specified NIC, creating one if
  353. // required.
  354. //
  355. Status = sfn_LookupUpdate(szNicGuid, TRUE, &pUpdate); // TRUE == Create
  356. if (FAILED(Status))
  357. {
  358. TRACE_CRIT(
  359. L"DoUpdate: Error creating new update object for NIC %ws",
  360. szNicGuid
  361. );
  362. pUpdate = NULL;
  363. goto end;
  364. }
  365. TRACE_INFO(
  366. L"DoUpdate: Created/found update object 0x%p update object for NIC %ws",
  367. pUpdate,
  368. szNicGuid
  369. );
  370. BOOL fDoAsync = FALSE;
  371. //
  372. // Get exclusive permission to perform an update on this NIC.
  373. // If mfn_StartUpdate succeeds we MUST make sure that mfn_StopUpdate() is
  374. // called, either here or asynchronously (or else we'll block all subsequent
  375. // updates to this NIC until this process/dll is unloaded!).
  376. // BUGBUG -- get rid of MyBreak
  377. MyBreak(L"Break before calling StartUpdate.\n");
  378. Status = pUpdate->mfn_StartUpdate(pNewCfg, szClientDescription, &fDoAsync, ppLog);
  379. if (FAILED(Status))
  380. {
  381. goto end;
  382. }
  383. if (Status == WBEM_S_FALSE)
  384. {
  385. //
  386. // The update is a No-Op. We return the current generation ID
  387. // and switch the status to WBEM_NO_ERROR.
  388. //
  389. // WARNING/TODO: we return the value in m_OldClusterConfig.Generation,
  390. // because we know that this gets filled in when analyzing the update.
  391. // However there is a small possibility that a complete update
  392. // happened in *another* thead in between when we called mfn_StartUpdate
  393. // and now, in which case we'll be reporting the generation ID of
  394. // the later update.
  395. //
  396. sfn_Lock();
  397. if (!pUpdate->m_OldClusterConfig.fValidNlbCfg)
  398. {
  399. //
  400. // We could get here if some activity happened in another
  401. // thread which resulted in the old cluster state now being
  402. // invalid. It's a highly unlikely possibility.
  403. //
  404. ASSERT(!"Old cluster state invalid");
  405. TRACE_CRIT("old cluster state is invalid %ws", szNicGuid);
  406. Status = WBEM_E_CRITICAL_ERROR;
  407. }
  408. else
  409. {
  410. *pGeneration = pUpdate->m_OldClusterConfig.Generation;
  411. Status = WBEM_NO_ERROR;
  412. }
  413. sfn_Unlock();
  414. goto end;
  415. }
  416. TRACE_INFO(
  417. L"DoUpdate: We're cleared to update for NIC %ws",
  418. szNicGuid
  419. );
  420. //
  421. // Once we've started the update, m_Generation is the generation number
  422. // assigned to this update.
  423. //
  424. *pGeneration = pUpdate->m_Generation;
  425. //
  426. // For testing purposes, force fDoAsync==FALSE;
  427. //
  428. // fDoAsync = FALSE;
  429. if (fDoAsync)
  430. {
  431. TRACE_INFO(
  432. L"DoUpdate: Initialting ASYNC update for NIC %ws",
  433. szNicGuid
  434. );
  435. HANDLE TokenHandle = NULL;
  436. HANDLE hThread = NULL;
  437. HRESULT hRes;
  438. Status = WBEM_NO_ERROR;
  439. do
  440. {
  441. //
  442. // NOTE ABOUT NLB_DUPLICATE_TOKEN:
  443. // Using duplicate access token caused the following problem. In the new
  444. // thread, control flows to EnablePnPPrivileges() (in base\pnp\cfgmgr32\util.c)
  445. // which calls OpenThreadToken() asking for TOKEN_ADJUST_PRIVILEGES access.
  446. // The call fails with "access denied". So, it looks like the duplicate access
  447. // token has a more restrictive ACL than the original access token.
  448. // Email exchanges with Jim Cavalaris & Rob Earhart resulted in the following
  449. // suggestions:
  450. // 1. Call OpenThreadToken() with "OpenAsSelf" set to TRUE
  451. // 2. Revert to Self before duplicating token
  452. // #1 by itself did not solve the problem. #1 & #2 in combination solved this problem.
  453. // However, it casued a different problem: Net config could not acquire the write
  454. // spin lock. This may be because the duplicated token has lower privileges since
  455. // it was created in the context of the process and NOT the client.
  456. // If ever we find a way around this, we should use the duplicated access token.
  457. // Using duplicate access token ensures that privileges manipulated in one (say, child)
  458. // thread will NOT affect the other (say, the parent) thread's token.
  459. // -- KarthicN, 4/15/02
  460. //
  461. // In order for the new thread (that is about to be created) to impersonate
  462. // the client, the impersonation access token of the curren thread must
  463. // be attached to the new thread.
  464. // The first step in this process is to call OpenThreadToken() to
  465. // open the impersonation access token of the current thread
  466. // with TOKEN_IMPERSONATE access. We need TOKEN_IMPERSONATE access so that
  467. // we may later attach this token to the new thread.
  468. // If we go back to using the duplicate access token. acquire TOKEN_DUPLICATE access
  469. // here so that we may duplicate the access token and attach the duplicate to the new thread.
  470. //
  471. // By the way, to maximize the chances of success, we use the
  472. // (potentially higher) credentials of the client being impersonated
  473. // to open the impersonation token.
  474. //
  475. extern BOOL g_Impersonate;
  476. if(!g_Impersonate)
  477. {
  478. fImpersonating = FALSE;
  479. }
  480. else if (OpenThreadToken(GetCurrentThread(),
  481. #ifdef NLB_DUPLICATE_TOKEN // NOT defined
  482. TOKEN_DUPLICATE,
  483. #else
  484. TOKEN_IMPERSONATE,
  485. #endif
  486. FALSE, // Use the credentials of the client (being impersonated) to obtain TOKEN_IMPERSONATE access
  487. &TokenHandle))
  488. {
  489. fImpersonating = TRUE;
  490. }
  491. else
  492. {
  493. TRACE_CRIT(L"%!FUNC! OpenThreadToken fails due to 0x%x",GetLastError());
  494. Status = WBEM_E_FAILED;
  495. TokenHandle = NULL;
  496. break;
  497. }
  498. #ifdef NLB_DUPLICATE_TOKEN // NOT defined
  499. HANDLE DuplicateTokenHandle = NULL;
  500. //
  501. // Before attaching the impersonation access token to the new thread, duplicate
  502. // it. Later, assign the duplicate access token to the new thread so that any modifications
  503. // (of privileges) made to the access token will only affect the new thread.
  504. // Moreover, the current thread exits immediately after resuming the new thread.
  505. // If the current thread were to share (instead of giving a duplicate) access
  506. // token with the new thread, we are not sure of the ramifications of the current
  507. // thread exiting before the new thread.
  508. //
  509. if (fImpersonating && !DuplicateToken(TokenHandle,
  510. SecurityImpersonation,
  511. &DuplicateTokenHandle)) // The returned handle has TOKEN_IMPERSONATE & TOKEN_QUERY access
  512. {
  513. TRACE_CRIT(L"%!FUNC! DuplicateToken fails due to 0x%x",GetLastError());
  514. Status = WBEM_E_FAILED;
  515. break;
  516. }
  517. // Close the handle to the original access token returned by OpenThreadToken()
  518. if (TokenHandle != NULL)
  519. {
  520. CloseHandle(TokenHandle);
  521. TokenHandle = DuplicateTokenHandle;
  522. }
  523. #endif
  524. //
  525. // We must do this asynchronously -- start a thread that'll complete
  526. // the configuration update, and return PENDING.
  527. //
  528. DWORD ThreadId;
  529. //
  530. // The current thread is impersonating the client. If the new thread is created in this
  531. // (impersonating) context, it will only have a subset (THREAD_SET_INFORMATION,
  532. // THREAD_QUERY_INFORMATION and THREAD_TERMINATE) of the usual (THREAD_ALL_ACCESS) access rights.
  533. // Pervasive operations (like binding NLB) performed by the new thread causes control to flow
  534. // into Threadpool. Threadpool needs to be able to create executive level objects
  535. // which will be used for other activities in the process, It doesn't want to be creating them
  536. // using the impersonation token, so it attempts to revert back to the process token. It fails
  537. // because the thread doesn't have THREAD_IMPERSONATE access to itself. (Explanation courtesy: Rob Earhart)
  538. // To overcome this problem, we have to revert to self when creating the thread so that it
  539. // will be created with THREAD_ALL_ACCESS access rights (which includes THREAD_IMPERSONATE).
  540. //
  541. if (fImpersonating)
  542. {
  543. hRes = CoRevertToSelf();
  544. if (FAILED(hRes))
  545. {
  546. TRACE_CRIT(L"%!FUNC! CoRevertToSelf() fails due to Error : 0x%x",HRESULT_CODE(hRes));
  547. Status = WBEM_E_FAILED;
  548. break;
  549. }
  550. }
  551. hThread = CreateThread(
  552. NULL, // lpThreadAttributes,
  553. 0, // dwStackSize,
  554. s_AsyncUpdateThreadProc, // lpStartAddress,
  555. pUpdate, // lpParameter,
  556. CREATE_SUSPENDED, // dwCreationFlags,
  557. &ThreadId // lpThreadId
  558. );
  559. // Go back to impersonating the client. The current thread does not really do much
  560. // after this point, so, really, impersonating may not be necessary. However, for
  561. // consistency sake, do it.
  562. if (fImpersonating)
  563. {
  564. hRes = CoImpersonateClient();
  565. if (FAILED(hRes))
  566. {
  567. TRACE_CRIT(L"%!FUNC! CoImpersonateClient() fails due to Error : 0x%x. Ignoring the failure and moving on...",HRESULT_CODE(hRes));
  568. }
  569. }
  570. if (hThread == NULL)
  571. {
  572. TRACE_INFO(
  573. L"DoUpdate: ERROR Creating Thread. Aborting update request for Nic %ws",
  574. szNicGuid
  575. );
  576. Status = WBEM_E_FAILED; // TODO -- find better error
  577. break;
  578. }
  579. //
  580. // Attach the impersonation access token to the new thread so that it may impersonate the client
  581. //
  582. if (fImpersonating && !SetThreadToken(&hThread, TokenHandle))
  583. {
  584. TRACE_CRIT(L"%!FUNC! SetThreadToken fails due to 0x%x",GetLastError());
  585. Status = WBEM_E_FAILED;
  586. break;
  587. }
  588. //
  589. // Since we've claimed the right to perform a config update on this
  590. // NIC we'd better not find an other update going on!
  591. // Save away the thread handle and id.
  592. //
  593. sfn_Lock();
  594. ASSERT(m_hAsyncThread == NULL);
  595. pUpdate->mfn_Reference(); // Add reference for async thread.
  596. pUpdate->m_hAsyncThread = hThread;
  597. pUpdate->m_AsyncThreadId = ThreadId;
  598. sfn_Unlock();
  599. //
  600. // The rest of the update will carry on in the context of the async
  601. // thread. That thread will make sure that pUpdate->mfn_StopUpdate()
  602. // is called so we shouldn't do it here.
  603. //
  604. DWORD dwRet = ResumeThread(hThread);
  605. if (dwRet == 0xFFFFFFFF) // this is what it says in the SDK
  606. {
  607. //
  608. // Aargh ... failure
  609. // Undo reference to this thread in pUpdate
  610. //
  611. TRACE_INFO("ERROR resuming thread for NIC %ws", szNicGuid);
  612. sfn_Lock();
  613. ASSERT(pUpdate->m_hAsyncThread == hThread);
  614. pUpdate->m_hAsyncThread = NULL;
  615. pUpdate->m_AsyncThreadId = 0;
  616. pUpdate->mfn_Dereference(); // Remove ref added above.
  617. sfn_Unlock();
  618. Status = WBEM_E_FAILED; // TODO -- find better error
  619. break;
  620. }
  621. Status = WBEM_S_PENDING;
  622. hThread = NULL; // Setting to NULL so that we don't call CloseHandle on it
  623. (VOID) pUpdate->mfn_ReleaseFirstMutex(FALSE); // FALSE == wait, don't cancel.
  624. }
  625. while(FALSE);
  626. // Close the handle to impersonation access token and thread
  627. if (hThread != NULL)
  628. CloseHandle(hThread);
  629. if (TokenHandle != NULL)
  630. CloseHandle(TokenHandle);
  631. // BUGBUG -- test the failure code path...
  632. //
  633. if (FAILED(Status)) // this doesn't include pending
  634. {
  635. //
  636. // We're supposed to do an async update, but can't.
  637. // Treat this as a failed sync update.
  638. //
  639. //
  640. // We must acquire the 2nd mutex and release the first.
  641. // This is the stage that mfn_StopUpdate expects things to be.
  642. //
  643. // BUGBUG deal with AcquireSecondMutex etc failing here...
  644. (VOID)pUpdate->mfn_AcquireSecondMutex();
  645. (VOID)pUpdate->mfn_ReleaseFirstMutex(FALSE); // FALSE == wait, don't cancel
  646. //
  647. // Signal the stop of the update process.
  648. // This also releases exclusive permission to do updates.
  649. //
  650. pUpdate->m_CompletionStatus = Status; // Stop update needs this to be set.
  651. pUpdate->mfn_StopUpdate(ppLog);
  652. }
  653. else
  654. {
  655. ASSERT(Status == WBEM_S_PENDING);
  656. }
  657. }
  658. else
  659. {
  660. //
  661. // We can do this synchronously -- call mfn_Update here itself
  662. // and return the result.
  663. //
  664. //
  665. // We must acquire the 2nd mutex and release the first before we
  666. // do the update.
  667. //
  668. //
  669. Status = pUpdate->mfn_AcquireSecondMutex();
  670. (VOID)pUpdate->mfn_ReleaseFirstMutex(FALSE); // FALSE == wait, don't cancel.
  671. if (FAILED(Status))
  672. {
  673. pUpdate->m_CompletionStatus = Status;
  674. }
  675. else
  676. {
  677. try
  678. {
  679. pUpdate->mfn_ReallyDoUpdate();
  680. }
  681. catch (...)
  682. {
  683. TRACE_CRIT(L"!FUNC! Caught exception!\n");
  684. ASSERT(!"Caught exception!");
  685. pUpdate->mfn_StopUpdate(ppLog);
  686. pUpdate->mfn_Dereference();
  687. throw;
  688. }
  689. //
  690. // Let's extract the result
  691. //
  692. sfn_Lock();
  693. Status = pUpdate->m_CompletionStatus;
  694. sfn_Unlock();
  695. }
  696. ASSERT(Status != WBEM_S_PENDING);
  697. //
  698. // Signal the stop of the update process. This also releases exclusive
  699. // permission to do updates. So potentially other updates can start
  700. // happening concurrently before mfn_StopUpdate returns.
  701. //
  702. pUpdate->mfn_StopUpdate(ppLog);
  703. }
  704. end:
  705. if (pUpdate != NULL)
  706. {
  707. //
  708. // Dereference the temporary reference added by sfn_LookupUpdate on
  709. // our behalf.
  710. //
  711. pUpdate->mfn_Dereference();
  712. }
  713. TRACE_INFO(L"<-%!FUNC!(Nic=%ws) returns 0x%08lx", szNicGuid, (UINT) Status);
  714. return Status;
  715. }
  716. //
  717. // Constructor and distructor -- note that these are private
  718. //
  719. NlbConfigurationUpdate::NlbConfigurationUpdate(VOID)
  720. //
  721. //
  722. //
  723. {
  724. //
  725. // This assumes that we don't have a parent class. We should never
  726. // have a parent class.
  727. // BUGBUG -- remove, replace by clearing out individual members
  728. // in the constructor.
  729. //
  730. ZeroMemory(this, sizeof(*this));
  731. m_State = UNINITIALIZED;
  732. //
  733. // Note: the refcount is zero on return from the constructor.
  734. // The caller is expected to bump it up when it adds this entry to
  735. // to the list.
  736. //
  737. }
  738. NlbConfigurationUpdate::~NlbConfigurationUpdate()
  739. //
  740. // Status: done
  741. //
  742. {
  743. ASSERT(m_RefCount == 0);
  744. ASSERT(m_State!=ACTIVE);
  745. ASSERT(m_hAsyncThreadId == 0);
  746. //
  747. // TODO: Delete ip-address-info structures if any
  748. //
  749. }
  750. VOID
  751. NlbConfigurationUpdate::mfn_Reference(
  752. VOID
  753. )
  754. {
  755. InterlockedIncrement(&m_RefCount);
  756. }
  757. VOID
  758. NlbConfigurationUpdate::mfn_Dereference(
  759. VOID
  760. )
  761. {
  762. LONG l = InterlockedDecrement(&m_RefCount);
  763. ASSERT(l >= 0);
  764. if (l == 0)
  765. {
  766. TRACE_CRIT("Deleting update instance 0x%p", (PVOID) this);
  767. delete this;
  768. }
  769. }
  770. VOID
  771. NlbConfigurationUpdate::sfn_ReadLog(
  772. IN HKEY hKeyLog,
  773. IN UINT Generation,
  774. OUT LPWSTR *ppLog
  775. )
  776. {
  777. WCHAR szValueName[128];
  778. WCHAR *pLog = NULL;
  779. LONG lRet;
  780. DWORD dwType;
  781. DWORD cbData;
  782. *ppLog = NULL;
  783. StringCbPrintf(szValueName, sizeof(szValueName), L"%d.log", Generation);
  784. cbData = 0;
  785. lRet = RegQueryValueEx(
  786. hKeyLog, // handle to key to query
  787. szValueName, // address of name of value to query
  788. NULL, // reserved
  789. &dwType, // address of buffer for value type
  790. NULL, // address of data buffer
  791. &cbData // address of data buffer size
  792. );
  793. if ( (lRet == ERROR_SUCCESS)
  794. && (cbData > sizeof(WCHAR))
  795. && (dwType == REG_SZ))
  796. {
  797. // BUGBUG -- put some limit on the accepted size of cbData -- say
  798. // 4K.
  799. // We've got a non-null log entry...
  800. // Let's try to read it..
  801. // cbData should be a multiple of sizeof(WCHAR) but just in
  802. // case let's allocate a little more...
  803. pLog = new WCHAR[(cbData+1)/sizeof(WCHAR)];
  804. if (pLog == NULL)
  805. {
  806. TRACE_CRIT("Error allocating space for log");
  807. }
  808. else
  809. {
  810. lRet = RegQueryValueEx(
  811. hKeyLog, // handle to key to query
  812. szValueName, // address of name of value to query
  813. NULL, // reserved
  814. &dwType, // address of buffer for value type
  815. (LPBYTE)pLog, // address of data buffer
  816. &cbData // address of data buffer size
  817. );
  818. if ( (lRet != ERROR_SUCCESS)
  819. || (cbData <= sizeof(WCHAR))
  820. || (dwType != REG_SZ))
  821. {
  822. // Oops -- an error this time around!
  823. TRACE_CRIT("Error reading log entry for gen %d", Generation);
  824. delete[] pLog;
  825. pLog = NULL;
  826. }
  827. }
  828. }
  829. else
  830. {
  831. TRACE_CRIT("Error reading log entry for Generation %lu", Generation);
  832. // ignore the rror
  833. //
  834. }
  835. *ppLog = pLog;
  836. }
  837. VOID
  838. NlbConfigurationUpdate::sfn_WriteLog(
  839. IN HKEY hKeyLog,
  840. IN UINT Generation,
  841. IN LPCWSTR pLog,
  842. IN BOOL fAppend
  843. )
  844. {
  845. //
  846. // TODO: If fAppend==TRUE, this function is a bit wasteful in its use
  847. // of the heap.
  848. //
  849. WCHAR szValueName[128];
  850. LONG lRet;
  851. LPWSTR pOldLog = NULL;
  852. LPWSTR pTmpLog = NULL;
  853. UINT Len = wcslen(pLog)+1; // +1 for ending NULL
  854. if (fAppend)
  855. {
  856. sfn_ReadLog(hKeyLog, Generation, &pOldLog);
  857. if (pOldLog != NULL && *pOldLog != NULL)
  858. {
  859. Len += wcslen(pOldLog);
  860. if (Len > NLBUPD_MAX_LOG_LENGTH)
  861. {
  862. TRACE_CRIT("sfn_WriteLog: log size exceeded");
  863. goto end;
  864. }
  865. pTmpLog = new WCHAR[Len];
  866. if (pTmpLog == NULL)
  867. {
  868. TRACE_CRIT("sfn_WriteLog: allocation failure!");
  869. goto end;
  870. }
  871. (void) StringCchCopy(pTmpLog, Len, pOldLog);
  872. (void) StringCchCat(pTmpLog, Len, pLog);
  873. pLog = pTmpLog;
  874. }
  875. }
  876. StringCbPrintf(szValueName, sizeof(szValueName), L"%d.log", Generation);
  877. lRet = RegSetValueEx(
  878. hKeyLog, // handle to key to set value for
  879. szValueName, // name of the value to set
  880. 0, // reserved
  881. REG_SZ, // flag for value type
  882. (BYTE*) pLog,// address of value data
  883. Len*sizeof(WCHAR) // size of value data
  884. );
  885. if (lRet != ERROR_SUCCESS)
  886. {
  887. TRACE_CRIT("Error writing log entry for generation %d", Generation);
  888. // We ignore this error.
  889. }
  890. end:
  891. if (pOldLog != NULL)
  892. {
  893. delete pOldLog;
  894. }
  895. if (pTmpLog != NULL)
  896. {
  897. delete[] pTmpLog;
  898. }
  899. return;
  900. }
  901. VOID
  902. NlbConfigurationUpdate::mfn_LogRawText(
  903. LPCWSTR szText
  904. )
  905. //
  906. // We read the current value of the log for this update, append szText
  907. // and write back the log.
  908. {
  909. TRACE_CRIT(L"LOG: %ws", szText);
  910. sfn_Lock();
  911. if (m_State!=ACTIVE)
  912. {
  913. //
  914. // Logging should only be performed when there is an active update
  915. // going on -- the log is specific to the currently active update.
  916. //
  917. TRACE_CRIT("WARNING: Attempt to log when not in ACTIVE state");
  918. goto end;
  919. }
  920. else
  921. {
  922. HKEY hKey = m_hCompletionKey;
  923. if (hKey != NULL)
  924. {
  925. sfn_WriteLog(hKey, m_Generation, szText, TRUE); // TRUE==append.
  926. }
  927. }
  928. end:
  929. sfn_Unlock();
  930. }
  931. //
  932. // Looks up the current update for the specific NIC.
  933. // We don't bother to reference count because this object never
  934. // goes away once created -- it's one per unique NIC GUID for as long as
  935. // the DLL is loaded (may want to revisit this).
  936. //
  937. WBEMSTATUS
  938. NlbConfigurationUpdate::sfn_LookupUpdate(
  939. IN LPCWSTR szNic,
  940. IN BOOL fCreate, // Create if required
  941. OUT NlbConfigurationUpdate ** ppUpdate
  942. )
  943. //
  944. //
  945. //
  946. {
  947. WBEMSTATUS Status;
  948. NlbConfigurationUpdate *pUpdate = NULL;
  949. *ppUpdate = NULL;
  950. //
  951. // With our global lock held, we'll look for an update structure
  952. // with the matching nic. If we find it, we'll return it, else
  953. // (if fCreate==TRUE) we'll create and initialize a structure and add
  954. // it to the list.
  955. //
  956. sfn_Lock();
  957. if (!s_fInitialized)
  958. {
  959. TRACE_CRIT(
  960. "LookupUpdate: We are Deinitializing, so we FAIL this request: %ws",
  961. szNic
  962. );
  963. Status = WBEM_E_NOT_AVAILABLE;
  964. goto end;
  965. }
  966. Status = CfgUtilsValidateNicGuid(szNic);
  967. if (FAILED(Status))
  968. {
  969. TRACE_CRIT(
  970. "LookupUpdate: Invalid GUID specified: %ws",
  971. szNic
  972. );
  973. goto end;
  974. }
  975. LIST_ENTRY *pLink = s_listCurrentUpdates.Flink;
  976. while (pLink != & s_listCurrentUpdates)
  977. {
  978. pUpdate = CONTAINING_RECORD(
  979. pLink,
  980. NlbConfigurationUpdate,
  981. m_linkUpdates
  982. );
  983. if (!_wcsicmp(pUpdate->m_szNicGuid, szNic))
  984. {
  985. // Found it!
  986. break;
  987. }
  988. pUpdate = NULL;
  989. pLink = pLink->Flink;
  990. }
  991. if (pUpdate==NULL && fCreate)
  992. {
  993. // Let's create one -- it does NOT add itself to the list, and
  994. // furthermore, its reference count is zero.
  995. //
  996. pUpdate = new NlbConfigurationUpdate();
  997. if (pUpdate==NULL)
  998. {
  999. Status = WBEM_E_OUT_OF_MEMORY;
  1000. goto end;
  1001. }
  1002. else
  1003. {
  1004. //
  1005. // Complete initialization here, and place it in the list.
  1006. //
  1007. // BUGBUG -- use string APIs for this one.
  1008. ARRAYSTRCPY(
  1009. pUpdate->m_szNicGuid,
  1010. szNic
  1011. );
  1012. InsertHeadList(&s_listCurrentUpdates, &pUpdate->m_linkUpdates);
  1013. pUpdate->mfn_Reference(); // Reference for being in the list
  1014. pUpdate->m_State = IDLE;
  1015. }
  1016. }
  1017. else if (pUpdate == NULL) // Couldn't find it, fCreate==FALSE
  1018. {
  1019. TRACE_CRIT(
  1020. "LookupUpdate: Could not find GUID specified: %ws",
  1021. szNic
  1022. );
  1023. Status = WBEM_E_NOT_FOUND;
  1024. goto end;
  1025. }
  1026. ASSERT(pUpdate!=NULL);
  1027. pUpdate->mfn_Reference(); // Reference for caller. Caller should deref.
  1028. *ppUpdate = pUpdate;
  1029. Status = WBEM_NO_ERROR;
  1030. end:
  1031. if (FAILED(Status))
  1032. {
  1033. ASSERT(pStatus!=NULL);
  1034. }
  1035. sfn_Unlock();
  1036. return Status;
  1037. }
  1038. DWORD
  1039. WINAPI
  1040. NlbConfigurationUpdate::s_AsyncUpdateThreadProc(
  1041. LPVOID lpParameter // thread data
  1042. )
  1043. /*++
  1044. --*/
  1045. {
  1046. //
  1047. // This thread is started only after we have exclusive right to perform
  1048. // an update on the specified NIC. This means that mfn_StartUpdate()
  1049. // has previously returned successfully. We need to call mfn_StopUpdate()
  1050. // to signal the end of the update when we're done.
  1051. //
  1052. WBEMSTATUS Status = WBEM_NO_ERROR;
  1053. NlbConfigurationUpdate *pUpdate = (NlbConfigurationUpdate *) lpParameter;
  1054. TRACE_INFO(L"->%!FUNC!(Nic=%ws)", pUpdate->m_szNicGuid);
  1055. ASSERT(pUpdate->m_AsyncThreadId == GetCurrentThreadId());
  1056. //
  1057. // We must acquire the 2nd mutex before we
  1058. // actually do the update. NOTE: the thread which called mfn_StartUpdate
  1059. // will call mfn_ReleaseFirstMutex.
  1060. //
  1061. Status = pUpdate->mfn_AcquireSecondMutex();
  1062. if (FAILED(Status))
  1063. {
  1064. pUpdate->m_CompletionStatus = Status;
  1065. // TODO -- check if we should be calling stop here ...
  1066. }
  1067. else
  1068. {
  1069. //
  1070. // Actually perform the update. mfn_ReallyDoUpate will save away the
  1071. // status appropriately.
  1072. //
  1073. try
  1074. {
  1075. pUpdate->mfn_ReallyDoUpdate();
  1076. }
  1077. catch (...)
  1078. {
  1079. TRACE_CRIT(L"%!FUNC! Caught exception!\n");
  1080. ASSERT(!"Caught exception!");
  1081. pUpdate->m_CompletionStatus = WBEM_E_CRITICAL_ERROR;
  1082. }
  1083. }
  1084. //
  1085. // We're done, let's remove the reference to our thread from pUpdate.
  1086. //
  1087. HANDLE hThread;
  1088. sfn_Lock();
  1089. hThread = pUpdate->m_hAsyncThread;
  1090. pUpdate->m_hAsyncThread = NULL;
  1091. pUpdate->m_AsyncThreadId = 0;
  1092. sfn_Unlock();
  1093. ASSERT(hThread!=NULL);
  1094. CloseHandle(hThread);
  1095. //
  1096. // Signal the stop of the update process. This also releases exclusive
  1097. // permission to do updates. So potentially other updates can start
  1098. // happening concurrently before mfn_StopUpdate returns.
  1099. //
  1100. {
  1101. //
  1102. // TODO: This is hokey. Use another technique to accomplish this
  1103. //
  1104. // Retrieve the log information from mfn_StopUpdate but dispose of it
  1105. // immediately afterward. The side effect (which we want) is that
  1106. // mfn_StopUpdate will include this log information into the event
  1107. // that it writes to the event log.
  1108. //
  1109. WCHAR *pLog = NULL;
  1110. pUpdate->mfn_StopUpdate(&pLog);
  1111. if (pLog != NULL)
  1112. {
  1113. delete pLog;
  1114. }
  1115. }
  1116. TRACE_INFO(L"<-%!FUNC!(Nic=%ws)", pUpdate->m_szNicGuid);
  1117. //
  1118. // Deref the ref to pUpdate added when this thread was started.
  1119. // pUpdate may not be valid after this.
  1120. //
  1121. pUpdate->mfn_Dereference();
  1122. return 0; // This return value is ignored.
  1123. }
  1124. //
  1125. // Create the specified subkey key (for r/w access) for the specified
  1126. // the specified NIC.
  1127. //
  1128. HKEY
  1129. NlbConfigurationUpdate::
  1130. sfn_RegCreateKey(
  1131. IN LPCWSTR szNicGuid,
  1132. IN LPCWSTR szSubKey, // Optional
  1133. IN BOOL fVolatile,
  1134. OUT BOOL *fExists
  1135. )
  1136. // Status
  1137. {
  1138. WCHAR szKey[256];
  1139. HKEY hKey = NULL;
  1140. HKEY hKeyHistory = NULL;
  1141. LONG lRet;
  1142. DWORD dwDisposition;
  1143. DWORD dwOptions = 0;
  1144. UINT u = wcslen(szNicGuid);
  1145. if (szSubKey != NULL)
  1146. {
  1147. u += wcslen(szSubKey) + 1; // 1 for the '\'.
  1148. }
  1149. if (u < sizeof(szKey)/sizeof(*szKey))
  1150. {
  1151. (void) StringCbCopy(szKey, sizeof(szKey), szNicGuid);
  1152. }
  1153. else
  1154. {
  1155. goto end;
  1156. }
  1157. if (szSubKey != NULL)
  1158. {
  1159. StringCbCat(szKey, sizeof(szKey), L"\\");
  1160. StringCbCat(szKey, sizeof(szKey), szSubKey);
  1161. }
  1162. lRet = RegCreateKeyEx(
  1163. HKEY_LOCAL_MACHINE, // handle to an open key
  1164. L"SYSTEM\\CurrentControlSet\\Services\\WLBS\\ConfigurationHistory",
  1165. 0, // reserved
  1166. L"class", // address of class string
  1167. 0, // special options flag
  1168. KEY_ALL_ACCESS, // desired security access
  1169. NULL, // address of key security structure
  1170. &hKeyHistory, // address of buffer for opened handle
  1171. &dwDisposition // address of disposition value buffer
  1172. );
  1173. if (lRet != ERROR_SUCCESS)
  1174. {
  1175. TRACE_CRIT("%!FUNC! error 0x%lx creating ConfigurationKey under WLBS",
  1176. lRet);
  1177. hKeyHistory = NULL;
  1178. goto end;
  1179. }
  1180. if (fVolatile)
  1181. {
  1182. dwOptions = REG_OPTION_VOLATILE;
  1183. }
  1184. lRet = RegCreateKeyEx(
  1185. hKeyHistory, // handle to an open key
  1186. szKey, // address of subkey name
  1187. 0, // reserved
  1188. L"class", // address of class string
  1189. dwOptions, // special options flag
  1190. KEY_ALL_ACCESS, // desired security access
  1191. NULL, // address of key security structure
  1192. &hKey, // address of buffer for opened handle
  1193. &dwDisposition // address of disposition value buffer
  1194. );
  1195. if (lRet == ERROR_SUCCESS)
  1196. {
  1197. if (dwDisposition == REG_CREATED_NEW_KEY)
  1198. {
  1199. *fExists = FALSE;
  1200. }
  1201. else
  1202. {
  1203. ASSERT(dwDisposition == REG_OPENED_EXISTING_KEY);
  1204. *fExists = TRUE;
  1205. }
  1206. }
  1207. else
  1208. {
  1209. TRACE_CRIT("Error creating key %ws. WinError=0x%08lx", szKey, GetLastError());
  1210. hKey = NULL;
  1211. }
  1212. end:
  1213. if (hKeyHistory != NULL)
  1214. {
  1215. RegCloseKey(hKeyHistory);
  1216. }
  1217. return hKey;
  1218. }
  1219. //
  1220. // Open the specified subkey key (for r/w access) for the specified
  1221. // the specified NIC.
  1222. //
  1223. HKEY
  1224. NlbConfigurationUpdate::
  1225. sfn_RegOpenKey(
  1226. IN LPCWSTR szNicGuid,
  1227. IN LPCWSTR szSubKey
  1228. )
  1229. {
  1230. WCHAR szKey[1024];
  1231. HKEY hKey = NULL;
  1232. StringCbCopy(szKey, sizeof(szKey),
  1233. L"SYSTEM\\CurrentControlSet\\Services\\WLBS\\ConfigurationHistory\\");
  1234. UINT u = wcslen(szKey) + wcslen(szNicGuid);
  1235. if (szSubKey != NULL)
  1236. {
  1237. u += wcslen(szSubKey) + 1; // 1 for the '\'.
  1238. }
  1239. if (u < sizeof(szKey)/sizeof(*szKey))
  1240. {
  1241. StringCbCat(szKey, sizeof(szKey), szNicGuid);
  1242. }
  1243. else
  1244. {
  1245. goto end;
  1246. }
  1247. if (szSubKey != NULL)
  1248. {
  1249. StringCbCat(szKey, sizeof(szKey), L"\\");
  1250. StringCbCat(szKey, sizeof(szKey), szSubKey);
  1251. }
  1252. DWORD dwDisposition;
  1253. LONG lRet;
  1254. lRet = RegOpenKeyEx(
  1255. HKEY_LOCAL_MACHINE, // handle to an open key
  1256. szKey, // address of subkey name
  1257. 0, // reserved
  1258. KEY_ALL_ACCESS, // desired security access
  1259. &hKey // address of buffer for opened handle
  1260. );
  1261. if (lRet != ERROR_SUCCESS)
  1262. {
  1263. TRACE_CRIT("Error opening key %ws. WinError=0x%08lx", szKey, GetLastError());
  1264. hKey = NULL;
  1265. }
  1266. end:
  1267. return hKey;
  1268. }
  1269. //
  1270. // Save the specified completion status to the registry.
  1271. //
  1272. WBEMSTATUS
  1273. NlbConfigurationUpdate::sfn_RegSetCompletion(
  1274. IN LPCWSTR szNicGuid,
  1275. IN UINT Generation,
  1276. IN WBEMSTATUS CompletionStatus
  1277. )
  1278. {
  1279. WBEMSTATUS Status = WBEM_E_FAILED;
  1280. HKEY hKey;
  1281. BOOL fExists;
  1282. hKey = sfn_RegCreateKey(
  1283. szNicGuid,
  1284. NLBUPD_REG_COMPLETIONS, // szSubKey,
  1285. TRUE, // TRUE == fVolatile,
  1286. &fExists
  1287. );
  1288. if (hKey == NULL)
  1289. {
  1290. TRACE_CRIT("Error creating key for %ws", szNicGuid);
  1291. goto end;
  1292. }
  1293. LONG lRet;
  1294. WCHAR szValueName[128];
  1295. NLB_COMPLETION_RECORD Record;
  1296. ZeroMemory(&Record, sizeof(Record));
  1297. Record.Version = NLB_CURRENT_COMPLETION_RECORD_VERSION;
  1298. Record.Generation = Generation;
  1299. Record.CompletionCode = (UINT) CompletionStatus;
  1300. StringCbPrintf(szValueName, sizeof(szValueName), L"%d", Generation);
  1301. lRet = RegSetValueEx(
  1302. hKey, // handle to key to set value for
  1303. szValueName, // name of the value to set
  1304. 0, // reserved
  1305. REG_BINARY, // flag for value type
  1306. (BYTE*) &Record,// address of value data
  1307. sizeof(Record) // size of value data
  1308. );
  1309. if (lRet == ERROR_SUCCESS)
  1310. {
  1311. Status = WBEM_NO_ERROR;
  1312. }
  1313. else
  1314. {
  1315. TRACE_CRIT("Error setting completion record for %ws(%lu)",
  1316. szNicGuid,
  1317. Generation
  1318. );
  1319. goto end;
  1320. }
  1321. end:
  1322. if (hKey != NULL)
  1323. {
  1324. RegCloseKey(hKey);
  1325. }
  1326. return Status;
  1327. }
  1328. //
  1329. // Retrieve the specified completion status from the registry.
  1330. //
  1331. WBEMSTATUS
  1332. NlbConfigurationUpdate::
  1333. sfn_RegGetCompletion(
  1334. IN LPCWSTR szNicGuid,
  1335. IN UINT Generation,
  1336. OUT WBEMSTATUS *pCompletionStatus,
  1337. OUT WCHAR **ppLog // free using delete operator.
  1338. )
  1339. {
  1340. WBEMSTATUS Status = WBEM_E_FAILED;
  1341. HKEY hKey;
  1342. WCHAR *pLog = NULL;
  1343. hKey = sfn_RegOpenKey(
  1344. szNicGuid,
  1345. NLBUPD_REG_COMPLETIONS // szSubKey,
  1346. );
  1347. if (hKey == NULL)
  1348. {
  1349. TRACE_CRIT("Error opening key for %ws", szNicGuid);
  1350. goto end;
  1351. }
  1352. LONG lRet;
  1353. WCHAR szValueName[128];
  1354. DWORD dwType;
  1355. NLB_COMPLETION_RECORD Record;
  1356. DWORD cbData = sizeof(Record);
  1357. StringCbPrintf(szValueName, sizeof(szValueName), L"%d", Generation);
  1358. lRet = RegQueryValueEx(
  1359. hKey, // handle to key to query
  1360. szValueName, // address of name of value to query
  1361. NULL, // reserved
  1362. &dwType, // address of buffer for value type
  1363. (LPBYTE)&Record, // address of data buffer
  1364. &cbData // address of data buffer size
  1365. );
  1366. if ( (lRet != ERROR_SUCCESS)
  1367. || (cbData != sizeof(Record)
  1368. || (dwType != REG_BINARY))
  1369. || (Record.Version != NLB_CURRENT_COMPLETION_RECORD_VERSION)
  1370. || (Record.Generation != Generation))
  1371. {
  1372. // This is not a valid record!
  1373. TRACE_CRIT("Error reading completion record for %ws(%d)",
  1374. szNicGuid, Generation);
  1375. goto end;
  1376. }
  1377. //
  1378. // We've got a valid completion record.
  1379. // Let's now try to read the log for this record.
  1380. //
  1381. sfn_ReadLog(hKey, Generation, &pLog);
  1382. //
  1383. // We've got valid values -- fill out the output params...
  1384. //
  1385. *pCompletionStatus = (WBEMSTATUS) Record.CompletionCode;
  1386. *ppLog = pLog; // could be NULL.
  1387. Status = WBEM_NO_ERROR;
  1388. end:
  1389. if (hKey != NULL)
  1390. {
  1391. RegCloseKey(hKey);
  1392. }
  1393. return Status;
  1394. }
  1395. //
  1396. // Delete the specified completion status from the registry.
  1397. //
  1398. VOID
  1399. NlbConfigurationUpdate::
  1400. sfn_RegDeleteCompletion(
  1401. IN LPCWSTR szNicGuid,
  1402. IN UINT Generation
  1403. )
  1404. {
  1405. WBEMSTATUS Status = WBEM_E_FAILED;
  1406. HKEY hKey;
  1407. WCHAR pLog = NULL;
  1408. hKey = sfn_RegOpenKey(
  1409. szNicGuid,
  1410. NLBUPD_REG_COMPLETIONS // szSubKey,
  1411. );
  1412. if (hKey == NULL)
  1413. {
  1414. TRACE_CRIT("Error opening key for %ws", szNicGuid);
  1415. goto end;
  1416. }
  1417. WCHAR szValueName[128];
  1418. StringCbPrintf(szValueName, sizeof(szValueName), L"%d", Generation);
  1419. RegDeleteValue(hKey, szValueName);
  1420. StringCbPrintf(szValueName, sizeof(szValueName), L"%d.log", Generation);
  1421. RegDeleteValue(hKey, szValueName);
  1422. end:
  1423. if (hKey != NULL)
  1424. {
  1425. RegCloseKey(hKey);
  1426. }
  1427. }
  1428. //
  1429. // Called to get the status of an update request, identified by
  1430. // Generation.
  1431. //
  1432. WBEMSTATUS
  1433. NlbConfigurationUpdate::GetUpdateStatus(
  1434. IN LPCWSTR szNicGuid,
  1435. IN UINT Generation,
  1436. IN BOOL fDelete, // Delete completion record
  1437. OUT WBEMSTATUS *pCompletionStatus,
  1438. OUT WCHAR **ppLog // free using delete operator.
  1439. )
  1440. //
  1441. //
  1442. //
  1443. {
  1444. WBEMSTATUS Status = WBEM_E_NOT_FOUND;
  1445. WBEMSTATUS CompletionStatus = WBEM_NO_ERROR;
  1446. TRACE_INFO(
  1447. L"->%!FUNC!(Nic=%ws, Gen=%ld)",
  1448. szNicGuid,
  1449. Generation
  1450. );
  1451. //
  1452. // We look in the registry for
  1453. // this generation ID and return the status based on the registry
  1454. // record
  1455. //
  1456. Status = sfn_RegGetCompletion(
  1457. szNicGuid,
  1458. Generation,
  1459. &CompletionStatus,
  1460. ppLog
  1461. );
  1462. if (!FAILED(Status))
  1463. {
  1464. if (fDelete && CompletionStatus!=WBEM_S_PENDING)
  1465. {
  1466. sfn_RegDeleteCompletion(
  1467. szNicGuid,
  1468. Generation
  1469. );
  1470. }
  1471. *pCompletionStatus = CompletionStatus;
  1472. }
  1473. TRACE_INFO(
  1474. L"<-%!FUNC!(Nic=%ws, Gen=%ld) returns 0x%08lx",
  1475. szNicGuid,
  1476. Generation,
  1477. (UINT) Status
  1478. );
  1479. return Status;
  1480. }
  1481. //
  1482. // Release the machine-wide update event for this NIC, and delete any
  1483. // temporary entries in the registry that were used for this update.
  1484. //
  1485. VOID
  1486. NlbConfigurationUpdate::mfn_StopUpdate(
  1487. OUT WCHAR ** ppLog
  1488. )
  1489. {
  1490. WBEMSTATUS Status;
  1491. if (ppLog != NULL)
  1492. {
  1493. *ppLog = NULL;
  1494. }
  1495. sfn_Lock();
  1496. if (m_State!=ACTIVE)
  1497. {
  1498. ASSERT(FALSE);
  1499. TRACE_CRIT("StopUpdate: invalid state %d", (int) m_State);
  1500. goto end;
  1501. }
  1502. ASSERT(m_hAsyncThread==NULL);
  1503. //
  1504. // Update the completion status value for current generation
  1505. //
  1506. Status = sfn_RegSetCompletion(
  1507. m_szNicGuid,
  1508. m_Generation,
  1509. m_CompletionStatus
  1510. );
  1511. if (FAILED(m_CompletionStatus))
  1512. {
  1513. TRACE_CRIT(L"Could not set completion for szNic=%ws, generation=%d, status=0x%x, completion-status=0x%x", m_szNicGuid, m_Generation, Status, m_CompletionStatus);
  1514. }
  1515. //
  1516. // Note: mfn_ReallyDoUpdate logs the fact that it started and stopped the
  1517. // update, so no need to do that here.
  1518. //
  1519. m_State = IDLE;
  1520. ASSERT(m_hCompletionKey != NULL); // If we started, this key should be !null
  1521. if (ppLog!=NULL)
  1522. {
  1523. sfn_ReadLog(m_hCompletionKey, m_Generation, ppLog);
  1524. }
  1525. RegCloseKey(m_hCompletionKey);
  1526. WORD wEventType = EVENTLOG_INFORMATION_TYPE;
  1527. if (FAILED(m_CompletionStatus))
  1528. {
  1529. wEventType = EVENTLOG_ERROR_TYPE;
  1530. }
  1531. ReportStopEvent (wEventType, ppLog);
  1532. m_hCompletionKey = NULL;
  1533. m_Generation = 0;
  1534. //
  1535. // Release the gobal config mutex for this NIC
  1536. //
  1537. (VOID) mfn_ReleaseSecondMutex();
  1538. end:
  1539. sfn_Unlock();
  1540. return;
  1541. }
  1542. WBEMSTATUS
  1543. NlbConfigurationUpdate::mfn_StartUpdate(
  1544. IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pNewCfg,
  1545. IN LPCWSTR szClientDescription,
  1546. OUT BOOL *pfDoAsync,
  1547. OUT WCHAR ** ppLog
  1548. )
  1549. //
  1550. // Special return values:
  1551. // WBEM_E_ALREADY_EXISTS: another update is in progress.
  1552. //
  1553. {
  1554. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  1555. BOOL fWeAcquiredLock = FALSE;
  1556. HKEY hRootKey = NULL;
  1557. BOOL fExists;
  1558. CLocalLogger logger;
  1559. UINT NewGeneration = 0;
  1560. TRACE_VERB(L"--> %!FUNC! Guid=%ws", m_szNicGuid);
  1561. if (ppLog != NULL)
  1562. {
  1563. *ppLog = NULL;
  1564. }
  1565. sfn_Lock();
  1566. do // while false
  1567. {
  1568. Status = mfn_AcquireFirstMutex();
  1569. if (FAILED(Status))
  1570. {
  1571. logger.Log(IDS_OTHER_UPDATE_ONGOING);
  1572. Status = WBEM_E_ALREADY_EXISTS;
  1573. break;
  1574. }
  1575. TRACE_INFO("Got global event!");
  1576. Status = WBEM_NO_ERROR;
  1577. fWeAcquiredLock = TRUE;
  1578. if (m_State!=IDLE)
  1579. {
  1580. //
  1581. // This is a code bug. We need to see if we should recover from
  1582. // this.
  1583. //
  1584. logger.Log(IDS_OTHER_UPDATE_ONGOING2);
  1585. Status = WBEM_E_ALREADY_EXISTS;
  1586. TRACE_CRIT("StartUpdate: invalid state %d", (int) m_State);
  1587. break;
  1588. }
  1589. //
  1590. // Create/Open the completions key for this NIC.
  1591. //
  1592. {
  1593. HKEY hKey;
  1594. hKey = sfn_RegCreateKey(
  1595. m_szNicGuid,
  1596. NLBUPD_REG_COMPLETIONS, // szSubKey,
  1597. TRUE, // TRUE == fVolatile,
  1598. &fExists
  1599. );
  1600. if (hKey == NULL)
  1601. {
  1602. TRACE_CRIT("Error creating completions key for %ws", m_szNicGuid);
  1603. Status = WBEM_E_CRITICAL_ERROR;
  1604. logger.Log(IDS_CRITICAL_RESOURCE_FAILURE);
  1605. ASSERT(m_hCompletionKey == NULL);
  1606. }
  1607. else
  1608. {
  1609. m_hCompletionKey = hKey;
  1610. }
  1611. }
  1612. }
  1613. while (FALSE);
  1614. if (!FAILED(Status))
  1615. {
  1616. m_State = ACTIVE;
  1617. }
  1618. sfn_Unlock();
  1619. if (FAILED(Status)) goto end;
  1620. //
  1621. // WE HAVE NOW GAINED EXCLUSIVE ACCESS TO UPDATE THE CONFIGURATION
  1622. //
  1623. //
  1624. // Creat/Open the root key for updates to the specified NIC, and determine
  1625. // the proposed NEW generation count for the NIC. We don't actually
  1626. // write the new generation count back to the registry unless we're
  1627. // going to do an update. The reasons for NOT doing an update are
  1628. // (a) some failure or (b) the update turns out to be a NO-OP.
  1629. //
  1630. {
  1631. LONG lRet;
  1632. DWORD dwType;
  1633. DWORD dwData;
  1634. DWORD Generation;
  1635. hRootKey = sfn_RegCreateKey(
  1636. m_szNicGuid,
  1637. NULL, // NULL == root for this guid.
  1638. FALSE, // FALSE == Non-volatile
  1639. &fExists
  1640. );
  1641. if (hRootKey==NULL)
  1642. {
  1643. TRACE_CRIT("CRITICAL ERROR: Couldn't set generation number for %ws", m_szNicGuid);
  1644. Status = WBEM_E_CRITICAL_ERROR;
  1645. logger.Log(IDS_CRITICAL_RESOURCE_FAILURE);
  1646. goto end;
  1647. }
  1648. Generation = 1; // We assume generation is 1 on error reading gen.
  1649. dwData = sizeof(Generation);
  1650. lRet = RegQueryValueEx(
  1651. hRootKey, // handle to key to query
  1652. L"Generation", // address of name of value to query
  1653. NULL, // reserved
  1654. &dwType, // address of buffer for value type
  1655. (LPBYTE) &Generation, // address of data buffer
  1656. &dwData // address of data buffer size
  1657. );
  1658. if ( lRet != ERROR_SUCCESS
  1659. || dwType != REG_DWORD
  1660. || dwData != sizeof(Generation))
  1661. {
  1662. //
  1663. // Couldn't read the generation. Let's assume it's
  1664. // a starting value of 1.
  1665. //
  1666. TRACE_CRIT("Error reading generation for %ws; assuming its 1", m_szNicGuid);
  1667. Generation = 1;
  1668. }
  1669. NewGeneration = Generation + 1;
  1670. }
  1671. //
  1672. // Copy over upto NLBUPD_MAX_CLIENT_DESCRIPTION_LENGTH chars of
  1673. // szClientDescription.
  1674. //
  1675. {
  1676. ARRAYSTRCPY(m_szClientDescription, szClientDescription);
  1677. #if OBSOLETE
  1678. UINT lClient = wcslen(szClientDescription)+1;
  1679. if (lClient > NLBUPD_MAX_CLIENT_DESCRIPTION_LENGTH)
  1680. {
  1681. TRACE_CRIT("Truncating client description %ws", szClientDescription);
  1682. lClient = NLBUPD_MAX_CLIENT_DESCRIPTION_LENGTH;
  1683. }
  1684. CopyMemory(
  1685. m_szClientDescription,
  1686. szClientDescription,
  1687. (lClient+1)*sizeof(WCHAR) // +1 for NULL
  1688. );
  1689. m_szClientDescription[NLBUPD_MAX_CLIENT_DESCRIPTION_LENGTH] = 0;
  1690. #endif // OBSOLETE
  1691. }
  1692. //
  1693. // Log the fact the we're received an update request from the specified
  1694. // client.
  1695. //
  1696. logger.Log(IDS_PROCESING_UPDATE, NewGeneration, m_szClientDescription);
  1697. ReportStartEvent(szClientDescription);
  1698. // Load the current cluster configuration into
  1699. // m_OldClusterConfig field.
  1700. // The m_OldClusterConfig.fValidNlbCfg field is set to TRUE IFF there were
  1701. // no errors trying to fill out the information.
  1702. //
  1703. if (m_OldClusterConfig.pIpAddressInfo != NULL)
  1704. {
  1705. delete m_OldClusterConfig.pIpAddressInfo;
  1706. }
  1707. // mfn_GetCurrentClusterConfiguration expects a zeroed-out structure
  1708. // on init...
  1709. ZeroMemory(&m_OldClusterConfig, sizeof(m_OldClusterConfig));
  1710. Status = mfn_GetCurrentClusterConfiguration(&m_OldClusterConfig);
  1711. if (FAILED(Status))
  1712. {
  1713. //
  1714. // Ouch, couldn't read the current cluster configuration...
  1715. //
  1716. TRACE_CRIT(L"Cannot get current cluster config on Nic %ws", m_szNicGuid);
  1717. logger.Log(IDS_ERROR_READING_CONFIG);
  1718. goto end;
  1719. }
  1720. ASSERT(mfn_OldClusterConfig.fValidNlbCfg == TRUE);
  1721. if (NewGeneration != (m_OldClusterConfig.Generation+1))
  1722. {
  1723. //
  1724. // We should never get here, because no one should updated the
  1725. // generation between when we read it in this function
  1726. // and when we called mfn_GetCurrentClusterConfiguration.
  1727. //
  1728. TRACE_CRIT("ERROR: Generation bumped up unexpectedly for %ws", m_szNicGuid);
  1729. logger.Log(IDS_CRIT_INTERNAL_ERROR);
  1730. Status = WBEM_E_CRITICAL_ERROR;
  1731. goto end;
  1732. }
  1733. //
  1734. // If the new requrested state is NLB-bound, and the previous state
  1735. // is NLB not bound, we'll check if MSCS is installed ...
  1736. // installed on this system
  1737. //
  1738. if (!m_OldClusterConfig.IsNlbBound() && pNewCfg->IsNlbBound())
  1739. {
  1740. //
  1741. // We're going from an unbound to bound state -- check if MSCS
  1742. // is installed
  1743. //
  1744. TRACE_INFO(L"Checking if MSCS Installed...");
  1745. if (CfgUtilIsMSCSInstalled())
  1746. {
  1747. TRACE_CRIT(L"Failing update request because MSCS is installed");
  1748. logger.Log(IDS_MSCS_INSTALLED);
  1749. Status = WBEM_E_NOT_SUPPORTED;
  1750. goto end;
  1751. }
  1752. TRACE_INFO(L"MSCS doesn't appear to be installed. Moving on...");
  1753. }
  1754. //
  1755. // Analyze the proposed update to see if we can do this synchronously
  1756. // or asynchronously..
  1757. // We also do parameter validation here.
  1758. //
  1759. BOOL ConnectivityChange = FALSE;
  1760. *pfDoAsync = FALSE;
  1761. Status = mfn_AnalyzeUpdate(
  1762. pNewCfg,
  1763. &ConnectivityChange,
  1764. REF logger
  1765. );
  1766. if (FAILED(Status))
  1767. {
  1768. //
  1769. // Ouch, we've hit some error -- probably bad params.
  1770. //
  1771. TRACE_CRIT(L"Cannot perform update on Nic %ws", m_szNicGuid);
  1772. goto end;
  1773. }
  1774. else if (Status == WBEM_S_FALSE)
  1775. {
  1776. //
  1777. // We use this success code to indicate that this is a No-op.
  1778. // That
  1779. //
  1780. TRACE_CRIT(L"Update is a NOOP on Nic %ws", m_szNicGuid);
  1781. logger.Log(IDS_UPDATE_NO_CHANGE);
  1782. goto end;
  1783. }
  1784. if (ConnectivityChange)
  1785. {
  1786. //
  1787. // Check if the NETCONFIG write lock is available. If not we bail ont.
  1788. // Note that it's possible that between when we check and when we
  1789. // actually do stuff someone else gets the netcfg lock -- touch luck
  1790. // -- we'll bail out later in the update process when we try
  1791. // to get the lock.
  1792. //
  1793. BOOL fCanLock = FALSE;
  1794. LPWSTR szLockedBy = NULL;
  1795. Status = CfgUtilGetNetcfgWriteLockState(&fCanLock, &szLockedBy);
  1796. if (!FAILED(Status) && !fCanLock)
  1797. {
  1798. TRACE_CRIT("%!FUNC! Someone else has netcfg write lock -- bailing");
  1799. if (szLockedBy!=NULL)
  1800. {
  1801. logger.Log(IDS_NETCFG_WRITELOCK_TAKEN, szLockedBy);
  1802. delete[] szLockedBy;
  1803. }
  1804. else
  1805. {
  1806. logger.Log(IDS_NETCFG_WRITELOCK_CANTTAKE);
  1807. }
  1808. Status = WBEM_E_SERVER_TOO_BUSY;
  1809. goto end;
  1810. }
  1811. }
  1812. //
  1813. // We recommend Async if there is a connectivity change, including
  1814. // changes in IP addresses or cluster operation modes (unicast/multicast).
  1815. //
  1816. *pfDoAsync = ConnectivityChange;
  1817. //
  1818. // Save the proposed new configuration...
  1819. //
  1820. Status = m_NewClusterConfig.Update(pNewCfg);
  1821. if (FAILED(Status))
  1822. {
  1823. //
  1824. // This is probably a memory allocation error.
  1825. //
  1826. TRACE_CRIT("Couldn't copy new config for %ws", m_szNicGuid);
  1827. logger.Log(IDS_MEM_ALLOC_FAILURE);
  1828. goto end;
  1829. }
  1830. //
  1831. // Create volatile "PendingOperation" key
  1832. //
  1833. // TODO: we don't use this pending operations key currently.
  1834. //
  1835. #if OBSOLETE
  1836. if (0)
  1837. {
  1838. HKEY hPendingKey = sfn_RegCreateKey(
  1839. m_szNicGuid,
  1840. NLBUPD_REG_PENDING, // szSubKey,
  1841. TRUE, // TRUE == fVolatile,
  1842. &fExists
  1843. );
  1844. if (hPendingKey == NULL)
  1845. {
  1846. // Ugh, can't create the volatile key...
  1847. //
  1848. TRACE_CRIT("Couldn't create pending key for %ws", m_szNicGuid);
  1849. Status = WBEM_E_CRITICAL_ERROR;
  1850. goto end;
  1851. }
  1852. else if (fExists)
  1853. {
  1854. // Ugh, this key already exists. Currently we'll just
  1855. // move on.
  1856. //
  1857. TRACE_CRIT("WARNING -- volatile pending-op key exists for %ws", m_szNicGuid);
  1858. }
  1859. RegCloseKey(hPendingKey);
  1860. hPendingKey = NULL;
  1861. }
  1862. #endif // OBSOLETE
  1863. //
  1864. // Actually write the new generation count to the registry...
  1865. //
  1866. {
  1867. LONG lRet;
  1868. lRet = RegSetValueEx(
  1869. hRootKey, // handle to key to set value for
  1870. L"Generation", // name of the value to set
  1871. 0, // reserved
  1872. REG_DWORD, // flag for value type
  1873. (BYTE*) &NewGeneration,// address of value data
  1874. sizeof(NewGeneration) // size of value data
  1875. );
  1876. if (lRet !=ERROR_SUCCESS)
  1877. {
  1878. TRACE_CRIT("CRITICAL ERROR: Couldn't set new generation number %d for %ws", NewGeneration, m_szNicGuid);
  1879. Status = WBEM_E_CRITICAL_ERROR;
  1880. logger.Log(IDS_CRIT_INTERNAL_ERROR);
  1881. goto end;
  1882. }
  1883. }
  1884. //
  1885. // The new cluster state's generation field is not filled in on entry.
  1886. // Set it to the new generation -- whose update is under progress.
  1887. //
  1888. m_NewClusterConfig.Generation = NewGeneration;
  1889. //
  1890. // We set the completion status to pending.
  1891. // It will be set to the final status when the update completes,
  1892. // either asynchronously or synchronously.
  1893. //
  1894. m_CompletionStatus = WBEM_S_PENDING;
  1895. Status = sfn_RegSetCompletion(
  1896. m_szNicGuid,
  1897. NewGeneration,
  1898. m_CompletionStatus
  1899. );
  1900. if (FAILED(Status))
  1901. {
  1902. logger.Log(IDS_CRIT_INTERNAL_ERROR);
  1903. }
  1904. else
  1905. {
  1906. LPCWSTR pLog = logger.GetStringSafe();
  1907. //
  1908. // We've actually succeeded -- let's update our internal active
  1909. // generation number, and save the local log. We must save
  1910. // the generation first, because th
  1911. //
  1912. m_Generation = NewGeneration;
  1913. if (*pLog != 0)
  1914. {
  1915. mfn_LogRawText(pLog);
  1916. }
  1917. //
  1918. // Let's clean up an old completion record here. This is our mechanism
  1919. // for garbage collection.
  1920. //
  1921. if (m_Generation > NLB_MAX_GENERATION_GAP)
  1922. {
  1923. UINT OldGeneration = m_Generation - NLB_MAX_GENERATION_GAP;
  1924. (VOID) sfn_RegDeleteCompletion(m_szNicGuid, OldGeneration);
  1925. }
  1926. }
  1927. end:
  1928. //
  1929. // If required, set *ppLog to a copy of the content in locallog.
  1930. //
  1931. if (ppLog != NULL)
  1932. {
  1933. UINT uSize=0;
  1934. LPCWSTR pLog = NULL;
  1935. logger.ExtractLog(REF pLog, REF uSize); // size includes ending NULL
  1936. if (uSize != 0)
  1937. {
  1938. LPWSTR pLogCopy = new WCHAR[uSize];
  1939. if (pLogCopy != NULL)
  1940. {
  1941. CopyMemory(pLogCopy, pLog, uSize*sizeof(*pLog));
  1942. *ppLog = pLogCopy;
  1943. }
  1944. }
  1945. }
  1946. if (fWeAcquiredLock && (FAILED(Status) || Status == WBEM_S_FALSE))
  1947. {
  1948. //
  1949. // Oops -- we acquired the lock but either had a problem
  1950. // or there is nothing to do. Clean up.
  1951. //
  1952. sfn_Lock();
  1953. ASSERT(m_State == ACTIVE);
  1954. m_State = IDLE;
  1955. if (m_hCompletionKey != NULL)
  1956. {
  1957. RegCloseKey(m_hCompletionKey);
  1958. m_hCompletionKey = NULL;
  1959. }
  1960. m_Generation = 0; // This field is unused when m_State != ACTIVE;
  1961. (void) mfn_ReleaseFirstMutex(TRUE); // TRUE == cancel, cleanup.
  1962. sfn_Unlock();
  1963. }
  1964. if (hRootKey != NULL)
  1965. {
  1966. RegCloseKey(hRootKey);
  1967. }
  1968. TRACE_VERB(L"<-- %!FUNC! Guid=%ws Status= 0x%lx", m_szNicGuid, Status);
  1969. return Status;
  1970. }
  1971. //
  1972. // Uses various windows APIs to fill up the current extended cluster
  1973. // information for a specific nic (identified by *this)
  1974. //
  1975. //
  1976. WBEMSTATUS
  1977. NlbConfigurationUpdate::mfn_GetCurrentClusterConfiguration(
  1978. OUT PNLB_EXTENDED_CLUSTER_CONFIGURATION pCfg
  1979. )
  1980. //
  1981. //
  1982. {
  1983. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  1984. NLB_IP_ADDRESS_INFO *pIpInfo = NULL;
  1985. LPWSTR szFriendlyName = NULL;
  1986. UINT NumIpAddresses = 0;
  1987. BOOL fNlbBound = FALSE;
  1988. WLBS_REG_PARAMS NlbParams; // The WLBS-specific configuration
  1989. BOOL fNlbParamsValid = FALSE;
  1990. UINT Generation = 1;
  1991. BOOL fDHCP = FALSE;
  1992. //
  1993. // Zero-out the entire structure.
  1994. //
  1995. pCfg->Clear();
  1996. //
  1997. // Get the ip address list.
  1998. //
  1999. Status = CfgUtilGetIpAddressesAndFriendlyName(
  2000. m_szNicGuid,
  2001. &NumIpAddresses,
  2002. &pIpInfo,
  2003. &szFriendlyName
  2004. );
  2005. if (FAILED(Status))
  2006. {
  2007. TRACE_CRIT("Error 0x%08lx getting ip address list for %ws", (UINT) Status, m_szNicGuid);
  2008. mfn_Log(IDS_ERROR_GETTING_IP);
  2009. pIpInfo = NULL;
  2010. szFriendlyName = NULL;
  2011. goto end;
  2012. }
  2013. //
  2014. // Check if NIC has DHCP enabled.
  2015. //
  2016. {
  2017. Status = CfgUtilGetDHCP(m_szNicGuid, &fDHCP);
  2018. if (FAILED(Status))
  2019. {
  2020. TRACE_CRIT(L"Error 0x%x attempting to determine DHCP state for NIC %ws -- ignoring (assuming no dhcp)",
  2021. (UINT) Status, m_szNicGuid);
  2022. fDHCP = FALSE;
  2023. }
  2024. // we plow on...
  2025. }
  2026. //
  2027. // Check if NLB is bound
  2028. //
  2029. Status = CfgUtilCheckIfNlbBound(
  2030. m_szNicGuid,
  2031. &fNlbBound
  2032. );
  2033. if (FAILED(Status))
  2034. {
  2035. if (Status == WBEM_E_NOT_FOUND)
  2036. {
  2037. //
  2038. // This means that NLB is not INSTALLED on this NIC.
  2039. //
  2040. TRACE_CRIT("NLB IS NOT INSTALLED ON THIS SYSTEM");
  2041. mfn_Log(IDS_NLB_NOT_INSTALLED);
  2042. fNlbBound = FALSE;
  2043. Status = WBEM_NO_ERROR;
  2044. }
  2045. else
  2046. {
  2047. TRACE_CRIT("Error 0x%08lx determining if NLB is bound to %ws", (UINT) Status, m_szNicGuid);
  2048. mfn_Log(IDS_ERROR_FINDING_NLB);
  2049. goto end;
  2050. }
  2051. }
  2052. if (fNlbBound)
  2053. {
  2054. //
  2055. // Get the latest NLB configuration information for this NIC.
  2056. //
  2057. Status = CfgUtilGetNlbConfig(
  2058. m_szNicGuid,
  2059. &NlbParams
  2060. );
  2061. if (FAILED(Status))
  2062. {
  2063. //
  2064. // We don't consider a catastrophic failure.
  2065. //
  2066. TRACE_CRIT("Error 0x%08lx reading NLB configuration for %ws", (UINT) Status, m_szNicGuid);
  2067. mfn_Log(IDS_ERROR_READING_CONFIG);
  2068. Status = WBEM_NO_ERROR;
  2069. fNlbParamsValid = FALSE;
  2070. ZeroMemory(&NlbParams, sizeof(NlbParams));
  2071. }
  2072. else
  2073. {
  2074. fNlbParamsValid = TRUE;
  2075. }
  2076. }
  2077. //
  2078. // Get the current generation
  2079. //
  2080. {
  2081. BOOL fExists=FALSE;
  2082. HKEY hKey = sfn_RegOpenKey(
  2083. m_szNicGuid,
  2084. NULL // NULL == root for this guid.,
  2085. );
  2086. Generation = 1; // We assume generation is 1 on error reading gen.
  2087. if (hKey!=NULL)
  2088. {
  2089. LONG lRet;
  2090. DWORD dwType;
  2091. DWORD dwData;
  2092. dwData = sizeof(Generation);
  2093. lRet = RegQueryValueEx(
  2094. hKey, // handle to key to query
  2095. L"Generation", // address of name of value to query
  2096. NULL, // reserved
  2097. &dwType, // address of buffer for value type
  2098. (LPBYTE) &Generation, // address of data buffer
  2099. &dwData // address of data buffer size
  2100. );
  2101. if ( lRet != ERROR_SUCCESS
  2102. || dwType != REG_DWORD
  2103. || dwData != sizeof(Generation))
  2104. {
  2105. //
  2106. // Couldn't read the generation. Let's assume it's
  2107. // a starting value of 1.
  2108. //
  2109. TRACE_CRIT("Error reading generation for %ws; assuming its 0", m_szNicGuid);
  2110. Generation = 1;
  2111. }
  2112. RegCloseKey(hKey);
  2113. }
  2114. }
  2115. //
  2116. // Success ... fill out pCfg
  2117. //
  2118. pCfg->fValidNlbCfg = fNlbParamsValid;
  2119. pCfg->Generation = Generation;
  2120. pCfg->fBound = fNlbBound;
  2121. pCfg->fDHCP = fDHCP;
  2122. pCfg->NumIpAddresses = NumIpAddresses;
  2123. pCfg->pIpAddressInfo = pIpInfo;
  2124. pIpInfo = NULL;
  2125. (VOID) pCfg->SetFriendlyName(szFriendlyName); // Copies this internally.
  2126. if (fNlbBound)
  2127. {
  2128. pCfg->NlbParams = NlbParams; // struct copy
  2129. }
  2130. Status = WBEM_NO_ERROR;
  2131. end:
  2132. if (pIpInfo!=NULL)
  2133. {
  2134. delete pIpInfo;
  2135. }
  2136. if (szFriendlyName != NULL)
  2137. {
  2138. delete szFriendlyName;
  2139. szFriendlyName = NULL;
  2140. }
  2141. if (FAILED(Status))
  2142. {
  2143. pCfg->fValidNlbCfg = FALSE;
  2144. }
  2145. return Status;
  2146. }
  2147. //
  2148. // Does the update synchronously -- this is where the meat of the update
  2149. // logic exists. It can range from a NoOp, through changing the
  2150. // fields of a single port rule, through binding NLB, setting up cluster
  2151. // parameters and adding the relevant IP addresses in TCPIP.
  2152. //
  2153. VOID
  2154. NlbConfigurationUpdate::mfn_ReallyDoUpdate(
  2155. VOID
  2156. )
  2157. {
  2158. WBEMSTATUS Status = WBEM_NO_ERROR;
  2159. BOOL fResetIpList = FALSE; // Whether to re-do ip addresses in the end
  2160. BOOL fJustBound = FALSE; // whether we're binding as part of the update.
  2161. BOOL fModeChange = FALSE; // There's been a change in operation mode.
  2162. TRACE_INFO(L"->%!FUNC!(Nic=%ws)", m_szNicGuid);
  2163. /*
  2164. PSEUDO CODE
  2165. if (bound)
  2166. {
  2167. if (major-change, including unbind or mac-address change)
  2168. {
  2169. stop wlbs, set initial-state to false/suspended.
  2170. remove all ip addresses except dedicated-ip
  2171. }
  2172. if (need-to-unbind)
  2173. {
  2174. <unbind>
  2175. }
  2176. }
  2177. else // not bound
  2178. {
  2179. if (need to bind)
  2180. {
  2181. if (nlb config already exists in registry)
  2182. {
  2183. munge initial state to stopped,
  2184. zap old cluster ip address.
  2185. }
  2186. <bind>
  2187. }
  2188. }
  2189. if (need to bind)
  2190. {
  2191. <change cluster properties>
  2192. }
  2193. <add new ip list if needed>
  2194. note: on major change, cluster is left in the stopped state,
  2195. with initial-state=stopped
  2196. this is so that a second round can be made just to start the hosts.
  2197. */
  2198. MyBreak(L"Break at start of ReallyDoUpdate.\n");
  2199. mfn_Log(IDS_STARTING_UPDATE);
  2200. if (m_OldClusterConfig.fBound)
  2201. {
  2202. BOOL fTakeOutVips = FALSE;
  2203. //
  2204. // We are currently bound
  2205. //
  2206. if (!m_NewClusterConfig.fBound)
  2207. {
  2208. //
  2209. // We need to unbind
  2210. //
  2211. fTakeOutVips = TRUE;
  2212. }
  2213. else
  2214. {
  2215. BOOL fConnectivityChange = FALSE;
  2216. //
  2217. // We were bound and need to remain bound.
  2218. // Determine if this is a major change or not.
  2219. //
  2220. Status = CfgUtilsAnalyzeNlbUpdate(
  2221. &m_OldClusterConfig.NlbParams,
  2222. &m_NewClusterConfig.NlbParams,
  2223. &fConnectivityChange
  2224. );
  2225. if (FAILED(Status))
  2226. {
  2227. if (Status == WBEM_E_INVALID_PARAMETER)
  2228. {
  2229. //
  2230. // We'd better exit.
  2231. //
  2232. mfn_Log(IDS_NEW_PARAMS_INCORRECT);
  2233. goto end;
  2234. }
  2235. else
  2236. {
  2237. //
  2238. // Lets try to plow on...
  2239. //
  2240. //
  2241. // Log
  2242. //
  2243. TRACE_CRIT("Analyze update returned error 0x%08lx, trying to continue...", (UINT)Status);
  2244. fConnectivityChange = TRUE;
  2245. }
  2246. }
  2247. //
  2248. // Check if there's a change in mode -- if so, we won't
  2249. // add back IP addresses because of the potential of IP address
  2250. // conflict.
  2251. //
  2252. {
  2253. NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE tmOld, tmNew;
  2254. tmOld = m_OldClusterConfig.GetTrafficMode();
  2255. tmNew = m_NewClusterConfig.GetTrafficMode();
  2256. fModeChange = (tmOld != tmNew);
  2257. }
  2258. fTakeOutVips = fConnectivityChange;
  2259. }
  2260. if (fTakeOutVips)
  2261. {
  2262. mfn_TakeOutVips();
  2263. fResetIpList = TRUE;
  2264. }
  2265. if (!m_NewClusterConfig.fBound)
  2266. {
  2267. // Unbind...
  2268. mfn_Log(IDS_UNBINDING_NLB);
  2269. Status = CfgUtilChangeNlbBindState(m_szNicGuid, FALSE);
  2270. if (FAILED(Status))
  2271. {
  2272. mfn_Log(IDS_UNBIND_FAILED);
  2273. }
  2274. else
  2275. {
  2276. mfn_Log(IDS_UNBIND_SUCCEEDED);
  2277. }
  2278. //
  2279. // Sleep a bit to allow things to settle down after binding...
  2280. //
  2281. Sleep(4000);
  2282. fResetIpList = TRUE;
  2283. }
  2284. }
  2285. else // We were previously unbound
  2286. {
  2287. if (m_NewClusterConfig.fBound)
  2288. {
  2289. // Before binding NLB, write the new NLB parameters to registry. This is
  2290. // so that after the binding is completed, NLB will come up with the new
  2291. // NLB parameters. We are not checking the status of this operation
  2292. // because we are going to be doing this operation once again after the binding
  2293. // is completed. We will fail only when the second attempt fails.
  2294. CfgUtilRegWriteParams(m_szNicGuid, &m_NewClusterConfig.NlbParams);
  2295. //
  2296. // We need to bind.
  2297. //
  2298. // TODO: mfn_ZapUnboundSettings();
  2299. mfn_Log(IDS_BINDING_NLB);
  2300. Status = CfgUtilChangeNlbBindState(m_szNicGuid, TRUE);
  2301. if (FAILED(Status))
  2302. {
  2303. mfn_Log(IDS_BIND_FAILED);
  2304. }
  2305. else
  2306. {
  2307. mfn_Log(IDS_BIND_SUCCEEDED);
  2308. fJustBound = TRUE;
  2309. //
  2310. // Let wait until we can read our config again...
  2311. //
  2312. // TODO: use constants here, see if there is a better
  2313. // way to do this. We retry because if the NIC is
  2314. // disconnected, we Bind returns, but GetConfig fails --
  2315. // because the driver is not really started yet -- we need
  2316. // to investigate why that is happening!
  2317. //
  2318. UINT MaxTry = 5;
  2319. WBEMSTATUS TmpStatus = WBEM_E_CRITICAL_ERROR;
  2320. for (UINT u=0;u<MaxTry;u++)
  2321. {
  2322. //
  2323. // TODO: we put this in here really to work around
  2324. // the real problem, which is that NLB is not readyrequest
  2325. // right after bind completes. We need to fix that.
  2326. //
  2327. Sleep(4000);
  2328. // Check if the binding operation has completed by issuing a "query" to the NLB driver.
  2329. // This call will fail if the binding operation has NOT completed.
  2330. TmpStatus = CfgUtilControlCluster( m_szNicGuid, WLBS_QUERY, 0, 0, NULL, NULL );
  2331. if (!FAILED(TmpStatus)) break;
  2332. TRACE_INFO("CfgUtilControlCluster failed with %x after bind, retrying %d times", TmpStatus, (MaxTry - u));
  2333. }
  2334. if (FAILED(TmpStatus))
  2335. {
  2336. Status = TmpStatus;
  2337. mfn_Log(IDS_ERROR_READING_CONFIG);
  2338. TRACE_CRIT("CfgUtilGetNlbConfig failed, returning %d", TmpStatus);
  2339. }
  2340. else
  2341. {
  2342. mfn_Log(IDS_CLUSTER_CONFIG_STABLE);
  2343. }
  2344. }
  2345. fResetIpList = TRUE;
  2346. }
  2347. }
  2348. if (FAILED(Status)) goto end;
  2349. if (m_NewClusterConfig.fBound)
  2350. {
  2351. //
  2352. // We should already be bound, so we change cluster properties
  2353. // if required.
  2354. //
  2355. mfn_Log(IDS_MODIFY_CLUSTER_CONFIG);
  2356. Status = CfgUtilSetNlbConfig(
  2357. m_szNicGuid,
  2358. &m_NewClusterConfig.NlbParams,
  2359. fJustBound
  2360. );
  2361. if (FAILED(Status))
  2362. {
  2363. mfn_Log(IDS_MODIFY_FAILED);
  2364. }
  2365. else
  2366. {
  2367. mfn_Log(IDS_MODIFY_SUCCEEDED);
  2368. }
  2369. }
  2370. if (FAILED(Status)) goto end;
  2371. if (!fResetIpList)
  2372. {
  2373. //
  2374. // Additionally check if there is a change in
  2375. // the before and after ip lists! We could get here for example of
  2376. // we were previously unbound and remain unbound, but there is
  2377. // a change in the set of IP addresses on the adapter.
  2378. //
  2379. INT NumOldAddresses = m_OldClusterConfig.NumIpAddresses;
  2380. if ( m_NewClusterConfig.NumIpAddresses != NumOldAddresses)
  2381. {
  2382. fResetIpList = TRUE;
  2383. }
  2384. else
  2385. {
  2386. //
  2387. // Check if there is a change in the list of ip addresses or
  2388. // their order of appearance.
  2389. //
  2390. NLB_IP_ADDRESS_INFO *pOldIpInfo = m_OldClusterConfig.pIpAddressInfo;
  2391. NLB_IP_ADDRESS_INFO *pNewIpInfo = m_NewClusterConfig.pIpAddressInfo;
  2392. for (UINT u=0; u<NumOldAddresses; u++)
  2393. {
  2394. if ( _wcsicmp(pNewIpInfo[u].IpAddress, pOldIpInfo[u].IpAddress)
  2395. || _wcsicmp(pNewIpInfo[u].SubnetMask, pOldIpInfo[u].SubnetMask))
  2396. {
  2397. fResetIpList = TRUE;
  2398. break;
  2399. }
  2400. }
  2401. }
  2402. }
  2403. if (fResetIpList && !fModeChange)
  2404. {
  2405. mfn_Log(IDS_MODIFYING_IP_ADDR);
  2406. //
  2407. // 5/30/01 JosephJ Right after bind/unbind things are unsettled, so
  2408. // we give things some time to stabilize.
  2409. // TODO: Get to the bottom of this -- basically bind is returning
  2410. // prematurely, and/or the enable/disable of the adapter is
  2411. // having an effect that takes Tcpip some time to be able to
  2412. // accept a change in the ip address list.
  2413. //
  2414. Sleep(5000);
  2415. if (m_NewClusterConfig.NumIpAddresses!=0)
  2416. {
  2417. Status = CfgUtilSetStaticIpAddresses(
  2418. m_szNicGuid,
  2419. m_NewClusterConfig.NumIpAddresses,
  2420. m_NewClusterConfig.pIpAddressInfo
  2421. );
  2422. }
  2423. else
  2424. {
  2425. Status = CfgUtilSetDHCP(
  2426. m_szNicGuid
  2427. );
  2428. }
  2429. if (FAILED(Status))
  2430. {
  2431. mfn_Log(IDS_MODIFY_IP_ADDR_FAILED);
  2432. }
  2433. else
  2434. {
  2435. mfn_Log(IDS_MODIFY_IP_ADDR_SUCCEEDED);
  2436. }
  2437. }
  2438. end:
  2439. if (FAILED(Status))
  2440. {
  2441. mfn_Log(
  2442. IDS_UPDATE_FAILED,
  2443. (UINT) Status
  2444. );
  2445. }
  2446. else
  2447. {
  2448. mfn_Log(IDS_UPDATE_SUCCEEDED);
  2449. }
  2450. TRACE_INFO(L"<-%!FUNC!(Nic=%ws)", m_szNicGuid);
  2451. m_CompletionStatus = Status;
  2452. }
  2453. VOID
  2454. NlbConfigurationUpdate::mfn_TakeOutVips(VOID)
  2455. {
  2456. WBEMSTATUS Status;
  2457. WLBS_REG_PARAMS *pParams = NULL;
  2458. //
  2459. // We keep the new ded ip address if possible, else the old, else nothing.
  2460. //
  2461. if (m_NewClusterConfig.fBound && !m_NewClusterConfig.IsBlankDedicatedIp())
  2462. {
  2463. pParams = &m_NewClusterConfig.NlbParams;
  2464. }
  2465. else if (!m_OldClusterConfig.IsBlankDedicatedIp())
  2466. {
  2467. pParams = &m_OldClusterConfig.NlbParams;
  2468. }
  2469. //
  2470. // Stop the cluster.
  2471. //
  2472. mfn_Log(IDS_STOPPING_CLUSTER);
  2473. Status = CfgUtilControlCluster(m_szNicGuid, WLBS_STOP, 0, 0, NULL, NULL);
  2474. if (FAILED(Status))
  2475. {
  2476. mfn_Log(IDS_STOP_FAILED, (UINT) Status);
  2477. }
  2478. else
  2479. {
  2480. mfn_Log(IDS_STOP_SUCCEEDED);
  2481. }
  2482. //
  2483. // Take out all vips and add only the dedicated IP address (new if possible,
  2484. // else old) if there is one.
  2485. //
  2486. if (pParams != NULL)
  2487. {
  2488. NLB_IP_ADDRESS_INFO IpInfo;
  2489. ZeroMemory(&IpInfo, sizeof(IpInfo));
  2490. StringCbCopy(IpInfo.IpAddress, sizeof(IpInfo.IpAddress), pParams->ded_ip_addr);
  2491. StringCbCopy(IpInfo.SubnetMask, sizeof(IpInfo.SubnetMask), pParams->ded_net_mask);
  2492. TRACE_INFO("Going to take out all addresses except dedicated address on %ws", m_szNicGuid);
  2493. mfn_Log(IDS_REMOVING_CLUSTER_IPS);
  2494. Status = CfgUtilSetStaticIpAddresses(
  2495. m_szNicGuid,
  2496. 1,
  2497. &IpInfo
  2498. );
  2499. }
  2500. else
  2501. {
  2502. TRACE_INFO("Going to take out ALL addresses on NIC %ws", m_szNicGuid);
  2503. mfn_Log(IDS_REMOVING_STATIC_IPS);
  2504. Status = CfgUtilSetDHCP(
  2505. m_szNicGuid
  2506. );
  2507. }
  2508. //
  2509. // 5/30/01 JosephJ Right after bind/unbind things are unsettled, so
  2510. // we give things some time to stabilize.
  2511. // TODO: Get to the bottom of this -- basically bind is returning
  2512. // prematurely, and/or the enable/disable of the adapter is
  2513. // having an effect that takes Tcpip some time to be able to
  2514. // accept a change in the ip address list.
  2515. //
  2516. Sleep(1000);
  2517. if (FAILED(Status))
  2518. {
  2519. mfn_Log(IDS_REMOVE_IP_FAILED);
  2520. }
  2521. else
  2522. {
  2523. mfn_Log(IDS_REMOVE_IP_SUCCEEDED);
  2524. }
  2525. }
  2526. //
  2527. // Analyzes the nature of the update, mainly to decide whether or not
  2528. // we need to do the update asynchronously.
  2529. //
  2530. // Side effect: builds/modifies a list of IP addresses that need to be added on
  2531. // the NIC. Also may munge some of the wlbsparm fields to bring them into
  2532. // canonical format.
  2533. // TODO This is duplicated from the one in cfgutils.lib -- get rid of this
  2534. // one!
  2535. //
  2536. WBEMSTATUS
  2537. NlbConfigurationUpdate::mfn_AnalyzeUpdate(
  2538. IN PNLB_EXTENDED_CLUSTER_CONFIGURATION pNewCfg,
  2539. IN BOOL *pConnectivityChange,
  2540. IN CLocalLogger &logger
  2541. )
  2542. //
  2543. // WBEM_S_FALSE -- update is a no-op.
  2544. //
  2545. {
  2546. WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER;
  2547. NLBERROR nerr;
  2548. sfn_Lock();
  2549. nerr = m_OldClusterConfig.AnalyzeUpdate(
  2550. pNewCfg,
  2551. pConnectivityChange
  2552. );
  2553. switch(nerr)
  2554. {
  2555. case NLBERR_OK:
  2556. Status = WBEM_NO_ERROR;
  2557. break;
  2558. case NLBERR_NO_CHANGE:
  2559. Status = WBEM_S_FALSE;
  2560. break;
  2561. case NLBERR_RESOURCE_ALLOCATION_FAILURE:
  2562. Status = WBEM_E_OUT_OF_MEMORY;
  2563. logger.Log(IDS_RR_OUT_OF_SYSTEM_RES);
  2564. break;
  2565. case NLBERR_LLAPI_FAILURE:
  2566. Status = WBEM_E_CRITICAL_ERROR;
  2567. logger.Log(IDS_RR_UNDERLYING_COM_FAILED);
  2568. break;
  2569. case NLBERR_INITIALIZATION_FAILURE:
  2570. Status = WBEM_E_CRITICAL_ERROR;
  2571. logger.Log(IDS_RR_INIT_FAILURE);
  2572. break;
  2573. case NLBERR_INVALID_CLUSTER_SPECIFICATION:
  2574. logger.Log(IDS_RR_INVALID_CLUSTER_SPEC);
  2575. Status = WBEM_E_INVALID_PARAMETER;
  2576. break;
  2577. case NLBERR_INTERNAL_ERROR: // fall through...
  2578. default:
  2579. Status = WBEM_E_CRITICAL_ERROR;
  2580. logger.Log(IDS_RR_INTERNAL_ERROR);
  2581. break;
  2582. }
  2583. sfn_Unlock();
  2584. return Status;
  2585. }
  2586. VOID
  2587. NlbConfigurationUpdate::mfn_Log(
  2588. UINT Id, // Resource ID of format,
  2589. ...
  2590. )
  2591. {
  2592. DWORD dwRet;
  2593. WCHAR wszFormat[NLBUPD_MAX_LOG_LENGTH];
  2594. WCHAR wszBuffer[NLBUPD_MAX_LOG_LENGTH];
  2595. if (!LoadString(ghModule, Id, wszFormat, NLBUPD_MAX_LOG_LENGTH))
  2596. {
  2597. TRACE_CRIT("LoadString returned 0, GetLastError() : 0x%x, Could not log message !!!", GetLastError());
  2598. return;
  2599. }
  2600. va_list arglist;
  2601. va_start (arglist, Id);
  2602. dwRet = FormatMessage(FORMAT_MESSAGE_FROM_STRING,
  2603. wszFormat,
  2604. 0, // Message Identifier - Ignored for FORMAT_MESSAGE_FROM_STRING
  2605. 0, // Language Identifier
  2606. wszBuffer,
  2607. NLBUPD_MAX_LOG_LENGTH,
  2608. &arglist);
  2609. va_end (arglist);
  2610. if (dwRet)
  2611. {
  2612. mfn_LogRawText(wszBuffer);
  2613. }
  2614. else
  2615. {
  2616. TRACE_CRIT("FormatMessage returned error : %u, Could not log message !!!", dwRet);
  2617. }
  2618. }
  2619. //
  2620. // Acquires the first global mutex, call this first.
  2621. //
  2622. WBEMSTATUS
  2623. NlbConfigurationUpdate::mfn_AcquireFirstMutex(
  2624. VOID
  2625. )
  2626. {
  2627. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2628. HANDLE hMtx1 = NULL;
  2629. HANDLE hMtx2 = NULL;
  2630. HANDLE hEvt = NULL;
  2631. BOOL fMutexAcquired = FALSE;
  2632. BOOL fMutex1Abandoned = FALSE;
  2633. BOOL fMutex2Abandoned = FALSE;
  2634. //
  2635. // Locally open a handle to hMtx1 and acquire it.
  2636. // This serializes access to m_hmutex.
  2637. //
  2638. {
  2639. hMtx1 = CreateMutex(
  2640. NULL, // lpEventAttributes,
  2641. FALSE, // FALSE == not initial owner
  2642. NLB_CONFIGURATION_MUTEX_PREFIX
  2643. );
  2644. TRACE_INFO(
  2645. L"CreateMutex(%ws) returns 0x%p",
  2646. NLB_CONFIGURATION_MUTEX_PREFIX,
  2647. hMtx1
  2648. );
  2649. if (hMtx1 == NULL)
  2650. {
  2651. TRACE_CRIT("ERROR: CreateMutex returned NULL for Mutex1");
  2652. goto end;
  2653. }
  2654. TRACE_INFO("Waiting for Mutex1...");
  2655. DWORD dwRet = WaitForSingleObject(hMtx1, NLB_MUTEX_TIMEOUT);
  2656. TRACE_INFO("Waiting for Mutex1 returns 0x%08lx", dwRet);
  2657. if (dwRet == WAIT_ABANDONED)
  2658. {
  2659. TRACE_CRIT("WARNING: Mutex1 abandoned!");
  2660. fMutex1Abandoned = TRUE;
  2661. }
  2662. else if (dwRet != WAIT_OBJECT_0)
  2663. {
  2664. TRACE_CRIT("Couldn't get Mutex1 -- probably busy elsewhere!");
  2665. Status = WBEM_E_ALREADY_EXISTS;
  2666. goto end;
  2667. }
  2668. fMutexAcquired = TRUE;
  2669. }
  2670. //
  2671. // open handles to hMtx2 and hEvt
  2672. //
  2673. {
  2674. WCHAR M2Name[sizeof(NLB_CONFIGURATION_MUTEX_PREFIX)/sizeof(WCHAR) + NLB_GUID_LEN];
  2675. StringCbCopy(M2Name, sizeof(M2Name), NLB_CONFIGURATION_MUTEX_PREFIX);
  2676. StringCbCat(M2Name, sizeof(M2Name), m_szNicGuid);
  2677. hMtx2 = CreateMutex(
  2678. NULL, // lpEventAttributes,
  2679. FALSE, // FALSE == not initial owner
  2680. M2Name
  2681. );
  2682. TRACE_INFO(
  2683. L"CreateMutex(%ws) returns 0x%08p",
  2684. M2Name,
  2685. hMtx2
  2686. );
  2687. if (hMtx2 == NULL)
  2688. {
  2689. TRACE_CRIT("ERROR: CreateMutex returned NULL for Mutex2");
  2690. goto end;
  2691. }
  2692. hEvt = CreateEvent(
  2693. NULL, // lpEventAttributes,
  2694. TRUE, // bManualReset TRUE==ManualReset
  2695. FALSE, // FALSE==initial state is not signaled.
  2696. NULL // NULL == no name
  2697. );
  2698. TRACE_INFO(
  2699. L"CreateEvent(<unnamed>) returns 0x%08p",
  2700. hEvt
  2701. );
  2702. if (hEvt == NULL)
  2703. {
  2704. TRACE_CRIT("ERROR: CreateEvent returned NULL for unnamed hEvt");
  2705. goto end;
  2706. }
  2707. }
  2708. //
  2709. // Acquire and immediately release 2nd mutex.
  2710. // This is subtle but nevertherless important to do.
  2711. // This is to ensure that there's no update pending -- some
  2712. // other thread/process could be in the middle of an update, with
  2713. // just hMtx2 held (not hMtx1). Since we've got hMtx1, once we do this
  2714. // test we need not fear that hMtx2 will subsequently be taken by
  2715. // anyone else as long as we keep hMtx1.
  2716. //
  2717. {
  2718. TRACE_INFO("Waiting for Mutex2...");
  2719. DWORD dwRet = WaitForSingleObject(hMtx2, NLB_MUTEX_TIMEOUT);
  2720. TRACE_INFO("Waiting for Mutex2 returns 0x%08lx", dwRet);
  2721. if (dwRet == WAIT_ABANDONED)
  2722. {
  2723. TRACE_CRIT("WARNING: Mutex2 abandoned!");
  2724. fMutex2Abandoned = TRUE;
  2725. }
  2726. else if (dwRet != WAIT_OBJECT_0)
  2727. {
  2728. TRACE_CRIT("Couldn't get Mutex2 -- probably busy elsewhere!");
  2729. Status = WBEM_E_ALREADY_EXISTS;
  2730. goto end;
  2731. }
  2732. ReleaseMutex(hMtx2);
  2733. }
  2734. //
  2735. // Lock s_Lock and save the 3 handles in m_hmutex. For now, fail if m_mmutex
  2736. // contains non-NULL handles (could happen if thread died on previous
  2737. // invocation).
  2738. //
  2739. {
  2740. sfn_Lock();
  2741. if ( m_mutex.hMtx1!=NULL
  2742. || m_mutex.hMtx2!=NULL
  2743. || m_mutex.hEvt!=NULL
  2744. )
  2745. {
  2746. TRACE_CRIT("%!FUNC! ERROR: m_mutex contains non-null handles.m1=0x%p; m2=0x%p; e=0x%p", m_mutex.hMtx1, m_mutex.hMtx2, m_mutex.hEvt);
  2747. //
  2748. // If we've found an abandoned mutex, we assume the saved handles
  2749. // are abandoned and clean them up.
  2750. //
  2751. if (fMutex1Abandoned || fMutex2Abandoned)
  2752. {
  2753. TRACE_CRIT("%!FUNC! found abandoned mutex(es) so cleaning up handles in m_mutex");
  2754. if (m_mutex.hMtx1 != NULL)
  2755. {
  2756. CloseHandle(m_mutex.hMtx1);
  2757. m_mutex.hMtx1 = NULL;
  2758. }
  2759. if (m_mutex.hMtx2 != NULL)
  2760. {
  2761. CloseHandle(m_mutex.hMtx2);
  2762. m_mutex.hMtx2 = NULL;
  2763. }
  2764. if (m_mutex.hEvt != NULL)
  2765. {
  2766. CloseHandle(m_mutex.hEvt);
  2767. m_mutex.hEvt = NULL;
  2768. }
  2769. // We'll try to move on...
  2770. TRACE_CRIT(L"Cleaning up state on receiving abandoned mutex and moving on...");
  2771. }
  2772. else
  2773. {
  2774. TRACE_CRIT(L"Bailing because of bad mutex state");
  2775. sfn_Unlock();
  2776. goto end;
  2777. }
  2778. }
  2779. m_mutex.hMtx1 = hMtx1;
  2780. m_mutex.hMtx2 = hMtx2;
  2781. m_mutex.hEvt = hEvt;
  2782. hMtx1 = NULL;
  2783. hMtx2 = NULL;
  2784. hEvt = NULL;
  2785. sfn_Unlock();
  2786. }
  2787. Status = WBEM_NO_ERROR;
  2788. end:
  2789. if (FAILED(Status))
  2790. {
  2791. if (fMutexAcquired)
  2792. {
  2793. ReleaseMutex(hMtx1);
  2794. }
  2795. if (hMtx1!=NULL)
  2796. {
  2797. CloseHandle(hMtx1);
  2798. hMtx1=NULL;
  2799. }
  2800. if (hMtx2!=NULL)
  2801. {
  2802. CloseHandle(hMtx2);
  2803. hMtx2=NULL;
  2804. }
  2805. if (hEvt!=NULL)
  2806. {
  2807. CloseHandle(hEvt);
  2808. hEvt = NULL;
  2809. }
  2810. }
  2811. return Status;
  2812. }
  2813. WBEMSTATUS
  2814. NlbConfigurationUpdate::mfn_ReleaseFirstMutex(
  2815. BOOL fCancel
  2816. )
  2817. {
  2818. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2819. HANDLE hMtx1 = NULL;
  2820. HANDLE hMtx2 = NULL;
  2821. HANDLE hEvt = NULL;
  2822. //
  2823. // Note -- this function is only called after mfn_AcquireFirstMutex,
  2824. // which sets up the following handles. So these handles SHOULD all
  2825. // be non-NULL -- else it's an internal fatal error (code bug).
  2826. //
  2827. sfn_Lock();
  2828. hMtx1 = m_mutex.hMtx1;
  2829. hMtx2 = m_mutex.hMtx2;
  2830. hEvt = m_mutex.hEvt;
  2831. sfn_Unlock();
  2832. if (hEvt == NULL || hMtx1==NULL || hMtx2==NULL)
  2833. {
  2834. ASSERT(!"NULL m_hmutex.hEvt or hMtx1 or hMtx2 unexpected!");
  2835. TRACE_CRIT("ERROR: null hEvt or hMtx1 or hMtx2");
  2836. goto end;
  2837. }
  2838. //
  2839. // If (!fCancel) wait for event to be signalled.
  2840. //
  2841. if (!fCancel)
  2842. {
  2843. TRACE_INFO("Waiting for event 0x%p...", hEvt);
  2844. (VOID) WaitForSingleObject(hEvt, INFINITE);
  2845. TRACE_INFO("Done waiting for event 0x%p", hEvt);
  2846. }
  2847. //
  2848. // Release first mutex and close the mutex and event handle
  2849. //
  2850. {
  2851. sfn_Lock();
  2852. if (hMtx1 != m_mutex.hMtx1 || hEvt != m_mutex.hEvt)
  2853. {
  2854. ASSERT(FALSE);
  2855. TRACE_CRIT("ERROR: %!FUNC!: hMtx1 or hEvt has changed!");
  2856. sfn_Unlock();
  2857. goto end;
  2858. }
  2859. if (fCancel)
  2860. {
  2861. if (hMtx2 == m_mutex.hMtx2)
  2862. {
  2863. m_mutex.hMtx2 = NULL;
  2864. CloseHandle(hMtx2);
  2865. hMtx2 = NULL;
  2866. }
  2867. else
  2868. {
  2869. ASSERT(FALSE);
  2870. TRACE_CRIT("ERROR: %!FUNC!: hMtx2 has changed!");
  2871. }
  2872. }
  2873. m_mutex.hMtx1 = NULL;
  2874. m_mutex.hEvt = NULL;
  2875. sfn_Unlock();
  2876. ReleaseMutex(hMtx1);
  2877. CloseHandle(hMtx1);
  2878. hMtx1 = NULL;
  2879. CloseHandle(hEvt);
  2880. hEvt = NULL;
  2881. }
  2882. Status = WBEM_NO_ERROR;
  2883. end:
  2884. return Status;
  2885. }
  2886. //
  2887. // Acquire the 2nd mutex (could be called from a different thread
  2888. // than the one that called mfn_AcquireFirstMutex.
  2889. // Also signals an internal event which mfn_ReleaseFirstMutex may
  2890. // be waiting on.
  2891. //
  2892. WBEMSTATUS
  2893. NlbConfigurationUpdate::mfn_AcquireSecondMutex(
  2894. VOID
  2895. )
  2896. {
  2897. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2898. HANDLE hMtx1 = NULL;
  2899. HANDLE hMtx2 = NULL;
  2900. HANDLE hEvt = NULL;
  2901. //
  2902. // Note -- this function is only called after mfn_AcquireFirstMutex,
  2903. // which sets up the following handles. So these handles SHOULD all
  2904. // be non-NULL -- else it's an internal fatal error (code bug).
  2905. //
  2906. sfn_Lock();
  2907. hMtx1 = m_mutex.hMtx1;
  2908. hMtx2 = m_mutex.hMtx2;
  2909. hEvt = m_mutex.hEvt;
  2910. sfn_Unlock();
  2911. if (hEvt == NULL || hMtx1==NULL || hMtx2==NULL)
  2912. {
  2913. ASSERT(!"NULL m_hmutex.hEvt or hMtx1 or hMtx2 unexpected!");
  2914. TRACE_CRIT("ERROR: %!FUNC! null hEvt or hMtx1 or hMtx2");
  2915. goto end;
  2916. }
  2917. //
  2918. // Acquire 2nd mutex -- we're really guaranteed to get it immediately here
  2919. //
  2920. TRACE_INFO("Waiting for Mutex2...");
  2921. DWORD dwRet = WaitForSingleObject(hMtx2, INFINITE);
  2922. TRACE_INFO("Waiting for Mutex2 returns 0x%08lx", dwRet);
  2923. if (dwRet == WAIT_ABANDONED)
  2924. {
  2925. TRACE_CRIT("WARNING: Mutex2 abandoned!");
  2926. }
  2927. //
  2928. // Signal event, letting mfn_ReleaseFirstMutex know that
  2929. // the 2nd mutex has been acquired.
  2930. //
  2931. SetEvent(hEvt);
  2932. Status = WBEM_NO_ERROR;
  2933. end:
  2934. return Status;
  2935. }
  2936. //
  2937. // Releases the second mutex.
  2938. //
  2939. WBEMSTATUS
  2940. NlbConfigurationUpdate::mfn_ReleaseSecondMutex(
  2941. VOID
  2942. )
  2943. {
  2944. WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR;
  2945. HANDLE hMtx2 = NULL;
  2946. //
  2947. // Note -- this function is only called after mfn_AcquireFirstMutex,
  2948. // which sets up the following handles. So hMtx2
  2949. // should be non-NULL -- else it's an internal fatal error (code bug).
  2950. // hMtx1 and hEvt however could (typically would) be NULL.
  2951. //
  2952. //
  2953. sfn_Lock();
  2954. hMtx2 = m_mutex.hMtx2;
  2955. m_mutex.hMtx2 = NULL;
  2956. sfn_Unlock();
  2957. if (hMtx2==NULL)
  2958. {
  2959. ASSERT(!"NULL hMtx2 unexpected!");
  2960. TRACE_CRIT("ERROR: %!FUNC! null hMtx2");
  2961. goto end;
  2962. }
  2963. //
  2964. // Release 2nd mutex, close handle.
  2965. // It's important to do this AFTER m_mutex.hMtx2 is cleared above.
  2966. // Why? Because mfn_AcquireFirstMutex, after aquiring hMtx1 AND hMtx2,
  2967. // then expects m_mutex to be all cleared.
  2968. //
  2969. ReleaseMutex(hMtx2);
  2970. CloseHandle(hMtx2);
  2971. hMtx2 = NULL;
  2972. Status = WBEM_NO_ERROR;
  2973. end:
  2974. return Status;
  2975. }
  2976. VOID NlbConfigurationUpdate::ReportStopEvent(
  2977. const WORD wEventType,
  2978. WCHAR **ppLog
  2979. )
  2980. {
  2981. TRACE_INFO("->");
  2982. if (g_hEventLog == NULL)
  2983. {
  2984. TRACE_CRIT("Event log not opened or failed to open");
  2985. TRACE_INFO("<-");
  2986. return;
  2987. }
  2988. //
  2989. // Log this to the system event log, WLBS source
  2990. //
  2991. WCHAR wszStatus[NLBUPD_NUM_CHAR_WBEMSTATUS_AS_HEX];
  2992. WCHAR wszGenID[NLBUPD_MAX_NUM_CHAR_UINT_AS_DECIMAL];
  2993. WCHAR *pwszTruncatedLog = NULL;
  2994. LPCWSTR pwszArg[4];
  2995. StringCbPrintf(wszStatus, sizeof(wszStatus), L"0x%x", m_CompletionStatus);
  2996. pwszArg[0] = wszStatus;
  2997. StringCbPrintf(wszGenID , sizeof(wszGenID), L"%u" , m_Generation);
  2998. pwszArg[1] = wszGenID;
  2999. pwszArg[2] = m_szNicGuid;
  3000. //
  3001. // TODO: Localize <empty> string
  3002. //
  3003. pwszArg[3] = L"<empty>"; // Initialize it just in case we have nothing to include
  3004. if (ppLog != NULL)
  3005. {
  3006. //
  3007. // The event log supports a max of 32K characters per argument. Take at most this much of ppLog if necessary.
  3008. //
  3009. UINT uiLogLen = wcslen(*ppLog);
  3010. if (uiLogLen > NLBUPD_MAX_EVENTLOG_ARG_LEN)
  3011. {
  3012. TRACE_INFO(
  3013. "NT Event argument max is %d characters and logging data contains %d. Truncate data to max",
  3014. NLBUPD_MAX_EVENTLOG_ARG_LEN,
  3015. uiLogLen
  3016. );
  3017. pwszTruncatedLog = new WCHAR[NLBUPD_MAX_EVENTLOG_ARG_LEN + 1];
  3018. //
  3019. // If memory allocation failed use the pre-initialized string
  3020. //
  3021. if (pwszTruncatedLog != NULL)
  3022. {
  3023. wcsncpy(pwszTruncatedLog, *ppLog, NLBUPD_MAX_EVENTLOG_ARG_LEN);
  3024. pwszTruncatedLog[NLBUPD_MAX_EVENTLOG_ARG_LEN] = L'\0';
  3025. pwszArg[3] = pwszTruncatedLog;
  3026. }
  3027. else
  3028. {
  3029. TRACE_CRIT("Memory allocation to hold truncated loggging data failed. Using the literal: %ls", pwszArg[3]);
  3030. }
  3031. }
  3032. else
  3033. {
  3034. pwszArg[3] = *ppLog;
  3035. }
  3036. }
  3037. //
  3038. // Note that ReportEvent can fail. Ignore return code as we make best effort only
  3039. //
  3040. ReportEvent (g_hEventLog, // Handle to event log
  3041. wEventType, // Event type
  3042. 0, // Category
  3043. MSG_UPDATE_CONFIGURATION_STOP, // MessageId
  3044. NULL, // Security identifier
  3045. 4, // Num args to event string
  3046. 0, // Size of binary data
  3047. pwszArg, // Ptr to args for event string
  3048. NULL); // Ptr to binary data
  3049. if (pwszTruncatedLog != NULL)
  3050. {
  3051. delete [] pwszTruncatedLog;
  3052. }
  3053. TRACE_INFO("<-");
  3054. }
  3055. VOID NlbConfigurationUpdate::ReportStartEvent(
  3056. LPCWSTR szClientDescription
  3057. )
  3058. {
  3059. TRACE_INFO("<-");
  3060. if (g_hEventLog == NULL)
  3061. {
  3062. TRACE_CRIT("Event log not opened or failed to open");
  3063. TRACE_INFO("<-");
  3064. return;
  3065. }
  3066. //
  3067. // Log to this to the system event log, WLBS source
  3068. //
  3069. WCHAR wszGenID[NLBUPD_MAX_NUM_CHAR_UINT_AS_DECIMAL];
  3070. LPCWSTR pwszArg[3];
  3071. pwszArg[0] = szClientDescription;
  3072. if (pwszArg[0] == NULL)
  3073. {
  3074. TRACE_INFO("No client description provided. Using empty string in NT event.");
  3075. pwszArg[0] = L"";
  3076. }
  3077. StringCbPrintf(wszGenID, sizeof(wszGenID), L"%u", m_Generation);
  3078. pwszArg[1] = wszGenID;
  3079. pwszArg[2] = m_szNicGuid;
  3080. //
  3081. // Note that ReportEvent can fail. Ignore return code as we make best effort only
  3082. //
  3083. ReportEvent (g_hEventLog, // Handle to event log
  3084. EVENTLOG_INFORMATION_TYPE, // Event type
  3085. 0, // Category
  3086. MSG_UPDATE_CONFIGURATION_START, // MessageId
  3087. NULL, // Security identifier
  3088. 3, // Num args to event string
  3089. 0, // Size of binary data
  3090. pwszArg, // Ptr to args for event string
  3091. NULL); // Ptr to binary data
  3092. TRACE_INFO("<-");
  3093. }