Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2658 lines
60 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name :
  4. instance.cxx
  5. Abstract:
  6. Defines the functions for TCP services Info class.
  7. This module is intended to capture the common scheduler
  8. code for the tcp services ( especially internet services)
  9. which involves the Service Controller dispatch functions.
  10. Also this class provides an interface for common dll of servers.
  11. Author:
  12. Murali R. Krishnan ( MuraliK ) 15-Nov-1994
  13. Project:
  14. Internet Servers Common DLL
  15. --*/
  16. #include "tcpdllp.hxx"
  17. #include <rpc.h>
  18. #include <tsunami.hxx>
  19. #include <iistypes.hxx>
  20. #include <iisbind.hxx>
  21. #include "inetreg.h"
  22. #include "tcpcons.h"
  23. #include "apiutil.h"
  24. #include <imd.h>
  25. #include <mb.hxx>
  26. #include "reftrce2.h"
  27. /************************************************************
  28. * Symbolic Constants
  29. ************************************************************/
  30. //
  31. // LOCAL Functions
  32. //
  33. static ULONGLONG InetServiceIdForService( IN DWORD serviceId);
  34. #define MAX_ADDRESSES_SUPPORTED 20
  35. #define SIZEOF_IP_SEC_LIST( IPList ) (sizeof(INET_INFO_IP_SEC_LIST) + \
  36. (IPList)->cEntries * \
  37. sizeof(INET_INFO_IP_SEC_ENTRY))
  38. #if SERVICE_REF_TRACKING
  39. //
  40. // Ref count trace log size
  41. //
  42. #define C_INSTANCE_REFTRACES 4000
  43. #define C_LOCAL_INSTANCE_REFTRACES 40
  44. #endif // SERVICE_REF_TRACKING
  45. //
  46. PTRACE_LOG IIS_SERVER_INSTANCE::sm_pDbgRefTraceLog = NULL;
  47. IIS_SERVER_INSTANCE::IIS_SERVER_INSTANCE(
  48. IN PIIS_SERVICE pService,
  49. IN DWORD dwInstanceId,
  50. IN USHORT sPort,
  51. IN LPCSTR lpszRegParamKey,
  52. IN LPWSTR lpwszAnonPasswordSecretName,
  53. IN LPWSTR lpwszVirtualRootsSecretName,
  54. IN BOOL fMigrateVroots
  55. )
  56. /*++
  57. Desrcription:
  58. Contructor for IIS_SERVER_INSTANCE class.
  59. This constructs a new service info object for the service specified.
  60. Arguments:
  61. pService - pointer to the service object.
  62. dwInstanceId - Instance number of this instance.
  63. sPort - Default port number
  64. lpszRegParamKey
  65. fully qualified name of the registry key that contains the
  66. common service data for this server
  67. lpszAnonPasswordSecretName
  68. The name of the LSA secret the anonymous password is stored under
  69. lpszVirtualRootsSecretName
  70. The name of the LSA secret the virtual root passwords are stored
  71. under
  72. On success it initializes all the members of the object,
  73. inserts itself to the global list of service info objects and
  74. returns with success.
  75. Note:
  76. The caller of this function should check the validity by
  77. invoking the member function IsValid() after constructing
  78. this object.
  79. --*/
  80. :
  81. m_tslock ( ),
  82. m_fZapRegKey ( FALSE),
  83. m_fDoServerNameCheck ( FALSE),
  84. m_reference ( 0),
  85. m_pDbgRefTraceLog ( NULL),
  86. m_sDefaultPort ( sPort ),
  87. m_dwServerState ( MD_SERVER_STATE_STOPPED),
  88. m_dwSavedState ( MD_SERVER_STATE_STOPPED),
  89. m_Service ( pService),
  90. m_instanceId ( dwInstanceId),
  91. m_strParametersKey ( lpszRegParamKey),
  92. m_cReadLocks ( 0),
  93. m_lpwszAnonPasswordSecretName( lpwszAnonPasswordSecretName ),
  94. m_lpwszRootPasswordSecretName( lpwszVirtualRootsSecretName ),
  95. m_strMDPath ( ),
  96. m_strSiteName ( ),
  97. m_strMDVirtualRootPath( ),
  98. m_dwMaxConnections ( INETA_DEF_MAX_CONNECTIONS),
  99. m_dwMaxEndpointConnections( INETA_DEF_MAX_ENDPOINT_CONNECTIONS ),
  100. m_dwCurrentConnections( 0),
  101. m_dwConnectionTimeout ( INETA_DEF_CONNECTION_TIMEOUT),
  102. m_dwServerSize ( INETA_DEF_SERVER_SIZE),
  103. m_nAcceptExOutstanding( INETA_DEF_ACCEPTEX_OUTSTANDING),
  104. m_AcceptExTimeout ( INETA_DEF_ACCEPTEX_TIMEOUT),
  105. m_dwLevelsToScan ( INETA_DEF_LEVELS_TO_SCAN ),
  106. m_fAddedToServerInstanceList( FALSE ),
  107. m_pBandwidthInfo ( NULL )
  108. {
  109. BOOL fReferenced = FALSE;
  110. DBG_ASSERT( lpszRegParamKey != NULL );
  111. IF_DEBUG(INSTANCE) {
  112. DBGPRINTF( ( DBG_CONTEXT,"Creating iis instance %p [%u]. \n",
  113. this, dwInstanceId));
  114. }
  115. //
  116. // Limit PWS connections
  117. //
  118. if ( !TsIsNtServer() ) {
  119. m_dwMaxConnections = INETA_DEF_MAX_CONNECTIONS_PWS;
  120. }
  121. //
  122. // initialize locks
  123. //
  124. INITIALIZE_CRITICAL_SECTION(&m_csLock);
  125. //
  126. // initialize binding support
  127. //
  128. InitializeListHead( &m_NormalBindingListHead );
  129. InitializeListHead( &m_SecureBindingListHead );
  130. #if SERVICE_REF_TRACKING
  131. m_pDbgRefTraceLog = CreateRefTraceLog(C_LOCAL_INSTANCE_REFTRACES, 0);
  132. #endif // SERVICE_REF_TRACKING
  133. //
  134. // reference the service
  135. //
  136. if ( !pService->CheckAndReference( )) {
  137. goto error_exit;
  138. }
  139. //
  140. // remember if we referenced the service
  141. //
  142. fReferenced = TRUE;
  143. m_Service = pService;
  144. //
  145. // Set the metabase path
  146. //
  147. if ( QueryInstanceId() == INET_INSTANCE_ROOT ) {
  148. DBG_ASSERT( FALSE );
  149. } else {
  150. CHAR szTemp[64];
  151. wsprintf(szTemp,"/%s/%s/%d",
  152. IIS_MD_LOCAL_MACHINE_PATH,
  153. pService->QueryServiceName(),
  154. QueryInstanceId());
  155. m_strMDPath.Copy(szTemp);
  156. wsprintf(szTemp,"/%s/%s/%d/%s/",
  157. IIS_MD_LOCAL_MACHINE_PATH,
  158. pService->QueryServiceName(),
  159. QueryInstanceId(),
  160. IIS_MD_INSTANCE_ROOT );
  161. m_strMDVirtualRootPath.Copy(szTemp);
  162. /* This doesn't do anything.
  163. if ( fMigrateVroots ) {
  164. MoveVrootFromRegToMD();
  165. }
  166. */
  167. }
  168. //
  169. // Initialize the bare minimum parameters needed to start.
  170. //
  171. if ( !RegReadCommonParams( FALSE, FALSE))
  172. {
  173. goto error_exit;
  174. }
  175. //
  176. // Set a reasonable initial state.
  177. //
  178. SetServerState(
  179. MD_SERVER_STATE_STOPPED,
  180. NO_ERROR
  181. );
  182. //
  183. // link this to the service
  184. //
  185. if ( dwInstanceId != INET_INSTANCE_ROOT ) {
  186. if ( !pService->AddServerInstance( this ) ) {
  187. DBG_ASSERT(m_reference == 0);
  188. goto error_exit;
  189. }
  190. DBG_ASSERT(m_reference == 1);
  191. }
  192. m_fAddedToServerInstanceList = TRUE;
  193. return;
  194. error_exit:
  195. if ( fReferenced )
  196. {
  197. m_Service->Dereference();
  198. }
  199. m_dwServerState = MD_SERVER_STATE_INVALID;
  200. DBG_ASSERT(m_reference == 0);
  201. return;
  202. } // IIS_SERVER_INSTANCE::IIS_SERVER_INSTANCE()
  203. IIS_SERVER_INSTANCE::~IIS_SERVER_INSTANCE( VOID)
  204. /*++
  205. Description:
  206. Cleanup the instance object. If the service is not already
  207. terminated, it terminates the service before cleanup.
  208. Arguments:
  209. None
  210. Returns:
  211. None
  212. --*/
  213. {
  214. DBG_ASSERT(m_dwServerState != MD_SERVER_STATE_STARTED);
  215. DBG_ASSERT(m_reference == 0);
  216. //
  217. // If we failed to create this instance or it's getting deleted, remove
  218. // the configuration tree
  219. //
  220. if ( m_fZapRegKey ) {
  221. DBGPRINTF((DBG_CONTEXT,"Zapping reg key for %p\n",this));
  222. ZapRegistryKey( NULL, QueryRegParamKey() );
  223. ZapInstanceMBTree( );
  224. }
  225. //
  226. // endpoints should have been dereferenced
  227. //
  228. DBG_ASSERT(IsListEmpty( &m_NormalBindingListHead ));
  229. DBG_ASSERT(IsListEmpty( &m_SecureBindingListHead ));
  230. //
  231. // dereference the service
  232. //
  233. if ( m_fAddedToServerInstanceList && m_Service != NULL ) {
  234. m_Service->Dereference( );
  235. }
  236. //
  237. // destroy bandwidth throttling descriptor
  238. //
  239. if ( m_pBandwidthInfo != NULL )
  240. {
  241. AtqFreeBandwidthInfo( m_pBandwidthInfo );
  242. m_pBandwidthInfo = NULL;
  243. }
  244. #if SERVICE_REF_TRACKING
  245. DestroyRefTraceLog( m_pDbgRefTraceLog );
  246. #endif // SERVICE_REF_TRACKING
  247. DeleteCriticalSection(&m_csLock);
  248. } // IIS_SERVER_INSTANCE::~IIS_SERVER_INSTANCE()
  249. //
  250. // Static Functions belonging to IIS_SERVICE class
  251. //
  252. BOOL
  253. IIS_SERVER_INSTANCE::Initialize( VOID)
  254. /*++
  255. Description:
  256. This function initializes all necessary local data for
  257. IIS_SERVER_INSTANCE class
  258. Only the first initialization call does the initialization.
  259. Others return without any effect.
  260. Should be called from the entry function for DLL.
  261. Arguments:
  262. None
  263. Returns:
  264. TRUE on success and FALSE if any failure.
  265. --*/
  266. {
  267. #if SERVICE_REF_TRACKING
  268. if (sm_pDbgRefTraceLog == NULL)
  269. {
  270. sm_pDbgRefTraceLog = CreateRefTraceLog(C_INSTANCE_REFTRACES, 0);
  271. IF_DEBUG( INSTANCE ) {
  272. DBGPRINTF((DBG_CONTEXT,"IIS_SERVER_INSTANCE RefTraceLog=%p\n",
  273. sm_pDbgRefTraceLog));
  274. }
  275. }
  276. #endif // SERVICE_REF_TRACKING
  277. return TRUE;
  278. }
  279. VOID
  280. IIS_SERVER_INSTANCE::Cleanup(
  281. VOID
  282. )
  283. /*++
  284. Description:
  285. Cleanup the data stored.
  286. This function should be called only after freeing all the
  287. services running using this DLL.
  288. This function is called typically when the DLL is unloaded.
  289. Arguments:
  290. None
  291. Returns:
  292. None
  293. --*/
  294. {
  295. #if SERVICE_REF_TRACKING
  296. if (sm_pDbgRefTraceLog != NULL)
  297. {
  298. IF_DEBUG( INSTANCE ) {
  299. DBGPRINTF((DBG_CONTEXT,
  300. "IIS_SERVER_INSTANCE: Closing RefTraceLog=%p\n",
  301. sm_pDbgRefTraceLog));
  302. }
  303. DestroyRefTraceLog( sm_pDbgRefTraceLog );
  304. }
  305. sm_pDbgRefTraceLog = NULL;
  306. #endif // SERVICE_REF_TRACKING
  307. }
  308. # if 0
  309. VOID
  310. IIS_SERVER_INSTANCE::Print( VOID) const
  311. {
  312. IIS_SERVER_INSTANCE::Print();
  313. DBGPRINTF( ( DBG_CONTEXT,
  314. " Printing IIS_SERVER_INSTANCE object ( %08p) \n"
  315. " State = %u.\n"
  316. ,
  317. this, m_dwServerState
  318. ));
  319. DBGPRINTF(( DBG_CONTEXT,
  320. " Server Admin Params: \n"
  321. " Log Anon = %u. Log NonAnon = %u.\n"
  322. ,
  323. m_fLogAnonymous, m_fLogNonAnonymous
  324. ));
  325. DBGPRINTF(( DBG_CONTEXT,
  326. " Printing IIS_SERVER_INSTANCE object (%08p)\n"
  327. " Readers # = %u.\n"
  328. " Reg Parameters Key = %s\n"
  329. " MaxConn = %d. ConnTimeout = %u secs.\n"
  330. ,
  331. this,
  332. m_cReadLocks,
  333. m_strParametersKey.QueryStr(),
  334. m_dwMaxConnections, m_dwConnectionTimeout
  335. ));
  336. return;
  337. } // IIS_SERVER_INSTANCE::Print()
  338. #endif // DBG
  339. VOID
  340. IIS_SERVER_INSTANCE::Reference( )
  341. {
  342. InterlockedIncrement( &m_reference );
  343. LONG lEntry = SHARED_LOG_REF_COUNT();
  344. LOCAL_LOG_REF_COUNT();
  345. IF_DEBUG( INSTANCE )
  346. DBGPRINTF((DBG_CONTEXT, "IIS_SERVER_INSTANCE ref count %ld\n (%ld)",
  347. m_reference, lEntry));
  348. }
  349. VOID
  350. IIS_SERVER_INSTANCE::Dereference( )
  351. {
  352. LONG lEntry = SHARED_EARLY_LOG_REF_COUNT();
  353. LOCAL_EARLY_LOG_REF_COUNT();
  354. LONG Reference = InterlockedDecrement( &m_reference );
  355. if ( 0 == Reference) {
  356. IF_DEBUG( INSTANCE )
  357. DBGPRINTF((DBG_CONTEXT, "deleting IIS_SERVER_INSTANCE %p (%ld)\n",
  358. this, lEntry));
  359. delete this;
  360. } else {
  361. IF_DEBUG( INSTANCE )
  362. DBGPRINTF((DBG_CONTEXT, "IIS_SERVER_INSTANCE deref count %ld (%ld)\n",
  363. Reference, lEntry));
  364. }
  365. }
  366. VOID
  367. IIS_SERVER_INSTANCE::ZapInstanceMBTree(
  368. VOID
  369. )
  370. {
  371. MB mb( (IMDCOM*) m_Service->QueryMDObject() );
  372. //
  373. // Do the metabase
  374. //
  375. IF_DEBUG(METABASE) {
  376. DBGPRINTF((DBG_CONTEXT,"Deleting metabase node %s\n",
  377. QueryMDPath()));
  378. }
  379. if ( !mb.Open( "/",
  380. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
  381. {
  382. IF_DEBUG(METABASE) {
  383. DBGPRINTF((DBG_CONTEXT,"Open MD instance root %s returns %d\n",
  384. "/", GetLastError() ));
  385. }
  386. return;
  387. }
  388. //
  389. // Delete the instance tree
  390. //
  391. if ( !mb.DeleteObject( QueryMDPath() ))
  392. {
  393. IF_DEBUG(METABASE) {
  394. DBGPRINTF((DBG_CONTEXT,
  395. "Deleting instance node %s returns %d\n",
  396. QueryMDPath(),
  397. GetLastError()));
  398. }
  399. }
  400. return;
  401. } // IIS_SERVER_INSTANCE::ZapInstanceMBTree
  402. DWORD
  403. IIS_SERVER_INSTANCE::BindInstance(
  404. VOID
  405. )
  406. /*++
  407. Routine Description:
  408. Binds an instance to all configured endpoints (normal & secure).
  409. Arguments:
  410. None.
  411. Return Value:
  412. DWORD - Completion status, 0 if successful, !0 otherwise.
  413. --*/
  414. {
  415. DWORD err;
  416. //
  417. // Update the "normal" (i.e. non-secure) bindings.
  418. //
  419. err = UpdateNormalBindings();
  420. if( err != NO_ERROR ) {
  421. IF_DEBUG(INSTANCE) {
  422. DBGPRINTF((DBG_CONTEXT, "UpdateNormalBindings() failed, %lu\n", err));
  423. }
  424. return err;
  425. }
  426. //
  427. // Update the secure bindings.
  428. //
  429. err = UpdateSecureBindings();
  430. if( err != NO_ERROR ) {
  431. IF_DEBUG(INSTANCE) {
  432. DBGPRINTF((DBG_CONTEXT, "UpdateSecureBindings() failed, %lu\n", err));
  433. }
  434. //
  435. // The main port(s) are OK, but the SSL port(s) failed,
  436. // so start anyway.
  437. //
  438. err = NO_ERROR;
  439. }
  440. //
  441. // Success!
  442. //
  443. DBG_ASSERT( err == NO_ERROR );
  444. return NO_ERROR;
  445. } // IIS_SERVER_INSTANCE::BindInstance
  446. DWORD
  447. IIS_SERVER_INSTANCE::UnbindInstance(
  448. VOID
  449. )
  450. /*++
  451. Routine Description:
  452. Removes all bindings from an instance.
  453. Arguments:
  454. None.
  455. Return Value:
  456. DWORD - Completion status, 0 if successful, !0 otherwise.
  457. --*/
  458. {
  459. LockThisForWrite();
  460. DBG_REQUIRE( RemoveNormalBindings() == NO_ERROR );
  461. DBG_REQUIRE( RemoveSecureBindings() == NO_ERROR );
  462. UnlockThis();
  463. return NO_ERROR;
  464. } // IIS_SERVER_INSTANCE::UnbindInstance
  465. DWORD
  466. IIS_SERVER_INSTANCE::UnbindHelper(
  467. IN PLIST_ENTRY BindingListHead
  468. )
  469. /*++
  470. Routine Description:
  471. Helper routine for UnbindInstance().
  472. Arguments:
  473. BindingListHead - The binding list to remove.
  474. Return Value:
  475. DWORD - Completion status, 0 if successful, !0 otherwise.
  476. --*/
  477. {
  478. PLIST_ENTRY listEntry;
  479. PIIS_SERVER_BINDING binding;
  480. //
  481. // Walk the list of bindings and destroy them.
  482. //
  483. while( !IsListEmpty( BindingListHead ) ) {
  484. listEntry = RemoveHeadList( BindingListHead );
  485. binding = CONTAINING_RECORD(
  486. listEntry,
  487. IIS_SERVER_BINDING,
  488. m_BindingListEntry
  489. );
  490. IF_DEBUG( INSTANCE ) {
  491. DBGPRINTF((
  492. DBG_CONTEXT,
  493. "unbinding %p from %p, binding %p (%lx:%d:%s)\n",
  494. binding->QueryEndpoint(),
  495. this,
  496. binding,
  497. binding->QueryIpAddress(),
  498. binding->QueryEndpoint()->QueryPort(),
  499. binding->QueryHostName()
  500. ));
  501. }
  502. binding->QueryEndpoint()->RemoveInstance(
  503. this,
  504. binding->QueryIpAddress(),
  505. binding->QueryHostName()
  506. );
  507. binding->QueryEndpoint()->Dereference();
  508. delete binding;
  509. }
  510. //
  511. // Success!
  512. //
  513. return NO_ERROR;
  514. } // IIS_SERVER_INSTANCE::UnbindHelper
  515. DWORD
  516. IIS_SERVER_INSTANCE::UpdateBindingsHelper(
  517. IN BOOL IsSecure
  518. )
  519. /*++
  520. Routine Description:
  521. Helper routine for UpdateNormalBindings() and UpdateSecureBindings().
  522. Arguments:
  523. IsSecure - TRUE if we're to update the secure bindings, FALSE for
  524. the normal bindings.
  525. Return Value:
  526. DWORD - Completion status, 0 if successful, !0 otherwise.
  527. --*/
  528. {
  529. MB mb( (IMDCOM*)m_Service->QueryMDObject() );
  530. MULTISZ msz;
  531. DWORD status = NO_ERROR;
  532. const CHAR * scan;
  533. DWORD ipAddress;
  534. USHORT ipPort;
  535. const CHAR * hostName;
  536. PIIS_SERVER_BINDING binding;
  537. LIST_ENTRY createdBindings;
  538. PLIST_ENTRY listEntry;
  539. PLIST_ENTRY targetBindingListHead;
  540. USHORT targetDefaultPort;
  541. DWORD targetMetadataId;
  542. DWORD numBindings = 0;
  543. const CHAR * apszSubStrings[2];
  544. CHAR instanceIdString[sizeof("4294967295")];
  545. DWORD fDisableSocketPooling;
  546. //
  547. // Setup locals.
  548. //
  549. InitializeListHead( &createdBindings );
  550. if( IsSecure ) {
  551. targetBindingListHead = &m_SecureBindingListHead;
  552. targetDefaultPort = 0;
  553. targetMetadataId = MD_SECURE_BINDINGS;
  554. } else {
  555. targetBindingListHead = &m_NormalBindingListHead;
  556. targetDefaultPort = m_sDefaultPort;
  557. targetMetadataId = MD_SERVER_BINDINGS;
  558. }
  559. //
  560. // Open the metabase and get the current binding list.
  561. //
  562. if( mb.Open( QueryMDPath() ) ) {
  563. if( !mb.GetMultisz(
  564. "",
  565. targetMetadataId,
  566. IIS_MD_UT_SERVER,
  567. &msz
  568. ) ) {
  569. status = GetLastError();
  570. }
  571. //
  572. // Get socket pooling flag.
  573. //
  574. mb.GetDword( "",
  575. MD_DISABLE_SOCKET_POOLING,
  576. IIS_MD_UT_SERVER,
  577. FALSE,
  578. &fDisableSocketPooling
  579. );
  580. //
  581. // Close the metabase before continuing, as anyone that needs
  582. // to update the service status will need write access.
  583. //
  584. mb.Close();
  585. } else {
  586. status = GetLastError();
  587. }
  588. //
  589. // Lock the instance.
  590. //
  591. LockThisForWrite();
  592. if ( status == MD_ERROR_DATA_NOT_FOUND ) {
  593. //
  594. // if the bindings just don't exist (as happens on service creation)
  595. // don't log an error.
  596. //
  597. goto fatal_nolog;
  598. } else if( status != NO_ERROR ) {
  599. goto fatal;
  600. }
  601. //
  602. // Scan the multisz and look for instances we'll need to create.
  603. //
  604. for( scan = msz.First() ;
  605. scan != NULL ;
  606. scan = msz.Next( scan ) ) {
  607. //
  608. // Parse the descriptor (in "ip_address:port:host_name" form)
  609. // into its component parts.
  610. //
  611. status = IIS_SERVER_BINDING::ParseDescriptor(
  612. scan,
  613. &ipAddress,
  614. &ipPort,
  615. &hostName
  616. );
  617. if( status == NO_ERROR ) {
  618. if( IsSecure ) {
  619. //
  620. // Secure bindings cannot key off the hostname, as
  621. // the hostname is encrypted in the header.
  622. //
  623. if( *hostName != '\0' ) {
  624. DBGPRINTF((
  625. DBG_CONTEXT,
  626. "Secure bindings cannot have host name! %s\n",
  627. scan
  628. ));
  629. wsprintfA(
  630. instanceIdString,
  631. "%lu",
  632. QueryInstanceId()
  633. );
  634. apszSubStrings[0] = (const CHAR *)instanceIdString;
  635. apszSubStrings[1] = (const CHAR *)scan;
  636. m_Service->LogEvent(
  637. INET_SVC_INVALID_SECURE_BINDING,
  638. 2,
  639. apszSubStrings
  640. );
  641. //
  642. // Press on regardless, but ignore the hostname.
  643. //
  644. hostName = "";
  645. }
  646. }
  647. //
  648. // See if the descriptor is in our current binding list.
  649. //
  650. if( IsInCurrentBindingList(
  651. targetBindingListHead,
  652. ipAddress,
  653. ipPort,
  654. hostName
  655. ) ) {
  656. //
  657. // It is, so remember that we have a binding.
  658. //
  659. numBindings++;
  660. } else {
  661. //
  662. // It's not, so we need to create a new binding.
  663. //
  664. IF_DEBUG( INSTANCE ) {
  665. DBGPRINTF((
  666. DBG_CONTEXT,
  667. "Adding %lx:%d:%s\n",
  668. ipAddress,
  669. ipPort,
  670. hostName
  671. ));
  672. }
  673. DBG_CODE( binding = NULL );
  674. status = CreateNewBinding(
  675. ipAddress,
  676. ipPort,
  677. hostName,
  678. IsSecure,
  679. fDisableSocketPooling,
  680. &binding
  681. );
  682. if( status == NO_ERROR ) {
  683. //
  684. // Add the new binding to the local list of
  685. // newly created bindings.
  686. //
  687. DBG_ASSERT( binding != NULL );
  688. InsertTailList(
  689. &createdBindings,
  690. &binding->m_BindingListEntry
  691. );
  692. numBindings++;
  693. } else {
  694. //
  695. // Could not create the new binding.
  696. //
  697. // Press on regardless.
  698. //
  699. }
  700. }
  701. } else {
  702. //
  703. // Could not parse the descriptor.
  704. //
  705. DBGPRINTF((
  706. DBG_CONTEXT,
  707. "UpdateNormalBindings: could not parse %s, error %lu\n",
  708. scan,
  709. status
  710. ));
  711. wsprintfA(
  712. instanceIdString,
  713. "%lu",
  714. QueryInstanceId()
  715. );
  716. apszSubStrings[0] = (const CHAR *)instanceIdString;
  717. apszSubStrings[1] = (const CHAR *)scan;
  718. m_Service->LogEvent(
  719. INET_SVC_INVALID_BINDING,
  720. 2,
  721. apszSubStrings
  722. );
  723. //
  724. // Press on regardless.
  725. //
  726. }
  727. }
  728. if( status != NO_ERROR ) {
  729. if( numBindings == 0 ) {
  730. //
  731. // All bindings failed, so fail the request.
  732. //
  733. goto fatal;
  734. }
  735. //
  736. // At least one binding succeeded, so succeed the request.
  737. //
  738. status = NO_ERROR;
  739. }
  740. //
  741. // Scan the existing bindings and look for those that need to
  742. // be deleted.
  743. //
  744. listEntry = targetBindingListHead->Flink;
  745. while( listEntry != targetBindingListHead ) {
  746. binding = CONTAINING_RECORD(
  747. listEntry,
  748. IIS_SERVER_BINDING,
  749. m_BindingListEntry
  750. );
  751. listEntry = listEntry->Flink;
  752. if( !IsBindingInMultiSz(
  753. binding,
  754. msz
  755. ) ) {
  756. //
  757. // Got one. Remove it from the instance list, dereference
  758. // the corresponding endpoint, then delete the binding.
  759. //
  760. IF_DEBUG( INSTANCE ) {
  761. DBGPRINTF((
  762. DBG_CONTEXT,
  763. "zapping %p from %p, binding %p (%lx:%d:%s)\n",
  764. binding->QueryEndpoint(),
  765. this,
  766. binding,
  767. binding->QueryIpAddress(),
  768. binding->QueryEndpoint()->QueryPort(),
  769. binding->QueryHostName()
  770. ));
  771. }
  772. binding->QueryEndpoint()->RemoveInstance(
  773. this,
  774. binding->QueryIpAddress(),
  775. binding->QueryHostName()
  776. );
  777. RemoveEntryList(
  778. &binding->m_BindingListEntry
  779. );
  780. binding->QueryEndpoint()->Dereference();
  781. delete binding;
  782. }
  783. }
  784. //
  785. // Move the newly created bindings over to the current binding
  786. // list.
  787. //
  788. targetBindingListHead->Blink->Flink = createdBindings.Flink;
  789. createdBindings.Flink->Blink = targetBindingListHead->Blink;
  790. createdBindings.Blink->Flink = targetBindingListHead;
  791. targetBindingListHead->Blink = createdBindings.Blink;
  792. UnlockThis();
  793. DBG_ASSERT( status == NO_ERROR );
  794. return NO_ERROR;
  795. fatal:
  796. //
  797. // An unrecoverable binding error occured. Log an event.
  798. //
  799. DBG_ASSERT( status != NO_ERROR );
  800. wsprintfA(
  801. instanceIdString,
  802. "%lu",
  803. QueryInstanceId()
  804. );
  805. apszSubStrings[0] = (const CHAR *)instanceIdString;
  806. //
  807. // map ERROR_INVALID_PARAMETER to ERROR_DUP_NAME. this is what the UI expect, and results in
  808. // a more useful message
  809. //
  810. if (status == ERROR_INVALID_PARAMETER) {
  811. status = ERROR_DUP_NAME;
  812. }
  813. m_Service->LogEvent(
  814. INET_SVC_FATAL_BINDING_ERROR,
  815. 1,
  816. apszSubStrings,
  817. status
  818. );
  819. fatal_nolog:
  820. //
  821. // Loop through the local list of newly created bindings and delete them.
  822. //
  823. while( !IsListEmpty( &createdBindings ) ) {
  824. listEntry = RemoveHeadList(
  825. &createdBindings
  826. );
  827. binding = CONTAINING_RECORD(
  828. listEntry,
  829. IIS_SERVER_BINDING,
  830. m_BindingListEntry
  831. );
  832. IF_DEBUG( INSTANCE ) {
  833. DBGPRINTF((
  834. DBG_CONTEXT,
  835. "zapping %p from %p, binding %p (%lx:%d:%s) (ERROR)\n",
  836. binding->QueryEndpoint(),
  837. this,
  838. binding,
  839. binding->QueryIpAddress(),
  840. binding->QueryEndpoint()->QueryPort(),
  841. binding->QueryHostName()
  842. ));
  843. }
  844. binding->QueryEndpoint()->RemoveInstance(
  845. this,
  846. binding->QueryIpAddress(),
  847. binding->QueryHostName()
  848. );
  849. binding->QueryEndpoint()->Dereference();
  850. delete binding;
  851. }
  852. //
  853. // this is a fatal error - stop the service if it was running
  854. //
  855. DWORD serviceState = m_Service->QueryCurrentServiceState();
  856. DWORD currentState = QueryServerState();
  857. if( ( serviceState == SERVICE_RUNNING ||
  858. serviceState == SERVICE_PAUSED ) &&
  859. ( currentState == MD_SERVER_STATE_STARTED ||
  860. currentState == MD_SERVER_STATE_PAUSED ) ) {
  861. DWORD err = StopInstance();
  862. if( err != NO_ERROR ) {
  863. DBGPRINTF((
  864. DBG_CONTEXT,
  865. "UpdateBindingsHelper(): cannot stop instance, error %lu\n",
  866. err
  867. ));
  868. }
  869. }
  870. UnlockThis();
  871. return status;
  872. } // IIS_SERVER_INSTANCE::UpdateBindingsHelper
  873. DWORD
  874. IIS_SERVER_INSTANCE::CreateNewBinding(
  875. IN DWORD IpAddress,
  876. IN USHORT IpPort,
  877. IN const CHAR * HostName,
  878. IN BOOL IsSecure,
  879. IN BOOL fDisableSocketPooling,
  880. OUT IIS_SERVER_BINDING ** NewBinding
  881. )
  882. /*++
  883. Routine Description:
  884. Creates a new binding object for the specified ip address, port, and
  885. host name, and creates/references the appropriate endpoint object.
  886. Arguments:
  887. IpAddress - The binding IP address. May be INADDR_ANY.
  888. IpPort - The binding IP port. Required.
  889. HostName - The binding host name. May be empty ("").
  890. IsSecure - TRUE for secure endpoints. Only used if a new endpoint
  891. is created.
  892. fDisableSocketPooling - TRUE to create unique endpoints based on both
  893. port & IP. Only used if a new endpoint is created.
  894. NewBinding - Receives a pointer to the new binding object if successful.
  895. Return Value:
  896. DWORD - Completion status, 0 if successful, !0 otherwise.
  897. --*/
  898. {
  899. PIIS_ENDPOINT endpoint;
  900. PIIS_SERVER_BINDING binding;
  901. DWORD status;
  902. //
  903. // Sanity check.
  904. //
  905. DBG_ASSERT( IpPort != 0 );
  906. DBG_ASSERT( HostName != NULL );
  907. DBG_ASSERT( NewBinding != NULL );
  908. //
  909. // Setup locals so we know how to cleanup on exit.
  910. //
  911. endpoint = NULL;
  912. binding = NULL;
  913. //
  914. // Try to find an endpoint for the specified port.
  915. //
  916. endpoint = m_Service->FindAndReferenceEndpoint(
  917. IpPort,
  918. IpAddress,
  919. TRUE, // CreateIfNotFound
  920. IsSecure,
  921. fDisableSocketPooling
  922. );
  923. if( endpoint != NULL ) {
  924. //
  925. // Create a new binding.
  926. //
  927. binding = new IIS_SERVER_BINDING(
  928. IpAddress,
  929. IpPort,
  930. HostName,
  931. endpoint
  932. );
  933. if( binding != NULL ) {
  934. if( endpoint->AddInstance(
  935. this,
  936. IpAddress,
  937. HostName
  938. ) ) {
  939. endpoint->Reference();
  940. *NewBinding = binding;
  941. status = NO_ERROR;
  942. } else {
  943. //
  944. // Could not associate the instance with the endpoint.
  945. //
  946. status = GetLastError();
  947. ASSERT( status != NO_ERROR );
  948. //
  949. // if we didn't get an error code back for some reason
  950. // we choose this one since resource shortages are
  951. // the most likely failure case.
  952. //
  953. if ( NO_ERROR == status ) {
  954. status = ERROR_NOT_ENOUGH_MEMORY;
  955. }
  956. }
  957. } else {
  958. //
  959. // Could not create new binding object.
  960. //
  961. status = ERROR_NOT_ENOUGH_MEMORY;
  962. }
  963. } else {
  964. //
  965. // Could not find & reference endpoint.
  966. //
  967. status = ERROR_NOT_ENOUGH_MEMORY;
  968. }
  969. //
  970. // Remove the reference added in FindAndReferenceEndpoint().
  971. //
  972. if( endpoint != NULL ) {
  973. endpoint->Dereference();
  974. }
  975. //
  976. // Cleanup if necessary.
  977. //
  978. if( status != NO_ERROR ) {
  979. if( binding != NULL ) {
  980. delete binding;
  981. }
  982. }
  983. return status;
  984. } // IIS_SERVER_INSTANCE::CreateNewBinding
  985. BOOL
  986. IIS_SERVER_INSTANCE::IsInCurrentBindingList(
  987. IN PLIST_ENTRY BindingListHead,
  988. IN DWORD IpAddress OPTIONAL,
  989. IN USHORT IpPort,
  990. IN const CHAR * HostName OPTIONAL
  991. )
  992. /*++
  993. Routine Description:
  994. Scans the current binding list looking for the specified IP address,
  995. port, and host name.
  996. Arguments:
  997. BindingListHead - The binding list to scan.
  998. IpAddress - The IP address to search for. May be INADDR_ANY.
  999. IpPort - The IP port to search for. Required.
  1000. HostName - The host name to search for. May be empty ("").
  1001. Return Value:
  1002. BOOL - TRUE if the binding was found, FALSE otherwise.
  1003. --*/
  1004. {
  1005. PLIST_ENTRY listEntry;
  1006. PIIS_SERVER_BINDING binding;
  1007. //
  1008. // Sanity check.
  1009. //
  1010. DBG_ASSERT( IpPort != 0 );
  1011. DBG_ASSERT( HostName != NULL );
  1012. //
  1013. // Scan the bindings.
  1014. //
  1015. for( listEntry = BindingListHead->Flink ;
  1016. listEntry != BindingListHead ;
  1017. listEntry = listEntry->Flink ) {
  1018. binding = CONTAINING_RECORD(
  1019. listEntry,
  1020. IIS_SERVER_BINDING,
  1021. m_BindingListEntry
  1022. );
  1023. if( binding->Compare(
  1024. IpAddress,
  1025. IpPort,
  1026. HostName
  1027. ) ) {
  1028. return TRUE;
  1029. }
  1030. }
  1031. return FALSE;
  1032. } // IIS_SERVER_INSTANCE::IsInCurrentBindingList
  1033. BOOL
  1034. IIS_SERVER_INSTANCE::IsBindingInMultiSz(
  1035. IN PIIS_SERVER_BINDING Binding,
  1036. IN const MULTISZ &msz
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. Scans the specified MULTISZ object to see if it contains a descriptor
  1041. matching the specified binding object.
  1042. Arguments:
  1043. Binding - The binding to search for.
  1044. msz - The MULTISZ to search.
  1045. Return Value:
  1046. DWORD - Completion status, 0 if successful, !0 otherwise.
  1047. --*/
  1048. {
  1049. const CHAR * scan;
  1050. DWORD status;
  1051. BOOL result;
  1052. //
  1053. // Sanity check.
  1054. //
  1055. DBG_ASSERT( Binding != NULL );
  1056. //
  1057. // Scan the MULTISZ.
  1058. //
  1059. for( scan = msz.First() ;
  1060. scan != NULL ;
  1061. scan = msz.Next( scan ) ) {
  1062. status = Binding->Compare( scan, &result );
  1063. if( status == NO_ERROR && result ) {
  1064. return TRUE;
  1065. }
  1066. }
  1067. return FALSE;
  1068. } // IIS_SERVER_INSTANCE::IsBindingInMultiSz
  1069. DWORD
  1070. IIS_SERVER_INSTANCE::PerformClusterModeChange(
  1071. VOID
  1072. )
  1073. /*++
  1074. Routine Description:
  1075. Reads the server cluster mode from the metabase and performs any
  1076. necessary changes.
  1077. Arguments:
  1078. None.
  1079. Return Value:
  1080. DWORD - Completion status, 0 if successful, !0 otherwise.
  1081. --*/
  1082. {
  1083. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1084. DWORD status;
  1085. DWORD currentState;
  1086. DWORD serviceState;
  1087. BOOL fPreviousClusterEnabled;
  1088. //
  1089. // Setup locals.
  1090. //
  1091. status = NO_ERROR;
  1092. fPreviousClusterEnabled = m_fClusterEnabled;
  1093. serviceState = m_Service->QueryCurrentServiceState();
  1094. currentState = QueryServerState();
  1095. //
  1096. // Open the metabase and query the cluster enabled flag
  1097. //
  1098. if( mb.Open(
  1099. QueryMDPath(),
  1100. METADATA_PERMISSION_READ ) )
  1101. {
  1102. if( !mb.GetDword(
  1103. "",
  1104. MD_CLUSTER_ENABLED,
  1105. IIS_MD_UT_SERVER,
  1106. (LPDWORD)&m_fClusterEnabled
  1107. ) )
  1108. {
  1109. m_fClusterEnabled = FALSE;
  1110. status = GetLastError();
  1111. IF_DEBUG( INSTANCE )
  1112. {
  1113. DBGPRINTF((
  1114. DBG_CONTEXT,
  1115. "PerformClusterModeChange: cannot read server command, error %lu\n",
  1116. status
  1117. ));
  1118. }
  1119. }
  1120. //
  1121. // Close it so that code needed to update the metabase when
  1122. // changing state can indeed open the metabase.
  1123. //
  1124. mb.Close();
  1125. }
  1126. else
  1127. {
  1128. status = GetLastError();
  1129. IF_DEBUG( INSTANCE )
  1130. {
  1131. DBGPRINTF((
  1132. DBG_CONTEXT,
  1133. "PerformClusterModeChange: cannot open metabase for READ, error %lu\n",
  1134. status
  1135. ));
  1136. }
  1137. }
  1138. //
  1139. // If cluster mode transition from non-cluster to cluster
  1140. // then must make sure that instance is stopped.
  1141. // instance will be started as required by cluster manager.
  1142. //
  1143. if ( status == NO_ERROR &&
  1144. m_fClusterEnabled &&
  1145. !fPreviousClusterEnabled )
  1146. {
  1147. if( ( serviceState == SERVICE_RUNNING ||
  1148. serviceState == SERVICE_PAUSED ) &&
  1149. ( currentState == MD_SERVER_STATE_STARTED ||
  1150. currentState == MD_SERVER_STATE_PAUSED ) ) {
  1151. LockThisForWrite();
  1152. status = StopInstance();
  1153. if( status != NO_ERROR ) {
  1154. DBGPRINTF((
  1155. DBG_CONTEXT,
  1156. "PerformClusterModeChange: cannot stop instance, error %lu\n",
  1157. status
  1158. ));
  1159. }
  1160. UnlockThis();
  1161. }
  1162. //
  1163. // Restore the state to the previous value if the state change failed.
  1164. //
  1165. if( status != NO_ERROR ) {
  1166. SetServerState( currentState, status );
  1167. }
  1168. }
  1169. return status;
  1170. }
  1171. DWORD
  1172. IIS_SERVER_INSTANCE::PerformStateChange(
  1173. VOID
  1174. )
  1175. /*++
  1176. Routine Description:
  1177. Reads the server instance state from the metabase and performs any
  1178. necessary state changes.
  1179. Arguments:
  1180. None.
  1181. Return Value:
  1182. DWORD - Completion status, 0 if successful, !0 otherwise.
  1183. --*/
  1184. {
  1185. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1186. DWORD status;
  1187. DWORD command;
  1188. DWORD currentState;
  1189. DWORD serviceState;
  1190. //
  1191. // Setup locals.
  1192. //
  1193. status = NO_ERROR;
  1194. serviceState = m_Service->QueryCurrentServiceState();
  1195. currentState = QueryServerState();
  1196. //
  1197. // Open the metabase and query the state change command.
  1198. //
  1199. if( mb.Open(
  1200. QueryMDPath(),
  1201. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) {
  1202. if( !mb.GetDword(
  1203. "",
  1204. IsClusterEnabled() ? MD_CLUSTER_SERVER_COMMAND : MD_SERVER_COMMAND,
  1205. IIS_MD_UT_SERVER,
  1206. &command
  1207. ) ) {
  1208. status = GetLastError();
  1209. IF_DEBUG( INSTANCE ) {
  1210. DBGPRINTF((
  1211. DBG_CONTEXT,
  1212. "PerformStateChange: cannot read server command, error %lu\n",
  1213. status
  1214. ));
  1215. }
  1216. }
  1217. //
  1218. // Update the instance AutoStart value so the instance state is
  1219. // persisted across service restarts
  1220. //
  1221. if( status == NO_ERROR ) {
  1222. switch( command ) {
  1223. case MD_SERVER_COMMAND_START :
  1224. mb.SetDword(
  1225. "",
  1226. MD_SERVER_AUTOSTART,
  1227. IIS_MD_UT_SERVER,
  1228. TRUE,
  1229. METADATA_NO_ATTRIBUTES );
  1230. break;
  1231. case MD_SERVER_COMMAND_STOP :
  1232. mb.SetDword(
  1233. "",
  1234. MD_SERVER_AUTOSTART,
  1235. IIS_MD_UT_SERVER,
  1236. FALSE,
  1237. METADATA_NO_ATTRIBUTES );
  1238. break;
  1239. default:
  1240. break;
  1241. }
  1242. }
  1243. //
  1244. // Close it so that code needed to update the metabase when
  1245. // changing state can indeed open the metabase.
  1246. //
  1247. mb.Close();
  1248. } else {
  1249. status = GetLastError();
  1250. IF_DEBUG( INSTANCE ) {
  1251. DBGPRINTF((
  1252. DBG_CONTEXT,
  1253. "PerformStateChange: cannot open metabase for READ, error %lu\n",
  1254. status
  1255. ));
  1256. }
  1257. }
  1258. //
  1259. // Lock the instance.
  1260. //
  1261. LockThisForWrite();
  1262. //
  1263. // Interpret the command. Note that the StartInstance(), StopInstance(),
  1264. // PauseInstance(), and ContinueInstance() methods will set the instance
  1265. // state if they complete successfully, but it is this routine's
  1266. // responsibility to reset the state to the original value if the
  1267. // methods fail.
  1268. //
  1269. if( status == NO_ERROR ) {
  1270. switch( command ) {
  1271. case MD_SERVER_COMMAND_START :
  1272. //
  1273. // Start the instance.
  1274. //
  1275. // If it's stopped, then start it. If it's in any other state,
  1276. // this is an invalid state transition.
  1277. //
  1278. // Note that the *service* must be running before an instance
  1279. // can be started.
  1280. //
  1281. if( serviceState == SERVICE_RUNNING &&
  1282. currentState == MD_SERVER_STATE_STOPPED ) {
  1283. status = DoStartInstance();
  1284. if( status != NO_ERROR ) {
  1285. DBGPRINTF((
  1286. DBG_CONTEXT,
  1287. "PerformStateChange: cannot start instance, error %lu\n",
  1288. status
  1289. ));
  1290. }
  1291. } else {
  1292. DBGPRINTF((
  1293. DBG_CONTEXT,
  1294. "PerformStateChange: invalid command %lu for state %lu\n",
  1295. command,
  1296. currentState
  1297. ));
  1298. status = ERROR_INVALID_SERVICE_CONTROL;
  1299. }
  1300. break;
  1301. case MD_SERVER_COMMAND_STOP :
  1302. //
  1303. // Stop the instance.
  1304. //
  1305. // If it's running or paused, then stop it. If it's in any
  1306. // other state, this is an invalid state transition.
  1307. //
  1308. // Note that the *service* must be either running or paused
  1309. // before an instance can be paused.
  1310. //
  1311. if( ( serviceState == SERVICE_RUNNING ||
  1312. serviceState == SERVICE_PAUSED ) &&
  1313. ( currentState == MD_SERVER_STATE_STARTED ||
  1314. currentState == MD_SERVER_STATE_PAUSED ) ) {
  1315. status = StopInstance();
  1316. if( status != NO_ERROR ) {
  1317. DBGPRINTF((
  1318. DBG_CONTEXT,
  1319. "PerformStateChange: cannot stop instance, error %lu\n",
  1320. status
  1321. ));
  1322. }
  1323. } else {
  1324. DBGPRINTF((
  1325. DBG_CONTEXT,
  1326. "PerformStateChange: invalid command %lu for state %lu\n",
  1327. command,
  1328. currentState
  1329. ));
  1330. status = ERROR_INVALID_SERVICE_CONTROL;
  1331. }
  1332. break;
  1333. case MD_SERVER_COMMAND_PAUSE :
  1334. //
  1335. // Pause the instance.
  1336. //
  1337. // If it's running, then pause it. If it's in any other state,
  1338. // this is an invalid state transition.
  1339. //
  1340. // Note that the *service* must be running before an instance
  1341. // can be paused.
  1342. //
  1343. if( serviceState == SERVICE_RUNNING &&
  1344. currentState == MD_SERVER_STATE_STARTED ) {
  1345. status = PauseInstance();
  1346. if( status != NO_ERROR ) {
  1347. DBGPRINTF((
  1348. DBG_CONTEXT,
  1349. "PerformStateChange: cannot pause instance, error %lu\n",
  1350. status
  1351. ));
  1352. }
  1353. } else {
  1354. DBGPRINTF((
  1355. DBG_CONTEXT,
  1356. "PerformStateChange: invalid command %lu for state %lu\n",
  1357. command,
  1358. currentState
  1359. ));
  1360. status = ERROR_INVALID_SERVICE_CONTROL;
  1361. }
  1362. break;
  1363. case MD_SERVER_COMMAND_CONTINUE :
  1364. //
  1365. // Continue the instance.
  1366. //
  1367. // If it's paused, then continue it. If it's in any other
  1368. // state, this is an invalid state transition.
  1369. //
  1370. // Note that the *service* must be running before an instance
  1371. // can be continued.
  1372. //
  1373. if( serviceState == SERVICE_RUNNING &&
  1374. currentState == MD_SERVER_STATE_PAUSED ) {
  1375. status = ContinueInstance();
  1376. if( status != NO_ERROR ) {
  1377. DBGPRINTF((
  1378. DBG_CONTEXT,
  1379. "PerformStateChange: cannot continue instance, error %lu\n",
  1380. status
  1381. ));
  1382. }
  1383. } else {
  1384. DBGPRINTF((
  1385. DBG_CONTEXT,
  1386. "PerformStateChange: invalid command %lu for state %lu\n",
  1387. command,
  1388. currentState
  1389. ));
  1390. status = ERROR_INVALID_SERVICE_CONTROL;
  1391. }
  1392. break;
  1393. default :
  1394. DBGPRINTF((
  1395. DBG_CONTEXT,
  1396. "PerformStateChange: invalid command %lu\n",
  1397. command
  1398. ));
  1399. status = ERROR_INVALID_SERVICE_CONTROL;
  1400. break;
  1401. }
  1402. } else {
  1403. DBGPRINTF((
  1404. DBG_CONTEXT,
  1405. "PerformStateChange: cannot read metabase, error %lu\n",
  1406. status
  1407. ));
  1408. }
  1409. //
  1410. // Unlock the instance before trying to reopen the metabase.
  1411. //
  1412. UnlockThis();
  1413. //
  1414. // Restore the state to the previous value if the state change failed.
  1415. //
  1416. if( status != NO_ERROR ) {
  1417. SetServerState( currentState, status );
  1418. }
  1419. return status;
  1420. } // IIS_SERVER_INSTANCE::PerformStateChange
  1421. VOID
  1422. IIS_SERVER_INSTANCE::SetServerState(
  1423. IN DWORD NewState,
  1424. IN DWORD Win32Error
  1425. )
  1426. /*++
  1427. Routine Description:
  1428. Sets the new server state, storing it locally and also storing the
  1429. new state in the metabase.
  1430. Arguments:
  1431. NewState - The new server state.
  1432. Win32Error - New Win32 error value.
  1433. Return Value:
  1434. None.
  1435. --*/
  1436. {
  1437. DWORD status = NO_ERROR;
  1438. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1439. //
  1440. // Open the metabase and save the new state. Note that we map
  1441. // MD_SERVER_STATE_INVALID to MD_SERVER_STATE_STOPPED in the metabase.
  1442. // Client applications would probably be confused by the _INVALID state.
  1443. //
  1444. if( mb.Open(
  1445. QueryMDPath(),
  1446. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) {
  1447. if( !mb.SetDword(
  1448. "",
  1449. MD_WIN32_ERROR,
  1450. IIS_MD_UT_SERVER,
  1451. Win32Error,
  1452. METADATA_VOLATILE
  1453. ) ||
  1454. !mb.SetDword(
  1455. "",
  1456. MD_SERVER_STATE,
  1457. IIS_MD_UT_SERVER,
  1458. NewState == MD_SERVER_STATE_INVALID
  1459. ? MD_SERVER_STATE_STOPPED
  1460. : NewState,
  1461. METADATA_VOLATILE
  1462. ) ) {
  1463. status = GetLastError();
  1464. }
  1465. } else {
  1466. status = GetLastError();
  1467. }
  1468. if( status != NO_ERROR ) {
  1469. DBGPRINTF((
  1470. DBG_CONTEXT,
  1471. "SetServerState: cannot write metabase (%lu), error %lu\n",
  1472. NewState,
  1473. status
  1474. ));
  1475. }
  1476. //
  1477. // Save it in the object also.
  1478. //
  1479. m_dwServerState = NewState;
  1480. } // IIS_SERVER_INSTANCE::SetServerState
  1481. BOOL
  1482. IIS_SERVER_INSTANCE::StopEndpoints( VOID)
  1483. /*++
  1484. Routine Description:
  1485. Walks down the list of Endpoints held by the Server instance and
  1486. calls IIS_ENDPOINT::StopEndpoint for the endpoints.
  1487. Arguments:
  1488. None
  1489. Return Value:
  1490. TRUE if stop is successful,
  1491. FALSE otherwise
  1492. --*/
  1493. {
  1494. BOOL fReturn = TRUE;
  1495. //
  1496. // Inside the locked section walk the normal & secure bindings
  1497. // to stop all relevant endpoints
  1498. //
  1499. LockThisForWrite();
  1500. if (!StopEndpointsHelper( &m_NormalBindingListHead)) {
  1501. fReturn = FALSE;
  1502. }
  1503. if (!StopEndpointsHelper( &m_SecureBindingListHead)) {
  1504. fReturn = FALSE;
  1505. }
  1506. UnlockThis();
  1507. return ( fReturn);
  1508. } // IIS_SERVER_INSTANCE::StopEndpoints()
  1509. BOOL
  1510. IIS_SERVER_INSTANCE::StopEndpointsHelper( PLIST_ENTRY pBindingListHead)
  1511. /*++
  1512. Routine Description:
  1513. Helper routine for StopEndpoints().
  1514. This function should be called with the Endpoints lock held
  1515. Arguments:
  1516. pBindingListHead - pointer to the binding list for endpoints to be stopped
  1517. Return Value:
  1518. BOOL - TRUE on success and FALSE on failure
  1519. --*/
  1520. {
  1521. BOOL fReturn = TRUE;
  1522. PLIST_ENTRY plBindingScan;
  1523. PIIS_SERVER_BINDING binding;
  1524. //
  1525. // Walk the list of bindings and destroy them.
  1526. //
  1527. for( plBindingScan = pBindingListHead->Flink;
  1528. plBindingScan != pBindingListHead;
  1529. plBindingScan = plBindingScan->Flink
  1530. ) {
  1531. binding = CONTAINING_RECORD(
  1532. plBindingScan,
  1533. IIS_SERVER_BINDING,
  1534. m_BindingListEntry
  1535. );
  1536. IF_DEBUG( INSTANCE ) {
  1537. DBGPRINTF((
  1538. DBG_CONTEXT,
  1539. "stop ATQ EP of %p from instance %p, "
  1540. " binding %p (%lx:%d:%s)\n",
  1541. binding->QueryEndpoint(),
  1542. this,
  1543. binding,
  1544. binding->QueryIpAddress(),
  1545. binding->QueryEndpoint()->QueryPort(),
  1546. binding->QueryHostName()
  1547. ));
  1548. }
  1549. if ( !binding->QueryEndpoint()->StopEndpoint()) {
  1550. fReturn = FALSE;
  1551. }
  1552. } // for
  1553. //
  1554. // Success!
  1555. //
  1556. return ( fReturn);
  1557. } // IIS_SERVER_INSTANCE::StopEndpointsHelper()
  1558. BOOL
  1559. IIS_SERVER_INSTANCE::CloseInstance(
  1560. VOID
  1561. )
  1562. /*++
  1563. Routine Description:
  1564. Shuts down instance
  1565. Arguments:
  1566. None
  1567. Return Value:
  1568. TRUE if Shutdown successful,
  1569. FALSE otherwise
  1570. --*/
  1571. {
  1572. IF_DEBUG(INSTANCE) {
  1573. DBGPRINTF((
  1574. DBG_CONTEXT,
  1575. "IIS_SERVER_INSTANCE::Close called for %p\n",
  1576. this
  1577. ));
  1578. }
  1579. (VOID)m_Service->DisassociateInstance( this );
  1580. return TRUE;
  1581. } // IIS_SERVER_INSTANCE::CloseInstance
  1582. DWORD
  1583. IIS_SERVER_INSTANCE::StartInstance()
  1584. /*++
  1585. Routine Description:
  1586. Sets instance to RUNNING
  1587. Arguments:
  1588. None.
  1589. Return Value:
  1590. DWORD - 0 if successful, !0 otherwise.
  1591. --*/
  1592. {
  1593. DWORD status;
  1594. IF_DEBUG(INSTANCE) {
  1595. DBGPRINTF((
  1596. DBG_CONTEXT,
  1597. "IIS_SERVER_INSTANCE::StartInstance called for %p. Current state %d\n",
  1598. this,
  1599. QueryServerState()
  1600. ));
  1601. }
  1602. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_STOPPED );
  1603. //
  1604. // Set the transient state.
  1605. //
  1606. SetServerState( MD_SERVER_STATE_STARTING, NO_ERROR );
  1607. //
  1608. // Set cache parameters
  1609. //
  1610. m_tsCache.SetParameters(
  1611. m_Service->QueryServiceId(),
  1612. QueryInstanceId(),
  1613. this );
  1614. if (( QueryInstanceId() != INET_INSTANCE_ROOT ) && IsDownLevelInstance() )
  1615. {
  1616. MoveMDVroots2Registry();
  1617. // no longer supporting migrating VRoots back from the registry
  1618. //PdcHackVRReg2MD( );
  1619. }
  1620. //
  1621. // Read all common parameters and initialize VDirs
  1622. //
  1623. if ( !RegReadCommonParams( TRUE, TRUE) ) {
  1624. return ERROR_NOT_ENOUGH_MEMORY;
  1625. }
  1626. //
  1627. // Start logging
  1628. //
  1629. m_Logging.ActivateLogging(
  1630. m_Service->QueryServiceName(),
  1631. QueryInstanceId(),
  1632. m_strMDPath.QueryStr(),
  1633. m_Service->QueryMDObject() );
  1634. //
  1635. // Verify the service can handle another instance.
  1636. //
  1637. if( !m_Service->RecordInstanceStart() ) {
  1638. m_Logging.ShutdownLogging();
  1639. QueryVrootTable()->RemoveVirtualRoots();
  1640. return ERROR_NOT_SUPPORTED;
  1641. }
  1642. //
  1643. // Bind the instance.
  1644. //
  1645. status = BindInstance();
  1646. if ( status != NO_ERROR ) {
  1647. m_Logging.ShutdownLogging();
  1648. QueryVrootTable()->RemoveVirtualRoots();
  1649. //
  1650. // Tell the service that we failed to start the instance.
  1651. //
  1652. m_Service->RecordInstanceStop();
  1653. }
  1654. return status;
  1655. } // IIS_SERVER_INSTANCE::StartInstance
  1656. DWORD
  1657. IIS_SERVER_INSTANCE::StopInstance()
  1658. /*++
  1659. Routine Description:
  1660. Sets instance to STOPPED
  1661. Arguments:
  1662. None.
  1663. Return Value:
  1664. DWORD - 0 if successful, !0 otherwise.
  1665. --*/
  1666. {
  1667. DWORD status;
  1668. IF_DEBUG(INSTANCE) {
  1669. DBGPRINTF((
  1670. DBG_CONTEXT,
  1671. "IIS_SERVER_INSTANCE::StopInstance called for %p. Current state %d\n",
  1672. this,
  1673. QueryServerState()
  1674. ));
  1675. }
  1676. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_STARTED ||
  1677. QueryServerState() == MD_SERVER_STATE_PAUSED );
  1678. Reference();
  1679. //
  1680. // Set the transient state.
  1681. //
  1682. SetServerState( MD_SERVER_STATE_STOPPING, NO_ERROR );
  1683. m_Service->StopInstanceProcs( this );
  1684. //
  1685. // Note that we call DisconnectUsersByInstance() before *and* after
  1686. // unbinding the instance. This is to prevent a potential race condition
  1687. // that can occur if another thread is already in IIS_ENDPOINT::
  1688. // FindAndReferenceInstance(), has found the instance, checked its state,
  1689. // and found it to be MD_SERVER_STATE_STARTED. The call to UnbindInstance()
  1690. // will lock any affected endpoints, ensuring that there are no other
  1691. // threads in the midst of a FindAndReferenceInstance(). The second
  1692. // (seemingly redundant) call to DisconnectUsersByInstance() will catch
  1693. // any threads that "snuck in" under these conditions.
  1694. //
  1695. status = m_Service->DisconnectUsersByInstance( this );
  1696. if( status == NO_ERROR ) {
  1697. status = UnbindInstance();
  1698. }
  1699. if( status == NO_ERROR ) {
  1700. status = m_Service->DisconnectUsersByInstance( this );
  1701. }
  1702. if( status == NO_ERROR ) {
  1703. SetServerState( MD_SERVER_STATE_STOPPED, NO_ERROR );
  1704. m_dwSavedState = MD_SERVER_STATE_STOPPED;
  1705. m_Service->RecordInstanceStop();
  1706. }
  1707. //
  1708. // logging cleanup
  1709. //
  1710. DBG_REQUIRE( m_Logging.ShutdownLogging());
  1711. DBG_REQUIRE( QueryVrootTable()->RemoveVirtualRoots());
  1712. Dereference();
  1713. return status;
  1714. } // IIS_SERVER_INSTANCE::StopInstance
  1715. DWORD
  1716. IIS_SERVER_INSTANCE::PauseInstance()
  1717. /*++
  1718. Routine Description:
  1719. Sets instance to PAUSE
  1720. Arguments:
  1721. None.
  1722. Return Value:
  1723. DWORD - 0 if successful, !0 otherwise.
  1724. --*/
  1725. {
  1726. IF_DEBUG(INSTANCE) {
  1727. DBGPRINTF((
  1728. DBG_CONTEXT,
  1729. "IIS_SERVER_INSTANCE::Pause called for %p. Current state %d\n",
  1730. this,
  1731. QueryServerState()
  1732. ));
  1733. }
  1734. //
  1735. // Just set the paused state (no need for a transient state).
  1736. // Setting the instance to paused will prevent new incoming
  1737. // connections on the instance.
  1738. //
  1739. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_STARTED );
  1740. SetServerState( MD_SERVER_STATE_PAUSED, NO_ERROR );
  1741. //
  1742. // Success!
  1743. //
  1744. return NO_ERROR;
  1745. } // IIS_SERVER_INSTANCE::PauseInstance
  1746. DWORD
  1747. IIS_SERVER_INSTANCE::ContinueInstance()
  1748. /*++
  1749. Routine Description:
  1750. Sets instance to STARTED.
  1751. Arguments:
  1752. None.
  1753. Return Value:
  1754. DWORD - 0 if successful, !0 otherwise.
  1755. --*/
  1756. {
  1757. IF_DEBUG(INSTANCE) {
  1758. DBGPRINTF((
  1759. DBG_CONTEXT,
  1760. "IIS_SERVER_INSTANCE::Continue called for %p. Current state %d\n",
  1761. this,
  1762. QueryServerState()
  1763. ));
  1764. }
  1765. //
  1766. // Just set the stated state (no need for a transient state).
  1767. // Setting the instance to started will allow new incoming
  1768. // connections on the instance.
  1769. //
  1770. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_PAUSED );
  1771. SetServerState( MD_SERVER_STATE_STARTED, NO_ERROR );
  1772. //
  1773. // Success!
  1774. //
  1775. return NO_ERROR;
  1776. } // IIS_SERVER_INSTANCE::ContinueInstance
  1777. VOID
  1778. IIS_SERVER_INSTANCE::SetWin32Error(
  1779. DWORD err
  1780. )
  1781. {
  1782. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1783. DWORD status = NO_ERROR;
  1784. //
  1785. // Open the metabase and save the error code.
  1786. //
  1787. if( mb.Open(
  1788. QueryMDPath(),
  1789. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) {
  1790. if( !mb.SetDword(
  1791. "",
  1792. MD_WIN32_ERROR,
  1793. IIS_MD_UT_SERVER,
  1794. err,
  1795. METADATA_VOLATILE
  1796. ) ) {
  1797. status = GetLastError();
  1798. }
  1799. } else {
  1800. status = GetLastError();
  1801. }
  1802. if( status != NO_ERROR ) {
  1803. DBGPRINTF((
  1804. DBG_CONTEXT,
  1805. "SetWin32Error: cannot save error %lu (%lx), error %lx\n",
  1806. err,
  1807. err,
  1808. status
  1809. ));
  1810. }
  1811. } // IIS_SERVER_INSTANCE::SetWin32Error
  1812. BOOL
  1813. IIS_SERVER_INSTANCE::SetBandwidthThrottle(
  1814. IN MB * pMB
  1815. )
  1816. /*++
  1817. Routine Description:
  1818. Set the bandwidth throttle threshold for this instance
  1819. Arguments:
  1820. pMB - pointer to metabase handle
  1821. Return Value:
  1822. TRUE if successful, FALSE otherwise
  1823. --*/
  1824. {
  1825. DWORD dwBandwidth;
  1826. if ( !TsIsNtServer() )
  1827. {
  1828. return TRUE;
  1829. }
  1830. DBG_ASSERT( pMB != NULL );
  1831. if ( !pMB->GetDword( "",
  1832. MD_MAX_BANDWIDTH,
  1833. IIS_MD_UT_SERVER,
  1834. &dwBandwidth,
  1835. 0 ) )
  1836. {
  1837. VOID * pTemp;
  1838. pTemp = InterlockedExchangePointer( (PVOID *) &m_pBandwidthInfo, NULL );
  1839. if ( pTemp )
  1840. {
  1841. DBG_REQUIRE( AtqFreeBandwidthInfo( pTemp ) );
  1842. }
  1843. }
  1844. else
  1845. {
  1846. if ( m_pBandwidthInfo == NULL )
  1847. {
  1848. VOID * pTemp = AtqCreateBandwidthInfo();
  1849. if ( pTemp != NULL )
  1850. {
  1851. AtqBandwidthSetInfo( pTemp,
  1852. ATQ_BW_BANDWIDTH_LEVEL,
  1853. dwBandwidth );
  1854. AtqBandwidthSetInfo( pTemp,
  1855. ATQ_BW_DESCRIPTION,
  1856. (ULONG_PTR) m_strMDPath.QueryStr() );
  1857. InterlockedExchangePointer( (PVOID *) &m_pBandwidthInfo, (PVOID) pTemp );
  1858. }
  1859. }
  1860. else
  1861. {
  1862. AtqBandwidthSetInfo( m_pBandwidthInfo,
  1863. ATQ_BW_BANDWIDTH_LEVEL,
  1864. (ULONG_PTR)dwBandwidth );
  1865. }
  1866. }
  1867. return TRUE;
  1868. }
  1869. BOOL
  1870. IIS_SERVER_INSTANCE::SetBandwidthThrottleMaxBlocked(
  1871. IN MB * pMB
  1872. )
  1873. {
  1874. DWORD dwMaxBlocked = INFINITE;
  1875. if ( !TsIsNtServer() )
  1876. {
  1877. return TRUE;
  1878. }
  1879. DBG_ASSERT( pMB != NULL );
  1880. if ( pMB->GetDword( "",
  1881. MD_MAX_BANDWIDTH_BLOCKED,
  1882. IIS_MD_UT_SERVER,
  1883. &dwMaxBlocked,
  1884. 0 ) )
  1885. {
  1886. if ( m_pBandwidthInfo )
  1887. {
  1888. AtqBandwidthSetInfo( m_pBandwidthInfo,
  1889. ATQ_BW_MAX_BLOCKED,
  1890. dwMaxBlocked );
  1891. }
  1892. }
  1893. return TRUE;
  1894. }
  1895. DWORD
  1896. IIS_SERVER_INSTANCE::DoStartInstance(
  1897. VOID
  1898. )
  1899. /*++
  1900. Routine Description:
  1901. Start an instance. This call encompasses the IIS_SERVER_INSTANCE and
  1902. inherited invocations of StartInstance
  1903. Arguments:
  1904. None.
  1905. Return Value:
  1906. DWORD - 0 if successful, !0 otherwise.
  1907. --*/
  1908. {
  1909. DWORD dwError;
  1910. dwError = StartInstance();
  1911. if ( dwError == NO_ERROR )
  1912. {
  1913. if( m_Service->QueryCurrentServiceState() == SERVICE_PAUSED )
  1914. {
  1915. SetServerState( MD_SERVER_STATE_PAUSED, NO_ERROR );
  1916. }
  1917. else
  1918. {
  1919. SetServerState( MD_SERVER_STATE_STARTED, NO_ERROR );
  1920. }
  1921. }
  1922. return dwError;
  1923. }