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.

2090 lines
67 KiB

  1. #include "CommonNLB.h"
  2. #include "MNLBCluster.h"
  3. #include "MNLBHost.h"
  4. #include "MNLBMachine.h"
  5. #include "MNLBNetCfg.h"
  6. #include "MWmiError.h"
  7. #include "MUsingCom.h"
  8. #include "MIPAddressAdmin.h"
  9. #include "ResourceString.h"
  10. #include "resource.h"
  11. #include <vector>
  12. #include <memory>
  13. #include <algorithm>
  14. #include <algorithm>
  15. using namespace std;
  16. // global only temporarily.
  17. //
  18. LeftView* g_leftView;
  19. CommonNLB::CommonNLB_Error
  20. CommonNLB::connectToClusterDirect( const _bstr_t& clusterIP,
  21. const _bstr_t& hostMember,
  22. ClusterData* p_clusterData,
  23. DataSinkI* dataSinkObj )
  24. {
  25. dataSinkObj->dataSink(
  26. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING) + hostMember );
  27. MNLBMachine nlbMachine( hostMember,
  28. clusterIP );
  29. dataSinkObj->dataSink(
  30. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  31. vector<MNLBMachine::HostInfo> hostInfo;
  32. dataSinkObj->dataSink(
  33. GETRESOURCEIDSTRING( IDS_INFO_FINDING_H ) );
  34. nlbMachine.getPresentHostsInfo( &hostInfo );
  35. dataSinkObj->dataSink(
  36. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  37. vector< _bstr_t> connectionIPS;
  38. for( int i = 0; i < hostInfo.size(); ++i )
  39. {
  40. connectionIPS.push_back( hostInfo[i].dedicatedIP );
  41. }
  42. #if 1
  43. return connectToClusterIndirect( clusterIP,
  44. connectionIPS,
  45. p_clusterData,
  46. dataSinkObj );
  47. #else
  48. vector<ClusterData> clusterDataStore;
  49. bool clusterPropertiesMatched;
  50. connectToClusterIndirectNew( clusterIP,
  51. connectionIPS,
  52. &clusterDataStore,
  53. clusterPropertiesMatched,
  54. dataSinkObj );
  55. (*p_clusterData) = clusterDataStore[0];
  56. return CommonNLB_SUCCESS;
  57. #endif
  58. }
  59. CommonNLB::CommonNLB_Error
  60. CommonNLB::connectToClusterIndirectNew( const _bstr_t& clusterIP,
  61. const vector<_bstr_t>& connectionIPS,
  62. vector< ClusterData>* clusterDataStore,
  63. bool& clusterPropertiesMatched,
  64. DataSinkI* dataSinkObj )
  65. {
  66. // connect to each host.
  67. // We are doing it here so that if there are any connectivity issues
  68. // we do not proceed with any further operation and ask user to
  69. // fix all issues before proceeding.
  70. // connect to each host.
  71. map< bstr_t, auto_ptr<MNLBMachine> > nlbMachine;
  72. for( int i = 0; i < connectionIPS.size(); ++i )
  73. {
  74. dataSinkObj->dataSink(
  75. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING) + connectionIPS[i] );
  76. auto_ptr<MNLBMachine> p_nlbMachine =
  77. auto_ptr<MNLBMachine> ( new MNLBMachine( connectionIPS[i],
  78. clusterIP ) );
  79. nlbMachine[connectionIPS[i] ] = p_nlbMachine;
  80. dataSinkObj->dataSink(
  81. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  82. }
  83. // get information from each host.
  84. //
  85. for( int i = 0; i < connectionIPS.size(); ++i )
  86. {
  87. ClusterData clusterData;
  88. // get cluster properties.
  89. dataSinkObj->dataSink(
  90. GETRESOURCEIDSTRING( IDS_INFO_FINDING_CL_P ) );
  91. ClusterProperties cp;
  92. nlbMachine[connectionIPS[i] ]->getClusterProperties( &cp );
  93. clusterData.cp = cp;
  94. dataSinkObj->dataSink(
  95. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  96. // get host properties.
  97. dataSinkObj->dataSink(
  98. GETRESOURCEIDSTRING( IDS_INFO_FINDING_H_P ) );
  99. HostProperties hp;
  100. nlbMachine[connectionIPS[i] ]->getHostProperties( &hp );
  101. dataSinkObj->dataSink(
  102. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  103. // set the host properties
  104. HostData hostData;
  105. hostData.hp = hp;
  106. // set the connection ip.
  107. hostData.connectionIP = connectionIPS[i];
  108. clusterData.hosts[hp.machineName] = hostData;
  109. // get port rules
  110. dataSinkObj->dataSink(
  111. GETRESOURCEIDSTRING( IDS_INFO_FINDING_P ) );
  112. vector<MNLBPortRuleLoadBalanced> portsLB;
  113. vector<MNLBPortRuleFailover> portsF;
  114. vector<MNLBPortRuleDisabled> portsD;
  115. PortDataULB ulbPortRule;
  116. PortDataF fPortRule;
  117. PortDataELB elbPortRule;
  118. PortDataD dPortRule;
  119. nlbMachine[connectionIPS[i] ]->getPortRulesLoadBalanced( &portsLB );
  120. for( int j = 0; j < portsLB.size(); ++j )
  121. {
  122. if( portsLB[j]._isEqualLoadBalanced == true )
  123. {
  124. // equal load balanced port rule.
  125. elbPortRule._startPort = portsLB[j]._startPort;
  126. elbPortRule._key = portsLB[j]._startPort;
  127. elbPortRule._endPort = portsLB[j]._endPort;
  128. elbPortRule._trafficToHandle = portsLB[j]._trafficToHandle;
  129. elbPortRule._affinity = portsLB[j]._affinity;
  130. clusterData.portELB[portsLB[j]._startPort] = elbPortRule;
  131. }
  132. else
  133. {
  134. ulbPortRule._startPort = portsLB[j]._startPort;
  135. ulbPortRule._key = portsLB[j]._startPort;
  136. ulbPortRule._endPort = portsLB[j]._endPort;
  137. ulbPortRule._trafficToHandle = portsLB[j]._trafficToHandle;
  138. ulbPortRule._affinity = portsLB[j]._affinity;
  139. ulbPortRule.machineMapToLoadWeight[hp.machineName] = portsLB[j]._load;
  140. clusterData.portULB[portsLB[j]._startPort] = ulbPortRule;
  141. }
  142. }
  143. portsLB.erase( portsLB.begin(), portsLB.end() );
  144. nlbMachine[connectionIPS[i] ]->getPortRulesFailover( &portsF );
  145. for( int j = 0; j < portsF.size(); ++j )
  146. {
  147. fPortRule._startPort = portsF[j]._startPort;
  148. fPortRule._key = portsF[j]._startPort;
  149. fPortRule._endPort = portsF[j]._endPort;
  150. fPortRule._trafficToHandle = portsF[j]._trafficToHandle;
  151. fPortRule.machineMapToPriority[ hp.machineName] = portsF[j]._priority;
  152. clusterData.portF[portsF[j]._startPort] = fPortRule;
  153. }
  154. portsF.erase( portsF.begin(), portsF.end() );
  155. // disabled port rules
  156. nlbMachine[connectionIPS[i] ]->getPortRulesDisabled( &portsD );
  157. for( int j = 0; j < portsD.size(); ++j )
  158. {
  159. dPortRule._startPort = portsD[j]._startPort;
  160. dPortRule._key = portsD[j]._startPort;
  161. dPortRule._endPort = portsD[j]._endPort;
  162. dPortRule._trafficToHandle = portsD[j]._trafficToHandle;
  163. clusterData.portD[portsD[j]._startPort] = dPortRule;
  164. }
  165. portsD.erase( portsD.begin(), portsD.end() );
  166. dataSinkObj->dataSink(
  167. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  168. // get virtual ips. These have already been got when we got the host properties
  169. // Thus here we are storing duplicate data, but this does ease
  170. // a lot of data structure manipulation.
  171. //
  172. clusterData.virtualIPs = clusterData.hosts[hp.machineName].hp.nicInfo.ipsOnNic;
  173. clusterData.virtualSubnets = clusterData.hosts[hp.machineName].hp.nicInfo.subnetMasks;
  174. clusterData.hosts[hp.machineName] = hostData;
  175. clusterDataStore->push_back( clusterData );
  176. }
  177. // now we will verify whether the cluster is
  178. // converged or there are mismatches.
  179. // rules for a converged cluster.
  180. //
  181. // cluster properties which need to
  182. // be same:
  183. // cluster ip
  184. // cluster subnet
  185. // full internet name
  186. // cluster mode
  187. // remote Control Enabled.
  188. //
  189. // host properties
  190. // host id has to be unique across hosts any
  191. // number from 1-32 inclusive.
  192. //
  193. // port rules
  194. // equal load balanced port rules have to be same
  195. // disabled port rules have to be same.
  196. // unequal load balanced port rules can differ only in load.
  197. // single host port rules can differ in priority, which has to be
  198. // unique across hosts for a specific port rule any number between 1-32.
  199. //
  200. // Each machine must have the cluster ip.
  201. //
  202. // Each machine must have the exactly same ips on the nic.
  203. clusterPropertiesMatched = true;
  204. // check if cluster ip is added.
  205. //
  206. if( find( (*clusterDataStore)[0].virtualIPs.begin(),
  207. (*clusterDataStore)[0].virtualIPs.end(),
  208. (*clusterDataStore)[0].cp.cIP ) == (*clusterDataStore)[0].virtualIPs.end() )
  209. {
  210. clusterPropertiesMatched = false;
  211. }
  212. if( clusterDataStore->size() == 1 )
  213. {
  214. // only one host in cluster so only
  215. return CommonNLB_SUCCESS;
  216. }
  217. // sort the virtual ips of the first node. Eases
  218. // comparision.
  219. sort( (*clusterDataStore)[0].virtualIPs.begin(),
  220. (*clusterDataStore)[0].virtualIPs.end() );
  221. for( int i = 1; i < clusterDataStore->size(); ++i )
  222. {
  223. // cluster properties must match.
  224. //
  225. if( (*clusterDataStore)[0].cp
  226. !=
  227. (*clusterDataStore)[i].cp )
  228. {
  229. // mismatch in cluster properties.
  230. // MISMATCH
  231. clusterPropertiesMatched = false;
  232. }
  233. // the ELB, ULB, F, D port rules have to
  234. // match.
  235. if ( (*clusterDataStore)[0].portELB.size()
  236. !=
  237. (*clusterDataStore)[i].portELB.size() )
  238. {
  239. // mismatch in port rules.
  240. // MISMATCH
  241. clusterPropertiesMatched = false;
  242. }
  243. else
  244. {
  245. // number of port rules are matching.
  246. map<long, PortDataELB>::iterator top;
  247. map<long, PortDataELB>::iterator location;
  248. for( top = (*clusterDataStore)[i].portELB.begin();
  249. top != (*clusterDataStore)[i].portELB.end();
  250. ++top )
  251. {
  252. location = (*clusterDataStore)[0].portELB.find( (*top).first );
  253. if( location == (*clusterDataStore)[0].portELB.end() )
  254. {
  255. // no such port exists.
  256. // thus mismatch.
  257. // MISMATCH
  258. clusterPropertiesMatched = false;
  259. }
  260. else
  261. {
  262. if( (*location).second._startPort != (*top).second._startPort
  263. ||
  264. (*location).second._endPort != (*top).second._endPort
  265. ||
  266. (*location).second._trafficToHandle != (*top).second._trafficToHandle
  267. ||
  268. (*location).second._affinity != (*top).second._affinity
  269. )
  270. {
  271. // things other than key which is start port
  272. // has been modified.
  273. // MISMATCH
  274. }
  275. }
  276. }
  277. }
  278. if ( (*clusterDataStore)[0].portULB.size()
  279. !=
  280. (*clusterDataStore)[i].portULB.size() )
  281. {
  282. // mismatch in port rules.
  283. // MISMATCH
  284. clusterPropertiesMatched = false;
  285. }
  286. else
  287. {
  288. // number of port rules are matching.
  289. map<long, PortDataULB>::iterator top;
  290. map<long, PortDataULB>::iterator location;
  291. for( top = (*clusterDataStore)[i].portULB.begin();
  292. top != (*clusterDataStore)[i].portULB.end();
  293. ++top )
  294. {
  295. location = (*clusterDataStore)[0].portULB.find( (*top).first );
  296. if( location == (*clusterDataStore)[0].portULB.end() )
  297. {
  298. // no such port exists.
  299. // thus mismatch.
  300. // MISMATCH
  301. clusterPropertiesMatched = false;
  302. }
  303. else
  304. {
  305. if( (*location).second._startPort != (*top).second._startPort
  306. ||
  307. (*location).second._endPort != (*top).second._endPort
  308. ||
  309. (*location).second._trafficToHandle != (*top).second._trafficToHandle
  310. ||
  311. (*location).second._affinity != (*top).second._affinity
  312. )
  313. {
  314. // things other than key which is start port
  315. // has been modified.
  316. // MISMATCH
  317. clusterPropertiesMatched = false;
  318. }
  319. }
  320. }
  321. }
  322. if ( (*clusterDataStore)[0].portF.size()
  323. !=
  324. (*clusterDataStore)[i].portF.size() )
  325. {
  326. // mismatch in port rules.
  327. // MISMATCH
  328. clusterPropertiesMatched = false;
  329. }
  330. else
  331. {
  332. // number of port rules are matching.
  333. map<long, PortDataF>::iterator top;
  334. map<long, PortDataF>::iterator location;
  335. for( top = (*clusterDataStore)[i].portF.begin();
  336. top != (*clusterDataStore)[i].portF.end();
  337. ++top )
  338. {
  339. location = (*clusterDataStore)[0].portF.find( (*top).first );
  340. if( location == (*clusterDataStore)[0].portF.end() )
  341. {
  342. // no such port exists.
  343. // thus mismatch.
  344. // MISMATCH
  345. clusterPropertiesMatched = false;
  346. }
  347. else
  348. {
  349. if( (*location).second._startPort != (*top).second._startPort
  350. ||
  351. (*location).second._endPort != (*top).second._endPort
  352. ||
  353. (*location).second._trafficToHandle != (*top).second._trafficToHandle
  354. )
  355. {
  356. // things other than key which is start port
  357. // has been modified.
  358. // MISMATCH
  359. clusterPropertiesMatched = false;
  360. }
  361. }
  362. }
  363. }
  364. if ( (*clusterDataStore)[0].portD.size()
  365. !=
  366. (*clusterDataStore)[i].portD.size() )
  367. {
  368. // mismatch in port rules.
  369. // MISMATCH
  370. clusterPropertiesMatched = false;
  371. }
  372. else
  373. {
  374. // number of port rules are matching.
  375. map<long, PortDataD>::iterator top;
  376. map<long, PortDataD>::iterator location;
  377. for( top = (*clusterDataStore)[i].portD.begin();
  378. top != (*clusterDataStore)[i].portD.end();
  379. ++top )
  380. {
  381. location = (*clusterDataStore)[0].portD.find( (*top).first );
  382. if( location == (*clusterDataStore)[0].portD.end() )
  383. {
  384. // no such port exists.
  385. // thus mismatch.
  386. // MISMATCH
  387. clusterPropertiesMatched = false;
  388. }
  389. else
  390. {
  391. if( (*location).second._startPort != (*top).second._startPort
  392. ||
  393. (*location).second._endPort != (*top).second._endPort
  394. ||
  395. (*location).second._trafficToHandle != (*top).second._trafficToHandle
  396. )
  397. {
  398. // things other than key which is start port
  399. // has been modified.
  400. // MISMATCH
  401. clusterPropertiesMatched = false;
  402. }
  403. }
  404. }
  405. }
  406. // check if each machine has the same virtual ips.
  407. //
  408. sort( (*clusterDataStore)[i].virtualIPs.begin(),
  409. (*clusterDataStore)[i].virtualIPs.end() );
  410. if( (*clusterDataStore)[0].virtualIPs
  411. !=
  412. (*clusterDataStore)[i].virtualIPs )
  413. {
  414. // MISMATCH
  415. clusterPropertiesMatched = false;
  416. }
  417. }
  418. // check if host ids are duplicate.
  419. map< _bstr_t, HostData>::iterator onlyHost;
  420. set<int> hostIDS;
  421. for( int i = 0; i < clusterDataStore->size(); ++i )
  422. {
  423. onlyHost = (*clusterDataStore)[i].hosts.begin();
  424. // check if this host id has been used previously.
  425. if( hostIDS.find( (*onlyHost).second.hp.hID ) == hostIDS.end() )
  426. {
  427. // host id is unused.
  428. hostIDS.insert( (*onlyHost).second.hp.hID );
  429. }
  430. else
  431. {
  432. // host id has been used previously.
  433. // Thus this is duplicate.
  434. // MISMATCH
  435. clusterPropertiesMatched = false;
  436. }
  437. }
  438. if( clusterPropertiesMatched == true )
  439. {
  440. // combine all the host information.
  441. //
  442. map<_bstr_t, HostData >::iterator top;
  443. for( int i = 1; i < clusterDataStore->size(); ++i )
  444. {
  445. top = (*clusterDataStore)[i].hosts.begin();
  446. (*clusterDataStore)[0].hosts[ (*top).first ] = (*top).second;
  447. }
  448. #if 1
  449. // combine all the port information for ULB and disabled port rules.
  450. // this may be a little difficult, but it works. Don't fiddle around
  451. // with this part.
  452. map<long, PortDataULB>::iterator topULB;
  453. for( topULB = (*clusterDataStore)[0].portULB.begin();
  454. topULB != (*clusterDataStore)[0].portULB.end();
  455. ++topULB )
  456. {
  457. map<_bstr_t, long>& ref = (*topULB).second.machineMapToLoadWeight;
  458. for( int i = 1; i < clusterDataStore->size(); ++i )
  459. {
  460. // find the machine name for this clusterdata.
  461. map<_bstr_t, HostData>::iterator top;
  462. top = (*clusterDataStore)[i].hosts.begin();
  463. _bstr_t machineName = (*top).first;
  464. ref[machineName] =
  465. (*clusterDataStore)[i].portULB[ (*topULB).first ].machineMapToLoadWeight[ machineName];
  466. }
  467. }
  468. map<long, PortDataF>::iterator topF;
  469. for( topF = (*clusterDataStore)[0].portF.begin();
  470. topF != (*clusterDataStore)[0].portF.end();
  471. ++topF )
  472. {
  473. map<_bstr_t, long>& ref = (*topF).second.machineMapToPriority;
  474. for( int i = 1; i < clusterDataStore->size(); ++i )
  475. {
  476. // find the machine name for this clusterdata.
  477. map<_bstr_t, HostData>::iterator top;
  478. top = (*clusterDataStore)[i].hosts.begin();
  479. _bstr_t machineName = (*top).first;
  480. ref[machineName] =
  481. (*clusterDataStore)[i].portF[ (*topF).first ].machineMapToPriority[ machineName];
  482. }
  483. }
  484. #endif
  485. }
  486. return CommonNLB_SUCCESS;
  487. }
  488. CommonNLB::CommonNLB_Error
  489. CommonNLB::connectToClusterIndirect( const _bstr_t& clusterIP,
  490. const vector<_bstr_t>& connectionIPS,
  491. ClusterData* p_clusterData,
  492. DataSinkI* dataSinkObj )
  493. {
  494. // connect to each host.
  495. // We are doing it here so that if there are any connectivity issues
  496. // we do not proceed with any further operation and ask user to
  497. // fix all issues before proceeding.
  498. // connect to each host.
  499. map< bstr_t, auto_ptr<MNLBMachine> > nlbMachine;
  500. for( int i = 0; i < connectionIPS.size(); ++i )
  501. {
  502. dataSinkObj->dataSink(
  503. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING) + connectionIPS[i] );
  504. auto_ptr<MNLBMachine> p_nlbMachine =
  505. auto_ptr<MNLBMachine> ( new MNLBMachine( connectionIPS[i],
  506. clusterIP ) );
  507. nlbMachine[connectionIPS[i] ] = p_nlbMachine;
  508. dataSinkObj->dataSink(
  509. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  510. }
  511. // rules for a converged cluster.
  512. //
  513. // cluster properties which need to
  514. // be same:
  515. // cluster ip
  516. // cluster subnet
  517. // full internet name
  518. // cluster mode
  519. //
  520. // host properties
  521. // host id has to be unique across hosts any
  522. // number from 1-32 inclusive.
  523. //
  524. // port rules
  525. // equal load balanced port rules have to be same
  526. // disabled port rules have to be same.
  527. // unequal load balanced port rules can differ only in load.
  528. // single host port rules can differ in priority, which has to be
  529. // unique across hosts for a specific port rule any number between 1-32.
  530. //
  531. for( int i = 0; i < connectionIPS.size(); ++i )
  532. {
  533. // get cluster properties.
  534. // cluster properties need to be got only for one host.
  535. if( i == 0 )
  536. {
  537. dataSinkObj->dataSink(
  538. GETRESOURCEIDSTRING( IDS_INFO_FINDING_CL_P ) );
  539. ClusterProperties cp;
  540. nlbMachine[connectionIPS[i] ]->getClusterProperties( &cp );
  541. p_clusterData->cp = cp;
  542. dataSinkObj->dataSink(
  543. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  544. }
  545. // get host properties.
  546. dataSinkObj->dataSink(
  547. GETRESOURCEIDSTRING( IDS_INFO_FINDING_H_P ) );
  548. HostProperties hp;
  549. nlbMachine[connectionIPS[i] ]->getHostProperties( &hp );
  550. dataSinkObj->dataSink(
  551. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  552. // set the host properties
  553. HostData hostData;
  554. hostData.hp = hp;
  555. // set the connection ip.
  556. hostData.connectionIP = connectionIPS[i];
  557. p_clusterData->hosts[hp.machineName] = hostData;
  558. // get port rules
  559. dataSinkObj->dataSink(
  560. GETRESOURCEIDSTRING( IDS_INFO_FINDING_P ) );
  561. vector<MNLBPortRuleLoadBalanced> portsLB;
  562. vector<MNLBPortRuleFailover> portsF;
  563. vector<MNLBPortRuleDisabled> portsD;
  564. PortDataULB ulbPortRule;
  565. PortDataF fPortRule;
  566. PortDataELB elbPortRule;
  567. PortDataD dPortRule;
  568. nlbMachine[connectionIPS[i] ]->getPortRulesLoadBalanced( &portsLB );
  569. for( int j = 0; j < portsLB.size(); ++j )
  570. {
  571. if( portsLB[j]._isEqualLoadBalanced == true )
  572. {
  573. // equal load balanced port rule.
  574. elbPortRule._startPort = portsLB[j]._startPort;
  575. elbPortRule._key = portsLB[j]._startPort;
  576. elbPortRule._endPort = portsLB[j]._endPort;
  577. elbPortRule._trafficToHandle = portsLB[j]._trafficToHandle;
  578. elbPortRule._affinity = portsLB[j]._affinity;
  579. p_clusterData->portELB[portsLB[j]._startPort] = elbPortRule;
  580. }
  581. else
  582. {
  583. // unequal load balanced.
  584. if( i == 0 )
  585. {
  586. ulbPortRule._startPort = portsLB[j]._startPort;
  587. ulbPortRule._key = portsLB[j]._startPort;
  588. ulbPortRule._endPort = portsLB[j]._endPort;
  589. ulbPortRule._trafficToHandle = portsLB[j]._trafficToHandle;
  590. ulbPortRule._affinity = portsLB[j]._affinity;
  591. ulbPortRule.machineMapToLoadWeight[hp.machineName] = portsLB[j]._load;
  592. p_clusterData->portULB[portsLB[j]._startPort] = ulbPortRule;
  593. }
  594. else
  595. {
  596. p_clusterData->portULB[portsLB[j]._startPort].machineMapToLoadWeight[ hp.machineName] = portsLB[j]._load;
  597. }
  598. }
  599. }
  600. portsLB.erase( portsLB.begin(), portsLB.end() );
  601. nlbMachine[connectionIPS[i] ]->getPortRulesFailover( &portsF );
  602. for( int j = 0; j < portsF.size(); ++j )
  603. {
  604. if( i == 0 )
  605. {
  606. fPortRule._startPort = portsF[j]._startPort;
  607. fPortRule._key = portsF[j]._startPort;
  608. fPortRule._endPort = portsF[j]._endPort;
  609. fPortRule._trafficToHandle = portsF[j]._trafficToHandle;
  610. fPortRule.machineMapToPriority[ hp.machineName] = portsF[j]._priority;
  611. p_clusterData->portF[portsF[j]._startPort] = fPortRule;
  612. }
  613. else
  614. {
  615. p_clusterData->portF[portsF[j]._startPort].machineMapToPriority[ hp.machineName] = portsF[j]._priority;
  616. }
  617. }
  618. portsF.erase( portsF.begin(), portsF.end() );
  619. // disabled need to be got only once.
  620. if( i == 0 )
  621. {
  622. nlbMachine[connectionIPS[i] ]->getPortRulesDisabled( &portsD );
  623. for( int j = 0; j < portsD.size(); ++j )
  624. {
  625. dPortRule._startPort = portsD[j]._startPort;
  626. dPortRule._key = portsD[j]._startPort;
  627. dPortRule._endPort = portsD[j]._endPort;
  628. dPortRule._trafficToHandle = portsD[j]._trafficToHandle;
  629. p_clusterData->portD[portsD[j]._startPort] = dPortRule;
  630. }
  631. portsD.erase( portsD.begin(), portsD.end() );
  632. }
  633. dataSinkObj->dataSink(
  634. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  635. }
  636. dataSinkObj->dataSink(
  637. GETRESOURCEIDSTRING( IDS_INFO_SUCCESS ) );
  638. return CommonNLB_SUCCESS;
  639. }
  640. CommonNLB::CommonNLB_Error
  641. CommonNLB::connectToMachine(
  642. const _bstr_t& machineToConnect,
  643. _bstr_t& machineServerName,
  644. vector< CommonNLB::NicNLBBound >& nicList,
  645. DataSinkI* dataSinkObj )
  646. {
  647. // connect to machine.
  648. //
  649. MWmiObject machine( machineToConnect,
  650. L"root\\microsoftnlb",
  651. L"administrator",
  652. L"" );
  653. // find all nics on machine.
  654. //
  655. vector<MWmiInstance> instanceStore;
  656. machine.getInstances( L"NlbsNic",
  657. &instanceStore );
  658. // check if nic has nlb bound.
  659. //
  660. // input parameters are none.
  661. //
  662. vector<MWmiParameter *> inputParameters;
  663. // output parameters which are of interest.
  664. //
  665. vector<MWmiParameter *> outputParameters;
  666. MWmiParameter ReturnValue(L"ReturnValue");
  667. outputParameters.push_back( &ReturnValue );
  668. vector<MWmiParameter *> parameterStore;
  669. MWmiParameter Server(L"__Server");
  670. parameterStore.push_back( &Server );
  671. MWmiParameter FullName(L"FullName");
  672. parameterStore.push_back( &FullName );
  673. MWmiParameter AdapterGuid(L"AdapterGuid");
  674. parameterStore.push_back( &AdapterGuid );
  675. MWmiParameter FriendlyName(L"FriendlyName");
  676. parameterStore.push_back( &FriendlyName );
  677. for( int i = 0; i < instanceStore.size(); ++i )
  678. {
  679. // get full name, guid and friendly name.
  680. //
  681. NicNLBBound temp;
  682. instanceStore[i].getParameters( parameterStore );
  683. temp.fullNicName = FullName.getValue();
  684. temp.adapterGuid = AdapterGuid.getValue();
  685. temp.friendlyName = FriendlyName.getValue();
  686. // get machine name.
  687. machineServerName = Server.getValue();
  688. // check if nic is bound to nlb or not.
  689. instanceStore[i].runMethod( L"isBound",
  690. inputParameters,
  691. outputParameters );
  692. if( long( ReturnValue.getValue() ) == 1 )
  693. {
  694. // this nic is bound.
  695. temp.isBoundToNLB = true;
  696. }
  697. else
  698. {
  699. temp.isBoundToNLB = false;
  700. }
  701. // get all the ip's on this nic.
  702. MIPAddressAdmin ipAdmin( machineToConnect,
  703. temp.fullNicName );
  704. ipAdmin.getIPAddresses( &temp.ipsOnNic,
  705. &temp.subnetMasks );
  706. // check if the nic is dhcp.
  707. ipAdmin.isDHCPEnabled( temp.dhcpEnabled );
  708. nicList.push_back( temp );
  709. }
  710. return CommonNLB_SUCCESS;
  711. }
  712. CommonNLB::CommonNLB_Error
  713. CommonNLB::changeNLBClusterSettings( const ClusterData* oldSettings,
  714. const ClusterData* newSettings,
  715. DataSinkI* dataSinkObj )
  716. {
  717. return CommonNLB_SUCCESS;
  718. }
  719. CommonNLB::CommonNLB_Error
  720. CommonNLB::changeNLBHostSettings( const ClusterData* oldSettings,
  721. const ClusterData* newSettings,
  722. const _bstr_t& machineName,
  723. DataSinkI* dataSinkObj )
  724. {
  725. ClusterData* oldSettingsCopy = const_cast <ClusterData *>( oldSettings );
  726. ClusterData* newSettingsCopy = const_cast <ClusterData *>( newSettings );
  727. map<_bstr_t, HostData>::iterator topOld;
  728. map<_bstr_t, HostData>::iterator topNew;
  729. // change host properties for host if that have changed.
  730. //
  731. if( oldSettingsCopy->hosts[machineName].hp
  732. !=
  733. newSettingsCopy->hosts[machineName].hp )
  734. {
  735. // connect to machine.
  736. //
  737. dataSinkObj->dataSink(
  738. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING ) +
  739. oldSettingsCopy->hosts[machineName].connectionIP );
  740. MNLBMachine nlbMachine(
  741. oldSettingsCopy->hosts[machineName].connectionIP,
  742. oldSettingsCopy->cp.cIP );
  743. dataSinkObj->dataSink(
  744. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  745. dataSinkObj->dataSink(
  746. GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_H_P ) );
  747. // host properties have changed.
  748. unsigned long returnValue;
  749. nlbMachine.setHostProperties( newSettingsCopy->hosts[machineName].hp,
  750. &returnValue );
  751. dataSinkObj->dataSink(
  752. GETRESOURCEIDSTRING( IDS_INFO_DONE) );
  753. }
  754. return CommonNLB_SUCCESS;
  755. }
  756. CommonNLB::CommonNLB_Error
  757. CommonNLB::changeNLBHostPortSettings( const ClusterData* oldSettings,
  758. const ClusterData* newSettings,
  759. const _bstr_t& machineName,
  760. DataSinkI* dataSinkObj )
  761. {
  762. ClusterData* oldSettingsCopy = const_cast <ClusterData *>( oldSettings );
  763. ClusterData* newSettingsCopy = const_cast <ClusterData *>( newSettings );
  764. map<_bstr_t, HostData>::iterator topOld;
  765. map<_bstr_t, HostData>::iterator topNew;
  766. // connect to machine.
  767. //
  768. dataSinkObj->dataSink(
  769. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING ) +
  770. oldSettingsCopy->hosts[machineName].connectionIP );
  771. MNLBMachine nlbMachine(
  772. oldSettingsCopy->hosts[machineName].connectionIP,
  773. oldSettingsCopy->cp.cIP );
  774. dataSinkObj->dataSink(
  775. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  776. // check if any load weights have changed.
  777. // for any unequal load balanced port rule.
  778. //
  779. map<long, PortDataULB>::iterator topOldULB;
  780. map<long, PortDataULB>::iterator topNewULB;
  781. for( topOldULB = oldSettingsCopy->portULB.begin(),
  782. topNewULB = newSettingsCopy->portULB.begin();
  783. topOldULB != oldSettingsCopy->portULB.end();
  784. ++topOldULB, ++topNewULB )
  785. {
  786. if( (*topOldULB).second.machineMapToLoadWeight[machineName]
  787. !=
  788. (*topNewULB).second.machineMapToLoadWeight[machineName]
  789. )
  790. {
  791. dataSinkObj->dataSink(
  792. GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_P_ULB ) );
  793. // load weight has changed.
  794. // remove old port rule
  795. MNLBPortRuleLoadBalanced portULB = (*topNewULB).second;
  796. portULB._load =
  797. (*topOldULB).second.machineMapToLoadWeight[machineName];
  798. nlbMachine.removePortRuleLoadBalanced( portULB );
  799. // add this port rule.
  800. // only load weight can change.
  801. portULB._load =
  802. (*topNewULB).second.machineMapToLoadWeight[machineName];
  803. nlbMachine.addPortRuleLoadBalanced( portULB );
  804. dataSinkObj->dataSink(
  805. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  806. }
  807. }
  808. // check if any priorities have changed.
  809. // for any failover port rules
  810. //
  811. map<long, PortDataF>::iterator topOldF;
  812. map<long, PortDataF>::iterator topNewF;
  813. for( topOldF = oldSettingsCopy->portF.begin(),
  814. topNewF = newSettingsCopy->portF.begin();
  815. topOldF != oldSettingsCopy->portF.end();
  816. ++topOldF, ++topNewF )
  817. {
  818. if( (*topOldF).second.machineMapToPriority[machineName]
  819. !=
  820. (*topNewF).second.machineMapToPriority[machineName]
  821. )
  822. {
  823. dataSinkObj->dataSink(
  824. GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_P_F ) );
  825. // priority has changed.
  826. MNLBMachine nlbMachine(
  827. newSettingsCopy->hosts[machineName].connectionIP,
  828. newSettingsCopy->cp.cIP );
  829. // remove old port rule
  830. MNLBPortRuleFailover portF = (*topNewF).second;
  831. portF._priority =
  832. (*topOldF).second.machineMapToPriority[machineName];
  833. nlbMachine.removePortRuleFailover( portF );
  834. // add new port rule.
  835. // only priority has changed.
  836. portF._priority =
  837. (*topNewF).second.machineMapToPriority[machineName];
  838. nlbMachine.addPortRuleFailover( portF );
  839. dataSinkObj->dataSink(
  840. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  841. }
  842. }
  843. return CommonNLB_SUCCESS;
  844. }
  845. CommonNLB::CommonNLB_Error
  846. CommonNLB::changeNLBClusterAndPortSettings( const ClusterData* oldSettings,
  847. const ClusterData* newSettings,
  848. DataSinkI* dataSinkObj,
  849. bool* pbClusterIpChanged)
  850. {
  851. ClusterData* oldSettingsCopy = const_cast <ClusterData *>( oldSettings );
  852. ClusterData* newSettingsCopy = const_cast <ClusterData *>( newSettings );
  853. bool bClusterParametersChanged, bPortRulesChanged, bOnlyClusterNameChanged;
  854. // Find out if the cluster parameters have changed. Also, find if the cluster name
  855. // is the only parameter that has changed
  856. bClusterParametersChanged = newSettingsCopy->cp.HaveClusterPropertiesChanged(oldSettingsCopy->cp,
  857. &bOnlyClusterNameChanged,
  858. pbClusterIpChanged);
  859. vector<long> rulesAddedELB;
  860. vector<long> rulesUnchangedELB;
  861. vector<long> rulesRemovedELB;
  862. findPortRulesAddedUnchangedRemovedELB( oldSettingsCopy,
  863. newSettingsCopy,
  864. dataSinkObj,
  865. rulesAddedELB,
  866. rulesUnchangedELB,
  867. rulesRemovedELB );
  868. vector<long> rulesAddedULB;
  869. vector<long> rulesUnchangedULB;
  870. vector<long> rulesRemovedULB;
  871. findPortRulesAddedUnchangedRemovedULB( oldSettingsCopy,
  872. newSettingsCopy,
  873. dataSinkObj,
  874. rulesAddedULB,
  875. rulesUnchangedULB,
  876. rulesRemovedULB );
  877. vector<long> rulesAddedD;
  878. vector<long> rulesUnchangedD;
  879. vector<long> rulesRemovedD;
  880. findPortRulesAddedUnchangedRemovedD( oldSettingsCopy,
  881. newSettingsCopy,
  882. dataSinkObj,
  883. rulesAddedD,
  884. rulesUnchangedD,
  885. rulesRemovedD );
  886. vector<long> rulesAddedF;
  887. vector<long> rulesUnchangedF;
  888. vector<long> rulesRemovedF;
  889. findPortRulesAddedUnchangedRemovedF( oldSettingsCopy,
  890. newSettingsCopy,
  891. dataSinkObj,
  892. rulesAddedF,
  893. rulesUnchangedF,
  894. rulesRemovedF );
  895. // check if any port rules have been added or removed
  896. // if not we don't want to do anything.
  897. if(
  898. ( rulesAddedULB.size() == 0 )
  899. &&
  900. ( rulesRemovedULB.size() == 0 )
  901. &&
  902. ( rulesAddedELB.size() == 0 )
  903. &&
  904. ( rulesRemovedELB.size() == 0 )
  905. &&
  906. ( rulesAddedD.size() == 0 )
  907. &&
  908. ( rulesRemovedD.size() == 0 )
  909. &&
  910. ( rulesAddedF.size() == 0 )
  911. &&
  912. ( rulesRemovedF.size() == 0 )
  913. )
  914. {
  915. //return CommonNLB_SUCCESS;
  916. //OutputDebugString(_T("No Change to Port Rules\n"));
  917. bPortRulesChanged = false;
  918. }
  919. else
  920. {
  921. bPortRulesChanged = true;
  922. }
  923. // Neither the cluster parameters nor the port rules have changed, so return
  924. if (!bClusterParametersChanged && !bPortRulesChanged)
  925. {
  926. //OutputDebugString(_T("No Change to Cluster Parameters or Port Rules\n"));
  927. return CommonNLB_SUCCESS;
  928. }
  929. // connect to each host.
  930. // We are doing it here so that if there are any connectivity issues
  931. // we do not proceed with any changes and just inform the user.
  932. // This is to ensure that we do not cause any convergence.
  933. // connect to each host.
  934. map<_bstr_t, HostData >::iterator top;
  935. map< bstr_t, auto_ptr<MNLBMachine> > nlbMachine;
  936. for( top = oldSettingsCopy->hosts.begin();
  937. top != oldSettingsCopy->hosts.end();
  938. ++top )
  939. {
  940. dataSinkObj->dataSink(
  941. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING )
  942. + (*top).second.connectionIP );
  943. auto_ptr<MNLBMachine> p_nlbMachine =
  944. auto_ptr<MNLBMachine> ( new MNLBMachine( (*top).second.connectionIP,
  945. oldSettingsCopy->cp.cIP ) );
  946. nlbMachine[(*top).first] = p_nlbMachine;
  947. dataSinkObj->dataSink(
  948. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  949. }
  950. // for each host in cluster apply the changed port & cluster rules.
  951. for( top = oldSettingsCopy->hosts.begin();
  952. top != oldSettingsCopy->hosts.end();
  953. ++top )
  954. {
  955. if (bPortRulesChanged)
  956. {
  957. dataSinkObj->dataSink(
  958. GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_P ) );
  959. // remove all port rules which need to be erased..
  960. //
  961. for( int i = 0; i < rulesRemovedELB.size(); ++i )
  962. {
  963. nlbMachine[ (*top).first ]->removePortRuleLoadBalanced( oldSettingsCopy->portELB[ rulesRemovedELB[i] ] );
  964. }
  965. for( int i = 0; i < rulesRemovedULB.size(); ++i )
  966. {
  967. nlbMachine[ (*top).first ]->removePortRuleLoadBalanced( oldSettingsCopy->portULB[ rulesRemovedULB[i] ] );
  968. }
  969. for( int i = 0; i < rulesRemovedD.size(); ++i )
  970. {
  971. nlbMachine[ (*top).first ]->removePortRuleDisabled( oldSettingsCopy->portD[ rulesRemovedD[i] ] );
  972. }
  973. for( int i = 0; i < rulesRemovedF.size(); ++i )
  974. {
  975. nlbMachine[ (*top).first ]->removePortRuleFailover( oldSettingsCopy->portF[rulesRemovedF[i] ] );
  976. }
  977. // add all new port rules
  978. //
  979. for( int i = 0; i < rulesAddedELB.size(); ++i )
  980. {
  981. nlbMachine[ (*top).first ]->addPortRuleLoadBalanced( newSettingsCopy->portELB[ rulesAddedELB[i] ] );
  982. }
  983. for( int i = 0; i < rulesAddedULB.size(); ++i )
  984. {
  985. MNLBPortRuleLoadBalanced portULB = newSettingsCopy->portULB[ rulesAddedULB[i] ];
  986. _bstr_t machineName = (*top).first;
  987. portULB._load =
  988. newSettingsCopy->portULB[rulesAddedULB[i]].machineMapToLoadWeight[ (*top).first ];
  989. nlbMachine[ (*top).first ]->addPortRuleLoadBalanced( portULB );
  990. }
  991. for( int i = 0; i < rulesAddedD.size(); ++i )
  992. {
  993. nlbMachine[ (*top).first ]->addPortRuleDisabled( newSettingsCopy->portD[rulesAddedD[i] ] );
  994. }
  995. for( int i = 0; i < rulesAddedF.size(); ++i )
  996. {
  997. MNLBPortRuleFailover portF = newSettingsCopy->portF[rulesAddedF[i] ];
  998. portF._priority =
  999. newSettingsCopy->portF[rulesAddedF[i]].machineMapToPriority[ (*top).first ];
  1000. nlbMachine[ (*top).first ]->addPortRuleFailover( portF );
  1001. }
  1002. dataSinkObj->dataSink(
  1003. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  1004. }
  1005. if (bClusterParametersChanged)
  1006. {
  1007. if (bOnlyClusterNameChanged)
  1008. {
  1009. unsigned long retVal;
  1010. dataSinkObj->dataSink(
  1011. GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_CN ) );
  1012. nlbMachine[ (*top).first ]->setClusterProperties(newSettingsCopy->cp, &retVal);
  1013. // if remote control is enabled set the password.
  1014. // even if password has not changed just making extra call.
  1015. if( newSettingsCopy->cp.remoteControlEnabled == true )
  1016. {
  1017. nlbMachine[ (*top).first ]->setPassword(newSettingsCopy->cp.password, &retVal);
  1018. }
  1019. }
  1020. else // Cluster Parameters other than Cluster name have changed too
  1021. {
  1022. dataSinkObj->dataSink(
  1023. GETRESOURCEIDSTRING( IDS_INFO_REMOVING_CL_IP ) );
  1024. MNLBNetCfg nlbNetCfg((*top).second.connectionIP, (*top).second.hp.nicInfo.fullNicName);
  1025. nlbNetCfg.removeClusterIP(oldSettingsCopy->cp.cIP);
  1026. }
  1027. dataSinkObj->dataSink(
  1028. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  1029. }
  1030. }
  1031. // If Cluster Paraters other than the Cluster Name has changed, call the NLB Manager
  1032. // provider's "ModifyClusterProperties" (eventually) to modify cluster properties
  1033. // and add the cluster ip to tcp/ip. Modification of the cluster properties will
  1034. // result in the disable/re-enable of the nic & hence the WMI DCOM connection might
  1035. // be lost. So, we are doing this two-step operation locally
  1036. if (bClusterParametersChanged && !bOnlyClusterNameChanged)
  1037. {
  1038. for( top = oldSettingsCopy->hosts.begin();
  1039. top != oldSettingsCopy->hosts.end();
  1040. ++top )
  1041. {
  1042. //OutputDebugString(_T("Modifying Cluster Parameters and adding cluster ip to tcp-ip !!!\n"));
  1043. dataSinkObj->dataSink(
  1044. GETRESOURCEIDSTRING( IDS_INFO_MODIFYING_CP_AND_ADD_IP ) );
  1045. MNLBNetCfg* p_nlbNetCfg = NULL;
  1046. ModifyClusterPropertiesParameters* par = NULL;
  1047. try {
  1048. p_nlbNetCfg = new MNLBNetCfg((*top).second.connectionIP, (*top).second.hp.nicInfo.fullNicName);
  1049. par = new ModifyClusterPropertiesParameters;
  1050. par->nlbNetCfg = p_nlbNetCfg;
  1051. par->clusterData = NULL;
  1052. par->clusterData = new ClusterData( *newSettingsCopy );
  1053. par->machineName = new _bstr_t( (*top).second.hp.machineName );
  1054. g_leftView = (LeftView *) dataSinkObj;
  1055. }
  1056. catch(...)
  1057. {
  1058. delete par->clusterData;
  1059. delete par;
  1060. delete p_nlbNetCfg;
  1061. dataSinkObj->dataSink(GETRESOURCEIDSTRING(IDS_INFO_NEW_EXCEPTION));
  1062. throw;
  1063. }
  1064. AfxBeginThread( (AFX_THREADPROC) ModifyClusterPropertiesThread, par );
  1065. dataSinkObj->dataSink(
  1066. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  1067. }
  1068. }
  1069. return CommonNLB_SUCCESS;
  1070. }
  1071. CommonNLB::CommonNLB_Error
  1072. CommonNLB::findPortRulesAddedUnchangedRemovedELB(
  1073. const ClusterData* oldSettings,
  1074. const ClusterData* newSettings,
  1075. DataSinkI* dataSinkObj,
  1076. vector<long>& rulesAdded,
  1077. vector<long>& rulesUnchanged,
  1078. vector<long>& rulesRemoved )
  1079. {
  1080. map<long, PortDataELB>::iterator top;
  1081. map<long, PortDataELB>::iterator location;
  1082. // find ports which have been newly added or modified.
  1083. //
  1084. for( top = newSettings->portELB.begin();
  1085. top != newSettings->portELB.end();
  1086. ++top )
  1087. {
  1088. rulesAdded.push_back( (*top).first );
  1089. }
  1090. // find ports which have remain unchanged and ports which have
  1091. // been removed or modified.
  1092. for( top = oldSettings->portELB.begin();
  1093. top != oldSettings->portELB.end();
  1094. ++top )
  1095. {
  1096. // check if this port rule has been removed or modified.
  1097. location = newSettings->portELB.find( (*top).first );
  1098. if( location == newSettings->portELB.end() )
  1099. {
  1100. // key has been removed
  1101. rulesRemoved.push_back( (*top).first );
  1102. }
  1103. else
  1104. {
  1105. // may be things other than key are modified or totally
  1106. // unchanged.
  1107. if( (*location).second == (*top).second )
  1108. {
  1109. // totally unchanged
  1110. rulesUnchanged.push_back( (*top).first );
  1111. rulesAdded.erase (find( rulesAdded.begin(),
  1112. rulesAdded.end(),
  1113. (*top).first ) );
  1114. }
  1115. else
  1116. {
  1117. // key is same but the other parts are modified.
  1118. rulesRemoved.push_back( (*top).first );
  1119. }
  1120. }
  1121. }
  1122. return CommonNLB_SUCCESS;
  1123. }
  1124. CommonNLB::CommonNLB_Error
  1125. CommonNLB::findPortRulesAddedUnchangedRemovedULB(
  1126. const ClusterData* oldSettings,
  1127. const ClusterData* newSettings,
  1128. DataSinkI* dataSinkObj,
  1129. vector<long>& rulesAdded,
  1130. vector<long>& rulesUnchanged,
  1131. vector<long>& rulesRemoved )
  1132. {
  1133. map<long, PortDataULB>::iterator top;
  1134. map<long, PortDataULB>::iterator location;
  1135. // find ports which have been newly added or modified.
  1136. //
  1137. for( top = newSettings->portULB.begin();
  1138. top != newSettings->portULB.end();
  1139. ++top )
  1140. {
  1141. rulesAdded.push_back( (*top).first );
  1142. }
  1143. // find ports which have remain unchanged and ports which have
  1144. // been removed or modified.
  1145. for( top = oldSettings->portULB.begin();
  1146. top != oldSettings->portULB.end();
  1147. ++top )
  1148. {
  1149. // check if this port rule has been removed or modified.
  1150. location = newSettings->portULB.find( (*top).first );
  1151. if( location == newSettings->portULB.end() )
  1152. {
  1153. // key has been removed
  1154. rulesRemoved.push_back( (*top).first );
  1155. }
  1156. else
  1157. {
  1158. // may be things other than key are modified or totally
  1159. // unchanged.
  1160. if( (*location).second == (*top).second )
  1161. {
  1162. // totally unchanged
  1163. rulesUnchanged.push_back( (*top).first );
  1164. rulesAdded.erase (find( rulesAdded.begin(),
  1165. rulesAdded.end(),
  1166. (*top).first ) );
  1167. }
  1168. else
  1169. {
  1170. // key is same but the other parts are modified.
  1171. rulesRemoved.push_back( (*top).first );
  1172. }
  1173. }
  1174. }
  1175. return CommonNLB_SUCCESS;
  1176. }
  1177. CommonNLB::CommonNLB_Error
  1178. CommonNLB::findPortRulesAddedUnchangedRemovedD(
  1179. const ClusterData* oldSettings,
  1180. const ClusterData* newSettings,
  1181. DataSinkI* dataSinkObj,
  1182. vector<long>& rulesAdded,
  1183. vector<long>& rulesUnchanged,
  1184. vector<long>& rulesRemoved )
  1185. {
  1186. map<long, PortDataD>::iterator top;
  1187. map<long, PortDataD>::iterator location;
  1188. // find ports which have been newly added or modified.
  1189. //
  1190. for( top = newSettings->portD.begin();
  1191. top != newSettings->portD.end();
  1192. ++top )
  1193. {
  1194. rulesAdded.push_back( (*top).first );
  1195. }
  1196. // find ports which have remain unchanged and ports which have
  1197. // been removed or modified.
  1198. for( top = oldSettings->portD.begin();
  1199. top != oldSettings->portD.end();
  1200. ++top )
  1201. {
  1202. // check if this port rule has been removed or modified.
  1203. location = newSettings->portD.find( (*top).first );
  1204. if( location == newSettings->portD.end() )
  1205. {
  1206. // key has been removed
  1207. rulesRemoved.push_back( (*top).first );
  1208. }
  1209. else
  1210. {
  1211. // may be things other than key are modified or totally
  1212. // unchanged.
  1213. if( (*location).second == (*top).second )
  1214. {
  1215. // totally unchanged
  1216. rulesUnchanged.push_back( (*top).first );
  1217. rulesAdded.erase (find( rulesAdded.begin(),
  1218. rulesAdded.end(),
  1219. (*top).first ) );
  1220. }
  1221. else
  1222. {
  1223. // key is same but the other parts are modified.
  1224. rulesRemoved.push_back( (*top).first );
  1225. }
  1226. }
  1227. }
  1228. return CommonNLB_SUCCESS;
  1229. }
  1230. CommonNLB::CommonNLB_Error
  1231. CommonNLB::findPortRulesAddedUnchangedRemovedF(
  1232. const ClusterData* oldSettings,
  1233. const ClusterData* newSettings,
  1234. DataSinkI* dataSinkObj,
  1235. vector<long>& rulesAdded,
  1236. vector<long>& rulesUnchanged,
  1237. vector<long>& rulesRemoved )
  1238. {
  1239. map<long, PortDataF>::iterator top;
  1240. map<long, PortDataF>::iterator location;
  1241. // find ports which have been newly added or modified.
  1242. //
  1243. for( top = newSettings->portF.begin();
  1244. top != newSettings->portF.end();
  1245. ++top )
  1246. {
  1247. rulesAdded.push_back( (*top).first );
  1248. }
  1249. // find ports which have remain unchanged and ports which have
  1250. // been removed or modified.
  1251. for( top = oldSettings->portF.begin();
  1252. top != oldSettings->portF.end();
  1253. ++top )
  1254. {
  1255. // check if this port rule has been removed or modified.
  1256. location = newSettings->portF.find( (*top).first );
  1257. if( location == newSettings->portF.end() )
  1258. {
  1259. // key has been removed
  1260. rulesRemoved.push_back( (*top).first );
  1261. }
  1262. else
  1263. {
  1264. // may be things other than key are modified or totally
  1265. // unchanged.
  1266. if( (*location).second == (*top).second )
  1267. {
  1268. // totally unchanged
  1269. rulesUnchanged.push_back( (*top).first );
  1270. rulesAdded.erase (find( rulesAdded.begin(),
  1271. rulesAdded.end(),
  1272. (*top).first ) );
  1273. }
  1274. else
  1275. {
  1276. // key is same but the other parts are modified.
  1277. rulesRemoved.push_back( (*top).first );
  1278. }
  1279. }
  1280. }
  1281. return CommonNLB_SUCCESS;
  1282. }
  1283. CommonNLB::CommonNLB_Error
  1284. CommonNLB::removeCluster( const ClusterData* clusterSettings,
  1285. DataSinkI* dataSinkObj )
  1286. {
  1287. map<_bstr_t, HostData>::iterator top;
  1288. for( top = clusterSettings->hosts.begin();
  1289. top != clusterSettings->hosts.end();
  1290. ++top )
  1291. {
  1292. removeHost( clusterSettings,
  1293. (*top).first,
  1294. dataSinkObj );
  1295. }
  1296. return CommonNLB_SUCCESS;
  1297. }
  1298. CommonNLB::CommonNLB_Error
  1299. CommonNLB::removeHost( const ClusterData* clusterSettings,
  1300. const _bstr_t& machineName,
  1301. DataSinkI* dataSinkObj )
  1302. {
  1303. ClusterData* clusterSettingsCopy =
  1304. const_cast <ClusterData *>( clusterSettings );
  1305. dataSinkObj->dataSink(
  1306. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING )
  1307. + clusterSettingsCopy->hosts[machineName].connectionIP );
  1308. // note that we are not responsible for freeing this pointer
  1309. // though if the removeClusterIP fails then we do need to free it.
  1310. // TODO
  1311. MNLBNetCfg* p_nlbNetCfg = new MNLBNetCfg(
  1312. clusterSettingsCopy->hosts[machineName].connectionIP,
  1313. clusterSettingsCopy->hosts[machineName].hp.nicInfo.fullNicName
  1314. );
  1315. dataSinkObj->dataSink(
  1316. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  1317. dataSinkObj->dataSink(
  1318. GETRESOURCEIDSTRING( IDS_INFO_REMOVING_CL_IP ) + clusterSettingsCopy->cp.cIP );
  1319. // remove cluster ip from machine specified.
  1320. p_nlbNetCfg->removeClusterIP(
  1321. clusterSettingsCopy->cp.cIP );
  1322. dataSinkObj->dataSink(
  1323. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  1324. dataSinkObj->dataSink(
  1325. GETRESOURCEIDSTRING( IDS_INFO_UNBINDING_NLB ) + clusterSettingsCopy->hosts[machineName].hp.nicInfo.fullNicName );
  1326. AfxBeginThread( (AFX_THREADPROC ) UnbindThread,
  1327. p_nlbNetCfg );
  1328. dataSinkObj->dataSink(
  1329. GETRESOURCEIDSTRING( IDS_INFO_REQUEST ) );
  1330. return CommonNLB_SUCCESS;
  1331. }
  1332. CommonNLB::CommonNLB_Error
  1333. CommonNLB::runControlMethodOnCluster( const ClusterData* clusterSettings,
  1334. DataSinkI* dataSinkObj,
  1335. const _bstr_t& methodToRun,
  1336. unsigned long portToAffect )
  1337. {
  1338. map<_bstr_t, HostData>::iterator top;
  1339. for( top = clusterSettings->hosts.begin();
  1340. top != clusterSettings->hosts.end();
  1341. ++top )
  1342. {
  1343. runControlMethodOnHost( clusterSettings,
  1344. (*top).first,
  1345. dataSinkObj,
  1346. methodToRun,
  1347. portToAffect );
  1348. }
  1349. return CommonNLB_SUCCESS;
  1350. }
  1351. CommonNLB::CommonNLB_Error
  1352. CommonNLB::runControlMethodOnHost( const ClusterData* clusterSettings,
  1353. const _bstr_t& machineName,
  1354. DataSinkI* dataSinkObj,
  1355. const _bstr_t& methodToRun,
  1356. unsigned long portToAffect )
  1357. {
  1358. ClusterData* clusterSettingsCopy =
  1359. const_cast <ClusterData *>( clusterSettings );
  1360. dataSinkObj->dataSink(
  1361. GETRESOURCEIDSTRING( IDS_INFO_CONNECTING )
  1362. + clusterSettingsCopy->hosts[machineName].connectionIP );
  1363. MNLBMachine nlbMachine(
  1364. clusterSettingsCopy->hosts[machineName].connectionIP,
  1365. clusterSettingsCopy->cp.cIP );
  1366. dataSinkObj->dataSink(
  1367. GETRESOURCEIDSTRING( IDS_INFO_DONE ) );
  1368. unsigned long retVal;
  1369. if( methodToRun == _bstr_t( L"query" ) )
  1370. {
  1371. dataSinkObj->dataSink(
  1372. GETRESOURCEIDSTRING( IDS_COMMAND_QUERY ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1373. // the hoststatus has the current state of the host.
  1374. HostProperties hp;
  1375. nlbMachine.getHostProperties( &hp );
  1376. retVal = hp.hostStatus;
  1377. }
  1378. else if( methodToRun == _bstr_t( L"start" ) )
  1379. {
  1380. dataSinkObj->dataSink(
  1381. GETRESOURCEIDSTRING( IDS_COMMAND_START ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1382. nlbMachine.start( Common::THIS_HOST, &retVal );
  1383. }
  1384. else if( methodToRun == _bstr_t( L"stop" ) )
  1385. {
  1386. dataSinkObj->dataSink(
  1387. GETRESOURCEIDSTRING( IDS_COMMAND_STOP ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1388. nlbMachine.stop( Common::THIS_HOST, &retVal );
  1389. }
  1390. else if( methodToRun == _bstr_t( L"drainstop" ) )
  1391. {
  1392. dataSinkObj->dataSink(
  1393. GETRESOURCEIDSTRING( IDS_COMMAND_DRAINSTOP ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1394. nlbMachine.drainstop( Common::THIS_HOST, &retVal );
  1395. }
  1396. else if( methodToRun == _bstr_t( L"resume" ) )
  1397. {
  1398. dataSinkObj->dataSink(
  1399. GETRESOURCEIDSTRING( IDS_COMMAND_RESUME ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1400. nlbMachine.resume( Common::THIS_HOST, &retVal );
  1401. }
  1402. else if( methodToRun == _bstr_t( L"suspend" ) )
  1403. {
  1404. dataSinkObj->dataSink(
  1405. GETRESOURCEIDSTRING( IDS_COMMAND_SUSPEND ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1406. nlbMachine.suspend( Common::THIS_HOST, &retVal );
  1407. }
  1408. else if( methodToRun == _bstr_t( L"enable" ) )
  1409. {
  1410. dataSinkObj->dataSink(
  1411. GETRESOURCEIDSTRING( IDS_COMMAND_ENABLE ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1412. nlbMachine.enable( Common::THIS_HOST, &retVal, portToAffect );
  1413. }
  1414. else if( methodToRun == _bstr_t( L"disable" ) )
  1415. {
  1416. dataSinkObj->dataSink(
  1417. GETRESOURCEIDSTRING( IDS_COMMAND_DISABLE ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1418. nlbMachine.disable( Common::THIS_HOST, &retVal, portToAffect );
  1419. }
  1420. else if( methodToRun == _bstr_t( L"drain" ) )
  1421. {
  1422. dataSinkObj->dataSink(
  1423. GETRESOURCEIDSTRING( IDS_COMMAND_DRAIN ) + clusterSettingsCopy->cp.cIP + L":" + machineName );
  1424. nlbMachine.drain( Common::THIS_HOST, &retVal, portToAffect );
  1425. }
  1426. else
  1427. {
  1428. // unknown method. It has to be one of above.
  1429. dataSinkObj->dataSink(
  1430. GETRESOURCEIDSTRING( IDS_WLBS_UNKNOWN ) );
  1431. }
  1432. // decipher the return.
  1433. _bstr_t errString;
  1434. getWLBSErrorString( retVal,
  1435. errString );
  1436. dataSinkObj->dataSink( errString );
  1437. return CommonNLB_SUCCESS;
  1438. }
  1439. // the unbinding is done in a separate thread
  1440. // as this call though successful, unloads and reloads the nic
  1441. // when nlb is unbound which can cause the connection to fail.
  1442. // This failure can occur after a very long time, which causes nlb
  1443. // manager to hang if this operation is not carried out in
  1444. // separate thread.
  1445. // Also note that the ownership of the MNLBNetCfg object is given
  1446. // to this thread, thus it is deleting this object. Thus caller
  1447. // needs to create the object on the heap, pass it in AfxBeginThread
  1448. // and be sure to not delete it.
  1449. UINT
  1450. CommonNLB::UnbindThread( LPVOID pParam )
  1451. {
  1452. MUsingCom com;
  1453. MNLBNetCfg* p_nlbNetCfg = ( MNLBNetCfg *) pParam;
  1454. try
  1455. {
  1456. p_nlbNetCfg->unbind();
  1457. }
  1458. catch( _com_error (e ) )
  1459. {
  1460. // the above call may fail, thus we want
  1461. // to catch exception.
  1462. }
  1463. delete p_nlbNetCfg;
  1464. return 0;
  1465. }
  1466. CommonNLB::CommonNLB_Error
  1467. CommonNLB::getWLBSErrorString( unsigned long errStatus, // IN
  1468. _bstr_t& extErrString // OUT
  1469. )
  1470. {
  1471. switch( errStatus )
  1472. {
  1473. case 1000 :
  1474. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_OK );
  1475. break;
  1476. case 1001 :
  1477. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_ALREADY );
  1478. break;
  1479. case 1002 :
  1480. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_DRAIN_STOP );
  1481. break;
  1482. case 1003 :
  1483. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_BAD_PARAMS );
  1484. break;
  1485. case 1004 :
  1486. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_NOT_FOUND );
  1487. break;
  1488. case 1005 :
  1489. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_STOPPED );
  1490. break;
  1491. case 1006 :
  1492. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_CONVERGING );
  1493. break;
  1494. case 1007 :
  1495. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_CONVERGED );
  1496. break;
  1497. case 1008 :
  1498. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_DEFAULT );
  1499. break;
  1500. case 1009 :
  1501. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_DRAINING );
  1502. break;
  1503. case 1013 :
  1504. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_SUSPENDED );
  1505. break;
  1506. case 1050 :
  1507. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_REBOOT );
  1508. break;
  1509. case 1100 :
  1510. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_INIT_ERROR );
  1511. break;
  1512. case 1101 :
  1513. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_BAD_PASSW );
  1514. break;
  1515. case 1102:
  1516. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_IO_ERROR );
  1517. break;
  1518. case 1103 :
  1519. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_TIMEOUT );
  1520. break;
  1521. case 1150 :
  1522. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_PORT_OVERLAP );
  1523. break;
  1524. case 1151 :
  1525. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_BAD_PORT_PARAMS );
  1526. break;
  1527. case 1152 :
  1528. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_MAX_PORT_RULES );
  1529. break;
  1530. case 1153 :
  1531. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_TRUNCATED );
  1532. break;
  1533. case 1154 :
  1534. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_REG_ERROR );
  1535. break;
  1536. default :
  1537. extErrString = GETRESOURCEIDSTRING( IDS_WLBS_UNKNOWN );
  1538. break;
  1539. }
  1540. return CommonNLB_SUCCESS;
  1541. }
  1542. CommonNLB::CommonNLB_Error
  1543. CommonNLB::addHostToCluster( const ClusterData* clusterToAddTo,
  1544. const _bstr_t& machineName,
  1545. DataSinkI* dataSinkObj )
  1546. {
  1547. ClusterData* clusterToAddToCopy =
  1548. const_cast <ClusterData *>( clusterToAddTo );
  1549. MNLBNetCfg* p_nlbNetCfg = NULL;
  1550. BindAndConfigureParameters* par = NULL;
  1551. try {
  1552. p_nlbNetCfg = new MNLBNetCfg(clusterToAddToCopy->hosts[machineName].connectionIP,
  1553. clusterToAddToCopy->hosts[machineName].hp.nicInfo.fullNicName
  1554. );
  1555. par = new BindAndConfigureParameters;
  1556. g_leftView = (LeftView *) dataSinkObj;
  1557. par->nlbNetCfg = p_nlbNetCfg;
  1558. par->clusterData = NULL;
  1559. par->machineName = NULL;
  1560. par->clusterData = new ClusterData( *clusterToAddToCopy );
  1561. par->machineName = new _bstr_t( machineName );
  1562. }
  1563. catch(...)
  1564. {
  1565. if (par != NULL)
  1566. {
  1567. delete par->machineName;
  1568. delete par->clusterData;
  1569. delete par;
  1570. }
  1571. delete p_nlbNetCfg;
  1572. dataSinkObj->dataSink(GETRESOURCEIDSTRING(IDS_INFO_NEW_EXCEPTION));
  1573. throw;
  1574. }
  1575. AfxBeginThread( (AFX_THREADPROC ) BindAndConfigureThread,
  1576. par );
  1577. return CommonNLB_SUCCESS;
  1578. }
  1579. // the binding and configuration is done in a separate thread
  1580. // as this call though successful, unloads and reloads the nic
  1581. // when nlb is bound which can cause the connection to fail.
  1582. // This failure can occur after a very long time, which causes nlb
  1583. // manager to hang if this operation is not carried out in
  1584. // separate thread.
  1585. // It is very important to ensure that you are completely sure
  1586. // that binding and configuration will succeed as this call will
  1587. // run in its separate thread and does not generate errors even if
  1588. // failure occurs.
  1589. //
  1590. // Also note that the ownership of the MNLBNetCfg object is given
  1591. // to this thread, thus it is deleting this object. Thus caller
  1592. // needs to create the object on the heap, pass it in AfxBeginThread
  1593. // and be sure to not delete it.
  1594. UINT
  1595. CommonNLB::BindAndConfigureThread( LPVOID pParam )
  1596. {
  1597. MUsingCom com;
  1598. BindAndConfigureParameters* parameters =
  1599. ( BindAndConfigureParameters *) pParam;
  1600. MNLBNetCfg* p_nlbNetCfg = parameters->nlbNetCfg;
  1601. ClusterData* p_clusterData = parameters->clusterData;
  1602. _bstr_t* p_machineName = parameters->machineName;
  1603. try
  1604. {
  1605. p_nlbNetCfg->bindAndConfigure(
  1606. p_clusterData,
  1607. *p_machineName );
  1608. }
  1609. catch( _com_error (e ) )
  1610. {
  1611. // the above call may fail, thus we want
  1612. // to catch exception.
  1613. }
  1614. delete p_nlbNetCfg;
  1615. delete p_clusterData;
  1616. delete p_machineName;
  1617. delete parameters;
  1618. return 0;
  1619. }
  1620. // the modification of cluster properties is done in a separate thread
  1621. // as this call though successful, might unload and reload the nic driver
  1622. // when nlb is bound which can cause the connection to fail.
  1623. // This failure can occur after a very long time, which causes nlb
  1624. // manager to hang if this operation is not carried out in
  1625. // separate thread.
  1626. // It is very important to ensure that you are completely sure
  1627. // that this operation will succeed as this call will
  1628. // run in its separate thread and does not generate errors even if
  1629. // failure occurs.
  1630. //
  1631. // Also note that the ownership of the MNLBNetCfg object is given
  1632. // to this thread, thus it is deleting this object. Thus caller
  1633. // needs to create the object on the heap, pass it in AfxBeginThread
  1634. // and be sure to not delete it.
  1635. UINT
  1636. CommonNLB::ModifyClusterPropertiesThread( LPVOID pParam )
  1637. {
  1638. MUsingCom com;
  1639. ModifyClusterPropertiesParameters* parameters =
  1640. ( ModifyClusterPropertiesParameters *) pParam;
  1641. MNLBNetCfg* p_nlbNetCfg = parameters->nlbNetCfg;
  1642. ClusterProperties* p_clusterProperties = &(parameters->clusterData->cp);
  1643. try
  1644. {
  1645. p_nlbNetCfg->modifyClusterProperties(p_clusterProperties);
  1646. }
  1647. catch( _com_error (e ) )
  1648. {
  1649. // the above call may fail, thus we want
  1650. // to catch exception.
  1651. }
  1652. delete p_nlbNetCfg;
  1653. delete parameters->clusterData;
  1654. delete parameters;
  1655. return 0;
  1656. }
  1657. UINT
  1658. CommonNLB::DummyThread( LPVOID pParam )
  1659. {
  1660. MUsingCom com;
  1661. Sleep( 1000 );
  1662. BindAndConfigureParameters* parameters =
  1663. ( BindAndConfigureParameters *) pParam;
  1664. LeftView * leftView = g_leftView;
  1665. TVINSERTSTRUCT item;
  1666. item.hParent = leftView->GetTreeCtrl().GetRootItem();
  1667. ClusterData* p_clusterDataItem;
  1668. HTREEITEM hNextItem;
  1669. HTREEITEM hChildItem;
  1670. if( leftView->GetTreeCtrl().ItemHasChildren( leftView->GetTreeCtrl().GetRootItem() ) )
  1671. {
  1672. hChildItem = leftView->GetTreeCtrl().GetChildItem(leftView->GetTreeCtrl().GetRootItem() );
  1673. while (hChildItem != NULL)
  1674. {
  1675. hNextItem = leftView->GetTreeCtrl().GetNextItem(hChildItem, TVGN_NEXT);
  1676. p_clusterDataItem = ( ClusterData * ) leftView->GetTreeCtrl().GetItemData( hChildItem );
  1677. if( p_clusterDataItem->cp.cIP == parameters->clusterData->cp.cIP )
  1678. {
  1679. // the cluster is found.
  1680. // get the exact host. Change icon of this host.
  1681. hChildItem = leftView->GetTreeCtrl().GetChildItem( hChildItem );
  1682. while( hChildItem != NULL )
  1683. {
  1684. hNextItem = leftView->GetTreeCtrl().GetNextItem(hChildItem, TVGN_NEXT);
  1685. _bstr_t* machineName = (_bstr_t *) leftView->GetTreeCtrl().GetItemData( hChildItem );
  1686. if( *( machineName ) == *(parameters->machineName) )
  1687. {
  1688. // found machine to change icon of.
  1689. leftView->GetTreeCtrl().SetItemImage( hChildItem, 5, 5 );
  1690. goto outofloop;
  1691. }
  1692. hChildItem = hNextItem;
  1693. }
  1694. }
  1695. hChildItem = hNextItem;
  1696. }
  1697. }
  1698. outofloop:
  1699. // loop for around let us say 1 minute.
  1700. // enable the icon.
  1701. Sleep( 10000 );
  1702. leftView->GetTreeCtrl().SetItemImage( hChildItem, 2, 2 );
  1703. return 0;
  1704. }