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.

437 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. waslaunch.cxx
  5. Abstract:
  6. These are the classes used to communicate between
  7. inetinfo and WAS for launching a worker process in
  8. inetinfo.
  9. Author:
  10. Emily Kruglick (EmilyK) 14-Jun-2000
  11. Revision History:
  12. --*/
  13. //
  14. // INCLUDES
  15. //
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <winsvc.h> // Service control APIs
  21. #include <rpc.h>
  22. #include <stdlib.h>
  23. #include <inetsvcs.h>
  24. #include <iis64.h>
  25. #include <wpif.h>
  26. #include "waslaunch.hxx"
  27. #include <objbase.h>
  28. //
  29. // System related headers
  30. //
  31. #ifndef _NO_TRACING_
  32. #include "dbgutil.h"
  33. #include "pudebug.h"
  34. #endif
  35. #include "ulw3.h"
  36. DECLARE_DEBUG_VARIABLE();
  37. //
  38. // Configuration parameters registry key.
  39. //
  40. // BUGBUG
  41. #undef INET_INFO_KEY
  42. #undef INET_INFO_PARAMETERS_KEY
  43. #define INET_INFO_KEY \
  44. "System\\CurrentControlSet\\Services\\iisw3adm"
  45. #define INET_INFO_PARAMETERS_KEY \
  46. INET_INFO_KEY "\\Parameters"
  47. const CHAR g_pszWpRegLocation[] =
  48. INET_INFO_PARAMETERS_KEY "\\WP";
  49. class DEBUG_WRAPPER {
  50. public:
  51. DEBUG_WRAPPER( IN LPCSTR pszModule)
  52. {
  53. #if DBG
  54. CREATE_DEBUG_PRINT_OBJECT( pszModule);
  55. #else
  56. UNREFERENCED_PARAMETER(pszModule);
  57. #endif
  58. LOAD_DEBUG_FLAGS_FROM_REG_STR( g_pszWpRegLocation, DEBUG_ERROR );
  59. }
  60. ~DEBUG_WRAPPER(void)
  61. { DELETE_DEBUG_PRINT_OBJECT(); }
  62. };
  63. VOID LaunchWorkerProcess()
  64. {
  65. DEBUG_WRAPPER dbgWrapper( "w3wp" );
  66. HRESULT hr = S_OK;
  67. HMODULE hModule = NULL;
  68. PFN_ULW3_ENTRY pEntry = NULL;
  69. BOOL fCoInit = FALSE;
  70. // Establish the parameters to pass in when starting
  71. // the worker process inside inetinfo.
  72. LPWSTR lpParameters[] =
  73. {
  74. { L"" }
  75. , { L"-a" }
  76. , { L"1" }
  77. , { L"DefaultAppPool" }
  78. };
  79. DWORD cParameters = 4;
  80. //
  81. // Do some COM junk
  82. //
  83. DBGPRINTF((
  84. DBG_CONTEXT,
  85. "Inetinfo launch WPW3 - CoInit. CTC = %d \n",
  86. GetTickCount()
  87. ));
  88. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  89. if (FAILED(hr))
  90. {
  91. DBGPRINTF(( DBG_CONTEXT,
  92. "Error in CoInitializeEx(). hr = %x\n",
  93. hr ));
  94. goto Finished;
  95. }
  96. fCoInit = TRUE;
  97. //
  98. // Load the ULW3 DLL which does all the work
  99. //
  100. DBGPRINTF((
  101. DBG_CONTEXT,
  102. "Inetinfo launch WPW3 - LoadLib. CTC = %d \n",
  103. GetTickCount()
  104. ));
  105. hModule = LoadLibraryW( ULW3_DLL_NAME );
  106. if ( hModule == NULL )
  107. {
  108. DBGPRINTF(( DBG_CONTEXT,
  109. "Error loading W3 service dll '%ws'. Error = %d\n",
  110. ULW3_DLL_NAME,
  111. GetLastError() ));
  112. goto Finished;
  113. }
  114. pEntry = (PFN_ULW3_ENTRY) GetProcAddress( hModule,
  115. ULW3_DLL_ENTRY );
  116. if ( pEntry == NULL )
  117. {
  118. DBGPRINTF(( DBG_CONTEXT,
  119. "Could not find entry point '%s'. Error = %d\n",
  120. ULW3_DLL_ENTRY,
  121. GetLastError() ));
  122. goto Finished;
  123. }
  124. DBGPRINTF((
  125. DBG_CONTEXT,
  126. "Inetinfo launch WPW3 - EntryPoint. CTC = %d \n",
  127. GetTickCount()
  128. ));
  129. hr = pEntry( cParameters,
  130. lpParameters,
  131. TRUE ); // Compatibility mode = TRUE
  132. if ( FAILED( hr ) )
  133. {
  134. DBGPRINTF(( DBG_CONTEXT,
  135. "Error executing W3WP. hr = %x\n",
  136. hr ));
  137. goto Finished;
  138. }
  139. Finished:
  140. //
  141. // Cleanup any lingering COM objects before unloading
  142. //
  143. if ( fCoInit )
  144. {
  145. CoUninitialize();
  146. }
  147. if ( hModule != NULL )
  148. {
  149. FreeLibrary( hModule );
  150. }
  151. }
  152. DWORD WaitOnIISAdminStartup(W3SVCLauncher* pLauncher)
  153. {
  154. DWORD dwErr = ERROR_SUCCESS;
  155. BOOL IISAdminIsStarted = FALSE;
  156. SC_HANDLE hService = NULL;
  157. SERVICE_STATUS ServiceStatus;
  158. SC_HANDLE hManager = OpenSCManager(NULL, NULL, GENERIC_READ);
  159. if ( hManager == NULL )
  160. {
  161. dwErr = GetLastError();
  162. IIS_PRINTF((buff,
  163. "Failed to open the scm manager, can't wait on iisadmin %x\n",
  164. HRESULT_FROM_WIN32(dwErr)));
  165. goto exit;
  166. };
  167. hService = OpenServiceA( hManager, "IISADMIN", SERVICE_QUERY_STATUS);
  168. if ( hService == NULL )
  169. {
  170. dwErr = GetLastError();
  171. goto exit;
  172. };
  173. //
  174. // Make sure iisadmin has not started, and also verify that we are
  175. // still running ( so we don't hang the thread ).
  176. //
  177. while ( !IISAdminIsStarted && pLauncher->StillRunning() )
  178. {
  179. if ( QueryServiceStatus( hService, &ServiceStatus ) )
  180. {
  181. if ( ServiceStatus.dwCurrentState == SERVICE_RUNNING )
  182. {
  183. IISAdminIsStarted = TRUE;
  184. }
  185. else
  186. {
  187. Sleep ( 1000 );
  188. }
  189. }
  190. else
  191. {
  192. dwErr = GetLastError();
  193. goto exit;
  194. }
  195. }; // end of loop
  196. exit:
  197. if ( hService )
  198. {
  199. CloseServiceHandle ( hService );
  200. hService = NULL;
  201. };
  202. if ( hManager )
  203. {
  204. CloseServiceHandle ( hManager );
  205. hManager = NULL;
  206. };
  207. return dwErr;
  208. };
  209. // Global Functions.
  210. DWORD WINAPI W3SVCThreadEntry(LPVOID lpParameter)
  211. {
  212. W3SVCLauncher* pLauncher = (W3SVCLauncher*) lpParameter;
  213. DWORD dwErr = ERROR_SUCCESS;
  214. dwErr = WaitOnIISAdminStartup(pLauncher);
  215. DBG_ASSERT (pLauncher);
  216. if ( pLauncher && dwErr == ERROR_SUCCESS )
  217. {
  218. // Wait on the W3SVCStartW3SP
  219. // If we are in shutdown mode just end, otherwise launch W3WP and wait
  220. // for it to return. Then loop back around.
  221. while (pLauncher->StillRunning())
  222. {
  223. // Do not care what the wait returns, just know that we did signal so we should
  224. // either end or start a W3WP in inetinfo.
  225. WaitForSingleObject(pLauncher->GetLaunchEvent(), INFINITE);
  226. DBGPRINTF((
  227. DBG_CONTEXT,
  228. "Inetinfo launch signal received. CTC = %d \n",
  229. GetTickCount()
  230. ));
  231. // Once inetinfo has heard the event reset it.
  232. if (!ResetEvent(pLauncher->GetLaunchEvent()))
  233. {
  234. dwErr = GetLastError();
  235. IIS_PRINTF((buff,
  236. "Inetinfo: Failed to reset the event %x\n",
  237. HRESULT_FROM_WIN32(dwErr)));
  238. break;
  239. }
  240. // Assuming we are still running we need
  241. // to start up the W3WP code now.
  242. if (pLauncher->StillRunning())
  243. {
  244. LaunchWorkerProcess();
  245. }
  246. }
  247. }
  248. DBGPRINTF((
  249. DBG_CONTEXT,
  250. "W3SVCThreadEntry exiting process (and thread). CTC = %d \n",
  251. GetTickCount()
  252. ));
  253. return dwErr;
  254. };
  255. W3SVCLauncher::W3SVCLauncher() :
  256. m_hW3SVCThread (NULL),
  257. m_hW3SVCStartEvent(NULL),
  258. m_dwW3SVCThreadId(0),
  259. m_bShutdown(FALSE)
  260. {};
  261. VOID W3SVCLauncher::StartListening()
  262. {
  263. // Make sure this function is not called twice
  264. // without a StopListening in between.
  265. DBG_ASSERT (m_hW3SVCStartEvent == NULL);
  266. DBG_ASSERT (m_hW3SVCThread == NULL);
  267. m_hW3SVCStartEvent = CreateEvent(NULL, TRUE, FALSE, WEB_ADMIN_SERVICE_START_EVENT_A);
  268. if (m_hW3SVCStartEvent != NULL)
  269. {
  270. // Before going off to the Service Controller set up a thread
  271. // that will allow WAS to contact inetinfo.exe if we need to start
  272. // w3wp inside of it for backward compatibility.
  273. m_hW3SVCThread = CreateThread( NULL // use current threads security
  274. , 0 // use default stack size
  275. , &W3SVCThreadEntry
  276. , this // pass this object in.
  277. , 0 // don't create suspended
  278. , &m_dwW3SVCThreadId);
  279. if (m_hW3SVCThread == NULL)
  280. {
  281. IIS_PRINTF((buff,
  282. "Inetinfo: Failed to start W3SVC listening thread %lu\n",
  283. GetLastError()));
  284. }
  285. }
  286. else
  287. {
  288. IIS_PRINTF((buff,
  289. "Inetinfo: Failed to create the W3SVC shutdown event so we can not start W3svc %lu\n",
  290. GetLastError()));
  291. }
  292. };
  293. VOID W3SVCLauncher::StopListening()
  294. {
  295. if (m_hW3SVCStartEvent && m_hW3SVCThread)
  296. {
  297. m_bShutdown = TRUE;
  298. if (!SetEvent(m_hW3SVCStartEvent))
  299. {
  300. IIS_PRINTF((buff, "Inetinfo: Failed to shutdown the W3SVC waiting thread %lu\n",
  301. GetLastError()));
  302. }
  303. DBGPRINTF((
  304. DBG_CONTEXT,
  305. "StopListening is waiting for thread exit. CTC = %d \n",
  306. GetTickCount()
  307. ));
  308. // Now wait on the thread to exit, so we don't allow
  309. // the caller to delete this object
  310. // before the thread is done deleting it's pieces.
  311. // BUGBUG: adjust the wait time to like 2 minutes
  312. // and use TerminateThread if we timeout.
  313. WaitForSingleObject(m_hW3SVCThread, INFINITE);
  314. CloseHandle(m_hW3SVCThread);
  315. m_hW3SVCThread = NULL;
  316. DBGPRINTF((
  317. DBG_CONTEXT,
  318. "StopListening thread has exited. CTC = %d \n",
  319. GetTickCount()
  320. ));
  321. }
  322. // Close down our handle to this event,
  323. // so the kernel can release it.
  324. if (m_hW3SVCStartEvent)
  325. {
  326. CloseHandle(m_hW3SVCStartEvent);
  327. m_hW3SVCStartEvent = NULL;
  328. }
  329. DBGPRINTF((
  330. DBG_CONTEXT,
  331. "Returning from stop listening call. CTC = %d \n",
  332. GetTickCount()
  333. ));
  334. };
  335. BOOL W3SVCLauncher::StillRunning()
  336. {
  337. return (m_bShutdown == FALSE);
  338. }
  339. HANDLE W3SVCLauncher::GetLaunchEvent()
  340. {
  341. DBG_ASSERT(m_hW3SVCStartEvent);
  342. return (m_hW3SVCStartEvent);
  343. }
  344. W3SVCLauncher::~W3SVCLauncher()
  345. {
  346. // Stop Listening should of been called first
  347. // which should of freed all of this.
  348. DBG_ASSERT(m_hW3SVCStartEvent == NULL);
  349. DBG_ASSERT(m_hW3SVCThread == NULL);
  350. };