Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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