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.

2857 lines
71 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. iis.c
  5. Abstract:
  6. Resource DLL for IIS. This DLL supports the following IIS services
  7. WWW
  8. FTP
  9. Each instance of a resouce is an IIS instance ( a.k.a. virtual server )
  10. Virtual root may have dependencies on IP Addresses, Physical Disks, or UNC names.
  11. Known Limitations
  12. Author:
  13. Pete Benoit (v-pbenoi) 12-SEP-1996
  14. Revision History:
  15. Rich Demar (rdemar) 5-18-1999
  16. --*/
  17. #define INITGUID
  18. #include "iisutil.h"
  19. #include <clusapi.h>
  20. #include <resapi.h>
  21. //#include "resmonp.h"
  22. //#include "clusres.h"
  23. #include <pudebug.h>
  24. DECLARE_DEBUG_BUFFER;
  25. //
  26. // Names used to start service
  27. //
  28. LPCWSTR ActualServiceName[] = {
  29. L"W3SVC", // WWW
  30. L"MSFTPSVC", // FTP
  31. L"SMTPSVC", // SMTP
  32. L"NNTPSVC" // NNTP
  33. };
  34. #define PARAM_NAME__SERVICENAME L"ServiceName"
  35. #define PARAM_NAME__INSTANCEID L"InstanceId"
  36. #define MAX_SCMFAILURE_RETRY 5
  37. #define BACKOFF_MULTIPLIER 2
  38. #define DELAY_BETWEEN_ISALIVE_CHECKS 5*1000
  39. #define MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS 5*60*1000 // five minutes in milliseconds
  40. //
  41. // IIS resource private read-write parameters.
  42. //
  43. RESUTIL_PROPERTY_ITEM
  44. IISResourcePrivateProperties[] = {
  45. { PARAM_NAME__SERVICENAME, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(IIS_PARAMS,ServiceName) },
  46. { PARAM_NAME__INSTANCEID, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(IIS_PARAMS,InstanceId) },
  47. { 0 }
  48. };
  49. //
  50. // Global data.
  51. //
  52. CRITICAL_SECTION IISTableLock;
  53. LIST_ENTRY IISResourceTable;
  54. BOOL g_fIISResourceTable_HadChanged = FALSE;
  55. CLUS_WORKER g_cwAlivePollingThread;
  56. DWORD g_dwTickOfLastResourceCheck = 0;
  57. DWORD g_dwTlsCoInit = 0xffffffff;
  58. #if defined(DBG_CANT_VERIFY)
  59. BOOL g_fDbgCantVerify = FALSE;
  60. #endif
  61. LONG g_lOpenRefs = 0;
  62. bool g_fWinsockInitialized = false;
  63. PLOG_EVENT_ROUTINE g_IISLogEvent = NULL;
  64. PSET_RESOURCE_STATUS_ROUTINE IISSetResourceStatus = NULL;
  65. HANDLE g_hEventLog = NULL;
  66. extern CLRES_FUNCTION_TABLE IISFunctionTable;
  67. //
  68. // Forward routines
  69. //
  70. PWSTR
  71. IISGetParameter(
  72. IN HKEY ClusterKey,
  73. IN LPCWSTR ValueName
  74. );
  75. BOOL
  76. WINAPI
  77. IISIsAlive(
  78. IN RESID Resource
  79. );
  80. DWORD
  81. IISReadParameters(
  82. IN OUT LPIIS_RESOURCE ResourceEntry
  83. );
  84. DWORD
  85. IISBuildInternalParameters(
  86. IN OUT IIS_PARAMS* ResourceEntry
  87. );
  88. VOID
  89. IISInitializeParams(
  90. IN OUT IIS_PARAMS* Params
  91. );
  92. VOID
  93. IISFreeInternalParameters(
  94. IN IIS_PARAMS* Params
  95. );
  96. LPIIS_RESOURCE
  97. GetValidResource(
  98. IN RESID Resource,
  99. IN LPWSTR RoutineName
  100. );
  101. DWORD
  102. IISSetPrivateResProperties(
  103. IN OUT LPIIS_RESOURCE ResourceEntry,
  104. IN PVOID InBuffer,
  105. IN DWORD InBufferSize
  106. );
  107. DWORD
  108. IISGetPrivateResProperties(
  109. IN OUT LPIIS_RESOURCE ResourceEntry,
  110. OUT PVOID OutBuffer,
  111. IN DWORD OutBufferSize,
  112. OUT LPDWORD BytesReturned
  113. );
  114. DWORD
  115. IISValidatePrivateResProperties(
  116. IN OUT LPIIS_RESOURCE ResourceEntry,
  117. IN PVOID InBuffer,
  118. IN DWORD InBufferSize,
  119. OUT PIIS_PARAMS Params
  120. );
  121. void
  122. IISReplicateProperties(
  123. IN IIS_PARAMS* lpNewParams,
  124. IN IIS_PARAMS* lpOldParams
  125. );
  126. void
  127. IISSetRemoteNodeProperties(
  128. IN LPWSTR wcsNodeName,
  129. IN IIS_PARAMS* lpNewParams,
  130. IN IIS_PARAMS* lpOldParams
  131. );
  132. DWORD
  133. WINAPI
  134. IISAlivePollingThread(
  135. IN PCLUS_WORKER pWorker,
  136. IN LPVOID lpVoid );
  137. //
  138. // Function definitions
  139. //
  140. BOOLEAN
  141. IISInit(
  142. VOID
  143. )
  144. {
  145. WSADATA wsaData;
  146. INT serr;
  147. INIT_DEBUG;
  148. INITIALIZE_CRITICAL_SECTION(&IISTableLock);
  149. InitializeListHead(&IISResourceTable);
  150. g_dwTlsCoInit = TlsAlloc();
  151. SetCoInit( FALSE );
  152. g_hEventLog = RegisterEventSource( NULL, L"CLUSIIS4" );
  153. //
  154. // Initialize winsock support
  155. //
  156. serr = WSAStartup( MAKEWORD( 2, 0), &wsaData);
  157. if( serr == 0 )
  158. {
  159. g_fWinsockInitialized = true;
  160. }
  161. else
  162. {
  163. TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] WSAStartup failed with %08x\n",serr) );
  164. }
  165. return TRUE;
  166. }
  167. VOID
  168. IISCleanup()
  169. {
  170. DeleteCriticalSection(&IISTableLock);
  171. TlsFree( g_dwTlsCoInit );
  172. if ( g_hEventLog != NULL )
  173. {
  174. DeregisterEventSource( g_hEventLog );
  175. }
  176. if (g_fWinsockInitialized)
  177. {
  178. WSACleanup();
  179. }
  180. TERMINATE_DEBUG;
  181. }
  182. extern "C" BOOL WINAPI
  183. DllMain(
  184. IN HINSTANCE DllHandle,
  185. IN DWORD Reason,
  186. IN LPVOID Reserved
  187. )
  188. {
  189. switch( Reason )
  190. {
  191. case DLL_PROCESS_ATTACH:
  192. if ( !IISInit() )
  193. {
  194. return(FALSE);
  195. }
  196. break;
  197. case DLL_PROCESS_DETACH:
  198. IISCleanup();
  199. break;
  200. case DLL_THREAD_ATTACH:
  201. SetCoInit( FALSE );
  202. break;
  203. default:
  204. break;
  205. }
  206. return(TRUE);
  207. } // IISShareDllEntryPoint
  208. BOOLEAN
  209. StartIIS(
  210. LPIIS_RESOURCE ResourceEntry
  211. )
  212. /*++
  213. Routine Description:
  214. Start the IIS service
  215. Arguments:
  216. ResourceEntry - resource entry structure, includes name of service
  217. Return Value:
  218. TRUE - Success
  219. FALSE - Failure
  220. --*/
  221. {
  222. SC_HANDLE scManagerHandle;
  223. SC_HANDLE serviceHandle;
  224. DWORD errorCode;
  225. DWORD iPoll;
  226. SERVICE_STATUS ss;
  227. BOOL fSt = FALSE;
  228. INT iMaxWaitTime = 1000; // One second
  229. //
  230. // (# 261897) IIS cluster resources are failing to come online because "OpenSCManager" is failing with error "1723"
  231. //
  232. srand( (unsigned int)GetCurrentThreadId() );
  233. for(int iScmRetry=0; iScmRetry < MAX_SCMFAILURE_RETRY; iScmRetry++)
  234. {
  235. //
  236. // Open the service control manager
  237. //
  238. scManagerHandle = OpenSCManager( NULL, // local machine
  239. NULL, // ServicesActive database
  240. SC_MANAGER_ALL_ACCESS ); // all access
  241. if ( scManagerHandle == NULL )
  242. {
  243. if( iScmRetry == (MAX_SCMFAILURE_RETRY-1) )
  244. {
  245. (g_IISLogEvent)(
  246. ResourceEntry->ResourceHandle,
  247. LOG_ERROR,
  248. L"Unable to open Service Control Manager '%1!ws!'. Error: %2!u!. Reached maximum retries (%3!u!)\n",
  249. ResourceEntry->ResourceName,
  250. GetLastError(),
  251. iScmRetry );
  252. return FALSE;
  253. }
  254. else
  255. {
  256. (g_IISLogEvent)(
  257. ResourceEntry->ResourceHandle,
  258. LOG_ERROR,
  259. L"Unable to open Service Control Manager '%1!ws!'. Error: %2!u!. Retry attempt (%3!u!)\n",
  260. ResourceEntry->ResourceName,
  261. GetLastError(),
  262. iScmRetry );
  263. }
  264. Sleep( (DWORD)(rand() % iMaxWaitTime) );
  265. iMaxWaitTime *= BACKOFF_MULTIPLIER;
  266. }
  267. else
  268. {
  269. break;
  270. }
  271. }
  272. //
  273. // Open the service
  274. //
  275. serviceHandle = OpenService( scManagerHandle,
  276. ResourceEntry->Params.ServiceName, // Service Name
  277. SERVICE_ALL_ACCESS );
  278. TR( (DEBUG_BUFFER,"[StartIIS] starting %S\n", ResourceEntry->Params.ServiceName) );
  279. if ( serviceHandle == NULL )
  280. {
  281. CloseServiceHandle( scManagerHandle );
  282. return FALSE;
  283. }
  284. //
  285. // Make sure the service is running
  286. //
  287. if ( !StartService( serviceHandle,
  288. 0,
  289. NULL) )
  290. {
  291. errorCode = GetLastError();
  292. if ( errorCode == ERROR_SERVICE_ALREADY_RUNNING )
  293. {
  294. TR( (DEBUG_BUFFER,"[StartIIS] allready running\n") );
  295. fSt = TRUE;
  296. }
  297. }
  298. else
  299. {
  300. for ( iPoll = 0 ; iPoll < SERVICE_START_MAX_POLL ; ++iPoll )
  301. {
  302. if ( !QueryServiceStatus( serviceHandle, &ss ) )
  303. {
  304. break;
  305. }
  306. if ( ss.dwCurrentState == SERVICE_RUNNING )
  307. {
  308. fSt = TRUE;
  309. break;
  310. }
  311. //
  312. // Give the IIS Server a second to start up
  313. //
  314. Sleep( SERVICE_START_POLL_DELAY );
  315. }
  316. }
  317. //
  318. // Close open handles
  319. //
  320. CloseServiceHandle( serviceHandle );
  321. CloseServiceHandle( scManagerHandle);
  322. return (BOOLEAN)fSt;
  323. } // StartIIS
  324. DWORD
  325. WINAPI
  326. Startup(
  327. IN LPCWSTR ResourceType,
  328. IN DWORD MinVersionSupported,
  329. IN DWORD MaxVersionSupported,
  330. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  331. IN PLOG_EVENT_ROUTINE LogEvent,
  332. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  333. )
  334. /*++
  335. Routine Description:
  336. Startup a particular resource type. This means verifying the version
  337. requested, and returning the function table for this resource type.
  338. Arguments:
  339. ResourceType - Supplies the type of resource.
  340. MinVersionSupported - The minimum version number supported by the cluster
  341. service on this system.
  342. MaxVersionSupported - The maximum version number supported by the cluster
  343. service on this system.
  344. FunctionTable - Returns the Function Table for this resource type.
  345. Return Value:
  346. ERROR_SUCCESS if successful.
  347. A Win32 error code on failure.
  348. --*/
  349. {
  350. DWORD serviceType = MAX_SERVICE;
  351. DWORD i;
  352. HRESULT hRes;
  353. #if 1
  354. hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  355. if ( FAILED(hRes) )
  356. {
  357. TR( (DEBUG_BUFFER,"[Startup] fail CoInitialize %08x\n",hRes) );
  358. }
  359. #endif
  360. //
  361. // Search for a valid service name supported by this DLL
  362. //
  363. for ( i = 0; i < MAX_RESOURCE_TYPE; i++ )
  364. {
  365. if ( lstrcmpiW( ResourceType, RESOURCE_TYPE[i] ) == 0 )
  366. break;
  367. }
  368. if ( MAX_RESOURCE_TYPE == i )
  369. {
  370. TR( (DEBUG_BUFFER,"[Startup] bad resource type\n") );
  371. return ERROR_UNKNOWN_REVISION;
  372. }
  373. g_IISLogEvent = LogEvent;
  374. IISSetResourceStatus = SetResourceStatus;
  375. if ( (MinVersionSupported <= CLRES_VERSION_V1_00) &&
  376. (MaxVersionSupported >= CLRES_VERSION_V1_00) )
  377. {
  378. TR( (DEBUG_BUFFER,"[Startup] OK, leave\n") );
  379. *FunctionTable = &IISFunctionTable;
  380. return ERROR_SUCCESS;
  381. }
  382. TR( (DEBUG_BUFFER,"[Startup] revision mismatch\n") );
  383. return ERROR_REVISION_MISMATCH;
  384. } // Startup
  385. RESID
  386. WINAPI
  387. IISOpen(
  388. IN LPCWSTR ResourceName,
  389. IN HKEY ResourceKey,
  390. IN RESOURCE_HANDLE ResourceHandle
  391. )
  392. /*++
  393. Routine Description:
  394. Open routine for IIS resource.
  395. Arguments:
  396. ResourceName - supplies the resource name
  397. ResourceKey - Supplies handle to resource's cluster registry key.
  398. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  399. is called.
  400. Return Value:
  401. RESID of created resource
  402. Zero on failure
  403. --*/
  404. {
  405. DWORD status;
  406. DWORD readStatus;
  407. LPIIS_RESOURCE ResourceEntry;
  408. DWORD count;
  409. DWORD Index;
  410. DWORD serviceType = MAX_SERVICE;
  411. LPCWSTR ResourceType;
  412. HKEY hKey;
  413. TR( (DEBUG_BUFFER,"[IISOpen] Enter\n") );
  414. EnterCriticalSection(&IISTableLock);
  415. //
  416. // Check if IIS is installed
  417. //
  418. if ( ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  419. L"SYSTEM\\CurrentControlSet\\Services\\IISADMIN",
  420. 0,
  421. KEY_READ,
  422. &hKey))
  423. {
  424. LeaveCriticalSection(&IISTableLock);
  425. return (RESID)0;
  426. }
  427. else
  428. {
  429. RegCloseKey(hKey);
  430. }
  431. if ( g_lOpenRefs == 0 )
  432. {
  433. if ( !CMetaData::Init() )
  434. {
  435. LeaveCriticalSection(&IISTableLock);
  436. return (RESID)0;
  437. }
  438. }
  439. InterlockedIncrement( &g_lOpenRefs );
  440. LeaveCriticalSection(&IISTableLock);
  441. ResourceEntry = (LPIIS_RESOURCE)LocalAlloc( LMEM_FIXED, sizeof(IIS_RESOURCE) );
  442. if ( ResourceEntry == NULL )
  443. {
  444. (g_IISLogEvent)(
  445. ResourceHandle,
  446. LOG_ERROR,
  447. L"Unable to allocate IIS resource structure.\n");
  448. TR( (DEBUG_BUFFER,"[IISOpen] can't alloc ResourceEntry\n") );
  449. InterlockedDecrement( &g_lOpenRefs );
  450. return (RESID)0;
  451. }
  452. ZeroMemory( ResourceEntry, sizeof(IIS_RESOURCE) );
  453. ResourceEntry->Signature = IIS_RESOURCE_SIGNATURE;
  454. //
  455. // Set the resource handle for logging and init the virtual root entry
  456. //
  457. ResourceEntry->ResourceHandle = ResourceHandle;
  458. //
  459. // Read the Name of the resource, since the GUID is passed in.
  460. //
  461. ResourceEntry->ResourceName = IISGetParameter( ResourceKey, L"Name" );
  462. if ( ResourceEntry->ResourceName == NULL )
  463. {
  464. (g_IISLogEvent)(
  465. ResourceHandle,
  466. LOG_ERROR,
  467. L"Unable to read resource name.\n" );
  468. status = ERROR_RESOURCE_NOT_FOUND;
  469. FreeIISResource(ResourceEntry);
  470. LocalFree( ResourceEntry );
  471. TR( (DEBUG_BUFFER,"[IISOpen] Can't get name\n") );
  472. InterlockedDecrement( &g_lOpenRefs );
  473. return (RESID)0;
  474. }
  475. //
  476. // Open the Parameters key for this resource.
  477. //
  478. status = ClusterRegOpenKey( ResourceKey,
  479. L"Parameters",
  480. KEY_READ,
  481. &ResourceEntry->ParametersKey );
  482. if ( status != ERROR_SUCCESS )
  483. {
  484. (g_IISLogEvent)(
  485. ResourceHandle,
  486. LOG_ERROR,
  487. L"Unable to open parameters key for resource. Error: %1!u!.\n",
  488. status );
  489. FreeIISResource( ResourceEntry );
  490. LocalFree( ResourceEntry );
  491. TR( (DEBUG_BUFFER,"[IISOpen] Can't open parameters\n") );
  492. InterlockedDecrement( &g_lOpenRefs );
  493. return (RESID)0;
  494. }
  495. ResourceEntry->State = ClusterResourceOffline;
  496. //
  497. // If instance parameters exist, check instance stopped & marked cluster enabled
  498. //
  499. LPWSTR pwszServiceName = IISGetParameter( ResourceEntry->ParametersKey,
  500. PARAM_NAME__SERVICENAME );
  501. LPWSTR pwszInstanceId = IISGetParameter( ResourceEntry->ParametersKey,
  502. PARAM_NAME__INSTANCEID );
  503. if ( pwszServiceName && pwszInstanceId )
  504. {
  505. InstanceEnableCluster( pwszServiceName, pwszInstanceId );
  506. }
  507. if ( pwszServiceName )
  508. {
  509. LocalFree(pwszServiceName);
  510. }
  511. if ( pwszInstanceId )
  512. {
  513. LocalFree(pwszInstanceId);
  514. }
  515. //
  516. // Initialize the metadata path for this instance
  517. //
  518. ResourceEntry->Params.MDPath = NULL;
  519. //
  520. // Set the resource's initial state to alive
  521. //
  522. ResourceEntry->bAlive = TRUE ;
  523. //
  524. // If this is first element being added to the list than start the polling thread
  525. //
  526. if ( IsListEmpty (&IISResourceTable) )
  527. {
  528. //
  529. // Initialize the timestamp used in the isalive/looksalive to determine if the polling thread is still running
  530. //
  531. InterlockedExchange( (LPLONG) &g_dwTickOfLastResourceCheck, GetTickCount() );
  532. TR( (DEBUG_BUFFER,"[IISOpen] initialized g_dwTickOfLastResourceCheck (%d)\n", g_dwTickOfLastResourceCheck) );
  533. if( ERROR_SUCCESS != (status = ClusWorkerCreate( &g_cwAlivePollingThread,
  534. (PWORKER_START_ROUTINE)IISAlivePollingThread,
  535. &IISResourceTable)) )
  536. {
  537. TR( (DEBUG_BUFFER,"[IISOpen] Error creating IISAlivePollingThread %08x\n",status) );
  538. return (RESID)0;
  539. }
  540. TR( (DEBUG_BUFFER,"[IISOpen] created IISAlivePollingThread\n") );
  541. }
  542. //
  543. // Add to resource list
  544. //
  545. EnterCriticalSection(&IISTableLock);
  546. InsertHeadList( &IISResourceTable, &ResourceEntry->ListEntry );
  547. g_fIISResourceTable_HadChanged = TRUE;
  548. LeaveCriticalSection(&IISTableLock);
  549. (g_IISLogEvent)(
  550. ResourceHandle,
  551. LOG_INFORMATION,
  552. L"Open request succeeded with id = %1!u!.\n",
  553. ResourceEntry );
  554. TR( (DEBUG_BUFFER,"[IISOpen] token=%x Leave\n", ResourceEntry) );
  555. return (RESID)ResourceEntry;
  556. } // IISOpen
  557. DWORD
  558. WINAPI
  559. IISOnlineThread(
  560. IN PCLUS_WORKER pWorker,
  561. IN LPIIS_RESOURCE ResourceEntry
  562. )
  563. /*++
  564. Routine Description:
  565. Brings a share resource online.
  566. Arguments:
  567. ResourceEntry - A pointer to a IIS_RESOURCE block for this resource
  568. Returns:
  569. ERROR_SUCCESS if successful.
  570. Win32 error code on failure.
  571. --*/
  572. {
  573. DWORD status;
  574. DWORD retry;
  575. RESOURCE_STATUS resourceStatus;
  576. TR( (DEBUG_BUFFER,"[IISOnlineThread] Enter\n") );
  577. ResUtilInitializeResourceStatus( &resourceStatus );
  578. resourceStatus.ResourceState = ClusterResourceOnlinePending;
  579. resourceStatus.WaitHint = 0;
  580. resourceStatus.CheckPoint = 1;
  581. ResourceEntry->State = ClusterResourceOnlinePending;
  582. InterlockedExchange( (LPLONG) &ResourceEntry->bAlive, TRUE );
  583. if (IISReadParameters(ResourceEntry) != ERROR_SUCCESS)
  584. {
  585. (g_IISLogEvent)(
  586. ResourceEntry->ResourceHandle,
  587. LOG_ERROR,
  588. L"ERROR [OnLineThread] Could not read resource parameters\n");
  589. status = ERROR_RESOURCE_NOT_FOUND;
  590. TR( (DEBUG_BUFFER,"[IISOnlineThread] can't read parameters\n") );
  591. goto SendStatus;
  592. }
  593. (g_IISLogEvent)(
  594. ResourceEntry->ResourceHandle,
  595. LOG_INFORMATION,
  596. L"INFO [OnLineThread] Service = %1!ws! InstanceId = %2!ws!\n",
  597. ResourceEntry->Params.ServiceName,
  598. ResourceEntry->Params.InstanceId );
  599. //
  600. // get the server bindings information, if this fails should be able to pick the information up in the polling thread
  601. //
  602. if ( ERROR_SUCCESS != (status = GetServerBindings( ResourceEntry->Params.MDPath, ResourceEntry->Params.ServiceType, &ResourceEntry->saServer, &ResourceEntry->dwPort )) )
  603. {
  604. TR( (DEBUG_BUFFER,"[IISOnLineThread] failed to get server bindings for %S (%d)\n", ResourceEntry->Params.MDPath, status) );
  605. }
  606. //
  607. // Try to Online the resources
  608. //
  609. //
  610. if ( !StartIIS( ResourceEntry ) )
  611. {
  612. status = ERROR_SERVICE_REQUEST_TIMEOUT;
  613. resourceStatus.ResourceState = ClusterResourceFailed;
  614. ResourceEntry->State = ClusterResourceFailed;
  615. TR( (DEBUG_BUFFER,"[IISOnlineThread] can't start IIS\n") );
  616. }
  617. else
  618. {
  619. status = SetInstanceState( pWorker,
  620. ResourceEntry,
  621. &resourceStatus,
  622. ClusterResourceOnline,
  623. L"online",
  624. MD_SERVER_COMMAND_START,
  625. MD_SERVER_STATE_STARTED );
  626. }
  627. SendStatus:
  628. //
  629. // Set the state of the resource
  630. //
  631. (IISSetResourceStatus)( ResourceEntry->ResourceHandle,
  632. &resourceStatus );
  633. TR( (DEBUG_BUFFER,"[IISOnlineThread] status = %d, Leave\n",status) );
  634. return status;
  635. } // IISOnlineThread
  636. DWORD
  637. WINAPI
  638. IISOfflineThread(
  639. IN PCLUS_WORKER pWorker,
  640. IN LPIIS_RESOURCE ResourceEntry
  641. )
  642. /*++
  643. Routine Description:
  644. Brings a share resource offline.
  645. Arguments:
  646. ResourceEntry - A pointer to a IIS_RESOURCE block for this resource
  647. Returns:
  648. ERROR_SUCCESS if successful.
  649. Win32 error code on failure.
  650. --*/
  651. {
  652. DWORD status;
  653. DWORD retry;
  654. RESOURCE_STATUS resourceStatus;
  655. TR( (DEBUG_BUFFER,"[IISOfflineThread] Enter\n") );
  656. #if defined(DBG_CANT_VERIFY)
  657. if ( g_fDbgCantVerify )
  658. {
  659. TR( (DEBUG_BUFFER,"[IISOfflineThread] skip stop after failure to verify service\n") );
  660. return ERROR_INVALID_PARAMETER;
  661. }
  662. #endif
  663. ResUtilInitializeResourceStatus( &resourceStatus );
  664. resourceStatus.ResourceState = ClusterResourceOfflinePending;
  665. resourceStatus.WaitHint = 0;
  666. resourceStatus.CheckPoint = 1;
  667. ResourceEntry->State = ClusterResourceOfflinePending;
  668. if (IISReadParameters(ResourceEntry) != ERROR_SUCCESS)
  669. {
  670. (g_IISLogEvent)(
  671. ResourceEntry->ResourceHandle,
  672. LOG_ERROR,
  673. L"ERROR [OffLineThread] Could not read resource parameters\n");
  674. status = ERROR_RESOURCE_NOT_FOUND;
  675. goto SendStatus;
  676. }
  677. (g_IISLogEvent)(
  678. ResourceEntry->ResourceHandle,
  679. LOG_INFORMATION,
  680. L"INFO [OffLineThread] Service = %1!ws! InstanceId = %2!ws!\n",
  681. ResourceEntry->Params.ServiceName,
  682. ResourceEntry->Params.InstanceId );
  683. //
  684. // Try to Offline the resources
  685. //
  686. //
  687. status = SetInstanceState( pWorker, ResourceEntry, &resourceStatus, ClusterResourceOffline, L"offline", MD_SERVER_COMMAND_STOP, MD_SERVER_STATE_STOPPED );
  688. SendStatus:
  689. //
  690. // Set the state of the resource
  691. //
  692. (IISSetResourceStatus)( ResourceEntry->ResourceHandle,
  693. &resourceStatus );
  694. TR( (DEBUG_BUFFER,"[IISOfflineThread] status = %d, Leave\n",status) );
  695. return(status);
  696. } // IISOfflineThread
  697. DWORD
  698. WINAPI
  699. IISOnline(
  700. IN RESID Resource,
  701. IN OUT PHANDLE EventHandle
  702. )
  703. /*++
  704. Routine Description:
  705. Online routine for IIS resource.
  706. Arguments:
  707. Resource - supplies resource id to be brought online
  708. EventHandle - supplies a pointer to a handle to signal on error.
  709. Return Value:
  710. ERROR_SUCCESS if successful.
  711. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  712. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  713. acquire 'ownership'.
  714. Win32 error code if other failure.
  715. --*/
  716. {
  717. LPIIS_RESOURCE ResourceEntry = NULL;
  718. DWORD status;
  719. TR( (DEBUG_BUFFER,"[IISOnline] Enter\n") );
  720. //
  721. // Get a valid resource
  722. //
  723. ResourceEntry = GetValidResource(Resource,L"OnLine");
  724. if ( ResourceEntry == NULL )
  725. {
  726. return ERROR_RESOURCE_NOT_FOUND;
  727. }
  728. //
  729. // Log the online request
  730. //
  731. (g_IISLogEvent)(
  732. ResourceEntry->ResourceHandle,
  733. LOG_INFORMATION,
  734. L"Online request for IIS Resource %1!u! (%2!ws!).\n",
  735. Resource,
  736. ResourceEntry->ResourceName );
  737. // Terminate (or wait) for workers
  738. ClusWorkerTerminate( &ResourceEntry->OnlineThread );
  739. ClusWorkerTerminate( &ResourceEntry->OfflineThread );
  740. status = ClusWorkerCreate( &ResourceEntry->OnlineThread,
  741. (PWORKER_START_ROUTINE)IISOnlineThread,
  742. ResourceEntry );
  743. if ( status == ERROR_SUCCESS )
  744. {
  745. return ERROR_IO_PENDING;
  746. }
  747. //
  748. // Failure
  749. //
  750. (g_IISLogEvent)(
  751. ResourceEntry->ResourceHandle,
  752. LOG_ERROR,
  753. L"Online request failed, error %1!u!.\n",
  754. GetLastError() );
  755. TR( (DEBUG_BUFFER,"[IISOnline] failed %d, Leave\n",GetLastError()) );
  756. return status;
  757. } // IISOnline
  758. VOID
  759. WINAPI
  760. IISTerminate(
  761. IN RESID Resource
  762. )
  763. /*++
  764. Routine Description:
  765. Terminate routine for IIS resource.
  766. Arguments:
  767. Resource - supplies resource id to be terminated
  768. Return Value:
  769. None.
  770. --*/
  771. {
  772. DWORD status;
  773. LPIIS_RESOURCE ResourceEntry;
  774. DWORD dwS;
  775. int retry;
  776. TR( (DEBUG_BUFFER,"[IISTerminate] Enter\n") );
  777. #if defined(DBG_CANT_VERIFY)
  778. if ( g_fDbgCantVerify )
  779. {
  780. TR( (DEBUG_BUFFER,"[IISTerminate] skip stop after failure to verify service\n") );
  781. return;
  782. }
  783. #endif
  784. //
  785. // Get a valid resource entry, return on error
  786. //
  787. ResourceEntry = GetValidResource(Resource,L"Terminate");
  788. if (ResourceEntry == NULL)
  789. {
  790. return;
  791. }
  792. (g_IISLogEvent)(
  793. ResourceEntry->ResourceHandle,
  794. LOG_INFORMATION,
  795. L"Terminate or offline request for Resource%1!u! (%2!ws!).\n",
  796. Resource,
  797. ResourceEntry->ResourceName );
  798. //
  799. // Try to take the resources offline, dont return if an error since
  800. // the resources may be offline when terminate called
  801. //
  802. //
  803. // Terminate the Online & Offline Threads
  804. //
  805. ClusWorkerTerminate( &ResourceEntry->OnlineThread);
  806. ClusWorkerTerminate( &ResourceEntry->OfflineThread);
  807. status = ERROR_SERVICE_NOT_ACTIVE;
  808. CMetaData MD;
  809. if ( MD.Open( ResourceEntry->Params.MDPath,
  810. FALSE,
  811. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
  812. {
  813. if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  814. {
  815. TR( (DEBUG_BUFFER,"[IISTerminate] state prob is %d\n",dwS) );
  816. }
  817. else
  818. {
  819. TR( (DEBUG_BUFFER,"[IISTerminate] failed to probe server state\n") );
  820. dwS = 0xffffffff;
  821. }
  822. if ( dwS != MD_SERVER_STATE_STOPPED )
  823. {
  824. if ( MD.SetDword( L"", MD_CLUSTER_SERVER_COMMAND, IIS_MD_UT_SERVER, MD_SERVER_COMMAND_STOP, 0 ) )
  825. {
  826. MD.Close();
  827. TR( (DEBUG_BUFFER,"[IISTerminate] command set to %d\n",MD_SERVER_COMMAND_STOP) );
  828. status = ERROR_SUCCESS;
  829. for ( retry = 3 ; retry-- ; )
  830. {
  831. if ( MD.GetDword( ResourceEntry->Params.MDPath, MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  832. {
  833. if ( dwS == MD_SERVER_STATE_STOPPED )
  834. {
  835. break;
  836. }
  837. }
  838. else
  839. {
  840. TR( (DEBUG_BUFFER,"[IISTerminate] failed to get server state\n") );
  841. break;
  842. }
  843. Sleep(SERVER_START_DELAY);
  844. }
  845. }
  846. else
  847. {
  848. MD.Close();
  849. TR( (DEBUG_BUFFER,"[IISTerminate] failed to set command to %d\n",MD_SERVER_COMMAND_STOP) );
  850. }
  851. }
  852. else
  853. {
  854. status = ERROR_SUCCESS;
  855. MD.Close();
  856. }
  857. }
  858. if ( status != ERROR_SUCCESS )
  859. {
  860. (g_IISLogEvent)(
  861. ResourceEntry->ResourceHandle,
  862. LOG_ERROR,
  863. L"Error removing Resource. Error %1!u!. Resource. %2!ws! Service. %3!ws!\n",
  864. status,
  865. ResourceEntry->ResourceName,
  866. ResourceEntry->Params.ServiceName);
  867. }
  868. //
  869. // Set status to offline
  870. //
  871. ResourceEntry->State = ClusterResourceOffline;
  872. TR( (DEBUG_BUFFER,"[IISTerminate] Leave\n") );
  873. } // IISTerminate
  874. DWORD
  875. WINAPI
  876. IISOffline(
  877. IN RESID Resource
  878. )
  879. /*++
  880. Routine Description:
  881. Offline routine for IIS resource.
  882. Arguments:
  883. Resource - supplies the resource it to be taken offline
  884. Return Value:
  885. ERROR_SUCCESS - always successful.
  886. --*/
  887. {
  888. LPIIS_RESOURCE ResourceEntry = NULL;
  889. DWORD status;
  890. //
  891. // Get a valid resource
  892. //
  893. ResourceEntry = GetValidResource(Resource,L"OffLine");
  894. if ( ResourceEntry == NULL )
  895. {
  896. return ERROR_RESOURCE_NOT_FOUND;
  897. }
  898. //
  899. // Log the online request
  900. //
  901. (g_IISLogEvent)(
  902. ResourceEntry->ResourceHandle,
  903. LOG_INFORMATION,
  904. L"Offline request for IIS Resource %1!u! (%2!ws!).\n",
  905. Resource,
  906. ResourceEntry->ResourceName );
  907. // Terminate (or wait) for workers
  908. ClusWorkerTerminate( &ResourceEntry->OnlineThread );
  909. ClusWorkerTerminate( &ResourceEntry->OfflineThread );
  910. status = ClusWorkerCreate( &ResourceEntry->OfflineThread,
  911. (PWORKER_START_ROUTINE)IISOfflineThread,
  912. ResourceEntry );
  913. if ( status == ERROR_SUCCESS )
  914. {
  915. return ERROR_IO_PENDING;
  916. }
  917. //
  918. // Failure
  919. //
  920. (g_IISLogEvent)(
  921. ResourceEntry->ResourceHandle,
  922. LOG_ERROR,
  923. L"Offline request failed, error %1!u!.\n",
  924. GetLastError() );
  925. return status;
  926. } // IISOffline
  927. BOOL
  928. WINAPI
  929. IISIsAlive(
  930. IN RESID Resource
  931. )
  932. /*++
  933. Routine Description:
  934. IsAlive routine for IIS service resource.
  935. Arguments:
  936. Resource - supplies the resource id to be polled.
  937. Return Value:
  938. TRUE - if service is running
  939. FALSE - if service is in any other state
  940. --*/
  941. {
  942. LPIIS_RESOURCE ResourceEntry;
  943. DWORD dwTickDifference = 0;
  944. DWORD dwCurrent;
  945. DWORD dwTickOfLastResourceCheck = 0;
  946. //
  947. // Get a valid resource
  948. //
  949. ResourceEntry = GetValidResource(Resource,L"IsAlive");
  950. if (ResourceEntry == NULL)
  951. {
  952. return(FALSE);
  953. }
  954. //
  955. // Save the current global tick count so it can't change during the calculation
  956. //
  957. dwTickOfLastResourceCheck = g_dwTickOfLastResourceCheck;
  958. //
  959. // Save the current tick count
  960. //
  961. dwCurrent = GetTickCount();
  962. if (dwCurrent >= g_dwTickOfLastResourceCheck)
  963. {
  964. dwTickDifference = dwCurrent - g_dwTickOfLastResourceCheck ;
  965. }
  966. else
  967. {
  968. dwTickDifference = (0xFFFFFFFF - g_dwTickOfLastResourceCheck) + dwCurrent ;
  969. }
  970. //
  971. // if the polling thread is taking too long there must be a problem
  972. //
  973. if ( dwTickDifference > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS)
  974. {
  975. TR( (DEBUG_BUFFER,"[IsAlive] (dwTickDifference(%d) > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS) returning FALSE dwCurrent(%d) dwTickOfLastResourceCheck(%d)\n", dwTickDifference, dwCurrent, dwTickOfLastResourceCheck) );
  976. return FALSE;
  977. }
  978. return ResourceEntry->bAlive ;
  979. } // IISIsAlive
  980. BOOL
  981. WINAPI
  982. IISLooksAlive(
  983. IN RESID Resource
  984. )
  985. /*++
  986. Routine Description:
  987. LooksAlive routine for IIS resource.
  988. Arguments:
  989. Resource - supplies the resource id to be polled.
  990. Return Value:
  991. TRUE - Resource looks like it is alive and well
  992. FALSE - Resource looks like it is toast.
  993. --*/
  994. {
  995. LPIIS_RESOURCE ResourceEntry;
  996. DWORD dwTickDifference = 0;
  997. DWORD dwCurrent;
  998. DWORD dwTickOfLastResourceCheck = 0;
  999. //
  1000. // Get a valid resource
  1001. //
  1002. ResourceEntry = GetValidResource(Resource,L"LooksAlive");
  1003. if (ResourceEntry == NULL)
  1004. {
  1005. return(FALSE);
  1006. }
  1007. //
  1008. // Save the current global tick count so it can't change during the calculation
  1009. //
  1010. dwTickOfLastResourceCheck = g_dwTickOfLastResourceCheck;
  1011. //
  1012. // Save the current tick count
  1013. //
  1014. dwCurrent = GetTickCount();
  1015. if (dwCurrent >= g_dwTickOfLastResourceCheck)
  1016. {
  1017. dwTickDifference = dwCurrent - g_dwTickOfLastResourceCheck ;
  1018. }
  1019. else
  1020. {
  1021. dwTickDifference = (0xFFFFFFFF - g_dwTickOfLastResourceCheck) + dwCurrent ;
  1022. }
  1023. //
  1024. // if the polling thread is taking too long there must be a problem
  1025. //
  1026. if ( dwTickDifference > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS )
  1027. {
  1028. TR( (DEBUG_BUFFER,"[LooksAlive] (dwTickDifference(%d) > MAX_DIFFERENCE_BETWEEN_RESOURCE_CHECKS) returning FALSE dwCurrent(%d) dwTickOfLastResourceCheck(%d)\n", dwTickDifference, dwCurrent, dwTickOfLastResourceCheck) );
  1029. return FALSE;
  1030. }
  1031. return ResourceEntry->bAlive ;
  1032. } // IISLooksAlive
  1033. VOID
  1034. WINAPI
  1035. IISClose(
  1036. IN RESID Resource
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. Close routine for IIS resource.
  1041. Arguments:
  1042. Resource - supplies resource id to be closed
  1043. Return Value:
  1044. None.
  1045. --*/
  1046. {
  1047. LPIIS_RESOURCE ResourceEntry = NULL;
  1048. //
  1049. // Get a valid resource
  1050. //
  1051. ResourceEntry = GetValidResource( Resource, L"Close");
  1052. if (ResourceEntry == NULL)
  1053. {
  1054. return; // this should not happen
  1055. }
  1056. (g_IISLogEvent)(
  1057. ResourceEntry->ResourceHandle,
  1058. LOG_INFORMATION,
  1059. L"Close request for resource '%1!ws!' Service '%2!ws!' \n",
  1060. ResourceEntry->ResourceName,
  1061. ResourceEntry->Params.ServiceName);
  1062. //
  1063. // Remove from list
  1064. //
  1065. EnterCriticalSection(&IISTableLock);
  1066. RemoveEntryList( &ResourceEntry->ListEntry );
  1067. g_fIISResourceTable_HadChanged = TRUE;
  1068. DestructIISResource(ResourceEntry);
  1069. if ( g_lOpenRefs > 0 )
  1070. {
  1071. if ( !InterlockedDecrement( &g_lOpenRefs ) )
  1072. {
  1073. CMetaData::Terminate();
  1074. }
  1075. }
  1076. LeaveCriticalSection(&IISTableLock);
  1077. //
  1078. // If this was the last resource in the list than stop the polling thread
  1079. //
  1080. if ( IsListEmpty (&IISResourceTable) )
  1081. {
  1082. ClusWorkerTerminate( &g_cwAlivePollingThread );
  1083. TR( (DEBUG_BUFFER,"[IISClose] Terminated IISAlivePollingThread\n") );
  1084. }
  1085. } // IISClose
  1086. LPIIS_RESOURCE
  1087. GetValidResource(
  1088. IN RESID Resource,
  1089. IN LPWSTR RoutineName
  1090. )
  1091. /*++
  1092. Routine Description:
  1093. Validate the resource ID, log any error, return valid resource
  1094. Arguments:
  1095. Resource - the resource to validate
  1096. RoutineName - the routine that is requesting the validation
  1097. Return Value:
  1098. Success - ResourceEntry
  1099. NULL - Error
  1100. --*/
  1101. {
  1102. DWORD Index;
  1103. LPIIS_RESOURCE ResourceEntry;
  1104. ResourceEntry = (LPIIS_RESOURCE)Resource;
  1105. //
  1106. // Check for a valid
  1107. //
  1108. if ( ResourceEntry == NULL )
  1109. {
  1110. (g_IISLogEvent)(
  1111. NULL,
  1112. LOG_ERROR,
  1113. L"[%1!ws!] Resource Entry is NULL for Resource Id = %2!u!\n",
  1114. RoutineName,
  1115. Resource);
  1116. return NULL;
  1117. }
  1118. //
  1119. // Sanity check the resource struct
  1120. //
  1121. if ( ResourceEntry->Signature != IIS_RESOURCE_SIGNATURE )
  1122. {
  1123. (g_IISLogEvent)(
  1124. ResourceEntry->ResourceHandle,
  1125. LOG_ERROR,
  1126. L"[%1!ws!] IIS Resource index sanity checked failed! Index = %2!u!.\n",
  1127. RoutineName,
  1128. Resource );
  1129. return NULL;
  1130. }
  1131. return ResourceEntry;
  1132. } // END GetValidResource
  1133. PWSTR
  1134. IISGetParameter(
  1135. IN HKEY ClusterKey,
  1136. IN LPCWSTR ValueName
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. Queries a REG_SZ parameter out of the registry and allocates the
  1141. necessary storage for it.
  1142. Arguments:
  1143. ClusterKey - Supplies the cluster key where the parameter is stored
  1144. ValueName - Supplies the name of the value.
  1145. Return Value:
  1146. A pointer to a buffer containing the parameter if successful.
  1147. NULL if unsuccessful.
  1148. --*/
  1149. {
  1150. PWSTR Value;
  1151. PWSTR Value2;
  1152. DWORD ValueLength;
  1153. DWORD ValueType;
  1154. DWORD Status;
  1155. ValueLength = 0;
  1156. Status = ClusterRegQueryValue(ClusterKey,
  1157. ValueName,
  1158. &ValueType,
  1159. NULL,
  1160. &ValueLength);
  1161. if ( (Status != ERROR_SUCCESS) &&
  1162. (Status != ERROR_MORE_DATA) )
  1163. {
  1164. TR( (DEBUG_BUFFER,"[IISGetParameter] Failed to open %S, error %u\n",ValueName,Status) );
  1165. return(NULL);
  1166. }
  1167. //
  1168. // Add on the size of the null terminator.
  1169. //
  1170. ValueLength += sizeof(UNICODE_NULL);
  1171. Value = (WCHAR*)LocalAlloc(LMEM_FIXED, ValueLength);
  1172. if (Value == NULL)
  1173. {
  1174. return(NULL);
  1175. }
  1176. Status = ClusterRegQueryValue(ClusterKey,
  1177. ValueName,
  1178. &ValueType,
  1179. (LPBYTE)Value,
  1180. &ValueLength);
  1181. if (Status != ERROR_SUCCESS)
  1182. {
  1183. LocalFree(Value);
  1184. Value = NULL;
  1185. }
  1186. else
  1187. {
  1188. //
  1189. // Numeric value are prefixed with '!' to force them to be stored as string,
  1190. // so remove leading '!' if present
  1191. //
  1192. if ( Value[0] == L'!' )
  1193. {
  1194. Value2 = (WCHAR*)LocalAlloc(LMEM_FIXED, ValueLength);
  1195. if (Value2 == NULL)
  1196. {
  1197. LocalFree( Value );
  1198. return(NULL);
  1199. }
  1200. wcscpy( Value2, Value + 1 );
  1201. LocalFree( Value );
  1202. Value = Value2;
  1203. }
  1204. }
  1205. TR( (DEBUG_BUFFER,"[IISGetParameter] Read %S, length %d, value %S\n",ValueName,ValueLength,Value?Value:L"ERROR") );
  1206. return(Value);
  1207. } // IISGetParameter
  1208. LPWSTR
  1209. GetResourceParameter(
  1210. IN HRESOURCE hResource,
  1211. IN LPCWSTR ValueName
  1212. )
  1213. /*++
  1214. Routine Description:
  1215. Opens the parameter key for the resource. Then Queries a REG_SZ parameter
  1216. out of the registry and allocates the necessary storage for it.
  1217. Arguments:
  1218. hResource - the resource to query
  1219. ValueName - Supplies the name of the value.
  1220. Return Value:
  1221. A pointer to a buffer containing the parameter if successful.
  1222. NULL if unsuccessful.
  1223. --*/
  1224. {
  1225. HKEY hKey = NULL;
  1226. HKEY hParametersKey = NULL;
  1227. DWORD status;
  1228. LPWSTR paramValue = NULL;
  1229. //
  1230. // Get Resource key
  1231. //
  1232. hKey = GetClusterResourceKey(hResource,KEY_READ);
  1233. if (hKey == NULL)
  1234. {
  1235. return(NULL);
  1236. }
  1237. //
  1238. // Get parameters key
  1239. //
  1240. status = ClusterRegOpenKey(hKey,
  1241. L"Parameters",
  1242. KEY_READ,
  1243. &hParametersKey );
  1244. if (status != ERROR_SUCCESS)
  1245. {
  1246. goto error_exit;
  1247. }
  1248. paramValue = IISGetParameter(hParametersKey,ValueName);
  1249. if (paramValue == NULL)
  1250. {
  1251. goto error_exit;
  1252. }
  1253. error_exit:
  1254. if (hParametersKey != NULL)
  1255. {
  1256. ClusterRegCloseKey(hParametersKey);
  1257. }
  1258. if (hKey != NULL)
  1259. {
  1260. ClusterRegCloseKey(hKey);
  1261. }
  1262. return(paramValue);
  1263. } // GetResourceParameter
  1264. DWORD
  1265. IISReadParameters(
  1266. IN OUT LPIIS_RESOURCE ResourceEntry
  1267. )
  1268. /*++
  1269. Routine Description:
  1270. Reads all the parameters for a resource.
  1271. Arguments:
  1272. ResourceEntry - Entry in the resource table.
  1273. Return Value:
  1274. ERROR_SUCCESS - Success
  1275. ERROR_RESOURCE_NOT_FOUND - failure
  1276. --*/
  1277. {
  1278. DWORD status;
  1279. //
  1280. // Read the parameters for the resource.
  1281. //
  1282. status = ResUtilReadProperties( ResourceEntry->ParametersKey,
  1283. IISResourcePrivateProperties,
  1284. (LPBYTE) &ResourceEntry->Params,
  1285. ResourceEntry->ResourceHandle,
  1286. g_IISLogEvent );
  1287. if ( status != ERROR_SUCCESS )
  1288. {
  1289. return status;
  1290. }
  1291. return IISBuildInternalParameters( &ResourceEntry->Params );
  1292. }
  1293. DWORD
  1294. IISBuildInternalParameters(
  1295. IN OUT IIS_PARAMS* Params
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. Build all the parameters for a resource from wolfpack parameters
  1300. Arguments:
  1301. ResourceEntry - Entry in the resource table.
  1302. Return Value:
  1303. ERROR_SUCCESS - Success
  1304. ERROR_RESOURCE_NOT_FOUND - failure
  1305. --*/
  1306. {
  1307. DWORD status;
  1308. INT iServiceType;
  1309. DWORD length;
  1310. //
  1311. // Make sure we got passed a valid service name
  1312. //
  1313. for ( iServiceType = 0 ; iServiceType < MAX_SERVICE ; iServiceType++ )
  1314. {
  1315. if ( lstrcmpiW( Params->ServiceName, ActualServiceName[iServiceType] ) == 0 )
  1316. {
  1317. break;
  1318. }
  1319. }
  1320. if ( iServiceType >= MAX_SERVICE )
  1321. {
  1322. TR( (DEBUG_BUFFER,"[IISBuildInternalParameters] Invalid service name %S", Params->ServiceName) );
  1323. return ERROR_RESOURCE_NOT_FOUND;
  1324. }
  1325. Params->ServiceType = iServiceType;
  1326. //
  1327. // Build MetaData path
  1328. //
  1329. TCHAR achMDPath[80];
  1330. DWORD dwL;
  1331. dwL = wsprintf( achMDPath, L"/LM/%s/%s", Params->ServiceName, Params->InstanceId );
  1332. Params->MDPath = (WCHAR*)LocalAlloc( LMEM_FIXED, (dwL+1)*sizeof(WCHAR) );
  1333. if ( Params->MDPath == NULL )
  1334. {
  1335. return ERROR_RESOURCE_NOT_FOUND;
  1336. }
  1337. memcpy( Params->MDPath, achMDPath,(dwL+1)*sizeof(TCHAR) );
  1338. TR( (DEBUG_BUFFER,"[IISBuildInternalParameters] Built path %S\n", Params->MDPath) );
  1339. return(ERROR_SUCCESS);
  1340. } // IISReadParameters
  1341. VOID
  1342. IISInitializeParams(
  1343. IN OUT IIS_PARAMS* Params
  1344. )
  1345. {
  1346. ZeroMemory( Params, sizeof(IIS_PARAMS) );
  1347. }
  1348. VOID
  1349. IISFreeInternalParameters(
  1350. IN IIS_PARAMS* Params
  1351. )
  1352. {
  1353. if ( Params->MDPath )
  1354. {
  1355. LocalFree( Params->MDPath );
  1356. Params->MDPath = NULL;
  1357. }
  1358. }
  1359. DWORD
  1360. IISGetRequiredDependencies(
  1361. OUT PVOID OutBuffer,
  1362. IN DWORD OutBufferSize,
  1363. OUT LPDWORD BytesReturned
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
  1368. for resources of type IIS server instance.
  1369. Arguments:
  1370. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1371. OutBufferSize - Supplies the size, in bytes, of the available space
  1372. pointed to by OutBuffer.
  1373. BytesReturned - Returns the number of bytes of OutBuffer actually
  1374. filled in by the resource. If OutBuffer is too small, BytesReturned
  1375. contains the total number of bytes for the operation to succeed.
  1376. Return Value:
  1377. ERROR_SUCCESS - The function completed successfully.
  1378. ERROR_MORE_DATA - The output buffer is too small to return the data.
  1379. BytesReturned contains the required size.
  1380. Win32 error code - The function failed.
  1381. --*/
  1382. {
  1383. typedef struct DEP_DATA
  1384. {
  1385. CLUSPROP_SZ_DECLARE( ipaddrEntry, sizeof(IP_ADDRESS_RESOURCE_NAME) / sizeof(WCHAR) );
  1386. CLUSPROP_SYNTAX endmark;
  1387. } DEP_DATA, *PDEP_DATA;
  1388. PDEP_DATA pdepdata = (PDEP_DATA)OutBuffer;
  1389. DWORD status;
  1390. *BytesReturned = sizeof(DEP_DATA);
  1391. if ( OutBufferSize < sizeof(DEP_DATA) )
  1392. {
  1393. if ( OutBuffer == NULL )
  1394. {
  1395. status = ERROR_SUCCESS;
  1396. }
  1397. else
  1398. {
  1399. TR( (DEBUG_BUFFER,"[IISGetRequiredDependencies] buffer too small: %d bytes\n",OutBufferSize) );
  1400. status = ERROR_MORE_DATA;
  1401. }
  1402. }
  1403. else
  1404. {
  1405. ZeroMemory( pdepdata, sizeof(DEP_DATA) );
  1406. pdepdata->ipaddrEntry.Syntax.dw = CLUSPROP_SYNTAX_NAME;
  1407. pdepdata->ipaddrEntry.cbLength = sizeof(IP_ADDRESS_RESOURCE_NAME);
  1408. lstrcpyW( pdepdata->ipaddrEntry.sz, IP_ADDRESS_RESOURCE_NAME );
  1409. pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
  1410. status = ERROR_SUCCESS;
  1411. }
  1412. return status;
  1413. } // IISGetRequiredDependencies
  1414. DWORD
  1415. IISResourceControl(
  1416. IN RESID ResourceId,
  1417. IN DWORD ControlCode,
  1418. IN PVOID InBuffer,
  1419. IN DWORD InBufferSize,
  1420. OUT PVOID OutBuffer,
  1421. IN DWORD OutBufferSize,
  1422. OUT LPDWORD BytesReturned
  1423. )
  1424. /*++
  1425. Routine Description:
  1426. ResourceControl routine for IIS Virtual Root resources.
  1427. Perform the control request specified by ControlCode on the specified
  1428. resource.
  1429. Arguments:
  1430. ResourceId - Supplies the resource id for the specific resource.
  1431. ControlCode - Supplies the control code that defines the action
  1432. to be performed.
  1433. InBuffer - Supplies a pointer to a buffer containing input data.
  1434. InBufferSize - Supplies the size, in bytes, of the data pointed
  1435. to by InBuffer.
  1436. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1437. OutBufferSize - Supplies the size, in bytes, of the available space
  1438. pointed to by OutBuffer.
  1439. BytesReturned - Returns the number of bytes of OutBuffer actually
  1440. filled in by the resource. If OutBuffer is too small, BytesReturned
  1441. contains the total number of bytes for the operation to succeed.
  1442. Return Value:
  1443. ERROR_SUCCESS - The function completed successfully.
  1444. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1445. In some cases, this allows the cluster software to perform the work.
  1446. Win32 error code - The function failed.
  1447. --*/
  1448. {
  1449. DWORD status = ERROR_SUCCESS;
  1450. LPIIS_RESOURCE resourceEntry = NULL;
  1451. IIS_PARAMS params;
  1452. //
  1453. // Get a valid resource
  1454. //
  1455. resourceEntry = GetValidResource( ResourceId, L"ResourceControl");
  1456. if ( resourceEntry == NULL )
  1457. {
  1458. return ERROR_RESOURCE_NOT_FOUND; // this should not happen
  1459. }
  1460. switch ( ControlCode )
  1461. {
  1462. case CLUSCTL_RESOURCE_UNKNOWN:
  1463. *BytesReturned = 0;
  1464. status = ERROR_SUCCESS;
  1465. TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_UNKNOWN : status = %d\n",status) );
  1466. break;
  1467. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  1468. status = IISGetRequiredDependencies(
  1469. OutBuffer,
  1470. OutBufferSize,
  1471. BytesReturned
  1472. );
  1473. TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES : status = %d\n",status) );
  1474. break;
  1475. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  1476. status = IISGetPrivateResProperties( resourceEntry,
  1477. OutBuffer,
  1478. OutBufferSize,
  1479. BytesReturned );
  1480. TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES : status = %d\n",status) );
  1481. break;
  1482. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  1483. status = IISValidatePrivateResProperties(
  1484. resourceEntry,
  1485. InBuffer,
  1486. InBufferSize,
  1487. &params );
  1488. TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES : status = %d\n",status) );
  1489. break;
  1490. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1491. status = IISSetPrivateResProperties(
  1492. resourceEntry,
  1493. InBuffer,
  1494. InBufferSize );
  1495. TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES : status = %d\n",status) );
  1496. break;
  1497. case CLUSCTL_RESOURCE_DELETE:
  1498. InstanceDisableCluster( resourceEntry->Params.ServiceName, resourceEntry->Params.InstanceId);
  1499. IISReplicateProperties(NULL, &(resourceEntry->Params));
  1500. TR( (DEBUG_BUFFER,"[IISResourceControl] CLUSCTL_RESOURCE_DELETE : status = %d\n",status) );
  1501. break;
  1502. default:
  1503. status = ERROR_INVALID_FUNCTION;
  1504. TR( (DEBUG_BUFFER,"[IISResourceControl] default %d: status = %d\n",ControlCode,status) );
  1505. break;
  1506. }
  1507. return(status);
  1508. } // IISResourceControl
  1509. DWORD
  1510. IISResourceTypeControl(
  1511. IN LPCWSTR ResourceTypeName,
  1512. IN DWORD ControlCode,
  1513. IN PVOID InBuffer,
  1514. IN DWORD InBufferSize,
  1515. OUT PVOID OutBuffer,
  1516. IN DWORD OutBufferSize,
  1517. OUT LPDWORD BytesReturned
  1518. )
  1519. /*++
  1520. Routine Description:
  1521. ResourceTypeControl routine for IIS Virtual Root resources.
  1522. Perform the control request specified by ControlCode.
  1523. Arguments:
  1524. ResourceTypeName - Supplies the name of the resource type.
  1525. ControlCode - Supplies the control code that defines the action
  1526. to be performed.
  1527. InBuffer - Supplies a pointer to a buffer containing input data.
  1528. InBufferSize - Supplies the size, in bytes, of the data pointed
  1529. to by InBuffer.
  1530. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1531. OutBufferSize - Supplies the size, in bytes, of the available space
  1532. pointed to by OutBuffer.
  1533. BytesReturned - Returns the number of bytes of OutBuffer actually
  1534. filled in by the resource. If OutBuffer is too small, BytesReturned
  1535. contains the total number of bytes for the operation to succeed.
  1536. Return Value:
  1537. ERROR_SUCCESS - The function completed successfully.
  1538. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1539. In some cases, this allows the cluster software to perform the work.
  1540. Win32 error code - The function failed.
  1541. --*/
  1542. {
  1543. DWORD status;
  1544. switch ( ControlCode )
  1545. {
  1546. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  1547. *BytesReturned = 0;
  1548. status = ERROR_SUCCESS;
  1549. break;
  1550. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  1551. status = IISGetRequiredDependencies(
  1552. OutBuffer,
  1553. OutBufferSize,
  1554. BytesReturned
  1555. );
  1556. break;
  1557. default:
  1558. status = ERROR_INVALID_FUNCTION;
  1559. break;
  1560. }
  1561. return(status);
  1562. } // IISResourceTypeControl
  1563. DWORD
  1564. IISGetPrivateResProperties(
  1565. IN OUT LPIIS_RESOURCE ResourceEntry,
  1566. OUT PVOID OutBuffer,
  1567. IN DWORD OutBufferSize,
  1568. OUT LPDWORD BytesReturned
  1569. )
  1570. /*++
  1571. Routine Description:
  1572. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  1573. for resources of type IIS.
  1574. Arguments:
  1575. ResourceEntry - Supplies the resource entry on which to operate.
  1576. OutBuffer - Returns the output data.
  1577. OutBufferSize - Supplies the size, in bytes, of the data pointed
  1578. to by OutBuffer.
  1579. BytesReturned - The number of bytes returned in OutBuffer.
  1580. Return Value:
  1581. ERROR_SUCCESS - The function completed successfully.
  1582. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1583. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1584. Win32 error code - The function failed.
  1585. --*/
  1586. {
  1587. DWORD status;
  1588. DWORD required;
  1589. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1590. IISResourcePrivateProperties,
  1591. OutBuffer,
  1592. OutBufferSize,
  1593. BytesReturned,
  1594. &required );
  1595. if ( status == ERROR_MORE_DATA )
  1596. {
  1597. *BytesReturned = required;
  1598. }
  1599. return(status);
  1600. } // IISGetPrivateResProperties
  1601. DWORD
  1602. IISValidatePrivateResProperties(
  1603. IN OUT LPIIS_RESOURCE ResourceEntry,
  1604. IN PVOID InBuffer,
  1605. IN DWORD InBufferSize,
  1606. OUT PIIS_PARAMS Params
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1611. function for resources of type IIS Virtual Root.
  1612. Arguments:
  1613. ResourceEntry - Supplies the resource entry on which to operate.
  1614. InBuffer - Supplies a pointer to a buffer containing input data.
  1615. InBufferSize - Supplies the size, in bytes, of the data pointed
  1616. to by InBuffer.
  1617. Params - Supplies the parameters structure to fill in. Pointers in this
  1618. structure will point to the data in InBuffer.
  1619. Return Value:
  1620. ERROR_SUCCESS - The function completed successfully.
  1621. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1622. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1623. Win32 error code - The function failed.
  1624. --*/
  1625. {
  1626. DWORD status;
  1627. IIS_PARAMS params;
  1628. PIIS_PARAMS pParams;
  1629. //
  1630. // Check if there is input data.
  1631. //
  1632. if ( (InBuffer == NULL) ||
  1633. (InBufferSize < sizeof(DWORD)) )
  1634. {
  1635. return(ERROR_INVALID_DATA);
  1636. }
  1637. //
  1638. // Duplicate the resource parameter block.
  1639. //
  1640. if ( Params == NULL )
  1641. {
  1642. pParams = &params;
  1643. }
  1644. else
  1645. {
  1646. pParams = Params;
  1647. }
  1648. ZeroMemory( pParams, sizeof(params) );
  1649. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1650. (LPBYTE) &ResourceEntry->Params,
  1651. IISResourcePrivateProperties );
  1652. if ( status != ERROR_SUCCESS )
  1653. {
  1654. return(status);
  1655. }
  1656. //
  1657. // Parse and validate the properties.
  1658. //
  1659. status = ResUtilVerifyPropertyTable( IISResourcePrivateProperties,
  1660. NULL,
  1661. TRUE,
  1662. InBuffer,
  1663. InBufferSize,
  1664. (LPBYTE) pParams );
  1665. //
  1666. // Cleanup our parameter block.
  1667. //
  1668. if ( pParams == &params )
  1669. {
  1670. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1671. (LPBYTE) &ResourceEntry->Params,
  1672. IISResourcePrivateProperties );
  1673. }
  1674. return(status);
  1675. } // IISValidatePrivateResProperties
  1676. DWORD
  1677. IISSetPrivateResProperties(
  1678. IN OUT LPIIS_RESOURCE ResourceEntry,
  1679. IN PVOID InBuffer,
  1680. IN DWORD InBufferSize
  1681. )
  1682. /*++
  1683. Routine Description:
  1684. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1685. for resources of type IIS Virtual Root.
  1686. Arguments:
  1687. ResourceEntry - Supplies the resource entry on which to operate.
  1688. InBuffer - Supplies a pointer to a buffer containing input data.
  1689. InBufferSize - Supplies the size, in bytes, of the data pointed
  1690. to by InBuffer.
  1691. Return Value:
  1692. ERROR_SUCCESS - The function completed successfully.
  1693. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1694. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1695. Win32 error code - The function failed.
  1696. --*/
  1697. {
  1698. DWORD status = ERROR_SUCCESS;
  1699. DWORD dupstatus = ERROR_SUCCESS;
  1700. IIS_PARAMS params;
  1701. IISInitializeParams( &params );
  1702. //
  1703. // Parse the properties so they can be validated together.
  1704. // This routine does individual property validation.
  1705. //
  1706. status = IISValidatePrivateResProperties( ResourceEntry,
  1707. InBuffer,
  1708. InBufferSize,
  1709. &params );
  1710. if ( status != ERROR_SUCCESS )
  1711. {
  1712. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1713. (LPBYTE) &ResourceEntry->Params,
  1714. IISResourcePrivateProperties );
  1715. return(status);
  1716. }
  1717. //
  1718. // Save the original paramters. Use them to unset properties.
  1719. //
  1720. IIS_PARAMS oldParams;
  1721. dupstatus = ResUtilDupParameterBlock( (LPBYTE) &oldParams,
  1722. (LPBYTE) &ResourceEntry->Params,
  1723. IISResourcePrivateProperties
  1724. );
  1725. //
  1726. // Save the parameter values.
  1727. //
  1728. status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1729. IISResourcePrivateProperties,
  1730. NULL,
  1731. (LPBYTE) &params,
  1732. InBuffer,
  1733. InBufferSize,
  1734. (LPBYTE) &ResourceEntry->Params );
  1735. //
  1736. // If the resource is online, return a non-success status.
  1737. //
  1738. if (status == ERROR_SUCCESS)
  1739. {
  1740. if ( params.ServiceName && params.InstanceId )
  1741. {
  1742. if ( IISBuildInternalParameters( &params ) == ERROR_SUCCESS )
  1743. {
  1744. //
  1745. // Reflect all properties we set to other nodes of the cluster.
  1746. //
  1747. if (ERROR_SUCCESS == dupstatus)
  1748. {
  1749. InstanceDisableCluster( oldParams.ServiceName, oldParams.InstanceId);
  1750. IISReplicateProperties(&params, &oldParams);
  1751. }
  1752. else
  1753. {
  1754. IISReplicateProperties(&params, NULL);
  1755. }
  1756. InstanceEnableCluster( params.ServiceName, params.InstanceId );
  1757. IISFreeInternalParameters( &params );
  1758. }
  1759. }
  1760. if ( (ResourceEntry->State == ClusterResourceOnline) ||
  1761. (ResourceEntry->State == ClusterResourceOnlinePending) )
  1762. {
  1763. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1764. }
  1765. else
  1766. {
  1767. status = ERROR_SUCCESS;
  1768. }
  1769. }
  1770. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1771. (LPBYTE) &ResourceEntry->Params,
  1772. IISResourcePrivateProperties );
  1773. if (ERROR_SUCCESS == dupstatus)
  1774. {
  1775. ResUtilFreeParameterBlock( (LPBYTE) &oldParams,
  1776. (LPBYTE) &ResourceEntry->Params,
  1777. IISResourcePrivateProperties );
  1778. }
  1779. return status;
  1780. } // IISSetPrivateResProperties
  1781. void
  1782. IISReplicateProperties(
  1783. IN IIS_PARAMS* lpNewParams,
  1784. IN IIS_PARAMS* lpOldParams
  1785. )
  1786. {
  1787. //
  1788. // Get Local Computer Name. Do not replicate to local computer
  1789. //
  1790. WCHAR wszLocalComputerName[MAX_COMPUTERNAME_LENGTH+1] = L"";
  1791. DWORD dwLength = MAX_COMPUTERNAME_LENGTH+1;
  1792. GetComputerName(wszLocalComputerName, &dwLength);
  1793. HCLUSTER hClus = OpenCluster(NULL);
  1794. if (hClus)
  1795. {
  1796. HCLUSENUM hClusEnumNode = ClusterOpenEnum( hClus, CLUSTER_ENUM_NODE);
  1797. if (hClusEnumNode)
  1798. {
  1799. DWORD dwType, dwIndex = 0;
  1800. WCHAR wszNodeName[MAX_COMPUTERNAME_LENGTH+1] = L"";
  1801. DWORD cbBufferLength = MAX_COMPUTERNAME_LENGTH+1;
  1802. while ( ERROR_SUCCESS == ClusterEnum( hClusEnumNode,
  1803. dwIndex,
  1804. &dwType,
  1805. wszNodeName,
  1806. &cbBufferLength))
  1807. {
  1808. dwIndex++;
  1809. //
  1810. // Set these properties on the node (if not local computer)
  1811. //
  1812. if (wcscmp(wszNodeName, wszLocalComputerName))
  1813. {
  1814. IISSetRemoteNodeProperties(wszNodeName, lpNewParams, lpOldParams);
  1815. }
  1816. cbBufferLength = MAX_COMPUTERNAME_LENGTH+1;
  1817. }
  1818. ClusterCloseEnum(hClusEnumNode);
  1819. }
  1820. CloseCluster(hClus);
  1821. }
  1822. } // IISReplicateProperties
  1823. void
  1824. IISSetRemoteNodeProperties(
  1825. IN LPWSTR wszNodeName,
  1826. IN IIS_PARAMS* lpNewParams,
  1827. IN IIS_PARAMS* lpOldParams
  1828. )
  1829. {
  1830. IMSAdminBaseW * pcAdmCom = NULL;
  1831. METADATA_HANDLE hmd;
  1832. HRESULT hRes = S_OK;
  1833. COSERVERINFO csiMachine;
  1834. MULTI_QI QI = {&IID_IMSAdminBase, NULL, 0};
  1835. //
  1836. // Open Metabase path to the remote Node
  1837. //
  1838. ZeroMemory( &csiMachine, sizeof(COSERVERINFO) );
  1839. csiMachine.pwszName = (LPWSTR)wszNodeName;
  1840. hRes = CoCreateInstanceEx( GETAdminBaseCLSID(TRUE),
  1841. NULL,
  1842. CLSCTX_SERVER,
  1843. &csiMachine,
  1844. 1,
  1845. &QI
  1846. );
  1847. if ( SUCCEEDED(hRes) && SUCCEEDED(QI.hr))
  1848. {
  1849. WCHAR achMDPath[80];
  1850. METADATA_RECORD mdRecord;
  1851. DWORD dwVal;
  1852. pcAdmCom = (IMSAdminBaseW *)QI.pItf;
  1853. if ( lpOldParams && lpOldParams->ServiceName && lpOldParams->InstanceId)
  1854. {
  1855. wcscpy(achMDPath,L"/LM/");
  1856. wcscat(achMDPath,lpOldParams->ServiceName);
  1857. wcscat(achMDPath,L"/");
  1858. wcscat(achMDPath,lpOldParams->InstanceId);
  1859. dwVal = 0;
  1860. if( SUCCEEDED( pcAdmCom->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  1861. achMDPath,
  1862. METADATA_PERMISSION_WRITE,
  1863. 5000,
  1864. &hmd)) )
  1865. {
  1866. MD_SET_DATA_RECORD ( &mdRecord,
  1867. MD_CLUSTER_ENABLED,
  1868. METADATA_INHERIT,
  1869. IIS_MD_UT_SERVER,
  1870. DWORD_METADATA,
  1871. sizeof(DWORD),
  1872. &dwVal
  1873. );
  1874. pcAdmCom->SetData( hmd, L"", &mdRecord);
  1875. pcAdmCom->CloseKey( hmd );
  1876. }
  1877. }
  1878. if ( lpNewParams && lpNewParams->ServiceName && lpNewParams->InstanceId)
  1879. {
  1880. wcscpy(achMDPath,L"/LM/");
  1881. wcscat(achMDPath,lpNewParams->ServiceName);
  1882. wcscat(achMDPath,L"/");
  1883. wcscat(achMDPath,lpNewParams->InstanceId);
  1884. dwVal = 1;
  1885. if( SUCCEEDED( pcAdmCom->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  1886. achMDPath,
  1887. METADATA_PERMISSION_WRITE,
  1888. 5000,
  1889. &hmd)) )
  1890. {
  1891. MD_SET_DATA_RECORD ( &mdRecord,
  1892. MD_CLUSTER_ENABLED,
  1893. METADATA_INHERIT,
  1894. IIS_MD_UT_SERVER,
  1895. DWORD_METADATA,
  1896. sizeof(DWORD),
  1897. &dwVal
  1898. );
  1899. pcAdmCom->SetData( hmd, L"", &mdRecord);
  1900. pcAdmCom->CloseKey( hmd );
  1901. }
  1902. }
  1903. pcAdmCom->Release();
  1904. }
  1905. } // IISSetRemoteNodeProperties
  1906. DWORD
  1907. WINAPI
  1908. IISAlivePollingThread(
  1909. IN PCLUS_WORKER pWorker,
  1910. IN LPVOID lpVoid )
  1911. /*++
  1912. Routine Description:
  1913. Polls the state of the given resource
  1914. Arguments:
  1915. Returns:
  1916. Win32 error code.
  1917. --*/
  1918. {
  1919. BOOL bIsAlive = TRUE;
  1920. BOOL bFoundRes = FALSE;
  1921. DWORD dwStatus = ERROR_SUCCESS;
  1922. PLIST_ENTRY pRes = NULL; // temp list entry for looping
  1923. PLIST_ENTRY pListStart = NULL; // temp list head used for looping
  1924. PLIST_ENTRY pEntry = NULL; // list entry used to check the list of resources
  1925. LPIIS_RESOURCE pResourceEntry = NULL; // resource entry that corresponds to the list entry
  1926. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Thread Started \n") );
  1927. while ( !ClusWorkerCheckTerminate( &g_cwAlivePollingThread ) )
  1928. {
  1929. DWORD dwPort = 0;
  1930. SOCKADDR saServer;
  1931. DWORD dwServiceType = 0;
  1932. LPWSTR szMDPath = NULL;
  1933. BOOL bReadBindingsInfo = FALSE ;
  1934. //
  1935. // update the time stamp that is used by the isalive/looksalive check to determine this thread is still running
  1936. //
  1937. InterlockedExchange( (LPLONG) &g_dwTickOfLastResourceCheck, GetTickCount() );
  1938. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] set g_dwTickOfLastResourceCheck (%d)\n", g_dwTickOfLastResourceCheck) );
  1939. EnterCriticalSection( &IISTableLock );
  1940. {
  1941. //
  1942. // check that the list is not empty
  1943. //
  1944. if ( IsListEmpty ( &IISResourceTable ) )
  1945. {
  1946. LeaveCriticalSection( &IISTableLock );
  1947. pEntry = NULL;
  1948. goto done_check;
  1949. }
  1950. //
  1951. // if we don't have a list element yet get the fisrt element in the list
  1952. //
  1953. if ( !pEntry || g_fIISResourceTable_HadChanged)
  1954. {
  1955. pEntry = IISResourceTable.Flink;
  1956. g_fIISResourceTable_HadChanged = FALSE;
  1957. }
  1958. //
  1959. // look for an element in the list that is OnLine
  1960. //
  1961. bFoundRes = FALSE ;
  1962. pListStart = pEntry;
  1963. do
  1964. {
  1965. if ( &IISResourceTable != pEntry )
  1966. {
  1967. //
  1968. // get the structure that contains this list element
  1969. //
  1970. pResourceEntry = CONTAINING_RECORD( pEntry,
  1971. IIS_RESOURCE,
  1972. ListEntry );
  1973. if ( pResourceEntry &&
  1974. (ClusterResourceOnline == pResourceEntry->State) )
  1975. {
  1976. //
  1977. // grab the info that we need from this structure so we can release the critical section
  1978. //
  1979. dwPort = pResourceEntry->dwPort;
  1980. dwServiceType = pResourceEntry->Params.ServiceType;
  1981. memcpy( (LPVOID) &saServer, (LPVOID) &pResourceEntry->saServer, sizeof(SOCKADDR) );
  1982. //
  1983. // allocate memory for the metabase path for this resource
  1984. //
  1985. if ( pResourceEntry->Params.MDPath )
  1986. {
  1987. szMDPath = (LPWSTR) LocalAlloc ( LPTR, (lstrlen(pResourceEntry->Params.MDPath)+1) * sizeof(WCHAR) ) ;
  1988. if ( szMDPath )
  1989. {
  1990. lstrcpy( szMDPath, pResourceEntry->Params.MDPath );
  1991. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] checking resource (%S/%S), State:%d OnLineState:%d\n", pResourceEntry->Params.ServiceName, pResourceEntry->Params.InstanceId, pResourceEntry->State, ClusterResourceOnline) );
  1992. bFoundRes = TRUE;
  1993. break;
  1994. }
  1995. else
  1996. {
  1997. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Failed to allocate memory for metadata path\n") );
  1998. }
  1999. }
  2000. if ( szMDPath ) TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Checking resource Metadata Path:%S\n", szMDPath) );
  2001. }
  2002. else
  2003. {
  2004. if ( pResourceEntry ) TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Not checking resource (%S/%S) because it's not Online, State:%d OnLineState:%d\n", pResourceEntry->Params.ServiceName, pResourceEntry->Params.InstanceId, pResourceEntry->State, ClusterResourceOnline) );
  2005. }
  2006. }
  2007. //
  2008. // check the next element
  2009. //
  2010. pEntry = pEntry->Flink ;
  2011. }
  2012. while ( pListStart != pEntry );
  2013. //
  2014. // verify the loop ended because a valid resource was found
  2015. //
  2016. if ( !bFoundRes )
  2017. {
  2018. LeaveCriticalSection( &IISTableLock );
  2019. pEntry = NULL;
  2020. goto done_check;
  2021. }
  2022. }
  2023. LeaveCriticalSection( &IISTableLock );
  2024. //
  2025. // if the service status check (isalive/looksalive check) fails then get server bindings and try again
  2026. //
  2027. if ( ERROR_SUCCESS != (dwStatus = VerifyIISService( szMDPath, dwServiceType, dwPort, saServer, g_IISLogEvent )) )
  2028. {
  2029. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] VerifyIISService failed , calling GetServerBindings() and retrying \n") );
  2030. if ( ERROR_SUCCESS == (dwStatus = GetServerBindings( szMDPath, dwServiceType, &saServer, &dwPort )) )
  2031. {
  2032. bReadBindingsInfo = TRUE ;
  2033. dwStatus = VerifyIISService( szMDPath, dwServiceType, dwPort, saServer, g_IISLogEvent );
  2034. }
  2035. }
  2036. bIsAlive = (dwStatus == ERROR_SUCCESS);
  2037. if ( szMDPath )
  2038. {
  2039. LocalFree ( szMDPath );
  2040. szMDPath = NULL;
  2041. }
  2042. EnterCriticalSection( &IISTableLock );
  2043. {
  2044. //
  2045. // check that the list is not empty
  2046. //
  2047. if ( IsListEmpty ( &IISResourceTable ) )
  2048. {
  2049. LeaveCriticalSection( &IISTableLock );
  2050. pEntry = NULL;
  2051. goto done_check;
  2052. }
  2053. //
  2054. // check that the element still exists in the list
  2055. //
  2056. bFoundRes = FALSE ;
  2057. for ( pRes = IISResourceTable.Flink;
  2058. pRes != &IISResourceTable;
  2059. pRes = pRes->Flink )
  2060. {
  2061. if ( pEntry == pRes )
  2062. {
  2063. bFoundRes = TRUE ;
  2064. break;
  2065. }
  2066. }
  2067. if( bFoundRes )
  2068. {
  2069. //
  2070. // get the elemement
  2071. //
  2072. pResourceEntry = CONTAINING_RECORD( pEntry,
  2073. IIS_RESOURCE,
  2074. ListEntry );
  2075. //
  2076. // update the element's state information (isalive/looksalive)
  2077. //
  2078. InterlockedExchange( (LPLONG)&pResourceEntry->bAlive , bIsAlive );
  2079. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Updating IsAlive/LooksAlive status for resource Metadata Path:%S bAlive:%d State:%d\n", pResourceEntry->Params.MDPath, bIsAlive, pResourceEntry->State) );
  2080. //
  2081. // update the bindings info if new information was found . these assignments do not need to be sync'ed
  2082. // since the only other thread they are used in is in the online thread . before the resource has been marked online
  2083. // so this code will never be executed at the same time .
  2084. //
  2085. if ( bReadBindingsInfo )
  2086. {
  2087. pResourceEntry->dwPort = dwPort ;
  2088. memcpy( (LPVOID) &pResourceEntry->saServer, (LPVOID) &saServer, sizeof(SOCKADDR) );
  2089. }
  2090. //
  2091. // print some error messages so users will know when a resource fails
  2092. //
  2093. if ( !pResourceEntry->bAlive )
  2094. {
  2095. if ( g_IISLogEvent )
  2096. {
  2097. //
  2098. // Some type of error
  2099. //
  2100. (g_IISLogEvent)(
  2101. pResourceEntry->ResourceHandle,
  2102. LOG_ERROR,
  2103. L"IsAlive/LooksAlive ERROR getting information for service %1!ws! resource %2!ws!\n",
  2104. pResourceEntry->Params.ServiceName,
  2105. pResourceEntry->ResourceName );
  2106. }
  2107. if ( g_hEventLog )
  2108. {
  2109. LPCTSTR aErrStr[3];
  2110. WCHAR aErrCode[32];
  2111. _ultow( dwStatus, aErrCode, 10 );
  2112. aErrStr[0] = pResourceEntry->Params.ServiceName;
  2113. aErrStr[1] = pResourceEntry->Params.InstanceId;
  2114. aErrStr[2] = aErrCode;
  2115. ReportEvent( g_hEventLog,
  2116. EVENTLOG_ERROR_TYPE,
  2117. 0,
  2118. IISCL_EVENT_CANT_ACCESS_IIS,
  2119. NULL,
  2120. sizeof(aErrStr)/sizeof(LPCTSTR),
  2121. 0,
  2122. aErrStr,
  2123. NULL );
  2124. }
  2125. }
  2126. //
  2127. // move to the next element
  2128. //
  2129. pEntry = pEntry->Flink;
  2130. }
  2131. else
  2132. {
  2133. //
  2134. // the resource was not found , probably deleted so pEntry is now invalid
  2135. //
  2136. pEntry = NULL;
  2137. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Failed to find a resource after checking its state\n") );
  2138. }
  2139. }
  2140. LeaveCriticalSection( &IISTableLock );
  2141. done_check:
  2142. Sleep( DELAY_BETWEEN_ISALIVE_CHECKS );
  2143. }
  2144. TR( (DEBUG_BUFFER,"[IISAlivePollingThread] Thread Exiting \n") );
  2145. return dwStatus;
  2146. } // IISAlivePollingThread
  2147. //***********************************************************
  2148. //
  2149. // Define Function Table
  2150. //
  2151. //***********************************************************
  2152. // Define entry points
  2153. CLRES_V1_FUNCTION_TABLE( IISFunctionTable,
  2154. CLRES_VERSION_V1_00,
  2155. IIS,
  2156. NULL,
  2157. NULL,
  2158. IISResourceControl,
  2159. IISResourceTypeControl );