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.

1899 lines
42 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name :
  4. workerrequest.cxx
  5. Abstract:
  6. UL_NATIVE_REQUEST implementation
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 23-Oct-1998
  9. Lei Jin ( leijin ) 13-Apr-1999 (Porting)
  10. Environment:
  11. Win32 - User Mode
  12. Project:
  13. ULATQ.DLL
  14. --*/
  15. #include "precomp.hxx"
  16. //
  17. // User supplied completion routines
  18. //
  19. extern PFN_ULATQ_NEW_REQUEST g_pfnNewRequest;
  20. extern PFN_ULATQ_IO_COMPLETION g_pfnIoCompletion;
  21. //
  22. // UL_NATIVE_REQUEST statics
  23. //
  24. ULONG UL_NATIVE_REQUEST::sm_cRequestsServed;
  25. ULONG UL_NATIVE_REQUEST::sm_cRestart;
  26. LONG UL_NATIVE_REQUEST::sm_RestartMsgSent;
  27. LIST_ENTRY UL_NATIVE_REQUEST::sm_RequestListHead;
  28. CRITICAL_SECTION UL_NATIVE_REQUEST::sm_csRequestList;
  29. DWORD UL_NATIVE_REQUEST::sm_cRequests;
  30. PTRACE_LOG UL_NATIVE_REQUEST::sm_pTraceLog;
  31. DWORD UL_NATIVE_REQUEST::sm_cRequestsPending;
  32. DWORD UL_NATIVE_REQUEST::sm_cDesiredPendingRequests;
  33. BOOL UL_NATIVE_REQUEST::sm_fAddingRequests;
  34. ALLOC_CACHE_HANDLER * UL_NATIVE_REQUEST::sm_pachNativeRequests;
  35. DWORD UL_NATIVE_REQUEST::sm_cMaxFreeRequests = DEFAULT_MAX_FREE_REQUESTS;
  36. DWORD UL_NATIVE_REQUEST::sm_cFreeRequests;
  37. #ifdef _WIN64
  38. CSpinLock UL_NATIVE_REQUEST::sm_FreeListLock;
  39. SINGLE_LIST_ENTRY UL_NATIVE_REQUEST::sm_FreeList;
  40. #else
  41. SLIST_HEADER UL_NATIVE_REQUEST::sm_FreeList;
  42. #endif
  43. HANDLE UL_NATIVE_REQUEST::sm_hPendingRequestsTimer = NULL;
  44. UL_NATIVE_REQUEST::UL_NATIVE_REQUEST(
  45. VOID
  46. ) : _pbBuffer( _achBuffer ),
  47. _cbBuffer( sizeof( _achBuffer ) ),
  48. _pClientCertInfo( NULL ),
  49. _cbAllocateMemoryOffset( 0 ),
  50. _cRefs( 1 )
  51. {
  52. InitializeListHead( &_ListEntry );
  53. _FreeListEntry.Next = NULL;
  54. AddToRequestList();
  55. Reset();
  56. _dwSignature = UL_NATIVE_REQUEST_SIGNATURE;
  57. }
  58. UL_NATIVE_REQUEST::~UL_NATIVE_REQUEST(
  59. VOID
  60. )
  61. {
  62. DBG_ASSERT( CheckSignature() );
  63. _dwSignature = UL_NATIVE_REQUEST_SIGNATURE_FREE;
  64. if ( !IsListEmpty( &_ListEntry ) )
  65. {
  66. RemoveFromRequestList();
  67. }
  68. DBG_ASSERT( _cRefs == 0 );
  69. Cleanup();
  70. }
  71. VOID
  72. UL_NATIVE_REQUEST::Cleanup(
  73. VOID
  74. )
  75. /*++
  76. Routine Description:
  77. Private helper method called by destructor and Reset()
  78. It assures that resources are cleaned up properly
  79. Arguments:
  80. None
  81. Return Value:
  82. None
  83. --*/
  84. {
  85. if ( _pbBuffer != _achBuffer )
  86. {
  87. LocalFree( _pbBuffer );
  88. }
  89. _pbBuffer = _achBuffer;
  90. _cbBuffer = sizeof( _achBuffer );
  91. //
  92. // http.sys returns token in HTTP_SSL_CLIENT_CERT_INFO structure
  93. // UL_NATIVE_REQUEST must take care of closing the token to avoid leak
  94. //
  95. if ( _pClientCertInfo != NULL &&
  96. _pClientCertInfo->Token != NULL )
  97. {
  98. CloseHandle( _pClientCertInfo->Token );
  99. _pClientCertInfo->Token = NULL;
  100. }
  101. //
  102. // Start allocating from the beginning of the buffer
  103. //
  104. _cbAllocateMemoryOffset = 0;
  105. }
  106. VOID
  107. UL_NATIVE_REQUEST::Reset(
  108. VOID
  109. )
  110. /*++
  111. Routine Description:
  112. Reset a UL_NATIVE_REQUEST for use in the request state machine
  113. Arguments:
  114. None
  115. Return Value:
  116. None
  117. --*/
  118. {
  119. Cleanup();
  120. _ExecState = NREQ_STATE_START;
  121. _pvContext = NULL;
  122. _cbAsyncIOData = 0;
  123. _dwAsyncIOError = NO_ERROR;
  124. _dwClientCertFlags = 0;
  125. ZeroMemory( &_Overlapped, sizeof(_Overlapped) );
  126. }
  127. VOID *
  128. UL_NATIVE_REQUEST::AllocateMemory(
  129. DWORD cbSize
  130. )
  131. /*++
  132. Routine Description:
  133. Allocate some memory for use by W3DT.DLL user
  134. in our private buffer
  135. Arguments:
  136. cbSize - Size to allocate
  137. Return Value:
  138. Pointer to memory (NULL if failed)
  139. --*/
  140. {
  141. DWORD cbSizeNeeded = 0;
  142. VOID * pvRet;
  143. ULONG_PTR ulPointer;
  144. cbSizeNeeded = _cbAllocateMemoryOffset + cbSize + sizeof( ULONG_PTR );
  145. if ( cbSizeNeeded <= sizeof( _abAllocateMemory ) )
  146. {
  147. //
  148. // Allocate inline
  149. //
  150. ulPointer = (ULONG_PTR) _abAllocateMemory + _cbAllocateMemoryOffset;
  151. ulPointer = ( ulPointer + 7 ) & ~7;
  152. pvRet = (VOID*) ulPointer;
  153. _cbAllocateMemoryOffset += cbSize + sizeof( ULONG_PTR );
  154. }
  155. else
  156. {
  157. pvRet = NULL;
  158. }
  159. return pvRet;
  160. }
  161. VOID
  162. UL_NATIVE_REQUEST::DoWork(
  163. DWORD cbData,
  164. DWORD dwError,
  165. LPOVERLAPPED lpo
  166. )
  167. /*++
  168. Routine Description:
  169. The driver of the state machine. It is called off async completions and
  170. initially (with lpo=NULL) to kick off the state machine.
  171. Arguments:
  172. cbData - Bytes completed
  173. dwError - Win32 Error of completion
  174. lpo - Pointer to OVERLAPPED passed in async call
  175. Return Value:
  176. None
  177. --*/
  178. {
  179. NREQ_STATUS Status = NSTATUS_NEXT;
  180. BOOL fError = FALSE;
  181. ReferenceWorkerRequest();
  182. if ( lpo != NULL )
  183. {
  184. //
  185. // This is an async completion. Dereference the request to match
  186. // the reference before posting async operation
  187. //
  188. DereferenceWorkerRequest();
  189. //
  190. // Save away the completion data for state handler use and debugging
  191. // purposes
  192. //
  193. _cbAsyncIOData = cbData;
  194. _dwAsyncIOError = dwError;
  195. ZeroMemory( &_Overlapped, sizeof( _Overlapped ) );
  196. }
  197. //
  198. // Keep on executing the state machine until a state handler returns
  199. // pending. If so, the IO completion will continue the machine
  200. //
  201. // We also break out on error (typical case will be shutdown)
  202. //
  203. while ( !fError && Status == NSTATUS_NEXT )
  204. {
  205. switch ( _ExecState )
  206. {
  207. case NREQ_STATE_START:
  208. Status = DoStateStart();
  209. break;
  210. case NREQ_STATE_READ:
  211. Status = DoStateRead();
  212. break;
  213. case NREQ_STATE_PROCESS:
  214. Status = DoStateProcess();
  215. break;
  216. case NREQ_STATE_ERROR:
  217. fError = TRUE;
  218. DereferenceWorkerRequest();
  219. break;
  220. case NREQ_STATE_CLIENT_CERT:
  221. Status = DoStateClientCertificate();
  222. break;
  223. default:
  224. fError = TRUE;
  225. DBG_ASSERT( FALSE );
  226. break;
  227. }
  228. }
  229. DereferenceWorkerRequest();
  230. }
  231. NREQ_STATUS
  232. UL_NATIVE_REQUEST::DoStateStart(
  233. VOID
  234. )
  235. /*++
  236. Routine Description:
  237. The NREQ_START state. This state does the initial read for a new HTTP
  238. request (it passes a NULL request ID). Continuing the read process (
  239. for example if the buffer is too small) happens in the NREQ_READ state.
  240. Arguments:
  241. None
  242. Return Value:
  243. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  244. --*/
  245. {
  246. ULONG rc;
  247. HTTP_REQUEST_ID RequestId;
  248. HANDLE hAsync;
  249. //
  250. // This is the initial read, therefore we don't know the request ID
  251. //
  252. HTTP_SET_NULL_ID( &RequestId );
  253. //
  254. // If we are in shutdown, then just bail with error
  255. //
  256. if ( g_pwpContext->IsInShutdown() )
  257. {
  258. _ExecState = NREQ_STATE_ERROR;
  259. return NSTATUS_NEXT;
  260. }
  261. //
  262. // Have we served enough requests?
  263. //
  264. if ( sm_cRestart &&
  265. sm_cRequestsServed >= sm_cRestart )
  266. {
  267. //
  268. // Indicate to WAS such and the error out
  269. //
  270. if ( NeedToSendRestartMsg() )
  271. {
  272. g_pwpContext->SendMsgToAdminProcess( IPM_WP_RESTART_COUNT_REACHED );
  273. }
  274. _ExecState = NREQ_STATE_ERROR;
  275. return NSTATUS_NEXT;
  276. }
  277. //
  278. // Make an async call to HttpReceiveHttpRequest to get the next request
  279. //
  280. _ExecState = NREQ_STATE_READ;
  281. InterlockedIncrement( (LPLONG) &sm_cRequestsPending );
  282. ReferenceWorkerRequest();
  283. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  284. if ( hAsync != NULL )
  285. {
  286. rc = HttpReceiveHttpRequest( hAsync,
  287. RequestId,
  288. HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
  289. (HTTP_REQUEST *) _pbBuffer,
  290. _cbBuffer,
  291. NULL,
  292. &_Overlapped );
  293. }
  294. else
  295. {
  296. rc = ERROR_INVALID_HANDLE;
  297. }
  298. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  299. if ( rc == NO_ERROR )
  300. {
  301. rc = ERROR_IO_PENDING;
  302. }
  303. if ( rc != ERROR_IO_PENDING )
  304. {
  305. DBG_ASSERT( rc != NO_ERROR );
  306. InterlockedDecrement( (LPLONG) &sm_cRequestsPending );
  307. _ExecState = NREQ_STATE_ERROR;
  308. DereferenceWorkerRequest();
  309. return NSTATUS_NEXT;
  310. }
  311. else
  312. {
  313. return NSTATUS_PENDING;
  314. }
  315. }
  316. NREQ_STATUS
  317. UL_NATIVE_REQUEST::DoStateRead(
  318. VOID
  319. )
  320. /*++
  321. Routine Description:
  322. The NREQ_READ state. This state is responsible for producing a complete
  323. UL_HTTP_REQUEST for consumption by the NREQ_PROCESS state. Note that
  324. this may require another UlReceiveHttpRequest() if the initial was not
  325. supplied a large enough buffer.
  326. Arguments:
  327. None
  328. Return Value:
  329. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  330. --*/
  331. {
  332. HTTP_REQUEST_ID RequestId;
  333. ULONG cbRequired;
  334. DWORD cCurrentRequestsPending;
  335. HANDLE hAsync;
  336. //
  337. // The initial read is complete. If the error is ERROR_MORE_DATA, then
  338. // our buffer was not large enough. Resize and try again
  339. //
  340. if ( _dwAsyncIOError == ERROR_MORE_DATA )
  341. {
  342. //
  343. // Remember the request ID to retry the the UlReceiveHttpRequest
  344. //
  345. RequestId = QueryRequestId();
  346. DBG_ASSERT( RequestId != HTTP_NULL_ID );
  347. //
  348. // We need to allocate a larger buffer :(
  349. //
  350. if ( _pbBuffer != _achBuffer )
  351. {
  352. //
  353. // We shouldn't be getting ERROR_MORE_DATA if we already
  354. // resized due to an earlier ERROR_MORE_DATA
  355. //
  356. DBG_ASSERT( FALSE );
  357. LocalFree( _pbBuffer );
  358. _pbBuffer = NULL;
  359. }
  360. //
  361. // The completed bytes tells us the required size of our input
  362. // buffer
  363. //
  364. _cbBuffer = _cbAsyncIOData;
  365. _pbBuffer = (UCHAR*) LocalAlloc( LPTR, _cbBuffer );
  366. if ( _pbBuffer == NULL )
  367. {
  368. _ExecState = NREQ_STATE_ERROR;
  369. return NSTATUS_NEXT;
  370. }
  371. //
  372. // Read the HTTP request again (better to do it sychronously, since
  373. // it is all ready now)
  374. //
  375. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  376. if ( hAsync != NULL )
  377. {
  378. _dwAsyncIOError = HttpReceiveHttpRequest(
  379. hAsync,
  380. RequestId,
  381. HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
  382. (HTTP_REQUEST *)_pbBuffer,
  383. _cbBuffer,
  384. &cbRequired,
  385. NULL );
  386. }
  387. else
  388. {
  389. _dwAsyncIOError = ERROR_INVALID_HANDLE;
  390. }
  391. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  392. //
  393. // No reason this should fail again with ERROR_MORE_DATA
  394. //
  395. DBG_ASSERT( _dwAsyncIOError != ERROR_MORE_DATA );
  396. }
  397. if ( _dwAsyncIOError == NO_ERROR )
  398. {
  399. //
  400. // We're done. The read was successful and we have a full
  401. // UL_HTTP_REQUEST. We can now pass off to the NREQ_PROCESS state
  402. //
  403. cCurrentRequestsPending = InterlockedDecrement( (LPLONG)
  404. &sm_cRequestsPending );
  405. if ( cCurrentRequestsPending < sm_cDesiredPendingRequests / 2 )
  406. {
  407. AddPendingRequests( sm_cDesiredPendingRequests - cCurrentRequestsPending );
  408. }
  409. _ExecState = NREQ_STATE_PROCESS;
  410. }
  411. else
  412. {
  413. //
  414. // Some other error. Try again
  415. //
  416. InterlockedDecrement( (LPLONG) &sm_cRequestsPending );
  417. Reset();
  418. }
  419. return NSTATUS_NEXT;
  420. }
  421. NREQ_STATUS
  422. UL_NATIVE_REQUEST::DoStateProcess(
  423. VOID
  424. )
  425. /*++
  426. Routine Description:
  427. The NREQ_PROCESS state. This state actually calls consumer of the
  428. NewRequests and IoCompletions. This state calls the set routines in
  429. W3CORE.DLL
  430. Arguments:
  431. None
  432. Return Value:
  433. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  434. --*/
  435. {
  436. WP_IDLE_TIMER * pTimer;
  437. //
  438. // Reset idle tick since we're not idle if we're processing
  439. //
  440. pTimer = g_pwpContext->QueryIdleTimer();
  441. if ( pTimer != NULL )
  442. {
  443. pTimer->ResetCurrentIdleTick();
  444. }
  445. ReferenceWorkerRequest();
  446. if ( _pvContext == NULL )
  447. {
  448. //
  449. // Extra reference here. The consumer must call UlAtqResetContext()
  450. // to finally cleanup. This complication is brought on by
  451. // scenarios where non-IO-completions are required to finish a request
  452. // (example: async ISAPI)
  453. //
  454. ReferenceWorkerRequest();
  455. DBG_ASSERT( g_pfnNewRequest != NULL );
  456. g_pfnNewRequest( this );
  457. }
  458. else
  459. {
  460. DBG_ASSERT( g_pfnIoCompletion != NULL );
  461. g_pfnIoCompletion( _pvContext,
  462. _cbAsyncIOData,
  463. _dwAsyncIOError,
  464. &_Overlapped );
  465. }
  466. DereferenceWorkerRequest();
  467. return NSTATUS_PENDING;
  468. }
  469. NREQ_STATUS
  470. UL_NATIVE_REQUEST::DoStateClientCertificate(
  471. VOID
  472. )
  473. /*++
  474. Routine Description:
  475. Handle a completion for receiving a client certificate
  476. Arguments:
  477. None
  478. Return Value:
  479. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  480. --*/
  481. {
  482. ULONG Status;
  483. HTTP_REQUEST * pRequest;
  484. HANDLE hAsync;
  485. DBG_ASSERT( _ExecState == NREQ_STATE_CLIENT_CERT );
  486. //
  487. // Is our buffer too small. If so retry the request synchronously with
  488. // a bigger buffer
  489. // Note: STATUS_BUFFER_OVERFLOW is translated to WIN32 Error - ERROR_MORE_DATA
  490. if ( _dwAsyncIOError == ERROR_MORE_DATA )
  491. {
  492. //
  493. // If buffer is not big enough, HTTP.sys will return only HTTP_SSL_CLIENT_CERT_INFO
  494. // structure that contains the size of the client certificate
  495. // The following assert is to assure that HTTP.SYS returns back that
  496. // HTTP_SSL_CLIENT_CERT_INFO structure and nothing more
  497. DBG_ASSERT( _cbAsyncIOData == sizeof( HTTP_SSL_CLIENT_CERT_INFO ) );
  498. //
  499. // We need to allocate enough memory to contain HTTP_SSL_CLIENT_CERT_INFO
  500. // and certificate blob
  501. //
  502. DWORD dwRequiredSize = _pClientCertInfo->CertEncodedSize +
  503. sizeof( HTTP_SSL_CLIENT_CERT_INFO );
  504. DBG_ASSERT( dwRequiredSize > _buffClientCertInfo.QuerySize() );
  505. if ( !_buffClientCertInfo.Resize( dwRequiredSize ) )
  506. {
  507. //
  508. // Funnel the fatal error to the complete
  509. //
  510. _dwAsyncIOError = GetLastError();
  511. }
  512. else
  513. {
  514. //
  515. // Retry the request for client cert synchronously
  516. //
  517. _pClientCertInfo = reinterpret_cast<HTTP_SSL_CLIENT_CERT_INFO *>( _buffClientCertInfo.QueryPtr() );
  518. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  519. if ( hAsync != NULL )
  520. {
  521. Status = HttpReceiveClientCertificate( hAsync,
  522. QueryConnectionId(),
  523. _dwClientCertFlags,
  524. _pClientCertInfo,
  525. _buffClientCertInfo.QuerySize(),
  526. NULL,
  527. NULL );
  528. }
  529. else
  530. {
  531. Status = ERROR_INVALID_HANDLE;
  532. }
  533. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  534. if ( Status != NO_ERROR )
  535. {
  536. DBG_ASSERT( _dwAsyncIOError != ERROR_MORE_DATA );
  537. }
  538. _dwAsyncIOError = Status;
  539. _cbAsyncIOData = dwRequiredSize;
  540. }
  541. }
  542. if ( _dwAsyncIOError == NO_ERROR )
  543. {
  544. pRequest = QueryHttpRequest();
  545. DBG_ASSERT( pRequest->pSslInfo != NULL );
  546. DBG_ASSERT( pRequest->pSslInfo->pClientCertInfo == NULL );
  547. pRequest->pSslInfo->pClientCertInfo = _pClientCertInfo;
  548. }
  549. //
  550. // Regardless of what happened, we are no longer processing a client cert
  551. //
  552. _ExecState = NREQ_STATE_PROCESS;
  553. DBG_ASSERT( g_pfnIoCompletion != NULL );
  554. g_pfnIoCompletion( _pvContext,
  555. _cbAsyncIOData,
  556. _dwAsyncIOError,
  557. &_Overlapped );
  558. return NSTATUS_PENDING;
  559. }
  560. VOID
  561. UL_NATIVE_REQUEST::ResetContext(
  562. VOID
  563. )
  564. /*++
  565. Routine Description:
  566. The implementation of UlAtqResetContext which the consumer of W3DT.DLL
  567. calls to cleanup the context.
  568. Arguments:
  569. None
  570. Return Value:
  571. None
  572. --*/
  573. {
  574. DereferenceWorkerRequest();
  575. }
  576. VOID
  577. UL_NATIVE_REQUEST::ReferenceWorkerRequest(
  578. VOID
  579. )
  580. /*++
  581. Routine Description:
  582. Increment the reference count on the worker request
  583. Arguments:
  584. None
  585. Return Value:
  586. None
  587. --*/
  588. {
  589. LONG cRefs = InterlockedIncrement( &_cRefs );
  590. //
  591. // Log the reference ( sm_pTraceLog!=NULL if DBG=1)
  592. //
  593. if ( sm_pTraceLog != NULL )
  594. {
  595. WriteRefTraceLog( sm_pTraceLog,
  596. cRefs,
  597. this );
  598. }
  599. }
  600. VOID
  601. UL_NATIVE_REQUEST::DereferenceWorkerRequest(
  602. VOID
  603. )
  604. /*++
  605. Routine Description:
  606. Dereference Request. This routine will optionally reset the context
  607. for use for reading the next HTTP request. Putting the reset code in
  608. one place (here) handles all the cases where we would want to reset.
  609. However, there are a few places where we definitely don't want to reset
  610. (in the case of error where the context will be going away)
  611. In either case, if the ref count goes to 0, we can delete the object.
  612. Arguments:
  613. None
  614. Return Value:
  615. None
  616. --*/
  617. {
  618. LONG cRefs = InterlockedDecrement( &_cRefs );
  619. if ( sm_pTraceLog != NULL )
  620. {
  621. WriteRefTraceLog( sm_pTraceLog,
  622. cRefs,
  623. this );
  624. }
  625. if ( cRefs == 0 )
  626. {
  627. //
  628. // If 0, we can definitely cleanup, regardless. This is the error
  629. // case which is used to cleanup contexts on shutdown (on shutdown,
  630. // the apppool handle is closed which will error out all pending
  631. // UlReceiveHttpRequests
  632. //
  633. delete this;
  634. }
  635. else if ( cRefs == 1 && _ExecState != NREQ_STATE_ERROR )
  636. {
  637. //
  638. // Reset the state machine. Now we can increment our served count
  639. //
  640. InterlockedIncrement( (PLONG) &sm_cRequestsServed );
  641. //
  642. // If we have too many outstanding requests, then don't pend
  643. // another receive. Keep the request around ready to go
  644. //
  645. if ( sm_cRequestsPending > sm_cDesiredPendingRequests * 2 )
  646. {
  647. FreeWorkerRequest( this );
  648. }
  649. else
  650. {
  651. Reset();
  652. //
  653. // Re-kickoff the state machine
  654. //
  655. DoWork( 0, 0, NULL );
  656. }
  657. }
  658. }
  659. VOID
  660. UL_NATIVE_REQUEST::RemoveFromRequestList(
  661. VOID
  662. )
  663. /*++
  664. Routine Description:
  665. Remove this UL_NATIVE_REQUEST from the static list of requests. Main
  666. purpose of the list is for debugging.
  667. Arguments:
  668. None
  669. Return Value:
  670. None
  671. --*/
  672. {
  673. EnterCriticalSection( &sm_csRequestList );
  674. RemoveEntryList( &_ListEntry );
  675. sm_cRequests--;
  676. LeaveCriticalSection( &sm_csRequestList );
  677. }
  678. VOID
  679. UL_NATIVE_REQUEST::AddToRequestList(
  680. VOID
  681. )
  682. /*++
  683. Routine Description:
  684. Add this request to the static list of requests. The main purpose of the
  685. list is for debugging.
  686. Arguments:
  687. None
  688. Return Value:
  689. None
  690. --*/
  691. {
  692. EnterCriticalSection( &sm_csRequestList );
  693. sm_cRequests++;
  694. InsertTailList( &sm_RequestListHead, &_ListEntry );
  695. LeaveCriticalSection( &sm_csRequestList );
  696. }
  697. HRESULT
  698. UL_NATIVE_REQUEST::SendResponse(
  699. BOOL fAsync,
  700. DWORD dwFlags,
  701. HTTP_RESPONSE * pResponse,
  702. HTTP_CACHE_POLICY * pCachePolicy,
  703. DWORD *pcbSent,
  704. HTTP_LOG_FIELDS_DATA *pUlLogData
  705. )
  706. /*++
  707. Routine Description:
  708. Send an HTTP response thru UL.
  709. Arguments:
  710. fAsync - TRUE if send is async
  711. dwFlags - UlSendHttpResponse flags
  712. pResponse - Pointer to UL_HTTP_RESPONSE
  713. pCachePolicy - Cache policy
  714. pcbSent - Receives number of bytes send
  715. pULLogData - Logging information
  716. Return Value:
  717. HRESULT (if pending, the return is NO_ERROR)
  718. --*/
  719. {
  720. ULONG Status = NO_ERROR;
  721. HRESULT hr = NO_ERROR;
  722. HANDLE hAsync;
  723. if ( pcbSent == NULL )
  724. {
  725. DBG_ASSERT( FALSE );
  726. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  727. }
  728. if ( fAsync )
  729. {
  730. ReferenceWorkerRequest();
  731. }
  732. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  733. if ( hAsync != NULL )
  734. {
  735. Status = HttpSendHttpResponse( hAsync,
  736. QueryRequestId(),
  737. dwFlags,
  738. pResponse,
  739. pCachePolicy,
  740. fAsync ? NULL : pcbSent,
  741. NULL,
  742. 0,
  743. fAsync ? &(_Overlapped) : NULL ,
  744. pUlLogData );
  745. }
  746. else
  747. {
  748. Status = ERROR_INVALID_HANDLE;
  749. }
  750. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  751. //
  752. // If the response is pending, then we return a successful error code.
  753. // This frees the caller from the ERROR_IO_PENDING checks in common
  754. // case
  755. //
  756. if ( fAsync )
  757. {
  758. if ( Status == NO_ERROR )
  759. {
  760. Status = ERROR_IO_PENDING;
  761. }
  762. DBG_ASSERT( Status != NO_ERROR );
  763. if ( Status != ERROR_IO_PENDING )
  764. {
  765. _Overlapped.Internal = Status;
  766. DereferenceWorkerRequest();
  767. hr = HRESULT_FROM_WIN32( Status );
  768. }
  769. }
  770. else if ( Status != NO_ERROR )
  771. {
  772. hr = HRESULT_FROM_WIN32( Status );
  773. }
  774. return hr;
  775. }
  776. HRESULT
  777. UL_NATIVE_REQUEST::SendEntity(
  778. BOOL fAsync,
  779. DWORD dwFlags,
  780. USHORT cChunks,
  781. HTTP_DATA_CHUNK * pChunks,
  782. DWORD *pcbSent,
  783. HTTP_LOG_FIELDS_DATA *pUlLogData
  784. )
  785. /*++
  786. Routine Description:
  787. Send an HTTP entity thru UL.
  788. Arguments:
  789. fAsync - TRUE if send is async
  790. dwFlags - UlSendHttpResponse flags
  791. cChunks - Number of chunks in response
  792. pChunks - Pointer to array of UL_DATA_CHUNKs
  793. pcbSent - Receives number of bytes sent
  794. pUlLogData - Log information
  795. Return Value:
  796. HRESULT (if pending, the return is NO_ERROR)
  797. --*/
  798. {
  799. ULONG Status = NO_ERROR;
  800. HRESULT hr = NO_ERROR;
  801. HANDLE hAsync;
  802. if ( pcbSent == NULL )
  803. {
  804. DBG_ASSERT( FALSE );
  805. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  806. }
  807. if ( fAsync )
  808. {
  809. ReferenceWorkerRequest();
  810. }
  811. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  812. if ( hAsync != NULL )
  813. {
  814. Status = HttpSendResponseEntityBody( hAsync,
  815. QueryRequestId(),
  816. dwFlags,
  817. cChunks,
  818. pChunks,
  819. fAsync ? NULL : pcbSent,
  820. NULL,
  821. 0,
  822. fAsync ? &(_Overlapped) : NULL,
  823. pUlLogData );
  824. }
  825. else
  826. {
  827. Status = ERROR_INVALID_HANDLE;
  828. }
  829. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  830. //
  831. // If the send is pending, then we return a successful error code.
  832. // This frees the caller from the ERROR_IO_PENDING checks in common
  833. // case
  834. //
  835. if ( fAsync )
  836. {
  837. if ( Status == NO_ERROR )
  838. {
  839. Status = ERROR_IO_PENDING;
  840. }
  841. DBG_ASSERT( Status != NO_ERROR );
  842. if ( Status != ERROR_IO_PENDING )
  843. {
  844. _Overlapped.Internal = Status;
  845. DereferenceWorkerRequest();
  846. hr = HRESULT_FROM_WIN32( Status );
  847. }
  848. }
  849. else if ( Status != NO_ERROR )
  850. {
  851. hr = HRESULT_FROM_WIN32( Status );
  852. }
  853. return hr;
  854. }
  855. HRESULT
  856. UL_NATIVE_REQUEST::ReceiveEntity(
  857. BOOL fAsync,
  858. DWORD dwFlags,
  859. VOID * pBuffer,
  860. DWORD cbBuffer,
  861. DWORD * pBytesReceived
  862. )
  863. /*++
  864. Routine Description:
  865. Receive HTTP entity thru UL.
  866. Arguments:
  867. fAsync - TRUE if receive is async
  868. dwFlags - UlSendHttpResponse flags
  869. pBuffer - A buffer to receive the data
  870. cbBuffer - The size of the receive buffer
  871. pBytesReceived - Upon return, the number of bytes
  872. copied to the buffer
  873. Return Value:
  874. HRESULT (if pending, the return is NO_ERROR)
  875. --*/
  876. {
  877. ULONG Status = NO_ERROR;
  878. HRESULT hr = NO_ERROR;
  879. HANDLE hAsync;
  880. if ( fAsync )
  881. {
  882. ReferenceWorkerRequest();
  883. }
  884. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  885. if ( hAsync != NULL )
  886. {
  887. Status = HttpReceiveRequestEntityBody( hAsync,
  888. QueryRequestId(),
  889. dwFlags,
  890. pBuffer,
  891. cbBuffer,
  892. fAsync ? NULL : pBytesReceived,
  893. fAsync ? &(_Overlapped) : NULL );
  894. }
  895. else
  896. {
  897. Status = ERROR_INVALID_HANDLE;
  898. }
  899. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  900. //
  901. // If the receive is pending, then we return a successful error code.
  902. // This frees the caller from the ERROR_IO_PENDING checks in common
  903. // case
  904. //
  905. if ( fAsync )
  906. {
  907. if ( Status == NO_ERROR )
  908. {
  909. Status = ERROR_IO_PENDING;
  910. }
  911. DBG_ASSERT( Status != NO_ERROR );
  912. if ( Status != ERROR_IO_PENDING )
  913. {
  914. _Overlapped.Internal = Status;
  915. DereferenceWorkerRequest();
  916. hr = HRESULT_FROM_WIN32( Status );
  917. }
  918. }
  919. else if ( Status != NO_ERROR )
  920. {
  921. hr = HRESULT_FROM_WIN32( Status );
  922. }
  923. return hr;
  924. }
  925. HRESULT
  926. UL_NATIVE_REQUEST::ReceiveClientCertificate(
  927. BOOL fAsync,
  928. BOOL fDoCertMap,
  929. HTTP_SSL_CLIENT_CERT_INFO **ppClientCertInfo
  930. )
  931. /*++
  932. Routine Description:
  933. Receive a client certificate
  934. Arguments:
  935. fAsync - TRUE if receive should be async
  936. fDoCertMap - TRUE if we should map client certificate to token
  937. ppClientCertInfo - Set to point to client cert info on success
  938. Return Value:
  939. HRESULT (if pending, the return is NO_ERROR)
  940. --*/
  941. {
  942. ULONG Status;
  943. HTTP_REQUEST * pHttpRequest;
  944. HRESULT hr = NO_ERROR;
  945. HANDLE hAsync;
  946. if ( ppClientCertInfo == NULL )
  947. {
  948. DBG_ASSERT( FALSE );
  949. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  950. }
  951. *ppClientCertInfo = NULL;
  952. //
  953. // If this request is not SSL enabled, then getting the client cert is
  954. // a no-go
  955. //
  956. pHttpRequest = QueryHttpRequest();
  957. DBG_ASSERT( pHttpRequest != NULL );
  958. if ( pHttpRequest->pSslInfo == NULL )
  959. {
  960. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  961. }
  962. //
  963. // Do we already have a cert associated with this request?
  964. //
  965. DBG_ASSERT( pHttpRequest->pSslInfo != NULL );
  966. if ( pHttpRequest->pSslInfo->pClientCertInfo != NULL )
  967. {
  968. if ( fAsync )
  969. {
  970. //
  971. // BUGBUG: Probably should support this case. And if I do, then
  972. // need to fake a completion!
  973. //
  974. DBG_ASSERT( FALSE );
  975. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  976. }
  977. *ppClientCertInfo = pHttpRequest->pSslInfo->pClientCertInfo;
  978. return NO_ERROR;
  979. }
  980. //
  981. // OK. We'll have to ask UL to renegotiate. We must be processing
  982. // a request
  983. //
  984. DBG_ASSERT( _ExecState == NREQ_STATE_PROCESS );
  985. if ( !_buffClientCertInfo.Resize( INITIAL_CERT_INFO_SIZE ) )
  986. {
  987. return HRESULT_FROM_WIN32( GetLastError() );
  988. }
  989. ZeroMemory( _buffClientCertInfo.QueryPtr(), INITIAL_CERT_INFO_SIZE );
  990. _pClientCertInfo = reinterpret_cast<HTTP_SSL_CLIENT_CERT_INFO *>( _buffClientCertInfo.QueryPtr() );
  991. //
  992. // Are we cert mapping?
  993. //
  994. if ( fDoCertMap )
  995. {
  996. _dwClientCertFlags = HTTP_RECEIVE_CLIENT_CERT_FLAG_MAP;
  997. }
  998. else
  999. {
  1000. _dwClientCertFlags = 0;
  1001. }
  1002. //
  1003. // If we're doing this async, then manage state such that
  1004. // DoStateClientCert gets the completion
  1005. //
  1006. if ( fAsync )
  1007. {
  1008. ReferenceWorkerRequest();
  1009. _ExecState = NREQ_STATE_CLIENT_CERT;
  1010. }
  1011. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  1012. if ( hAsync != NULL )
  1013. {
  1014. Status = HttpReceiveClientCertificate( hAsync,
  1015. QueryConnectionId(),
  1016. _dwClientCertFlags,
  1017. _pClientCertInfo,
  1018. _buffClientCertInfo.QuerySize(),
  1019. NULL,
  1020. fAsync ? &_Overlapped : NULL );
  1021. }
  1022. else
  1023. {
  1024. Status = ERROR_INVALID_HANDLE;
  1025. }
  1026. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  1027. if ( fAsync )
  1028. {
  1029. if ( Status == NO_ERROR )
  1030. {
  1031. Status = ERROR_IO_PENDING;
  1032. }
  1033. DBG_ASSERT( Status != NO_ERROR );
  1034. if ( Status != ERROR_IO_PENDING )
  1035. {
  1036. _Overlapped.Internal = Status;
  1037. DereferenceWorkerRequest();
  1038. hr = HRESULT_FROM_WIN32( Status );
  1039. _ExecState = NREQ_STATE_PROCESS;
  1040. }
  1041. }
  1042. else if ( Status != NO_ERROR )
  1043. {
  1044. hr = HRESULT_FROM_WIN32( Status );
  1045. }
  1046. return hr;
  1047. }
  1048. //static
  1049. HRESULT
  1050. UL_NATIVE_REQUEST::Initialize(
  1051. VOID
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Static initialization of UL_NATIVE_REQUESTs
  1056. Arguments:
  1057. None
  1058. Return Value:
  1059. HRESULT
  1060. --*/
  1061. {
  1062. ALLOC_CACHE_CONFIGURATION acConfig;
  1063. HKEY hKey;
  1064. BOOL fRet;
  1065. HRESULT hr;
  1066. //
  1067. // Setup allocation lookaside
  1068. //
  1069. acConfig.nConcurrency = 1;
  1070. acConfig.nThreshold = 100;
  1071. acConfig.cbSize = sizeof( UL_NATIVE_REQUEST );
  1072. DBG_ASSERT( sm_pachNativeRequests == NULL );
  1073. sm_pachNativeRequests = new ALLOC_CACHE_HANDLER( "UL_NATIVE_REQUEST",
  1074. &acConfig );
  1075. if ( sm_pachNativeRequests == NULL )
  1076. {
  1077. return HRESULT_FROM_WIN32( GetLastError() );
  1078. }
  1079. fRet = InitializeCriticalSectionAndSpinCount( &sm_csRequestList,
  1080. UL_NATIVE_REQUEST_CS_SPINS );
  1081. if ( !fRet )
  1082. {
  1083. hr = HRESULT_FROM_WIN32( GetLastError() );
  1084. delete sm_pachNativeRequests;
  1085. sm_pachNativeRequests = NULL;
  1086. return hr;
  1087. }
  1088. InitializeListHead( &sm_RequestListHead );
  1089. #ifdef _WIN64
  1090. sm_FreeList.Next = NULL;
  1091. #else
  1092. InitializeSListHead( &sm_FreeList );
  1093. #endif
  1094. sm_cRequestsServed = 0;
  1095. sm_cRestart = 0;
  1096. sm_RestartMsgSent = 0;
  1097. sm_cRequestsPending = 0;
  1098. //
  1099. // If the number of pending HttpReceiveHttpRequest is configured, use
  1100. // that rather than the default value
  1101. //
  1102. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1103. REGISTRY_KEY_W3SVC_PERFORMANCE_KEY_W,
  1104. 0,
  1105. KEY_READ,
  1106. &hKey ) == ERROR_SUCCESS)
  1107. {
  1108. DWORD cbBuffer = sizeof(DWORD);
  1109. DWORD dwType;
  1110. if (RegQueryValueEx( hKey,
  1111. L"ReceiveRequestsPending",
  1112. NULL,
  1113. &dwType,
  1114. (LPBYTE)&sm_cDesiredPendingRequests,
  1115. &cbBuffer ) != NO_ERROR ||
  1116. dwType != REG_DWORD)
  1117. {
  1118. sm_cDesiredPendingRequests = DESIRED_PENDING_REQUESTS;
  1119. }
  1120. RegCloseKey( hKey );
  1121. }
  1122. else
  1123. {
  1124. sm_cDesiredPendingRequests = DESIRED_PENDING_REQUESTS;
  1125. }
  1126. sm_fAddingRequests = FALSE;
  1127. #if DBG
  1128. sm_pTraceLog = CreateRefTraceLog( 2000, 0 );
  1129. #endif
  1130. return NO_ERROR;
  1131. }
  1132. //static
  1133. VOID
  1134. UL_NATIVE_REQUEST::StopListening(
  1135. VOID
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Shutdown the apppool in preparation for shutdown
  1140. Arguments:
  1141. None
  1142. Return Value:
  1143. None
  1144. --*/
  1145. {
  1146. HANDLE hAsync;
  1147. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  1148. if ( hAsync != NULL )
  1149. {
  1150. //
  1151. // This will cause us to cancel all pending HttpReceiveHttpRequest calls
  1152. // and not get any more but other operations will still go on
  1153. //
  1154. HttpShutdownAppPool( hAsync );
  1155. }
  1156. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  1157. }
  1158. //static
  1159. VOID
  1160. UL_NATIVE_REQUEST::Terminate(
  1161. VOID
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. Static termination
  1166. Arguments:
  1167. None
  1168. Return Value:
  1169. None
  1170. --*/
  1171. {
  1172. if ( sm_pTraceLog != NULL )
  1173. {
  1174. DestroyRefTraceLog( sm_pTraceLog );
  1175. sm_pTraceLog = NULL;
  1176. }
  1177. DeleteCriticalSection( &sm_csRequestList );
  1178. if ( sm_pachNativeRequests != NULL )
  1179. {
  1180. delete sm_pachNativeRequests;
  1181. sm_pachNativeRequests = NULL;
  1182. }
  1183. }
  1184. //static
  1185. HRESULT
  1186. UL_NATIVE_REQUEST::AddPendingRequests(
  1187. DWORD cRequests
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. Pools calls to UlReceiveHttpRequest by creating new UL_NATIVE_REQUESTs
  1192. and kicking off their state machines
  1193. Arguments:
  1194. cRequests - Number of requests to read
  1195. Return Value:
  1196. HRESULT
  1197. --*/
  1198. {
  1199. UL_NATIVE_REQUEST * pRequest;
  1200. if ( sm_fAddingRequests )
  1201. {
  1202. return NO_ERROR;
  1203. }
  1204. if ( InterlockedCompareExchange( (LPLONG) &sm_fAddingRequests,
  1205. TRUE,
  1206. FALSE ) == FALSE )
  1207. {
  1208. for ( DWORD i = 0; i < cRequests; i++ )
  1209. {
  1210. pRequest = AllocateWorkerRequest();
  1211. if ( pRequest == NULL )
  1212. {
  1213. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1214. }
  1215. pRequest->DoWork( 0, 0, NULL );
  1216. }
  1217. sm_fAddingRequests = FALSE;
  1218. }
  1219. return NO_ERROR;
  1220. }
  1221. //static
  1222. HRESULT
  1223. UL_NATIVE_REQUEST::ReleaseAllWorkerRequests(
  1224. VOID
  1225. )
  1226. /*++
  1227. Routine Description:
  1228. Wait for all outstanding UL_NATIVE_REQUESTs to drain
  1229. Arguments:
  1230. None
  1231. Return Value:
  1232. HRESULT
  1233. --*/
  1234. {
  1235. UL_NATIVE_REQUEST * pRequest;
  1236. //
  1237. // Now, wait for all requests to be destructed
  1238. //
  1239. while ( sm_cRequests )
  1240. {
  1241. //
  1242. // Clear out any of our free list items. Since this list
  1243. // may be appended to right now, keep on cleaning it
  1244. //
  1245. for ( ; ; )
  1246. {
  1247. pRequest = PopFreeList();
  1248. if ( pRequest == NULL )
  1249. {
  1250. break;
  1251. }
  1252. DBG_ASSERT( pRequest != NULL );
  1253. DBG_ASSERT( pRequest->CheckSignature() );
  1254. //
  1255. // Free it up
  1256. //
  1257. pRequest->DereferenceWorkerRequest();
  1258. }
  1259. Sleep( 1000 );
  1260. DBGPRINTF(( DBG_CONTEXT,
  1261. "UL_NATIVE_REQUEST::ReleaseAllWorkerRequests waiting for %d requests to drain.\n",
  1262. sm_cRequests ));
  1263. }
  1264. return NO_ERROR;
  1265. }
  1266. //static
  1267. VOID
  1268. WINAPI
  1269. UL_NATIVE_REQUEST::PendingRequestsMonitorHandler(
  1270. PVOID,
  1271. BOOLEAN
  1272. )
  1273. /*++
  1274. Routine Description:
  1275. Check if pending requests number is 0.
  1276. If it is 0 then try to add 1 pending request
  1277. to allow this worker process to start handling
  1278. http requests again
  1279. Arguments:
  1280. None
  1281. Return Value:
  1282. NONE
  1283. --*/
  1284. {
  1285. if ( sm_cRequestsPending == 0 )
  1286. {
  1287. DBGPRINTF((DBG_CONTEXT,
  1288. "Worker process has run out of pending requests. Trying to add one\n"
  1289. ));
  1290. //
  1291. // If pending requests number is 0 then
  1292. // it means there must have been errors on
  1293. // HttpReceiveHttpRequest() call that
  1294. // caused worker process to run out of pending requests
  1295. // It is time to intervene by adding one
  1296. // pending request. That should jump start
  1297. // the process of handling the requests again
  1298. //
  1299. // Note: We don't check the error because there
  1300. // is nothing we can do about the error. If
  1301. // we failed then the next time timer fires and
  1302. // this handler gets called we will simply retry
  1303. AddPendingRequests( 1 );
  1304. }
  1305. }
  1306. //static
  1307. HRESULT
  1308. UL_NATIVE_REQUEST::StartPendingRequestsMonitor(
  1309. VOID
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. Start timer to enable monitoring of the pending requests
  1314. Arguments:
  1315. None
  1316. Return Value:
  1317. HRESULT
  1318. --*/
  1319. {
  1320. HRESULT hr = E_FAIL;
  1321. //
  1322. // create timer to wake up every 5 seconds
  1323. //
  1324. //
  1325. if ( !CreateTimerQueueTimer( &sm_hPendingRequestsTimer,
  1326. NULL,
  1327. UL_NATIVE_REQUEST::PendingRequestsMonitorHandler,
  1328. NULL,
  1329. 5000,
  1330. 5000,
  1331. WT_EXECUTELONGFUNCTION ) )
  1332. {
  1333. hr = HRESULT_FROM_WIN32( GetLastError() );
  1334. }
  1335. else
  1336. {
  1337. hr = S_OK;
  1338. }
  1339. return hr;
  1340. }
  1341. //static
  1342. VOID
  1343. UL_NATIVE_REQUEST::StopPendingRequestsMonitor(
  1344. VOID
  1345. )
  1346. /*++
  1347. Routine Description:
  1348. Stop timer for monitoring of the pending requests
  1349. Arguments:
  1350. None
  1351. Return Value:
  1352. HRESULT
  1353. --*/
  1354. {
  1355. if ( sm_hPendingRequestsTimer != NULL )
  1356. {
  1357. if ( !DeleteTimerQueueTimer(
  1358. NULL,
  1359. sm_hPendingRequestsTimer,
  1360. INVALID_HANDLE_VALUE /* wait for callbacks to complete */
  1361. ) )
  1362. {
  1363. DBGPRINTF(( DBG_CONTEXT,
  1364. "Failed to delete Ping timer (%d)\n",
  1365. GetLastError() ));
  1366. }
  1367. sm_hPendingRequestsTimer = NULL;
  1368. }
  1369. }
  1370. //static
  1371. VOID
  1372. UL_NATIVE_REQUEST::FreeWorkerRequest(
  1373. UL_NATIVE_REQUEST * pWorkerRequest
  1374. )
  1375. /*++
  1376. Routine Description:
  1377. Free worker request
  1378. Arguments:
  1379. pNativeRequest - Worker request to retrieve
  1380. Return Value:
  1381. None
  1382. --*/
  1383. {
  1384. DBG_ASSERT( pWorkerRequest != NULL );
  1385. if ( sm_cFreeRequests > sm_cMaxFreeRequests ||
  1386. g_pwpContext->IsInShutdown() )
  1387. {
  1388. //
  1389. // Don't keep too many around (especially in shutdown ;-)).
  1390. // Just free this guy by dereferencing one more time
  1391. //
  1392. pWorkerRequest->DereferenceWorkerRequest();
  1393. }
  1394. else
  1395. {
  1396. pWorkerRequest->Reset();
  1397. PushFreeList( pWorkerRequest );
  1398. sm_cFreeRequests++;
  1399. }
  1400. }
  1401. //static
  1402. UL_NATIVE_REQUEST *
  1403. UL_NATIVE_REQUEST::AllocateWorkerRequest(
  1404. VOID
  1405. )
  1406. /*++
  1407. Routine Description:
  1408. Allocate a new request
  1409. Arguments:
  1410. None
  1411. Return Value:
  1412. Pointer to new request or NULL if error
  1413. --*/
  1414. {
  1415. UL_NATIVE_REQUEST * pRequest;
  1416. if ( sm_cFreeRequests )
  1417. {
  1418. pRequest = PopFreeList();
  1419. if ( pRequest != NULL )
  1420. {
  1421. DBG_ASSERT( pRequest->CheckSignature() );
  1422. sm_cFreeRequests--;
  1423. return pRequest;
  1424. }
  1425. }
  1426. //
  1427. // If we got to here, we have to allocate a new request
  1428. //
  1429. pRequest = new UL_NATIVE_REQUEST;
  1430. return pRequest;
  1431. }