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.

2629 lines
56 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. // OK. Let's avoid a change in the UI by mapping
  808. // ERROR_INVALID_PARAMETER to ERROR_DUP_NAME so that the eventlog
  809. // message is more useful.
  810. //
  811. m_Service->LogEvent(
  812. INET_SVC_FATAL_BINDING_ERROR,
  813. 1,
  814. apszSubStrings,
  815. status == ERROR_INVALID_PARAMETER ? ERROR_DUP_NAME : status
  816. );
  817. fatal_nolog:
  818. //
  819. // Loop through the local list of newly created bindings and delete them.
  820. //
  821. while( !IsListEmpty( &createdBindings ) ) {
  822. listEntry = RemoveHeadList(
  823. &createdBindings
  824. );
  825. binding = CONTAINING_RECORD(
  826. listEntry,
  827. IIS_SERVER_BINDING,
  828. m_BindingListEntry
  829. );
  830. IF_DEBUG( INSTANCE ) {
  831. DBGPRINTF((
  832. DBG_CONTEXT,
  833. "zapping %p from %p, binding %p (%lx:%d:%s) (ERROR)\n",
  834. binding->QueryEndpoint(),
  835. this,
  836. binding,
  837. binding->QueryIpAddress(),
  838. binding->QueryEndpoint()->QueryPort(),
  839. binding->QueryHostName()
  840. ));
  841. }
  842. binding->QueryEndpoint()->RemoveInstance(
  843. this,
  844. binding->QueryIpAddress(),
  845. binding->QueryHostName()
  846. );
  847. binding->QueryEndpoint()->Dereference();
  848. delete binding;
  849. }
  850. UnlockThis();
  851. return status;
  852. } // IIS_SERVER_INSTANCE::UpdateBindingsHelper
  853. DWORD
  854. IIS_SERVER_INSTANCE::CreateNewBinding(
  855. IN DWORD IpAddress,
  856. IN USHORT IpPort,
  857. IN const CHAR * HostName,
  858. IN BOOL IsSecure,
  859. IN BOOL fDisableSocketPooling,
  860. OUT IIS_SERVER_BINDING ** NewBinding
  861. )
  862. /*++
  863. Routine Description:
  864. Creates a new binding object for the specified ip address, port, and
  865. host name, and creates/references the appropriate endpoint object.
  866. Arguments:
  867. IpAddress - The binding IP address. May be INADDR_ANY.
  868. IpPort - The binding IP port. Required.
  869. HostName - The binding host name. May be empty ("").
  870. IsSecure - TRUE for secure endpoints. Only used if a new endpoint
  871. is created.
  872. fDisableSocketPooling - TRUE to create unique endpoints based on both
  873. port & IP. Only used if a new endpoint is created.
  874. NewBinding - Receives a pointer to the new binding object if successful.
  875. Return Value:
  876. DWORD - Completion status, 0 if successful, !0 otherwise.
  877. --*/
  878. {
  879. PIIS_ENDPOINT endpoint;
  880. PIIS_SERVER_BINDING binding;
  881. DWORD status;
  882. //
  883. // Sanity check.
  884. //
  885. DBG_ASSERT( IpPort != 0 );
  886. DBG_ASSERT( HostName != NULL );
  887. DBG_ASSERT( NewBinding != NULL );
  888. //
  889. // Setup locals so we know how to cleanup on exit.
  890. //
  891. endpoint = NULL;
  892. binding = NULL;
  893. //
  894. // Try to find an endpoint for the specified port.
  895. //
  896. endpoint = m_Service->FindAndReferenceEndpoint(
  897. IpPort,
  898. IpAddress,
  899. TRUE, // CreateIfNotFound
  900. IsSecure,
  901. fDisableSocketPooling
  902. );
  903. if( endpoint != NULL ) {
  904. //
  905. // Create a new binding.
  906. //
  907. binding = new IIS_SERVER_BINDING(
  908. IpAddress,
  909. IpPort,
  910. HostName,
  911. endpoint
  912. );
  913. if( binding != NULL ) {
  914. if( endpoint->AddInstance(
  915. this,
  916. IpAddress,
  917. HostName
  918. ) ) {
  919. endpoint->Reference();
  920. *NewBinding = binding;
  921. status = NO_ERROR;
  922. } else {
  923. //
  924. // Could not associate the instance with the endpoint.
  925. //
  926. status = GetLastError();
  927. ASSERT( status != NO_ERROR );
  928. //
  929. // if we didn't get an error code back for some reason
  930. // we choose this one since resource shortages are
  931. // the most likely failure case.
  932. //
  933. if ( NO_ERROR == status ) {
  934. status = ERROR_NOT_ENOUGH_MEMORY;
  935. }
  936. }
  937. } else {
  938. //
  939. // Could not create new binding object.
  940. //
  941. status = ERROR_NOT_ENOUGH_MEMORY;
  942. }
  943. } else {
  944. //
  945. // Could not find & reference endpoint.
  946. //
  947. status = ERROR_NOT_ENOUGH_MEMORY;
  948. }
  949. //
  950. // Remove the reference added in FindAndReferenceEndpoint().
  951. //
  952. if( endpoint != NULL ) {
  953. endpoint->Dereference();
  954. }
  955. //
  956. // Cleanup if necessary.
  957. //
  958. if( status != NO_ERROR ) {
  959. if( binding != NULL ) {
  960. delete binding;
  961. }
  962. }
  963. return status;
  964. } // IIS_SERVER_INSTANCE::CreateNewBinding
  965. BOOL
  966. IIS_SERVER_INSTANCE::IsInCurrentBindingList(
  967. IN PLIST_ENTRY BindingListHead,
  968. IN DWORD IpAddress OPTIONAL,
  969. IN USHORT IpPort,
  970. IN const CHAR * HostName OPTIONAL
  971. )
  972. /*++
  973. Routine Description:
  974. Scans the current binding list looking for the specified IP address,
  975. port, and host name.
  976. Arguments:
  977. BindingListHead - The binding list to scan.
  978. IpAddress - The IP address to search for. May be INADDR_ANY.
  979. IpPort - The IP port to search for. Required.
  980. HostName - The host name to search for. May be empty ("").
  981. Return Value:
  982. BOOL - TRUE if the binding was found, FALSE otherwise.
  983. --*/
  984. {
  985. PLIST_ENTRY listEntry;
  986. PIIS_SERVER_BINDING binding;
  987. //
  988. // Sanity check.
  989. //
  990. DBG_ASSERT( IpPort != 0 );
  991. DBG_ASSERT( HostName != NULL );
  992. //
  993. // Scan the bindings.
  994. //
  995. for( listEntry = BindingListHead->Flink ;
  996. listEntry != BindingListHead ;
  997. listEntry = listEntry->Flink ) {
  998. binding = CONTAINING_RECORD(
  999. listEntry,
  1000. IIS_SERVER_BINDING,
  1001. m_BindingListEntry
  1002. );
  1003. if( binding->Compare(
  1004. IpAddress,
  1005. IpPort,
  1006. HostName
  1007. ) ) {
  1008. return TRUE;
  1009. }
  1010. }
  1011. return FALSE;
  1012. } // IIS_SERVER_INSTANCE::IsInCurrentBindingList
  1013. BOOL
  1014. IIS_SERVER_INSTANCE::IsBindingInMultiSz(
  1015. IN PIIS_SERVER_BINDING Binding,
  1016. IN const MULTISZ &msz
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. Scans the specified MULTISZ object to see if it contains a descriptor
  1021. matching the specified binding object.
  1022. Arguments:
  1023. Binding - The binding to search for.
  1024. msz - The MULTISZ to search.
  1025. Return Value:
  1026. DWORD - Completion status, 0 if successful, !0 otherwise.
  1027. --*/
  1028. {
  1029. const CHAR * scan;
  1030. DWORD status;
  1031. BOOL result;
  1032. //
  1033. // Sanity check.
  1034. //
  1035. DBG_ASSERT( Binding != NULL );
  1036. //
  1037. // Scan the MULTISZ.
  1038. //
  1039. for( scan = msz.First() ;
  1040. scan != NULL ;
  1041. scan = msz.Next( scan ) ) {
  1042. status = Binding->Compare( scan, &result );
  1043. if( status == NO_ERROR && result ) {
  1044. return TRUE;
  1045. }
  1046. }
  1047. return FALSE;
  1048. } // IIS_SERVER_INSTANCE::IsBindingInMultiSz
  1049. DWORD
  1050. IIS_SERVER_INSTANCE::PerformClusterModeChange(
  1051. VOID
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Reads the server cluster mode from the metabase and performs any
  1056. necessary changes.
  1057. Arguments:
  1058. None.
  1059. Return Value:
  1060. DWORD - Completion status, 0 if successful, !0 otherwise.
  1061. --*/
  1062. {
  1063. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1064. DWORD status;
  1065. DWORD currentState;
  1066. DWORD serviceState;
  1067. BOOL fPreviousClusterEnabled;
  1068. //
  1069. // Setup locals.
  1070. //
  1071. status = NO_ERROR;
  1072. fPreviousClusterEnabled = m_fClusterEnabled;
  1073. serviceState = m_Service->QueryCurrentServiceState();
  1074. currentState = QueryServerState();
  1075. //
  1076. // Open the metabase and query the cluster enabled flag
  1077. //
  1078. if( mb.Open(
  1079. QueryMDPath(),
  1080. METADATA_PERMISSION_READ ) )
  1081. {
  1082. if( !mb.GetDword(
  1083. "",
  1084. MD_CLUSTER_ENABLED,
  1085. IIS_MD_UT_SERVER,
  1086. (LPDWORD)&m_fClusterEnabled
  1087. ) )
  1088. {
  1089. m_fClusterEnabled = FALSE;
  1090. status = GetLastError();
  1091. IF_DEBUG( INSTANCE )
  1092. {
  1093. DBGPRINTF((
  1094. DBG_CONTEXT,
  1095. "PerformClusterModeChange: cannot read server command, error %lu\n",
  1096. status
  1097. ));
  1098. }
  1099. }
  1100. //
  1101. // Close it so that code needed to update the metabase when
  1102. // changing state can indeed open the metabase.
  1103. //
  1104. mb.Close();
  1105. }
  1106. else
  1107. {
  1108. status = GetLastError();
  1109. IF_DEBUG( INSTANCE )
  1110. {
  1111. DBGPRINTF((
  1112. DBG_CONTEXT,
  1113. "PerformClusterModeChange: cannot open metabase for READ, error %lu\n",
  1114. status
  1115. ));
  1116. }
  1117. }
  1118. //
  1119. // If cluster mode transition from non-cluster to cluster
  1120. // then must make sure that instance is stopped.
  1121. // instance will be started as required by cluster manager.
  1122. //
  1123. if ( status == NO_ERROR &&
  1124. m_fClusterEnabled &&
  1125. !fPreviousClusterEnabled )
  1126. {
  1127. if( ( serviceState == SERVICE_RUNNING ||
  1128. serviceState == SERVICE_PAUSED ) &&
  1129. ( currentState == MD_SERVER_STATE_STARTED ||
  1130. currentState == MD_SERVER_STATE_PAUSED ) ) {
  1131. LockThisForWrite();
  1132. status = StopInstance();
  1133. if( status != NO_ERROR ) {
  1134. DBGPRINTF((
  1135. DBG_CONTEXT,
  1136. "PerformClusterModeChange: cannot stop instance, error %lu\n",
  1137. status
  1138. ));
  1139. }
  1140. UnlockThis();
  1141. }
  1142. //
  1143. // Restore the state to the previous value if the state change failed.
  1144. //
  1145. if( status != NO_ERROR ) {
  1146. SetServerState( currentState, status );
  1147. }
  1148. }
  1149. return status;
  1150. }
  1151. DWORD
  1152. IIS_SERVER_INSTANCE::PerformStateChange(
  1153. VOID
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Reads the server instance state from the metabase and performs any
  1158. necessary state changes.
  1159. Arguments:
  1160. None.
  1161. Return Value:
  1162. DWORD - Completion status, 0 if successful, !0 otherwise.
  1163. --*/
  1164. {
  1165. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1166. DWORD status;
  1167. DWORD command;
  1168. DWORD currentState;
  1169. DWORD serviceState;
  1170. //
  1171. // Setup locals.
  1172. //
  1173. status = NO_ERROR;
  1174. serviceState = m_Service->QueryCurrentServiceState();
  1175. currentState = QueryServerState();
  1176. //
  1177. // Open the metabase and query the state change command.
  1178. //
  1179. if( mb.Open(
  1180. QueryMDPath(),
  1181. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) {
  1182. if( !mb.GetDword(
  1183. "",
  1184. IsClusterEnabled() ? MD_CLUSTER_SERVER_COMMAND : MD_SERVER_COMMAND,
  1185. IIS_MD_UT_SERVER,
  1186. &command
  1187. ) ) {
  1188. status = GetLastError();
  1189. IF_DEBUG( INSTANCE ) {
  1190. DBGPRINTF((
  1191. DBG_CONTEXT,
  1192. "PerformStateChange: cannot read server command, error %lu\n",
  1193. status
  1194. ));
  1195. }
  1196. }
  1197. //
  1198. // Update the instance AutoStart value so the instance state is
  1199. // persisted across service restarts
  1200. //
  1201. if( status == NO_ERROR ) {
  1202. switch( command ) {
  1203. case MD_SERVER_COMMAND_START :
  1204. mb.SetDword(
  1205. "",
  1206. MD_SERVER_AUTOSTART,
  1207. IIS_MD_UT_SERVER,
  1208. TRUE );
  1209. break;
  1210. case MD_SERVER_COMMAND_STOP :
  1211. mb.SetDword(
  1212. "",
  1213. MD_SERVER_AUTOSTART,
  1214. IIS_MD_UT_SERVER,
  1215. FALSE );
  1216. break;
  1217. default:
  1218. break;
  1219. }
  1220. }
  1221. //
  1222. // Close it so that code needed to update the metabase when
  1223. // changing state can indeed open the metabase.
  1224. //
  1225. mb.Close();
  1226. } else {
  1227. status = GetLastError();
  1228. IF_DEBUG( INSTANCE ) {
  1229. DBGPRINTF((
  1230. DBG_CONTEXT,
  1231. "PerformStateChange: cannot open metabase for READ, error %lu\n",
  1232. status
  1233. ));
  1234. }
  1235. }
  1236. //
  1237. // Lock the instance.
  1238. //
  1239. LockThisForWrite();
  1240. //
  1241. // Interpret the command. Note that the StartInstance(), StopInstance(),
  1242. // PauseInstance(), and ContinueInstance() methods will set the instance
  1243. // state if they complete successfully, but it is this routine's
  1244. // responsibility to reset the state to the original value if the
  1245. // methods fail.
  1246. //
  1247. if( status == NO_ERROR ) {
  1248. switch( command ) {
  1249. case MD_SERVER_COMMAND_START :
  1250. //
  1251. // Start the instance.
  1252. //
  1253. // If it's stopped, then start it. If it's in any other state,
  1254. // this is an invalid state transition.
  1255. //
  1256. // Note that the *service* must be running before an instance
  1257. // can be started.
  1258. //
  1259. if( serviceState == SERVICE_RUNNING &&
  1260. currentState == MD_SERVER_STATE_STOPPED ) {
  1261. status = DoStartInstance();
  1262. if( status != NO_ERROR ) {
  1263. DBGPRINTF((
  1264. DBG_CONTEXT,
  1265. "PerformStateChange: cannot start instance, error %lu\n",
  1266. status
  1267. ));
  1268. }
  1269. } else {
  1270. DBGPRINTF((
  1271. DBG_CONTEXT,
  1272. "PerformStateChange: invalid command %lu for state %lu\n",
  1273. command,
  1274. currentState
  1275. ));
  1276. status = ERROR_INVALID_SERVICE_CONTROL;
  1277. }
  1278. break;
  1279. case MD_SERVER_COMMAND_STOP :
  1280. //
  1281. // Stop the instance.
  1282. //
  1283. // If it's running or paused, then start it. If it's in any
  1284. // other state, this is an invalid state transition.
  1285. //
  1286. // Note that the *service* must be either running or paused
  1287. // before an instance can be paused.
  1288. //
  1289. if( ( serviceState == SERVICE_RUNNING ||
  1290. serviceState == SERVICE_PAUSED ) &&
  1291. ( currentState == MD_SERVER_STATE_STARTED ||
  1292. currentState == MD_SERVER_STATE_PAUSED ) ) {
  1293. status = StopInstance();
  1294. if( status != NO_ERROR ) {
  1295. DBGPRINTF((
  1296. DBG_CONTEXT,
  1297. "PerformStateChange: cannot stop instance, error %lu\n",
  1298. status
  1299. ));
  1300. }
  1301. } else {
  1302. DBGPRINTF((
  1303. DBG_CONTEXT,
  1304. "PerformStateChange: invalid command %lu for state %lu\n",
  1305. command,
  1306. currentState
  1307. ));
  1308. status = ERROR_INVALID_SERVICE_CONTROL;
  1309. }
  1310. break;
  1311. case MD_SERVER_COMMAND_PAUSE :
  1312. //
  1313. // Pause the instance.
  1314. //
  1315. // If it's running, then pause it. If it's in any other state,
  1316. // this is an invalid state transition.
  1317. //
  1318. // Note that the *service* must be running before an instance
  1319. // can be paused.
  1320. //
  1321. if( serviceState == SERVICE_RUNNING &&
  1322. currentState == MD_SERVER_STATE_STARTED ) {
  1323. status = PauseInstance();
  1324. if( status != NO_ERROR ) {
  1325. DBGPRINTF((
  1326. DBG_CONTEXT,
  1327. "PerformStateChange: cannot pause instance, error %lu\n",
  1328. status
  1329. ));
  1330. }
  1331. } else {
  1332. DBGPRINTF((
  1333. DBG_CONTEXT,
  1334. "PerformStateChange: invalid command %lu for state %lu\n",
  1335. command,
  1336. currentState
  1337. ));
  1338. status = ERROR_INVALID_SERVICE_CONTROL;
  1339. }
  1340. break;
  1341. case MD_SERVER_COMMAND_CONTINUE :
  1342. //
  1343. // Continue the instance.
  1344. //
  1345. // If it's paused, then continue it. If it's in any other
  1346. // state, this is an invalid state transition.
  1347. //
  1348. // Note that the *service* must be running before an instance
  1349. // can be continued.
  1350. //
  1351. if( serviceState == SERVICE_RUNNING &&
  1352. currentState == MD_SERVER_STATE_PAUSED ) {
  1353. status = ContinueInstance();
  1354. if( status != NO_ERROR ) {
  1355. DBGPRINTF((
  1356. DBG_CONTEXT,
  1357. "PerformStateChange: cannot continue instance, error %lu\n",
  1358. status
  1359. ));
  1360. }
  1361. } else {
  1362. DBGPRINTF((
  1363. DBG_CONTEXT,
  1364. "PerformStateChange: invalid command %lu for state %lu\n",
  1365. command,
  1366. currentState
  1367. ));
  1368. status = ERROR_INVALID_SERVICE_CONTROL;
  1369. }
  1370. break;
  1371. default :
  1372. DBGPRINTF((
  1373. DBG_CONTEXT,
  1374. "PerformStateChange: invalid command %lu\n",
  1375. command
  1376. ));
  1377. status = ERROR_INVALID_SERVICE_CONTROL;
  1378. break;
  1379. }
  1380. } else {
  1381. DBGPRINTF((
  1382. DBG_CONTEXT,
  1383. "PerformStateChange: cannot read metabase, error %lu\n",
  1384. status
  1385. ));
  1386. }
  1387. //
  1388. // Unlock the instance before trying to reopen the metabase.
  1389. //
  1390. UnlockThis();
  1391. //
  1392. // Restore the state to the previous value if the state change failed.
  1393. //
  1394. if( status != NO_ERROR ) {
  1395. SetServerState( currentState, status );
  1396. }
  1397. return status;
  1398. } // IIS_SERVER_INSTANCE::PerformStateChange
  1399. VOID
  1400. IIS_SERVER_INSTANCE::SetServerState(
  1401. IN DWORD NewState,
  1402. IN DWORD Win32Error
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. Sets the new server state, storing it locally and also storing the
  1407. new state in the metabase.
  1408. Arguments:
  1409. NewState - The new server state.
  1410. Win32Error - New Win32 error value.
  1411. Return Value:
  1412. None.
  1413. --*/
  1414. {
  1415. DWORD status = NO_ERROR;
  1416. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1417. //
  1418. // Open the metabase and save the new state. Note that we map
  1419. // MD_SERVER_STATE_INVALID to MD_SERVER_STATE_STOPPED in the metabase.
  1420. // Client applications would probably be confused by the _INVALID state.
  1421. //
  1422. if( mb.Open(
  1423. QueryMDPath(),
  1424. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) {
  1425. if( !mb.SetDword(
  1426. "",
  1427. MD_WIN32_ERROR,
  1428. IIS_MD_UT_SERVER,
  1429. Win32Error,
  1430. 0
  1431. ) ||
  1432. !mb.SetDword(
  1433. "",
  1434. MD_SERVER_STATE,
  1435. IIS_MD_UT_SERVER,
  1436. NewState == MD_SERVER_STATE_INVALID
  1437. ? MD_SERVER_STATE_STOPPED
  1438. : NewState,
  1439. 0
  1440. ) ) {
  1441. status = GetLastError();
  1442. }
  1443. } else {
  1444. status = GetLastError();
  1445. }
  1446. if( status != NO_ERROR ) {
  1447. DBGPRINTF((
  1448. DBG_CONTEXT,
  1449. "SetServerState: cannot write metabase (%lu), error %lu\n",
  1450. NewState,
  1451. status
  1452. ));
  1453. }
  1454. //
  1455. // Save it in the object also.
  1456. //
  1457. m_dwServerState = NewState;
  1458. } // IIS_SERVER_INSTANCE::SetServerState
  1459. BOOL
  1460. IIS_SERVER_INSTANCE::StopEndpoints( VOID)
  1461. /*++
  1462. Routine Description:
  1463. Walks down the list of Endpoints held by the Server instance and
  1464. calls IIS_ENDPOINT::StopEndpoint for the endpoints.
  1465. Arguments:
  1466. None
  1467. Return Value:
  1468. TRUE if stop is successful,
  1469. FALSE otherwise
  1470. --*/
  1471. {
  1472. BOOL fReturn = TRUE;
  1473. //
  1474. // Inside the locked section walk the normal & secure bindings
  1475. // to stop all relevant endpoints
  1476. //
  1477. LockThisForWrite();
  1478. if (!StopEndpointsHelper( &m_NormalBindingListHead)) {
  1479. fReturn = FALSE;
  1480. }
  1481. if (!StopEndpointsHelper( &m_SecureBindingListHead)) {
  1482. fReturn = FALSE;
  1483. }
  1484. UnlockThis();
  1485. return ( fReturn);
  1486. } // IIS_SERVER_INSTANCE::StopEndpoints()
  1487. BOOL
  1488. IIS_SERVER_INSTANCE::StopEndpointsHelper( PLIST_ENTRY pBindingListHead)
  1489. /*++
  1490. Routine Description:
  1491. Helper routine for StopEndpoints().
  1492. This function should be called with the Endpoints lock held
  1493. Arguments:
  1494. pBindingListHead - pointer to the binding list for endpoints to be stopped
  1495. Return Value:
  1496. BOOL - TRUE on success and FALSE on failure
  1497. --*/
  1498. {
  1499. BOOL fReturn = TRUE;
  1500. PLIST_ENTRY plBindingScan;
  1501. PIIS_SERVER_BINDING binding;
  1502. //
  1503. // Walk the list of bindings and destroy them.
  1504. //
  1505. for( plBindingScan = pBindingListHead->Flink;
  1506. plBindingScan != pBindingListHead;
  1507. plBindingScan = plBindingScan->Flink
  1508. ) {
  1509. binding = CONTAINING_RECORD(
  1510. plBindingScan,
  1511. IIS_SERVER_BINDING,
  1512. m_BindingListEntry
  1513. );
  1514. IF_DEBUG( INSTANCE ) {
  1515. DBGPRINTF((
  1516. DBG_CONTEXT,
  1517. "stop ATQ EP of %p from instance %p, "
  1518. " binding %p (%lx:%d:%s)\n",
  1519. binding->QueryEndpoint(),
  1520. this,
  1521. binding,
  1522. binding->QueryIpAddress(),
  1523. binding->QueryEndpoint()->QueryPort(),
  1524. binding->QueryHostName()
  1525. ));
  1526. }
  1527. if ( !binding->QueryEndpoint()->StopEndpoint()) {
  1528. fReturn = FALSE;
  1529. }
  1530. } // for
  1531. //
  1532. // Success!
  1533. //
  1534. return ( fReturn);
  1535. } // IIS_SERVER_INSTANCE::StopEndpointsHelper()
  1536. BOOL
  1537. IIS_SERVER_INSTANCE::CloseInstance(
  1538. VOID
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. Shuts down instance
  1543. Arguments:
  1544. None
  1545. Return Value:
  1546. TRUE if Shutdown successful,
  1547. FALSE otherwise
  1548. --*/
  1549. {
  1550. IF_DEBUG(INSTANCE) {
  1551. DBGPRINTF((
  1552. DBG_CONTEXT,
  1553. "IIS_SERVER_INSTANCE::Close called for %p\n",
  1554. this
  1555. ));
  1556. }
  1557. (VOID)m_Service->DisassociateInstance( this );
  1558. return TRUE;
  1559. } // IIS_SERVER_INSTANCE::CloseInstance
  1560. DWORD
  1561. IIS_SERVER_INSTANCE::StartInstance()
  1562. /*++
  1563. Routine Description:
  1564. Sets instance to RUNNING
  1565. Arguments:
  1566. None.
  1567. Return Value:
  1568. DWORD - 0 if successful, !0 otherwise.
  1569. --*/
  1570. {
  1571. DWORD status;
  1572. IF_DEBUG(INSTANCE) {
  1573. DBGPRINTF((
  1574. DBG_CONTEXT,
  1575. "IIS_SERVER_INSTANCE::StartInstance called for %p. Current state %d\n",
  1576. this,
  1577. QueryServerState()
  1578. ));
  1579. }
  1580. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_STOPPED );
  1581. //
  1582. // Set the transient state.
  1583. //
  1584. SetServerState( MD_SERVER_STATE_STARTING, NO_ERROR );
  1585. //
  1586. // Set cache parameters
  1587. //
  1588. m_tsCache.SetParameters(
  1589. m_Service->QueryServiceId(),
  1590. QueryInstanceId(),
  1591. this );
  1592. if (( QueryInstanceId() != INET_INSTANCE_ROOT ) && IsDownLevelInstance() )
  1593. {
  1594. MoveMDVroots2Registry();
  1595. // no longer supporting migrating VRoots back from the registry
  1596. //PdcHackVRReg2MD( );
  1597. }
  1598. //
  1599. // Read all common parameters and initialize VDirs
  1600. //
  1601. if ( !RegReadCommonParams( TRUE, TRUE) ) {
  1602. return ERROR_NOT_ENOUGH_MEMORY;
  1603. }
  1604. //
  1605. // Start logging
  1606. //
  1607. m_Logging.ActivateLogging(
  1608. m_Service->QueryServiceName(),
  1609. QueryInstanceId(),
  1610. m_strMDPath.QueryStr(),
  1611. m_Service->QueryMDObject() );
  1612. //
  1613. // Verify the service can handle another instance.
  1614. //
  1615. if( !m_Service->RecordInstanceStart() ) {
  1616. m_Logging.ShutdownLogging();
  1617. QueryVrootTable()->RemoveVirtualRoots();
  1618. return ERROR_NOT_SUPPORTED;
  1619. }
  1620. //
  1621. // Bind the instance.
  1622. //
  1623. status = BindInstance();
  1624. if ( status != NO_ERROR ) {
  1625. m_Logging.ShutdownLogging();
  1626. QueryVrootTable()->RemoveVirtualRoots();
  1627. //
  1628. // Tell the service that we failed to start the instance.
  1629. //
  1630. m_Service->RecordInstanceStop();
  1631. }
  1632. return status;
  1633. } // IIS_SERVER_INSTANCE::StartInstance
  1634. DWORD
  1635. IIS_SERVER_INSTANCE::StopInstance()
  1636. /*++
  1637. Routine Description:
  1638. Sets instance to STOPPED
  1639. Arguments:
  1640. None.
  1641. Return Value:
  1642. DWORD - 0 if successful, !0 otherwise.
  1643. --*/
  1644. {
  1645. DWORD status;
  1646. IF_DEBUG(INSTANCE) {
  1647. DBGPRINTF((
  1648. DBG_CONTEXT,
  1649. "IIS_SERVER_INSTANCE::StopInstance called for %p. Current state %d\n",
  1650. this,
  1651. QueryServerState()
  1652. ));
  1653. }
  1654. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_STARTED ||
  1655. QueryServerState() == MD_SERVER_STATE_PAUSED );
  1656. Reference();
  1657. //
  1658. // Set the transient state.
  1659. //
  1660. SetServerState( MD_SERVER_STATE_STOPPING, NO_ERROR );
  1661. m_Service->StopInstanceProcs( this );
  1662. //
  1663. // Note that we call DisconnectUsersByInstance() before *and* after
  1664. // unbinding the instance. This is to prevent a potential race condition
  1665. // that can occur if another thread is already in IIS_ENDPOINT::
  1666. // FindAndReferenceInstance(), has found the instance, checked its state,
  1667. // and found it to be MD_SERVER_STATE_STARTED. The call to UnbindInstance()
  1668. // will lock any affected endpoints, ensuring that there are no other
  1669. // threads in the midst of a FindAndReferenceInstance(). The second
  1670. // (seemingly redundant) call to DisconnectUsersByInstance() will catch
  1671. // any threads that "snuck in" under these conditions.
  1672. //
  1673. status = m_Service->DisconnectUsersByInstance( this );
  1674. if( status == NO_ERROR ) {
  1675. status = UnbindInstance();
  1676. }
  1677. if( status == NO_ERROR ) {
  1678. status = m_Service->DisconnectUsersByInstance( this );
  1679. }
  1680. if( status == NO_ERROR ) {
  1681. SetServerState( MD_SERVER_STATE_STOPPED, NO_ERROR );
  1682. m_dwSavedState = MD_SERVER_STATE_STOPPED;
  1683. m_Service->RecordInstanceStop();
  1684. }
  1685. //
  1686. // logging cleanup
  1687. //
  1688. DBG_REQUIRE( m_Logging.ShutdownLogging());
  1689. DBG_REQUIRE( QueryVrootTable()->RemoveVirtualRoots());
  1690. Dereference();
  1691. return status;
  1692. } // IIS_SERVER_INSTANCE::StopInstance
  1693. DWORD
  1694. IIS_SERVER_INSTANCE::PauseInstance()
  1695. /*++
  1696. Routine Description:
  1697. Sets instance to PAUSE
  1698. Arguments:
  1699. None.
  1700. Return Value:
  1701. DWORD - 0 if successful, !0 otherwise.
  1702. --*/
  1703. {
  1704. IF_DEBUG(INSTANCE) {
  1705. DBGPRINTF((
  1706. DBG_CONTEXT,
  1707. "IIS_SERVER_INSTANCE::Pause called for %p. Current state %d\n",
  1708. this,
  1709. QueryServerState()
  1710. ));
  1711. }
  1712. //
  1713. // Just set the paused state (no need for a transient state).
  1714. // Setting the instance to paused will prevent new incoming
  1715. // connections on the instance.
  1716. //
  1717. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_STARTED );
  1718. SetServerState( MD_SERVER_STATE_PAUSED, NO_ERROR );
  1719. //
  1720. // Success!
  1721. //
  1722. return NO_ERROR;
  1723. } // IIS_SERVER_INSTANCE::PauseInstance
  1724. DWORD
  1725. IIS_SERVER_INSTANCE::ContinueInstance()
  1726. /*++
  1727. Routine Description:
  1728. Sets instance to STARTED.
  1729. Arguments:
  1730. None.
  1731. Return Value:
  1732. DWORD - 0 if successful, !0 otherwise.
  1733. --*/
  1734. {
  1735. IF_DEBUG(INSTANCE) {
  1736. DBGPRINTF((
  1737. DBG_CONTEXT,
  1738. "IIS_SERVER_INSTANCE::Continue called for %p. Current state %d\n",
  1739. this,
  1740. QueryServerState()
  1741. ));
  1742. }
  1743. //
  1744. // Just set the stated state (no need for a transient state).
  1745. // Setting the instance to started will allow new incoming
  1746. // connections on the instance.
  1747. //
  1748. DBG_ASSERT( QueryServerState() == MD_SERVER_STATE_PAUSED );
  1749. SetServerState( MD_SERVER_STATE_STARTED, NO_ERROR );
  1750. //
  1751. // Success!
  1752. //
  1753. return NO_ERROR;
  1754. } // IIS_SERVER_INSTANCE::ContinueInstance
  1755. VOID
  1756. IIS_SERVER_INSTANCE::SetWin32Error(
  1757. DWORD err
  1758. )
  1759. {
  1760. MB mb( (IMDCOM *)m_Service->QueryMDObject() );
  1761. DWORD status = NO_ERROR;
  1762. //
  1763. // Open the metabase and save the error code.
  1764. //
  1765. if( mb.Open(
  1766. QueryMDPath(),
  1767. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) {
  1768. if( !mb.SetDword(
  1769. "",
  1770. MD_WIN32_ERROR,
  1771. IIS_MD_UT_SERVER,
  1772. err,
  1773. 0
  1774. ) ) {
  1775. status = GetLastError();
  1776. }
  1777. } else {
  1778. status = GetLastError();
  1779. }
  1780. if( status != NO_ERROR ) {
  1781. DBGPRINTF((
  1782. DBG_CONTEXT,
  1783. "SetWin32Error: cannot save error %lu (%lx), error %lx\n",
  1784. err,
  1785. err,
  1786. status
  1787. ));
  1788. }
  1789. } // IIS_SERVER_INSTANCE::SetWin32Error
  1790. BOOL
  1791. IIS_SERVER_INSTANCE::SetBandwidthThrottle(
  1792. IN MB * pMB
  1793. )
  1794. /*++
  1795. Routine Description:
  1796. Set the bandwidth throttle threshold for this instance
  1797. Arguments:
  1798. pMB - pointer to metabase handle
  1799. Return Value:
  1800. TRUE if successful, FALSE otherwise
  1801. --*/
  1802. {
  1803. DWORD dwBandwidth;
  1804. if ( !TsIsNtServer() )
  1805. {
  1806. return TRUE;
  1807. }
  1808. DBG_ASSERT( pMB != NULL );
  1809. if ( !pMB->GetDword( "",
  1810. MD_MAX_BANDWIDTH,
  1811. IIS_MD_UT_SERVER,
  1812. &dwBandwidth,
  1813. 0 ) )
  1814. {
  1815. VOID * pTemp;
  1816. pTemp = InterlockedExchangePointer( (PVOID *) &m_pBandwidthInfo, NULL );
  1817. if ( pTemp )
  1818. {
  1819. DBG_REQUIRE( AtqFreeBandwidthInfo( pTemp ) );
  1820. }
  1821. }
  1822. else
  1823. {
  1824. if ( m_pBandwidthInfo == NULL )
  1825. {
  1826. VOID * pTemp = AtqCreateBandwidthInfo();
  1827. if ( pTemp != NULL )
  1828. {
  1829. AtqBandwidthSetInfo( pTemp,
  1830. ATQ_BW_BANDWIDTH_LEVEL,
  1831. dwBandwidth );
  1832. AtqBandwidthSetInfo( pTemp,
  1833. ATQ_BW_DESCRIPTION,
  1834. (ULONG_PTR) m_strMDPath.QueryStr() );
  1835. InterlockedExchangePointer( (PVOID *) &m_pBandwidthInfo, (PVOID) pTemp );
  1836. }
  1837. }
  1838. else
  1839. {
  1840. AtqBandwidthSetInfo( m_pBandwidthInfo,
  1841. ATQ_BW_BANDWIDTH_LEVEL,
  1842. (ULONG_PTR)dwBandwidth );
  1843. }
  1844. }
  1845. return TRUE;
  1846. }
  1847. BOOL
  1848. IIS_SERVER_INSTANCE::SetBandwidthThrottleMaxBlocked(
  1849. IN MB * pMB
  1850. )
  1851. {
  1852. DWORD dwMaxBlocked = INFINITE;
  1853. if ( !TsIsNtServer() )
  1854. {
  1855. return TRUE;
  1856. }
  1857. DBG_ASSERT( pMB != NULL );
  1858. if ( pMB->GetDword( "",
  1859. MD_MAX_BANDWIDTH_BLOCKED,
  1860. IIS_MD_UT_SERVER,
  1861. &dwMaxBlocked,
  1862. 0 ) )
  1863. {
  1864. if ( m_pBandwidthInfo )
  1865. {
  1866. AtqBandwidthSetInfo( m_pBandwidthInfo,
  1867. ATQ_BW_MAX_BLOCKED,
  1868. dwMaxBlocked );
  1869. }
  1870. }
  1871. return TRUE;
  1872. }
  1873. DWORD
  1874. IIS_SERVER_INSTANCE::DoStartInstance(
  1875. VOID
  1876. )
  1877. /*++
  1878. Routine Description:
  1879. Start an instance. This call encompasses the IIS_SERVER_INSTANCE and
  1880. inherited invocations of StartInstance
  1881. Arguments:
  1882. None.
  1883. Return Value:
  1884. DWORD - 0 if successful, !0 otherwise.
  1885. --*/
  1886. {
  1887. DWORD dwError;
  1888. dwError = StartInstance();
  1889. if ( dwError == NO_ERROR )
  1890. {
  1891. if( m_Service->QueryCurrentServiceState() == SERVICE_PAUSED )
  1892. {
  1893. SetServerState( MD_SERVER_STATE_PAUSED, NO_ERROR );
  1894. }
  1895. else
  1896. {
  1897. SetServerState( MD_SERVER_STATE_STARTED, NO_ERROR );
  1898. }
  1899. }
  1900. return dwError;
  1901. }