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.

2230 lines
61 KiB

  1. /*++
  2. Copyright (c) 1994-1996 Microsoft Corporation
  3. Module Name :
  4. atqsupp.cxx
  5. Abstract:
  6. Contains internal support routines for the ATQ package
  7. From atqnew.c
  8. Author:
  9. Murali R. Krishnan (MuraliK) 02-Apr-1996
  10. Project:
  11. Internet Server Common DLL
  12. --*/
  13. #include "isatq.hxx"
  14. #include <iscaptrc.h>
  15. DWORD AtqPoolThread( LPDWORD param );
  16. extern PBANDWIDTH_INFO g_pBandwidthInfo;
  17. extern DWORD IISCapTraceFlag;
  18. extern TRACEHANDLE IISCapTraceLoggerHandle;
  19. DWORD g_fAlwaysReuseSockets = FALSE;
  20. /************************************************************
  21. * Functions for ATQ_CONTEXT
  22. ************************************************************/
  23. PATQ_CONT
  24. I_AtqAllocContextFromCache( VOID);
  25. VOID
  26. I_AtqFreeContextToCache(
  27. IN PATQ_CONT pAtqContext,
  28. IN BOOL UnlinkContext
  29. );
  30. PATQ_CONT
  31. I_AtqAllocContextFromCache( VOID)
  32. /*++
  33. This function attempts to allocate an ATQ context from the allocation cache.
  34. It then initializes the state information in the ATQ context object and
  35. returns the context on success.
  36. Arguments:
  37. None
  38. Returns:
  39. On success a valid pointer to ATQ_CONT. Otherwise NULL.
  40. --*/
  41. {
  42. PATQ_CONT pAtqContext;
  43. DBG_ASSERT( NULL != g_pachAtqContexts);
  44. pAtqContext = (ATQ_CONTEXT * ) g_pachAtqContexts->Alloc();
  45. if ( NULL != pAtqContext ) {
  46. //
  47. // Make sure everything is zeroed out so there is
  48. // no crud from previous use.
  49. //
  50. memset(pAtqContext, 0, sizeof(ATQ_CONTEXT));
  51. pAtqContext->ContextList =
  52. &AtqActiveContextList[(++AtqGlobalContextCount %
  53. g_dwNumContextLists)];
  54. pAtqContext->Signature = ATQ_CONTEXT_SIGNATURE;
  55. }
  56. return (pAtqContext);
  57. } // I_AtqAllocContextFromCache()
  58. VOID
  59. I_AtqFreeContextToCache(
  60. IN PATQ_CONT pAtqContext
  61. )
  62. /*++
  63. This function releases the given context to the allocation cache.
  64. Arguments:
  65. pAtqContext pointer to the ATQ_CONTEXT that is being freed.
  66. Returns:
  67. None
  68. Issues:
  69. This function also performs some other cleanup specific to AtqContexts.
  70. --*/
  71. {
  72. #if 0
  73. ATQ_PRINTF(( DBG_CONTEXT,
  74. "[I_AtqFreeCtxtToCache] Freed up %08x\n",
  75. pAtqContext
  76. ));
  77. #endif
  78. DBG_ASSERT( pAtqContext->Signature == ATQ_FREE_CONTEXT_SIGNATURE);
  79. DBG_ASSERT( pAtqContext->lSyncTimeout ==0);
  80. DBG_ASSERT( pAtqContext->m_nIO ==0);
  81. DBG_ASSERT( pAtqContext->m_acFlags == 0);
  82. DBG_ASSERT( pAtqContext->m_acState == 0);
  83. DBG_ASSERT( pAtqContext->m_leTimeout.Flink == NULL);
  84. DBG_ASSERT( pAtqContext->m_leTimeout.Blink == NULL);
  85. DBG_ASSERT( pAtqContext->pvBuff == NULL);
  86. DBG_ASSERT( pAtqContext->pEndpoint == NULL);
  87. DBG_ASSERT( pAtqContext->hAsyncIO == NULL);
  88. DBG_REQUIRE( g_pachAtqContexts->Free( pAtqContext));
  89. return;
  90. } // I_AtqFreeContextToCache
  91. void
  92. ATQ_CONTEXT::Print( void) const
  93. {
  94. DBGPRINTF(( DBG_CONTEXT,
  95. " ATQ_CONTEXT (%08x)\n"
  96. "\thAsyncIO = %p Signature = %08lx\n"
  97. "\tOverlapped.Internal = %p Overlapped.Offset= %08lx\n"
  98. "\tm_leTimeout.Flink = %p m_leTimeout.Blink= %p\n"
  99. "\tClientContext = %p ContextList = %p\n"
  100. "\tpfnCompletion = %p ()\n"
  101. "\tpEndPoint = %p fAcceptExContext = %s\n"
  102. "\tlSyncTimeout = %8d fInTimeout = %s\n"
  103. "\tTimeOut = %08lx NextTimeout = %08lx\n"
  104. "\tBytesSent = %d (0x%08lx)\n"
  105. "\tpvBuff = %p JraAsyncIo = %p\n"
  106. "\tfConnectionIndicated= %s fBlocked = %8lx\n"
  107. "\tState = %8lx Flags = %8lx\n",
  108. this,
  109. hAsyncIO,
  110. Signature,
  111. Overlapped.Internal,
  112. Overlapped.Offset,
  113. m_leTimeout.Flink,
  114. m_leTimeout.Blink,
  115. ClientContext,
  116. ContextList,
  117. pfnCompletion,
  118. pEndpoint,
  119. (IsAcceptExRootContext() ? "TRUE" : "FALSE"),
  120. lSyncTimeout,
  121. (IsFlag( ACF_IN_TIMEOUT) ? "TRUE" : "FALSE"),
  122. TimeOut,
  123. NextTimeout,
  124. BytesSent,
  125. BytesSent,
  126. pvBuff,
  127. hJraAsyncIO,
  128. (IsFlag( ACF_CONN_INDICATED) ? "TRUE" : "FALSE"),
  129. IsBlocked(),
  130. m_acState, m_acFlags
  131. ));
  132. // Print the buffer if necessary.
  133. return;
  134. } // ATQ_CONTEXT::Print()
  135. VOID
  136. ATQ_CONTEXT::HardCloseSocket( VOID)
  137. /*++
  138. Description:
  139. This socket closes the socket by forcibly calling closesocket() on
  140. the socket. This function is used during the endpoint shutdown
  141. stage for an atq context
  142. Arguments:
  143. None
  144. Returns:
  145. None
  146. --*/
  147. {
  148. HANDLE haio = (HANDLE )
  149. InterlockedExchangePointer( (PVOID *)&hAsyncIO, NULL );
  150. DBG_ASSERT( IsState( ACS_SOCK_LISTENING) ||
  151. IsState( ACS_SOCK_CONNECTED) ||
  152. IsState( ACS_SOCK_CLOSED) ||
  153. IsState( ACS_SOCK_UNCONNECTED)
  154. );
  155. MoveState( ACS_SOCK_CLOSED);
  156. //
  157. // Let us do a hard close on the socket (handle).
  158. // This should generate an IO completion which will free this
  159. // ATQ context
  160. //
  161. if ( (haio != NULL) &&
  162. (closesocket( HANDLE_TO_SOCKET(haio) ) == SOCKET_ERROR)
  163. ) {
  164. ATQ_PRINTF(( DBG_CONTEXT,
  165. "Warning - "
  166. " Context=%08x closesocket failed,"
  167. " error %d, socket = %x\n",
  168. this,
  169. GetLastError(),
  170. haio ));
  171. Print();
  172. }
  173. return;
  174. } // ATQ_CONTEXT::HardCloseSocket()
  175. VOID
  176. ATQ_CONTEXT::InitWithDefaults(
  177. IN ATQ_COMPLETION pfnCompletion,
  178. IN DWORD TimeOut,
  179. IN HANDLE hAsyncIO
  180. )
  181. {
  182. DBG_ASSERT( this->Signature == ATQ_CONTEXT_SIGNATURE);
  183. this->InitTimeoutListEntry();
  184. this->Signature = ATQ_CONTEXT_SIGNATURE;
  185. // start life at 1. This ref count will be freed up by AtqFreeContext()
  186. this->m_nIO = 1;
  187. this->pfnCompletion = pfnCompletion;
  188. this->TimeOut = TimeOut;
  189. this->TimeOutScanID = 0;
  190. this->lSyncTimeout = 0;
  191. this->hAsyncIO = hAsyncIO;
  192. this->hJraAsyncIO = (ULONG_PTR)hAsyncIO | 0x80000000;
  193. this->m_acState = 0;
  194. this->m_acFlags = 0;
  195. // Initialize pbandwidthinfo to point to global object
  196. this->m_pBandwidthInfo = g_pBandwidthInfo;
  197. ZeroMemory(
  198. &this->Overlapped,
  199. sizeof( this->Overlapped )
  200. );
  201. DBG_ASSERT( this->lSyncTimeout == 0);
  202. //
  203. // Following added for bandwidth throttling purposes
  204. //
  205. DBG_ASSERT( !this->IsBlocked());
  206. this->arInfo.atqOp = AtqIoNone;
  207. this->arInfo.lpOverlapped = NULL;
  208. // bandwidth throttling initialization ends here.
  209. //
  210. // Should we force socket closure?
  211. //
  212. this->m_fForceClose = FALSE;
  213. } // ATQ_CONTEXT::InitWithDefaults()
  214. VOID
  215. ATQ_CONTEXT::InitNonAcceptExState(
  216. IN PVOID pClientContext
  217. )
  218. {
  219. //
  220. // Note that if we're not using AcceptEx, then we consider the client
  221. // to have been notified externally (thus ACF_CONN_INDICATED is set).
  222. // Also we set the next timeout to be infinite, which may be reset
  223. // when the next IO is submitted.
  224. //
  225. this->NextTimeout = ATQ_INFINITE;
  226. this->ClientContext = pClientContext;
  227. this->pEndpoint = NULL;
  228. this->SetFlag( ACF_CONN_INDICATED);
  229. this->SetState( ACS_SOCK_CONNECTED);
  230. this->ResetFlag( ACF_ACCEPTEX_ROOT_CONTEXT);
  231. //
  232. // Insert this into the active list - since this is a non-acceptex socket
  233. //
  234. DBG_ASSERT( this->ContextList != NULL);
  235. this->ContextList->InsertIntoActiveList( &this->m_leTimeout );
  236. return;
  237. } // ATQ_CONTEXT::InitNonAcceptExState()
  238. VOID
  239. ATQ_CONTEXT::InitAcceptExState(
  240. IN DWORD NextTimeOut
  241. )
  242. {
  243. this->NextTimeout = NextTimeOut;
  244. this->ClientContext = NULL;
  245. this->lSyncTimeout = 0;
  246. this->ResetFlag( ACF_CONN_INDICATED);
  247. this->SetState( ACS_SOCK_LISTENING);
  248. //
  249. // Add it to the pending accept ex list
  250. //
  251. DBG_ASSERT( this->ContextList != NULL);
  252. this->ContextList->InsertIntoPendingList( &this->m_leTimeout);
  253. return;
  254. } // ATQ_CONTEXT::InitAcceptExState()
  255. BOOL
  256. ATQ_CONTEXT::PrepareAcceptExContext(
  257. PATQ_ENDPOINT pEndpoint
  258. )
  259. /*++
  260. Routine Description:
  261. Initializes the state for completely initializing the state and
  262. hence prepares the context for AcceptEx
  263. It expects the caller to send a AtqContext with certain characteristics
  264. 1) this is not NULL
  265. 2) this->pvBuff has valid values
  266. In the case of failure, caller should call
  267. pAtqContext->CleanupAndRelese() to free the memory associated with
  268. this object.
  269. Arguments:
  270. pEndpoint - pointer to endpoint object for this context
  271. Return Value:
  272. TRUE if successful, FALSE on error (call GetLastError)
  273. The caller should free the object on a failure.
  274. --*/
  275. {
  276. DBG_ASSERT( g_fUseAcceptEx); // only support AcceptEx() cases
  277. DBG_ASSERT( pEndpoint != NULL);
  278. DBG_ASSERT( this != NULL);
  279. DBG_ASSERT( this->pvBuff != NULL);
  280. //
  281. // Make sure that we are adding a AcceptEx() version of AtqContext
  282. //
  283. DBG_ASSERT( pEndpoint->ConnectExCompletion != NULL);
  284. DBG_ASSERT( pEndpoint->UseAcceptEx);
  285. //
  286. // Fill out the context. We set NextTimeout to INFINITE
  287. // so the timeout thread will ignore this entry until an IO
  288. // request is made unless this is an AcceptEx socket, that means
  289. // we're about to submit the IO.
  290. //
  291. this->
  292. InitWithDefaults(
  293. pEndpoint->IoCompletion,
  294. pEndpoint->AcceptExTimeout, // canonical Timeout
  295. this->hAsyncIO
  296. );
  297. //
  298. // TBD: What is the circumstance in which this->pEndpoint!= NULL?
  299. //
  300. if ( this->pEndpoint == NULL ) {
  301. pEndpoint->Reference();
  302. this->pEndpoint = pEndpoint;
  303. }
  304. this->ResetFlag( ACF_ACCEPTEX_ROOT_CONTEXT );
  305. this->InitAcceptExState( AtqGetCurrentTick() + TimeOut);
  306. DBG_ASSERT( this->pvBuff != NULL);
  307. //
  308. // Initialize capacity planning trace info
  309. //
  310. m_CapTraceInfo.IISCapTraceHeader.TraceHeader.Guid = IISCapTraceGuid;
  311. m_CapTraceInfo.IISCapTraceHeader.TraceHeader.Class.Type = EVENT_TRACE_TYPE_START;
  312. m_CapTraceInfo.IISCapTraceHeader.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  313. m_CapTraceInfo.IISCapTraceHeader.TraceHeader.Size = sizeof (IIS_CAP_TRACE_HEADER);
  314. m_CapTraceInfo.IISCapTraceHeader.TraceContext.Length = sizeof(ULONGLONG);
  315. // Will get over-written
  316. m_CapTraceInfo.IISCapTraceHeader.TraceContext.DataPtr = (ULONGLONG)
  317. (&m_CapTraceInfo.IISCapTraceHeader.TraceContext.DataPtr);
  318. return (TRUE);
  319. } // ATQ_CONTEXT::PrepareAcceptExContext()
  320. VOID
  321. ATQ_CONTEXT::CleanupAndRelease( VOID)
  322. /*++
  323. Routine Description:
  324. This function does the cleanup of the ATQ context. It does not
  325. attempt to do any reuse of the atq context. After cleanup
  326. the context is freed to the ATQ pool. Supplied context
  327. is not valid after calling this function.
  328. Arguments:
  329. None
  330. Returns:
  331. None
  332. --*/
  333. {
  334. DBG_ASSERT( this->m_nIO == 0);
  335. //
  336. // Cleanup and free the ATQ Context entirely
  337. //
  338. if ( this->hAsyncIO != NULL ) {
  339. // It is too dangerous to assume that the handle is a socket!
  340. // But we will do that for fast-pathing IIS operations.
  341. HANDLE hTmp =
  342. (HANDLE)InterlockedExchangePointer( (PVOID *)&this->hAsyncIO,
  343. NULL );
  344. SOCKET hIO = HANDLE_TO_SOCKET(hTmp);
  345. if ( hIO != NULL &&
  346. (closesocket( hIO ) == SOCKET_ERROR ) ) {
  347. ATQ_PRINTF(( DBG_CONTEXT,
  348. "ATQ_CONTEXT(%08x)::CleanupAndRelease() : Warning"
  349. " - Context=%08x, "
  350. " closesocket failed, error %d, socket = %x\n",
  351. this,
  352. GetLastError(),
  353. hIO ));
  354. this->Print();
  355. }
  356. }
  357. DBG_ASSERT( this->hAsyncIO == NULL);
  358. if ( this->pvBuff != NULL ) {
  359. LocalFree( this->pvBuff );
  360. this->pvBuff = NULL;
  361. }
  362. //
  363. // Unlink from the list
  364. //
  365. DBG_ASSERT( this->ContextList != NULL);
  366. // NYI: Can I avoid this comparison?
  367. //
  368. // Check if this context is part of a timeout list.
  369. // If it is then remove it from the list
  370. // Only during shutdown code path, we will see trouble here.
  371. //
  372. if ( this->m_leTimeout.Flink != NULL ) {
  373. this->ContextList->RemoveFromList( &this->m_leTimeout);
  374. }
  375. //
  376. // Deref the listen info if this context is associated with one
  377. //
  378. if ( this->pEndpoint != NULL ) {
  379. this->pEndpoint->Dereference();
  380. this->pEndpoint = NULL;
  381. }
  382. this->Signature = ATQ_FREE_CONTEXT_SIGNATURE;
  383. this->lSyncTimeout = 0;
  384. this->m_acState = 0;
  385. this->m_acFlags = 0;
  386. I_AtqFreeContextToCache( this);
  387. return;
  388. } // ATQ_CONTEXT::CleanupAndRelease()
  389. inline VOID
  390. DBG_PRINT_ATQ_SPUDCONTEXT( IN PATQ_CONT pAtqContext,
  391. IN PSPUD_REQ_CONTEXT reqContext)
  392. {
  393. ATQ_PRINTF(( DBG_CONTEXT,
  394. "[AtqPoolThread] pAtqContext = %08lx\n"
  395. "[AtqPoolThread] IoStatus1.Status = %08lx\n"
  396. "[AtqPoolThread] IoStatus1.Information = %08lx\n"
  397. "[AtqPoolThread] IoStatus2.Status = %08lx\n"
  398. "[AtqPoolThread] IoStatus2.Information = %08lx\n"
  399. ,
  400. pAtqContext,
  401. reqContext->IoStatus1.Status,
  402. reqContext->IoStatus1.Information,
  403. reqContext->IoStatus2.Status,
  404. reqContext->IoStatus2.Information
  405. ));
  406. return;
  407. } // DBG_PRINT_ATQ_SPUDCONTEXT()
  408. VOID
  409. AtqpUpdateBandwidth( IN PATQ_CONT pAtqContext,
  410. IN DWORD cbWritten)
  411. {
  412. PBANDWIDTH_INFO pBandwidthInfo = pAtqContext->m_pBandwidthInfo;
  413. DBG_ASSERT( pBandwidthInfo != NULL );
  414. DBG_ASSERT( pBandwidthInfo->QuerySignature() == ATQ_BW_INFO_SIGNATURE );
  415. // add the bandwidth info to active list if necessary
  416. pBandwidthInfo->AddToActiveList();
  417. //this will have problems when we use XmitFile for large files.
  418. pBandwidthInfo->UpdateBytesXfered( pAtqContext, cbWritten );
  419. } // AtqpUpdateBandwidth()
  420. VOID
  421. AtqpCallOplockCompletion( IN PATQ_CONT pAtqContext,
  422. IN DWORD cbWritten)
  423. {
  424. ATQ_OPLOCK_COMPLETION pfnOplockCompletion;
  425. PVOID OplockContext;
  426. POPLOCK_INFO pOplock;
  427. IF_DEBUG( SPUD) {
  428. DBGPRINTF(( DBG_CONTEXT,
  429. "CallOplockCompletion on OpLockInfo=%08x.cbWritten = %d\n",
  430. (POPLOCK_INFO ) pAtqContext, cbWritten));
  431. }
  432. //
  433. // The ATQ context object received is a fake one. We actually get
  434. // back POPLOCK_INFO object that is used to extract the callback
  435. // function & context for the callback
  436. //
  437. pOplock = (POPLOCK_INFO)pAtqContext;
  438. pfnOplockCompletion = (ATQ_OPLOCK_COMPLETION)pOplock->pfnOplockCompletion;
  439. OplockContext = (PVOID)pOplock->Context;
  440. LocalFree(pOplock);
  441. (*pfnOplockCompletion)(OplockContext, (DWORD)cbWritten);
  442. return;
  443. } // AtqpCallOplockCompletion()
  444. VOID
  445. AtqpProcessContext( IN PATQ_CONT pAtqContext,
  446. IN DWORD cbWritten,
  447. IN LPOVERLAPPED lpo,
  448. IN BOOL fRet)
  449. {
  450. BOOL fDriverCall = FALSE;
  451. BOOL fRecvCalled = FALSE;
  452. PSPUD_REQ_CONTEXT reqContext;
  453. DWORD dwError;
  454. DBG_ASSERT( pAtqContext != NULL);
  455. //
  456. // Check to see if this is a completion request from the
  457. // NTS kernel driver.
  458. //
  459. if ( lpo == NULL ) {
  460. if ( cbWritten == 0xffffffff ) {
  461. //
  462. // One of the SPUD's IO completion. Handle it appropriately.
  463. //
  464. reqContext = (PSPUD_REQ_CONTEXT)pAtqContext;
  465. pAtqContext = CONTAINING_RECORD( reqContext, ATQ_CONTEXT,
  466. spudContext );
  467. IF_DEBUG( SPUD) {
  468. DBG_PRINT_ATQ_SPUDCONTEXT( pAtqContext, reqContext);
  469. }
  470. #if CC_REF_TRACKING
  471. //
  472. // ATQ notification trace
  473. //
  474. // Notify client context of all non-oplock notification.
  475. // This is for debugging purpose only.
  476. //
  477. // Code 0xfcfcfcfc indicates a SPUD I/O Completion
  478. //
  479. pAtqContext->NotifyIOCompletion( (ULONG_PTR)pAtqContext, reqContext->IoStatus1.Status, 0xfcfcfcfc );
  480. #endif
  481. cbWritten = (DWORD)reqContext->IoStatus1.Information;
  482. fRet = (reqContext->IoStatus1.Status == STATUS_SUCCESS);
  483. SetLastError(g_pfnRtlNtStatusToDosError(reqContext->IoStatus1.Status));
  484. lpo = &pAtqContext->Overlapped;
  485. //
  486. // If the TransmitFile fails then the receive is not issued.
  487. //
  488. if ( fRet ) {
  489. fDriverCall = TRUE;
  490. } else {
  491. DBG_ASSERT( fDriverCall == FALSE);
  492. pAtqContext->ResetFlag( ACF_RECV_ISSUED);
  493. }
  494. } else {
  495. //
  496. // An Oplock notification - handle it via oplock path.
  497. //
  498. AtqpCallOplockCompletion( pAtqContext, cbWritten);
  499. return;
  500. }
  501. }
  502. dwError = (fRet) ? NO_ERROR: GetLastError();
  503. //
  504. // If this is an AcceptEx listen socket atq completion, then the
  505. // client Atq context we really want is keyed from the overlapped
  506. // structure that is stored in the client's Atq context.
  507. //
  508. if ( pAtqContext->IsAcceptExRootContext() ) {
  509. pAtqContext = CONTAINING_RECORD( lpo, ATQ_CONTEXT, Overlapped );
  510. }
  511. #if CC_REF_TRACKING
  512. //
  513. // ATQ notification trace
  514. //
  515. // Notify client context of all non-oplock notification.
  516. // This is for debugging purpose only.
  517. //
  518. pAtqContext->NotifyIOCompletion( cbWritten, (fRet) ? NO_ERROR: GetLastError(), 0xfefefefe );
  519. #endif
  520. DBG_CODE(
  521. if ( ATQ_CONTEXT_SIGNATURE != pAtqContext->Signature) {
  522. pAtqContext->Print();
  523. DBG_ASSERT( FALSE);
  524. });
  525. //
  526. // m_nIO also acts as the reference count for the atq contexts
  527. // So, increment the count now, so that there is no other thread
  528. // that will free up this ATQ context accidentally.
  529. //
  530. InterlockedIncrement( &pAtqContext->m_nIO);
  531. //
  532. // Busy wait for timeout processing to complete!
  533. // This is ugly :( A fix in time for IIS 2.0/Catapult 1.0 release
  534. //
  535. InterlockedIncrement( &pAtqContext->lSyncTimeout);
  536. while ( pAtqContext->IsFlag( ACF_IN_TIMEOUT)) {
  537. AcIncrement( CacAtqWaitsForTimeout);
  538. Sleep( ATQ_WAIT_FOR_TIMEOUT_PROCESSING);
  539. };
  540. //
  541. // We need to make sure the timeout thread doesn't time this
  542. // request out so reset the timeout value
  543. //
  544. InterlockedExchange( (LPLONG )&pAtqContext->NextTimeout,
  545. (LONG ) ATQ_INFINITE);
  546. //
  547. // Update Bandwidth information on successful completion, if needed
  548. //
  549. if ( BANDWIDTH_INFO::GlobalEnabled() && fRet && cbWritten > 0)
  550. {
  551. AtqpUpdateBandwidth( pAtqContext, cbWritten);
  552. }
  553. //
  554. // Since the IO completion means that one of the async operation finished
  555. // decrement our internal ref count appropriately to balance the addition
  556. // when the IO operation was submitted.
  557. //
  558. InterlockedDecrement( &pAtqContext->m_nIO);
  559. //
  560. // Is this a connection indication?
  561. //
  562. if ( !pAtqContext->IsFlag( ACF_CONN_INDICATED) ) {
  563. PATQ_ENDPOINT pEndpoint = pAtqContext->pEndpoint;
  564. if ( NULL == pEndpoint) {
  565. pAtqContext->Print();
  566. OutputDebugString( "Found an ATQ context with bad Endpoint\n");
  567. DBG_ASSERT( FALSE);
  568. DBG_REQUIRE( InterlockedDecrement( &pAtqContext->lSyncTimeout) == 0);
  569. InterlockedDecrement( &pAtqContext->m_nIO); // balance entry count
  570. return;
  571. }
  572. DBG_ASSERT( pEndpoint != NULL );
  573. //
  574. // If the endpoint isn't active it may not be safe to call
  575. // the connection completion function. Setting an error
  576. // state will close the connection below.
  577. //
  578. if ( fRet && !IS_BLOCK_ACTIVE( pEndpoint ) ) {
  579. fRet = FALSE;
  580. dwError = ERROR_OPERATION_ABORTED;
  581. }
  582. //
  583. // Indicate this socket is in use
  584. //
  585. InterlockedDecrement( &pEndpoint->nSocketsAvail );
  586. //
  587. // If we're running low on sockets, add some more now
  588. //
  589. if ( pEndpoint->nSocketsAvail <
  590. (LONG )(pEndpoint->nAcceptExOutstanding >> 2) ) {
  591. AcIncrement( CacAtqPrepareContexts);
  592. (VOID ) I_AtqPrepareAcceptExSockets(pEndpoint,
  593. pEndpoint->nAcceptExOutstanding
  594. );
  595. }
  596. //
  597. // If an error occurred on this completion,
  598. // shutdown the socket
  599. //
  600. if ( !fRet ) {
  601. IF_DEBUG( ERROR) {
  602. if ( dwError != ERROR_OPERATION_ABORTED &&
  603. dwError != ERROR_NETNAME_DELETED ) {
  604. ATQ_PRINTF(( DBG_CONTEXT,
  605. " Free Context(%08x, EP=%08x) to cache. "
  606. "Err=%d, sock=%08x\n",
  607. pAtqContext, pEndpoint,
  608. dwError,
  609. pAtqContext->hAsyncIO));
  610. }
  611. }
  612. DBG_REQUIRE( InterlockedDecrement( &pAtqContext->lSyncTimeout) == 0);
  613. InterlockedDecrement( &pAtqContext->m_nIO); // balance entry count
  614. // balance original count
  615. InterlockedDecrement( &pAtqContext->m_nIO);
  616. // Free up the atq context without Reuse
  617. pAtqContext->CleanupAndRelease();
  618. return;
  619. }
  620. //
  621. // Shutdown may close the socket from underneath us so don't
  622. // assert, just warn.
  623. //
  624. if ( !pAtqContext->IsState( ACS_SOCK_LISTENING) ) {
  625. ATQ_PRINTF(( DBG_CONTEXT,
  626. "[AtqPoolThread] Warning-Socket state not listening\n"
  627. ));
  628. DBG_CODE( pAtqContext->Print());
  629. }
  630. pAtqContext->MoveState( ACS_SOCK_CONNECTED);
  631. //
  632. // Remove the context from the pending list and put
  633. // it on the active list
  634. //
  635. DBG_ASSERT( pAtqContext->ContextList != NULL);
  636. pAtqContext->ContextList->MoveToActiveList( &pAtqContext->m_leTimeout);
  637. //
  638. // Set the connection indicated flag. After we return from
  639. // the connection completion routine we assume it's
  640. // safe to call the IO completion routine
  641. // (or the connection indication routine should do cleanup
  642. // and never issue an IO request). This is primarily for
  643. // the timeout thread.
  644. //
  645. pAtqContext->ConnectionCompletion( cbWritten, lpo);
  646. } else {
  647. //
  648. // Not a connection completion indication. I/O completion.
  649. //
  650. //
  651. // If an error occurred on a TransmitFile (or other IO),
  652. // set the state to connected so the socket will get
  653. // closed on cleanup
  654. //
  655. if ( !fRet &&
  656. pAtqContext->IsState( ACS_SOCK_UNCONNECTED)
  657. ){
  658. pAtqContext->MoveState( ACS_SOCK_CONNECTED);
  659. }
  660. #if 0
  661. if (fDriverCall) {
  662. ATQ_PRINTF(( DBG_CONTEXT,
  663. "[AtqPoolThread] pfnCompletion1(%08lx)\n",
  664. pAtqContext ));
  665. }
  666. #endif
  667. pAtqContext->IOCompletion( cbWritten, dwError, lpo);
  668. if (fDriverCall) {
  669. pAtqContext->ResetFlag( ACF_RECV_ISSUED);
  670. fRet = (reqContext->IoStatus2.Status == STATUS_SUCCESS);
  671. SetLastError( g_pfnRtlNtStatusToDosError(
  672. reqContext->IoStatus2.Status));
  673. //
  674. // If an error occurred on a TransmitFile (or other IO),
  675. // set the state to connected so the socket will get
  676. // closed on cleanup
  677. //
  678. if ( !fRet &&
  679. pAtqContext->IsState( ACS_SOCK_UNCONNECTED) ) {
  680. pAtqContext->MoveState( ACS_SOCK_CONNECTED);
  681. }
  682. #if CC_REF_TRACKING
  683. //
  684. // ATQ notification trace
  685. //
  686. // Notify client context of status after 1st notification
  687. // This is for debugging purpose only.
  688. //
  689. // Code 0xfafafafa means we're processing a recv that
  690. // SPUD combined with another notification
  691. //
  692. // pAtqContext->NotifyIOCompletion( pAtqContext->m_acFlags, reqContext->IoStatus1.Status, 0xfafafafa );
  693. #endif
  694. if ( pAtqContext->IsFlag( ACF_RECV_CALLED ) ) {
  695. fRecvCalled = TRUE;
  696. pAtqContext->ResetFlag( ACF_RECV_CALLED);
  697. }
  698. if ((reqContext->IoStatus1.Status == STATUS_SUCCESS) &&
  699. (pAtqContext->ClientContext != NULL) &&
  700. fRecvCalled ) {
  701. #if CC_REF_TRACKING
  702. //
  703. // ATQ notification trace
  704. //
  705. // Notify client context of all non-oplock notification.
  706. // This is for debugging purpose only.
  707. //
  708. // Code 0xfdfdfdfd means we're processing a recv that
  709. // SPUD combined with another notification
  710. //
  711. pAtqContext->NotifyIOCompletion( cbWritten, (fRet) ? NO_ERROR: GetLastError(), 0xfdfdfdfd );
  712. #endif
  713. IF_DEBUG( SPUD) {
  714. ATQ_PRINTF(( DBG_CONTEXT,
  715. "[AtqPoolThread] pfnCompletion2(%08lx)\n",
  716. pAtqContext ));
  717. };
  718. pAtqContext->IOCompletion(
  719. (DWORD)reqContext->IoStatus2.Information,
  720. (fRet) ? NO_ERROR : GetLastError(),
  721. lpo
  722. );
  723. }
  724. }
  725. }
  726. DBG_ASSERT( pAtqContext->lSyncTimeout > 0);
  727. InterlockedDecrement( &pAtqContext->lSyncTimeout);
  728. //
  729. // We do an interlocked decrement on m_nIO to sync up state
  730. // so that the context is not prematurely deleted.
  731. //
  732. if ( InterlockedDecrement( &pAtqContext->m_nIO) == 0) {
  733. //
  734. // The number of outstanding ref holders is ZERO.
  735. // Free up this ATQ context.
  736. //
  737. // We really do not free up the context - but try to reuse
  738. // it if possible
  739. //
  740. // free the atq context now or reuse if possible.
  741. AtqpReuseOrFreeContext( pAtqContext,
  742. (pAtqContext->
  743. IsFlag( ACF_REUSE_CONTEXT) != 0)
  744. );
  745. }
  746. return;
  747. } // AtqpProcessContext()
  748. DWORD
  749. AtqPoolThread(
  750. LPDWORD param
  751. )
  752. /*++
  753. Routine Description:
  754. This is the pool thread wait and dispatch routine
  755. Arguments:
  756. param : unused.
  757. Return Value:
  758. Thread return value (ignored)
  759. --*/
  760. {
  761. PATQ_CONT pAtqContext = NULL;
  762. BOOL fRet;
  763. LPOVERLAPPED lpo;
  764. DWORD cbWritten;
  765. DWORD returnValue;
  766. DWORD availThreads;
  767. for(;;) {
  768. pAtqContext = NULL;
  769. InterlockedIncrement( &g_cAvailableThreads );
  770. fRet = g_pfnGetQueuedCompletionStatus( g_hCompPort,
  771. &cbWritten,
  772. (PULONG_PTR)&pAtqContext,
  773. &lpo,
  774. g_msThreadTimeout );
  775. availThreads = InterlockedDecrement( &g_cAvailableThreads );
  776. if ( fRet || lpo ) {
  777. if ( pAtqContext == NULL) {
  778. if ( g_fShutdown ) {
  779. //
  780. // This is our signal to exit.
  781. //
  782. returnValue = NO_ERROR;
  783. break;
  784. }
  785. OutputDebugString( "A null context received\n");
  786. continue; // some error in the context has occured.
  787. }
  788. //
  789. // Make sure we're not running out of threads
  790. //
  791. if ( availThreads == 0 ) {
  792. //
  793. // Make sure there are pool threads to service the request
  794. //
  795. (VOID)I_AtqCheckThreadStatus();
  796. }
  797. if ( (ULONG_PTR) param == ATQ_DEBUG_THREAD )
  798. {
  799. //
  800. // If this is a DEBUG thread, we are only concerned with new
  801. // connections. Anything else we ignore.
  802. //
  803. if ( pAtqContext->IsFlag( ACF_CONN_INDICATED ) )
  804. {
  805. continue;
  806. }
  807. }
  808. //
  809. // Capacity planning log
  810. //
  811. if (IISCapTraceFlag && pAtqContext)
  812. {
  813. PIIS_CAP_TRACE_INFO pCapTraceInfo = pAtqContext->GetCapTraceInfo();
  814. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Class.Type = EVENT_TRACE_TYPE_START;
  815. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Size = sizeof (IIS_CAP_TRACE_HEADER);
  816. pCapTraceInfo->IISCapTraceHeader.TraceContext.DataPtr = (ULONGLONG) &pAtqContext;
  817. pCapTraceInfo->IISCapTraceHeader.TraceContext.Length = sizeof(ULONG_PTR);
  818. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  819. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Guid = IISCapTraceGuid;
  820. if ( ERROR_INVALID_HANDLE == TraceEvent ( IISCapTraceLoggerHandle,
  821. (PEVENT_TRACE_HEADER) pCapTraceInfo))
  822. {
  823. IISCapTraceFlag = FALSE;
  824. }
  825. }
  826. AtqpProcessContext( pAtqContext, cbWritten, lpo, fRet);
  827. //
  828. // Capacity planning log
  829. //
  830. if (IISCapTraceFlag && pAtqContext)
  831. {
  832. PIIS_CAP_TRACE_INFO pCapTraceInfo = pAtqContext->GetCapTraceInfo();
  833. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Class.Type = EVENT_TRACE_TYPE_END;
  834. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Size = sizeof (IIS_CAP_TRACE_HEADER);
  835. pCapTraceInfo->IISCapTraceHeader.TraceContext.DataPtr = (ULONGLONG) &pAtqContext;
  836. pCapTraceInfo->IISCapTraceHeader.TraceContext.Length = sizeof(ULONG_PTR);
  837. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Guid = IISCapTraceGuid;
  838. pCapTraceInfo->IISCapTraceHeader.TraceHeader.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
  839. if ( ERROR_INVALID_HANDLE == TraceEvent ( IISCapTraceLoggerHandle,
  840. (PEVENT_TRACE_HEADER) pCapTraceInfo))
  841. {
  842. IISCapTraceFlag = FALSE;
  843. }
  844. }
  845. } else {
  846. //
  847. // don't kill the initial thread - any thread that doesn't have
  848. // pending I/Os go ahead and allow to die
  849. //
  850. if ( ((ULONG_PTR)param == ATQ_INITIAL_THREAD) && !g_fShutdown ) {
  851. continue;
  852. }
  853. if ( !g_fShutdown && GetLastError() == WAIT_TIMEOUT ) {
  854. NTSTATUS status;
  855. ULONG flag;
  856. status = NtQueryInformationThread(
  857. NtCurrentThread(),
  858. ThreadIsIoPending,
  859. &flag,
  860. sizeof(flag),
  861. NULL );
  862. IF_DEBUG( TIMEOUT ) {
  863. ATQ_PRINTF(( DBG_CONTEXT,
  864. "[ATQ Pool Thread] NtQueryInformationThread() returned 0x%08x, flag = %d\n",
  865. status,
  866. flag ));
  867. }
  868. if ( NT_SUCCESS( status ) && flag ) {
  869. //
  870. // There are pending I/Os on this thread so don't exit
  871. //
  872. continue;
  873. }
  874. }
  875. IF_DEBUG( TIMEOUT ) {
  876. ATQ_PRINTF(( DBG_CONTEXT,
  877. "[ATQ Pool Thread] Exiting thread 0x%x\n",
  878. GetCurrentThread() ));
  879. }
  880. //
  881. // An error occurred. Either the thread timed out, the handle
  882. // is going away or something bad happened. Let the thread exit.
  883. //
  884. returnValue = GetLastError();
  885. break;
  886. }
  887. } // for
  888. if ( NULL != g_pfnExitThreadCallback) {
  889. //
  890. // Client wishes to be told when ATQ threads terminate.
  891. //
  892. g_pfnExitThreadCallback();
  893. }
  894. if ( InterlockedDecrement( &g_cThreads ) == 0 ) {
  895. //
  896. // Wake up ATQTerminate()
  897. //
  898. IF_DEBUG( ERROR) {
  899. ATQ_PRINTF(( DBG_CONTEXT,
  900. "AtqPoolThread() - setting shutdown event %08x."
  901. " g_cThreads = %d\n",
  902. g_hShutdownEvent, g_cThreads
  903. ));
  904. }
  905. SetEvent( g_hShutdownEvent );
  906. }
  907. return returnValue;
  908. } // AtqPoolThread
  909. BOOL
  910. I_AtqCheckThreadStatus(
  911. PVOID Context
  912. )
  913. /*++
  914. Routine Description:
  915. This routine makes sure there is at least one thread in
  916. the thread pool. We're fast and loose so a couple of extra
  917. threads may be created.
  918. Arguments:
  919. Return Value:
  920. TRUE if successful, FALSE on error (call GetLastError)
  921. --*/
  922. {
  923. BOOL fRet = TRUE;
  924. BOOL fIsDebugThread = ( (ULONG_PTR) Context == ( ATQ_DEBUG_THREAD ) );
  925. //
  926. // If no threads are available, kick a new one off up to the limit
  927. //
  928. // WE NEED TO CHANGE THE CONDITIONS FOR STARTING ANOTHER THREAD
  929. // IT SHOULD NOT BE VERY EASY TO START A THREAD ....
  930. //
  931. if ( ( (g_cAvailableThreads == 0) &&
  932. (g_cThreads < g_cMaxThreads) &&
  933. (g_cThreads < g_cMaxThreadLimit) ) ||
  934. fIsDebugThread )
  935. {
  936. HANDLE hThread;
  937. DWORD dwThreadID;
  938. if ( !fIsDebugThread )
  939. {
  940. InterlockedIncrement( &g_cThreads );
  941. }
  942. hThread = CreateThread( NULL,
  943. 0,
  944. (LPTHREAD_START_ROUTINE)AtqPoolThread,
  945. Context,
  946. 0,
  947. &dwThreadID );
  948. if ( hThread ) {
  949. CloseHandle( hThread ); // Free system resources
  950. } else if ( !fIsDebugThread ) {
  951. //
  952. // We fail if there are no threads running
  953. //
  954. if ( InterlockedDecrement( &g_cThreads ) == 0) {
  955. ATQ_PRINTF(( DBG_CONTEXT,
  956. "AtqCheckThread: Cannot create ATQ threads\n"));
  957. fRet = FALSE;
  958. }
  959. }
  960. }
  961. return fRet;
  962. } // I_AtqCheckThreadStatus()
  963. /************************************************************
  964. * Functions to Add/Delete Atq Contexts
  965. ************************************************************/
  966. BOOL
  967. I_AtqAddAsyncHandle(
  968. IN OUT PATQ_CONT * ppAtqContext,
  969. IN PATQ_ENDPOINT pEndpoint,
  970. PVOID ClientContext,
  971. ATQ_COMPLETION pfnCompletion,
  972. DWORD TimeOut,
  973. HANDLE hAsyncIO
  974. )
  975. /*++
  976. Description:
  977. This functio adds creates a new NON-AcceptEx() based Atq Context,
  978. and includes it in proper lists fo ATQ Context management.
  979. Note:
  980. The client should call this after the IO handle is openned
  981. and before the first IO request is made
  982. Even in the case of failure, client should call AtqFreeContext() and
  983. free the memory associated with this object.
  984. --*/
  985. {
  986. BOOL fReturn = TRUE;
  987. DBG_ASSERT( ppAtqContext != NULL);
  988. DBG_ASSERT( ClientContext != NULL);
  989. *ppAtqContext = NULL; // initialize
  990. if ( g_fShutdown) {
  991. SetLastError( ERROR_NOT_READY);
  992. return (FALSE);
  993. } else {
  994. PATQ_CONT pAtqContext;
  995. //
  996. // Note we take and release the lock here as we're
  997. // optimizing for the reuseable context case
  998. //
  999. pAtqContext = I_AtqAllocContextFromCache();
  1000. if ( pAtqContext == NULL) {
  1001. return (FALSE);
  1002. }
  1003. //
  1004. // Fill out the context. We set NextTimeout to INFINITE
  1005. // so the timeout thread will ignore this entry until an IO
  1006. // request is made unless this is an AcceptEx socket, that means
  1007. // we're about to submit the IO.
  1008. //
  1009. pAtqContext->InitWithDefaults(pfnCompletion,
  1010. CanonTimeout( TimeOut ), hAsyncIO);
  1011. //
  1012. // These data members are used if we're doing AcceptEx processing
  1013. //
  1014. pAtqContext->SetAcceptExBuffer( NULL);
  1015. pAtqContext->InitNonAcceptExState(ClientContext);
  1016. //
  1017. // If an endpoint is provided, reference it
  1018. //
  1019. if ( pEndpoint != NULL ) {
  1020. pEndpoint->Reference();
  1021. pAtqContext->pEndpoint = pEndpoint;
  1022. }
  1023. *ppAtqContext = pAtqContext;
  1024. }
  1025. return (TRUE);
  1026. } // I_AtqAddAsyncHandle()
  1027. BOOL
  1028. I_AtqAddListenEndpointToPort(
  1029. IN OUT PATQ_CONT * ppAtqContext,
  1030. IN PATQ_ENDPOINT pEndpoint
  1031. )
  1032. /*++
  1033. Description:
  1034. This function creates a new AtqContext for the given ListenSocket.
  1035. It uses the listen socket as the AcceptEx() socket too for adding
  1036. the atq context to the completion port.
  1037. It assumes
  1038. TimeOut to be INFINITE, with no Endpoint structure.
  1039. Arguments:
  1040. ppAtqContext - pointer to location that will contain the atq context
  1041. on successful return.
  1042. pEndpoint - pointer to the endpoint.
  1043. Returns:
  1044. TRUE on success
  1045. FALSE if there is a failure.
  1046. Note:
  1047. The caller should free the *ppAtqContext if there is a failure.
  1048. --*/
  1049. {
  1050. BOOL fReturn = TRUE;
  1051. PATQ_CONT pAtqContext;
  1052. DBG_ASSERT( g_fUseAcceptEx); // only support AcceptEx() cases
  1053. *ppAtqContext = NULL; // initialize
  1054. if ( g_fShutdown) {
  1055. SetLastError( ERROR_NOT_READY);
  1056. return (FALSE);
  1057. } else {
  1058. //
  1059. // Note we take and release the lock here as we're
  1060. // optimizing for the reuseable context case
  1061. //
  1062. pAtqContext = I_AtqAllocContextFromCache();
  1063. if ( pAtqContext == NULL) {
  1064. return (FALSE);
  1065. }
  1066. //
  1067. // Fill out the context.
  1068. // We set the TimeOut for this object to be ATQ_INFINITE,
  1069. // since we do not want any interference from the Timeout loop.
  1070. //
  1071. pAtqContext->InitWithDefaults(
  1072. pEndpoint->IoCompletion,
  1073. ATQ_INFINITE,
  1074. SOCKET_TO_HANDLE(pEndpoint->ListenSocket)
  1075. );
  1076. //
  1077. // These data members are used if we're doing AcceptEx processing
  1078. //
  1079. pAtqContext->SetAcceptExBuffer( NULL);
  1080. //
  1081. // Among AcceptEx ATQ Contexts,
  1082. // only the listen ATQ context will have the Endpoint field as NULL
  1083. //
  1084. pAtqContext->pEndpoint = NULL;
  1085. pAtqContext->SetFlag( ACF_ACCEPTEX_ROOT_CONTEXT );
  1086. //
  1087. // We set NextTimeout to INFINITE
  1088. // so the timeout thread will ignore this entry until an IO
  1089. // request is made unless this is an AcceptEx socket, that means
  1090. // we're about to submit the IO.
  1091. DBG_ASSERT( g_fUseAcceptEx && pEndpoint->ConnectExCompletion != NULL);
  1092. pAtqContext->InitAcceptExState( ATQ_INFINITE);
  1093. *ppAtqContext = pAtqContext;
  1094. }
  1095. fReturn = I_AddAtqContextToPort( pAtqContext);
  1096. return (fReturn);
  1097. } // I_AtqAddListenEndpointToPort()
  1098. BOOL
  1099. I_AtqAddAcceptExSocket(
  1100. IN PATQ_ENDPOINT pEndpoint,
  1101. IN PATQ_CONT pAtqContext
  1102. )
  1103. /*++
  1104. Routine Description:
  1105. Adds the AtqContext to the AcceptEx() waiters list,
  1106. after allocating a new socket, since pAtqContext->hAsyncIO = NULL.
  1107. Arguments:
  1108. pEndpoint - Information about this listenning socket
  1109. patqReusedContext - optional context to use
  1110. Return Value:
  1111. TRUE on success, FALSE on failure.
  1112. On failure the caller should free the pAtqContext
  1113. --*/
  1114. {
  1115. BOOL fAddToPort = FALSE;
  1116. BOOL fSuccess = TRUE;
  1117. DBG_ASSERT( pAtqContext != NULL);
  1118. DBG_ASSERT( g_pfnAcceptEx != NULL);
  1119. DBG_ASSERT( pAtqContext->pvBuff != NULL);
  1120. DBG_ASSERT( !TsIsWindows95() );
  1121. //
  1122. // If this listen socket isn't accepting new connections, just return
  1123. //
  1124. if ( !IS_BLOCK_ACTIVE(pEndpoint) ) {
  1125. SetLastError( ERROR_NOT_READY );
  1126. return ( FALSE);
  1127. }
  1128. //
  1129. // Use the supplied socket if any.
  1130. // Otherwise create a new socket
  1131. //
  1132. if ( pAtqContext->hAsyncIO == NULL) {
  1133. SOCKET sAcceptSocket;
  1134. #if WINSOCK11
  1135. sAcceptSocket = socket(
  1136. AF_INET,
  1137. SOCK_STREAM,
  1138. IPPROTO_TCP
  1139. );
  1140. #else
  1141. sAcceptSocket = WSASocketW(
  1142. AF_INET,
  1143. SOCK_STREAM,
  1144. IPPROTO_TCP,
  1145. NULL, // protocol info
  1146. 0, // Group ID = 0 => no constraints
  1147. (g_fUseFakeCompletionPort ?
  1148. 0:
  1149. WSA_FLAG_OVERLAPPED // completion port notifications
  1150. )
  1151. );
  1152. #endif // WINSOCK11
  1153. if ( sAcceptSocket == INVALID_SOCKET ) {
  1154. fSuccess = FALSE;
  1155. sAcceptSocket = NULL;
  1156. //
  1157. // no need to unlink from any list, since we did not add it to any
  1158. //
  1159. } else {
  1160. //
  1161. // Setup the accept ex socket in the atq context.
  1162. //
  1163. pAtqContext->hAsyncIO = SOCKET_TO_HANDLE(sAcceptSocket);
  1164. pAtqContext->hJraAsyncIO = (ULONG_PTR)sAcceptSocket | 0x80000000;
  1165. fAddToPort = TRUE;
  1166. DBG_ASSERT( fSuccess);
  1167. }
  1168. }
  1169. if ( fSuccess) {
  1170. DWORD cbRecvd;
  1171. if ( g_fShutdown) {
  1172. //
  1173. // no need to unlink from any list, since we did not add it to any
  1174. //
  1175. SetLastError( ERROR_NOT_READY);
  1176. return (FALSE);
  1177. }
  1178. DBG_ASSERT( pAtqContext->hAsyncIO != NULL);
  1179. //
  1180. // 1. Call I_AtqAddAsyncHandleEx() to establish the links with
  1181. // proper AcceptEx & AtqContext processing lists.
  1182. //
  1183. // After 1, the atqcontext will be in the lists, so
  1184. // cleanup should remove the context from proper lists.
  1185. //
  1186. // 2. Add the socket to Completion Port (if new),
  1187. // i.e. if fAddToPort is true)
  1188. //
  1189. // 3. Submit the new socket to AcceptEx() so that it may be
  1190. // used for processing about the new connections.
  1191. //
  1192. // 1.
  1193. DBG_REQUIRE( pAtqContext->PrepareAcceptExContext(pEndpoint));
  1194. // increment outstanding async io operations before AcceptEx() call
  1195. InterlockedIncrement( &pAtqContext->m_nIO);
  1196. fSuccess = (// 2.
  1197. ( !fAddToPort || I_AddAtqContextToPort( pAtqContext))
  1198. &&
  1199. // 3.
  1200. (
  1201. g_pfnAcceptEx( pEndpoint->ListenSocket,
  1202. HANDLE_TO_SOCKET(pAtqContext->hAsyncIO),
  1203. pAtqContext->pvBuff,
  1204. pEndpoint->InitialRecvSize,
  1205. MIN_SOCKADDR_SIZE,
  1206. MIN_SOCKADDR_SIZE,
  1207. &cbRecvd,
  1208. &pAtqContext->Overlapped )
  1209. ||
  1210. (GetLastError() == ERROR_IO_PENDING)
  1211. )
  1212. );
  1213. if ( fSuccess) {
  1214. //
  1215. // We've successfully added this socket, increment the count
  1216. //
  1217. InterlockedIncrement( &pEndpoint->nSocketsAvail );
  1218. } else {
  1219. ATQ_PRINTF(( DBG_CONTEXT,
  1220. "[AtqAddAcceptExSocket] Reusing an old context (%08x)"
  1221. " failed; error %d:%d, sAcceptSocket = %x, "
  1222. " pEndpoint = %lx, parm4 = %d, parm7 = %lx,"
  1223. " parm8 = %lx\n",
  1224. pAtqContext,
  1225. GetLastError(),
  1226. WSAGetLastError(),
  1227. pAtqContext->hAsyncIO,
  1228. pEndpoint,
  1229. pEndpoint->InitialRecvSize,
  1230. &cbRecvd,
  1231. &pAtqContext->Overlapped ));
  1232. //
  1233. // Unlink from the current list, where it was added as a result of
  1234. // step 1 above.
  1235. //
  1236. DBG_ASSERT( pAtqContext->ContextList != NULL);
  1237. // balance the increment of the async operations outstanding
  1238. DBG_REQUIRE( InterlockedDecrement( &pAtqContext->m_nIO) > 0);
  1239. DBG_ASSERT( pAtqContext->m_leTimeout.Flink != NULL);
  1240. pAtqContext->ContextList->
  1241. RemoveFromList( &pAtqContext->m_leTimeout);
  1242. //
  1243. // balance the increment done
  1244. // by pAtqContext->PrepareAcceptExContext()
  1245. //
  1246. DBG_REQUIRE( InterlockedDecrement( &pAtqContext->m_nIO) == 0);
  1247. DBG_ASSERT( !fSuccess);
  1248. //
  1249. // the caller will free the Atq context on failure
  1250. //
  1251. }
  1252. }
  1253. return ( fSuccess);
  1254. } // I_AtqAddAcceptExSocket()
  1255. VOID
  1256. AtqpReuseContext( PATQ_CONT pAtqContext)
  1257. /*++
  1258. Description:
  1259. This function attempts to reuse the ATQ context.
  1260. It first cleans up the state and then uses the function
  1261. I_AtqAddAccetpEx() socket to re-add the context to acceptex pool
  1262. Arguments:
  1263. pAtqContext - pointer to ATQ context that can be reused
  1264. Returns:
  1265. None
  1266. --*/
  1267. {
  1268. PATQ_ENDPOINT pEndpoint = pAtqContext->pEndpoint;
  1269. DBG_ASSERT( pEndpoint != NULL);
  1270. DBG_ASSERT( pEndpoint->UseAcceptEx);
  1271. //
  1272. // Complete connection has been processed prior to coming here
  1273. //
  1274. DBG_ASSERT(pAtqContext->IsFlag( ACF_CONN_INDICATED));
  1275. //
  1276. // Remove from the current active list
  1277. //
  1278. if ( pAtqContext->m_leTimeout.Flink != NULL ) {
  1279. pAtqContext->ContextList->RemoveFromList( &pAtqContext->m_leTimeout );
  1280. }
  1281. DBG_ASSERT( pAtqContext->m_leTimeout.Flink == NULL);
  1282. DBG_ASSERT( pAtqContext->m_leTimeout.Blink == NULL);
  1283. DBG_ASSERT( pEndpoint->Signature == ATQ_ENDPOINT_SIGNATURE );
  1284. //
  1285. // Either there is no socket or the socket must be in the
  1286. // unconnected state (meaning reused after TransmitFile)
  1287. //
  1288. if ( !(!pAtqContext->hAsyncIO ||
  1289. (pAtqContext->hAsyncIO &&
  1290. pAtqContext->IsState( ACS_SOCK_UNCONNECTED |
  1291. ACS_SOCK_TOBE_FREED)
  1292. )
  1293. )) {
  1294. ATQ_PRINTF(( DBG_CONTEXT,
  1295. "[AtqReuseContext] Warning:"
  1296. " state = %08x, socket = %x (context %lx), "
  1297. " was Free called w/o close?\n",
  1298. pAtqContext->m_acState,
  1299. pAtqContext->hAsyncIO,
  1300. pAtqContext ));
  1301. DBG_ASSERT( FALSE);
  1302. }
  1303. //
  1304. // Need to make sure that the state information is cleaned up
  1305. // before re-adding the context to the list. Also reset socket options.
  1306. //
  1307. if ( pAtqContext->hAsyncIO && pAtqContext->IsFlag(ACF_TCP_NODELAY))
  1308. {
  1309. INT optValue = 0;
  1310. setsockopt( HANDLE_TO_SOCKET(pAtqContext->hAsyncIO),
  1311. IPPROTO_TCP,
  1312. TCP_NODELAY,
  1313. (char *)&optValue,
  1314. sizeof(INT)
  1315. );
  1316. //
  1317. // No need to reset the flag. It will be 0'd out during the Add
  1318. //
  1319. }
  1320. if ( !I_AtqAddAcceptExSocket(pEndpoint, pAtqContext) ) {
  1321. //
  1322. // Failed to add the socket, free up the context without reuse
  1323. //
  1324. ATQ_PRINTF(( DBG_CONTEXT,
  1325. "[AtqpReuseContext] for (%08x) failed with "
  1326. " Error = %d; Now freeing the context ...\n",
  1327. pAtqContext, GetLastError()
  1328. ));
  1329. DBG_ASSERT( pAtqContext->m_nIO == 0);
  1330. // free without reuse
  1331. pAtqContext->CleanupAndRelease();
  1332. }
  1333. return;
  1334. } // AtqpReuseContext()
  1335. VOID
  1336. AtqpReuseOrFreeContext(
  1337. PATQ_CONT pAtqContext,
  1338. BOOL fReuseContext
  1339. )
  1340. /*++
  1341. Routine Description:
  1342. This function does a free-up of the ATQ contexts. During the free-up
  1343. path, we also attempt to reuse the ATQ context if the fReuseContext is
  1344. set.
  1345. Arguments:
  1346. pAtqContext - pointer to the ATQ context that needs to be freedup
  1347. fReuseContext - BOOLEAN flag indicating if this context should be reused
  1348. Returns:
  1349. None
  1350. --*/
  1351. {
  1352. //
  1353. // Get this object out of the Blocked Requests List.
  1354. //
  1355. if ( pAtqContext->IsBlocked()) {
  1356. ATQ_REQUIRE( pAtqContext->m_pBandwidthInfo
  1357. ->RemoveFromBlockedList( pAtqContext ));
  1358. DBG_ASSERT( !pAtqContext->IsBlocked());
  1359. }
  1360. DBG_ASSERT( pAtqContext->m_pBandwidthInfo != NULL);
  1361. pAtqContext->m_pBandwidthInfo->Dereference();
  1362. //
  1363. // Conditions for Reuse:
  1364. // 1) fReuseContext == TRUE => caller wants us to reuse context
  1365. // 2) pAtqContext->pEndpoint != NULL => valid endpoint exists
  1366. // 3) pEndpoint->UseAcceptEx => AcceptEx is enabled
  1367. // 4) pEndpoint->nSocketsAvail < nAcceptExOutstanding * 2 =>
  1368. // We do not have lots of outstanding idle sockets
  1369. // Condition (4) ensures that we do not flood the system
  1370. // with too many AcceptEx sockets as a result of some spike.
  1371. // AcceptEx sockets once added to the pool are hard to
  1372. // remove, because of various timing problems.
  1373. // Hence we want to prevent arbitrarily adding AcceptEx sockets.
  1374. //
  1375. // In condition (4) I use a fudge factor of "2", so that
  1376. // we do continue to prevent reuse of sockets prematurely.
  1377. //
  1378. if ( fReuseContext &&
  1379. (pAtqContext->pEndpoint != NULL) &&
  1380. (pAtqContext->pEndpoint->UseAcceptEx)
  1381. &&
  1382. ( g_fAlwaysReuseSockets ||
  1383. ((DWORD )pAtqContext->pEndpoint->nSocketsAvail <
  1384. pAtqContext->pEndpoint->nAcceptExOutstanding * 2)
  1385. )
  1386. ) {
  1387. //
  1388. // Call the function to reuse context. On failure
  1389. // the AtqpReuseContext will free up the context
  1390. //
  1391. AcIncrement( CacAtqContextsReused);
  1392. AtqpReuseContext( pAtqContext);
  1393. } else {
  1394. AcIncrement( CacAtqContextsCleanedup);
  1395. pAtqContext->CleanupAndRelease();
  1396. }
  1397. return;
  1398. } // AtqpReuseOrFreeContext()
  1399. BOOL
  1400. I_AtqPrepareAcceptExSockets(
  1401. IN PATQ_ENDPOINT pEndpoint,
  1402. IN DWORD nSockets
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. Prepare specified number of AcceptEx sockets for the given
  1407. ListenSocket in [pEndpoint]
  1408. Arguments:
  1409. pEndpoint - Information about this listenning socket
  1410. nSockets - number of AcceptEx() sockets to be created.
  1411. Return Value:
  1412. TRUE on success, FALSE on failure.
  1413. --*/
  1414. {
  1415. BOOL fReturn;
  1416. DWORD cbBuffer;
  1417. DWORD i;
  1418. if ( !g_fUseAcceptEx ) {
  1419. SetLastError( ERROR_NOT_SUPPORTED );
  1420. return FALSE;
  1421. }
  1422. //
  1423. // If this listen socket isn't accepting new connections, just return
  1424. //
  1425. if ( pEndpoint->State != AtqStateActive ) {
  1426. SetLastError( ERROR_NOT_READY );
  1427. return(FALSE);
  1428. }
  1429. if ( pEndpoint->fAddingSockets) {
  1430. //
  1431. // Someone is already adding sockets. Do not add more
  1432. // Just return success
  1433. //
  1434. return ( TRUE);
  1435. }
  1436. pEndpoint->fAddingSockets = TRUE;
  1437. // calculate the buffer size
  1438. cbBuffer = pEndpoint->InitialRecvSize + 2* MIN_SOCKADDR_SIZE;
  1439. for ( fReturn = TRUE, i = 0 ; fReturn && i++ < nSockets; ) {
  1440. PVOID pvBuff;
  1441. PATQ_CONT pAtqContext = NULL;
  1442. //
  1443. // Alloc a buffer for receive data
  1444. // TBD: Pool all these buffers into one large buffer.
  1445. //
  1446. pvBuff = LocalAlloc( LPTR, cbBuffer);
  1447. //
  1448. // Get the ATQ context now because we need its overlapped structure
  1449. //
  1450. if (pvBuff != NULL)
  1451. pAtqContext = I_AtqAllocContextFromCache();
  1452. //
  1453. // Now check if allocations are valid and do proper cleanup on failure
  1454. //
  1455. if ( pvBuff == NULL || pAtqContext == NULL) {
  1456. if ( pvBuff ) {
  1457. LocalFree( pvBuff );
  1458. pvBuff = NULL;
  1459. }
  1460. if ( pAtqContext ) {
  1461. pAtqContext->Signature = ATQ_FREE_CONTEXT_SIGNATURE;
  1462. I_AtqFreeContextToCache( pAtqContext );
  1463. pAtqContext = NULL;
  1464. }
  1465. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1466. fReturn = FALSE;
  1467. break;
  1468. } else {
  1469. //
  1470. // Add this socket to AtqContext lists & completion ports
  1471. // From now on the called function will take care of freeing up
  1472. // pAtqContext, if there is a failure.
  1473. //
  1474. pAtqContext->SetAcceptExBuffer( pvBuff);
  1475. pAtqContext->hAsyncIO = NULL;
  1476. pAtqContext->hJraAsyncIO = 0;
  1477. if ( !I_AtqAddAcceptExSocket(pEndpoint, pAtqContext) ) {
  1478. //
  1479. // Failed to add the socket, free up the context without reuse
  1480. //
  1481. ATQ_PRINTF(( DBG_CONTEXT,
  1482. "[I_AtqPrepareAcceptExSockets] for Endpoint %08x"
  1483. " and AtqContext (%08x) failed with "
  1484. " Error = %d; Now freeing the context ...\n",
  1485. pEndpoint, pAtqContext, GetLastError()
  1486. ));
  1487. DWORD dwError = GetLastError();
  1488. // free without reuse
  1489. DBG_ASSERT( pAtqContext->m_nIO == 0);
  1490. pAtqContext->CleanupAndRelease();
  1491. SetLastError(dwError);
  1492. fReturn = FALSE;
  1493. }
  1494. }
  1495. } // for
  1496. //
  1497. // Finished Adding sockets. Indicate that by resetting the flab
  1498. //
  1499. pEndpoint->fAddingSockets = FALSE;
  1500. ATQ_PRINTF(( DBG_CONTEXT,
  1501. "PrepareAcceptExSockets( Endpoint[%08x], nSockets = %d)==>"
  1502. " avail = %d; Total Refs = %d.\n",
  1503. pEndpoint,
  1504. nSockets,
  1505. pEndpoint->nSocketsAvail,
  1506. pEndpoint->m_refCount
  1507. ));
  1508. return ( fReturn);
  1509. } // I_AtqPrepareAcceptExSockets()
  1510. BOOL
  1511. I_AtqInitializeNtEntryPoints(
  1512. VOID
  1513. )
  1514. {
  1515. HINSTANCE tmpInstance;
  1516. //
  1517. // load kernel32 and get NT specific entry points
  1518. //
  1519. tmpInstance = LoadLibrary("kernel32.dll");
  1520. if ( tmpInstance != NULL ) {
  1521. g_pfnReadDirChangesW = (PFN_READ_DIR_CHANGES_W)
  1522. GetProcAddress( tmpInstance, "ReadDirectoryChangesW");
  1523. DBG_ASSERT(g_pfnReadDirChangesW != NULL);
  1524. //
  1525. // We can free this because we are statically linked to it
  1526. //
  1527. FreeLibrary(tmpInstance);
  1528. }
  1529. g_hMSWsock = LoadLibrary( "mswsock.dll" );
  1530. if ( g_hMSWsock != NULL ) {
  1531. SOCKET sTempSocket = INVALID_SOCKET;
  1532. GUID guidTransmitFile = WSAID_TRANSMITFILE;
  1533. GUID guidAcceptEx = WSAID_ACCEPTEX;
  1534. GUID guidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;
  1535. DWORD cbReturned;
  1536. //
  1537. // Lets create a temporary socket so that we can use WSAIoctl to
  1538. // get the direct function pointers for AcceptEx(), TransmitFile(),
  1539. // etc.
  1540. //
  1541. sTempSocket = WSASocketW( AF_INET,
  1542. SOCK_STREAM,
  1543. IPPROTO_TCP,
  1544. NULL,
  1545. 0,
  1546. 0 );
  1547. if ( sTempSocket == INVALID_SOCKET )
  1548. {
  1549. ATQ_PRINTF(( DBG_CONTEXT,
  1550. "Failed to create temp socket "
  1551. "for determining WinSock provider. Error = %d",
  1552. WSAGetLastError() ));
  1553. goto cleanup;
  1554. }
  1555. WSAIoctl( sTempSocket,
  1556. SIO_GET_EXTENSION_FUNCTION_POINTER,
  1557. (LPVOID) &guidTransmitFile,
  1558. sizeof( guidTransmitFile ),
  1559. &g_pfnTransmitFile,
  1560. sizeof( g_pfnTransmitFile ),
  1561. &cbReturned,
  1562. NULL,
  1563. NULL );
  1564. WSAIoctl( sTempSocket,
  1565. SIO_GET_EXTENSION_FUNCTION_POINTER,
  1566. (LPVOID) &guidAcceptEx,
  1567. sizeof( guidAcceptEx ),
  1568. &g_pfnAcceptEx,
  1569. sizeof( g_pfnAcceptEx ),
  1570. &cbReturned,
  1571. NULL,
  1572. NULL );
  1573. WSAIoctl( sTempSocket,
  1574. SIO_GET_EXTENSION_FUNCTION_POINTER,
  1575. (LPVOID) &guidGetAcceptExSockAddrs,
  1576. sizeof( guidGetAcceptExSockAddrs ),
  1577. &g_pfnGetAcceptExSockaddrs,
  1578. sizeof( g_pfnGetAcceptExSockaddrs ),
  1579. &cbReturned,
  1580. NULL,
  1581. NULL );
  1582. //
  1583. // Close temporary socket
  1584. //
  1585. closesocket( sTempSocket );
  1586. if ( !g_pfnAcceptEx ||
  1587. !g_pfnGetAcceptExSockaddrs ||
  1588. !g_pfnTransmitFile ) {
  1589. //
  1590. // This is bad.
  1591. //
  1592. DBG_ASSERT(FALSE);
  1593. ATQ_PRINTF(( DBG_CONTEXT,
  1594. "Failed to get entry points AE %x TF %x GAE %x\n",
  1595. g_pfnAcceptEx, g_pfnTransmitFile,
  1596. g_pfnGetAcceptExSockaddrs));
  1597. goto cleanup;
  1598. }
  1599. } else {
  1600. ATQ_PRINTF((DBG_CONTEXT,
  1601. "Error %d in LoadLibrary[mswsock.dll]\n",
  1602. GetLastError()));
  1603. goto cleanup;
  1604. }
  1605. //
  1606. // load ntdll
  1607. //
  1608. if ( g_fUseDriver ) {
  1609. g_hNtdll = LoadLibrary( "ntdll.dll" );
  1610. if ( g_hNtdll != NULL ) {
  1611. g_pfnNtLoadDriver = (PFN_NT_LOAD_DRIVER)
  1612. GetProcAddress( g_hNtdll, "NtLoadDriver" );
  1613. g_pfnRtlInitUnicodeString = (PFN_RTL_INIT_UNICODE_STRING)
  1614. GetProcAddress( g_hNtdll, "RtlInitUnicodeString" );
  1615. g_pfnRtlNtStatusToDosError = (PFN_RTL_NTSTATUS_TO_DOSERR)
  1616. GetProcAddress( g_hNtdll, "RtlNtStatusToDosError" );
  1617. g_pfnRtlInitAnsiString = (PFN_RTL_INIT_ANSI_STRING)
  1618. GetProcAddress( g_hNtdll, "RtlInitAnsiString" );
  1619. g_pfnRtlAnsiStringToUnicodeString =
  1620. (PFN_RTL_ANSI_STRING_TO_UNICODE_STRING)
  1621. GetProcAddress( g_hNtdll, "RtlAnsiStringToUnicodeString" );
  1622. g_pfnRtlFreeHeap = (PFN_RTL_FREE_HEAP)
  1623. GetProcAddress( g_hNtdll, "RtlFreeHeap" );
  1624. g_pfnRtlDosPathNameToNtPathName_U =
  1625. (PFN_RTL_DOS_PATHNAME_TO_NT_PATHNAME)
  1626. GetProcAddress( g_hNtdll, "RtlDosPathNameToNtPathName_U" );
  1627. if ( !g_pfnNtLoadDriver ||
  1628. !g_pfnRtlInitUnicodeString ||
  1629. !g_pfnRtlNtStatusToDosError ||
  1630. !g_pfnRtlInitAnsiString ||
  1631. !g_pfnRtlAnsiStringToUnicodeString ||
  1632. !g_pfnRtlFreeHeap ||
  1633. !g_pfnRtlDosPathNameToNtPathName_U ) {
  1634. //
  1635. // This is bad.
  1636. //
  1637. ATQ_PRINTF(( DBG_CONTEXT,
  1638. "Failed to get entry points for ntdll.dll\n"));
  1639. DBG_ASSERT(FALSE);
  1640. goto cleanup;
  1641. }
  1642. } else {
  1643. ATQ_PRINTF((DBG_CONTEXT,
  1644. "Error %d in LoadLibrary[ntdll.dll]\n", GetLastError()));
  1645. goto cleanup;
  1646. }
  1647. }
  1648. return(TRUE);
  1649. cleanup:
  1650. if ( g_hNtdll != NULL ) {
  1651. FreeLibrary( g_hNtdll );
  1652. g_hNtdll = NULL;
  1653. }
  1654. if ( g_hMSWsock != NULL ) {
  1655. FreeLibrary( g_hMSWsock );
  1656. g_hMSWsock = NULL;
  1657. }
  1658. return(FALSE);
  1659. } // I_AtqInitializeEntryPoints