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.

553 lines
11 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. wpipm.cxx
  5. Abstract:
  6. Contains the WPIPM class that handles communication with
  7. the admin service. WPIPM responds to pings, and tells
  8. the process when to shut down.
  9. Author:
  10. Michael Courage (MCourage) 22-Feb-1999
  11. Revision History:
  12. --*/
  13. #include <precomp.hxx>
  14. #include "dbgutil.h"
  15. #include "wpipm.hxx"
  16. extern PFN_ULATQ_COLLECT_PERF_COUNTERS g_pfnCollectCounters;
  17. /**
  18. *
  19. * Routine Description:
  20. *
  21. * Initializes WPIPM.
  22. *
  23. * Arguments:
  24. *
  25. * pWpContext - pointer to the wp context (so we can tell it to shutdown)
  26. *
  27. * Return Value:
  28. *
  29. * HRESULT
  30. */
  31. HRESULT
  32. WP_IPM::Initialize(
  33. WP_CONTEXT * pWpContext
  34. )
  35. {
  36. HRESULT hr = S_OK;
  37. m_pWpContext = pWpContext;
  38. DWORD dwId = GetCurrentProcessId();
  39. //
  40. // create pipe
  41. //
  42. hr = IPM_MESSAGE_PIPE::CreateIpmMessagePipe(this,
  43. pWpContext->QueryConfig()->QueryNamedPipeId(),
  44. FALSE, // not server side
  45. NULL, // security descriptor
  46. &m_pPipe);
  47. if (FAILED(hr))
  48. {
  49. goto exit;
  50. }
  51. //
  52. // Send the real pid over the pipe
  53. //
  54. hr = m_pPipe->WriteMessage(IPM_OP_GETPID,
  55. sizeof(dwId),
  56. &dwId);
  57. if (FAILED(hr))
  58. {
  59. goto exit;
  60. }
  61. hr = S_OK;
  62. exit:
  63. if (FAILED(hr))
  64. {
  65. Terminate();
  66. }
  67. return hr;
  68. }
  69. /**
  70. *
  71. * Routine Description:
  72. *
  73. * Terminates WPIPM.
  74. *
  75. * If the message pipe is open this function will disconnect it
  76. * and wait for the pipe's disconnection callback.
  77. *
  78. * Arguments:
  79. *
  80. * None.
  81. *
  82. * Return Value:
  83. *
  84. * HRESULT
  85. */
  86. HRESULT
  87. WP_IPM::Terminate(
  88. VOID
  89. )
  90. {
  91. if (m_pPipe)
  92. {
  93. m_pPipe->DestroyIpmMessagePipe();
  94. // pipe deletes itself
  95. m_pPipe = NULL;
  96. }
  97. m_pWpContext = NULL;
  98. return S_OK;
  99. }
  100. /**
  101. *
  102. *
  103. * Routine Description:
  104. *
  105. * This is a callback from the message pipe that means
  106. * the pipe has received a message.
  107. *
  108. * We decode the message and respond appropriately.
  109. *
  110. * Arguments:
  111. *
  112. * pPipeMessage - the message that we received
  113. *
  114. * Return Value:
  115. *
  116. * HRESULT
  117. *
  118. */
  119. VOID
  120. WP_IPM::AcceptMessage(
  121. IN const IPM_MESSAGE * pPipeMessage
  122. )
  123. {
  124. HRESULT hr = NO_ERROR;
  125. BOOL fRet = FALSE;
  126. switch (pPipeMessage->GetOpcode())
  127. {
  128. case IPM_OP_PING:
  129. //
  130. // Pings must go through the same mechanism that requests go through
  131. // to verify that requests are being picked off of the completion port
  132. //
  133. fRet = ThreadPoolPostCompletion(0, HandlePing, (LPOVERLAPPED)this);
  134. if (FALSE == fRet)
  135. {
  136. hr = HRESULT_FROM_WIN32(GetLastError());
  137. DBGPRINTF((DBG_CONTEXT, "Posting completion for ping handling failed"));
  138. break;
  139. }
  140. break;
  141. case IPM_OP_SHUTDOWN:
  142. hr = HandleShutdown(
  143. *( reinterpret_cast<const BOOL *>( pPipeMessage->GetData() ) )
  144. );
  145. break;
  146. case IPM_OP_REQUEST_COUNTERS:
  147. hr = HandleCounterRequest();
  148. break;
  149. case IPM_OP_PERIODIC_PROCESS_RESTART_PERIOD_IN_MINUTES:
  150. DBG_ASSERT( pPipeMessage->GetData() != NULL );
  151. hr = WP_RECYCLER::StartTimeBased(
  152. *( reinterpret_cast<const DWORD *>( pPipeMessage->GetData() ) )
  153. );
  154. hr = NO_ERROR;
  155. break;
  156. case IPM_OP_PERIODIC_PROCESS_RESTART_MEMORY_USAGE_IN_KB:
  157. {
  158. DBG_ASSERT( pPipeMessage->GetData() != NULL );
  159. // there are 2 DWORDS sent with memory based recycling
  160. // first is Max Virtual Memory, second is Max Private Bytes
  161. DWORD dwMaxVirtualMemoryKbUsage =
  162. *( reinterpret_cast<const DWORD *>( pPipeMessage->GetData() ) );
  163. DWORD dwMaxPrivateBytesKbUsage =
  164. *( reinterpret_cast<const DWORD *>( pPipeMessage->GetData() ) + 1 );
  165. hr = WP_RECYCLER::StartMemoryBased(
  166. dwMaxVirtualMemoryKbUsage,
  167. dwMaxPrivateBytesKbUsage );
  168. hr = NO_ERROR;
  169. break;
  170. }
  171. case IPM_OP_PERIODIC_PROCESS_RESTART_SCHEDULE:
  172. DBG_ASSERT( pPipeMessage->GetData() != NULL );
  173. hr = WP_RECYCLER::StartScheduleBased(
  174. ( reinterpret_cast<const WCHAR *>( pPipeMessage->GetData() ) )
  175. );
  176. hr = NO_ERROR;
  177. break;
  178. default:
  179. DBG_ASSERT(FALSE);
  180. hr = E_FAIL;
  181. break;
  182. }
  183. return;
  184. }
  185. /**
  186. *
  187. * Routine Description:
  188. *
  189. * This is a callback from the message pipe that means
  190. * the pipe has been connected and is ready for use.
  191. *
  192. * Arguments:
  193. *
  194. * None.
  195. *
  196. * Return Value:
  197. *
  198. * VOID
  199. */
  200. VOID
  201. WP_IPM::PipeConnected(
  202. VOID
  203. )
  204. {
  205. return;
  206. }
  207. /**
  208. *
  209. * Routine Description:
  210. *
  211. * This is a callback from the message pipe that means
  212. * the pipe has been disconnected and you won't be receiving
  213. * any more messages.
  214. *
  215. * Tells WPIPM::Terminate that it's ok to exit now.
  216. *
  217. * Arguments:
  218. *
  219. * hr - the error code associated with the pipe disconnection
  220. *
  221. * Return Value:
  222. *
  223. * VOID
  224. */
  225. VOID
  226. WP_IPM::PipeDisconnected(
  227. IN HRESULT hr
  228. )
  229. {
  230. if (FAILED(hr))
  231. {
  232. IF_DEBUG( WPIPM )
  233. {
  234. DBGPRINTF(( DBG_CONTEXT, "FSDF" ));
  235. }
  236. }
  237. //
  238. // If the pipe disappears out from under us, WAS has probably orphaned
  239. // us, initiate fast shutdown of this worker process.
  240. //
  241. if (!m_pWpContext->IsInShutdown() &&
  242. hr != HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) &&
  243. IsDebuggerPresent())
  244. {
  245. DBG_ASSERT( !"w3wp.exe is getting orphaned" );
  246. }
  247. m_pWpContext->IndicateShutdown( TRUE );
  248. return;
  249. }
  250. /**
  251. *
  252. * Routine Description:
  253. *
  254. * This is a callback from the message pipe that means
  255. * that the pipe received an invalid message.
  256. * Therefore, we signal to shutdown.
  257. *
  258. * Arguments:
  259. *
  260. * VOID
  261. *
  262. * Return Value:
  263. *
  264. * VOID
  265. */
  266. VOID
  267. WP_IPM::PipeMessageInvalid(
  268. VOID
  269. )
  270. {
  271. return PipeDisconnected(HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
  272. }
  273. /**
  274. *
  275. * Routine Description:
  276. *
  277. * Handles the ping message. Sends the ping response message.
  278. *
  279. * Arguments:
  280. *
  281. * None.
  282. *
  283. * Return Value:
  284. *
  285. * HRESULT
  286. */
  287. //static
  288. VOID
  289. WP_IPM::HandlePing(
  290. DWORD,
  291. DWORD dwNumberOfBytesTransferred,
  292. LPOVERLAPPED lpOverlapped
  293. )
  294. {
  295. if (0 != dwNumberOfBytesTransferred)
  296. {
  297. DBG_ASSERT(0 == dwNumberOfBytesTransferred);
  298. return;
  299. }
  300. DBG_ASSERT(NULL != lpOverlapped);
  301. WP_IPM * pThis = (WP_IPM*) lpOverlapped;
  302. DBG_ASSERT(pThis->m_pPipe);
  303. HRESULT hr = NO_ERROR;
  304. IF_DEBUG( WPIPM )
  305. {
  306. DBGPRINTF((DBG_CONTEXT, "Handle Ping\n\n"));
  307. }
  308. hr = pThis->m_pPipe->WriteMessage(
  309. IPM_OP_PING_REPLY, // ping reply opcode
  310. 0, // no data to send
  311. NULL // pointer to no data
  312. );
  313. if ( FAILED ( hr ) )
  314. {
  315. IF_DEBUG( WPIPM )
  316. {
  317. DBGPRINTF((DBG_CONTEXT, "Failed to respond to ping\n\n"));
  318. }
  319. goto exit;
  320. }
  321. //
  322. // if we are not healthy then we need to to ask WAS to
  323. // shut us down.
  324. //
  325. if ( !( g_pwpContext->GetUnhealthy()))
  326. {
  327. IF_DEBUG( WPIPM )
  328. {
  329. DBGPRINTF((DBG_CONTEXT, "Requesting shutdown due to isapi reporting unhealthiness\n\n"));
  330. }
  331. hr = pThis->SendMsgToAdminProcess( IPM_WP_RESTART_ISAPI_REQUESTED_RECYCLE );
  332. if ( FAILED ( hr ) )
  333. {
  334. IF_DEBUG( WPIPM )
  335. {
  336. DBGPRINTF((DBG_CONTEXT, "Failed telling WAS to shut us down\n\n"));
  337. }
  338. goto exit;
  339. }
  340. }
  341. exit:
  342. return;
  343. }
  344. /**
  345. *
  346. * Routine Description:
  347. *
  348. * Handles the counter request message.
  349. *
  350. * Arguments:
  351. *
  352. * None.
  353. *
  354. * Return Value:
  355. *
  356. * HRESULT
  357. */
  358. HRESULT
  359. WP_IPM::HandleCounterRequest(
  360. VOID
  361. )
  362. {
  363. IF_DEBUG( WPIPM )
  364. {
  365. DBGPRINTF((DBG_CONTEXT, "Handle Counter Request\n\n"));
  366. }
  367. HRESULT hr;
  368. PBYTE pCounterData;
  369. DWORD dwCounterData;
  370. DBG_ASSERT ( m_pPipe );
  371. if (FAILED(hr = g_pfnCollectCounters(&pCounterData, &dwCounterData)))
  372. {
  373. return hr;
  374. }
  375. return m_pPipe->WriteMessage(IPM_OP_SEND_COUNTERS, // ping reply opcode
  376. dwCounterData, // no data to send
  377. pCounterData); // pointer to no data
  378. }
  379. /**
  380. *
  381. * Routine Description:
  382. *
  383. *
  384. * Handles the shutdown message. Shuts down the process
  385. *
  386. * Arguments:
  387. *
  388. * None.
  389. *
  390. * Return Value:
  391. *
  392. * HRESULT
  393. */
  394. HRESULT
  395. WP_IPM::HandleShutdown(
  396. BOOL fDoImmediate
  397. )
  398. {
  399. HRESULT hr = S_OK;
  400. IF_DEBUG( WPIPM )
  401. {
  402. DBGPRINTF((DBG_CONTEXT, "Handle ******************** Shutdown\n\n"));
  403. }
  404. m_pWpContext->IndicateShutdown( fDoImmediate );
  405. return hr;
  406. }
  407. /**
  408. *
  409. * Routine Description:
  410. *
  411. * Sends the message to indicate the worker process has either finished
  412. * initializing or has failed to initialize.
  413. *
  414. * Arguments:
  415. *
  416. * HRESULT indicating success/failure of initialization
  417. *
  418. * Return Value:
  419. *
  420. * HRESULT
  421. */
  422. HRESULT
  423. WP_IPM::SendInitCompleteMessage(
  424. HRESULT hrToSend
  425. )
  426. {
  427. if ( m_pPipe )
  428. {
  429. return m_pPipe->WriteMessage(
  430. IPM_OP_HRESULT, // opcode
  431. sizeof( hrToSend ), // data length
  432. reinterpret_cast<BYTE*>( &hrToSend ) // pointer to data
  433. );
  434. }
  435. // if the pipe did not exist then we started up
  436. // without the IPM, probably we are attempting
  437. // to run without WAS support. ( from the cmd line )
  438. return S_OK;
  439. }
  440. /**
  441. *
  442. * Routine Description:
  443. *
  444. * Sends the message to indicate the worker process has reach certain state.
  445. * Main use is in shutdown. See IPM_WP_SHUTDOWN_MSG for reasons.
  446. *
  447. * Arguments:
  448. *
  449. * None.
  450. *
  451. * Return Value:
  452. *
  453. * HRESULT
  454. */
  455. HRESULT
  456. WP_IPM::SendMsgToAdminProcess(
  457. IPM_WP_SHUTDOWN_MSG reason
  458. )
  459. {
  460. if (m_pPipe)
  461. {
  462. return m_pPipe->WriteMessage(
  463. IPM_OP_WORKER_REQUESTS_SHUTDOWN, // sends message indicate shutdown
  464. sizeof(reason), // no data to send
  465. (BYTE *)&reason // pointer to no data
  466. );
  467. }
  468. return S_OK;
  469. }