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.

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