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.

1471 lines
36 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. atqendp.cxx
  5. Abstract:
  6. This module implements ATQ endpoints
  7. Author:
  8. Johnson Apacible (JohnsonA) 13-May-1996
  9. Environment:
  10. User Mode -- Win32
  11. --*/
  12. #include "isatq.hxx"
  13. //
  14. // Forward declarations
  15. //
  16. BOOL
  17. I_CreateListenSocket(
  18. IN PATQ_ENDPOINT Endpoint
  19. );
  20. BOOL
  21. I_CloseListenSocket(
  22. IN PATQ_ENDPOINT Endpoint
  23. );
  24. BOOL
  25. StartListenThread(
  26. IN PATQ_ENDPOINT Endpoint
  27. );
  28. # define ATQ_MIN_ACCEPTEX_TIMEOUT (120) // 2 minutes = 120 seconds
  29. #define ATQ_CLOSE_ENDPOINT_SLEEP_TIME (200) // 200ms = 1/5 second
  30. #define ATQ_CLOSE_ENDPOINT_TIMEOUT ((100*1000) / ATQ_CLOSE_ENDPOINT_SLEEP_TIME)
  31. // 100 seconds
  32. PVOID
  33. AtqCreateEndpoint(
  34. IN PATQ_ENDPOINT_CONFIGURATION Configuration,
  35. IN PVOID EndpointContext
  36. )
  37. /*++
  38. Routine Description:
  39. Creates a server instance.
  40. Arguments:
  41. Context - Context value returned
  42. Return Value:
  43. TRUE if successful, FALSE on error (call GetLastError)
  44. --*/
  45. {
  46. DWORD timeout = Configuration->AcceptExTimeout;
  47. PATQ_ENDPOINT endpoint;
  48. IF_DEBUG(API_ENTRY) {
  49. ATQ_PRINTF((DBG_CONTEXT,"AtqCreateEndpoint entered\n"));
  50. }
  51. //
  52. // Allocate list
  53. //
  54. endpoint = (PATQ_ENDPOINT)LocalAlloc(0,sizeof(ATQ_ENDPOINT));
  55. if ( endpoint == NULL ) {
  56. ATQ_PRINTF(( DBG_CONTEXT,"Unable to allocate ATQ Endpoint\n"));
  57. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  58. goto error;
  59. }
  60. //
  61. // Initialize
  62. //
  63. ZeroMemory(endpoint,sizeof(ATQ_ENDPOINT));
  64. endpoint->Signature = ATQ_ENDPOINT_SIGNATURE;
  65. endpoint->m_refCount = 1;
  66. SET_BLOCK_STATE(endpoint, AtqStateActive);
  67. endpoint->EnableBw = FALSE;
  68. endpoint->ConnectCompletion = Configuration->pfnConnect;
  69. endpoint->ConnectExCompletion = Configuration->pfnConnectEx;
  70. endpoint->UseAcceptEx = (g_fUseAcceptEx) && (endpoint->ConnectExCompletion);
  71. endpoint->IoCompletion = Configuration->pfnIoCompletion;
  72. endpoint->ListenSocket = INVALID_SOCKET;
  73. endpoint->pListenAtqContext = NULL;
  74. endpoint->nAvailDuringTimeOut = 0;
  75. endpoint->nSocketsAvail = 0;
  76. endpoint->Context = EndpointContext;
  77. endpoint->pBacklogMon = NULL;
  78. endpoint->InitialRecvSize = Configuration->cbAcceptExRecvBuffer;
  79. // we need to maintain at least 5 outstanding accept ex sockets
  80. // for our auto-tune algo to work.
  81. endpoint->nAcceptExOutstanding =
  82. ( (Configuration->nAcceptExOutstanding > 4) ?
  83. Configuration->nAcceptExOutstanding : 5);
  84. //
  85. // fAddingSockets prevents two threads from adding AcceptEx sockets
  86. // at the same time. Since the endpoint isn't ready to have sockets
  87. // added we'll set this to TRUE until the endpoint is fully initialized
  88. // in ActivateEndpoint.
  89. //
  90. endpoint->fAddingSockets = TRUE;
  91. //
  92. // Check and set the timeout to be atleast minimum timeout for AcceptEx
  93. //
  94. if ( timeout <= ATQ_MIN_ACCEPTEX_TIMEOUT) {
  95. timeout = ATQ_MIN_ACCEPTEX_TIMEOUT;
  96. }
  97. endpoint->AcceptExTimeout = CanonTimeout( timeout);
  98. endpoint->Port = Configuration->ListenPort;
  99. endpoint->IpAddress = Configuration->IpAddress;
  100. //endpoint->ContextList.Initialize( );
  101. #if DBG
  102. endpoint->RefTraceLog = CreateRefTraceLog( TRACE_LOG_SIZE, 0 );
  103. #endif
  104. #if 0
  105. ATQ_PRINTF(( DBG_CONTEXT,"port %d nAX %d nAT %d nLB %d\n",
  106. endpoint->Port, endpoint->nAcceptExOutstanding,
  107. endpoint->AcceptExTimeout, g_cListenBacklog));
  108. #endif
  109. //
  110. // Create the socket
  111. //
  112. if (!I_CreateListenSocket(endpoint) ) {
  113. goto error;
  114. }
  115. return((PVOID)endpoint);
  116. error:
  117. if ( endpoint != NULL ) {
  118. #if DBG
  119. if( endpoint->RefTraceLog != NULL ) {
  120. DestroyRefTraceLog( endpoint->RefTraceLog );
  121. }
  122. #endif
  123. LocalFree( endpoint );
  124. }
  125. return(NULL);
  126. } // AtqCreateEndpoint
  127. BOOL
  128. AtqStartEndpoint(
  129. IN PVOID Endpoint
  130. )
  131. {
  132. PATQ_ENDPOINT pEndpoint = (PATQ_ENDPOINT)Endpoint;
  133. BOOL fReturn;
  134. DWORD dwError = NO_ERROR;
  135. ATQ_ASSERT(IS_BLOCK_ACTIVE(pEndpoint));
  136. IF_DEBUG(API_ENTRY) {
  137. ATQ_PRINTF((DBG_CONTEXT,"AtqStartEndpoint called. UseAcceptEx[%d]\n",
  138. pEndpoint->UseAcceptEx));
  139. }
  140. //
  141. // if AcceptEx is supported, create AcceptEx contexts
  142. //
  143. if ( pEndpoint->UseAcceptEx ) {
  144. //
  145. // Add AcceptEx sockets
  146. //
  147. fReturn = pEndpoint->ActivateEndpoint();
  148. if ( !fReturn ) {
  149. dwError = GetLastError();
  150. DBGERROR(( DBG_CONTEXT,"Error %d in %08x::ActivateEndpoint()\n",
  151. GetLastError(), pEndpoint));
  152. }
  153. } else {
  154. //
  155. // We need to start a listen thread
  156. //
  157. fReturn = StartListenThread( pEndpoint );
  158. if ( !fReturn ) {
  159. dwError = GetLastError();
  160. DBGERROR(( DBG_CONTEXT,"Error %d in %08x::StartListenThread()\n",
  161. GetLastError(), pEndpoint));
  162. }
  163. }
  164. if (!fReturn) {
  165. AtqStopEndpoint(pEndpoint);
  166. }
  167. SetLastError(dwError);
  168. return (fReturn);
  169. } // AtqStartEndpoint
  170. ULONG_PTR
  171. AtqEndpointGetInfo(
  172. IN PVOID Endpoint,
  173. IN ATQ_ENDPOINT_INFO EndpointInfo
  174. )
  175. /*++
  176. Routine Description:
  177. Gets various bits of information for the ATQ endpoint
  178. Arguments:
  179. Endpoint - endpoint to get data from
  180. EndpointInfo - type of info to get
  181. Return Value:
  182. The old value of the parameter
  183. --*/
  184. {
  185. PATQ_ENDPOINT pEndpoint = (PATQ_ENDPOINT)Endpoint;
  186. DWORD_PTR dwVal = 0;
  187. switch ( EndpointInfo ) {
  188. case EndpointInfoListenPort:
  189. dwVal = pEndpoint->Port;
  190. break;
  191. case EndpointInfoListenSocket:
  192. dwVal = pEndpoint->ListenSocket;
  193. break;
  194. default:
  195. ATQ_ASSERT( FALSE );
  196. }
  197. return dwVal;
  198. } // AtqEndpointGetInfo()
  199. ULONG_PTR
  200. AtqEndpointSetInfo(
  201. IN PVOID Endpoint,
  202. IN ATQ_ENDPOINT_INFO EndpointInfo,
  203. IN ULONG_PTR Info
  204. )
  205. /*++
  206. Routine Description:
  207. Gets various bits of information for the ATQ module
  208. Arguments:
  209. Endpoint - endpoint to set info on
  210. EndpointInfo - type of info to set
  211. Info - info to set
  212. Return Value:
  213. The old value of the parameter
  214. --*/
  215. {
  216. PATQ_ENDPOINT pEndpoint = (PATQ_ENDPOINT)Endpoint;
  217. ULONG_PTR Val = 0;
  218. switch ( EndpointInfo ) {
  219. case EndpointInfoAcceptExOutstanding:
  220. Val = (ULONG_PTR)pEndpoint->nAcceptExOutstanding;
  221. if ( Val < Info ) {
  222. //
  223. // Make up for increased limit
  224. //
  225. if ( (DWORD ) pEndpoint->nSocketsAvail < (DWORD)(Info >> 2) ) {
  226. (VOID ) I_AtqPrepareAcceptExSockets(
  227. pEndpoint,
  228. (DWORD)(Info>>2) - pEndpoint->nSocketsAvail
  229. );
  230. }
  231. pEndpoint->nAcceptExOutstanding = (DWORD)Info;
  232. }
  233. break;
  234. default:
  235. ATQ_ASSERT( FALSE );
  236. }
  237. return Val;
  238. } // AtqEndpointSetInfo()
  239. BOOL
  240. AtqStopEndpoint(
  241. IN PVOID Endpoint
  242. )
  243. /*++
  244. Routine Description:
  245. Stops the endpoint - marks the Endpoint as to be shutdown and closes
  246. the listening socket -> forcing new connections to stop for this endpoint
  247. Arguments:
  248. Endpoint - endpoint to be stopped
  249. Return Value:
  250. TRUE if successful, FALSE on error (call GetLastError)
  251. --*/
  252. {
  253. PATQ_ENDPOINT pEndpoint = (PATQ_ENDPOINT)Endpoint;
  254. DWORD nClosed;
  255. IF_DEBUG( API_ENTRY) {
  256. ATQ_PRINTF(( DBG_CONTEXT,
  257. "AtqStopEndpoint( %08x)\n", pEndpoint));
  258. }
  259. //
  260. // Find the listen socket info
  261. //
  262. AcquireLock( &AtqEndpointLock );
  263. if ( !IS_BLOCK_ACTIVE(pEndpoint) ) {
  264. ATQ_PRINTF(( DBG_CONTEXT,
  265. "Attempt to Stop Endpoint (%08x) more than once",
  266. pEndpoint
  267. ));
  268. ReleaseLock( &AtqEndpointLock );
  269. return(FALSE);
  270. }
  271. //
  272. // Mark the listen info as no longer accepting connections
  273. //
  274. SET_BLOCK_STATE(pEndpoint, AtqStateClosed);
  275. //
  276. // Remove the entry from the end points list
  277. //
  278. RemoveEntryList(&pEndpoint->ListEntry);
  279. ReleaseLock( &AtqEndpointLock );
  280. //
  281. // Remove us from the Backlog Monitor
  282. //
  283. DBG_ASSERT( g_pAtqBacklogMonitor );
  284. if (pEndpoint->pBacklogMon) {
  285. DBG_REQUIRE( g_pAtqBacklogMonitor->RemoveEntry(pEndpoint->pBacklogMon) );
  286. delete pEndpoint->pBacklogMon;
  287. pEndpoint->pBacklogMon = NULL;
  288. }
  289. //
  290. // Close the listen socket which forces the cleanup for all the
  291. // pending LISTEN ATQ contexts. We do this early on so that
  292. // we can prevent any new entrant connections into the processing code.
  293. //
  294. I_CloseListenSocket( pEndpoint );
  295. //
  296. // Forcibly close all the pending LISTEN contexts tied to this endpoint
  297. //
  298. nClosed = pEndpoint->CloseAtqContexts( TRUE);
  299. DBGPRINTF(( DBG_CONTEXT,
  300. "ATQ_ENDPOINT(%08x)::Closed %d pending Listen sockets\n",
  301. pEndpoint, nClosed));
  302. //
  303. // if this is a non-acceptex socket, wait for the listen thread to die
  304. //
  305. if ( !pEndpoint->UseAcceptEx ) {
  306. WaitForSingleObject(pEndpoint->hListenThread, 10*1000);
  307. }
  308. return ( TRUE);
  309. } // AtqStopEndpoint()
  310. BOOL
  311. AtqCloseEndpoint(
  312. IN PVOID Endpoint
  313. )
  314. /*++
  315. Routine Description:
  316. Closes the endpoint - it forcefully fress up all references to the
  317. endpoint (held by ATQ Contexts) by shutting down the ATQ contexts.
  318. In the course of this operation if some context does not go away, this
  319. code will end up looping forever!
  320. Note: Should be called *after* AtqStopEndpoint()
  321. Arguments:
  322. Endpoint - endpoint to be stopped
  323. Return Value:
  324. TRUE if successful, FALSE on error (call GetLastError)
  325. --*/
  326. {
  327. PATQ_ENDPOINT pEndpoint = (PATQ_ENDPOINT)Endpoint;
  328. DWORD nClosed;
  329. DWORD i;
  330. ASSERT( pEndpoint->Signature == ATQ_ENDPOINT_SIGNATURE );
  331. IF_DEBUG( API_ENTRY) {
  332. ATQ_PRINTF(( DBG_CONTEXT,
  333. "AtqCloseEndpoint( %08x)\n", pEndpoint));
  334. }
  335. if ( pEndpoint->State != AtqStateClosed) {
  336. ATQ_PRINTF(( DBG_CONTEXT,
  337. "Attempt to Close Endpoint (%08x) when it is "
  338. " not stopped yet!\n'",
  339. pEndpoint
  340. ));
  341. DBG_ASSERT(pEndpoint->State == AtqStateClosed);
  342. return(FALSE);
  343. }
  344. //
  345. // wait for all the contexts for this endpoint to go away
  346. // or for about two minutes
  347. //
  348. i = 0;
  349. while (( pEndpoint->m_refCount > 1) && (i < ATQ_CLOSE_ENDPOINT_TIMEOUT)) {
  350. ATQ_PRINTF(( DBG_CONTEXT, " Endpoint(%08x) has %d refs\n",
  351. pEndpoint, pEndpoint->m_refCount));
  352. //
  353. // Forcibly close all the contexts tied to this endpoint again!
  354. // Sometimes for some random reasons ATQ contexts get left out
  355. // during the first clean we did above. In such case it is important
  356. // to retry again
  357. // THIS IS UGLY. But if we did not do this then the Endpoint
  358. // structure might get freed => ATQ contexts will be hanging on to
  359. // dead ATQ endpoint
  360. //
  361. nClosed = pEndpoint->CloseAtqContexts();
  362. DBGPRINTF(( DBG_CONTEXT, " ATQ_ENDPOINT(%08x)::Closed %d sockets\n",
  363. pEndpoint, nClosed));
  364. //
  365. // NYI: I need to auto-tune this sleep function
  366. //
  367. Sleep( ATQ_CLOSE_ENDPOINT_SLEEP_TIME); // sleep and check again.
  368. #if DBG
  369. //
  370. // loop forever for checked builds
  371. //
  372. #else
  373. //
  374. // loop until timeout for retail
  375. //
  376. i++;
  377. #endif
  378. // wake up and check again.
  379. } // while (busy wait)
  380. //
  381. // Undo the reference for being on the listen info list.
  382. // decr final ref count => the endpoint will be cleaned up & freed
  383. //
  384. // If we timed out just leak the endpoints!
  385. //
  386. if ( pEndpoint->m_refCount == 1 ) {
  387. pEndpoint->Dereference();
  388. return TRUE;
  389. } else {
  390. return FALSE;
  391. }
  392. } // AtqCloseEndpoint()
  393. BOOL
  394. AtqStopAndCloseEndpoint(
  395. IN PVOID Endpoint,
  396. IN LPTHREAD_START_ROUTINE lpCompletion,
  397. IN PVOID lpCompletionContext
  398. )
  399. /*++
  400. Routine Description:
  401. Stops the endpoint and closes it after forcing close of
  402. associated ATQ contexts.
  403. Arguments:
  404. Endpoint - endpoint to shutdown.
  405. lpCompletion - routine to be called when endpoint is completely shutdown.
  406. lpCompletionContext - Context to be returned with the routine
  407. Return Value:
  408. TRUE if successful, FALSE on error (call GetLastError)
  409. --*/
  410. {
  411. PATQ_ENDPOINT pEndpoint = (PATQ_ENDPOINT)Endpoint;
  412. BOOL fReturn;
  413. //
  414. // Warn all the callers of this to be deprecated API and pray that
  415. // they will all switch over
  416. //
  417. #ifndef _NO_TRACING_
  418. DBGPRINTF( (DBG_CONTEXT, "\n-----------------------------------------------\n"));
  419. DBGPRINTF( (DBG_CONTEXT, " AtqStopAndCloseEndpoint() should NOT be called\n"));
  420. DBGPRINTF( (DBG_CONTEXT, " Call 1) AtqStopEndpoint() and \n"));
  421. DBGPRINTF( (DBG_CONTEXT, " 2) AtqCloseEndpoint() instead\n"));
  422. DBGPRINTF( (DBG_CONTEXT, " For Now, this call will simulate 1 & 2\n"));
  423. DBGPRINTF( (DBG_CONTEXT, "-----------------------------------------------\n"));
  424. #else
  425. OutputDebugStringA( "\n-----------------------------------------------\n");
  426. OutputDebugStringA( " AtqStopAndCloseEndpoint() should NOT be called\n");
  427. OutputDebugStringA( " Call 1) AtqStopEndpoint() and \n");
  428. OutputDebugStringA( " 2) AtqCloseEndpoint() instead\n");
  429. OutputDebugStringA( " For Now, this call will simulate 1 & 2\n");
  430. OutputDebugStringA( "-----------------------------------------------\n");
  431. #endif
  432. IF_DEBUG( API_ENTRY) {
  433. ATQ_PRINTF(( DBG_CONTEXT,
  434. "AtqStopAndCloseEndpoint( %08x)\n", pEndpoint));
  435. }
  436. fReturn = AtqStopEndpoint( Endpoint);
  437. if ( fReturn) {
  438. //
  439. // Call any custom shutdown function
  440. // NYI: Too Bad the Endpoint object is not a base class object
  441. //
  442. if ( lpCompletion != NULL ) {
  443. pEndpoint->ShutdownCallback = lpCompletion;
  444. pEndpoint->ShutdownCallbackContext = lpCompletionContext;
  445. }
  446. //
  447. // Now that the Endpoint is stopped and callback functions are called,
  448. // Let us call the AtqCloseEndpoint() to cleanup the endpoint itself.
  449. //
  450. fReturn = AtqCloseEndpoint( Endpoint);
  451. }
  452. return (fReturn);
  453. } // AtqStopAndCloseEndpoint()
  454. BOOL
  455. ATQ_ENDPOINT::ActivateEndpoint( VOID)
  456. /*++
  457. Routine Description:
  458. This function creates the initial listening socket & ATQ context for given
  459. endpoint. It also adds initial set of AcceptEx Sockets to the ATQ listening
  460. pool (if we are using the AcceptEx())
  461. Arguments:
  462. None
  463. Return Value:
  464. TRUE on success, FALSE on failure
  465. --*/
  466. {
  467. PATQ_CONT patqContext = NULL;
  468. BOOL fReturn;
  469. DWORD cInitial = this->nAcceptExOutstanding;
  470. //
  471. // Add the listen socket
  472. //
  473. DBG_ASSERT( this->pListenAtqContext == NULL);
  474. fReturn =
  475. I_AtqAddListenEndpointToPort(
  476. (PATQ_CONT*)&this->pListenAtqContext,
  477. this
  478. );
  479. if ( !fReturn) {
  480. if ( this->pListenAtqContext ) {
  481. AtqFreeContext( this->pListenAtqContext, FALSE);
  482. this->pListenAtqContext = NULL;
  483. }
  484. return FALSE;
  485. }
  486. cInitial = max(cInitial, 1);
  487. if ( !TsIsNtServer( ) ) {
  488. //
  489. // Limit what a workstation can specify
  490. //
  491. cInitial = min(cInitial, ATQ_MIN_CTX_INC);
  492. this->nAcceptExOutstanding = cInitial;
  493. }
  494. //
  495. // start with 1/4 of the intended
  496. //
  497. cInitial = max( cInitial >> 2, 1);
  498. //
  499. // Now we're finally ready to add AcceptEx sockets, so we'll
  500. // reset the flag that was preventing it.
  501. //
  502. fAddingSockets = FALSE;
  503. //
  504. // Now add the acceptex sockets for this ListenInfo object
  505. //
  506. fReturn = I_AtqPrepareAcceptExSockets(this, cInitial);
  507. if (fReturn && !g_fDisableBacklogMonitor ) {
  508. //
  509. // Set up the Backlog monitor
  510. //
  511. DBG_ASSERT( pBacklogMon == NULL );
  512. DBG_ASSERT( g_pAtqBacklogMonitor );
  513. pBacklogMon = new ATQ_ENDPOINT_BMON(ListenSocket, this);
  514. if (pBacklogMon) {
  515. fReturn = (pBacklogMon->InitEvent()
  516. && g_pAtqBacklogMonitor->AddEntry(pBacklogMon));
  517. if (!fReturn) {
  518. delete pBacklogMon;
  519. pBacklogMon = NULL;
  520. }
  521. } else {
  522. fReturn = FALSE;
  523. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  524. }
  525. }
  526. return(fReturn);
  527. } // ATQ_ENDPOINT::ActivateEndpoint()
  528. DWORD
  529. ATQ_ENDPOINT::CloseAtqContexts( IN BOOL fPendingOnly)
  530. /*++
  531. Description:
  532. This function searches for all ATQ contexts associated
  533. with the given endpoint and forcibly closes them all.
  534. Arguments:
  535. fPendingOnly - close only the pending sockets
  536. Returns:
  537. DWORD containing the number of ATQ contexts closed.
  538. --*/
  539. {
  540. DWORD nClosed = 0;
  541. DWORD i;
  542. PLIST_ENTRY pEntry;
  543. PATQ_CONT pContext;
  544. //
  545. // Force a close on all the connected sockets so that all the holders
  546. // and use of such contexts will bail out of this endpoint entirely.
  547. // NYI: We need a way to tag on all these lists on per-endpoint basis
  548. //
  549. for ( i = 0; i < g_dwNumContextLists; i++) {
  550. PLIST_ENTRY pListHead;
  551. AtqActiveContextList[i].Lock();
  552. //
  553. // Hard close sockets in the pending list
  554. //
  555. pListHead = &AtqActiveContextList[i].PendingAcceptExListHead;
  556. for ( pEntry = pListHead->Flink;
  557. pEntry != pListHead;
  558. pEntry = pEntry->Flink ) {
  559. pContext = CONTAINING_RECORD( pEntry, ATQ_CONTEXT, m_leTimeout );
  560. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  561. if ( (pContext->pEndpoint == this) &&
  562. (pContext->IsState( ACS_SOCK_CONNECTED) ||
  563. pContext->IsState( ACS_SOCK_LISTENING)
  564. ) &&
  565. (pContext->hAsyncIO != NULL) ) {
  566. nClosed++;
  567. pContext->HardCloseSocket();
  568. }
  569. } // for items in pending list
  570. if ( !fPendingOnly) {
  571. //
  572. // Hard close sockets in the active list
  573. // Active list includes sockets in ACS_SOCK_CLOSED state
  574. // that ought to be freed up, because we could have reached
  575. // this through the optimizations for TransmitFile()
  576. //
  577. pListHead = &AtqActiveContextList[i].ActiveListHead;
  578. for ( pEntry = pListHead->Flink;
  579. pEntry != pListHead;
  580. pEntry = pEntry->Flink ) {
  581. pContext = CONTAINING_RECORD( pEntry, ATQ_CONTEXT,
  582. m_leTimeout );
  583. ATQ_ASSERT( pContext->Signature == ATQ_CONTEXT_SIGNATURE );
  584. if ( (pContext->pEndpoint == this) &&
  585. (pContext->IsState( ACS_SOCK_CONNECTED) ||
  586. pContext->IsState( ACS_SOCK_LISTENING) ||
  587. pContext->IsState( ACS_SOCK_CLOSED) ||
  588. pContext->IsState( ACS_SOCK_UNCONNECTED)
  589. ) &&
  590. (pContext->hAsyncIO != NULL) ) {
  591. nClosed++;
  592. pContext->HardCloseSocket();
  593. }
  594. } // for items in active list
  595. } // if (! fPendingOnly)
  596. AtqActiveContextList[i].Unlock();
  597. } // for
  598. return ( nClosed);
  599. } // ATQ_ENDPOINT::CloseAtqContexts()
  600. /************************************************************
  601. * Internal Functions
  602. ************************************************************/
  603. BOOL
  604. I_CreateListenSocket(
  605. IN PATQ_ENDPOINT pEndpoint
  606. )
  607. /*++
  608. Creates a socket for listening to connections on given address.
  609. Arguments:
  610. lpSockAddress pointer to local socket address structure used to bind
  611. the given connection.
  612. lenSockAddress length of the socket address structure.
  613. socketType integer containing the type of the socket ( stream )
  614. socketProtocol protocol to be used for the socket.
  615. nBackLog Maximum length to which a queue of pending connections
  616. may grow.
  617. Returns:
  618. NO_ERROR on success; otherwise returns Sockets error code.
  619. --*/
  620. {
  621. INT serr;
  622. SOCKET sNew;
  623. BOOL fReuseAddr = FALSE;
  624. SOCKADDR_IN inAddr;
  625. PSOCKADDR addr;
  626. INT addrLength;
  627. PLIST_ENTRY listEntry;
  628. PATQ_ENDPOINT scanEndpoint;
  629. IF_DEBUG(API_ENTRY) {
  630. ATQ_PRINTF((DBG_CONTEXT,"I_CreateListenEndpoint called. \n"));
  631. }
  632. //
  633. // Since we'll be altering our behaviour based on the contents of
  634. // the endpoint list, we must acquire the endpoint list lock and
  635. // hold this lock throughout this routine.
  636. //
  637. AcquireLock( &AtqEndpointLock);
  638. //
  639. // If this is the first endpoint to be bound to this port, then
  640. // disable SO_REUSEADDR. Otherwise (there are other endpoints already
  641. // using this port), then enable SO_REUSEADDR.
  642. //
  643. // "Why are we doing this" you ask? Since we're binding our listening
  644. // sockets to specific IP addresses, we must enable SO_REUSEADDR
  645. // (otherwise, we'd get WSAEADDRINUSE errors). However, in an effort
  646. // to detect a port conflicts with other (non-IIS) software, we'll
  647. // disable SO_REUSEADDR the *first* time a particular port is used.
  648. //
  649. for( listEntry = AtqEndpointList.Flink;
  650. listEntry != &AtqEndpointList;
  651. listEntry = listEntry->Flink ) {
  652. scanEndpoint = CONTAINING_RECORD(
  653. listEntry,
  654. ATQ_ENDPOINT,
  655. ListEntry
  656. );
  657. ATQ_ASSERT( scanEndpoint->Signature == ATQ_ENDPOINT_SIGNATURE );
  658. if( scanEndpoint->Port == pEndpoint->Port ) {
  659. fReuseAddr = TRUE;
  660. break;
  661. }
  662. }
  663. //
  664. // Create a new socket
  665. //
  666. #if WINSOCK11
  667. sNew = socket(
  668. AF_INET,
  669. SOCK_STREAM,
  670. IPPROTO_TCP
  671. );
  672. #else
  673. sNew = WSASocket(
  674. AF_INET,
  675. SOCK_STREAM,
  676. IPPROTO_TCP,
  677. NULL, // protocol info
  678. 0, // Group ID = 0 => no constraints
  679. WSA_FLAG_OVERLAPPED // completion port notifications
  680. );
  681. # endif // WINSOCK11
  682. if ( sNew == INVALID_SOCKET ) {
  683. serr = WSAGetLastError();
  684. ATQ_PRINTF(( DBG_CONTEXT,
  685. "Error %d in socket( %d, %d, %d)\n",
  686. serr,
  687. AF_INET,
  688. SOCK_STREAM,
  689. IPPROTO_TCP
  690. ));
  691. goto cleanup;
  692. }
  693. //
  694. // Set SO_REUSEADDR based on results of the endpoint scan above.
  695. //
  696. if ( setsockopt( sNew, SOL_SOCKET, SO_REUSEADDR,
  697. (const CHAR *) &fReuseAddr,
  698. sizeof( fReuseAddr)) != 0) {
  699. serr = WSAGetLastError();
  700. ATQ_PRINTF(( DBG_CONTEXT,
  701. " setsockopt( %d, REUSE_ADDR, FALSE) failed."
  702. " Error = %d\n",
  703. sNew, serr));
  704. goto cleanup;
  705. }
  706. //
  707. // See which address family we're dealing with
  708. //
  709. addr = (PSOCKADDR)&inAddr;
  710. addrLength = sizeof(inAddr);
  711. ZeroMemory(addr, addrLength);
  712. inAddr.sin_family = AF_INET;
  713. inAddr.sin_port = htons(pEndpoint->Port);
  714. inAddr.sin_addr.s_addr = pEndpoint->IpAddress;
  715. //
  716. // Bind an address to socket
  717. //
  718. if ( bind( sNew, addr, addrLength) != 0) {
  719. serr = WSAGetLastError();
  720. ATQ_PRINTF(( DBG_CONTEXT,
  721. "bind ( socket = %d, Address = %08x, len = %d) "
  722. " returns error = %u\n",
  723. sNew, addr, addrLength, serr));
  724. goto cleanup;
  725. }
  726. //
  727. // Put the socket in listen mode
  728. //
  729. if ( listen( sNew, g_cListenBacklog) != 0) {
  730. serr = WSAGetLastError();
  731. ATQ_PRINTF(( DBG_CONTEXT,
  732. " listen( %d, %d) returned %d.\n",
  733. sNew, g_cListenBacklog, serr));
  734. goto cleanup;
  735. }
  736. pEndpoint->ListenSocket = sNew;
  737. //
  738. // Link to server listen list
  739. //
  740. InsertTailList(
  741. &AtqEndpointList,
  742. &pEndpoint->ListEntry
  743. );
  744. ReleaseLock( &AtqEndpointLock);
  745. return(TRUE);
  746. cleanup:
  747. if ( sNew != INVALID_SOCKET) {
  748. closesocket( sNew);
  749. }
  750. ReleaseLock( &AtqEndpointLock);
  751. SetLastError(serr);
  752. return(FALSE);
  753. } // I_CreateListenSocket
  754. BOOL
  755. I_CloseListenSocket(
  756. IN PATQ_ENDPOINT Endpoint
  757. )
  758. /*++
  759. Closes the socket on which a listen was possibly established.
  760. Returns:
  761. TRUE, if successful,
  762. FALSE, otherwise
  763. --*/
  764. {
  765. INT serr = NO_ERROR;
  766. LINGER linger;
  767. SOCKET s;
  768. IF_DEBUG(API_ENTRY) {
  769. ATQ_PRINTF((DBG_CONTEXT,"I_CloseListenSocket called.\n"));
  770. }
  771. s = (SOCKET)InterlockedExchangePointer(
  772. (PVOID *)&Endpoint->ListenSocket,
  773. (PVOID)INVALID_SOCKET
  774. );
  775. if ( s == INVALID_SOCKET) {
  776. return(TRUE);
  777. }
  778. //
  779. // Enable linger with timeout of ZERO for "hard" close
  780. //
  781. // Error code from sock option is ignored, since we are
  782. // anyway closing the socket
  783. //
  784. linger.l_onoff = TRUE;
  785. linger.l_linger = 0;
  786. setsockopt( s, SOL_SOCKET, SO_LINGER, (PCHAR)&linger,sizeof(linger));
  787. //
  788. // Close the socket
  789. //
  790. if (closesocket(s) != 0) {
  791. serr = WSAGetLastError();
  792. ATQ_PRINTF(( DBG_CONTEXT,"error %d in closesocket\n",serr));
  793. } else {
  794. // Remove the socket from the ListenAtq Context as well
  795. // since the socket is now closed here in this function.
  796. PATQ_CONTEXT patqc = Endpoint->pListenAtqContext;
  797. if ( patqc != NULL) {
  798. patqc->hAsyncIO = NULL;
  799. }
  800. }
  801. return (TRUE);
  802. } // I_CloseListenSocket()
  803. DWORD
  804. ListenThreadFunc(
  805. LPVOID Context
  806. )
  807. /*++
  808. Main loop waiting for connections. ( The core of server)
  809. The thread loops around waiting on an accept() call on
  810. listenSocket.
  811. If there is a new message on socket, it invokes the
  812. callback function for connection.
  813. NEVER returns untill it is requested to stop by someother
  814. thread using a call to TS_CONNECTION_INFO::StopConnectionThread().
  815. Returns:
  816. 0 on success and error code if there is a fatal error.
  817. --*/
  818. {
  819. INT serr;
  820. register SOCKET sNewConnection;
  821. SOCKADDR_IN sockAddrRemote;
  822. PATQ_ENDPOINT endpoint = (PATQ_ENDPOINT)Context;
  823. IF_DEBUG(ENDPOINT) {
  824. ATQ_PRINTF((DBG_CONTEXT,"ListenThreadFunc() running.\n"));
  825. }
  826. //
  827. // Loop Forever
  828. //
  829. for( ; ;) {
  830. int cbAddr = sizeof( sockAddrRemote);
  831. //
  832. // Wait for a connection
  833. //
  834. IF_DEBUG(ENDPOINT) {
  835. ATQ_PRINTF((DBG_CONTEXT,"Listening for new connection\n"));
  836. }
  837. if ((sNewConnection = WSAAccept(
  838. endpoint->ListenSocket,
  839. (LPSOCKADDR ) &sockAddrRemote,
  840. &cbAddr,
  841. NULL,
  842. 0)) != INVALID_SOCKET) {
  843. //
  844. // Valid Connection has been established.
  845. // Invoke the callback function to process this connection
  846. // and then continue the loop
  847. //
  848. IF_DEBUG(ENDPOINT) {
  849. ATQ_PRINTF((DBG_CONTEXT,"Got new connection. sock[%d]\n",
  850. sNewConnection));
  851. }
  852. (*endpoint->ConnectCompletion)(
  853. sNewConnection,
  854. &sockAddrRemote,
  855. endpoint->Context,
  856. (PVOID)endpoint
  857. );
  858. } else {
  859. //
  860. // Some low level error has occured.
  861. //
  862. serr = WSAGetLastError();
  863. ATQ_PRINTF((DBG_CONTEXT,"Error %d in accept\n", serr));
  864. if ( serr == WSAEINTR) {
  865. //
  866. // Socket was closed by low-level call. Get out.
  867. //
  868. break;
  869. }
  870. //
  871. // Check if we are shutting down and if so QUIT
  872. //
  873. if (!IS_BLOCK_ACTIVE(endpoint)) {
  874. IF_DEBUG(ENDPOINT) {
  875. ATQ_PRINTF((DBG_CONTEXT,"ListenThread shutting down\n"));
  876. }
  877. break;
  878. }
  879. //
  880. // Perform a graceful recovery from failure. NYI
  881. // ( Tricky code). Both FTP and Web server are to test it!
  882. // Will add this code later. ( MuraliK)
  883. //
  884. IF_DEBUG(ENDPOINT) {
  885. ATQ_PRINTF((DBG_CONTEXT,"Unexpected error %d on accept\n",
  886. serr));
  887. }
  888. }
  889. }
  890. //
  891. // Cleanup & Exit. Cleanup is done by the code which called the shut down.
  892. //
  893. IF_DEBUG(ENDPOINT) {
  894. ATQ_PRINTF((DBG_CONTEXT,"ListenThread exiting.\n"));
  895. }
  896. return ( 0); // No errors
  897. } // ListenThreadFunc()
  898. BOOL
  899. StartListenThread(
  900. IN PATQ_ENDPOINT Endpoint
  901. )
  902. {
  903. DWORD id;
  904. Endpoint->hListenThread = CreateThread(
  905. NULL,
  906. 0,
  907. ListenThreadFunc,
  908. (PVOID )Endpoint,
  909. 0,
  910. &id
  911. );
  912. if ( Endpoint->hListenThread != NULL) {
  913. return(TRUE);
  914. }
  915. return(FALSE);
  916. } // StartListenThread
  917. VOID
  918. ATQ_ENDPOINT::CleanupEndpoint(
  919. VOID
  920. )
  921. /*++
  922. Description:
  923. This function cleansup the internal state of the object and prepares
  924. it for the deletion.
  925. All endpoints should pass through this function when the ref count
  926. this zero.
  927. --*/
  928. {
  929. DBG_ASSERT( this->m_refCount == 0);
  930. ATQ_ASSERT( !IS_BLOCK_ACTIVE( this) );
  931. ASSERT( this->Signature == ATQ_ENDPOINT_SIGNATURE );
  932. // the following free will throw away the listen atq context
  933. if ( this->pListenAtqContext != NULL) {
  934. ATQ_PRINTF(( DBG_CONTEXT,
  935. "Endpoint(%08x) frees listen context %08x\n",
  936. this, this->pListenAtqContext));
  937. AtqFreeContext( this->pListenAtqContext, FALSE);
  938. this->pListenAtqContext = NULL;
  939. }
  940. if ( this->ShutdownCallback != NULL ) {
  941. //
  942. // This only happens when someone calls AtqStopAndCloseEndpoint which should
  943. // never happen in K2.
  944. //
  945. ASSERT( FALSE );
  946. this->ShutdownCallback( this->ShutdownCallbackContext);
  947. }
  948. this->Signature = ATQ_ENDPOINT_SIGNATURE_FREE;
  949. #if DBG
  950. if( this->RefTraceLog != NULL ) {
  951. DestroyRefTraceLog( this->RefTraceLog );
  952. }
  953. #endif
  954. return;
  955. } // ATQ_ENDPOINT::CleanupEndpoint()
  956. VOID
  957. ATQ_ENDPOINT_BMON::ForceCompletion(
  958. IN PVOID pvContext
  959. )
  960. /*++
  961. Routine Description:
  962. Scheduled timeout of all unconnected sockets
  963. Arguments:
  964. pvContext - Context (ATQ_ENDPOINT_BMON *)
  965. Return Values:
  966. None
  967. --*/
  968. {
  969. ATQ_ENDPOINT_BMON* pEndpointBMon;
  970. PATQ_CONTEXT_LISTHEAD pACL;
  971. DWORD cForcedTotal = 0;
  972. DWORD cForced = 0;
  973. if ( !pvContext )
  974. {
  975. DBG_ASSERT( FALSE );
  976. return;
  977. }
  978. pEndpointBMon = (ATQ_ENDPOINT_BMON*) pvContext;
  979. for ( pACL = AtqActiveContextList;
  980. pACL < (AtqActiveContextList + g_dwNumContextLists);
  981. pACL++ )
  982. {
  983. I_AtqProcessPendingListens( pACL,
  984. pEndpointBMon->m_pEndpoint,
  985. &cForced );
  986. cForcedTotal += cForced;
  987. }
  988. //
  989. // Add back any sockets we forced
  990. //
  991. if ( cForcedTotal )
  992. {
  993. I_AtqPrepareAcceptExSockets( pEndpointBMon->m_pEndpoint,
  994. cForcedTotal );
  995. }
  996. //
  997. // Update stats
  998. //
  999. pEndpointBMon->m_nSocketsReset += cForcedTotal;
  1000. pEndpointBMon->m_dwForceCookie = 0;
  1001. }
  1002. BOOL
  1003. ATQ_ENDPOINT_BMON::Callback(
  1004. VOID
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. The ATQ_BACKLOG_MONITOR calls this function
  1009. when our listen socket runs out of AccepEx
  1010. sockets.
  1011. Arguments:
  1012. None
  1013. Return Values:
  1014. Return TRUE if successful, else FALSE
  1015. --*/
  1016. {
  1017. PLIST_ENTRY pListEntry;
  1018. // How many times were we called?
  1019. m_nActivations++;
  1020. //
  1021. // Inform the set thread to sleep after all notifications
  1022. //
  1023. GetContainingBmonSet()->DoSleep( TRUE );
  1024. //
  1025. // Are there available threads? If not, then this condition won't be
  1026. // helped by creating more sockets. Do nothing.
  1027. //
  1028. if ( g_cAvailableThreads )
  1029. {
  1030. DBG_ASSERT( m_pEndpoint );
  1031. if ( !g_cForceTimeout )
  1032. {
  1033. //
  1034. // No wait period before force. Just do it.
  1035. //
  1036. ForceCompletion( this );
  1037. }
  1038. else if ( !m_dwForceCookie )
  1039. {
  1040. //
  1041. // OK. Let's do something. Traverse the list of unconnected
  1042. // sockets and set an <x> second timeout on each
  1043. //
  1044. m_dwForceCookie = ScheduleWorkItem(
  1045. ATQ_ENDPOINT_BMON::ForceCompletion,
  1046. this,
  1047. TimeToWait( g_cForceTimeout ),
  1048. FALSE );
  1049. }
  1050. }
  1051. return TRUE;
  1052. }
  1053. ATQ_ENDPOINT_BMON::~ATQ_ENDPOINT_BMON(
  1054. VOID
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. ATQ_ENDPOINT_BMON destructor. Kill the scheduled work item if there
  1059. Arguments:
  1060. None
  1061. Return Values:
  1062. None
  1063. --*/
  1064. {
  1065. if ( m_dwForceCookie )
  1066. {
  1067. RemoveWorkItem( m_dwForceCookie );
  1068. m_dwForceCookie = 0;
  1069. }
  1070. }