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.

418 lines
16 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CNode.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CNode class.
  10. //
  11. // Maintained By:
  12. // Vij Vasu (Vvasu) 08-MAR-2000
  13. //
  14. //////////////////////////////////////////////////////////////////////////////
  15. //////////////////////////////////////////////////////////////////////////////
  16. // Include Files
  17. //////////////////////////////////////////////////////////////////////////////
  18. // The precompiled header.
  19. #include "pch.h"
  20. // The header for this file
  21. #include "CNode.h"
  22. // For the CRegistryKey class
  23. #include "CRegistryKey.h"
  24. // For the CStr class
  25. #include "CStr.h"
  26. //////////////////////////////////////////////////////////////////////////////
  27. // Macros
  28. //////////////////////////////////////////////////////////////////////////////
  29. // Names of the sections in the main INF file which deal with node configuration
  30. // and cleanup.
  31. #define NODE_CONFIG_INF_SECTION L"Node_Create"
  32. #define NODE_CLEANUP_INF_SECTION L"Node_Cleanup"
  33. // Registry key storing the list of connections for the cluster administrator
  34. #define CLUADMIN_CONNECTIONS_KEY_NAME L"Software\\Microsoft\\Cluster Administrator\\Connections"
  35. // Name of the registry value storing the list of connections for the cluster administrator
  36. #define CLUADMIN_CONNECTIONS_VALUE_NAME L"Connections"
  37. //////////////////////////////////////////////////////////////////////////////
  38. //++
  39. //
  40. // CNode::CNode()
  41. //
  42. // Description:
  43. // Constructor of the CNode class
  44. //
  45. // Arguments:
  46. // pbcaParentActionIn
  47. // Pointer to the base cluster action of which this action is a part.
  48. //
  49. // Return Value:
  50. // None.
  51. //
  52. // Exceptions Thrown:
  53. // CAssert
  54. // If the parameters are incorrect.
  55. //
  56. // Any exceptions thrown by underlying functions
  57. //
  58. //--
  59. //////////////////////////////////////////////////////////////////////////////
  60. CNode::CNode(
  61. CBaseClusterAction * pbcaParentActionIn
  62. )
  63. : m_pbcaParentAction( pbcaParentActionIn )
  64. , m_fChangedConnectionsList( false )
  65. {
  66. BCATraceScope( "" );
  67. if ( m_pbcaParentAction == NULL)
  68. {
  69. BCATraceMsg( "Pointers to the parent action is NULL. Throwing exception." );
  70. THROW_ASSERT(
  71. E_INVALIDARG
  72. , "CNode::CNode() => Required input pointer in NULL"
  73. );
  74. } // if: the parent action pointer is NULL
  75. } //*** CNode::CNode()
  76. //////////////////////////////////////////////////////////////////////////////
  77. //++
  78. //
  79. // CNode::~CNode()
  80. //
  81. // Description:
  82. // Destructor of the CNode class.
  83. //
  84. // Arguments:
  85. // None.
  86. //
  87. // Return Value:
  88. // None.
  89. //
  90. // Exceptions Thrown:
  91. // Any exceptions thrown by underlying functions
  92. //
  93. //--
  94. //////////////////////////////////////////////////////////////////////////////
  95. CNode::~CNode( void )
  96. {
  97. BCATraceScope( "" );
  98. } //*** CNode::~CNode()
  99. //////////////////////////////////////////////////////////////////////////////
  100. //++
  101. //
  102. // void
  103. // CNode::Configure()
  104. //
  105. // Description:
  106. // Make the changes that need to be made when a node becomes part of a
  107. // cluster.
  108. //
  109. // Arguments:
  110. // rcstrClusterNameIn
  111. // Name of the cluster being configured.
  112. //
  113. // Return Value:
  114. // None.
  115. //
  116. // Exceptions Thrown:
  117. // CRuntimeError
  118. // If any of the APIs fail.
  119. //
  120. // Any that are thrown by the underlying functions.
  121. //
  122. //--
  123. //////////////////////////////////////////////////////////////////////////////
  124. void
  125. CNode::Configure( const CStr & rcstrClusterNameIn )
  126. {
  127. BCATraceScope( "" );
  128. //
  129. // Validate the parameter
  130. //
  131. if ( rcstrClusterNameIn.FIsEmpty() )
  132. {
  133. BCATraceMsg( "The name of the cluster is empty. Throwing exception." );
  134. THROW_ASSERT( E_INVALIDARG, "The name of the cluster cannot be empty." );
  135. } // if: the cluster name is not valid
  136. BCATraceMsg( "Attempting to make miscellaneous changes to the node." );
  137. // Process the registry keys.
  138. if ( SetupInstallFromInfSection(
  139. NULL // optional, handle of a parent window
  140. , m_pbcaParentAction->HGetMainInfFileHandle() // handle to the INF file
  141. , NODE_CONFIG_INF_SECTION // name of the Install section
  142. , SPINST_REGISTRY // which lines to install from section
  143. , NULL // optional, key for registry installs
  144. , NULL // optional, path for source files
  145. , NULL // optional, specifies copy behavior
  146. , NULL // optional, specifies callback routine
  147. , NULL // optional, callback routine context
  148. , NULL // optional, device information set
  149. , NULL // optional, device info structure
  150. ) == FALSE
  151. )
  152. {
  153. DWORD dwError = TW32( GetLastError() );
  154. BCATraceMsg1( "Setup API returned error %#08x while trying to make miscellaneous changes to the node. Throwing exception.", dwError );
  155. LogMsg( "Error %#08x occurred while trying to make miscellaneous changes to the node.", dwError );
  156. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_NODE_CONFIG );
  157. } // if: SetupInstallFromInfSection failed
  158. //
  159. // Add the name of the cluster that this node is a part of to the list of connections
  160. // that will be opened when the cluster administrator is started on this node.
  161. // The list of connections is a comma separated list of cluster names.
  162. //
  163. BCATraceMsg1( "Adding the cluster name '%s' to the list of cluadmin connections.", rcstrClusterNameIn.PszData() );
  164. // Reset the state.
  165. m_fChangedConnectionsList = false;
  166. m_sszOldConnectionsList.PRelease();
  167. do
  168. {
  169. WCHAR * pszConnectionsValue = NULL;
  170. DWORD cbConnectionsValueSize = 0;
  171. DWORD cchOldListLen = 0;
  172. CRegistryKey rkConnectionsKey;
  173. BCATraceMsg( "Trying to read the existing connections list." );
  174. // Open the cluster administrator connections key. Create it if it does not exist.
  175. rkConnectionsKey.CreateKey(
  176. HKEY_CURRENT_USER
  177. , CLUADMIN_CONNECTIONS_KEY_NAME
  178. );
  179. try
  180. {
  181. // Try and get the current value
  182. rkConnectionsKey.QueryValue(
  183. CLUADMIN_CONNECTIONS_VALUE_NAME
  184. , reinterpret_cast< LPBYTE * >( &pszConnectionsValue )
  185. , &cbConnectionsValueSize
  186. );
  187. } // try: to read the "Connections" value
  188. catch( CRuntimeError & crte )
  189. {
  190. // Check if this error occurred because the value did not exist
  191. if ( crte.HrGetErrorCode() == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) )
  192. {
  193. BCATraceMsg1( "The registry value '%s' does not exist. This is ok and is not an error.", CLUADMIN_CONNECTIONS_VALUE_NAME );
  194. LogMsg( "The registry value '%s' does not exist. This is ok and is not an error.", CLUADMIN_CONNECTIONS_VALUE_NAME );
  195. cchOldListLen = 0;
  196. } // if: the value does not exist
  197. else
  198. {
  199. throw;
  200. } // else: something else is wrong - rethrow the exception
  201. } // catch: the run time error that occurred
  202. // Number of characters in the old list, including the terminating NULL.
  203. cchOldListLen = cbConnectionsValueSize / sizeof( *pszConnectionsValue );
  204. if ( cchOldListLen <= 1 )
  205. {
  206. BCATraceMsg( "There are no existing cluadmin connections. Creating a new list with just one name in it." );
  207. // Write the cluster name to the value
  208. rkConnectionsKey.SetValue(
  209. CLUADMIN_CONNECTIONS_VALUE_NAME
  210. , REG_SZ
  211. , reinterpret_cast< const BYTE * >( rcstrClusterNameIn.PszData() )
  212. , ( rcstrClusterNameIn.NGetLen() + 1 ) * sizeof( WCHAR )
  213. );
  214. // We have changed the connections list.
  215. m_fChangedConnectionsList = true;
  216. } // if: there are no existing connections
  217. else
  218. {
  219. WCHAR * pszSubString = NULL;
  220. bool fIsInList = false;
  221. BCATraceMsg1( "The existing list of cluadmin connections is '%s'.", pszConnectionsValue );
  222. //
  223. // Is the cluster name already in the list of connections?
  224. //
  225. pszSubString = wcsstr( pszConnectionsValue, rcstrClusterNameIn.PszData() );
  226. while ( pszSubString != NULL )
  227. {
  228. //
  229. // The cluster name is a substring of the list.
  230. // Make sure that the cluster name is not a proper substring of an cluster name already in the list.
  231. //
  232. if ( (
  233. ( pszSubString == pszConnectionsValue ) // the substring was found at the beginning of the string
  234. || ( *( pszSubString - 1 ) == L',' ) // or the character before the substring is a comma
  235. ) // AND
  236. && ( ( *( pszSubString + rcstrClusterNameIn.NGetLen() ) == L'\0' ) // the character after the substring is a '\0'
  237. || ( *( pszSubString + rcstrClusterNameIn.NGetLen() ) == L',' ) // or character after the substring is a comma
  238. )
  239. )
  240. {
  241. fIsInList = true;
  242. break;
  243. } // if: the cluster name is not a proper substring of a cluster name that is already in the list
  244. // Continue searching.
  245. pszSubString = wcsstr( pszSubString + rcstrClusterNameIn.NGetLen(), rcstrClusterNameIn.PszData() );
  246. } // while: the cluster name is a substring of the list of existing connections
  247. if ( fIsInList )
  248. {
  249. // Nothing more to be done.
  250. BCATraceMsg1( "The cluster '%s' is already in the list of connections.", rcstrClusterNameIn.PszData() );
  251. break;
  252. } // if: the cluster name is already in the list
  253. BCATraceMsg1( "The cluster '%s' is not in the list of connections.", rcstrClusterNameIn.PszData() );
  254. // Store the current value in the member variable for restoration in case of error.
  255. m_sszOldConnectionsList.Assign( pszConnectionsValue );
  256. // Set the new connections value.
  257. {
  258. // Define a string to hold the new connections value. Preallocate its buffer.
  259. CStr strNewConnectionsValue(
  260. cchOldListLen // length of the old list ( including terminating '\0' )
  261. + 1 // for the comma
  262. + rcstrClusterNameIn.NGetLen() // length of the cluster name( including terminating '\0' )
  263. );
  264. //
  265. // Form the new list
  266. //
  267. strNewConnectionsValue = rcstrClusterNameIn;
  268. strNewConnectionsValue += L",";
  269. strNewConnectionsValue += m_sszOldConnectionsList.PMem();
  270. BCATraceMsg1( "Writing the new list of connections '%s'.", strNewConnectionsValue.PszData() );
  271. // Write the new list.
  272. rkConnectionsKey.SetValue(
  273. CLUADMIN_CONNECTIONS_VALUE_NAME
  274. , REG_SZ
  275. , reinterpret_cast< const BYTE * >( strNewConnectionsValue.PszData() )
  276. , ( strNewConnectionsValue.NGetLen() + 1 ) * sizeof( WCHAR )
  277. );
  278. // We have changed the connections list.
  279. m_fChangedConnectionsList = true;
  280. }
  281. } // else: there are existing connections
  282. }
  283. while( false ); // dummy do-while loop to avoid gotos
  284. BCATraceMsg( "The changes were made successfully." );
  285. } //*** CNode::Configure()
  286. //////////////////////////////////////////////////////////////////////////////
  287. //++
  288. //
  289. // void
  290. // CNode::Cleanup()
  291. //
  292. // Description:
  293. // Clean up the changes made to this node when it became part of a cluster.
  294. // Note that the changes made during Configure() are not really undone here -
  295. // we just bring the node back to an acceptable state. This is because,
  296. // without a transactional registry, it will be very diffult to get
  297. // the registry back to the exact state it was in before Configure() was
  298. // called.
  299. //
  300. // Arguments:
  301. // None.
  302. //
  303. // Return Value:
  304. // None.
  305. //
  306. // Exceptions Thrown:
  307. // Any that are thrown by the underlying functions.
  308. //
  309. //--
  310. //////////////////////////////////////////////////////////////////////////////
  311. void
  312. CNode::Cleanup( void )
  313. {
  314. BCATraceScope( "" );
  315. BCATraceMsg( "Attempting to cleanup changes made when this node was made a part of a cluster." );
  316. // Process the registry keys.
  317. if ( SetupInstallFromInfSection(
  318. NULL // optional, handle of a parent window
  319. , m_pbcaParentAction->HGetMainInfFileHandle() // handle to the INF file
  320. , NODE_CLEANUP_INF_SECTION // name of the Install section
  321. , SPINST_REGISTRY // which lines to install from section
  322. , NULL // optional, key for registry installs
  323. , NULL // optional, path for source files
  324. , NULL // optional, specifies copy behavior
  325. , NULL // optional, specifies callback routine
  326. , NULL // optional, callback routine context
  327. , NULL // optional, device information set
  328. , NULL // optional, device info structure
  329. ) == FALSE
  330. )
  331. {
  332. DWORD dwError = TW32( GetLastError() );
  333. BCATraceMsg1( "Setup API returned error %#08x while trying to cleanup miscellaneous changes. Throwing exception.", dwError );
  334. LogMsg( "Error %#08x occurred while trying to clean up miscellaneous changes.", dwError );
  335. THROW_RUNTIME_ERROR( HRESULT_FROM_WIN32( dwError ), IDS_ERROR_NODE_CLEANUP );
  336. } // if: SetupInstallFromInfSection failed
  337. if ( m_fChangedConnectionsList )
  338. {
  339. BCATraceMsg1( "Restoring the list of cluster administrator connections to '%s'", m_sszOldConnectionsList.PMem() );
  340. // Open the cluster administrator connections key.
  341. CRegistryKey rkConnectionsKey(
  342. HKEY_CURRENT_USER
  343. , CLUADMIN_CONNECTIONS_KEY_NAME
  344. );
  345. // Write the old list back.
  346. rkConnectionsKey.SetValue(
  347. CLUADMIN_CONNECTIONS_VALUE_NAME
  348. , REG_SZ
  349. , reinterpret_cast< const BYTE * >( m_sszOldConnectionsList.PMem() )
  350. , ( wcslen( m_sszOldConnectionsList.PMem() ) + 1 ) * sizeof( WCHAR )
  351. );
  352. } // if: we changed the list of cluadmin connections
  353. BCATraceMsg( "The cleanup was successfully." );
  354. } //*** CNode::Cleanup()