Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1469 lines
42 KiB

  1. //***************************************************************************
  2. //
  3. // CONNECT.CPP
  4. //
  5. // Module: NLB Manager
  6. //
  7. // Purpose: Implements ConnectDialog, which is a dialog for connecting
  8. // to a host, extracting and displaying its list of adapters.
  9. //
  10. // Copyright (c)2001 Microsoft Corporation, All Rights Reserved
  11. //
  12. // History:
  13. //
  14. // 07/30/01 JosephJ Created
  15. //
  16. //***************************************************************************
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. #include "private.h"
  20. #include "connect.h"
  21. #include "connect.tmh"
  22. // BEGIN_MESSAGE_MAP( ConnectDialog, CDialog )
  23. BEGIN_MESSAGE_MAP( ConnectDialog, CPropertyPage )
  24. ON_BN_CLICKED(IDC_BUTTON_CONNECT, OnButtonConnect)
  25. ON_WM_HELPINFO()
  26. ON_WM_CONTEXTMENU()
  27. ON_NOTIFY( LVN_ITEMCHANGED, IDC_LIST_INTERFACES, OnSelchanged )
  28. ON_EN_UPDATE(IDC_EDIT_HOSTADDRESS,OnUpdateEditHostAddress)
  29. //
  30. // Other options...
  31. //
  32. // ON_EN_SETFOCUS(IDC_EDIT_HOSTADDRESS,OnSetFocusEditHostAddress)
  33. // ON_WM_ACTIVATE()
  34. // ON_NOTIFY( NM_DBLCLK, IDC_LIST_INTERFACES, OnDoubleClick )
  35. // ON_NOTIFY( LVN_COLUMNCLICK, IDC_LIST_INTERFACES, OnColumnClick )
  36. //
  37. END_MESSAGE_MAP()
  38. //
  39. // Static help-id maps
  40. //
  41. DWORD
  42. ConnectDialog::s_HelpIDs[] =
  43. {
  44. IDC_TEXT_HOSTADDRESS, IDC_EDIT_HOSTADDRESS,
  45. IDC_EDIT_HOSTADDRESS, IDC_EDIT_HOSTADDRESS,
  46. IDC_BUTTON_CONNECT, IDC_BUTTON_CONNECT,
  47. IDC_GROUP_CONNECTION_STATUS, IDC_GROUP_CONNECTION_STATUS,
  48. IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS,
  49. IDC_TEXT_INTERFACES, IDC_LIST_INTERFACES,
  50. IDC_LIST_INTERFACES, IDC_LIST_INTERFACES,
  51. 0, 0
  52. };
  53. DWORD
  54. ConnectDialog::s_ExistingClusterHelpIDs[] =
  55. {
  56. IDC_TEXT_HOSTADDRESS, IDC_EDIT_HOSTADDRESSEX,
  57. IDC_EDIT_HOSTADDRESS, IDC_EDIT_HOSTADDRESSEX,
  58. IDC_BUTTON_CONNECT, IDC_BUTTON_CONNECTEX,
  59. IDC_GROUP_CONNECTION_STATUS, IDC_GROUP_CONNECTION_STATUS,
  60. IDC_TEXT_CONNECTION_STATUS, IDC_TEXT_CONNECTION_STATUS,
  61. IDC_TEXT_INTERFACES, IDC_LIST_INTERFACESEX,
  62. IDC_LIST_INTERFACES, IDC_LIST_INTERFACESEX,
  63. 0, 0
  64. };
  65. VOID zap_slash(LPWSTR sz) // Look for a the first '/' and set it to zero.
  66. {
  67. sz = wcschr(sz, '/');
  68. if (sz!=NULL) *sz=0;
  69. }
  70. ConnectDialog::ConnectDialog(
  71. CPropertySheet *psh,
  72. Document *pDocument,
  73. NLB_EXTENDED_CLUSTER_CONFIGURATION *pNlbCfg,
  74. ENGINEHANDLE *pehInterface, // IN OUT
  75. DlgType type,
  76. CWnd* parent
  77. )
  78. :
  79. // CDialog( IDD, parent )
  80. CPropertyPage(IDD),
  81. m_type(type),
  82. m_fOK(FALSE),
  83. m_pshOwner(psh),
  84. m_pDocument(pDocument),
  85. m_fInterfaceSelected(FALSE),
  86. m_iInterfaceListItem(0),
  87. m_pehSelectedInterfaceId(pehInterface),
  88. m_fSelectedInterfaceIsInCluster(FALSE),
  89. m_pNlbCfg(pNlbCfg),
  90. m_ehHostId(NULL)
  91. {
  92. *m_pehSelectedInterfaceId = NULL;
  93. }
  94. void
  95. ConnectDialog::DoDataExchange( CDataExchange* pDX )
  96. {
  97. // CDialog::DoDataExchange(pDX);
  98. CPropertyPage::DoDataExchange(pDX);
  99. DDX_Control(pDX, IDC_LIST_INTERFACES, interfaceList);
  100. DDX_Control(pDX, IDC_TEXT_CONNECTION_STATUS, connectionStatus);
  101. DDX_Control(pDX, IDC_TEXT_INTERFACES, listHeading);
  102. DDX_Control(pDX, IDC_EDIT_HOSTADDRESS, hostAddress);
  103. //
  104. // Note: the buttons are handled by the ON_BN_CLICKED macro
  105. // above.
  106. //
  107. // DDX_Control(pDX, IDC_BUTTON_CONNECT, buttonConnect);
  108. // DDX_Control(pDX, IDC_BUTTON_CREDENTIALS, credentialsButton);
  109. }
  110. BOOL
  111. ConnectDialog::OnInitDialog()
  112. {
  113. // BOOL fRet = CDialog::OnInitDialog();
  114. BOOL fRet = CPropertyPage::OnInitDialog();
  115. _bstr_t bstrDescription;
  116. _bstr_t bstrListText;
  117. m_fOK = FALSE;
  118. switch(m_type)
  119. {
  120. case DLGTYPE_NEW_CLUSTER:
  121. bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_NEW_HINT);
  122. bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_NEW_LIST_TXT);
  123. break;
  124. case DLGTYPE_EXISTING_CLUSTER:
  125. bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_EXISTING_HINT);
  126. bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_EXISTING_LIST_TXT);
  127. break;
  128. case DLGTYPE_ADD_HOST:
  129. bstrDescription = GETRESOURCEIDSTRING(IDS_CONNECT_ADD_HOST_HINT);
  130. bstrListText = GETRESOURCEIDSTRING(IDS_CONNECT_ADD_HOST_LIST_TXT);
  131. break;
  132. }
  133. //
  134. // Initialize the caption and discription based on the type of
  135. // dialog.
  136. //
  137. {
  138. CWnd *pItem = GetDlgItem(IDC_TEXT_CONNECT_DESCRIPTION);
  139. pItem->SetWindowText(bstrDescription);
  140. pItem = GetDlgItem(IDC_TEXT_INTERFACES);
  141. pItem->SetWindowText(bstrListText);
  142. }
  143. // Initialize the list control
  144. mfn_InitializeListView();
  145. // interfaceList.SetCurSel( 0 );
  146. // ::EnableWindow(::GetDlgItem(m_hWnd, IDC_EDIT_HOSTADDRESS), TRUE );
  147. // ::EnableWindow(::GetDlgItem(m_hWnd, IDC_LIST_INTERFACES), TRUE );
  148. //
  149. // The "Connect" button starts out disabled. It is only enabled
  150. // when the uers types non-whitespace text in the host address
  151. // edit control.
  152. //
  153. ::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, FALSE);
  154. return fRet;
  155. }
  156. BOOL
  157. ConnectDialog::OnHelpInfo (HELPINFO* helpInfo )
  158. {
  159. if( helpInfo->iContextType == HELPINFO_WINDOW )
  160. {
  161. //
  162. // We choose the context-senstive map appropriate to the
  163. // type of dialog (m_type).
  164. //
  165. ULONG_PTR pHelpIds = (ULONG_PTR) s_HelpIDs;
  166. BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER);
  167. if (fExisting)
  168. {
  169. pHelpIds = (ULONG_PTR) s_ExistingClusterHelpIDs;
  170. }
  171. ::WinHelp( static_cast<HWND> ( helpInfo->hItemHandle ),
  172. CVY_CTXT_HELP_FILE,
  173. HELP_WM_HELP,
  174. (ULONG_PTR ) pHelpIds);
  175. }
  176. return TRUE;
  177. }
  178. void
  179. ConnectDialog::OnContextMenu( CWnd* pWnd, CPoint point )
  180. {
  181. ::WinHelp( m_hWnd,
  182. CVY_CTXT_HELP_FILE,
  183. HELP_CONTEXTMENU,
  184. (ULONG_PTR ) s_HelpIDs);
  185. }
  186. void
  187. ConnectDialog::mfn_InitializeListView(void)
  188. //
  189. // Set the columns on the list box based on the type of dialog
  190. //
  191. {
  192. BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER);
  193. RECT rect;
  194. INT colWidth;
  195. interfaceList.GetClientRect(&rect);
  196. colWidth = (rect.right - rect.left)/4;
  197. if (fExisting)
  198. {
  199. //
  200. // The interface list is that of interfaces already bound to NLB.
  201. // we display the cluster dnsname and ip first, then adapter name.
  202. //
  203. interfaceList.InsertColumn(
  204. 0,
  205. GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERNAME),
  206. LVCFMT_LEFT,
  207. colWidth);
  208. interfaceList.InsertColumn(
  209. 1,
  210. GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERIP),
  211. LVCFMT_LEFT,
  212. colWidth);
  213. interfaceList.InsertColumn(
  214. 2,
  215. GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFNAME),
  216. LVCFMT_LEFT,
  217. colWidth * 2);
  218. }
  219. else
  220. {
  221. //
  222. // The interface list is that of interfaces NOT bound to NLB.
  223. // We display the current IP address first, then adapter name.
  224. //
  225. interfaceList.InsertColumn(
  226. 0,
  227. GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFNAME),
  228. LVCFMT_LEFT,
  229. colWidth * 2);
  230. interfaceList.InsertColumn(
  231. 1,
  232. GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_IFIP),
  233. LVCFMT_LEFT,
  234. colWidth);
  235. interfaceList.InsertColumn(
  236. 2,
  237. GETRESOURCEIDSTRING( IDS_HEADER_IFLIST_CLUSTERIP),
  238. LVCFMT_LEFT,
  239. colWidth);
  240. }
  241. //
  242. // Allow entire row to be selected.
  243. //
  244. interfaceList.SetExtendedStyle(
  245. interfaceList.GetExtendedStyle() | LVS_EX_FULLROWSELECT );
  246. }
  247. void
  248. ConnectDialog::mfn_InsertBoundInterface(
  249. ENGINEHANDLE ehInterfaceId,
  250. LPCWSTR szClusterName,
  251. LPCWSTR szClusterIp,
  252. LPCWSTR szInterfaceName
  253. )
  254. {
  255. if (szClusterName == NULL)
  256. {
  257. szClusterName = L"";
  258. }
  259. if (szClusterIp == NULL)
  260. {
  261. szClusterIp = L"";
  262. }
  263. if (szInterfaceName == NULL)
  264. {
  265. szInterfaceName = L""; // TODO: localize
  266. }
  267. int iRet = interfaceList.InsertItem(
  268. LVIF_TEXT | LVIF_PARAM, // nMask
  269. 0, // nItem,
  270. szClusterName, // lpszItem
  271. 0, // nState (unused)
  272. 0, // nStateMask (unused)
  273. 0, // nImage (unused)
  274. (LPARAM) ehInterfaceId // lParam
  275. );
  276. // interfaceList.InsertItem(0, szClusterName);
  277. interfaceList.SetItem(
  278. 0, // nItem
  279. 1,// nSubItem
  280. LVIF_TEXT, // nMask
  281. szClusterIp, // lpszItem
  282. 0, // nImage
  283. 0, // nState
  284. 0, // nStateMask
  285. 0 // lParam
  286. );
  287. interfaceList.SetItem(
  288. 0, // nItem
  289. 2,// nSubItem
  290. LVIF_TEXT, // nMask
  291. szInterfaceName, // lpszItem
  292. 0, // nImage
  293. 0, // nState
  294. 0, // nStateMask
  295. 0 // lParam
  296. );
  297. }
  298. void
  299. ConnectDialog::mfn_InsertInterface(
  300. ENGINEHANDLE ehInterfaceId,
  301. LPCWSTR szInterfaceIp,
  302. LPCWSTR szInterfaceName,
  303. LPCWSTR szClusterIp
  304. )
  305. {
  306. if (szInterfaceIp == NULL)
  307. {
  308. szInterfaceIp = L"";
  309. }
  310. if (szInterfaceName == NULL)
  311. {
  312. szInterfaceName = L""; // TODO: localize
  313. }
  314. if (szClusterIp == NULL)
  315. {
  316. szClusterIp = L"";
  317. }
  318. int iRet = interfaceList.InsertItem(
  319. LVIF_TEXT | LVIF_PARAM, // nMask
  320. 0, // nItem,
  321. szInterfaceName, // lpszItem
  322. 0, // nState (unused)
  323. 0, // nStateMask (unused)
  324. 0, // nImage (unused)
  325. (LPARAM) ehInterfaceId // lParam
  326. );
  327. // interfaceList.InsertItem(0, szInterfaceIp);
  328. interfaceList.SetItem(
  329. 0, // nItem
  330. 1,// nSubItem
  331. LVIF_TEXT, // nMask
  332. szInterfaceIp, // lpszItem
  333. 0, // nImage
  334. 0, // nState
  335. 0, // nStateMask
  336. 0 // lParam
  337. );
  338. // interfaceList.InsertItem(0, szInterfaceIp);
  339. interfaceList.SetItem(
  340. 0, // nItem
  341. 2,// nSubItem
  342. LVIF_TEXT, // nMask
  343. szClusterIp, // lpszItem
  344. 0, // nImage
  345. 0, // nState
  346. 0, // nStateMask
  347. 0 // lParam
  348. );
  349. // interfaceList.SetCurSel( 0 );
  350. }
  351. void ConnectDialog::OnOK()
  352. {
  353. // CDialog::OnOK();
  354. CPropertyPage::OnOK();
  355. }
  356. _bstr_t g_hostName;
  357. void ConnectDialog::OnButtonConnect()
  358. /*
  359. User has clicked the "Connect" button.
  360. 1. (For now) If empty string, do nothing. Later we'll disable/enable.
  361. 2. Switch cursor to hourglass, connect, switch back from hourglass.
  362. */
  363. {
  364. BOOL fExisting = (m_type == DLGTYPE_EXISTING_CLUSTER);
  365. BOOL fRet;
  366. #define MAX_HOST_ADDRESS_LENGTH 256
  367. WCHAR szHostAddress[MAX_HOST_ADDRESS_LENGTH+1];
  368. ENGINEHANDLE ehHostId;
  369. CHostSpec hSpec;
  370. BOOL fNicsAvailable = FALSE;
  371. NLBERROR err;
  372. _bstr_t bstrUserName;
  373. _bstr_t bstrPassword;
  374. _bstr_t bstrConnectionStatus;
  375. //
  376. // Get the connection string. If empty, we simply return.
  377. //
  378. {
  379. fRet = GetDlgItemText(
  380. IDC_EDIT_HOSTADDRESS,
  381. szHostAddress,
  382. MAX_HOST_ADDRESS_LENGTH
  383. );
  384. if (!fRet)
  385. {
  386. goto end;
  387. }
  388. //
  389. // Clean out trailing whitespace..
  390. //
  391. {
  392. LPWSTR sz = (szHostAddress+wcslen(szHostAddress))-1;
  393. while (sz >= szHostAddress)
  394. {
  395. WCHAR c = *sz;
  396. if (c == ' ' || c == '\t')
  397. {
  398. *sz = 0;
  399. }
  400. else
  401. {
  402. break;
  403. }
  404. sz--;
  405. }
  406. }
  407. if (szHostAddress[0] == 0)
  408. {
  409. goto end;
  410. }
  411. }
  412. //
  413. // Let's see if we have any record of this connection string -- if so
  414. // we use that record's username and password as the first guest.
  415. //
  416. err = gEngine.LookupConnectionInfo(
  417. szHostAddress,
  418. REF bstrUserName,
  419. REF bstrPassword
  420. );
  421. if (NLBFAILED(err))
  422. {
  423. //
  424. // Nope -- let's use default credentials...
  425. //
  426. m_pDocument->getDefaultCredentials(REF bstrUserName, REF bstrPassword);
  427. }
  428. //
  429. // Set status
  430. //
  431. {
  432. bstrConnectionStatus = GETRESOURCEIDSTRING(IDS_CONNECT_STATUS_CONNECTING);
  433. SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, (LPCWSTR) bstrConnectionStatus);
  434. }
  435. //
  436. // Clear the list of interfaces.
  437. //
  438. interfaceList.DeleteAllItems();
  439. //
  440. // These two buffers must be defined outside the loop below because
  441. // ConnInfo points to them across multiple iterations.
  442. // We initialize them to the user-name and password we obtained above...
  443. //
  444. WCHAR rgUserName[CREDUI_MAX_USERNAME_LENGTH+1];
  445. WCHAR rgPassword[MAX_ENCRYPTED_PASSWORD_LENGTH];
  446. LPCWSTR szName = (LPCWSTR) bstrUserName;
  447. LPCWSTR szPassword = (LPCWSTR) bstrPassword;
  448. if (szName == NULL)
  449. {
  450. szName = L"";
  451. }
  452. if (szPassword == NULL)
  453. {
  454. szPassword = L"";
  455. }
  456. ARRAYSTRCPY(rgUserName, szName);
  457. ARRAYSTRCPY(rgPassword, szPassword);
  458. while (1)
  459. {
  460. WMI_CONNECTION_INFO ConnInfo;
  461. CLocalLogger logger;
  462. ZeroMemory(&ConnInfo, sizeof(ConnInfo));
  463. ConnInfo.szMachine = szHostAddress;
  464. if (*rgUserName == 0)
  465. {
  466. // Use default creds ...
  467. ConnInfo.szUserName = NULL;
  468. ConnInfo.szPassword = NULL;
  469. }
  470. else
  471. {
  472. ConnInfo.szUserName = rgUserName;
  473. ConnInfo.szPassword = rgPassword;
  474. }
  475. //
  476. // ACTUALLY CONNECT TO THE HOST
  477. //
  478. BeginWaitCursor();
  479. // TRUE 2nd param says overwrite the connection info for this host
  480. // if the connect succeeds.
  481. err = gEngine.ConnectToHost(&ConnInfo, TRUE, REF ehHostId, REF bstrConnectionStatus);
  482. EndWaitCursor();
  483. if (err != NLBERR_ACCESS_DENIED)
  484. {
  485. break;
  486. }
  487. //
  488. // We got an access-denied --
  489. // Bring ui UI prompting for new username and password.
  490. //
  491. _bstr_t bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_CONNECT);
  492. logger.Log(IDS_SPECIFY_MACHINE_CREDS, ConnInfo.szMachine);
  493. fRet = PromptForEncryptedCreds(
  494. m_hWnd,
  495. (LPCWSTR) bstrCaption,
  496. logger.GetStringSafe(),
  497. rgUserName,
  498. ASIZE(rgUserName),
  499. rgPassword,
  500. ASIZE(rgPassword)
  501. );
  502. if (!fRet)
  503. {
  504. err = NLBERR_CANCELLED;
  505. break;
  506. }
  507. } // while (1)
  508. if (err == NLBERR_OK)
  509. {
  510. //
  511. // Set status
  512. //
  513. bstrConnectionStatus = GETRESOURCEIDSTRING(IDS_CONNECT_STATUS_CONNECTED);
  514. SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, (LPCWSTR) bstrConnectionStatus);
  515. //
  516. // Clear list of all items
  517. //
  518. interfaceList.DeleteAllItems();
  519. err = gEngine.GetHostSpec(ehHostId, REF hSpec);
  520. if (NLBFAILED(err))
  521. {
  522. goto end;
  523. }
  524. //
  525. // Extract list of interfaces
  526. //
  527. for( int i = 0; i < hSpec.m_ehInterfaceIdList.size(); ++i )
  528. {
  529. ENGINEHANDLE ehIID = hSpec.m_ehInterfaceIdList[i];
  530. CInterfaceSpec iSpec;
  531. err = gEngine.GetInterfaceSpec(ehIID, REF iSpec);
  532. if (err == NLBERR_OK)
  533. {
  534. //
  535. // Get interfaces.
  536. //
  537. // szFriendlyName
  538. // szClusterIp (NULL if nlb not bound)
  539. // szClusterName (NULL if nlb not bound)
  540. // szFirstIp (first ip bound to NLB)
  541. //
  542. WBEMSTATUS wStat;
  543. LPWSTR szFriendlyName = NULL;
  544. LPWSTR szClusterIp = NULL;
  545. LPWSTR szClusterName = NULL;
  546. LPWSTR *pszNetworkAddresses = NULL;
  547. BOOL fNlbBound = FALSE;
  548. UINT NumAddresses=0;
  549. LPWSTR szFirstNetworkAddress = NULL;
  550. wStat = iSpec.m_NlbCfg.GetFriendlyName(&szFriendlyName);
  551. if (FAILED(wStat)) szFriendlyName = NULL;
  552. wStat = iSpec.m_NlbCfg.GetNetworkAddresses(
  553. &pszNetworkAddresses,
  554. &NumAddresses
  555. );
  556. if (FAILED(wStat))
  557. {
  558. pszNetworkAddresses = NULL;
  559. NumAddresses = 0;
  560. }
  561. else if (NumAddresses != 0)
  562. {
  563. szFirstNetworkAddress = pszNetworkAddresses[0];
  564. zap_slash(szFirstNetworkAddress); // zap the /
  565. }
  566. if (iSpec.m_NlbCfg.IsNlbBound())
  567. {
  568. fNlbBound = TRUE;
  569. if (iSpec.m_NlbCfg.IsValidNlbConfig())
  570. {
  571. wStat = iSpec.m_NlbCfg.GetClusterNetworkAddress(
  572. &szClusterIp
  573. );
  574. if (FAILED(wStat))
  575. {
  576. szClusterIp = NULL;
  577. }
  578. else if (szClusterIp!=NULL)
  579. {
  580. zap_slash(szClusterIp);
  581. }
  582. wStat = iSpec.m_NlbCfg.GetClusterName(
  583. &szClusterName
  584. );
  585. if (FAILED(wStat))
  586. {
  587. szClusterName = NULL;
  588. }
  589. }
  590. }
  591. if (fExisting && fNlbBound)
  592. {
  593. fNicsAvailable = TRUE;
  594. mfn_InsertBoundInterface(
  595. ehIID,
  596. szClusterName,
  597. szClusterIp,
  598. szFriendlyName
  599. );
  600. }
  601. else if (!fExisting)
  602. {
  603. fNicsAvailable = TRUE;
  604. mfn_InsertInterface(
  605. ehIID,
  606. szFirstNetworkAddress,
  607. szFriendlyName,
  608. szClusterIp
  609. );
  610. }
  611. delete szFriendlyName;
  612. delete szClusterIp;
  613. delete szClusterName;
  614. delete pszNetworkAddresses;
  615. }
  616. }
  617. if (!fNicsAvailable)
  618. {
  619. //
  620. // There are no NICs on this host on which NLB may be installed.
  621. //
  622. if (fExisting)
  623. {
  624. MessageBox(
  625. GETRESOURCEIDSTRING( IDS_CONNECT_NO_NICS_EXISTING_CLUSTER),
  626. GETRESOURCEIDSTRING( IDS_CONNECT_SELECT_NICS_ERROR ),
  627. MB_ICONSTOP | MB_OK
  628. );
  629. }
  630. else
  631. {
  632. MessageBox(
  633. GETRESOURCEIDSTRING( IDS_CONNECT_NO_NICS_NEW_CLUSTER ),
  634. GETRESOURCEIDSTRING( IDS_CONNECT_SELECT_NICS_ERROR ),
  635. MB_ICONSTOP | MB_OK
  636. );
  637. }
  638. }
  639. else
  640. {
  641. m_ehHostId = ehHostId;
  642. m_MachineName = hSpec.m_MachineName; // machine name.
  643. m_fInterfaceSelected = FALSE;
  644. m_iInterfaceListItem = 0;
  645. *m_pehSelectedInterfaceId = NULL;
  646. m_fSelectedInterfaceIsInCluster = FALSE;
  647. if (fExisting)
  648. {
  649. //
  650. // We're asked to pick an existing cluster.
  651. // Let's select the first interface bound to NLB
  652. //
  653. mfn_SelectInterfaceIfAlreadyInCluster(
  654. NULL
  655. );
  656. }
  657. else
  658. {
  659. //
  660. // We're asked to add a host to a cluster.
  661. //
  662. // Now we check if an interfaces is already part of
  663. // the cluster. If so we select it and prevent the user from
  664. // subsequently changing this selection. Furthermore, we use
  665. // the host-specific settings that already exist on that
  666. // interface.
  667. //
  668. mfn_SelectInterfaceIfAlreadyInCluster(
  669. m_pNlbCfg->NlbParams.cl_ip_addr
  670. );
  671. //
  672. // Let's apply the selected interface's information.
  673. //
  674. mfn_ApplySelectedInterfaceConfiguration();
  675. }
  676. }
  677. }
  678. else
  679. {
  680. //
  681. // Error connecting.
  682. //
  683. LPCWSTR szErr = (LPCWSTR)bstrConnectionStatus;
  684. if (szErr == NULL)
  685. {
  686. szErr = L"";
  687. }
  688. SetDlgItemText(IDC_TEXT_CONNECTION_STATUS, szErr);
  689. }
  690. end:
  691. return;
  692. }
  693. void ConnectDialog::OnSelchanged(NMHDR * pNotifyStruct, LRESULT * result )
  694. /*
  695. A listbox item has been selected.
  696. */
  697. {
  698. POSITION pos = interfaceList.GetFirstSelectedItemPosition();
  699. UINT WizardFlags = 0;
  700. int index = -1;
  701. if( pos != NULL )
  702. {
  703. index = interfaceList.GetNextSelectedItem( pos );
  704. }
  705. if (m_type == DLGTYPE_NEW_CLUSTER)
  706. {
  707. //
  708. // We're not the first, so we enable the back button.
  709. //
  710. WizardFlags = PSWIZB_BACK;
  711. }
  712. if (m_fInterfaceSelected && index == m_iInterfaceListItem)
  713. {
  714. //
  715. // No change in selection; Nothing to do..
  716. // In fact we do NOT want to change the settings because the user
  717. // may have made some host-specific changes like change the
  718. // dedicated IP.
  719. //
  720. goto end;
  721. }
  722. if (m_fSelectedInterfaceIsInCluster)
  723. {
  724. BOOL fRet = FALSE;
  725. //
  726. // we don't allow a change in selection -- move back to
  727. // selecting the cluster ip.
  728. fRet = interfaceList.SetItemState(
  729. m_iInterfaceListItem,
  730. LVIS_FOCUSED | LVIS_SELECTED, // nState
  731. LVIS_FOCUSED | LVIS_SELECTED // nMask
  732. );
  733. if (fRet)
  734. {
  735. goto end;
  736. }
  737. }
  738. //
  739. // We are getting here ONLY if (a) there has been a change in the selection
  740. // and (b) the selected interface is NOT already in the cluster.
  741. // We'll set the dedicated ip and subnet mask to be the first
  742. // address/subnet bound to the adapter.
  743. //
  744. // If adapter is configured for DHCP, we leave the dedicated IP field
  745. // blank.
  746. //
  747. if (index != -1)
  748. {
  749. //
  750. // Update m_pNlbCfg appropriately...
  751. //
  752. ENGINEHANDLE ehIID = NULL;
  753. ehIID = (ENGINEHANDLE) interfaceList.GetItemData(index);
  754. if (ehIID == NULL)
  755. {
  756. TRACE_CRIT("%!FUNC! could not get ehIID for index %lu", index);
  757. goto end;
  758. }
  759. else
  760. {
  761. //
  762. // Update the saved-away "selected interface" ID.
  763. //
  764. ENGINEHANDLE ehOldId = *m_pehSelectedInterfaceId;
  765. *m_pehSelectedInterfaceId = ehIID;
  766. m_fInterfaceSelected = TRUE;
  767. m_iInterfaceListItem = index;
  768. //
  769. // TODO: duplicate code
  770. //
  771. CInterfaceSpec iSpec;
  772. WBEMSTATUS wStat;
  773. LPWSTR szFriendlyName = NULL;
  774. LPWSTR szClusterIp = NULL;
  775. LPWSTR szClusterName = NULL;
  776. LPWSTR *pszNetworkAddresses = NULL;
  777. UINT NumAddresses=0;
  778. LPWSTR szFirstNetworkAddress = NULL;
  779. NLBERROR err;
  780. err = gEngine.GetInterfaceSpec(ehIID, REF iSpec);
  781. if (!NLBOK(err))
  782. {
  783. TRACE_CRIT("%!FUNC! could not get iSpec for ehSpec 0x%lx", ehIID);
  784. goto end;
  785. }
  786. wStat = iSpec.m_NlbCfg.GetFriendlyName(&szFriendlyName);
  787. if (FAILED(wStat)) szFriendlyName = NULL;
  788. wStat = iSpec.m_NlbCfg.GetNetworkAddresses(
  789. &pszNetworkAddresses,
  790. &NumAddresses
  791. );
  792. if (FAILED(wStat))
  793. {
  794. pszNetworkAddresses = NULL;
  795. NumAddresses = 0;
  796. }
  797. else if (NumAddresses != 0)
  798. {
  799. szFirstNetworkAddress = pszNetworkAddresses[0];
  800. }
  801. m_pNlbCfg->SetFriendlyName(szFriendlyName);
  802. if (iSpec.m_NlbCfg.IsNlbBound())
  803. {
  804. if (m_type != DLGTYPE_EXISTING_CLUSTER)
  805. {
  806. //
  807. // The user has selected an interface that is bound with
  808. // some other IP address -- we should put up a message box
  809. // here or maybe later, on kill-active.
  810. //
  811. }
  812. }
  813. //
  814. // Set defaults for dedicatedip -- the first network address on
  815. // the NIC, but ONLY if this address is not a cluster IP address.
  816. //
  817. if (szFirstNetworkAddress != NULL)
  818. {
  819. LPCWSTR szAddress = szFirstNetworkAddress;
  820. WCHAR rgIp[WLBS_MAX_CL_IP_ADDR+1];
  821. LPCWSTR pSlash = wcsrchr(szAddress, (int) '/');
  822. if (pSlash != NULL)
  823. {
  824. UINT len = (UINT) (pSlash - szAddress);
  825. if (len < WLBS_MAX_CL_IP_ADDR)
  826. {
  827. CopyMemory(rgIp, szAddress, len*sizeof(WCHAR));
  828. rgIp[len] = 0;
  829. szAddress = rgIp;
  830. }
  831. }
  832. if (!_wcsicmp(m_pNlbCfg->NlbParams.cl_ip_addr, szAddress))
  833. {
  834. szFirstNetworkAddress = NULL;
  835. }
  836. if (iSpec.m_NlbCfg.fDHCP)
  837. {
  838. //
  839. // The adapter is currently under DHCP control. We don't
  840. // want to suggest that we use the current IP address
  841. // as the static DIP!
  842. //
  843. szFirstNetworkAddress = NULL;
  844. }
  845. //
  846. // TODO -- check also if this address conflicts with the
  847. // additional VIPS.
  848. //
  849. }
  850. m_pNlbCfg->SetDedicatedNetworkAddress(szFirstNetworkAddress); // NULL ok
  851. delete szFriendlyName;
  852. delete szClusterIp;
  853. delete szClusterName;
  854. delete pszNetworkAddresses;
  855. }
  856. if (m_type == DLGTYPE_EXISTING_CLUSTER)
  857. {
  858. // we're last page, so enable finish.
  859. WizardFlags |= PSWIZB_FINISH;
  860. }
  861. else
  862. {
  863. // we're not the last page, so enable next.
  864. WizardFlags |= PSWIZB_NEXT;
  865. }
  866. }
  867. m_pshOwner->SetWizardButtons(WizardFlags);
  868. end:
  869. return;
  870. }
  871. BOOL
  872. ConnectDialog::OnSetActive()
  873. {
  874. BOOL fRet = CPropertyPage::OnSetActive();
  875. if (fRet)
  876. {
  877. UINT WizardFlags = 0;
  878. if (m_type == DLGTYPE_NEW_CLUSTER)
  879. {
  880. WizardFlags |= PSWIZB_BACK; // we're not the first page.
  881. }
  882. if (m_fInterfaceSelected)
  883. {
  884. WizardFlags |= PSWIZB_NEXT; // Ok to continue.
  885. }
  886. m_pshOwner->SetWizardButtons(WizardFlags);
  887. }
  888. return fRet;
  889. }
  890. LRESULT ConnectDialog::OnWizardNext()
  891. {
  892. LRESULT lRet = 0;
  893. TRACE_INFO("%!FUNC! ->");
  894. lRet = CPropertyPage::OnWizardNext();
  895. if (lRet != 0)
  896. {
  897. goto end;
  898. }
  899. if (mfn_ValidateData())
  900. {
  901. lRet = 0;
  902. }
  903. else
  904. {
  905. lRet = -1; // validation failed -- stay in current page.
  906. }
  907. end:
  908. TRACE_INFO("%!FUNC! <- returns %lu", lRet);
  909. return lRet;
  910. }
  911. void ConnectDialog::OnUpdateEditHostAddress()
  912. {
  913. //
  914. // This gets called when the user has made changes to the connect-to-host
  915. // edit control.
  916. //
  917. //
  918. // We get the latest text -- if null or just blanks, we
  919. // disable the connect window.
  920. // Else we enable the connect window.
  921. //
  922. #define BUF_SIZ 32
  923. WCHAR rgBuf[BUF_SIZ+1];
  924. int l = hostAddress.GetWindowText(rgBuf, BUF_SIZ);
  925. if (l == 0 || _wcsspnp(rgBuf, L" \t")==NULL)
  926. {
  927. //
  928. // Empty string or entirely whitespace.
  929. //
  930. ::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, FALSE);
  931. }
  932. else
  933. {
  934. //
  935. // Non-empty string -- enable button and make it the default.
  936. //
  937. ::EnableWindow (GetDlgItem(IDC_BUTTON_CONNECT)->m_hWnd, TRUE);
  938. this->SetDefID(IDC_BUTTON_CONNECT);
  939. }
  940. }
  941. void
  942. ConnectDialog::mfn_SelectInterfaceIfAlreadyInCluster(LPCWSTR szClusterIp)
  943. /*
  944. Check the list of interfaces to see if there exists an interface
  945. which is is already part of the cluster -- i.e., it is bound and it's
  946. cluster ip matches the one in m_pNlbCfg.
  947. If so, we select it, and furthermore, prevent the user from selecting
  948. any other interface.
  949. */
  950. {
  951. ENGINEHANDLE ehInterfaceId = NULL;
  952. NLBERROR nerr;
  953. UINT NumFound = 0;
  954. nerr = gEngine.FindInterfaceOnHostByClusterIp(
  955. m_ehHostId,
  956. //m_pNlbCfg->NlbParams.cl_ip_addr,
  957. szClusterIp,
  958. REF ehInterfaceId,
  959. REF NumFound
  960. );
  961. if (!NLBOK(nerr))
  962. {
  963. // not found or bad host id or some other err -- we don't care which.
  964. goto end;
  965. }
  966. //
  967. // Find the list item with this ehInterfaceId.
  968. //
  969. {
  970. LVFINDINFO Info;
  971. int nItem;
  972. ZeroMemory(&Info, sizeof(Info));
  973. Info.flags = LVFI_PARAM;
  974. Info.lParam = ehInterfaceId;
  975. nItem = interfaceList.FindItem(&Info);
  976. if (nItem != -1)
  977. {
  978. BOOL fRet;
  979. UINT WizardFlags = 0;
  980. //
  981. // Found it! -- select it and use it's host-specific information
  982. //
  983. m_fInterfaceSelected = TRUE;
  984. m_iInterfaceListItem = nItem;
  985. *m_pehSelectedInterfaceId = ehInterfaceId;
  986. if (NumFound == 1)
  987. {
  988. m_fSelectedInterfaceIsInCluster = TRUE;
  989. }
  990. fRet = interfaceList.SetItemState(
  991. nItem,
  992. LVIS_FOCUSED | LVIS_SELECTED, // nState
  993. LVIS_FOCUSED | LVIS_SELECTED // nMask
  994. );
  995. if (m_type == DLGTYPE_NEW_CLUSTER)
  996. {
  997. WizardFlags |= PSWIZB_BACK; // we're not the first page.
  998. }
  999. if (m_type == DLGTYPE_EXISTING_CLUSTER)
  1000. {
  1001. WizardFlags |= PSWIZB_FINISH;
  1002. }
  1003. else
  1004. {
  1005. WizardFlags |= PSWIZB_NEXT;
  1006. }
  1007. // TODO: consider adding finish in add-host case here.
  1008. m_pshOwner->SetWizardButtons(WizardFlags);
  1009. }
  1010. }
  1011. //
  1012. // Go through and set all other list items to have a gray background.
  1013. //
  1014. end:
  1015. return;
  1016. }
  1017. void
  1018. ConnectDialog::mfn_ApplySelectedInterfaceConfiguration(void)
  1019. {
  1020. ENGINEHANDLE ehIID = *m_pehSelectedInterfaceId;
  1021. CInterfaceSpec iSpec;
  1022. WBEMSTATUS wStat;
  1023. BOOL fNlbBound = FALSE;
  1024. NLBERROR err;
  1025. NLB_EXTENDED_CLUSTER_CONFIGURATION TmpConfig;
  1026. if (!m_fSelectedInterfaceIsInCluster) goto end;
  1027. err = gEngine.GetInterfaceSpec(ehIID, REF iSpec);
  1028. if (!NLBOK(err))
  1029. {
  1030. TRACE_CRIT("%!FUNC! could not get iSpec for ehSpec 0x%lx", ehIID);
  1031. goto end;
  1032. }
  1033. if (!iSpec.m_NlbCfg.IsValidNlbConfig())
  1034. {
  1035. // can't trust NLB config info on this interface.
  1036. goto end;
  1037. }
  1038. //
  1039. // We'll make a copy of the interface's config and apply the cluster
  1040. // properties to it and then copy this copy over to the cluster properties.
  1041. //
  1042. wStat = TmpConfig.Update(&iSpec.m_NlbCfg);
  1043. if (FAILED(wStat))
  1044. {
  1045. TRACE_CRIT("%!FUNC! could not perform an internal copy!");
  1046. goto end;
  1047. }
  1048. err = gEngine.ApplyClusterWideConfiguration(REF *m_pNlbCfg, TmpConfig);
  1049. if (!NLBOK(err))
  1050. {
  1051. goto end;
  1052. }
  1053. wStat = m_pNlbCfg->Update(&TmpConfig);
  1054. if (FAILED(wStat))
  1055. {
  1056. goto end;
  1057. }
  1058. // Fall through.
  1059. end:
  1060. return;
  1061. }
  1062. BOOL
  1063. ConnectDialog::mfn_ValidateData()
  1064. /*
  1065. Make sure the interface is not already part of a different cluster,
  1066. or other problem (eg we're connnecting to this interface and it's DHCP)
  1067. NewCluster:
  1068. ExistingCluster:
  1069. AddHost:
  1070. In all cases, we fail if pISpec already has an ehCluster associated with
  1071. it. Put up a message box with the associated ehCluster.
  1072. */
  1073. {
  1074. BOOL fRet = FALSE;
  1075. NLBERROR nerr;
  1076. ENGINEHANDLE ehHost = NULL;
  1077. ENGINEHANDLE ehCluster = NULL;
  1078. _bstr_t bstrFriendlyName;
  1079. _bstr_t bstrDisplayName;
  1080. _bstr_t bstrHostName;
  1081. LPCWSTR szFriendlyName = NULL;
  1082. BOOL fOkCancel=FALSE;
  1083. CLocalLogger msgLog;
  1084. _bstr_t bstrCaption;
  1085. if (*m_pehSelectedInterfaceId == NULL)
  1086. {
  1087. //
  1088. // We shouldn't get here because the "Next" button is only enabled
  1089. // if there IS a selection; however we deal with this case anyway.
  1090. //
  1091. // bstrCaption = L"No interface selected";
  1092. bstrCaption = GETRESOURCEIDSTRING (IDS_CONNECT_NO_INTERFACE_SELECTED);
  1093. msgLog.Log(IDS_CONNECT_SELECT_AN_INTERFACE);
  1094. goto end;
  1095. }
  1096. nerr = gEngine.GetInterfaceIdentification(
  1097. *m_pehSelectedInterfaceId,
  1098. REF ehHost,
  1099. REF ehCluster,
  1100. REF bstrFriendlyName,
  1101. REF bstrDisplayName,
  1102. REF bstrHostName
  1103. );
  1104. if (NLBFAILED(nerr))
  1105. {
  1106. //
  1107. // This indicates an internal error like a bad handle.
  1108. //
  1109. bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
  1110. // szCaption = L"Unable to proceed";
  1111. msgLog.Log(IDS_CONNECT_UNABLE_TO_PROCEEED_INTERNAL);
  1112. // szMessage = L"Unable to proceed due to an internal error.";
  1113. goto end;
  1114. }
  1115. szFriendlyName = (LPCWSTR) bstrFriendlyName;
  1116. if (szFriendlyName == NULL)
  1117. {
  1118. szFriendlyName = L"";
  1119. }
  1120. if (ehCluster == NULL)
  1121. {
  1122. //
  1123. // Should be good to go.
  1124. // TODO -- if interface already bound AND m_type is NOT
  1125. // DLGTYPE_EXISTING_CLUSTER, we should ask if user wants to
  1126. // clobber the existing interface.
  1127. //
  1128. if (m_type != DLGTYPE_EXISTING_CLUSTER)
  1129. {
  1130. CInterfaceSpec iSpec;
  1131. nerr = gEngine.GetInterfaceSpec(*m_pehSelectedInterfaceId, REF iSpec);
  1132. if (nerr == NLBERR_OK)
  1133. {
  1134. //
  1135. // Check if we're connected to this NIC, and
  1136. // the NIC is DHCP, so we're not going to be able to
  1137. // keep the connected IP address.
  1138. //
  1139. // If so, we cannot proceed.
  1140. //
  1141. {
  1142. ENGINEHANDLE ehConnectionIF = NULL;
  1143. _bstr_t bstrConnectionString;
  1144. UINT uConnectionIp = 0;
  1145. nerr = gEngine.GetHostConnectionInformation(
  1146. ehHost,
  1147. REF ehConnectionIF,
  1148. REF bstrConnectionString,
  1149. REF uConnectionIp
  1150. );
  1151. if (NLBFAILED(nerr))
  1152. {
  1153. TRACE_CRIT(L"%!FUNC! gEngine.GetHostConnectionInformation fails!");
  1154. //
  1155. // We'll plow on...
  1156. //
  1157. ehConnectionIF = NULL;
  1158. uConnectionIp = 0;
  1159. }
  1160. if (ehConnectionIF == *m_pehSelectedInterfaceId)
  1161. {
  1162. //
  1163. // The selected interface is also the interface that we
  1164. // are connecting over...
  1165. //
  1166. if (iSpec.m_NlbCfg.fDHCP)
  1167. {
  1168. //
  1169. // Ouch -- it's also DHCP. We can't allow this...
  1170. //
  1171. msgLog.Log(IDS_CANT_USE_DHCP_NIC_MSG);
  1172. bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
  1173. fRet = FALSE;
  1174. goto end;
  1175. }
  1176. }
  1177. }
  1178. //
  1179. // Check if nlb is bound and if so, if it's cluster ip address
  1180. // is different.
  1181. //
  1182. if (iSpec.m_NlbCfg.IsValidNlbConfig())
  1183. {
  1184. //
  1185. // Hmm... interface is already bound to NLB.
  1186. // Let's see if the cluster IP address is different...
  1187. //
  1188. LPCWSTR szClusterIp = m_pNlbCfg->NlbParams.cl_ip_addr;
  1189. LPCWSTR szIfClusterIp = iSpec.m_NlbCfg.NlbParams.cl_ip_addr;
  1190. if ( szIfClusterIp[0]!=0
  1191. && (_wcsspnp(szIfClusterIp, L".0")!=NULL))
  1192. {
  1193. // non-blank cluster Ip address
  1194. if (wcscmp(szClusterIp, szIfClusterIp))
  1195. {
  1196. //
  1197. // IPs don't match! Put up message box..
  1198. //
  1199. msgLog.Log(
  1200. IDS_CONNECT_MSG_IF_ALREADY_BOUND,
  1201. szFriendlyName,
  1202. iSpec.m_NlbCfg.NlbParams.domain_name,
  1203. szIfClusterIp
  1204. );
  1205. bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_CAP_IF_ALREADY_BOUND);
  1206. // szCaption = L"Interface already configured for NLB";
  1207. fOkCancel=TRUE;
  1208. fRet = FALSE;
  1209. goto end;
  1210. }
  1211. }
  1212. }
  1213. }
  1214. }
  1215. fRet = TRUE;
  1216. }
  1217. else
  1218. {
  1219. _bstr_t bstrClusterDescription;
  1220. _bstr_t bstrIpAddress;
  1221. _bstr_t bstrDomainName;
  1222. LPCWSTR szClusterDescription = NULL;
  1223. nerr = gEngine.GetClusterIdentification(
  1224. ehCluster,
  1225. REF bstrIpAddress,
  1226. REF bstrDomainName,
  1227. REF bstrDisplayName
  1228. );
  1229. if (FAILED(nerr))
  1230. {
  1231. TRACE_CRIT(L"%!FUNC!: Error 0x%lx getting ehCluster 0x%lx identification\n",
  1232. nerr, ehCluster);
  1233. bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
  1234. // szCaption = L"Unable to proceed";
  1235. msgLog.Log(IDS_CONNECT_UNABLE_TO_PROCEEED_INTERNAL);
  1236. // szMessage = L"Unable to proceed due to an internal error.";
  1237. goto end;
  1238. }
  1239. szClusterDescription = bstrDisplayName;
  1240. if (szClusterDescription==NULL)
  1241. {
  1242. szClusterDescription = L"";
  1243. }
  1244. //
  1245. // We won't allow proceeding in this case, because this indicates that
  1246. // this interface is already part of a cluster managed by NLB Manger.
  1247. //
  1248. msgLog.Log(
  1249. IDS_CONNECT_MSG_INTERFACE_ALREADY_MANAGED,
  1250. szFriendlyName,
  1251. szClusterDescription
  1252. );
  1253. bstrCaption = GETRESOURCEIDSTRING(IDS_CONNECT_UNABLE_TO_PROCEED);
  1254. }
  1255. end:
  1256. if (!fRet)
  1257. {
  1258. LPCWSTR szCaption = (LPCWSTR) bstrCaption;
  1259. LPCWSTR szMessage = msgLog.GetStringSafe();
  1260. if (fOkCancel)
  1261. {
  1262. int i = MessageBox( szMessage, szCaption, MB_OKCANCEL);
  1263. if (i == IDOK)
  1264. {
  1265. fRet = TRUE;
  1266. }
  1267. }
  1268. else
  1269. {
  1270. MessageBox( szMessage, szCaption, MB_ICONSTOP | MB_OK);
  1271. }
  1272. }
  1273. return fRet;
  1274. }
  1275. BOOL g_Silent = FALSE;