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.

429 lines
16 KiB

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