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.

964 lines
20 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. ulatq.cxx
  5. Abstract:
  6. Exported ULATQ.DLL routines
  7. Author:
  8. Bilal Alam (balam) 13-Dec-1999
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULATQ.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include "rwpfunctions.hxx"
  16. //
  17. // Configuration parameters registry key.
  18. //
  19. #define INET_INFO_KEY \
  20. "System\\CurrentControlSet\\Services\\w3svc"
  21. #define INET_INFO_PARAMETERS_KEY \
  22. INET_INFO_KEY "\\Parameters"
  23. const CHAR g_pszWpRegLocation[] =
  24. INET_INFO_PARAMETERS_KEY "\\w3dt";
  25. DECLARE_DEBUG_PRINTS_OBJECT();
  26. DECLARE_DEBUG_VARIABLE();
  27. DECLARE_PLATFORM_TYPE();
  28. WP_CONTEXT * g_pwpContext = NULL;
  29. //
  30. // Completion routines for new requests, io completions, and disconnect
  31. // notifications.
  32. //
  33. // CODEWORK: Can we get away with these being global
  34. //
  35. PFN_ULATQ_NEW_REQUEST g_pfnNewRequest = NULL;
  36. PFN_ULATQ_IO_COMPLETION g_pfnIoCompletion = NULL;
  37. PFN_ULATQ_DISCONNECT g_pfnDisconnect = NULL;
  38. PFN_ULATQ_ON_SHUTDOWN g_pfnOnShutdown = NULL;
  39. PFN_ULATQ_COLLECT_PERF_COUNTERS g_pfnCollectCounters = NULL;
  40. HRESULT
  41. UlAtqInitialize(
  42. INT argc,
  43. LPWSTR argv[],
  44. ULATQ_CONFIG * pConfig
  45. )
  46. /*++
  47. Routine Description:
  48. Initialize ULATQ
  49. Arguments:
  50. argc - Number of command line parameters to worker process
  51. argv - Command line parameters
  52. pConfig - Configuration settings for ULATQ
  53. Return Value:
  54. HRESULT
  55. --*/
  56. {
  57. HRESULT rc = NO_ERROR;
  58. BOOL fUlInit = FALSE;
  59. BOOL fThreadPoolInit = FALSE;
  60. HTTPAPI_VERSION HttpVersion = HTTPAPI_VERSION_1;
  61. CREATE_DEBUG_PRINT_OBJECT("w3dt");
  62. #if DBG
  63. if (!VALID_DEBUG_PRINT_OBJECT())
  64. {
  65. return E_FAIL;
  66. }
  67. #endif
  68. LOAD_DEBUG_FLAGS_FROM_REG_STR( g_pszWpRegLocation, DEBUG_ERROR );
  69. INITIALIZE_PLATFORM_TYPE();
  70. //
  71. // Honour ULATQ_CONFIG settings. Set completion routines
  72. // Need to set this up before we do any other initialization
  73. //
  74. g_pfnNewRequest = pConfig->pfnNewRequest;
  75. g_pfnIoCompletion = pConfig->pfnIoCompletion;
  76. g_pfnDisconnect = pConfig->pfnDisconnect;
  77. g_pfnOnShutdown = pConfig->pfnOnShutdown;
  78. g_pfnCollectCounters = pConfig->pfnCollectCounters;
  79. //
  80. // Initialize the thread pool
  81. //
  82. rc = ThreadPoolInitialize( 0 ); // Use the process default stack size
  83. if ( FAILED( rc ) )
  84. {
  85. goto Finished;
  86. }
  87. fThreadPoolInit = TRUE;
  88. //
  89. // Init UL
  90. //
  91. rc = HttpInitialize( HttpVersion, 0, NULL );
  92. if ( rc != NO_ERROR )
  93. {
  94. rc = HRESULT_FROM_WIN32( rc );
  95. DBGPRINTF(( DBG_CONTEXT, "Error (rc=%08x) in UlInitialize. Exiting\n",
  96. rc ));
  97. goto Finished;
  98. }
  99. fUlInit = TRUE;
  100. //
  101. // Determine if we should be deterministic or random,
  102. // and declare our intentions
  103. //
  104. // Note: this needs to be called prior to attempting to run any rogue
  105. // tests. This appears to be a good early time to call it.
  106. //
  107. RWP_Read_Config(RWP_CONFIG_LOCATION);
  108. //
  109. // Create global state object
  110. //
  111. g_pwpContext = new WP_CONTEXT;
  112. if ( g_pwpContext == NULL )
  113. {
  114. rc = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  115. goto Finished;
  116. }
  117. //
  118. // Do global state initialization
  119. //
  120. rc = g_pwpContext->Initialize( argc, argv );
  121. if ( rc != NO_ERROR )
  122. {
  123. //
  124. // WP_CONTEXT::Initialize returns a Win32 error code
  125. //
  126. rc = HRESULT_FROM_WIN32( rc );
  127. goto Finished;
  128. }
  129. Finished:
  130. if ( rc != NO_ERROR )
  131. {
  132. if ( g_pwpContext != NULL )
  133. {
  134. delete g_pwpContext;
  135. g_pwpContext = NULL;
  136. }
  137. if ( fUlInit )
  138. {
  139. HttpTerminate(0, NULL);
  140. }
  141. if ( fThreadPoolInit )
  142. {
  143. ThreadPoolTerminate();
  144. }
  145. }
  146. return rc;
  147. }
  148. HRESULT
  149. UlAtqStartListen(
  150. VOID
  151. )
  152. /*++
  153. Routine Description:
  154. Begin listening for HTTP requests from UL. This call must happen only
  155. after ULATQ has been initialized correctly (for example, completion
  156. routines should be set).
  157. Arguments:
  158. None
  159. Return Value:
  160. HRESULT
  161. --*/
  162. {
  163. HRESULT hr = NO_ERROR;
  164. DBG_ASSERT( g_pfnIoCompletion != NULL );
  165. DBG_ASSERT( g_pfnNewRequest != NULL );
  166. //
  167. // Make some UlReceiveHttpRequest calls
  168. //
  169. hr = g_pwpContext->Start();
  170. if ( FAILED(hr) )
  171. {
  172. //
  173. // If we failed to start, we may outstanding requests to cleanup.
  174. //
  175. goto DoShutdown;
  176. }
  177. //
  178. // Send message to WAS that our initialization is complete
  179. //
  180. g_pwpContext->SendInitCompleteMessage( S_OK );
  181. //
  182. // Wait for shutdown because of WAS/request-count-max/etc.
  183. //
  184. g_pwpContext->RunMainThreadLoop();
  185. DoShutdown:
  186. //
  187. // Do stuff needed to stop listening for new requests
  188. //
  189. UL_NATIVE_REQUEST::StopListening();
  190. //
  191. // Before connection drain, allow the user to execute some code
  192. //
  193. if ( g_pfnOnShutdown != NULL )
  194. {
  195. g_pfnOnShutdown( g_pwpContext->QueryDoImmediateShutdown() );
  196. }
  197. //
  198. // Before we return, wait for outstanding requests to drain. This
  199. // prevents race before caller's shutdown and new requests coming in
  200. //
  201. g_pwpContext->CleanupOutstandingRequests();
  202. return hr;
  203. }
  204. VOID
  205. UlAtqTerminate(
  206. HRESULT hrToSend
  207. )
  208. /*++
  209. Routine Description:
  210. Terminate ULATQ
  211. Arguments:
  212. None
  213. Return Value:
  214. None
  215. --*/
  216. {
  217. if ( g_pwpContext != NULL )
  218. {
  219. if (FAILED(hrToSend))
  220. {
  221. g_pwpContext->SendInitCompleteMessage( hrToSend );
  222. }
  223. g_pwpContext->Terminate();
  224. delete g_pwpContext;
  225. g_pwpContext = NULL;
  226. }
  227. HttpTerminate(0, NULL);
  228. ThreadPoolTerminate();
  229. DELETE_DEBUG_PRINT_OBJECT();
  230. }
  231. VOID *
  232. UlAtqGetContextProperty(
  233. ULATQ_CONTEXT pContext,
  234. ULATQ_CONTEXT_PROPERTY_ID PropertyId
  235. )
  236. /*++
  237. Routine Description:
  238. Get the UL_HTTP_REQUEST from the ULATQ_CONTEXT
  239. Arguments:
  240. pContext - ULATQ_CONTEXT
  241. PropertyId - Property Id to set
  242. Return Value:
  243. The actual property
  244. --*/
  245. {
  246. switch (PropertyId)
  247. {
  248. case ULATQ_PROPERTY_HTTP_REQUEST:
  249. UL_NATIVE_REQUEST * pRequest;
  250. pRequest = (UL_NATIVE_REQUEST*) pContext;
  251. DBG_ASSERT( pRequest != NULL );
  252. return pRequest->QueryHttpRequest();
  253. case ULATQ_PROPERTY_APP_POOL_ID:
  254. return (VOID *)g_pwpContext->QueryConfig()->QueryAppPoolName();
  255. case ULATQ_PROPERTY_IS_COMMAND_LINE_LAUNCH:
  256. return (VOID *)!(g_pwpContext->QueryConfig()->QueryRegisterWithWAS());
  257. case ULATQ_PROPERTY_DO_CENTRAL_BINARY_LOGGING:
  258. return (VOID *)(DWORD_PTR)g_pwpContext->QueryConfig()->QueryDoCentralBinaryLogging();
  259. default:
  260. DBG_ASSERT(FALSE);
  261. }
  262. return NULL;
  263. }
  264. VOID
  265. UlAtqSetContextProperty(
  266. ULATQ_CONTEXT pContext,
  267. ULATQ_CONTEXT_PROPERTY_ID PropertyId,
  268. PVOID pvData
  269. )
  270. /*++
  271. Routine Description:
  272. Set a property of the ULATQ_CONTEXT
  273. Arguments:
  274. pContext - ULATQ_CONTEXT
  275. PropertyId - Property Id to set
  276. pvData - Data specific to the property being set
  277. Return Value:
  278. None
  279. --*/
  280. {
  281. UL_NATIVE_REQUEST * pRequest;
  282. pRequest = (UL_NATIVE_REQUEST*) pContext;
  283. DBG_ASSERT( pRequest != NULL );
  284. switch ( PropertyId )
  285. {
  286. case ULATQ_PROPERTY_COMPLETION_CONTEXT:
  287. pRequest->SetContext( pvData );
  288. break;
  289. default:
  290. DBG_ASSERT( FALSE );
  291. }
  292. }
  293. VOID
  294. UlAtqFreeContext(
  295. ULATQ_CONTEXT pContext
  296. )
  297. /*++
  298. Routine Description:
  299. Frees the ULATQ_CONTEXT so that it can be used to retrieve next request
  300. Arguments:
  301. pContext - ULATQ_CONTEXT
  302. Return Value:
  303. None
  304. --*/
  305. {
  306. UL_NATIVE_REQUEST * pRequest;
  307. pRequest = (UL_NATIVE_REQUEST*) pContext;
  308. DBG_ASSERT( pRequest != NULL );
  309. pRequest->ResetContext();
  310. }
  311. HRESULT
  312. UlAtqSendHttpResponse(
  313. ULATQ_CONTEXT pContext,
  314. BOOL fAsync,
  315. DWORD dwFlags,
  316. HTTP_RESPONSE * pResponse,
  317. HTTP_CACHE_POLICY * pCachePolicy,
  318. DWORD *pcbSent,
  319. HTTP_LOG_FIELDS_DATA *pUlLogData
  320. )
  321. /*++
  322. Routine Description:
  323. Send a response to the client
  324. Arguments:
  325. pContext - ULATQ_CONTEXT
  326. fAsync - Asynchronous or not?
  327. dwFlags - Response flags (like killing the connection)
  328. pResponse - UL_HTTP_RESPONSE to send
  329. pCachePolicy - Cache policy
  330. Return Value:
  331. Win32 Error
  332. --*/
  333. {
  334. UL_NATIVE_REQUEST * pRequest;
  335. pRequest = (UL_NATIVE_REQUEST*) pContext;
  336. DBG_ASSERT( pRequest != NULL );
  337. return pRequest->SendResponse( fAsync,
  338. dwFlags,
  339. pResponse,
  340. pCachePolicy,
  341. pcbSent,
  342. pUlLogData );
  343. }
  344. HRESULT
  345. UlAtqSendEntityBody(
  346. ULATQ_CONTEXT pContext,
  347. BOOL fAsync,
  348. DWORD dwFlags,
  349. USHORT cChunks,
  350. HTTP_DATA_CHUNK * pChunks,
  351. DWORD *pcbSent,
  352. HTTP_LOG_FIELDS_DATA *pUlLogData
  353. )
  354. /*++
  355. Routine Description:
  356. Send entity to the client
  357. Arguments:
  358. pContext - ULATQ_CONTEXT
  359. fAsync - Asynchronous or not?
  360. dwFlags - Response flags (like killing the connection)
  361. cChunks - Number of chunks in the response
  362. pChunks - Points to array of chunks
  363. Return Value:
  364. HRESULT
  365. --*/
  366. {
  367. UL_NATIVE_REQUEST * pRequest;
  368. pRequest = (UL_NATIVE_REQUEST*) pContext;
  369. DBG_ASSERT( pRequest != NULL );
  370. return pRequest->SendEntity( fAsync,
  371. dwFlags,
  372. cChunks,
  373. pChunks,
  374. pcbSent,
  375. pUlLogData );
  376. }
  377. HRESULT
  378. UlAtqReceiveEntityBody(
  379. ULATQ_CONTEXT pContext,
  380. BOOL fAsync,
  381. DWORD dwFlags,
  382. VOID * pBuffer,
  383. DWORD cbBuffer,
  384. DWORD * pBytesReceived
  385. )
  386. /*++
  387. Routine Description:
  388. Receive entity from the client
  389. Arguments:
  390. pContext - ULATQ_CONTEXT
  391. fAsync - Asynchronous or not?
  392. dwFlags - Response flags (like killing the connection)
  393. pBuffer - Buffer to store the data
  394. cbBuffer - The size of the receive buffer
  395. pBytesReceived - The number of bytes copied to the buffer upon return
  396. Return Value:
  397. HRESULT
  398. --*/
  399. {
  400. UL_NATIVE_REQUEST * pRequest;
  401. pRequest = (UL_NATIVE_REQUEST*) pContext;
  402. DBG_ASSERT( pRequest != NULL );
  403. return pRequest->ReceiveEntity( fAsync,
  404. dwFlags,
  405. pBuffer,
  406. cbBuffer,
  407. pBytesReceived);
  408. }
  409. HRESULT
  410. UlAtqWaitForDisconnect(
  411. HTTP_CONNECTION_ID connectionId,
  412. BOOL fAsync,
  413. PVOID pvContext,
  414. BOOL * pfAlreadyCompleted
  415. )
  416. /*++
  417. Routine Description:
  418. Used to wait for a connection to close.
  419. Arguments:
  420. connectionId - connection in question
  421. fAsync - should we wait asynchronously?
  422. pvContext - context to pass back on async disconnect wait
  423. Return Value:
  424. HRESULT
  425. --*/
  426. {
  427. UL_DISCONNECT_CONTEXT * pContext;
  428. ULONG Status;
  429. HRESULT hr = NO_ERROR;
  430. HANDLE hAsync;
  431. //
  432. // Allocate an async context which will be freed once the connection
  433. // has been closed
  434. //
  435. pContext = new UL_DISCONNECT_CONTEXT( pvContext );
  436. if ( pContext == NULL )
  437. {
  438. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  439. }
  440. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  441. pContext->ReferenceUlDisconnectContext();
  442. if ( hAsync != NULL )
  443. {
  444. //
  445. // Do the wait
  446. //
  447. Status = HttpWaitForDisconnect( hAsync,
  448. connectionId,
  449. fAsync ? &(pContext->_Overlapped) : NULL );
  450. }
  451. else
  452. {
  453. Status = ERROR_INVALID_HANDLE;
  454. }
  455. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  456. if ( pfAlreadyCompleted )
  457. {
  458. *pfAlreadyCompleted = HasOverlappedIoCompleted( &(pContext->_Overlapped) );
  459. }
  460. if ( Status != ERROR_IO_PENDING && Status != NO_ERROR )
  461. {
  462. hr = HRESULT_FROM_WIN32( Status );
  463. pContext->DereferenceUlDisconnectContext();
  464. }
  465. pContext->DereferenceUlDisconnectContext();
  466. return hr;
  467. }
  468. HRESULT
  469. UlAtqInduceShutdown(
  470. BOOL fImmediate
  471. )
  472. /*++
  473. Routine Description:
  474. Induce shutdown (used when IIS+ hosted in inetinfo.exe). Simulates
  475. WAS telling us to shutdown
  476. Arguments:
  477. None
  478. Return Value:
  479. HRESULT
  480. --*/
  481. {
  482. DBG_ASSERT( g_pwpContext != NULL );
  483. if ( !g_pwpContext->IndicateShutdown( fImmediate ) )
  484. {
  485. return HRESULT_FROM_WIN32( GetLastError() );
  486. }
  487. return NO_ERROR;
  488. }
  489. HRESULT
  490. UlAtqReceiveClientCertificate(
  491. ULATQ_CONTEXT pContext,
  492. BOOL fAsync,
  493. BOOL fDoCertMap,
  494. HTTP_SSL_CLIENT_CERT_INFO **ppClientCertInfo
  495. )
  496. /*++
  497. Routine Description:
  498. Receive client certificate
  499. Arguments:
  500. pContext - ULATQ context
  501. fAsync - TRUE if we should do it asynchronously
  502. fDoCertMap - Map client certificate to token
  503. ppClientCertInfo - Set to point to client cert on success
  504. Return Value:
  505. HRESULT
  506. --*/
  507. {
  508. UL_NATIVE_REQUEST * pRequest;
  509. pRequest = (UL_NATIVE_REQUEST*) pContext;
  510. DBG_ASSERT( pRequest != NULL );
  511. DBG_ASSERT( pRequest->CheckSignature() );
  512. return pRequest->ReceiveClientCertificate( fAsync,
  513. fDoCertMap,
  514. ppClientCertInfo );
  515. }
  516. HRESULT
  517. UlAtqFlushUlCache(
  518. WCHAR * pszUrlPrefix
  519. )
  520. /*++
  521. Routine Description:
  522. Flush the UL cache at the given URL prefix
  523. Arguments:
  524. pszUrlPrefix - UL prefix to flush
  525. Return Value:
  526. HRESULT
  527. --*/
  528. {
  529. HANDLE hAsync;
  530. if ( pszUrlPrefix == NULL )
  531. {
  532. DBG_ASSERT( FALSE );
  533. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  534. }
  535. if ( g_pwpContext == NULL )
  536. {
  537. //
  538. // Before removing this assert, please think hard (and then
  539. // think again)
  540. //
  541. DBG_ASSERT( FALSE );
  542. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  543. }
  544. //
  545. // The AppPool handle may already have been closed, eg during shutdown
  546. //
  547. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  548. if ( hAsync != NULL )
  549. {
  550. HttpFlushResponseCache( hAsync,
  551. pszUrlPrefix,
  552. 0,
  553. NULL );
  554. }
  555. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  556. //
  557. // Mask the error since we may be flushing URLs which aren't
  558. // in the cache (that's OK)
  559. //
  560. return NO_ERROR;
  561. }
  562. VOID
  563. UlAtqSetUnhealthy(
  564. VOID
  565. )
  566. /*++
  567. Routine Description:
  568. Marks the state of the process as unhealthy
  569. Arguments:
  570. None
  571. Return Value:
  572. None
  573. --*/
  574. {
  575. g_pwpContext->SetUnhealthy();
  576. }
  577. HRESULT
  578. UlAtqAddFragmentToCache(
  579. HTTP_DATA_CHUNK * pDataChunk,
  580. WCHAR * pszFragmentName
  581. )
  582. /*++
  583. Routine Description:
  584. Add the fragment to cache
  585. Arguments:
  586. pDataChunk - The chunk to be added
  587. pszFragmentName - name of the fragment
  588. Return Value:
  589. HRESULT
  590. --*/
  591. {
  592. DWORD err;
  593. HANDLE hAsync;
  594. HTTP_CACHE_POLICY cachePolicy = { HttpCachePolicyUserInvalidates, 0 };
  595. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  596. if ( hAsync != NULL )
  597. {
  598. err = HttpAddFragmentToCache( hAsync,
  599. pszFragmentName,
  600. pDataChunk,
  601. &cachePolicy,
  602. NULL );
  603. }
  604. else
  605. {
  606. err = ERROR_INVALID_HANDLE;
  607. }
  608. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  609. return HRESULT_FROM_WIN32(err);
  610. }
  611. HRESULT
  612. UlAtqReadFragmentFromCache(
  613. WCHAR * pszFragmentName,
  614. BYTE * pvBuffer,
  615. DWORD cbSize,
  616. DWORD * pcbCopied
  617. )
  618. /*++
  619. Routine Description:
  620. Read the fragment from cache
  621. Arguments:
  622. pszFragmentName - name of the fragment
  623. pvBuffer - the buffer to read in
  624. cbSize - the size of the buffer
  625. pcbCopied - the amount copied in on return
  626. Return Value:
  627. HRESULT
  628. --*/
  629. {
  630. DWORD err;
  631. HANDLE hAsync;
  632. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  633. if ( hAsync != NULL )
  634. {
  635. err = HttpReadFragmentFromCache( hAsync,
  636. pszFragmentName,
  637. NULL,
  638. pvBuffer,
  639. cbSize,
  640. pcbCopied,
  641. NULL);
  642. }
  643. else
  644. {
  645. err = ERROR_INVALID_HANDLE;
  646. }
  647. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  648. return HRESULT_FROM_WIN32(err);
  649. }
  650. HRESULT
  651. UlAtqRemoveFragmentFromCache(
  652. WCHAR * pszFragmentName
  653. )
  654. /*++
  655. Routine Description:
  656. Remove the fragment from cache
  657. Arguments:
  658. pszFragmentName - name of the fragment
  659. Return Value:
  660. HRESULT
  661. --*/
  662. {
  663. DWORD err;
  664. HANDLE hAsync;
  665. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  666. if ( hAsync != NULL )
  667. {
  668. err = HttpFlushResponseCache( hAsync,
  669. pszFragmentName,
  670. 0,
  671. NULL);
  672. }
  673. else
  674. {
  675. err = ERROR_INVALID_HANDLE;
  676. }
  677. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  678. return HRESULT_FROM_WIN32(err);
  679. }
  680. VOID *
  681. UlAtqAllocateMemory(
  682. ULATQ_CONTEXT pContext,
  683. DWORD cbSize
  684. )
  685. /*++
  686. Routine Description:
  687. Allocate some memory associated with the native request
  688. Arguments:
  689. pContext - ULATQ Context
  690. cbSize - Size to allocate
  691. Return Value:
  692. Pointer to memory or NULL if failed
  693. --*/
  694. {
  695. UL_NATIVE_REQUEST * pRequest;
  696. if ( pContext == NULL )
  697. {
  698. DBG_ASSERT( FALSE );
  699. SetLastError( ERROR_INVALID_PARAMETER );
  700. return NULL;
  701. }
  702. pRequest = (UL_NATIVE_REQUEST*) pContext;
  703. DBG_ASSERT( pRequest->CheckSignature() );
  704. return pRequest->AllocateMemory( cbSize );
  705. }