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.

695 lines
14 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. //
  16. // Configuration parameters registry key.
  17. //
  18. #define INET_INFO_KEY \
  19. "System\\CurrentControlSet\\Services\\w3svc"
  20. #define INET_INFO_PARAMETERS_KEY \
  21. INET_INFO_KEY "\\Parameters"
  22. const CHAR g_pszWpRegLocation[] =
  23. INET_INFO_PARAMETERS_KEY "\\w3dt";
  24. DECLARE_DEBUG_PRINTS_OBJECT();
  25. DECLARE_DEBUG_VARIABLE();
  26. DECLARE_PLATFORM_TYPE();
  27. WP_CONTEXT * g_pwpContext = NULL;
  28. //
  29. // Completion routines for new requests, io completions, and disconnect
  30. // notifications.
  31. //
  32. // CODEWORK: Can we get away with these being global
  33. //
  34. PFN_ULATQ_NEW_REQUEST g_pfnNewRequest = NULL;
  35. PFN_ULATQ_IO_COMPLETION g_pfnIoCompletion = NULL;
  36. PFN_ULATQ_DISCONNECT g_pfnDisconnect = NULL;
  37. PFN_ULATQ_ON_SHUTDOWN g_pfnOnShutdown = NULL;
  38. PFN_ULATQ_COLLECT_PERF_COUNTERS g_pfnCollectCounters = NULL;
  39. HRESULT
  40. UlAtqInitialize(
  41. INT argc,
  42. LPWSTR argv[],
  43. ULATQ_CONFIG * pConfig
  44. )
  45. /*++
  46. Routine Description:
  47. Initialize ULATQ
  48. Arguments:
  49. argc - Number of command line parameters to worker process
  50. argv - Command line parameters
  51. pConfig - Configuration settings for ULATQ
  52. Return Value:
  53. HRESULT
  54. --*/
  55. {
  56. HRESULT rc = NO_ERROR;
  57. BOOL fUlInit = FALSE;
  58. BOOL fThreadPoolInit = FALSE;
  59. CREATE_DEBUG_PRINT_OBJECT("w3dt");
  60. if (!VALID_DEBUG_PRINT_OBJECT())
  61. {
  62. return E_FAIL;
  63. }
  64. LOAD_DEBUG_FLAGS_FROM_REG_STR( g_pszWpRegLocation, DEBUG_ERROR );
  65. INITIALIZE_PLATFORM_TYPE();
  66. //
  67. // Honour ULATQ_CONFIG settings. Set completion routines
  68. // Need to set this up before we do any other initialization
  69. //
  70. g_pfnNewRequest = pConfig->pfnNewRequest;
  71. g_pfnIoCompletion = pConfig->pfnIoCompletion;
  72. g_pfnDisconnect = pConfig->pfnDisconnect;
  73. g_pfnOnShutdown = pConfig->pfnOnShutdown;
  74. g_pfnCollectCounters = pConfig->pfnCollectCounters;
  75. //
  76. // Initialize the thread pool
  77. //
  78. rc = ThreadPoolInitialize();
  79. if ( FAILED( rc ) )
  80. {
  81. goto Finished;
  82. }
  83. fThreadPoolInit = TRUE;
  84. //
  85. // Init UL
  86. //
  87. rc = HttpInitialize( 0 );
  88. if ( rc != NO_ERROR )
  89. {
  90. DBGPRINTF(( DBG_CONTEXT, "Error (rc=%08x) in UlInitialize. Exiting\n",
  91. rc ));
  92. goto Finished;
  93. }
  94. fUlInit = TRUE;
  95. //
  96. // Create global state object
  97. //
  98. g_pwpContext = new WP_CONTEXT;
  99. if ( g_pwpContext == NULL )
  100. {
  101. rc = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  102. goto Finished;
  103. }
  104. //
  105. // Do global state initialization
  106. //
  107. rc = g_pwpContext->Initialize( argc, argv );
  108. if ( rc != NO_ERROR )
  109. {
  110. //
  111. // WP_CONTEXT::Initialize returns a Win32 error code
  112. //
  113. rc = HRESULT_FROM_WIN32( rc );
  114. goto Finished;
  115. }
  116. Finished:
  117. if ( rc != NO_ERROR )
  118. {
  119. if ( g_pwpContext != NULL )
  120. {
  121. delete g_pwpContext;
  122. g_pwpContext = NULL;
  123. }
  124. if ( fUlInit )
  125. {
  126. HttpTerminate();
  127. }
  128. if ( fThreadPoolInit )
  129. {
  130. ThreadPoolTerminate();
  131. }
  132. }
  133. return rc;
  134. }
  135. HRESULT
  136. UlAtqStartListen(
  137. VOID
  138. )
  139. /*++
  140. Routine Description:
  141. Begin listening for HTTP requests from UL. This call must happen only
  142. after ULATQ has been initialized correctly (for example, completion
  143. routines should be set).
  144. Arguments:
  145. None
  146. Return Value:
  147. HRESULT
  148. --*/
  149. {
  150. HRESULT rc = NO_ERROR;
  151. DBG_ASSERT( g_pfnIoCompletion != NULL );
  152. DBG_ASSERT( g_pfnNewRequest != NULL );
  153. //
  154. // Make some UlReceiveHttpRequest calls
  155. //
  156. rc = g_pwpContext->Start();
  157. if ( rc != NO_ERROR )
  158. {
  159. return rc;
  160. }
  161. //
  162. // Send message to WAS that our initialization is complete
  163. //
  164. g_pwpContext->SendInitCompleteMessage( S_OK );
  165. //
  166. // Wait for shutdown because of WAS/request-count-max/etc.
  167. //
  168. g_pwpContext->RunMainThreadLoop();
  169. //
  170. // Before connection drain, allow the user to execute some code
  171. //
  172. if ( g_pfnOnShutdown != NULL )
  173. {
  174. g_pfnOnShutdown( g_pwpContext->QueryDoImmediateShutdown() );
  175. }
  176. //
  177. // Before we return, wait for outstanding requests to drain. This
  178. // prevents race before caller's shutdown and new requests coming in
  179. //
  180. g_pwpContext->CleanupOutstandingRequests();
  181. return rc;
  182. }
  183. VOID
  184. UlAtqTerminate(
  185. HRESULT hrToSend
  186. )
  187. /*++
  188. Routine Description:
  189. Terminate ULATQ
  190. Arguments:
  191. None
  192. Return Value:
  193. None
  194. --*/
  195. {
  196. if ( g_pwpContext != NULL )
  197. {
  198. if (FAILED(hrToSend))
  199. {
  200. g_pwpContext->SendInitCompleteMessage( hrToSend );
  201. }
  202. g_pwpContext->Terminate();
  203. delete g_pwpContext;
  204. g_pwpContext = NULL;
  205. }
  206. HttpTerminate();
  207. ThreadPoolTerminate();
  208. DELETE_DEBUG_PRINT_OBJECT();
  209. }
  210. VOID *
  211. UlAtqGetContextProperty(
  212. ULATQ_CONTEXT pContext,
  213. ULATQ_CONTEXT_PROPERTY_ID PropertyId
  214. )
  215. /*++
  216. Routine Description:
  217. Get the UL_HTTP_REQUEST from the ULATQ_CONTEXT
  218. Arguments:
  219. pContext - ULATQ_CONTEXT
  220. PropertyId - Property Id to set
  221. Return Value:
  222. The actual property
  223. --*/
  224. {
  225. switch (PropertyId)
  226. {
  227. case ULATQ_PROPERTY_HTTP_REQUEST:
  228. UL_NATIVE_REQUEST * pRequest;
  229. pRequest = (UL_NATIVE_REQUEST*) pContext;
  230. DBG_ASSERT( pRequest != NULL );
  231. return pRequest->QueryHttpRequest();
  232. case ULATQ_PROPERTY_APP_POOL_ID:
  233. return (VOID *)g_pwpContext->QueryConfig()->QueryAppPoolName();
  234. default:
  235. DBG_ASSERT(FALSE);
  236. }
  237. return NULL;
  238. }
  239. VOID
  240. UlAtqSetContextProperty(
  241. ULATQ_CONTEXT pContext,
  242. ULATQ_CONTEXT_PROPERTY_ID PropertyId,
  243. PVOID pvData
  244. )
  245. /*++
  246. Routine Description:
  247. Set a property of the ULATQ_CONTEXT
  248. Arguments:
  249. pContext - ULATQ_CONTEXT
  250. PropertyId - Property Id to set
  251. pvData - Data specific to the property being set
  252. Return Value:
  253. None
  254. --*/
  255. {
  256. UL_NATIVE_REQUEST * pRequest;
  257. pRequest = (UL_NATIVE_REQUEST*) pContext;
  258. DBG_ASSERT( pRequest != NULL );
  259. switch ( PropertyId )
  260. {
  261. case ULATQ_PROPERTY_COMPLETION_CONTEXT:
  262. pRequest->SetContext( pvData );
  263. break;
  264. default:
  265. DBG_ASSERT( FALSE );
  266. }
  267. }
  268. VOID
  269. UlAtqFreeContext(
  270. ULATQ_CONTEXT pContext
  271. )
  272. /*++
  273. Routine Description:
  274. Frees the ULATQ_CONTEXT so that it can be used to retrieve next request
  275. Arguments:
  276. pContext - ULATQ_CONTEXT
  277. Return Value:
  278. None
  279. --*/
  280. {
  281. UL_NATIVE_REQUEST * pRequest;
  282. pRequest = (UL_NATIVE_REQUEST*) pContext;
  283. DBG_ASSERT( pRequest != NULL );
  284. pRequest->ResetContext();
  285. }
  286. HRESULT
  287. UlAtqSendHttpResponse(
  288. ULATQ_CONTEXT pContext,
  289. BOOL fAsync,
  290. DWORD dwFlags,
  291. HTTP_RESPONSE * pResponse,
  292. HTTP_CACHE_POLICY * pCachePolicy,
  293. DWORD *pcbSent,
  294. HTTP_LOG_FIELDS_DATA *pUlLogData
  295. )
  296. /*++
  297. Routine Description:
  298. Send a response to the client
  299. Arguments:
  300. pContext - ULATQ_CONTEXT
  301. fAsync - Asynchronous or not?
  302. dwFlags - Response flags (like killing the connection)
  303. pResponse - UL_HTTP_RESPONSE to send
  304. pCachePolicy - Cache policy
  305. Return Value:
  306. Win32 Error
  307. --*/
  308. {
  309. UL_NATIVE_REQUEST * pRequest;
  310. pRequest = (UL_NATIVE_REQUEST*) pContext;
  311. DBG_ASSERT( pRequest != NULL );
  312. return pRequest->SendResponse( fAsync,
  313. dwFlags,
  314. pResponse,
  315. pCachePolicy,
  316. pcbSent,
  317. pUlLogData );
  318. }
  319. HRESULT
  320. UlAtqSendEntityBody(
  321. ULATQ_CONTEXT pContext,
  322. BOOL fAsync,
  323. DWORD dwFlags,
  324. DWORD cChunks,
  325. HTTP_DATA_CHUNK * pChunks,
  326. DWORD *pcbSent,
  327. HTTP_LOG_FIELDS_DATA *pUlLogData
  328. )
  329. /*++
  330. Routine Description:
  331. Send entity to the client
  332. Arguments:
  333. pContext - ULATQ_CONTEXT
  334. fAsync - Asynchronous or not?
  335. dwFlags - Response flags (like killing the connection)
  336. cChunks - Number of chunks in the response
  337. pChunks - Points to array of chunks
  338. Return Value:
  339. HRESULT
  340. --*/
  341. {
  342. UL_NATIVE_REQUEST * pRequest;
  343. pRequest = (UL_NATIVE_REQUEST*) pContext;
  344. DBG_ASSERT( pRequest != NULL );
  345. return pRequest->SendEntity( fAsync,
  346. dwFlags,
  347. cChunks,
  348. pChunks,
  349. pcbSent,
  350. pUlLogData );
  351. }
  352. HRESULT
  353. UlAtqReceiveEntityBody(
  354. ULATQ_CONTEXT pContext,
  355. BOOL fAsync,
  356. DWORD dwFlags,
  357. VOID * pBuffer,
  358. DWORD cbBuffer,
  359. DWORD * pBytesReceived
  360. )
  361. /*++
  362. Routine Description:
  363. Receive entity from the client
  364. Arguments:
  365. pContext - ULATQ_CONTEXT
  366. fAsync - Asynchronous or not?
  367. dwFlags - Response flags (like killing the connection)
  368. pBuffer - Buffer to store the data
  369. cbBuffer - The size of the receive buffer
  370. pBytesReceived - The number of bytes copied to the buffer upon return
  371. Return Value:
  372. HRESULT
  373. --*/
  374. {
  375. UL_NATIVE_REQUEST * pRequest;
  376. pRequest = (UL_NATIVE_REQUEST*) pContext;
  377. DBG_ASSERT( pRequest != NULL );
  378. return pRequest->ReceiveEntity( fAsync,
  379. dwFlags,
  380. pBuffer,
  381. cbBuffer,
  382. pBytesReceived);
  383. }
  384. HRESULT
  385. UlAtqWaitForDisconnect(
  386. HTTP_CONNECTION_ID connectionId,
  387. BOOL fAsync,
  388. PVOID pvContext
  389. )
  390. /*++
  391. Routine Description:
  392. Used to wait for a connection to close.
  393. Arguments:
  394. connectionId - connection in question
  395. fAsync - should we wait asynchronously?
  396. pvContext - context to pass back on async disconnect wait
  397. Return Value:
  398. HRESULT
  399. --*/
  400. {
  401. UL_DISCONNECT_CONTEXT * pContext;
  402. ULONG Status;
  403. HRESULT hr = NO_ERROR;
  404. //
  405. // Allocate an async context which will be freed once the connection
  406. // has been closed
  407. //
  408. pContext = new UL_DISCONNECT_CONTEXT( pvContext );
  409. if ( pContext == NULL )
  410. {
  411. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  412. }
  413. //
  414. // Do the wait
  415. //
  416. Status = HttpWaitForDisconnect( g_pwpContext->GetAsyncHandle(),
  417. connectionId,
  418. fAsync ? &(pContext->_Overlapped) : NULL );
  419. if ( Status != ERROR_IO_PENDING && Status != NO_ERROR )
  420. {
  421. hr = HRESULT_FROM_WIN32( Status );
  422. delete pContext;
  423. }
  424. return hr;
  425. }
  426. HRESULT
  427. UlAtqInduceShutdown(
  428. BOOL fImmediate
  429. )
  430. /*++
  431. Routine Description:
  432. Induce shutdown (used when IIS+ hosted in inetinfo.exe). Simulates
  433. WAS telling us to shutdown
  434. Arguments:
  435. None
  436. Return Value:
  437. HRESULT
  438. --*/
  439. {
  440. DBG_ASSERT( g_pwpContext != NULL );
  441. if ( !g_pwpContext->IndicateShutdown( fImmediate ) )
  442. {
  443. return HRESULT_FROM_WIN32( GetLastError() );
  444. }
  445. return NO_ERROR;
  446. }
  447. HRESULT
  448. UlAtqReceiveClientCertificate(
  449. ULATQ_CONTEXT pContext,
  450. BOOL fAsync,
  451. BOOL fDoCertMap,
  452. HTTP_SSL_CLIENT_CERT_INFO **ppClientCertInfo
  453. )
  454. /*++
  455. Routine Description:
  456. Receive client certificate
  457. Arguments:
  458. pContext - ULATQ context
  459. fAsync - TRUE if we should do it asynchronously
  460. fDoCertMap - Map client certificate to token
  461. ppClientCertInfo - Set to point to client cert on success
  462. Return Value:
  463. HRESULT
  464. --*/
  465. {
  466. UL_NATIVE_REQUEST * pRequest;
  467. pRequest = (UL_NATIVE_REQUEST*) pContext;
  468. DBG_ASSERT( pRequest != NULL );
  469. DBG_ASSERT( pRequest->CheckSignature() );
  470. return pRequest->ReceiveClientCertificate( fAsync,
  471. fDoCertMap,
  472. ppClientCertInfo );
  473. }
  474. HRESULT
  475. UlAtqFlushUlCache(
  476. WCHAR * pszUrlPrefix
  477. )
  478. /*++
  479. Routine Description:
  480. Flush the UL cache at the given URL prefix
  481. Arguments:
  482. pszUrlPrefix - UL prefix to flush
  483. Return Value:
  484. HRESULT
  485. --*/
  486. {
  487. if ( pszUrlPrefix == NULL )
  488. {
  489. DBG_ASSERT( FALSE );
  490. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  491. }
  492. if ( g_pwpContext == NULL )
  493. {
  494. //
  495. // Before removing this assert, please think hard (and then
  496. // think again)
  497. //
  498. DBG_ASSERT( FALSE );
  499. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  500. }
  501. HttpFlushResponseCache( g_pwpContext->GetAsyncHandle(),
  502. pszUrlPrefix,
  503. HTTP_FLUSH_RESPONSE_FLAG_RECURSIVE,
  504. NULL );
  505. //
  506. // Mask the error since we may be flushing URLs which aren't
  507. // in the cache (that's OK)
  508. //
  509. return NO_ERROR;
  510. }