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.

1063 lines
24 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. aap.cxx
  7. This module contains implementation of the Asynchronous Accept Pool
  8. package.
  9. Functions exported by this module:
  10. AapInitialize
  11. AapTerminate
  12. AapAcquire
  13. AapRelease
  14. AapAccept
  15. AapAbort
  16. FILE HISTORY:
  17. KeithMo 01-Mar-1995 Created.
  18. */
  19. #include "ftpdp.hxx"
  20. //
  21. // Private constants.
  22. //
  23. #define MAX_IDLE_THREADS 10
  24. #define AapLockLists() EnterCriticalSection( &p_AapListLock )
  25. #define AapUnlockLists() LeaveCriticalSection( &p_AapListLock )
  26. //
  27. // Private types.
  28. //
  29. typedef enum _AAP_STATE
  30. {
  31. AapStateFirst = -1, // Must be first aap state!
  32. AapStateIdle, // Idle.
  33. AapStateActive, // Waiting for incoming connection.
  34. AapStateAbort, // Aborting, return to idle.
  35. AapStateShutdown, // Shutting down.
  36. AapStateLast // Must be last aap state!
  37. } AAP_STATE;
  38. #define IS_VALID_AAP_STATE(x) (((x) > AapStateFirst) && ((x) < AapStateLast))
  39. typedef struct _AAP_CONTEXT
  40. {
  41. //
  42. // Structure signature, for safety's sake.
  43. //
  44. DEBUG_SIGNATURE
  45. //
  46. // Links onto a list of idle/active contexts.
  47. //
  48. LIST_ENTRY ContextList;
  49. //
  50. // Current state.
  51. //
  52. AAP_STATE State;
  53. //
  54. // The listening socket.
  55. //
  56. SOCKET ListeningSocket;
  57. //
  58. // An event object for synchronizing with the worker thread.
  59. //
  60. HANDLE EventHandle;
  61. //
  62. // A handle to the worker thread for synchronizing shutdown.
  63. //
  64. HANDLE ThreadHandle;
  65. //
  66. // The callback associated with this context.
  67. //
  68. LPAAP_CALLBACK AapCallback;
  69. //
  70. // A user-definable context.
  71. //
  72. LPVOID UserContext;
  73. } AAP_CONTEXT, * LPAAP_CONTEXT;
  74. #if DBG
  75. #define AAP_SIGNATURE (DWORD)'cPaA'
  76. #define AAP_SIGNATURE_X (DWORD)'paaX'
  77. #define INIT_AAP_SIG(p) ((p)->Signature = AAP_SIGNATURE)
  78. #define KILL_AAP_SIG(p) ((p)->Signature = AAP_SIGNATURE_X)
  79. #define IS_VALID_AAP_CONTEXT(p) (((p) != NULL) && ((p)->Signature == AAP_SIGNATURE))
  80. #else // !DBG
  81. #define INIT_AAP_SIG(p) ((void)(p))
  82. #define KILL_AAP_SIG(p) ((void)(p))
  83. #define IS_VALID_AAP_CONTEXT(p) (((void)(p)), TRUE)
  84. #endif // DBG
  85. //
  86. // Private globals.
  87. //
  88. LIST_ENTRY p_AapIdleList;
  89. LIST_ENTRY p_AapActiveList;
  90. CRITICAL_SECTION p_AapListLock;
  91. DWORD p_AapIdleCount;
  92. //
  93. // Private prototypes.
  94. //
  95. LPAAP_CONTEXT
  96. AappCreateContext(
  97. VOID
  98. );
  99. VOID
  100. AappFreeResources(
  101. LPAAP_CONTEXT AapContext
  102. );
  103. DWORD
  104. AappWorkerThread(
  105. LPVOID Param
  106. );
  107. //
  108. // Public functions.
  109. //
  110. /*******************************************************************
  111. NAME: AapInitialize
  112. SYNOPSIS: Initializes the AAP package.
  113. EXIT: APIERR - 0 if successful, !0 if not.
  114. HISTORY:
  115. KeithMo 01-Mar-1995 Created.
  116. ********************************************************************/
  117. APIERR
  118. AapInitialize(
  119. VOID
  120. )
  121. {
  122. IF_DEBUG( AAP )
  123. {
  124. DBGPRINTF(( DBG_CONTEXT,
  125. "in AapInitialize\n" ));
  126. }
  127. //
  128. // Initialize the critical section.
  129. //
  130. INITIALIZE_CRITICAL_SECTION( &p_AapListLock );
  131. //
  132. // Initialize the worker lists.
  133. //
  134. InitializeListHead( &p_AapIdleList );
  135. InitializeListHead( &p_AapActiveList );
  136. p_AapIdleCount = 0;
  137. //
  138. // Success!
  139. //
  140. return 0;
  141. } // AapInitialize
  142. /*******************************************************************
  143. NAME: AapTerminate
  144. SYNOPSIS: Terminates the AAP package.
  145. HISTORY:
  146. KeithMo 01-Mar-1995 Created.
  147. ********************************************************************/
  148. VOID
  149. AapTerminate(
  150. VOID
  151. )
  152. {
  153. PLIST_ENTRY Entry;
  154. IF_DEBUG( AAP )
  155. {
  156. DBGPRINTF(( DBG_CONTEXT,
  157. "in AapTerminate\n" ));
  158. }
  159. //
  160. // Lock the lists.
  161. //
  162. AapLockLists();
  163. //
  164. // Scan the idle list and blow them away.
  165. //
  166. Entry = p_AapIdleList.Flink;
  167. while( Entry != &p_AapIdleList )
  168. {
  169. LPAAP_CONTEXT AapContext;
  170. AapContext = CONTAINING_RECORD( Entry, AAP_CONTEXT, ContextList );
  171. Entry = Entry->Flink;
  172. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapContext ) );
  173. DBG_ASSERT( AapContext->State == AapStateIdle );
  174. IF_DEBUG( AAP )
  175. {
  176. DBGPRINTF(( DBG_CONTEXT,
  177. "AapTerminate: killing idle context @ %08lX\n",
  178. AapContext ));
  179. }
  180. //
  181. // Set the state to closing so the thread will know to exit.
  182. //
  183. AapContext->State = AapStateShutdown;
  184. //
  185. // Signal the event to wake up the thread.
  186. //
  187. DBG_ASSERT( AapContext->EventHandle != NULL );
  188. TCP_REQUIRE( SetEvent( AapContext->EventHandle ) );
  189. }
  190. //
  191. // Scan the active list and blow them away.
  192. //
  193. Entry = p_AapActiveList.Flink;
  194. while( Entry != &p_AapActiveList )
  195. {
  196. LPAAP_CONTEXT AapContext;
  197. SOCKET Socket;
  198. AapContext = CONTAINING_RECORD( Entry, AAP_CONTEXT, ContextList );
  199. Entry = Entry->Flink;
  200. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapContext ) );
  201. DBG_ASSERT( AapContext->State == AapStateActive );
  202. IF_DEBUG( AAP )
  203. {
  204. DBGPRINTF(( DBG_CONTEXT,
  205. "AapTerminate: killing active context @ %08lX\n",
  206. AapContext ));
  207. }
  208. //
  209. // Set the state to closing so the thread will know to exit.
  210. //
  211. AapContext->State = AapStateShutdown;
  212. //
  213. // Close the listening socket to wake up the thread.
  214. //
  215. Socket = AapContext->ListeningSocket;
  216. DBG_ASSERT( Socket != INVALID_SOCKET );
  217. AapContext->ListeningSocket = INVALID_SOCKET;
  218. TCP_REQUIRE( closesocket( Socket ) == 0 );
  219. DBG_ASSERT( AapContext->EventHandle != NULL );
  220. TCP_REQUIRE( SetEvent( AapContext->EventHandle ) );
  221. }
  222. //
  223. // Wait for the worker threads to exit. Note that the list
  224. // lock is currently held.
  225. //
  226. for( ; ; )
  227. {
  228. LPAAP_CONTEXT AapContext;
  229. //
  230. // Find a thread to wait on. If both lists are empty,
  231. // then we're done.
  232. //
  233. if( IsListEmpty( &p_AapIdleList ) )
  234. {
  235. if( IsListEmpty( &p_AapActiveList ) )
  236. {
  237. break;
  238. }
  239. AapContext = CONTAINING_RECORD( p_AapActiveList.Flink,
  240. AAP_CONTEXT,
  241. ContextList );
  242. }
  243. else
  244. {
  245. AapContext = CONTAINING_RECORD( p_AapIdleList.Flink,
  246. AAP_CONTEXT,
  247. ContextList );
  248. }
  249. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapContext ) );
  250. DBG_ASSERT( AapContext->State == AapStateShutdown );
  251. //
  252. // Unlock the lists, wait for the thread to exit, then
  253. // relock the lists.
  254. //
  255. AapUnlockLists();
  256. WaitForSingleObject( AapContext->ThreadHandle, INFINITE );
  257. AapLockLists();
  258. //
  259. // Note that worker threads will neither close their thread
  260. // handles nor free their AAP_CONTEXT structures during shutdown.
  261. // This is our responsibility.
  262. //
  263. AappFreeResources( AapContext );
  264. }
  265. DBG_ASSERT( p_AapIdleCount == 0 );
  266. //
  267. // Unlock the lists.
  268. //
  269. AapUnlockLists();
  270. } // AapTerminate
  271. /*******************************************************************
  272. NAME: AapAcquire
  273. SYNOPSIS: Acquires an AAP socket/thread pair for a future
  274. asynchronous accept request.
  275. ENTRY: AapCallback - Pointer to a callback function to be
  276. invoked when the accept() completes.
  277. UserContext - An uninterpreted context value passed
  278. into the callback.
  279. EXIT: AAP_HANDLE - A valid AAP handle if !NULL, NULL if
  280. an error occurred.
  281. HISTORY:
  282. KeithMo 01-Mar-1995 Created.
  283. ********************************************************************/
  284. AAP_HANDLE
  285. AapAcquire(
  286. LPAAP_CALLBACK AapCallback,
  287. LPVOID UserContext
  288. )
  289. {
  290. PLIST_ENTRY Entry;
  291. LPAAP_CONTEXT AapContext;
  292. //
  293. // Sanity check.
  294. //
  295. DBG_ASSERT( AapCallback != NULL );
  296. IF_DEBUG( AAP )
  297. {
  298. DBGPRINTF(( DBG_CONTEXT,
  299. "AapAcquire: callback @ %08lX, context = %08lX\n",
  300. AapCallback,
  301. UserContext ));
  302. }
  303. //
  304. // See if there's something available on the idle list.
  305. //
  306. AapLockLists();
  307. if( !IsListEmpty( &p_AapIdleList ) )
  308. {
  309. Entry = RemoveHeadList( &p_AapIdleList );
  310. AapContext = CONTAINING_RECORD( Entry, AAP_CONTEXT, ContextList );
  311. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapContext ) );
  312. DBG_ASSERT( AapContext->State == AapStateIdle );
  313. DBG_ASSERT( p_AapIdleCount > 0 );
  314. p_AapIdleCount--;
  315. IF_DEBUG( AAP )
  316. {
  317. DBGPRINTF(( DBG_CONTEXT,
  318. "AapAcquire: got idle context @ %08lX\n",
  319. AapContext ));
  320. }
  321. }
  322. else
  323. {
  324. //
  325. // Create a new one.
  326. //
  327. AapContext = AappCreateContext();
  328. }
  329. if( AapContext != NULL )
  330. {
  331. //
  332. // Initialize it.
  333. //
  334. AapContext->AapCallback = AapCallback;
  335. AapContext->UserContext = UserContext;
  336. AapContext->State = AapStateActive;
  337. //
  338. // Put it on the active list.
  339. //
  340. InsertHeadList( &p_AapActiveList, &AapContext->ContextList );
  341. }
  342. //
  343. // Unlock the lists & return the (potentially NULL) context.
  344. //
  345. AapUnlockLists();
  346. IF_DEBUG( AAP )
  347. {
  348. DBGPRINTF(( DBG_CONTEXT,
  349. "AapAcquire: returning context @ %08lX\n",
  350. AapContext ));
  351. }
  352. return AapContext;
  353. } // AapAcquire
  354. /*******************************************************************
  355. NAME: AapRelease
  356. SYNOPSIS: Releases an open AAP handle and makes the associated
  357. socket/thread pair available for use.
  358. ENTRY: AapHandle - A valid AAP handle returned by AapAcquire().
  359. After this API completes, the handle is no longer
  360. valid.
  361. HISTORY:
  362. KeithMo 01-Mar-1995 Created.
  363. ********************************************************************/
  364. VOID
  365. AapRelease(
  366. AAP_HANDLE AapHandle
  367. )
  368. {
  369. //
  370. // Sanity check.
  371. //
  372. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapHandle ) );
  373. DBG_ASSERT( AapHandle->State == AapStateActive );
  374. IF_DEBUG( AAP )
  375. {
  376. DBGPRINTF(( DBG_CONTEXT,
  377. "AapRelease: releasing context @ %08lX\n",
  378. AapHandle ));
  379. }
  380. //
  381. // Lock the lists.
  382. //
  383. AapLockLists();
  384. //
  385. // let it decide how to handle this.
  386. //
  387. AapHandle->State = AapStateAbort;
  388. DBG_ASSERT( AapHandle->EventHandle != NULL );
  389. TCP_REQUIRE( SetEvent( AapHandle->EventHandle ) );
  390. //
  391. // Unlock the lists.
  392. //
  393. AapUnlockLists();
  394. } // AapRelease
  395. /*******************************************************************
  396. NAME: AapAccept
  397. SYNOPSIS: Initiates an accept(). The callback associated with
  398. the AAP handle will be invoked when the accept()
  399. completes.
  400. ENTRY: AapHandle - A valid AAP handle returned by AapAcquire().
  401. EXIT: APIERR - 0 if successful, !0 if not.
  402. HISTORY:
  403. KeithMo 01-Mar-1995 Created.
  404. ********************************************************************/
  405. APIERR
  406. AapAccept(
  407. AAP_HANDLE AapHandle
  408. )
  409. {
  410. //
  411. // Sanity check.
  412. //
  413. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapHandle ) );
  414. DBG_ASSERT( AapHandle->State == AapStateActive );
  415. IF_DEBUG( AAP )
  416. {
  417. DBGPRINTF(( DBG_CONTEXT,
  418. "AapAccept: context @ %08lX\n",
  419. AapHandle ));
  420. }
  421. //
  422. // Release the worker thread.
  423. //
  424. TCP_REQUIRE( SetEvent( AapHandle->EventHandle ) );
  425. return 0;
  426. } // AapAccept
  427. /*******************************************************************
  428. NAME: AapAbort
  429. SYNOPSIS: Aborts a pending accept().
  430. ENTRY: AapHandle - A valid AAP handle returned by AapAcquire().
  431. EXIT: APIERR - 0 if successful, !0 if not.
  432. HISTORY:
  433. KeithMo 01-Mar-1995 Created.
  434. ********************************************************************/
  435. APIERR
  436. AapAbort(
  437. AAP_HANDLE AapHandle
  438. )
  439. {
  440. //
  441. // Sanity check.
  442. //
  443. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapHandle ) );
  444. DBG_ASSERT( AapHandle->State == AapStateActive );
  445. IF_DEBUG( AAP )
  446. {
  447. DBGPRINTF(( DBG_CONTEXT,
  448. "AapAbort: context @ %08lX\n",
  449. AapHandle ));
  450. }
  451. //
  452. // Just zap the listening handle. The worker thread will clean
  453. // up after itself.
  454. //
  455. TCP_REQUIRE( closesocket( AapHandle->ListeningSocket ) == 0 );
  456. return 0;
  457. } // AapAbort
  458. //
  459. // Private functions.
  460. //
  461. /*******************************************************************
  462. NAME: AappCreateContext
  463. SYNOPSIS: Creates a new AAP context, including the associated
  464. thread, socket, and synchronization objects.
  465. RETURNS: LPAAP_CONTEXT - The newly created context if successful,
  466. NULL otherwise.
  467. HISTORY:
  468. KeithMo 01-Mar-1995 Created.
  469. ********************************************************************/
  470. LPAAP_CONTEXT
  471. AappCreateContext(
  472. VOID
  473. )
  474. {
  475. LPAAP_CONTEXT AapContext;
  476. SOCKADDR_IN LocalAddress;
  477. DWORD ThreadId;
  478. //
  479. // Create the context structure.
  480. //
  481. AapContext = (LPAAP_CONTEXT)TCP_ALLOC( sizeof(AAP_CONTEXT) );
  482. if( AapContext == NULL )
  483. {
  484. DBGERROR(( DBG_CONTEXT,
  485. "AappCreateContext: allocation failure\n" ));
  486. goto FatalExit0;
  487. }
  488. RtlZeroMemory( AapContext, sizeof(AAP_CONTEXT) );
  489. INIT_AAP_SIG( AapContext );
  490. //
  491. // Create the listening socket.
  492. //
  493. AapContext->ListeningSocket = socket( AF_INET, SOCK_STREAM, 0 );
  494. if( AapContext->ListeningSocket == INVALID_SOCKET)
  495. {
  496. DBGERROR(( DBG_CONTEXT,
  497. "AappCreateContext: socket() failure %d\n",
  498. WSAGetLastError() ));
  499. goto FatalExit1;
  500. }
  501. LocalAddress.sin_family = AF_INET;
  502. LocalAddress.sin_port = 0;
  503. LocalAddress.sin_addr.s_addr = 0;
  504. if( bind( AapContext->ListeningSocket,
  505. (LPSOCKADDR)&LocalAddress,
  506. sizeof(LocalAddress) ) != 0 )
  507. {
  508. DBGERROR(( DBG_CONTEXT,
  509. "AappCreateContext: bind() failure %d\n",
  510. WSAGetLastError() ));
  511. goto FatalExit2;
  512. }
  513. if( listen( AapContext->ListeningSocket, 2 ) != 0 )
  514. {
  515. DBGERROR(( DBG_CONTEXT,
  516. "AappCreateContext: listen() failure %d\n",
  517. WSAGetLastError() ));
  518. goto FatalExit2;
  519. }
  520. //
  521. // Create the event object.
  522. //
  523. AapContext->EventHandle = CreateEvent( NULL, // lpEventAttributes
  524. FALSE, // bManualReset
  525. FALSE, // bInitialState
  526. NULL ); // lpName
  527. if( AapContext->EventHandle == NULL )
  528. {
  529. DBGWARN(( DBG_CONTEXT,
  530. "AappCreateContext: CreateEvent() failure %d\n",
  531. GetLastError() ));
  532. goto FatalExit2;
  533. }
  534. //
  535. // Create the worker thread.
  536. //
  537. AapContext->ThreadHandle = CreateThread( NULL, // lpsa
  538. 0, // cbStack
  539. AappWorkerThread, // lpStartAddr
  540. AapContext, // lpvThreadParm
  541. 0, // fdwCreate
  542. &ThreadId ); // lpIDThread
  543. if( AapContext->ThreadHandle == NULL )
  544. {
  545. DBGPRINTF(( DBG_CONTEXT,
  546. "AappCreateContext: CreateThread() failure %d\n",
  547. GetLastError() ));
  548. goto FatalExit3;
  549. }
  550. //
  551. // Success!
  552. //
  553. return AapContext;
  554. //
  555. // Cleanup from various levels of fatal error.
  556. //
  557. FatalExit3:
  558. CloseHandle( AapContext->EventHandle );
  559. FatalExit2:
  560. closesocket( AapContext->ListeningSocket );
  561. FatalExit1:
  562. TCP_FREE( AapContext );
  563. FatalExit0:
  564. return NULL;
  565. } // AappCreateContext
  566. /*******************************************************************
  567. NAME: AappFreeResources
  568. SYNOPSIS: Frees the system resources associated with a given
  569. AAP_CONTEXT structure, then frees the structure
  570. itself.
  571. NOTE: This routine MUST be called with the list lock
  572. held!
  573. ENTRY: AapContext - The AAP_CONTEXT structure to free.
  574. HISTORY:
  575. KeithMo 01-Mar-1995 Created.
  576. ********************************************************************/
  577. VOID
  578. AappFreeResources(
  579. LPAAP_CONTEXT AapContext
  580. )
  581. {
  582. //
  583. // Sanity check.
  584. //
  585. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapContext ) );
  586. IF_DEBUG( AAP )
  587. {
  588. DBGWARN(( DBG_CONTEXT,
  589. "AappFreeResource: context @ %08lX\n",
  590. AapContext ));
  591. }
  592. //
  593. // Close the thread handle if open.
  594. //
  595. if( AapContext->ThreadHandle != NULL )
  596. {
  597. CloseHandle( AapContext->ThreadHandle );
  598. }
  599. //
  600. // Remove this structure from the list.
  601. //
  602. RemoveEntryList( &AapContext->ContextList );
  603. //
  604. // Free the structure.
  605. //
  606. KILL_AAP_SIG( AapContext );
  607. TCP_FREE( AapContext );
  608. } // AappFreeResources
  609. /*******************************************************************
  610. NAME: AappWorkerThread
  611. SYNOPSIS: Worker thread for accept()ing incoming connections.
  612. ENTRY: Param - Actually the LPAAP_CONTEXT structure for this
  613. thread.
  614. RETURNS: DWORD - Thread exit code (ignored).
  615. HISTORY:
  616. KeithMo 01-Mar-1995 Created.
  617. ********************************************************************/
  618. DWORD
  619. AappWorkerThread(
  620. LPVOID Param
  621. )
  622. {
  623. LPAAP_CONTEXT AapContext;
  624. AAP_STATE AapState;
  625. LPAAP_CALLBACK AapCallback;
  626. LPVOID UserContext;
  627. DWORD WaitResult;
  628. BOOL CallbackResult;
  629. SOCKET ListeningSocket;
  630. SOCKET AcceptedSocket;
  631. SOCKERR SocketStatus;
  632. INT RemoteAddressLength;
  633. SOCKADDR_IN RemoteAddress;
  634. //
  635. // Grab the context structure.
  636. //
  637. AapContext = (LPAAP_CONTEXT)Param;
  638. DBG_ASSERT( IS_VALID_AAP_CONTEXT( AapContext ) );
  639. IF_DEBUG( AAP )
  640. {
  641. DBGPRINTF(( DBG_CONTEXT,
  642. "AappWorkerThread: starting, context @ %08lX\n",
  643. AapContext ));
  644. }
  645. //
  646. // Capture some fields from the structure.
  647. //
  648. AapCallback = AapContext->AapCallback;
  649. UserContext = AapContext->UserContext;
  650. ListeningSocket = AapContext->ListeningSocket;
  651. //
  652. // Loop forever, or at least until we're told to shutdown.
  653. //
  654. for( ; ; )
  655. {
  656. //
  657. // Wait for a request.
  658. //
  659. WaitResult = WaitForSingleObject( AapContext->EventHandle,
  660. INFINITE );
  661. if( WaitResult != WAIT_OBJECT_0 )
  662. {
  663. DBGWARN(( DBG_CONTEXT,
  664. "AappWorkerThread: wait failure %lu : %d\n",
  665. WaitResult,
  666. GetLastError() ));
  667. break;
  668. }
  669. //
  670. // Check our state.
  671. //
  672. AapLockLists();
  673. AapState = AapContext->State;
  674. AapUnlockLists();
  675. if( AapState == AapStateShutdown )
  676. {
  677. IF_DEBUG( AAP )
  678. {
  679. DBGPRINTF(( DBG_CONTEXT,
  680. "AappWorkerThread: context @ %08lX state == %d, exiting\n",
  681. AapContext,
  682. AapState ));
  683. }
  684. break;
  685. }
  686. for( ; ; )
  687. {
  688. //
  689. // Wait for an incoming connection.
  690. //
  691. RemoteAddressLength = sizeof(RemoteAddress);
  692. AcceptedSocket = accept( ListeningSocket,
  693. (LPSOCKADDR)&RemoteAddress,
  694. &RemoteAddressLength );
  695. SocketStatus = ( AcceptedSocket == INVALID_SOCKET )
  696. ? WSAGetLastError()
  697. : 0;
  698. IF_DEBUG( AAP )
  699. {
  700. if( SocketStatus != 0 )
  701. {
  702. DBGERROR(( DBG_CONTEXT,
  703. "AappWorkerThread: accept() failure %d\n",
  704. SocketStatus ));
  705. }
  706. }
  707. //
  708. // Invoke the callback.
  709. //
  710. IF_DEBUG( AAP )
  711. {
  712. DBGPRINTF(( DBG_CONTEXT,
  713. "AappWorkerThread: context @ %08lX calling %08lX[%08lX]\n",
  714. AapContext,
  715. AapCallback,
  716. UserContext ));
  717. }
  718. CallbackResult = AapCallback( UserContext,
  719. SocketStatus,
  720. AcceptedSocket,
  721. (LPSOCKADDR)&RemoteAddress,
  722. RemoteAddressLength );
  723. //
  724. // If the callback returned FALSE (indicating that it wants no
  725. // further callbacks) OR if the accept() failed for any reason,
  726. // then exit the accept() loop.
  727. //
  728. if( !CallbackResult || ( SocketStatus != 0 ) )
  729. {
  730. break;
  731. }
  732. }
  733. //
  734. // If we hit a socket error, then bail.
  735. //
  736. if( SocketStatus != 0 )
  737. {
  738. IF_DEBUG( AAP )
  739. {
  740. DBGWARN(( DBG_CONTEXT,
  741. "AappWorkerThread: context @ %08lX, exiting\n",
  742. AapContext ));
  743. }
  744. break;
  745. }
  746. //
  747. // If we haven't exhausted the idle thread quota, then add
  748. // ourselves to the idle list. Otherwise, exit the main
  749. // processing loop & terminate this thread.
  750. //
  751. AapLockLists();
  752. if( ( AapContext->State == AapStateShutdown ) ||
  753. ( p_AapIdleCount >= MAX_IDLE_THREADS ) )
  754. {
  755. AapUnlockLists();
  756. break;
  757. }
  758. RemoveEntryList( &AapContext->ContextList );
  759. AapContext->State = AapStateIdle;
  760. InsertHeadList( &p_AapIdleList, &AapContext->ContextList );
  761. p_AapIdleCount++;
  762. IF_DEBUG( AAP )
  763. {
  764. DBGPRINTF(( DBG_CONTEXT,
  765. "AappWorkerThread: context @ %08lX put on idle list\n",
  766. AapContext ));
  767. }
  768. AapUnlockLists();
  769. }
  770. //
  771. // We only make it this far if it's time to die.
  772. //
  773. AapLockLists();
  774. if( AapContext->State != AapStateShutdown )
  775. {
  776. TCP_REQUIRE( CloseHandle( AapContext->EventHandle ) );
  777. TCP_REQUIRE( CloseHandle( AapContext->ThreadHandle ) );
  778. TCP_REQUIRE( closesocket( AapContext->ListeningSocket ) == 0 );
  779. AappFreeResources( AapContext );
  780. }
  781. AapUnlockLists();
  782. return 0;
  783. } // AappWorkerThread