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.

761 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992, 1996 Microsoft Corporation
  3. Module Name:
  4. timesvc.c
  5. Abstract:
  6. Resource DLL to control and monitor the Cluster Time Service
  7. Author:
  8. Rod Gamache, 21-July-1996.
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "clusres.h"
  13. #include "tsapi.h"
  14. #define TIMESVC_PRINT printf
  15. #define NOTIFY_KEY_RESOURCE_STATE 1
  16. #define TimeSvcLogEvent ClusResLogEvent
  17. #define SEMAPHORE_NAME L"Cluster$TimeSvcSemaphore"
  18. #define MAX_RESOURCE_NAME_LENGTH 256
  19. //
  20. // Global Data
  21. //
  22. typedef struct _SERVICE_INFORMATION {
  23. RESOURCE_HANDLE ResourceHandle;
  24. HCLUSTER ClusterHandle;
  25. HCHANGE ClusterChange;
  26. HRESOURCE hResource;
  27. } SERVICE_INFORMATION, *PSERVICE_INFORMATION;
  28. // Global event handle
  29. HANDLE TimeSvcSemaphore = NULL;
  30. // The resource handle for the active instance.
  31. PSERVICE_INFORMATION TimeSvcInfo = NULL;
  32. // Local Computer Name
  33. WCHAR TimeSvcLocalComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  34. // Notify thread handle
  35. CLUS_WORKER TimeSvcNotifyHandle = {NULL, TRUE};
  36. extern CLRES_FUNCTION_TABLE TimeSvcFunctionTable;
  37. //
  38. // Forward routines
  39. //
  40. BOOL
  41. VerifyService(
  42. IN RESID Resource,
  43. IN BOOL IsAliveFlag
  44. );
  45. BOOLEAN
  46. WINAPI
  47. TimeSvcDllEntryPoint(
  48. IN HINSTANCE DllHandle,
  49. IN DWORD Reason,
  50. IN LPVOID Reserved
  51. )
  52. {
  53. switch ( Reason ) {
  54. case DLL_PROCESS_ATTACH:
  55. TimeSvcSemaphore = CreateSemaphoreW( NULL,
  56. 0,
  57. 1,
  58. SEMAPHORE_NAME );
  59. if ( TimeSvcSemaphore == NULL ) {
  60. return(FALSE);
  61. }
  62. if (GetLastError() != ERROR_ALREADY_EXISTS)
  63. {
  64. //if the semaphore didnt exist, set its initial count to 1
  65. ReleaseSemaphore(TimeSvcSemaphore, 1, NULL);
  66. }
  67. break;
  68. case DLL_PROCESS_DETACH:
  69. if ( TimeSvcSemaphore ) {
  70. CloseHandle( TimeSvcSemaphore );
  71. }
  72. break;
  73. default:
  74. break;
  75. }
  76. return(TRUE);
  77. } // TimeSvcDllEntryPoint
  78. DWORD
  79. TimeSvcNotifyThread(
  80. IN PCLUS_WORKER Worker,
  81. IN PVOID Context
  82. )
  83. /*++
  84. Routine Description:
  85. Thread to listen for resource change events on the Time Service resource.
  86. Arguments:
  87. Worker - Supplies the worker structure
  88. Context - not used.
  89. Return Value:
  90. ERROR_SUCCESS
  91. --*/
  92. {
  93. DWORD status;
  94. HRESOURCE resource;
  95. WCHAR* buffer;
  96. DWORD bufSize;
  97. DWORD bufAlloced;
  98. DWORD failures = 0;
  99. DWORD_PTR notifyKey;
  100. DWORD filter;
  101. CLUSTER_RESOURCE_STATE resourceState;
  102. DWORD notUsed = 0;
  103. //
  104. // Now register for Notification of resource state change events.
  105. //
  106. if ( TimeSvcInfo->ClusterHandle == NULL ) {
  107. goto error_exit;
  108. }
  109. //
  110. // Create a real notification port.
  111. //
  112. if ( TimeSvcInfo->ClusterChange != NULL ) {
  113. CloseClusterNotifyPort( TimeSvcInfo->ClusterChange );
  114. }
  115. TimeSvcInfo->ClusterChange = CreateClusterNotifyPort( INVALID_HANDLE_VALUE,
  116. TimeSvcInfo->ClusterHandle,
  117. (DWORD) CLUSTER_CHANGE_RESOURCE_STATE |
  118. CLUSTER_CHANGE_HANDLE_CLOSE,
  119. NOTIFY_KEY_RESOURCE_STATE);
  120. if ( TimeSvcInfo->ClusterChange == NULL ) {
  121. (TimeSvcLogEvent)(
  122. TimeSvcInfo->ResourceHandle,
  123. LOG_ERROR,
  124. L"Failed to create notify port, status %1!u!. Stopped Listening...\n",
  125. GetLastError() );
  126. goto error_exit;
  127. }
  128. bufAlloced = 100;
  129. buffer = LocalAlloc( LMEM_FIXED, bufAlloced * sizeof( WCHAR ) );
  130. if ( buffer == NULL ) {
  131. (TimeSvcLogEvent)(
  132. TimeSvcInfo->ResourceHandle,
  133. LOG_ERROR,
  134. L"Failed to allocate a Notify buffer.\n");
  135. status = ERROR_NOT_ENOUGH_MEMORY;
  136. goto error_exit;
  137. }
  138. //
  139. // Loop listening for resource state change events...
  140. //
  141. while ( TRUE ) {
  142. bufSize = bufAlloced;
  143. status = GetClusterNotify( TimeSvcInfo->ClusterChange,
  144. &notifyKey,
  145. &filter,
  146. buffer,
  147. &bufSize,
  148. INFINITE );
  149. if ( ClusWorkerCheckTerminate( &TimeSvcNotifyHandle ) ) {
  150. break;
  151. }
  152. if ( status == ERROR_MORE_DATA ) {
  153. //
  154. // resize the buffer and loop again
  155. //
  156. LocalFree( buffer );
  157. bufSize++; //add one for NULL
  158. bufAlloced = bufSize;
  159. buffer = LocalAlloc( LMEM_FIXED, bufAlloced * sizeof( WCHAR ) );
  160. if ( buffer == NULL ) {
  161. (TimeSvcLogEvent)(
  162. TimeSvcInfo->ResourceHandle,
  163. LOG_ERROR,
  164. L"Failed to allocate a Notify buffer.\n");
  165. status = ERROR_NOT_ENOUGH_MEMORY;
  166. break;
  167. }
  168. } else if ( status != ERROR_SUCCESS ) {
  169. (TimeSvcLogEvent)(
  170. TimeSvcInfo->ResourceHandle,
  171. LOG_ERROR,
  172. L"Getting notification event failed, status %1!u!. \n",
  173. status);
  174. break;
  175. } else {
  176. WCHAR lpszResourceName[MAX_RESOURCE_NAME_LENGTH];
  177. DWORD bytesReturned;
  178. //
  179. // Re-fetch our name each time, in case it changes.
  180. //
  181. status = ClusterResourceControl(
  182. TimeSvcInfo->hResource,
  183. NULL,
  184. CLUSCTL_RESOURCE_GET_NAME,
  185. 0,
  186. 0,
  187. (PUCHAR)&lpszResourceName,
  188. MAX_RESOURCE_NAME_LENGTH * sizeof(WCHAR),
  189. &bytesReturned );
  190. if (status != ERROR_SUCCESS) {
  191. break;
  192. }
  193. if ( (filter == CLUSTER_CHANGE_RESOURCE_STATE) &&
  194. (lstrcmpiW( buffer, lpszResourceName ) == 0) ) {
  195. bufSize = bufAlloced;
  196. resourceState = GetClusterResourceState( TimeSvcInfo->hResource,
  197. buffer,
  198. &bufSize,
  199. NULL,
  200. &notUsed );
  201. if ( resourceState == ClusterResourceOnline ) {
  202. status = TSNewSource( TimeSvcLocalComputerName,
  203. buffer,
  204. 0 );
  205. (TimeSvcLogEvent)(
  206. TimeSvcInfo->ResourceHandle,
  207. LOG_INFORMATION,
  208. L"Status of Time Service request to sync from node %1!ws! is %2!u!.\n",
  209. buffer,
  210. status);
  211. }
  212. } else if (filter == CLUSTER_CHANGE_HANDLE_CLOSE) {
  213. //
  214. // Clean up and exit.
  215. //
  216. break;
  217. }
  218. }
  219. }
  220. error_exit:
  221. // Don't close the ClusterChange notification handle, let the close
  222. // routine do that!
  223. return(ERROR_SUCCESS);
  224. } // TimeSvcNotifyThread
  225. RESID
  226. WINAPI
  227. TimeSvcOpen(
  228. IN LPCWSTR ResourceName,
  229. IN HKEY ResourceKey,
  230. IN RESOURCE_HANDLE ResourceHandle
  231. )
  232. /*++
  233. Routine Description:
  234. Open routine for Cluster Time Service resource.
  235. This routine gets a handle to the service controller, if we dont already have one,
  236. and then gets a handle to the specified service. The service handle is saved
  237. in the TimeSvcInfo structure.
  238. Arguments:
  239. ResourceName - supplies the resource name
  240. ResourceKey - supplies a handle to the resource's cluster registry key
  241. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  242. is called.
  243. Return Value:
  244. RESID of created resource
  245. Zero on failure
  246. --*/
  247. {
  248. ULONG index = 1;
  249. DWORD status;
  250. HKEY parametersKey = NULL;
  251. PSERVICE_INFORMATION serviceInfo = NULL;
  252. DWORD computerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
  253. WCHAR nodeName[MAX_COMPUTERNAME_LENGTH+1];
  254. DWORD nodeNameSize = MAX_COMPUTERNAME_LENGTH + 1;
  255. DWORD notUsed = 0;
  256. CLUSTER_RESOURCE_STATE resourceState;
  257. DWORD threadId;
  258. DWORD nameLength;
  259. (TimeSvcLogEvent)(
  260. ResourceHandle,
  261. LOG_INFORMATION,
  262. L"Creating resource.\n" );
  263. //
  264. // Make sure this is the only time we've been called!
  265. //
  266. if ( WaitForSingleObject( TimeSvcSemaphore, 0 ) == WAIT_TIMEOUT ) {
  267. //
  268. // A version of this service is already running
  269. //
  270. (TimeSvcLogEvent)(
  271. ResourceHandle,
  272. LOG_ERROR,
  273. L"Service is already running.\n" );
  274. status = ERROR_SERVICE_ALREADY_RUNNING;
  275. goto error_exit2;
  276. }
  277. serviceInfo = LocalAlloc( LMEM_FIXED, sizeof(SERVICE_INFORMATION) );
  278. if ( serviceInfo == NULL ) {
  279. (TimeSvcLogEvent)(
  280. ResourceHandle,
  281. LOG_ERROR,
  282. L"Failed to allocate a service info structure.\n");
  283. status = ERROR_NOT_ENOUGH_MEMORY;
  284. goto error_exit;
  285. }
  286. ZeroMemory( serviceInfo, sizeof(SERVICE_INFORMATION) );
  287. //
  288. // Get the local computer name.
  289. //
  290. status = GetComputerNameW( TimeSvcLocalComputerName, &computerNameSize );
  291. if ( !status ) {
  292. (TimeSvcLogEvent)(
  293. ResourceHandle,
  294. LOG_ERROR,
  295. L"Failed to get local computer name, error %1!u!.\n",
  296. status);
  297. goto error_exit;
  298. }
  299. if ( serviceInfo->ClusterHandle == NULL ) {
  300. serviceInfo->ClusterHandle = OpenCluster( NULL );
  301. }
  302. if ( serviceInfo->ClusterHandle == NULL ) {
  303. status = GetLastError();
  304. (TimeSvcLogEvent)(
  305. ResourceHandle,
  306. LOG_ERROR,
  307. L"Failed to open local cluster, error %1!u!.\n",
  308. status);
  309. goto error_exit;
  310. }
  311. //
  312. // Sync our time from whatever system currently 'owns' the time service.
  313. //
  314. if ( serviceInfo->hResource == NULL ) {
  315. serviceInfo->hResource = OpenClusterResource( serviceInfo->ClusterHandle,
  316. ResourceName );
  317. }
  318. if ( serviceInfo->hResource == NULL ) {
  319. status = GetLastError();
  320. (TimeSvcLogEvent)(
  321. ResourceHandle,
  322. LOG_ERROR,
  323. L"Failed to open Time Service resource.\n");
  324. goto error_exit;
  325. }
  326. resourceState = GetClusterResourceState( serviceInfo->hResource,
  327. nodeName,
  328. &nodeNameSize,
  329. NULL,
  330. &notUsed );
  331. if ( resourceState == ClusterResourceOnline ) {
  332. status = TSNewSource( TimeSvcLocalComputerName,
  333. nodeName,
  334. 0 );
  335. }
  336. //
  337. // Create a notification thread to watch if the time service moves!
  338. //
  339. ClusWorkerTerminate(&TimeSvcNotifyHandle);
  340. status = ClusWorkerCreate(&TimeSvcNotifyHandle,
  341. TimeSvcNotifyThread,
  342. serviceInfo);
  343. if ( status != ERROR_SUCCESS ) {
  344. (TimeSvcLogEvent)(
  345. serviceInfo->ResourceHandle,
  346. LOG_ERROR,
  347. L"Error creating notify thread, status %1!u!.\n",
  348. status );
  349. goto error_exit;
  350. }
  351. TimeSvcInfo = serviceInfo;
  352. serviceInfo->ResourceHandle = ResourceHandle;
  353. return((RESID)serviceInfo);
  354. error_exit:
  355. ReleaseSemaphore ( TimeSvcSemaphore, 1 , 0 );
  356. if ( TimeSvcInfo == serviceInfo ) {
  357. TimeSvcInfo = NULL;
  358. }
  359. error_exit2:
  360. if ( parametersKey != NULL ) {
  361. ClusterRegCloseKey( parametersKey );
  362. }
  363. if ( serviceInfo != NULL ) {
  364. if ( serviceInfo->hResource ) {
  365. CloseClusterResource( serviceInfo->hResource );
  366. }
  367. if ( serviceInfo->ClusterHandle ) {
  368. CloseCluster( serviceInfo->ClusterHandle );
  369. }
  370. LocalFree( serviceInfo );
  371. }
  372. SetLastError(status);
  373. return(0);
  374. } // TimeSvcOpen
  375. DWORD
  376. WINAPI
  377. TimeSvcOnline(
  378. IN RESID Resource,
  379. IN OUT PHANDLE EventHandle
  380. )
  381. /*++
  382. Routine Description:
  383. Online routine for Cluster Time Service resource.
  384. Arguments:
  385. Resource - supplies resource id to be brought online
  386. EventHandle - supplies a pointer to a handle to signal on error.
  387. Return Value:
  388. ERROR_SUCCESS if successful.
  389. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  390. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  391. acquire 'ownership'.
  392. Win32 error code if other failure.
  393. --*/
  394. {
  395. if ( TimeSvcInfo == NULL ) {
  396. TIMESVC_PRINT("TimeSvc: Online request for a nonexistent resource id 0x%p.\n",
  397. Resource);
  398. return(ERROR_RESOURCE_NOT_FOUND);
  399. }
  400. if ( TimeSvcInfo != (PSERVICE_INFORMATION)Resource ) {
  401. (TimeSvcLogEvent)(
  402. TimeSvcInfo->ResourceHandle,
  403. LOG_ERROR,
  404. L"Online service info checked failed! Resource = %1!lx!.\n",
  405. Resource);
  406. return(ERROR_RESOURCE_NOT_FOUND);
  407. }
  408. return(ERROR_SUCCESS);
  409. } // TimeSvcOnline
  410. VOID
  411. WINAPI
  412. TimeSvcTerminate(
  413. IN RESID Resource
  414. )
  415. /*++
  416. Routine Description:
  417. Terminate routine for Cluster Time Service resource.
  418. Arguments:
  419. Resource - supplies resource id to be terminated
  420. Return Value:
  421. None.
  422. --*/
  423. {
  424. if ( TimeSvcInfo == NULL ) {
  425. TIMESVC_PRINT("TimeSvc: Offline request for a nonexistent resource id 0x%p.\n",
  426. Resource);
  427. return;
  428. }
  429. if ( TimeSvcInfo != (PSERVICE_INFORMATION)Resource ) {
  430. (TimeSvcLogEvent)(
  431. TimeSvcInfo->ResourceHandle,
  432. LOG_ERROR,
  433. L"Offline service info check failed! Resource = %1!u!.\n",
  434. Resource);
  435. return;
  436. }
  437. (TimeSvcLogEvent)(
  438. TimeSvcInfo->ResourceHandle,
  439. LOG_INFORMATION,
  440. L"Terminate request, returning.\n");
  441. return;
  442. } // TimeSvcTerminate
  443. DWORD
  444. WINAPI
  445. TimeSvcOffline(
  446. IN RESID Resource
  447. )
  448. /*++
  449. Routine Description:
  450. Offline routine for Cluster Time Service resource.
  451. Arguments:
  452. Resource - supplies the resource to be taken offline
  453. Return Value:
  454. ERROR_SUCCESS - always successful.
  455. --*/
  456. {
  457. TimeSvcTerminate( Resource );
  458. return(ERROR_SUCCESS);
  459. } // Offline
  460. BOOL
  461. WINAPI
  462. TimeSvcIsAlive(
  463. IN RESID Resource
  464. )
  465. /*++
  466. Routine Description:
  467. IsAlive routine for Cluster Time Service resource.
  468. Arguments:
  469. Resource - supplies the resource id to be polled.
  470. Return Value:
  471. TRUE - if service is running
  472. FALSE - if service is in any other state
  473. --*/
  474. {
  475. return( TRUE );
  476. } // TimeSvcIsAlive
  477. BOOL
  478. WINAPI
  479. TimeSvcLooksAlive(
  480. IN RESID Resource
  481. )
  482. /*++
  483. Routine Description:
  484. LooksAlive routine for Cluster Time Service resource.
  485. Arguments:
  486. Resource - supplies the resource id to be polled.
  487. Return Value:
  488. TRUE - Resource looks like it is alive and well
  489. FALSE - Resource looks like it is toast.
  490. --*/
  491. {
  492. return( TRUE );
  493. } // TimeSvcLooksAlive
  494. VOID
  495. WINAPI
  496. TimeSvcClose(
  497. IN RESID Resource
  498. )
  499. /*++
  500. Routine Description:
  501. Close routine for Cluster Time Service resource.
  502. This routine will stop the service, and delete the cluster
  503. information regarding that service.
  504. Arguments:
  505. Resource - supplies resource id to be closed
  506. Return Value:
  507. None.
  508. --*/
  509. {
  510. DWORD status;
  511. PSERVICE_INFORMATION serviceInfo = NULL;
  512. serviceInfo = (PSERVICE_INFORMATION)Resource;
  513. if ( serviceInfo == NULL ) {
  514. TIMESVC_PRINT("TimeSvc: Close request for a nonexistent resource id 0x%p\n",
  515. Resource);
  516. return;
  517. }
  518. (TimeSvcLogEvent)(
  519. serviceInfo->ResourceHandle,
  520. LOG_INFORMATION,
  521. L"Close request for %1!lx!, TimeSvcInfo = %2!lx!.\n",
  522. serviceInfo, TimeSvcInfo);
  523. //
  524. // Shut it down if it's on line
  525. //
  526. TimeSvcTerminate(Resource);
  527. if ( serviceInfo->ClusterHandle ) {
  528. CloseCluster( serviceInfo->ClusterHandle );
  529. }
  530. if ( serviceInfo == TimeSvcInfo ) {
  531. ClusWorkerTerminate( &TimeSvcNotifyHandle );
  532. TimeSvcInfo = NULL;
  533. //SetEvent ( TimeSvcSemaphore );
  534. ReleaseSemaphore ( TimeSvcSemaphore, 1 , 0 );
  535. }
  536. if ( serviceInfo->hResource ) {
  537. CloseClusterResource( serviceInfo->hResource );
  538. }
  539. if ( serviceInfo->ClusterChange != NULL ) {
  540. CloseClusterNotifyPort( serviceInfo->ClusterChange );
  541. }
  542. LocalFree( serviceInfo );
  543. return;
  544. } // TimeSvcClose
  545. //***********************************************************
  546. //
  547. // Define Function Table
  548. //
  549. //***********************************************************
  550. CLRES_V1_FUNCTION_TABLE( TimeSvcFunctionTable,
  551. CLRES_VERSION_V1_00,
  552. TimeSvc,
  553. NULL,
  554. NULL,
  555. NULL,
  556. NULL );