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.

1389 lines
29 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. iisendp.cxx
  5. Abstract:
  6. This module defines the IIS_ENDPOINT class
  7. Author:
  8. Johnson Apacible (JohnsonA) June-04-1996
  9. --*/
  10. #include "tcpdllp.hxx"
  11. #include <rpc.h>
  12. #include <tsunami.hxx>
  13. #include <iistypes.hxx>
  14. #include <iisendp.hxx>
  15. #include <iisassoc.hxx>
  16. #include "inetreg.h"
  17. #include <tcpcons.h>
  18. #include <apiutil.h>
  19. #include <issched.hxx>
  20. #include "..\atq\atqtypes.hxx"
  21. #if IE_REF_TRACKING
  22. //
  23. // Ref count trace log size
  24. //
  25. #define C_IIS_ENDP_REFTRACES 4000
  26. #define C_LOCAL_ENDP_REFTRACES 40
  27. //
  28. // Ref trace log for IIS_ENDPOINT objects
  29. // NOTE we make this global so other classes can get at it
  30. //
  31. PTRACE_LOG g_pDbgIERefTraceLog = NULL;
  32. #endif
  33. /*******************************************************************
  34. Macro support for IIS_ENDPOINT::Reference/Dereference
  35. HISTORY:
  36. MCourage 31-Oct-1997 Added ref trace logging
  37. ********************************************************************/
  38. #if IE_REF_TRACKING
  39. #define IE_LOG_REF_COUNT( cRefs ) \
  40. \
  41. IE_SHARED_LOG_REF_COUNT( \
  42. cRefs \
  43. , (PVOID) this \
  44. , m_state \
  45. , m_atqEndpoint \
  46. , 0xffffffff \
  47. ); \
  48. IE_LOCAL_LOG_REF_COUNT( \
  49. cRefs \
  50. , (PVOID) this \
  51. , m_state \
  52. , m_atqEndpoint \
  53. , 0xffffffff \
  54. );
  55. #else
  56. #define IE_LOG_REF_COUNT( cRefs )
  57. #endif
  58. PVOID
  59. I_IISAddListenEndpoint(
  60. IN PATQ_ENDPOINT_CONFIGURATION Configuration,
  61. IN PVOID EndpointContext
  62. );
  63. BOOL
  64. IIS_SERVICE::AssociateInstance(
  65. IN PIIS_SERVER_INSTANCE pInstance
  66. )
  67. /*++
  68. Routine Description:
  69. Associates an instance with an endpoint. It also activates the endpoint.
  70. Arguments:
  71. pInstance - instance to associate.
  72. Return Value:
  73. TRUE - if successful, FALSE otherwise
  74. --*/
  75. {
  76. DWORD err = NO_ERROR;
  77. BOOL shouldStart = FALSE;
  78. IF_DEBUG(ENDPOINT) {
  79. DBGPRINTF((DBG_CONTEXT,
  80. "AssociateInstance %p called\n",
  81. pInstance));
  82. }
  83. //
  84. // Lock the service.
  85. //
  86. AcquireServiceLock( TRUE );
  87. //
  88. // if service is closing, abort
  89. //
  90. if ( !IsActive() ) {
  91. err = ERROR_NOT_READY;
  92. goto exit;
  93. }
  94. if ( pInstance->QueryServerState( ) != MD_SERVER_STATE_STOPPED ) {
  95. IF_DEBUG(ENDPOINT) {
  96. DBGPRINTF((DBG_CONTEXT,"Server not in stopped (%d) state\n",
  97. pInstance->QueryServerState()));
  98. }
  99. err = ERROR_INVALID_FUNCTION;
  100. goto exit;
  101. }
  102. //
  103. // Start the server instance.
  104. //
  105. shouldStart = TRUE;
  106. err = pInstance->DoStartInstance();
  107. if( err != NO_ERROR ) {
  108. IF_DEBUG(ENDPOINT) {
  109. DBGPRINTF((DBG_CONTEXT, "BindInstance() failed, %lu\n", err));
  110. }
  111. }
  112. exit:
  113. if( shouldStart ) {
  114. //
  115. // We're up and running. Note that the StartInstance() method will
  116. // set the instance state appropriately if successful, so we only
  117. // need to set it if the start failed.
  118. //
  119. if( err != NO_ERROR ) {
  120. pInstance->SetServerState( MD_SERVER_STATE_STOPPED, err );
  121. }
  122. ReleaseServiceLock( TRUE );
  123. return TRUE;
  124. } else {
  125. IF_DEBUG(ENDPOINT) {
  126. DBGPRINTF((DBG_CONTEXT,"AssociateInstace: Error %d\n",
  127. err));
  128. }
  129. pInstance->SetServerState( MD_SERVER_STATE_STOPPED, err );
  130. ReleaseServiceLock( TRUE );
  131. SetLastError(err);
  132. return FALSE;
  133. }
  134. } // IIS_SERVICE::AssociateInstance
  135. BOOL
  136. IIS_SERVICE::DisassociateInstance(
  137. IN PIIS_SERVER_INSTANCE pInstance
  138. )
  139. /*++
  140. Routine Description:
  141. Removes an instance from an endpoint.
  142. Arguments:
  143. pInstance - instance to associate.
  144. Return Value:
  145. TRUE - if successful, FALSE otherwise
  146. --*/
  147. {
  148. //
  149. // if it's running, stop it
  150. //
  151. AcquireServiceLock( TRUE );
  152. if ( pInstance->QueryServerState( ) == MD_SERVER_STATE_STOPPED ) {
  153. ReleaseServiceLock( TRUE );
  154. IF_DEBUG(ENDPOINT) {
  155. DBGPRINTF((DBG_CONTEXT,
  156. "Cannot disassociate stopped server %p\n",pInstance));
  157. }
  158. return(TRUE);
  159. }
  160. pInstance->SetServerState( MD_SERVER_STATE_STOPPED, NO_ERROR );
  161. ReleaseServiceLock( TRUE );
  162. //
  163. // Blow away any users still clinging to this instance,
  164. // then unbind the instance.
  165. //
  166. pInstance->Reference();
  167. DisconnectUsersByInstance( pInstance );
  168. pInstance->UnbindInstance();
  169. pInstance->Dereference();
  170. return TRUE;
  171. } // IIS_SERVICE::DisassociateInstance
  172. BOOL
  173. IIS_SERVICE::ShutdownService(
  174. VOID
  175. )
  176. /*++
  177. Routine Description:
  178. Shuts down all endpoints.
  179. Arguments:
  180. None.
  181. Return Value:
  182. TRUE if successful, FALSE otherwise.
  183. --*/
  184. {
  185. //
  186. // Walk the list and close the instances
  187. //
  188. IF_DEBUG(ENDPOINT) {
  189. DBGPRINTF((DBG_CONTEXT, "ShutdownService called\n"));
  190. }
  191. //
  192. // Update the service state.
  193. //
  194. AcquireServiceLock( );
  195. m_state = BlockStateClosed;
  196. ReleaseServiceLock( );
  197. //
  198. // Blow away all instances.
  199. //
  200. DestroyAllServerInstances();
  201. return TRUE;
  202. } // IIS_SERVICE::ShutdownService
  203. IIS_ENDPOINT::IIS_ENDPOINT(
  204. IN PIIS_SERVICE pService,
  205. IN USHORT Port,
  206. IN DWORD IpAddress,
  207. IN BOOL fIsSecure
  208. )
  209. :
  210. m_signature ( IIS_ENDPOINT_SIGNATURE),
  211. m_state ( BlockStateIdle),
  212. m_atqEndpoint ( NULL),
  213. m_isSecure ( fIsSecure),
  214. m_fAtqEpStopped ( FALSE),
  215. m_service ( NULL),
  216. m_reference ( 1),
  217. m_NumQualifiedInstances ( 0),
  218. m_WildcardInstance ( NULL),
  219. m_nAcceptExOutstanding ( 0),
  220. m_AcceptExTimeout ( 0),
  221. m_nInstances ( 0)
  222. {
  223. //
  224. // initialize the lock
  225. //
  226. INITIALIZE_CRITICAL_SECTION(&m_endpointLock);
  227. //
  228. // initialize the association info
  229. //
  230. ZeroMemory(
  231. m_QualifiedInstances,
  232. sizeof(m_QualifiedInstances)
  233. );
  234. //
  235. // reference the service
  236. //
  237. if ( !pService->CheckAndReference( ) ) {
  238. m_state = BlockStateInvalid;
  239. return;
  240. }
  241. m_service = pService;
  242. //
  243. // use the service name as the advertised name
  244. //
  245. m_Port = Port;
  246. m_IpAddress = IpAddress;
  247. #if IE_REF_TRACKING
  248. _pDbgIERefTraceLog = CreateRefTraceLog( C_LOCAL_ENDP_REFTRACES, 0 );
  249. #endif
  250. } // IIS_ENDPOINT::IIS_ENDPOINT
  251. IIS_ENDPOINT::~IIS_ENDPOINT(
  252. VOID
  253. )
  254. {
  255. IF_DEBUG(ENDPOINT) {
  256. DBGPRINTF((DBG_CONTEXT,"IIS Endpoint %p freed\n",this));
  257. }
  258. DBG_ASSERT( m_signature == IIS_ENDPOINT_SIGNATURE );
  259. //
  260. // Delete the instance association objects.
  261. //
  262. for( INT qualifier = (INT)FullyQualified ;
  263. qualifier < (INT)NumInstanceQualifiers ;
  264. qualifier++ ) {
  265. delete m_QualifiedInstances[qualifier];
  266. }
  267. //
  268. // Dereference the owning service.
  269. //
  270. if ( m_service != NULL ) {
  271. m_service->Dereference();
  272. m_service = NULL;
  273. }
  274. m_signature = IIS_ENDPOINT_SIGNATURE_FREE;
  275. DeleteCriticalSection(&m_endpointLock);
  276. #if IE_REF_TRACKING
  277. DestroyRefTraceLog( _pDbgIERefTraceLog );
  278. #endif
  279. } // IIS_ENDPOINT::~IIS_ENDPOINT
  280. BOOL
  281. IIS_ENDPOINT::AddInstance(
  282. IN PIIS_SERVER_INSTANCE pInstance,
  283. IN DWORD IpAddress,
  284. IN const CHAR * HostName
  285. )
  286. /*++
  287. Routine Description:
  288. Adds an instance to an existing endpoint.
  289. Arguments:
  290. pInstance - instance to add.
  291. IpAddress - The IP address for this instance; may be INADDR_ANY;.
  292. HostName - The host name for this instance; may be empty ("").
  293. Return Value:
  294. TRUE - if successful, FALSE otherwise
  295. --*/
  296. {
  297. INSTANCE_QUALIFIER qualifier;
  298. DWORD status;
  299. IF_DEBUG(ENDPOINT) {
  300. DBGPRINTF((DBG_CONTEXT,
  301. "IIS_ENDPOINT::AddInstance %p called\n", pInstance));
  302. }
  303. //
  304. // Determine the proper qualifier based on the presence of the
  305. // IP address and host name.
  306. //
  307. qualifier = CalcQualifier( IpAddress, HostName );
  308. LockEndpoint();
  309. //
  310. // Put instance into proper association.
  311. //
  312. if( qualifier == WildcardInstance ) {
  313. if( m_WildcardInstance == NULL ) {
  314. m_WildcardInstance = pInstance;
  315. } else {
  316. DBGPRINTF((
  317. DBG_CONTEXT,
  318. "AddInstance: endpoint %p already has a wildcard instance\n",
  319. this
  320. ));
  321. status = ERROR_INVALID_PARAMETER;
  322. goto unlock_and_fail;
  323. }
  324. } else {
  325. PIIS_ASSOCIATION association;
  326. //
  327. // Create a new instance association object if necessary.
  328. //
  329. association = m_QualifiedInstances[qualifier];
  330. if( association == NULL ) {
  331. association = new IIS_ASSOCIATION(
  332. ( qualifier == FullyQualified ) ||
  333. ( qualifier == QualifiedByIpAddress ),
  334. ( qualifier == FullyQualified ) ||
  335. ( qualifier == QualifiedByHostName )
  336. );
  337. if( association == NULL ) {
  338. DBGPRINTF((
  339. DBG_CONTEXT,
  340. "AddInstance: cannot create new association\n"
  341. ));
  342. status = ERROR_NOT_ENOUGH_MEMORY;
  343. goto unlock_and_fail;
  344. }
  345. m_QualifiedInstances[qualifier] = association;
  346. }
  347. //
  348. // Add the instance to the association.
  349. //
  350. status = association->AddDescriptor(
  351. IpAddress,
  352. HostName,
  353. (LPVOID)pInstance
  354. );
  355. if( status != NO_ERROR ) {
  356. goto unlock_and_fail;
  357. }
  358. //
  359. // Update the number of qualified instances on this endpoint.
  360. // We use this to "short circuit" the instance lookup in the
  361. // common case of a single wildcard instance per endpoint.
  362. //
  363. m_NumQualifiedInstances++;
  364. }
  365. //
  366. // Setup the necessary references, update the server state.
  367. //
  368. Reference();
  369. pInstance->Reference();
  370. InterlockedIncrement( (LPLONG)&m_nInstances );
  371. //
  372. // Aggregate the AcceptEx outstanding parameter.
  373. //
  374. m_nAcceptExOutstanding += pInstance->QueryAcceptExOutstanding();
  375. m_nMaximumAcceptExOutstanding = pInstance->QueryMaxEndpointConnections();
  376. //
  377. // Activate the endpoint if necessary.
  378. //
  379. if ( !ActivateEndpoint() ) {
  380. status = GetLastError();
  381. RemoveInstance( pInstance, IpAddress, HostName );
  382. goto unlock_and_fail;
  383. }
  384. UnlockEndpoint();
  385. return TRUE;
  386. unlock_and_fail:
  387. DBG_ASSERT( status != NO_ERROR );
  388. UnlockEndpoint();
  389. SetLastError( status );
  390. return FALSE;
  391. } // IIS_ENDPOINT::AddInstance
  392. BOOL
  393. IIS_ENDPOINT::RemoveInstance(
  394. IN PIIS_SERVER_INSTANCE pInstance,
  395. IN DWORD IpAddress,
  396. IN const CHAR * HostName
  397. )
  398. /*++
  399. Routine Description:
  400. Removes an instance to an existing endpoint.
  401. Arguments:
  402. pInstance - instance to remove
  403. IpAddress - The IP address for this instance; may be INADDR_ANY;.
  404. HostName - The host name for this instance; may be empty ("").
  405. Return Value:
  406. TRUE - if successful, FALSE otherwise
  407. --*/
  408. {
  409. INSTANCE_QUALIFIER qualifier;
  410. DWORD status;
  411. IF_DEBUG(ENDPOINT) {
  412. DBGPRINTF((DBG_CONTEXT,
  413. "RemoveInstance called endpoint %p instance %p\n",
  414. this, pInstance ));
  415. }
  416. DBG_ASSERT( m_signature == IIS_ENDPOINT_SIGNATURE );
  417. //
  418. // Determine the proper qualifier based on the presence of the
  419. // IP address and host name.
  420. //
  421. qualifier = CalcQualifier( IpAddress, HostName );
  422. LockEndpoint();
  423. m_nAcceptExOutstanding -= pInstance->QueryAcceptExOutstanding();
  424. if( qualifier == WildcardInstance ) {
  425. DBG_ASSERT( m_WildcardInstance == pInstance );
  426. m_WildcardInstance->Dereference();
  427. m_WildcardInstance = NULL;
  428. } else {
  429. LPVOID Context;
  430. DBG_ASSERT( m_QualifiedInstances[qualifier] != NULL );
  431. status = m_QualifiedInstances[qualifier]->RemoveDescriptor(
  432. IpAddress,
  433. HostName,
  434. &Context
  435. );
  436. if( status == NO_ERROR ) {
  437. DBG_ASSERT( Context == (LPVOID)pInstance );
  438. pInstance->Dereference();
  439. m_NumQualifiedInstances--;
  440. }
  441. }
  442. UnlockEndpoint();
  443. //
  444. // If this was the last instance, then remove ourselves from
  445. // the service's endpoint list and initiate shutdown.
  446. //
  447. if ( InterlockedDecrement( (LPLONG ) &m_nInstances) == 0 ) {
  448. RemoveEntryList( &m_EndpointListEntry );
  449. ShutdownEndpoint( );
  450. }
  451. //
  452. // Remove the reference added in AddInstance().
  453. //
  454. Dereference();
  455. return TRUE;
  456. } // IIS_ENDPOINT::RemoveInstance
  457. BOOL
  458. IIS_ENDPOINT::ActivateEndpoint(
  459. VOID
  460. )
  461. /*++
  462. Routine Description:
  463. Starts an idle endpoint.
  464. Arguments:
  465. None.
  466. Return Value:
  467. TRUE - if successful, FALSE otherwise
  468. --*/
  469. {
  470. PVOID atqEndpoint = NULL;
  471. ATQ_ENDPOINT_CONFIGURATION config;
  472. //
  473. // Make sure this is idle
  474. //
  475. IF_DEBUG(ENDPOINT) {
  476. DBGPRINTF((DBG_CONTEXT,"Calling activate on %p\n",this));
  477. }
  478. LockEndpoint( );
  479. if ( m_state == BlockStateActive ) {
  480. IF_DEBUG(ENDPOINT) {
  481. DBGPRINTF(( DBG_CONTEXT,
  482. "Activate called on %p is not in idle state(%d)\n",
  483. this, (DWORD)m_state ));
  484. }
  485. DBG_ASSERT(m_atqEndpoint != NULL);
  486. AtqEndpointSetInfo(
  487. m_atqEndpoint,
  488. EndpointInfoAcceptExOutstanding,
  489. min(
  490. m_nAcceptExOutstanding,
  491. m_nMaximumAcceptExOutstanding
  492. )
  493. );
  494. UnlockEndpoint();
  495. return(TRUE);
  496. }
  497. config.cbAcceptExRecvBuffer = m_service->m_cbRecvBuffer;
  498. config.pfnConnect = m_service->m_pfnConnect;
  499. config.pfnConnectEx = m_service->m_pfnConnectEx;
  500. config.pfnIoCompletion = m_service->m_pfnIoCompletion;
  501. config.ListenPort = m_Port;
  502. config.IpAddress = m_IpAddress;
  503. config.nAcceptExOutstanding = min( m_nAcceptExOutstanding,
  504. m_nMaximumAcceptExOutstanding );
  505. config.AcceptExTimeout = m_AcceptExTimeout;
  506. IF_DEBUG(ENDPOINT) {
  507. DBGPRINTF((DBG_CONTEXT,"%d %d %d\n",
  508. config.ListenPort,
  509. config.nAcceptExOutstanding, config.AcceptExTimeout ));
  510. }
  511. atqEndpoint = I_IISAddListenEndpoint(
  512. &config,
  513. (PVOID)this
  514. );
  515. if ( atqEndpoint == NULL ) {
  516. UnlockEndpoint();
  517. DBGPRINTF(( DBG_CONTEXT,
  518. "Activate failed, error %d\n",GetLastError()));
  519. return(FALSE);
  520. }
  521. //
  522. // Update the state
  523. //
  524. m_state = BlockStateActive;
  525. m_atqEndpoint = atqEndpoint;
  526. Reference( );
  527. UnlockEndpoint();
  528. return(TRUE);
  529. } // IIS_ENDPOINT::ActivateEndpoint
  530. BOOL
  531. IIS_ENDPOINT::StopEndpoint( VOID)
  532. /*++
  533. Routine Description:
  534. Stops the ATQ endpoint structure stored inside the IIS_ENDPOINT
  535. This will prevent us from accepting new connection. This function
  536. should be called only when are preparing ourselves to shut this
  537. endpoint down entirely.
  538. Arguments:
  539. None.
  540. Return Value:
  541. None.
  542. History:
  543. MuraliK 7/8/97
  544. --*/
  545. {
  546. BOOL fReturn = TRUE;
  547. //
  548. // lock, check the state and
  549. // then, stop any Atq Endpoint, if any.
  550. //
  551. LockEndpoint( );
  552. //
  553. // NYI: We mayhave to use an intermediate state for STopped endpoint.
  554. // Unfortunately the state machine usage in IIS_SERVICE/INSTANCE/ENDPOINT
  555. // is not setup for doing so. For now I will just assert that this
  556. // object is in an Active State
  557. // - muralik 7/8/97
  558. //
  559. DBG_ASSERT( m_state == BlockStateActive);
  560. if ( m_atqEndpoint != NULL ) {
  561. IF_DEBUG(ENDPOINT) {
  562. DBGPRINTF((DBG_CONTEXT,
  563. "IIS_ENDPOINT(%08p) Stopping ATQ Endpoint %p\n",
  564. this, m_atqEndpoint));
  565. }
  566. if ( !m_fAtqEpStopped ) {
  567. fReturn = AtqStopEndpoint( m_atqEndpoint);
  568. if ( fReturn ) {
  569. m_fAtqEpStopped = TRUE;
  570. }
  571. }
  572. }
  573. UnlockEndpoint();
  574. return (fReturn);
  575. } // IIS_ENDPOINT::StopEndpoint()
  576. VOID
  577. IIS_ENDPOINT::ShutdownEndpoint(
  578. VOID
  579. )
  580. /*++
  581. Routine Description:
  582. Shuts down an endpoint.
  583. Arguments:
  584. None.
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. //
  590. // lock, check the state and mark it closed.
  591. // then, shutdown any Atq Endpoint, if any.
  592. //
  593. LockEndpoint( );
  594. DBG_ASSERT(m_nInstances == 0);
  595. if ( m_state == BlockStateActive ) {
  596. IF_DEBUG(ENDPOINT) {
  597. DBGPRINTF((DBG_CONTEXT,"Shutting down endpoint %p\n",this));
  598. }
  599. m_state = BlockStateClosed;
  600. UnlockEndpoint();
  601. IF_DEBUG( INSTANCE ) {
  602. DBGPRINTF(( DBG_CONTEXT,
  603. "IIS_ENDPOINT(%08p)::ShutdownEndpoint() for "
  604. " AtqEndpoint %08p\n",
  605. this, m_atqEndpoint ));
  606. }
  607. if ( m_atqEndpoint != NULL ) {
  608. // I replaced AtqStopAndCloseEndpoint() here
  609. if ( !m_fAtqEpStopped ) {
  610. DBG_REQUIRE( AtqStopEndpoint( m_atqEndpoint));
  611. m_fAtqEpStopped = TRUE;
  612. }
  613. /*
  614. * Moved this to IIS_ENDPOINT::Dereference for shutdown thread hack
  615. *
  616. AtqCloseEndpoint( m_atqEndpoint);
  617. m_atqEndpoint = NULL;
  618. */
  619. }
  620. Dereference( );
  621. } else {
  622. UnlockEndpoint();
  623. }
  624. return;
  625. } // IIS_ENDPOINT::ShutdownEndpoint
  626. PIIS_SERVER_INSTANCE
  627. IIS_ENDPOINT::FindAndReferenceInstance(
  628. IN LPCSTR pszDomainName,
  629. IN const DWORD IPAddress,
  630. OUT LPBOOL pbMaxConnExceeded
  631. )
  632. /*++
  633. Routine Description:
  634. Finds the appropriate instance given domain name and
  635. socket information. The instance is referenced if found.
  636. Arguments:
  637. pszDomainName - Domain name of request.
  638. IPAddress - Local IP Address of the connection.
  639. pbMaxConnExceeded - Receives TRUE if the maximum number of connections
  640. for this endpoint has been exceeded. It is still the caller's
  641. responsibility to properly dispose of the instance.
  642. Return Value:
  643. if successful, returns the pointer to the instance.
  644. NULL, otherwise.
  645. --*/
  646. {
  647. PIIS_SERVER_INSTANCE instance;
  648. DWORD status;
  649. INT qualifier;
  650. IIS_ASSOCIATION::HASH_CONTEXT context;
  651. IF_DEBUG(ENDPOINT) {
  652. LPCSTR tmp = pszDomainName;
  653. if ( tmp == NULL ) {
  654. tmp = "";
  655. }
  656. DBGPRINTF((DBG_CONTEXT,"Finding %s %x\n", tmp, IPAddress));
  657. }
  658. LockEndpoint( );
  659. DBG_CODE( instance = NULL );
  660. if( m_NumQualifiedInstances == 0 ) {
  661. //
  662. // Fast path: only the wildcard instance.
  663. //
  664. instance = m_WildcardInstance;
  665. status = NO_ERROR;
  666. } else {
  667. //
  668. // Less-fast path: we'll need to go hunt for it.
  669. //
  670. if( pszDomainName == NULL ) {
  671. pszDomainName = "";
  672. }
  673. IIS_ASSOCIATION::InitializeHashContext( &context );
  674. for( qualifier = FullyQualified ;
  675. qualifier < NumInstanceQualifiers ;
  676. qualifier++ ) {
  677. if( m_QualifiedInstances[qualifier] != NULL ) {
  678. status = m_QualifiedInstances[qualifier]->LookupDescriptor(
  679. IPAddress,
  680. pszDomainName,
  681. (LPVOID *)&instance,
  682. &context
  683. );
  684. if( status == NO_ERROR ) {
  685. goto FoundInstance;
  686. }
  687. DBG_ASSERT( instance == NULL );
  688. }
  689. }
  690. //
  691. // If we made it this far, then no qualified instances will
  692. // take the request, so use the wildcard (if available).
  693. //
  694. instance = m_WildcardInstance;
  695. //
  696. // Reset the status so that we may continue.
  697. //
  698. status = NO_ERROR;
  699. }
  700. if( instance == NULL ) {
  701. status = ERROR_BAD_NET_NAME;
  702. }
  703. FoundInstance:
  704. if( status == NO_ERROR ) {
  705. DBG_ASSERT( instance != NULL );
  706. if( instance->QueryServerState() != MD_SERVER_STATE_STARTED ) {
  707. status = ERROR_FILE_NOT_FOUND;
  708. }
  709. }
  710. if( status == NO_ERROR ) {
  711. //
  712. // Reference this
  713. //
  714. instance->Reference( );
  715. UnlockEndpoint( );
  716. //
  717. // Make sure that we have not exceeded the max
  718. //
  719. instance->IncrementCurrentConnections();
  720. *pbMaxConnExceeded = ( instance->QueryCurrentConnections() >
  721. instance->QueryMaxConnections() );
  722. if( *pbMaxConnExceeded ) {
  723. IF_DEBUG(ERROR) {
  724. DBGPRINTF((DBG_CONTEXT,
  725. "Too many connected users (%d) max %d, refusing connection\n",
  726. instance->QueryCurrentConnections(),
  727. instance->QueryMaxConnections() ));
  728. }
  729. }
  730. IF_DEBUG(ENDPOINT) {
  731. DBGPRINTF((DBG_CONTEXT,
  732. "Found and referenced instance %p\n",instance));
  733. }
  734. return instance;
  735. }
  736. UnlockEndpoint();
  737. SetLastError( status );
  738. return NULL;
  739. } // IIS_ENDPOINT::FindInstance
  740. PVOID
  741. I_IISAddListenEndpoint(
  742. IN PATQ_ENDPOINT_CONFIGURATION Configuration,
  743. IN PVOID EndpointContext
  744. )
  745. /*++
  746. Description:
  747. Adds a TCPIP ATQ endpoint.
  748. Arguments:
  749. Configuration - contains the endpoint configuration
  750. EndpointContext - context to return during completion
  751. Returns:
  752. TRUE if successful,
  753. FALSE, otherwise
  754. --*/
  755. {
  756. PVOID atqEndpoint;
  757. BOOL fReturn = FALSE;
  758. IF_DEBUG( INSTANCE ) {
  759. DBGPRINTF(( DBG_CONTEXT, "I_IISAddListenEndpoint called\n"));
  760. }
  761. //
  762. // Create the endpoint
  763. //
  764. atqEndpoint = AtqCreateEndpoint(
  765. Configuration,
  766. EndpointContext
  767. );
  768. if ( atqEndpoint == NULL ) {
  769. goto error_exit;
  770. }
  771. //
  772. // Activate the endpoint
  773. //
  774. if ( !AtqStartEndpoint(atqEndpoint) ) {
  775. goto error_exit;
  776. }
  777. return (atqEndpoint);
  778. error_exit:
  779. DWORD dwError = GetLastError();
  780. DBG_ASSERT( NO_ERROR != dwError );
  781. if ( atqEndpoint != NULL ) {
  782. AtqCloseEndpoint( atqEndpoint);
  783. atqEndpoint = NULL;
  784. }
  785. SetLastError(dwError);
  786. return(NULL);
  787. } // I_IISAddListenEndpoint()
  788. VOID
  789. IIS_ENDPOINT::Reference( VOID )
  790. /*++
  791. Routine Description:
  792. Increments the reference count for the endpoint
  793. Arguments:
  794. None
  795. Return Value:
  796. None
  797. --*/
  798. {
  799. InterlockedIncrement( &m_reference );
  800. IE_LOG_REF_COUNT( m_reference );
  801. }
  802. typedef struct _ENDPOINT_HACK_PARAM {
  803. PIIS_ENDPOINT piisEndpoint;
  804. PVOID patqEndpoint;
  805. } ENDPOINT_HACK_PARAM, *PENDPOINT_HACK_PARAM;
  806. VOID
  807. WINAPI
  808. EndpointHackFunc( PVOID pv );
  809. VOID
  810. IIS_ENDPOINT::Dereference( )
  811. /*++
  812. Routine Description:
  813. Decrements the reference count for the endpoint and cleans up if the refcount
  814. reaches zero.
  815. Arguments:
  816. None
  817. Return Value:
  818. None
  819. --*/
  820. {
  821. ASSERT( m_signature == IIS_ENDPOINT_SIGNATURE );
  822. ASSERT( m_reference > 0 );
  823. //
  824. // Write the trace log BEFORE the decrement operation :(
  825. // If we write it after the decrement, we will run into potential
  826. // race conditions in this object getting freed up accidentally
  827. // by another thread
  828. //
  829. // NOTE we write (_cRef - 1) == ref count AFTER decrement happens
  830. //
  831. LONG cRefsAfter = (m_reference - 1);
  832. IE_LOG_REF_COUNT( cRefsAfter );
  833. if ( InterlockedDecrement( &m_reference ) == 0 ) {
  834. DWORD dwCookie;
  835. PENDPOINT_HACK_PARAM pParam;
  836. DBGPRINTF((DBG_CONTEXT,"deleting endpoint %p\n",this));
  837. if ( m_atqEndpoint != NULL ) {
  838. ASSERT( ((PATQ_ENDPOINT)m_atqEndpoint)->Signature == ATQ_ENDPOINT_SIGNATURE );
  839. //
  840. // Because the ATQ endpoint has an uncounted reference to this object, we can't
  841. // go away until the ATQ endpoint is closed. Since it may be bad to block our
  842. // own thread while waiting for the ATQ endpoint, we create a new thread to do
  843. // it.
  844. //
  845. pParam = new ENDPOINT_HACK_PARAM;
  846. if (pParam == NULL) {
  847. goto threadfail;
  848. }
  849. pParam->piisEndpoint = this;
  850. pParam->patqEndpoint = m_atqEndpoint;
  851. dwCookie = ScheduleWorkItem( EndpointHackFunc, pParam, 0 );
  852. if ( dwCookie == 0 ) {
  853. goto threadfail;
  854. }
  855. } else {
  856. //
  857. // If we couldn't activate the endpoint we will not have an ATQ_ENDPOINT
  858. // to close. In this case we can clean up immediately
  859. //
  860. delete this;
  861. }
  862. } else {
  863. //DBGPRINTF((DBG_CONTEXT,"endpoint deref count %d\n",m_reference));
  864. }
  865. return;
  866. threadfail:
  867. if ( AtqCloseEndpoint( m_atqEndpoint ) ) {
  868. ASSERT( m_signature == IIS_ENDPOINT_SIGNATURE );
  869. delete this;
  870. } else {
  871. //
  872. // There could still be some connections to us, so we can't free the memory.
  873. // However we have to dereference the IIS_SERVICE, which is waiting for us
  874. // during shutdown. Normally this deref occurs during the IIS_ENDPOINT destructor.
  875. //
  876. m_service->Dereference();
  877. m_service = NULL;
  878. DBGPRINTF((DBG_CONTEXT,
  879. "AtqCloseEndpoint returned FALSE! "
  880. "Leaking endpoints: iisEndpoint = %p, atqEndpoint = %p\n",
  881. this, m_atqEndpoint));
  882. }
  883. }
  884. VOID
  885. WINAPI
  886. EndpointHackFunc(
  887. PVOID pv
  888. )
  889. /*++
  890. Routine Description:
  891. This function is a work item scheduled by IIS_ENDPOINT::Dereference. When the IIS_ENDPOINT
  892. refcount hits zero, there is still a reference to the structure from the ATQ_ENDPOINT.
  893. We call AtqCloseEndpoint, which returns when the reference is gone, and then clean up
  894. when it is safe to do so.
  895. Arguments:
  896. pv - a parameter block containing pointers to the IIS_ENDPOINT and it's ATQ_ENDPOINT.
  897. Return Value:
  898. None
  899. --*/
  900. {
  901. PENDPOINT_HACK_PARAM pParam = (PENDPOINT_HACK_PARAM) pv;
  902. ASSERT( pParam->piisEndpoint->CheckSignature(IIS_ENDPOINT_SIGNATURE) );
  903. ASSERT( ((PATQ_ENDPOINT)pParam->patqEndpoint)->Signature == ATQ_ENDPOINT_SIGNATURE );
  904. IF_DEBUG(ENDPOINT) {
  905. DBGPRINTF((DBG_CONTEXT, "EndpointHackFunc: iis=%p atq=%p\n",
  906. pParam->piisEndpoint, pParam->patqEndpoint));
  907. }
  908. //
  909. // if AtqCloseEndpoint fails we can't clean up, because someone could
  910. // still have a pointer to us!
  911. //
  912. if ( AtqCloseEndpoint( pParam->patqEndpoint ) ) {
  913. ASSERT( pParam->piisEndpoint->CheckSignature(IIS_ENDPOINT_SIGNATURE) );
  914. delete pParam->piisEndpoint;
  915. } else {
  916. //
  917. // There could still be some connections to us, so we can't free the memory.
  918. // However we have to dereference the IIS_SERVICE, which is waiting for us
  919. // during shutdown. Normally this deref occurs during the IIS_ENDPOINT destructor.
  920. //
  921. pParam->piisEndpoint->QueryService()->Dereference();
  922. pParam->piisEndpoint->SetService( NULL );
  923. DBGPRINTF((DBG_CONTEXT,
  924. "AtqCloseEndpoint returned FALSE! "
  925. "Leaking endpoints: iisEndpoint = %p, atqEndpoint = %p\n",
  926. pParam->piisEndpoint, pParam->patqEndpoint));
  927. }
  928. delete pParam;
  929. }
  930. BOOL
  931. InitializeEndpointUtilities(
  932. VOID
  933. )
  934. /*++
  935. Routine Description:
  936. Called during infocomm initialization. This sets up a global debug trace
  937. log object
  938. Arguments:
  939. None
  940. Return Value:
  941. TRUE if successful
  942. --*/
  943. {
  944. #if IE_REF_TRACKING
  945. if ( g_pDbgIERefTraceLog == NULL )
  946. {
  947. g_pDbgIERefTraceLog = CreateRefTraceLog( C_IIS_ENDP_REFTRACES, 0 );
  948. return g_pDbgIERefTraceLog != NULL;
  949. }
  950. #endif
  951. return TRUE;
  952. }
  953. BOOL
  954. TerminateEndpointUtilities(
  955. VOID
  956. )
  957. /*++
  958. Routine Description:
  959. Called during infocomm cleanup. This cleans up the global debug trace
  960. log object
  961. Arguments:
  962. None
  963. Return Value:
  964. TRUE if successful
  965. --*/
  966. {
  967. #if IE_REF_TRACKING
  968. if ( g_pDbgIERefTraceLog )
  969. {
  970. DestroyRefTraceLog( g_pDbgIERefTraceLog );
  971. g_pDbgIERefTraceLog = NULL;
  972. }
  973. #endif
  974. return TRUE;
  975. }