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.

2395 lines
57 KiB

  1. /*++
  2. Copyright (c) 1992-1996 Microsoft Corporation
  3. Module Name:
  4. iisutil.c
  5. Abstract:
  6. IIS Resource utility routine DLL
  7. Author:
  8. Pete Benoit (v-pbenoi) 12-SEP-1996
  9. Revision History:
  10. --*/
  11. #include "iisutil.h"
  12. #if defined(_DEBUG_SUPPORT)
  13. #include <time.h>
  14. #endif
  15. #include <pudebug.h>
  16. IMSAdminBase* CMetaData::g_pMBCom;
  17. CRITICAL_SECTION CMetaData::g_cs;
  18. VOID
  19. FreeIISResource(
  20. IN LPIIS_RESOURCE ResourceEntry
  21. )
  22. /*++
  23. Routine Description:
  24. Free all the storage for a IIS_RESOURCE
  25. Arguments:
  26. vr - virtual root to free
  27. Return Value:
  28. NONE
  29. --*/
  30. {
  31. if (ResourceEntry != NULL)
  32. {
  33. if ( ResourceEntry->ResourceName != NULL )
  34. {
  35. LocalFree( ResourceEntry->ResourceName );
  36. ResourceEntry->ResourceName = NULL;
  37. }
  38. #if 0
  39. if ( ResourceEntry->ResourceHandle != NULL )
  40. {
  41. CloseClusterResource( ResourceEntry->ResourceHandle );
  42. }
  43. #endif
  44. if ( ResourceEntry->ParametersKey != NULL )
  45. {
  46. ClusterRegCloseKey( ResourceEntry->ParametersKey );
  47. ResourceEntry->ParametersKey = NULL;
  48. }
  49. if ( ResourceEntry->Params.ServiceName != NULL )
  50. {
  51. LocalFree( ResourceEntry->Params.ServiceName);
  52. ResourceEntry->Params.ServiceName = NULL;
  53. }
  54. if ( ResourceEntry->Params.InstanceId != NULL )
  55. {
  56. LocalFree( ResourceEntry->Params.InstanceId);
  57. ResourceEntry->Params.InstanceId = NULL;
  58. }
  59. if ( ResourceEntry->Params.MDPath != NULL )
  60. {
  61. LocalFree( ResourceEntry->Params.MDPath);
  62. ResourceEntry->Params.MDPath = NULL;
  63. }
  64. } // ResourceEntry != NULL
  65. } // FreeIISResource
  66. VOID
  67. DestructIISResource(
  68. IN LPIIS_RESOURCE ResourceEntry
  69. )
  70. /*++
  71. Routine Description:
  72. Free all the storage for a ResourceEntry and the ResourceEntry
  73. Arguments:
  74. vr - virtual root to free
  75. Return Value:
  76. NONE
  77. --*/
  78. {
  79. if (ResourceEntry != NULL)
  80. {
  81. FreeIISResource(ResourceEntry);
  82. LocalFree(ResourceEntry);
  83. } // ResourceEntry != NULL
  84. } // DestructIISResource
  85. DWORD
  86. GetServerBindings(
  87. LPWSTR MDPath,
  88. DWORD dwServiceType,
  89. SOCKADDR* psaServer,
  90. LPDWORD pdwPort
  91. )
  92. /*++
  93. Routine Description:
  94. Read the first ip address and port number form the ServerBindings property for a particlar branch of the metabase
  95. Arguments:
  96. MDPath : the particular branch of the metabase to read the information from (ex. /LM/W3SVC/1)
  97. dwServiceType : the service type id
  98. pszServer : the structure to save the ip address
  99. pdwPort : the returned port number
  100. Return Value:
  101. sucess : ERROR_SUCCESS
  102. failure : the win32 error code of the failure
  103. --*/
  104. {
  105. DWORD dwStatus = ERROR_SUCCESS;
  106. DWORD dwR = 0;
  107. DWORD dwW = 0;
  108. TCHAR * achBindings = NULL;
  109. INT cBindingsSize = sizeof(TCHAR)*1024;
  110. TCHAR * pB = NULL;
  111. TCHAR * pP = NULL;
  112. DWORD cL = 0;
  113. BOOL bGetBindingsStatus = FALSE ;
  114. //
  115. // allocate space for the server bindings string
  116. //
  117. if( !(achBindings = (TCHAR*)LocalAlloc(LMEM_FIXED, cBindingsSize)) )
  118. {
  119. dwStatus = GetLastError();
  120. TR( (DEBUG_BUFFER,"[GetServerBindings] Can't allocate memory for server bindings info. (%d)\n",dwStatus) );
  121. }
  122. if ( achBindings )
  123. {
  124. //
  125. // Get binding info from metabase
  126. //
  127. CMetaData MD;
  128. if ( MD.Open( MDPath ) )
  129. {
  130. dwR = cBindingsSize;
  131. if( !(bGetBindingsStatus = MD.GetMultisz( L"",
  132. MD_SERVER_BINDINGS,
  133. IIS_MD_UT_SERVER,
  134. achBindings,
  135. &dwR )) )
  136. {
  137. dwStatus = GetLastError();
  138. if ( ERROR_INSUFFICIENT_BUFFER == dwStatus )
  139. {
  140. TR( (DEBUG_BUFFER,"[GetServerBindings] Buffer too small, reallocating\n") );
  141. //
  142. // (# 296798) If the original binding's buffer size is too small so realloc memory to the required size
  143. //
  144. TCHAR* achBindingsNew = (TCHAR*)LocalReAlloc(achBindings, dwR, 0);
  145. if( !achBindingsNew )
  146. {
  147. dwStatus = GetLastError();
  148. LocalFree (achBindings);
  149. achBindings = NULL;
  150. }
  151. else
  152. {
  153. achBindings = achBindingsNew;
  154. bGetBindingsStatus = MD.GetMultisz( L"",
  155. MD_SERVER_BINDINGS,
  156. IIS_MD_UT_SERVER,
  157. achBindings,
  158. &dwR );
  159. }
  160. }
  161. else
  162. {
  163. //
  164. // error getting server bindings information from the metabase
  165. //
  166. TR( (DEBUG_BUFFER,"[GetServerBindings] error getting server bindings information (%d)\n", dwStatus) );
  167. }
  168. }
  169. MD.Close();
  170. }
  171. else
  172. {
  173. dwStatus = GetLastError();
  174. TR( (DEBUG_BUFFER,"[GetServerBindings] failed to open MD, error %08x\n", dwStatus) );
  175. }
  176. }
  177. //
  178. // not getting server bindings information is a serious error
  179. //
  180. if ( !bGetBindingsStatus )
  181. {
  182. TR( (DEBUG_BUFFER,"[GetServerBindings] error getting server bindings infomation (%d) \n", dwStatus ) );
  183. }
  184. else
  185. {
  186. TR( (DEBUG_BUFFER,"[GetServerBindings] got server bindings string (%S) \n", achBindings ) );
  187. (*pdwPort) = DEFAULT_PORT[dwServiceType];
  188. ZeroMemory( psaServer, sizeof(SOCKADDR) );
  189. ((SOCKADDR_IN*)psaServer)->sin_family = AF_INET;
  190. ((SOCKADDR_IN*)psaServer)->sin_addr.s_net = 127;
  191. ((SOCKADDR_IN*)psaServer)->sin_addr.s_impno = 1;
  192. //
  193. // Each binding is of the form "addr:port:hostname"
  194. // we look only at addr & port
  195. //
  196. // use the 1st valid binding ( i.e. contains ':' )
  197. //
  198. dwR /= sizeof(WCHAR);
  199. for ( pB = achBindings ; *pB && dwR ; )
  200. {
  201. if ( (cL = wcslen( pB ) + 1 ) > dwR )
  202. {
  203. break;
  204. }
  205. if ( (pP = wcschr( pB, L':' )) )
  206. {
  207. SOCKADDR sa;
  208. INT cL = sizeof(sa);
  209. pP[0] = '\0';
  210. if ( achBindings[0] &&
  211. WSAStringToAddress( achBindings,
  212. AF_INET,
  213. NULL,
  214. &sa,
  215. &cL ) == 0 )
  216. {
  217. memcpy( psaServer, &sa, cL );
  218. }
  219. else
  220. {
  221. TR( (DEBUG_BUFFER,"[GetServerBindings] WSAStringToAddress failed converting string (%S) \n", achBindings ) );
  222. }
  223. if ( iswdigit(pP[1]) )
  224. {
  225. (*pdwPort) = wcstoul( pP + 1, NULL, 0 );
  226. }
  227. TR( (DEBUG_BUFFER,"[GetServerBindings] found binding addr %S %u.%u.%u.%u port %u\n",
  228. achBindings,
  229. ((SOCKADDR_IN*)psaServer)->sin_addr.s_net,
  230. ((SOCKADDR_IN*)psaServer)->sin_addr.s_host,
  231. ((SOCKADDR_IN*)psaServer)->sin_addr.s_lh,
  232. ((SOCKADDR_IN*)psaServer)->sin_addr.s_impno,
  233. (*pdwPort) ) );
  234. goto found_bindings;
  235. }
  236. pB += cL;
  237. dwR -= cL;
  238. }
  239. }
  240. found_bindings:
  241. if( achBindings )
  242. {
  243. LocalFree(achBindings);
  244. achBindings = NULL;
  245. }
  246. return dwStatus ;
  247. } // GetServerBindings
  248. CHAR IsAliveRequest[]="TRACK / HTTP/1.1\r\nHost: CLUSIIS\r\nConnection: close\r\nContent-length: 0\r\n\r\n"; // # 292727
  249. DWORD
  250. VerifyIISService(
  251. IN LPWSTR MDPath,
  252. IN DWORD ServiceType,
  253. IN DWORD dwPort,
  254. IN SOCKADDR saServer,
  255. IN PLOG_EVENT_ROUTINE LogEvent
  256. )
  257. /*++
  258. Routine Description:
  259. Verify that the IIS service is running and that it has virtual roots
  260. contained in the resource
  261. Steps:
  262. 1. get server instance binding info
  263. 2. connect to server, send HTTP request & wait for response
  264. Arguments:
  265. Resource - supplies the resource id
  266. IsAliveFlag - says this is an IsAlive call
  267. Return Value:
  268. TRUE - if service is running and service contains resources virtual roots
  269. FALSE - service is in any other state
  270. --*/
  271. {
  272. DWORD status = ERROR_SUCCESS;
  273. DWORD dwR;
  274. DWORD dwW;
  275. SOCKET s;
  276. CHAR IsAliveResponse[1024];
  277. TR( (DEBUG_BUFFER,"[IISVerify] Enter\n") );
  278. TR( (DEBUG_BUFFER,"[IISVerify] checking address %S : %u.%u.%u.%u port %u\n",
  279. MDPath,
  280. ((SOCKADDR_IN*)&saServer)->sin_addr.s_net,
  281. ((SOCKADDR_IN*)&saServer)->sin_addr.s_host,
  282. ((SOCKADDR_IN*)&saServer)->sin_addr.s_lh,
  283. ((SOCKADDR_IN*)&saServer)->sin_addr.s_impno,
  284. dwPort ) );
  285. if ( (s = TcpSockConnectToHost( &saServer,
  286. dwPort,
  287. CHECK_IS_ALIVE_CONNECT_TIMEOUT )) != NULL )
  288. {
  289. if ( ServiceType == IIS_SERVICE_TYPE_W3 )
  290. {
  291. //
  292. // If this is W3 then attempt to send a request and get response from server.
  293. //
  294. if ( TcpSockSend( s,
  295. IsAliveRequest,
  296. sizeof(IsAliveRequest),
  297. &dwW,
  298. CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
  299. TcpSockRecv( s,
  300. IsAliveResponse,
  301. sizeof(IsAliveResponse),
  302. &dwR,
  303. CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
  304. dwR > 5 )
  305. {
  306. status = ERROR_SUCCESS;
  307. TcpSockClose( s );
  308. goto finished_check;
  309. }
  310. else
  311. {
  312. TR( (DEBUG_BUFFER,"[IISVerify] failed HTTP request\n") );
  313. status = ERROR_SERVICE_NOT_ACTIVE;
  314. }
  315. }
  316. else if ( ServiceType == IIS_SERVICE_TYPE_SMTP )
  317. {
  318. //
  319. // If this is SMTP then check the reply code.
  320. // (220: service ready)
  321. //
  322. if ( TcpSockRecv( s,
  323. IsAliveResponse,
  324. sizeof(IsAliveResponse),
  325. &dwR,
  326. CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
  327. strncmp( IsAliveResponse, "220", 3 ) == 0 )
  328. {
  329. status = ERROR_SUCCESS;
  330. TcpSockClose( s );
  331. goto finished_check;
  332. }
  333. else
  334. {
  335. TR( (DEBUG_BUFFER,"[IISVerify] failed SMTP request, response:%S\n", IsAliveResponse) );
  336. status = ERROR_SERVICE_NOT_ACTIVE;
  337. }
  338. }
  339. else if ( ServiceType == IIS_SERVICE_TYPE_NNTP )
  340. {
  341. //
  342. // If this is NNTP then check the reply code.
  343. // (200: service ready - posting allowed) or
  344. // (201: service ready - no posting allowed)
  345. //
  346. if ( TcpSockRecv( s,
  347. IsAliveResponse,
  348. sizeof(IsAliveResponse),
  349. &dwR,
  350. CHECK_IS_ALIVE_SEND_TIMEOUT ) &&
  351. ( strncmp( IsAliveResponse, "200", 3 ) == 0 ||
  352. strncmp( IsAliveResponse, "201", 3 ) == 0 ) )
  353. {
  354. status = ERROR_SUCCESS;
  355. TcpSockClose( s );
  356. goto finished_check;
  357. }
  358. else
  359. {
  360. TR( (DEBUG_BUFFER,"[IISVerify] failed NNTP request, response:%S\n", IsAliveResponse) );
  361. status = ERROR_SERVICE_NOT_ACTIVE;
  362. }
  363. }
  364. else
  365. {
  366. status = ERROR_SUCCESS;
  367. TcpSockClose( s );
  368. goto finished_check;
  369. }
  370. TcpSockClose( s );
  371. }
  372. else
  373. {
  374. TR( (DEBUG_BUFFER,"[IISVerify] failed to connect port %d\n", dwPort) );
  375. status = ERROR_SERVICE_NOT_ACTIVE;
  376. }
  377. finished_check:
  378. //
  379. // Check to see if there was an error
  380. //
  381. if ( status != ERROR_SUCCESS )
  382. {
  383. TR( (DEBUG_BUFFER,"[IISVerify] FALSE (%d), Leave\n", status) );
  384. #if defined(DBG_CANT_VERIFY)
  385. g_fDbgCantVerify = TRUE;
  386. #endif
  387. }
  388. else
  389. {
  390. TR( (DEBUG_BUFFER,"[IISVerify] TRUE, Leave\n") );
  391. }
  392. return status;
  393. } // VerifyIISService
  394. LPWSTR
  395. GetClusterResourceType(
  396. HRESOURCE hResource,
  397. LPIIS_RESOURCE ResourceEntry,
  398. IN PLOG_EVENT_ROUTINE LogEvent
  399. )
  400. /*++
  401. Routine Description:
  402. Returns the resource type for the resource
  403. Arguments:
  404. hResource - handle to a resource
  405. Return Value:
  406. TRUE - if service is running and service contains resources virtual roots
  407. FALSE - service is in any other state
  408. --*/
  409. {
  410. DWORD dwType = 0;
  411. DWORD dwSize = MAX_DEFAULT_WSTRING_SIZE;
  412. WCHAR lpzTypeName[MAX_DEFAULT_WSTRING_SIZE];
  413. LPWSTR TypeName = NULL;
  414. HKEY hKey = NULL;
  415. LONG status;
  416. (LogEvent)(
  417. ResourceEntry->ResourceHandle,
  418. LOG_ERROR,
  419. L"[GetClusterResourceType] entry\n");
  420. //
  421. // Valid resource now open the reg and get it's type
  422. //
  423. hKey = GetClusterResourceKey(hResource,KEY_READ);
  424. if (hKey == NULL)
  425. {
  426. (LogEvent)(
  427. ResourceEntry->ResourceHandle,
  428. LOG_ERROR,
  429. L"[GetClusterResourceType] Unable to open resource key = %1!u!\n",GetLastError());
  430. return(NULL);
  431. }
  432. //
  433. // Got a valid key now get the type
  434. //
  435. status = ClusterRegQueryValue(hKey,L"Type",&dwType,(LPBYTE)lpzTypeName,&dwSize);
  436. if (status == ERROR_SUCCESS)
  437. {
  438. TypeName = (WCHAR*)LocalAlloc(LMEM_FIXED,(dwSize+16)*sizeof(WCHAR));
  439. if (TypeName != NULL)
  440. {
  441. wcscpy(TypeName,lpzTypeName);
  442. } // TypeName != NULL
  443. }
  444. else
  445. {
  446. (LogEvent)(
  447. ResourceEntry->ResourceHandle,
  448. LOG_ERROR,
  449. L"[GetClusterResourceType] Unable to Query Value = %1!u!\n",status);
  450. }
  451. ClusterRegCloseKey(hKey);
  452. (LogEvent)(
  453. ResourceEntry->ResourceHandle,
  454. LOG_ERROR,
  455. L"[GetClusterResourceType] TypeName = %1!ws!\n",TypeName);
  456. return TypeName;
  457. }// end GetClusterResourceType
  458. HRESOURCE
  459. ClusterGetResourceDependency(
  460. IN LPCWSTR ResourceName,
  461. IN LPCWSTR ResourceType,
  462. IN LPIIS_RESOURCE ResourceEntry,
  463. IN PLOG_EVENT_ROUTINE LogEvent
  464. )
  465. /*++
  466. Routine Description:
  467. Returns a dependent resource
  468. Arguments:
  469. ResourceName - the resource
  470. ResourceType - the type of resource that it depends on
  471. Return Value:
  472. NULL - error (use GetLastError() to get further info)
  473. NON-NULL - Handle to a resource of type ResourceType
  474. --*/
  475. {
  476. HCLUSTER hCluster = NULL;
  477. HRESOURCE hResource = NULL;
  478. HRESOURCE hResDepends = NULL;
  479. HRESENUM hResEnum = NULL;
  480. DWORD dwType = 0;
  481. DWORD dwIndex = 0;
  482. DWORD dwSize = MAX_DEFAULT_WSTRING_SIZE;
  483. WCHAR lpszName[MAX_DEFAULT_WSTRING_SIZE];
  484. LPWSTR ResTypeName = NULL;
  485. DWORD status;
  486. //
  487. // Open the cluster
  488. //
  489. hCluster = OpenCluster(NULL);
  490. if (hCluster == NULL)
  491. {
  492. (LogEvent)(
  493. ResourceEntry->ResourceHandle,
  494. LOG_ERROR,
  495. L"[ClusterGetResourceDependency] Unable to OpenCluster status = %1!u!\n",GetLastError());
  496. return(NULL);
  497. }
  498. //
  499. // Open the resource
  500. //
  501. hResource = OpenClusterResource(hCluster,ResourceName);
  502. if (hResource == NULL)
  503. {
  504. (LogEvent)(
  505. ResourceEntry->ResourceHandle,
  506. LOG_ERROR,
  507. L"[ClusterGetResourceDependency] Unable to OpenClusterResource status = %1!u!\n",GetLastError());
  508. goto error_exit;
  509. }
  510. //
  511. // Open the depends on enum
  512. //
  513. hResEnum = ClusterResourceOpenEnum(hResource,CLUSTER_RESOURCE_ENUM_DEPENDS);
  514. if (hResEnum == NULL)
  515. {
  516. (LogEvent)(
  517. ResourceEntry->ResourceHandle,
  518. LOG_ERROR,
  519. L"[ClusterGetResourceDependency] Unsuccessful ClusterResourceOpenEnum status = %1!u!\n",GetLastError());
  520. goto error_exit;
  521. }
  522. //
  523. // Enumerate all the depends on keys
  524. //
  525. do {
  526. dwSize = MAX_DEFAULT_WSTRING_SIZE;
  527. status = ClusterResourceEnum(hResEnum,dwIndex++,&dwType,lpszName,&dwSize);
  528. if ((status != ERROR_SUCCESS) && (status != ERROR_MORE_DATA))
  529. {
  530. //
  531. // This checks to see if NO dependencies were found
  532. //
  533. if ((status == ERROR_NO_MORE_ITEMS) && (dwIndex == 1))
  534. {
  535. SetLastError( ERROR_NO_DATA );
  536. }
  537. else
  538. {
  539. SetLastError( status );
  540. }
  541. goto error_exit;
  542. }
  543. //
  544. // Determine the type of resource found
  545. //
  546. hResDepends = OpenClusterResource(hCluster,lpszName);
  547. if (hResDepends == NULL)
  548. {
  549. (LogEvent)(
  550. ResourceEntry->ResourceHandle,
  551. LOG_ERROR,
  552. L"[ClusterGetResourceDependency] Unsuccessful OpenClusterResource status = %1!u!\n",GetLastError());
  553. }
  554. else
  555. {
  556. //
  557. // Valid resource now open the reg and get it's type
  558. //
  559. ResTypeName = GetClusterResourceType(hResDepends,ResourceEntry,LogEvent);
  560. if (ResTypeName == NULL)
  561. {
  562. (LogEvent)(
  563. ResourceEntry->ResourceHandle,
  564. LOG_ERROR,
  565. L"[ClusterGetResourceDependency] Unsuccessful GetClusterResourceType status = %1!u!\n",GetLastError());
  566. }
  567. else
  568. {
  569. //
  570. // Compare the types and look for a match
  571. //
  572. if ( (_wcsicmp(ResTypeName,ResourceType)) == 0)
  573. {
  574. //
  575. //Found a match
  576. //
  577. goto success_exit;
  578. } // END _wcsicmp(ResTypeName,ResourceType)
  579. } // END if ResourceTypeName != NULL
  580. } // END if hResDepends != NULL
  581. //
  582. // Close all handles, key's
  583. //
  584. if (hResDepends != NULL)
  585. {
  586. CloseClusterResource(hResDepends);
  587. hResDepends = NULL;
  588. }
  589. } while ((status == ERROR_SUCCESS) || (status == ERROR_MORE_DATA));
  590. if (hResDepends == NULL)
  591. {
  592. (LogEvent)(
  593. ResourceEntry->ResourceHandle,
  594. LOG_ERROR,
  595. L"[ClusterGetResourceDependency] Unsuccessful resource enum status = %1!u! %2!x! last error = %3!u!\n",status,status,GetLastError());
  596. }
  597. success_exit:
  598. error_exit:
  599. //
  600. // At this point hResDepends is NULL if no match or non-null (success)
  601. //
  602. if (hCluster != NULL)
  603. {
  604. CloseCluster(hCluster);
  605. }
  606. if (hResource != NULL)
  607. {
  608. CloseClusterResource(hResource);
  609. }
  610. if (hResEnum != NULL)
  611. {
  612. ClusterResourceCloseEnum(hResEnum);
  613. }
  614. return hResDepends;
  615. } // ClusterGetResourceDependency
  616. DWORD
  617. SetInstanceState(
  618. IN PCLUS_WORKER pWorker,
  619. IN LPIIS_RESOURCE ResourceEntry,
  620. IN RESOURCE_STATUS* presourceStatus,
  621. IN CLUSTER_RESOURCE_STATE TargetState,
  622. IN LPWSTR TargetStateString,
  623. IN DWORD dwMdPropControl,
  624. IN DWORD dwMdPropTarget
  625. )
  626. /*++
  627. Routine Description:
  628. Set the server instance to te requested state ( start / stop )
  629. Arguments:
  630. pWorker - thread context to monitor for cancel request
  631. ResourceEntry - ptr to IIS server instance resource ctx
  632. presourceStatus - ptr to struct to be updated with new status
  633. TargetState - cluster API target state
  634. dwMdPropControl - IIS metabase property value for request to server
  635. dwMdPropTarget - IIS metabase property value for target state
  636. Return Value:
  637. Win32 error code, ERROR_SUCCESS if success
  638. --*/
  639. {
  640. DWORD status = ERROR_SERVICE_NOT_ACTIVE;
  641. int retry;
  642. DWORD dwS;
  643. DWORD dwEnabled;
  644. CMetaData MD;
  645. TR( (DEBUG_BUFFER,"[SetInstanceState] Enter\n") );
  646. if ( MD.Open( ResourceEntry->Params.MDPath,
  647. TRUE,
  648. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
  649. {
  650. //
  651. // Reenable clustering. If we are receiving this notification we know
  652. // enabled should be set to true.
  653. //
  654. if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwEnabled, 0 ) ||
  655. dwEnabled == 0 )
  656. {
  657. TR( (DEBUG_BUFFER,"[SetInstanceState] cluster not enabled\n") );
  658. if ( !MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 1, 0 ) )
  659. {
  660. TR( (DEBUG_BUFFER,"[SetInstanceState] failed to re-enable cluster\n") );
  661. }
  662. }
  663. if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  664. {
  665. TR( (DEBUG_BUFFER,"[SetInstanceState] state prob is %d\n",dwS) );
  666. }
  667. else
  668. {
  669. TR( (DEBUG_BUFFER,"[SetInstanceState] failed to probe server state\n") );
  670. dwS = 0xffffffff;
  671. }
  672. if ( dwS != dwMdPropTarget )
  673. {
  674. if ( MD.SetDword( L"", MD_CLUSTER_SERVER_COMMAND, IIS_MD_UT_SERVER, dwMdPropControl, 0 ) )
  675. {
  676. MD.Close();
  677. TR( (DEBUG_BUFFER,"[SetInstanceState] command set to %d\n",dwMdPropControl) );
  678. for ( retry = (TargetState == ClusterResourceOnline) ? IISCLUS_ONLINE_TIMEOUT :IISCLUS_OFFLINE_TIMEOUT ;
  679. retry-- ; )
  680. {
  681. if ( ClusWorkerCheckTerminate(pWorker) )
  682. {
  683. status = ERROR_OPERATION_ABORTED;
  684. break;
  685. }
  686. if ( MD.GetDword( ResourceEntry->Params.MDPath, MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  687. {
  688. if ( dwS == dwMdPropTarget )
  689. {
  690. status = ERROR_SUCCESS;
  691. break;
  692. }
  693. TR( (DEBUG_BUFFER,"[SetInstanceState] state is %d, waiting for %d\n",dwS,dwMdPropTarget) );
  694. }
  695. else
  696. {
  697. TR( (DEBUG_BUFFER,"[SetInstanceState] failed to get server state\n") );
  698. break;
  699. }
  700. Sleep(SERVER_START_DELAY);
  701. }
  702. }
  703. else
  704. {
  705. TR( (DEBUG_BUFFER,"[SetInstanceState] failed to set server command to %d\n",dwMdPropControl) );
  706. MD.Close();
  707. }
  708. }
  709. else
  710. {
  711. status = ERROR_SUCCESS;
  712. MD.Close();
  713. }
  714. }
  715. else
  716. {
  717. if ( g_hEventLog && TargetState == ClusterResourceOnline )
  718. {
  719. LPCTSTR aErrStr[3];
  720. WCHAR aErrCode[32];
  721. _ultow( GetLastError(), aErrCode, 10 );
  722. aErrStr[0] = ResourceEntry->Params.ServiceName;
  723. aErrStr[1] = ResourceEntry->Params.InstanceId;
  724. aErrStr[2] = aErrCode;
  725. ReportEvent( g_hEventLog,
  726. EVENTLOG_ERROR_TYPE,
  727. 0,
  728. IISCL_EVENT_CANT_OPEN_METABASE,
  729. NULL,
  730. sizeof(aErrStr) / sizeof(LPCTSTR),
  731. 0,
  732. aErrStr,
  733. NULL );
  734. }
  735. TR( (DEBUG_BUFFER,"[SetInstanceState] failed to open %S, error %08x\n",ResourceEntry->Params.MDPath, GetLastError()) );
  736. }
  737. if ( status != ERROR_SUCCESS )
  738. {
  739. //
  740. // Error
  741. //
  742. (g_IISLogEvent)(
  743. ResourceEntry->ResourceHandle,
  744. LOG_ERROR,
  745. L"Error %1!u! cannot bring resource %2!ws! %3!ws!.\n",
  746. status,
  747. ResourceEntry->ResourceName,
  748. TargetStateString );
  749. presourceStatus->ResourceState = ClusterResourceFailed;
  750. ResourceEntry->State = ClusterResourceFailed;
  751. }
  752. else
  753. {
  754. //
  755. // Success, update state, log message
  756. //
  757. presourceStatus->ResourceState = TargetState;
  758. ResourceEntry->State = TargetState;
  759. TR( (DEBUG_BUFFER,"[SetInstanceState] Setting Metadata Path:%S ResourceEntry->State:%d\n", ResourceEntry->Params.MDPath, TargetState) );
  760. (g_IISLogEvent)(
  761. ResourceEntry->ResourceHandle,
  762. LOG_INFORMATION,
  763. L"Success bringing resource %1!ws! %2!ws!.\n",
  764. ResourceEntry->ResourceName,
  765. TargetStateString );
  766. }
  767. TR( (DEBUG_BUFFER,"[SetInstanceState] status = %d, Leave\n",status) );
  768. return status;
  769. }
  770. DWORD
  771. InstanceEnableCluster(
  772. LPWSTR pwszServiceName,
  773. LPWSTR pwszInstanceId
  774. )
  775. /*++
  776. Routine Description:
  777. Ensure server instance in state consistent with cluster membership.
  778. If not already part of a cluster, stop instance & flag it as cluster enabled
  779. Arguments:
  780. pwszServiceName - IIS service name ( e.g. W3SVC )
  781. pwszInstanceId - IIS serverr instance ID
  782. Return Value:
  783. win32 error code or ERROR_SUCCESS if success
  784. --*/
  785. {
  786. DWORD status = ERROR_SERVICE_NOT_ACTIVE;
  787. int retry;
  788. DWORD dwS;
  789. TCHAR achMDPath[80];
  790. DWORD dwL;
  791. dwL = wsprintf( achMDPath, L"/LM/%s/%s", pwszServiceName, pwszInstanceId );
  792. CMetaData MD;
  793. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] for %S, Enter\n", achMDPath ) );
  794. if ( MD.Open( achMDPath,
  795. TRUE,
  796. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
  797. {
  798. //
  799. // ensure instance is marked as cluster enabled
  800. //
  801. if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwS, 0 ) ||
  802. dwS == 0 )
  803. {
  804. if ( MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 1, 0 ) )
  805. {
  806. if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  807. {
  808. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] state prob is %d\n",dwS) );
  809. }
  810. else
  811. {
  812. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to probe server state\n") );
  813. dwS = 0xffffffff;
  814. }
  815. MD.Close();
  816. if ( dwS != MD_SERVER_STATE_STOPPED )
  817. {
  818. if ( MD.Open( achMDPath,
  819. TRUE,
  820. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) &&
  821. MD.SetDword( L"",
  822. MD_CLUSTER_SERVER_COMMAND,
  823. IIS_MD_UT_SERVER,
  824. MD_SERVER_COMMAND_STOP,
  825. 0 ) )
  826. {
  827. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] command set to %d\n",MD_SERVER_COMMAND_STOP) );
  828. for ( retry = 30 ; retry-- ; )
  829. {
  830. if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  831. {
  832. if ( dwS == MD_SERVER_STATE_STOPPED )
  833. {
  834. status = ERROR_SUCCESS;
  835. break;
  836. }
  837. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] state is %d, waiting for %d\n",dwS,MD_SERVER_STATE_STOPPED) );
  838. }
  839. else
  840. {
  841. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to get server state\n") );
  842. break;
  843. }
  844. Sleep(SERVER_START_DELAY);
  845. }
  846. }
  847. else
  848. {
  849. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_STOP) );
  850. }
  851. }
  852. else
  853. {
  854. status = ERROR_SUCCESS;
  855. }
  856. }
  857. else
  858. {
  859. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to set cluster enabled\n") );
  860. }
  861. }
  862. }
  863. else
  864. {
  865. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] failed to open %S, error %08x\n",achMDPath, GetLastError()) );
  866. }
  867. TR( (DEBUG_BUFFER,"[InstanceEnableCluster] status = %d, Leave\n",status) );
  868. MD.Close();
  869. return status;
  870. }
  871. DWORD
  872. InstanceDisableCluster(
  873. LPWSTR pwszServiceName,
  874. LPWSTR pwszInstanceId
  875. )
  876. /*++
  877. Routine Description:
  878. Ensure server instance in state consistent with cluster membership.
  879. If already part of a cluster, stop instance & remove its cluster enabled flag.
  880. Arguments:
  881. pwszServiceName - IIS service name ( e.g. W3SVC )
  882. pwszInstanceId - IIS serverr instance ID
  883. Return Value:
  884. win32 error code or ERROR_SUCCESS if success
  885. --*/
  886. {
  887. DWORD status = ERROR_SERVICE_NOT_ACTIVE;
  888. int retry;
  889. DWORD dwS;
  890. TCHAR achMDPath[80];
  891. DWORD dwL;
  892. dwL = wsprintf( achMDPath, L"/LM/%s/%s", pwszServiceName, pwszInstanceId );
  893. CMetaData MD;
  894. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] for %S, Enter\n", achMDPath ) );
  895. if ( MD.Open( achMDPath,
  896. TRUE,
  897. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) )
  898. {
  899. //
  900. // ensure instance is marked as cluster enabled
  901. //
  902. if ( !MD.GetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, &dwS, 0 ) ||
  903. ( dwS == 0) )
  904. {
  905. MD.Close();
  906. return status;
  907. }
  908. if ( MD.SetDword( L"", MD_CLUSTER_ENABLED, IIS_MD_UT_SERVER, 0, 0 ) )
  909. {
  910. if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  911. {
  912. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] state prob is %d\n",dwS) );
  913. }
  914. else
  915. {
  916. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to probe server state\n") );
  917. dwS = 0xffffffff;
  918. }
  919. MD.Close();
  920. if ( dwS != MD_SERVER_STATE_STOPPED )
  921. {
  922. if ( MD.Open( achMDPath,
  923. TRUE,
  924. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) &&
  925. MD.SetDword( L"",
  926. MD_SERVER_COMMAND,
  927. IIS_MD_UT_SERVER,
  928. MD_SERVER_COMMAND_STOP,
  929. 0 ))
  930. {
  931. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] command set to %d\n",MD_SERVER_COMMAND_STOP) );
  932. for ( retry = 30 ; retry-- ; )
  933. {
  934. if ( MD.GetDword( L"", MD_SERVER_STATE, IIS_MD_UT_SERVER, &dwS, 0 ) )
  935. {
  936. if ( dwS == MD_SERVER_STATE_STOPPED )
  937. {
  938. break;
  939. }
  940. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] state is %d, waiting for %d\n",dwS,MD_SERVER_STATE_STOPPED) );
  941. }
  942. else
  943. {
  944. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to get server state\n") );
  945. break;
  946. }
  947. Sleep(SERVER_START_DELAY);
  948. }
  949. }
  950. else
  951. {
  952. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_STOP) );
  953. }
  954. MD.Close();
  955. //
  956. // restart the server
  957. //
  958. if ( MD.Open( achMDPath,
  959. TRUE,
  960. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) &&
  961. MD.SetDword( L"",
  962. MD_SERVER_COMMAND,
  963. IIS_MD_UT_SERVER,
  964. MD_SERVER_COMMAND_START,
  965. 0 ))
  966. {
  967. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] set server command to %d\n",MD_SERVER_COMMAND_START) );
  968. }
  969. else
  970. {
  971. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set server command to %d\n",MD_SERVER_COMMAND_START) );
  972. }
  973. status = ERROR_SUCCESS;
  974. }
  975. }
  976. else
  977. {
  978. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to set cluster disbled\n") );
  979. }
  980. }
  981. else
  982. {
  983. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] failed to open %S, error %08x\n",achMDPath, GetLastError()) );
  984. }
  985. MD.Close();
  986. TR( (DEBUG_BUFFER,"[InstanceDisableCluster] status = %d, Leave\n",status) );
  987. return status;
  988. }
  989. BOOL
  990. CMetaData::Open(
  991. LPWSTR pszPath,
  992. BOOL fReconnect,
  993. DWORD dwFlags
  994. )
  995. /*++
  996. Routine Description:
  997. Opens the metabase
  998. Arguments:
  999. pszPath - Path to open
  1000. dwFlags - Open flags
  1001. Return:
  1002. TRUE if success, FALSE on error, (call GetLastError())
  1003. --*/
  1004. {
  1005. HRESULT hRes;
  1006. TR( (DEBUG_BUFFER,"[MDOpen] %S\n",pszPath) );
  1007. if ( !GetCoInit() )
  1008. {
  1009. TR( (DEBUG_BUFFER,"[MDOpen] calling CoInit\n") );
  1010. hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1011. if ( FAILED(hRes) )
  1012. {
  1013. TR( (DEBUG_BUFFER,"[MD:GetMD::CoInitializeEx] error %08x\n",HRESULTTOWIN32( hRes )) );
  1014. SetLastError( HRESULTTOWIN32( hRes ) );
  1015. return FALSE;
  1016. }
  1017. SetCoInit( TRUE );
  1018. }
  1019. EnterCriticalSection( &g_cs );
  1020. for ( int retry = 2 ; retry-- ; )
  1021. {
  1022. if ( !GetMD() )
  1023. {
  1024. LeaveCriticalSection( &g_cs );
  1025. TR( (DEBUG_BUFFER,"[MDOpen] can't get MD interface\n") );
  1026. return FALSE;
  1027. }
  1028. TR( (DEBUG_BUFFER,"[MDOpen] before OpenKey\n") );
  1029. hRes = g_pMBCom->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  1030. pszPath,
  1031. dwFlags,
  1032. MB_TIMEOUT,
  1033. &m_hMB );
  1034. if ( SUCCEEDED( hRes ) )
  1035. {
  1036. LeaveCriticalSection( &g_cs );
  1037. TR( (DEBUG_BUFFER,"[MDOpen] OK, leave\n") );
  1038. return TRUE;
  1039. }
  1040. if ( !fReconnect )
  1041. {
  1042. break;
  1043. }
  1044. TR( (DEBUG_BUFFER,"[MDOpen] error %d, fReconnect=%d\n",HRESULTTOWIN32( hRes ),fReconnect) );
  1045. if ( HRESULTTOWIN32( hRes ) == RPC_S_SERVER_UNAVAILABLE ||
  1046. HRESULTTOWIN32( hRes ) == RPC_S_CALL_FAILED_DNE )
  1047. {
  1048. ReleaseMD();
  1049. }
  1050. else
  1051. {
  1052. break;
  1053. }
  1054. }
  1055. SetLastError( HRESULTTOWIN32( hRes ) );
  1056. LeaveCriticalSection( &g_cs );
  1057. return FALSE;
  1058. }
  1059. BOOL
  1060. CMetaData::Close(
  1061. VOID
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Close opened handle to metadata
  1066. Arguments:
  1067. None
  1068. Return Value:
  1069. TRUE if success, otherwise FALSE
  1070. --*/
  1071. {
  1072. if ( m_hMB )
  1073. {
  1074. g_pMBCom->CloseKey( m_hMB );
  1075. m_hMB = NULL;
  1076. }
  1077. return TRUE;
  1078. }
  1079. BOOL
  1080. CMetaData::SetData(
  1081. LPWSTR pszPath,
  1082. DWORD dwPropID,
  1083. DWORD dwUserType,
  1084. DWORD dwDataType,
  1085. VOID * pvData,
  1086. DWORD cbData,
  1087. DWORD dwFlags
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. Sets a metadata property on an openned metabase
  1092. Arguments:
  1093. pszPath - Path to set data on
  1094. dwPropID - Metabase property ID
  1095. dwUserType - User type for this property
  1096. dwDataType - Type of data being set (dword, string etc)
  1097. pvData - Pointer to data
  1098. cbData - Size of data
  1099. dwFlags - Inheritance flags
  1100. Return:
  1101. TRUE if success, FALSE on error, (call GetLastError())
  1102. --*/
  1103. {
  1104. METADATA_RECORD mdRecord;
  1105. HRESULT hRes;
  1106. mdRecord.dwMDIdentifier = dwPropID;
  1107. mdRecord.dwMDAttributes = dwFlags;
  1108. mdRecord.dwMDUserType = dwUserType;
  1109. mdRecord.dwMDDataType = dwDataType;
  1110. mdRecord.dwMDDataLen = cbData;
  1111. mdRecord.pbMDData = (PBYTE) pvData;
  1112. EnterCriticalSection( &g_cs );
  1113. if ( !GetMD() )
  1114. {
  1115. LeaveCriticalSection( &g_cs );
  1116. return FALSE;
  1117. }
  1118. hRes = g_pMBCom->SetData( m_hMB,
  1119. pszPath,
  1120. &mdRecord );
  1121. if ( SUCCEEDED( hRes ))
  1122. {
  1123. LeaveCriticalSection( &g_cs );
  1124. return TRUE;
  1125. }
  1126. SetLastError( HRESULTTOWIN32( hRes ) );
  1127. LeaveCriticalSection( &g_cs );
  1128. return FALSE;
  1129. }
  1130. BOOL
  1131. CMetaData::GetData(
  1132. LPWSTR pszPath,
  1133. DWORD dwPropID,
  1134. DWORD dwUserType,
  1135. DWORD dwDataType,
  1136. VOID * pvData,
  1137. DWORD * pcbData,
  1138. DWORD dwFlags
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. Retrieves a metadata property on an openned metabase
  1143. Arguments:
  1144. pszPath - Path to set data on
  1145. dwPropID - Metabase property ID
  1146. dwUserType - User type for this property
  1147. dwDataType - Type of data being set (dword, string etc)
  1148. pvData - Pointer to data
  1149. pcbData - Size of pvData, receives size of object
  1150. dwFlags - Inheritance flags
  1151. Return:
  1152. TRUE if success, FALSE on error, (call GetLastError())
  1153. --*/
  1154. {
  1155. METADATA_RECORD mdRecord;
  1156. HRESULT hRes;
  1157. DWORD dwRequiredLen;
  1158. BOOL fConvert;
  1159. mdRecord.pbMDData = (PBYTE) pvData;
  1160. mdRecord.dwMDDataLen = *pcbData;
  1161. mdRecord.dwMDIdentifier = dwPropID;
  1162. mdRecord.dwMDAttributes = dwFlags;
  1163. mdRecord.dwMDUserType = dwUserType;
  1164. mdRecord.dwMDDataType = dwDataType;
  1165. EnterCriticalSection( &g_cs );
  1166. if ( !GetMD() )
  1167. {
  1168. LeaveCriticalSection( &g_cs );
  1169. return FALSE;
  1170. }
  1171. hRes = g_pMBCom->GetData( m_hMB,
  1172. pszPath,
  1173. &mdRecord,
  1174. &dwRequiredLen );
  1175. if ( SUCCEEDED( hRes ))
  1176. {
  1177. LeaveCriticalSection( &g_cs );
  1178. *pcbData = mdRecord.dwMDDataLen;
  1179. return TRUE;
  1180. }
  1181. LeaveCriticalSection( &g_cs );
  1182. *pcbData = dwRequiredLen;
  1183. SetLastError( HRESULTTOWIN32( hRes ) );
  1184. return FALSE;
  1185. }
  1186. BOOL
  1187. CMetaData::Init(
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. Initialize access to metadata
  1192. Arguments:
  1193. None
  1194. Return Value:
  1195. TRUE if success, otherwise FALSE
  1196. --*/
  1197. {
  1198. INITIALIZE_CRITICAL_SECTION( &g_cs );
  1199. g_pMBCom = NULL;
  1200. return TRUE;
  1201. }
  1202. BOOL
  1203. CMetaData::Terminate(
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. Terminate access to metadata
  1208. Arguments:
  1209. None
  1210. Return Value:
  1211. TRUE if success, otherwise FALSE
  1212. --*/
  1213. {
  1214. DeleteCriticalSection( &g_cs );
  1215. if ( g_pMBCom )
  1216. {
  1217. if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
  1218. {
  1219. return FALSE;
  1220. }
  1221. g_pMBCom->Release();
  1222. g_pMBCom = NULL;
  1223. }
  1224. return TRUE;
  1225. }
  1226. BOOL
  1227. CMetaData::GetMD(
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. Initialize interface pointer to DCOM metabase object
  1232. Arguments:
  1233. None
  1234. Return Value:
  1235. TRUE if success, otherwise FALSE
  1236. --*/
  1237. {
  1238. if ( g_pMBCom == NULL )
  1239. {
  1240. HRESULT hRes;
  1241. hRes = CoCreateInstance(CLSID_MSAdminBase, NULL,
  1242. CLSCTX_SERVER, IID_IMSAdminBase, (void**) &g_pMBCom);
  1243. TR( (DEBUG_BUFFER,"[MD:GetMD] called cocreate\n") );
  1244. if ( hRes == CO_E_NOTINITIALIZED )
  1245. {
  1246. TR( (DEBUG_BUFFER,"[MD:GetMD] call coinit\n") );
  1247. hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1248. if ( FAILED(hRes) )
  1249. {
  1250. TR( (DEBUG_BUFFER,"[MD:GetMD::CoInitializeEx] error %08x\n",HRESULTTOWIN32( hRes )) );
  1251. SetLastError( HRESULTTOWIN32( hRes ) );
  1252. return FALSE;
  1253. }
  1254. hRes = CoCreateInstance(CLSID_MSAdminBase, NULL,
  1255. CLSCTX_SERVER, IID_IMSAdminBase, (void**) &g_pMBCom);
  1256. }
  1257. if ( FAILED(hRes) )
  1258. {
  1259. TR( (DEBUG_BUFFER,"[MD:GetMD] error %08x\n",HRESULTTOWIN32( hRes )) );
  1260. SetLastError( HRESULTTOWIN32( hRes ) );
  1261. return FALSE;
  1262. }
  1263. }
  1264. return TRUE;
  1265. }
  1266. BOOL
  1267. CMetaData::ReleaseMD(
  1268. )
  1269. /*++
  1270. Routine Description:
  1271. Release interface pointer to DCOM metabase object
  1272. Arguments:
  1273. None
  1274. Return Value:
  1275. TRUE if success, otherwise FALSE
  1276. --*/
  1277. {
  1278. if ( g_pMBCom )
  1279. {
  1280. g_pMBCom->Release();
  1281. g_pMBCom = NULL;
  1282. }
  1283. return TRUE;
  1284. }
  1285. SOCKET
  1286. TcpSockConnectToHost(
  1287. SOCKADDR* psaServer,
  1288. DWORD dwPort,
  1289. DWORD dwTimeOut
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. Create a TCP connection to specified port on specified machine
  1294. Arguments:
  1295. psaServer - target address
  1296. dwPort - target port to connect to
  1297. dwTimeOut - time out for connection ( in seconds )
  1298. Return Value:
  1299. socket or NULL if error
  1300. --*/
  1301. {
  1302. SOCKET sNew;
  1303. BOOL fWrite = FALSE;
  1304. INT serr = 0;
  1305. SOCKADDR_IN inAddr;
  1306. PSOCKADDR addr;
  1307. INT addrLength;
  1308. sNew = WSASocket(
  1309. AF_INET,
  1310. SOCK_STREAM,
  1311. 0,
  1312. NULL, // protocol info
  1313. 0, // Group ID = 0 => no constraints
  1314. WSA_FLAG_OVERLAPPED // completion port notifications
  1315. );
  1316. if ( sNew == INVALID_SOCKET )
  1317. {
  1318. TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] failed WSASocket, error %08x\n",GetLastError()) );
  1319. return NULL;
  1320. }
  1321. addrLength = sizeof(inAddr);
  1322. ZeroMemory(&inAddr, addrLength);
  1323. inAddr.sin_family = AF_INET;
  1324. inAddr.sin_port = 0;
  1325. ((PSOCKADDR_IN)psaServer)->sin_port = (unsigned short)htons((unsigned short)dwPort );
  1326. //
  1327. // Bind an address to socket
  1328. //
  1329. if ( bind( sNew,
  1330. (PSOCKADDR)&inAddr,
  1331. addrLength ) == 0 &&
  1332. WSAConnect( sNew,
  1333. (PSOCKADDR)psaServer,
  1334. addrLength,
  1335. NULL,
  1336. NULL,
  1337. NULL,
  1338. NULL ) == 0 &&
  1339. WaitForSocketWorker(
  1340. INVALID_SOCKET,
  1341. sNew,
  1342. NULL,
  1343. &fWrite,
  1344. dwTimeOut ) == 0 )
  1345. {
  1346. return sNew;
  1347. }
  1348. TR( (DEBUG_BUFFER,"[TcpSockConnectToLocalHost] failed connect, error %08x\n",GetLastError()) );
  1349. closesocket( sNew );
  1350. return NULL;
  1351. }
  1352. VOID
  1353. TcpSockClose(
  1354. SOCKET hSocket
  1355. )
  1356. /*++
  1357. Routine Description:
  1358. Close a socket opened by TcpSockConnectToLocalHost
  1359. Arguments:
  1360. hSocket - socket opened by TcpSockConnectToLocalHost
  1361. Return Value:
  1362. Nothing
  1363. --*/
  1364. {
  1365. closesocket( hSocket );
  1366. }
  1367. BOOL
  1368. TcpSockSend(
  1369. IN SOCKET sock,
  1370. IN LPVOID pBuffer,
  1371. IN DWORD cbBuffer,
  1372. OUT PDWORD pcbTotalSent,
  1373. IN DWORD nTimeout
  1374. )
  1375. /*++
  1376. Description:
  1377. Do async socket send
  1378. Arguments:
  1379. sock - socket
  1380. pBuffer - buffer to send
  1381. cbBuffer - size of buffer
  1382. pcbTotalSent - bytes sent
  1383. nTimeout - timeout in seconds to use
  1384. Returns:
  1385. FALSE if there is any error.
  1386. TRUE otherwise
  1387. --*/
  1388. {
  1389. INT serr = 0;
  1390. INT cbSent;
  1391. DWORD dwBytesSent = 0;
  1392. ULONG one;
  1393. //
  1394. // Loop until there's no more data to send.
  1395. //
  1396. while( cbBuffer > 0 )
  1397. {
  1398. //
  1399. // Wait for the socket to become writeable.
  1400. //
  1401. BOOL fWrite = FALSE;
  1402. serr = WaitForSocketWorker(
  1403. INVALID_SOCKET,
  1404. sock,
  1405. NULL,
  1406. &fWrite,
  1407. nTimeout
  1408. );
  1409. if( serr == 0 )
  1410. {
  1411. //
  1412. // Write a block to the socket.
  1413. //
  1414. cbSent = send( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
  1415. if( cbSent < 0 )
  1416. {
  1417. //
  1418. // Socket error.
  1419. //
  1420. serr = WSAGetLastError();
  1421. }
  1422. else
  1423. {
  1424. dwBytesSent += (DWORD)cbSent;
  1425. }
  1426. }
  1427. if( serr != 0 )
  1428. {
  1429. TR( (DEBUG_BUFFER,"[TcpSockSend] failed send, error %08x\n",serr) );
  1430. break;
  1431. }
  1432. pBuffer = (LPVOID)( (LPBYTE)pBuffer + cbSent );
  1433. cbBuffer -= (DWORD)cbSent;
  1434. }
  1435. if(pcbTotalSent)
  1436. {
  1437. *pcbTotalSent = dwBytesSent;
  1438. }
  1439. return (serr == 0);
  1440. } // SockSend
  1441. BOOL
  1442. TcpSockRecv(
  1443. IN SOCKET sock,
  1444. IN LPVOID pBuffer,
  1445. IN DWORD cbBuffer,
  1446. OUT LPDWORD pbReceived,
  1447. IN DWORD nTimeout
  1448. )
  1449. /*++
  1450. Description:
  1451. Do async socket recv
  1452. Arguments:
  1453. sock - The target socket.
  1454. pBuffer - Will receive the data.
  1455. cbBuffer - The size (in bytes) of the buffer.
  1456. pbReceived - Will receive the actual number of bytes
  1457. nTimeout - timeout in seconds
  1458. Returns:
  1459. TRUE, if successful
  1460. --*/
  1461. {
  1462. INT serr = 0;
  1463. DWORD cbTotal = 0;
  1464. INT cbReceived;
  1465. DWORD dwBytesRecv = 0;
  1466. ULONG one;
  1467. BOOL fRead = FALSE;
  1468. //
  1469. // Wait for the socket to become readable.
  1470. //
  1471. serr = WaitForSocketWorker(
  1472. sock,
  1473. INVALID_SOCKET,
  1474. &fRead,
  1475. NULL,
  1476. nTimeout
  1477. );
  1478. if( serr == 0 )
  1479. {
  1480. //
  1481. // Read a block from the socket.
  1482. //
  1483. cbReceived = recv( sock, (CHAR *)pBuffer, (INT)cbBuffer, 0 );
  1484. if( cbReceived < 0 )
  1485. {
  1486. //
  1487. // Socket error.
  1488. //
  1489. serr = WSAGetLastError();
  1490. }
  1491. else
  1492. {
  1493. cbTotal = cbReceived;
  1494. }
  1495. }
  1496. else
  1497. {
  1498. TR( (DEBUG_BUFFER,"[TcpSockRecv] failed send, error %08x\n",serr) );
  1499. }
  1500. if( serr == 0 )
  1501. {
  1502. //
  1503. // Return total byte count to caller.
  1504. //
  1505. *pbReceived = cbTotal;
  1506. }
  1507. return (serr == 0);
  1508. } // SockRecv
  1509. INT
  1510. WaitForSocketWorker(
  1511. IN SOCKET sockRead,
  1512. IN SOCKET sockWrite,
  1513. IN LPBOOL pfRead,
  1514. IN LPBOOL pfWrite,
  1515. IN DWORD nTimeout
  1516. )
  1517. /*++
  1518. Description:
  1519. Wait routine
  1520. NOTES: Any (but not all) sockets may be INVALID_SOCKET. For
  1521. each socket that is INVALID_SOCKET, the corresponding
  1522. pf* parameter may be NULL.
  1523. Arguments:
  1524. sockRead - The socket to check for readability.
  1525. sockWrite - The socket to check for writeability.
  1526. pfRead - Will receive TRUE if sockRead is readable.
  1527. pfWrite - Will receive TRUE if sockWrite is writeable.
  1528. nTimeout - timeout in seconds
  1529. Returns:
  1530. SOCKERR - 0 if successful, !0 if not. Will return
  1531. WSAETIMEDOUT if the timeout period expired.
  1532. --*/
  1533. {
  1534. INT serr = 0;
  1535. TIMEVAL timeout;
  1536. LPTIMEVAL ptimeout;
  1537. fd_set fdsRead;
  1538. fd_set fdsWrite;
  1539. INT res;
  1540. //
  1541. // Ensure we got valid parameters.
  1542. //
  1543. if( ( sockRead == INVALID_SOCKET ) &&
  1544. ( sockWrite == INVALID_SOCKET ) )
  1545. {
  1546. return WSAENOTSOCK;
  1547. }
  1548. timeout.tv_sec = (LONG )nTimeout;
  1549. if( timeout.tv_sec == 0 )
  1550. {
  1551. //
  1552. // If the connection timeout == 0, then we have no timeout.
  1553. // So, we block and wait for the specified conditions.
  1554. //
  1555. ptimeout = NULL;
  1556. }
  1557. else
  1558. {
  1559. //
  1560. // The connectio timeout is > 0, so setup the timeout structure.
  1561. //
  1562. timeout.tv_usec = 0;
  1563. ptimeout = &timeout;
  1564. }
  1565. for( ; ; )
  1566. {
  1567. //
  1568. // Setup our socket sets.
  1569. //
  1570. FD_ZERO( &fdsRead );
  1571. FD_ZERO( &fdsWrite );
  1572. if( sockRead != INVALID_SOCKET )
  1573. {
  1574. FD_SET( sockRead, &fdsRead );
  1575. *pfRead = FALSE;
  1576. }
  1577. if( sockWrite != INVALID_SOCKET )
  1578. {
  1579. FD_SET( sockWrite, &fdsWrite );
  1580. *pfWrite = FALSE;
  1581. }
  1582. //
  1583. // Wait for one of the conditions to be met.
  1584. //
  1585. res = select( 0, &fdsRead, &fdsWrite, NULL, ptimeout );
  1586. if( res == 0 )
  1587. {
  1588. //
  1589. // Timeout.
  1590. //
  1591. serr = WSAETIMEDOUT;
  1592. break;
  1593. }
  1594. else if( res == SOCKET_ERROR )
  1595. {
  1596. //
  1597. // Bad news.
  1598. //
  1599. serr = WSAGetLastError();
  1600. TR( (DEBUG_BUFFER,"[WaitForSocketWorker] failed send, error %08x\n",serr) );
  1601. break;
  1602. }
  1603. else
  1604. {
  1605. BOOL fSomethingWasSet = FALSE;
  1606. if( pfRead != NULL )
  1607. {
  1608. *pfRead = FD_ISSET( sockRead, &fdsRead );
  1609. fSomethingWasSet = TRUE;
  1610. }
  1611. if( pfWrite != NULL )
  1612. {
  1613. *pfWrite = FD_ISSET( sockWrite, &fdsWrite );
  1614. fSomethingWasSet = TRUE;
  1615. }
  1616. if( fSomethingWasSet )
  1617. {
  1618. //
  1619. // Success.
  1620. //
  1621. serr = 0;
  1622. break;
  1623. }
  1624. else
  1625. {
  1626. //
  1627. // select() returned with neither a timeout, nor
  1628. // an error, nor any bits set. This feels bad...
  1629. //
  1630. continue;
  1631. }
  1632. }
  1633. }
  1634. return serr;
  1635. } // WaitForSocketWorker()
  1636. #if defined(_DEBUG_SUPPORT)
  1637. void
  1638. TimeStamp(
  1639. FILE* f
  1640. )
  1641. {
  1642. time_t t = time( NULL );
  1643. struct tm *pTm;
  1644. if ( pTm = localtime( &t ) )
  1645. {
  1646. fprintf( f,
  1647. "%02d:%02d:%02d> ",
  1648. pTm->tm_hour,
  1649. pTm->tm_min,
  1650. pTm->tm_sec );
  1651. }
  1652. }
  1653. void
  1654. InitDebug(
  1655. )
  1656. {
  1657. char achPath[MAX_PATH];
  1658. HKEY hKey;
  1659. DWORD dwValue;
  1660. DWORD dwType;
  1661. DWORD dwLen;
  1662. BOOL fDoDebug = FALSE;
  1663. BOOL fAppend = TRUE;
  1664. INT cL = 0;
  1665. LPSTR pTmp;
  1666. //
  1667. // get debug flag from registry
  1668. //
  1669. if ( RegOpenKey( HKEY_LOCAL_MACHINE,
  1670. L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters",
  1671. &hKey )
  1672. == ERROR_SUCCESS )
  1673. {
  1674. TR( (DEBUG_BUFFER,"[InitDebug] opened key\n") );
  1675. dwLen = sizeof( dwValue );
  1676. if ( RegQueryValueEx( hKey,
  1677. L"ClusterDebugMode",
  1678. NULL,
  1679. &dwType,
  1680. (LPBYTE)&dwValue,
  1681. &dwLen ) == ERROR_SUCCESS &&
  1682. dwType == REG_DWORD )
  1683. {
  1684. fDoDebug = !!dwValue;
  1685. }
  1686. dwLen = sizeof( dwValue );
  1687. if ( RegQueryValueEx( hKey,
  1688. L"ClusterDebugAppendToFile",
  1689. NULL,
  1690. &dwType,
  1691. (LPBYTE)&dwValue,
  1692. &dwLen ) == ERROR_SUCCESS &&
  1693. dwType == REG_DWORD )
  1694. {
  1695. fAppend = !!dwValue;
  1696. }
  1697. dwLen = sizeof( achPath );
  1698. if ( RegQueryValueExA( hKey,
  1699. "ClusterDebugPath",
  1700. NULL,
  1701. &dwType,
  1702. (LPBYTE)achPath,
  1703. &dwLen ) == ERROR_SUCCESS &&
  1704. dwType == REG_SZ )
  1705. {
  1706. if ( dwLen )
  1707. {
  1708. cL = dwLen - 1;
  1709. if ( cL && achPath[cL-1] != '\\' )
  1710. {
  1711. achPath[cL++] = '\\';
  1712. }
  1713. }
  1714. }
  1715. RegCloseKey( hKey );
  1716. }
  1717. if ( fDoDebug && cL )
  1718. {
  1719. memcpy( achPath + cL, "iisclus.trc", sizeof("iisclus.trc") );
  1720. debug_file = fopen(achPath, fAppend ? "a" : "w" );
  1721. }
  1722. }
  1723. #endif
  1724. DWORD
  1725. WINAPI
  1726. ResUtilReadProperties(
  1727. IN HKEY RegistryKey,
  1728. IN const PRESUTIL_PROPERTY_ITEM PropertyTable,
  1729. IN OUT LPBYTE OutParams,
  1730. IN RESOURCE_HANDLE ResourceHandle,
  1731. IN PLOG_EVENT_ROUTINE LogEvent
  1732. )
  1733. /*++
  1734. Routine Description:
  1735. Read properties based on a property table.
  1736. Arguments:
  1737. RegistryKey - Supplies the cluster key where the properties are stored.
  1738. PropertyTable - Pointer to the property table to process.
  1739. OutParams - Parameter block to read into.
  1740. ResourceHandle - Handle for the resource fo which properties are being read.
  1741. LogEvent - Function to call to log events to the cluster log.
  1742. Return Value:
  1743. ERROR_SUCCESS - Properties read successfully.
  1744. ERROR_INVALID_DATA - Required property not present.
  1745. --*/
  1746. {
  1747. PRESUTIL_PROPERTY_ITEM propertyItem = PropertyTable;
  1748. HKEY key;
  1749. DWORD status = ERROR_SUCCESS;
  1750. LPWSTR pszInValue;
  1751. LPBYTE pbInValue;
  1752. DWORD dwInValue;
  1753. LPWSTR * ppszOutValue;
  1754. LPBYTE * ppbOutValue;
  1755. LPDWORD pdwOutValue;
  1756. while ( propertyItem->Name != NULL ) {
  1757. //
  1758. // If the value resides at a different location, create the key.
  1759. //
  1760. if ( propertyItem->KeyName != NULL ) {
  1761. DWORD disposition;
  1762. status = ClusterRegCreateKey( RegistryKey,
  1763. propertyItem->KeyName,
  1764. 0,
  1765. KEY_ALL_ACCESS,
  1766. NULL,
  1767. &key,
  1768. &disposition );
  1769. if ( status != ERROR_SUCCESS ) {
  1770. return(status);
  1771. }
  1772. } else {
  1773. key = RegistryKey;
  1774. }
  1775. switch ( propertyItem->Format ) {
  1776. case CLUSPROP_FORMAT_DWORD:
  1777. pdwOutValue = (LPDWORD) &OutParams[propertyItem->Offset];
  1778. status = ResUtilGetDwordValue( RegistryKey,
  1779. propertyItem->Name,
  1780. pdwOutValue,
  1781. propertyItem->Default );
  1782. if ( (status == ERROR_FILE_NOT_FOUND) &&
  1783. !(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) {
  1784. *pdwOutValue = propertyItem->Default;
  1785. }
  1786. break;
  1787. case CLUSPROP_FORMAT_SZ:
  1788. case CLUSPROP_FORMAT_EXPAND_SZ:
  1789. ppszOutValue = (LPWSTR*) &OutParams[propertyItem->Offset];
  1790. pszInValue = ResUtilGetSzValue( RegistryKey,
  1791. propertyItem->Name );
  1792. if ( pszInValue == NULL ) {
  1793. status = GetLastError();
  1794. if ( (status == ERROR_FILE_NOT_FOUND) &&
  1795. !(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) {
  1796. if ( *ppszOutValue != NULL ) {
  1797. LocalFree( *ppszOutValue );
  1798. *ppszOutValue = NULL;
  1799. }
  1800. // If a default is specified, copy it.
  1801. if ( propertyItem->lpDefault != NULL ) {
  1802. *ppszOutValue = (LPWSTR)LocalAlloc( LMEM_FIXED, (lstrlenW( (LPCWSTR) propertyItem->lpDefault ) + 1) * sizeof(WCHAR) );
  1803. if ( *ppszOutValue == NULL ) {
  1804. status = GetLastError();
  1805. } else {
  1806. lstrcpyW( *ppszOutValue, (LPCWSTR) propertyItem->lpDefault );
  1807. }
  1808. }
  1809. }
  1810. } else {
  1811. if ( *ppszOutValue != NULL ) {
  1812. LocalFree( *ppszOutValue );
  1813. }
  1814. *ppszOutValue = pszInValue;
  1815. }
  1816. break;
  1817. case CLUSPROP_FORMAT_MULTI_SZ:
  1818. case CLUSPROP_FORMAT_BINARY:
  1819. ppbOutValue = (LPBYTE*) &OutParams[propertyItem->Offset];
  1820. pdwOutValue = (PDWORD) &OutParams[propertyItem->Offset+sizeof(LPBYTE*)];
  1821. status = ResUtilGetBinaryValue( RegistryKey,
  1822. propertyItem->Name,
  1823. &pbInValue,
  1824. &dwInValue );
  1825. if ( status == ERROR_SUCCESS ) {
  1826. if ( *ppbOutValue != NULL ) {
  1827. LocalFree( *ppbOutValue );
  1828. }
  1829. *ppbOutValue = pbInValue;
  1830. *pdwOutValue = dwInValue;
  1831. } else if ( (status == ERROR_FILE_NOT_FOUND) &&
  1832. !(propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED) ) {
  1833. if ( *ppbOutValue != NULL ) {
  1834. LocalFree( *ppbOutValue );
  1835. *ppbOutValue = NULL;
  1836. *pdwOutValue = 0;
  1837. }
  1838. // If a default is specified, copy it.
  1839. if ( propertyItem->lpDefault != NULL ) {
  1840. *ppbOutValue = (LPBYTE)LocalAlloc( LMEM_FIXED, propertyItem->Minimum );
  1841. if ( *ppbOutValue == NULL ) {
  1842. status = GetLastError();
  1843. } else {
  1844. memcpy( *ppbOutValue, propertyItem->lpDefault, propertyItem->Minimum );
  1845. *pdwOutValue = propertyItem->Minimum;
  1846. }
  1847. }
  1848. }
  1849. break;
  1850. }
  1851. //
  1852. // Close the key if we opened it.
  1853. //
  1854. if ( (propertyItem->KeyName != NULL) &&
  1855. (key != NULL) ) {
  1856. ClusterRegCloseKey( key );
  1857. }
  1858. //
  1859. // Handle any errors that occurred.
  1860. //
  1861. if ( status != ERROR_SUCCESS ) {
  1862. (LogEvent)(
  1863. ResourceHandle,
  1864. LOG_ERROR,
  1865. L"Unable to read the '%1' property. Error: %2!u!.\n",
  1866. propertyItem->Name,
  1867. status );
  1868. if ( propertyItem->Flags & RESUTIL_PROPITEM_REQUIRED ) {
  1869. if ( status == ERROR_FILE_NOT_FOUND ) {
  1870. status = ERROR_INVALID_DATA;
  1871. }
  1872. break;
  1873. } else {
  1874. status = ERROR_SUCCESS;
  1875. }
  1876. }
  1877. //
  1878. // Advance to the next property.
  1879. //
  1880. propertyItem++;
  1881. }
  1882. return(status);
  1883. } // ResUtilReadProperties