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.

569 lines
16 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. WpConfig.cxx
  5. Abstract:
  6. Module implementing the Worker Process Configuration Data structure.
  7. WP_CONFIG object encapsulates configuration supplied from the commandline
  8. as well as remotely supplied from the admin process.
  9. Author:
  10. Murali R. Krishnan ( MuraliK ) 21-Oct-1998
  11. Environment:
  12. Win32 - User Mode
  13. Project:
  14. IIS Worker Process
  15. --*/
  16. /************************************************************
  17. * Include Headers
  18. ************************************************************/
  19. #include "precomp.hxx"
  20. /************************************************************
  21. Launch Parameters for W3WP:
  22. Private: ( one's only WAS uses )
  23. -r <N> ( Number of requests to recycle wp after )
  24. -t <N> ( Number of idle milliseconds to shutdown the WP after )
  25. -a <guid> ( look for WAS and register with this namepipe )
  26. -c ( Use binary centralized logging )
  27. Public: ( one's that can be used by command line launch ( must have -Debug )
  28. -Debug ( tells us that the user is trying to do the command line launch
  29. for debugging purposes has the side affect of not registering with WAS )
  30. -d <URL List> ( overrides the default url list of * port 80 with a specific list )
  31. -s <N> ( indicates the site that we should assume when listening to these urls ( default is site 1 ) )
  32. Both: ( one's used by either command line or was )
  33. -ap <AppPoolName> ( AppPool Name that the wp is serving )
  34. No one: ( were originally here, but are not being used and are being disabled by my change )
  35. -l ( log errors that stop the worker process into the event log )
  36. -ld ( disables logging of errors of the worker process to the event log )
  37. -ad ( don't look for WAS nor register with it )
  38. -p ( tells COR to add IceCAP instrumentation )
  39. URL List looks like:
  40. {http[s]://IP:port/URL | http[s]://hostname:port/URL | http[s]://hostname:port:IP/URL}+
  41. with space as separator
  42. eg: -d http://localhost:80/ => listen for all HTTP requests on port 80
  43. eg: -d http://localhost:80/ http://localhost:81/ => listen on port 80 & 81
  44. eg: -d http://foo:80:111.11.ll.111/ => listen on port 80 to request to 111.11.11.111 with foo as a header.
  45. ************************************************************/
  46. //
  47. // While the above shows all the usages for the w3wp command line parameters,
  48. // the print statment will only show the usage for the actual parameters that
  49. // users can use.
  50. //
  51. const WCHAR g_rgwchUsage[] =
  52. L"Usage: %ws [options] \n"
  53. L"\n"
  54. L"\t-debug \n"
  55. L"\t\t This option is required for launching from the command line.\n"
  56. L"\t\t If not provided the app pool name, default url, and site id \n"
  57. L"\t\t will be defaulted to \n"
  58. L"\t\t\t AppPoolName = StandAloneAppPool \n"
  59. L"\t\t\t URL list = http://*:80/ \n"
  60. L"\t\t\t Site Id = 1 \n"
  61. L"\n"
  62. L"\t-ap <Application Pool Name> \n"
  63. L"\t\t Indicates the application pool name\n"
  64. L"\t\t that will queue requests for the\n"
  65. L"\t\t worker process. No other worker processes \n"
  66. L"\t\t with this name can be running at the \n"
  67. L"\t\t same time as this one \n"
  68. L"\n"
  69. L"\t-d <URL List> \n"
  70. L"\t\t Indicates the urls to listen to. \n"
  71. L"\t\t Examples: \n"
  72. L"\t\t\t http://*:80/ \n"
  73. L"\t\t\t http://HostString:80/ \n"
  74. L"\t\t\t http://111.11.111.11:80:111.11.111.11/ \n"
  75. L"\t\t\t http://HostString:80:111.11.111.11/ \n"
  76. L"\n"
  77. L"\t-s <#> \n"
  78. L"\t\t Which site are the urls provided associated with. \n"
  79. L"\t\t The site number is used to access data from the metabase \n"
  80. L"\t\t for processing the requests. \n"
  81. ;
  82. /************************************************************
  83. * Member functions of WP_CONFIG
  84. ************************************************************/
  85. WP_CONFIG::WP_CONFIG(void)
  86. : _pwszAppPoolName (AP_NAME),
  87. _fSetupControlChannel(FALSE),
  88. _fLogErrorsToEventLog(FALSE),
  89. _fRegisterWithWAS (TRUE),
  90. _RestartCount (0),
  91. _pwszNamedPipeId (NULL),
  92. _IdleTime (0),
  93. _SiteId (0),
  94. _fDoCentralBinaryLogging (FALSE)
  95. {
  96. lstrcpy( _pwszProgram, L"WP");
  97. }
  98. WP_CONFIG::~WP_CONFIG()
  99. {
  100. _ulcc.Cleanup();
  101. delete[] _pwszNamedPipeId;
  102. _pwszNamedPipeId = NULL;
  103. }
  104. void
  105. WP_CONFIG::PrintUsage() const
  106. {
  107. wprintf( g_rgwchUsage, _pwszProgram );
  108. }
  109. /********************************************************************++
  110. Routine Description:
  111. Parses the command line to read in all configuration supplied.
  112. This function updates the state variables inside WP_CONFIG for use
  113. in starting up the Worker process.
  114. See comment at beginning of file for details on the arguments that can be supplied
  115. Arguments:
  116. argc - count of arguments supplied
  117. argv - pointer to strings containing the arguments.
  118. Returns:
  119. Boolean
  120. --********************************************************************/
  121. BOOL
  122. WP_CONFIG::ParseCommandLine(int argc, PWSTR argv[])
  123. {
  124. BOOL fRet = TRUE;
  125. int iArg;
  126. BOOL fAppPoolNameFound = FALSE;
  127. BOOL fUrlsFound = FALSE;
  128. lstrcpyn( _pwszProgram, argv[0], sizeof _pwszProgram / sizeof _pwszProgram[0]);
  129. if ( argc < 2)
  130. {
  131. DBGPRINTF((DBG_CONTEXT, "Invalid number of parameters (%d)\n", argc));
  132. PrintUsage();
  133. return (FALSE);
  134. }
  135. for( iArg = 1; iArg < argc; iArg++)
  136. {
  137. // get out of here if we all ready found an error.
  138. if ( fRet == FALSE )
  139. {
  140. break;
  141. }
  142. if ( (argv[iArg][0] == L'-') || (argv[iArg][0] == L'/'))
  143. {
  144. switch (argv[iArg][1])
  145. {
  146. case L's': case L'S':
  147. if ( argv[iArg][2] != '\0' )
  148. {
  149. DBGPRINTF((DBG_CONTEXT, "invalid argument %S\n", argv[iArg]));
  150. fRet = FALSE;
  151. }
  152. else
  153. {
  154. _SiteId = wcstoul(argv[++iArg], NULL, 0);
  155. if (_SiteId == 0)
  156. {
  157. DBGPRINTF((DBG_CONTEXT, "Invalid site id %ws\n", argv[iArg]));
  158. fRet = FALSE;
  159. }
  160. else
  161. {
  162. DBGPRINTF((DBG_CONTEXT, "Site Id is %lu\n", _SiteId));
  163. }
  164. }
  165. break;
  166. case L'd': case L'D':
  167. if ( _wcsicmp(&(argv[iArg][1]), L"Debug") == 0 )
  168. {
  169. _fSetupControlChannel = TRUE;
  170. }
  171. else if ( argv[iArg][2] != '\0' )
  172. {
  173. DBGPRINTF((DBG_CONTEXT, "invalid argument %S\n", argv[iArg]));
  174. fRet = FALSE;
  175. }
  176. else
  177. {
  178. fUrlsFound = TRUE;
  179. // need to determine if the string is just d or if it is debug here.
  180. iArg++;
  181. while ( (iArg < argc) &&
  182. (argv[iArg][0] != L'-') && (argv[iArg][0] != L'/'))
  183. {
  184. if ( !InsertURLIntoList(argv[iArg]) )
  185. {
  186. DBGPRINTF((DBG_CONTEXT, "Invalid URL: %ws\n", argv[iArg]));
  187. }
  188. iArg++;
  189. }
  190. iArg--;
  191. }
  192. break;
  193. case L'a': case L'A':
  194. if ( ((L'p' == argv[iArg][2]) || (L'P' == argv[iArg][2])) &&
  195. (L'\0' == argv[iArg][3] ))
  196. {
  197. //
  198. // get the app pool name
  199. //
  200. iArg++;
  201. _pwszAppPoolName = argv[iArg];
  202. fAppPoolNameFound = TRUE;
  203. }
  204. else if ( L'\0' != argv[iArg][2] )
  205. {
  206. DBGPRINTF((DBG_CONTEXT, "invalid parameter passed in '%S' \n", argv[iArg]));
  207. fRet = FALSE;
  208. }
  209. else
  210. {
  211. // -a NamedPipeId
  212. iArg++;
  213. _pwszNamedPipeId = new WCHAR[wcslen(argv[iArg]) + 1];
  214. if ( NULL == _pwszNamedPipeId )
  215. {
  216. DBGPRINTF((DBG_CONTEXT, "Failed allocation for named pipe name."));
  217. fRet = FALSE;
  218. }
  219. wcscpy(_pwszNamedPipeId, argv[iArg]);
  220. DBGPRINTF((DBG_CONTEXT, "NamedPipe Id, %S\n", _pwszNamedPipeId));
  221. }
  222. break;
  223. case L'r': case L'R':
  224. if ( argv[iArg][2] != '\0' )
  225. {
  226. DBGPRINTF((DBG_CONTEXT, "invalid argument %S\n", argv[iArg]));
  227. fRet = FALSE;
  228. }
  229. else
  230. {
  231. _RestartCount = wcstoul(argv[++iArg], NULL, 0);
  232. if (_RestartCount == 0)
  233. {
  234. DBGPRINTF((DBG_CONTEXT, "Invalid maximum requests %ws\n", argv[iArg]));
  235. fRet = FALSE;
  236. }
  237. else
  238. {
  239. DBGPRINTF((DBG_CONTEXT, "Maximum requests is %lu\n", _RestartCount));
  240. }
  241. }
  242. break;
  243. case L't': case L'T':
  244. if ( argv[iArg][2] != '\0' )
  245. {
  246. DBGPRINTF((DBG_CONTEXT, "invalid argument %S\n", argv[iArg]));
  247. fRet = FALSE;
  248. }
  249. else
  250. {
  251. _IdleTime = wcstoul(argv[++iArg], NULL, 0);
  252. if (_IdleTime == 0)
  253. {
  254. DBGPRINTF((DBG_CONTEXT, "Invalid idle time %ws\n", argv[iArg]));
  255. fRet = FALSE;
  256. }
  257. else
  258. {
  259. DBGPRINTF((DBG_CONTEXT, "The idle time value is %lu\n", _IdleTime));
  260. }
  261. }
  262. break;
  263. case L'c': case L'C':
  264. if ( argv[iArg][2] != '\0' )
  265. {
  266. DBGPRINTF((DBG_CONTEXT, "invalid argument %S\n", argv[iArg]));
  267. fRet = FALSE;
  268. }
  269. else
  270. {
  271. _fDoCentralBinaryLogging = TRUE;
  272. }
  273. break;
  274. default:
  275. case L'?':
  276. fRet = FALSE;
  277. break;
  278. } // switch
  279. }
  280. else
  281. {
  282. DBG_ASSERT ( !L"Argument passed in that does not start with '-' or '/'" );
  283. fRet = FALSE;
  284. break;
  285. }
  286. }
  287. if ( fRet )
  288. {
  289. // if we are still on the right track, do some parameter verification.
  290. // In command line launch mode we need to do some checks.
  291. if ( _fSetupControlChannel )
  292. {
  293. // Don't register with WAS.
  294. _fRegisterWithWAS = FALSE;
  295. if ( _SiteId == 0 )
  296. {
  297. // default the site id to 1.
  298. _SiteId = 1;
  299. }
  300. if ( !fUrlsFound )
  301. {
  302. if ( !InsertURLIntoList(L"http://*:80/") )
  303. {
  304. DBGPRINTF((DBG_CONTEXT, "Error adding default url\n"));
  305. fRet = FALSE;
  306. }
  307. }
  308. if ( !fAppPoolNameFound )
  309. {
  310. _pwszAppPoolName = L"StandAloneAppPool";
  311. }
  312. if ( _pwszNamedPipeId )
  313. {
  314. DBGPRINTF((DBG_CONTEXT, "Name pipe id can not be passed when in debugging mode\n"));
  315. fRet = FALSE;
  316. }
  317. if ( _RestartCount != 0 )
  318. {
  319. DBGPRINTF((DBG_CONTEXT, "Restart count can not be passed when in debugging mode\n"));
  320. fRet = FALSE;
  321. }
  322. if ( _IdleTime != 0 )
  323. {
  324. DBGPRINTF((DBG_CONTEXT, "Idle time can not be passed when in debugging mode\n"));
  325. fRet = FALSE;
  326. }
  327. }
  328. else
  329. {
  330. if ( _SiteId != 0 )
  331. {
  332. DBGPRINTF((DBG_CONTEXT, "Site id can not be passed when not in debugging mode\n"));
  333. fRet = FALSE;
  334. }
  335. if ( fUrlsFound )
  336. {
  337. DBGPRINTF((DBG_CONTEXT, "Urls can not be passed in when not in debugging mode\n"));
  338. fRet = FALSE;
  339. }
  340. if ( !fAppPoolNameFound )
  341. {
  342. DBGPRINTF((DBG_CONTEXT, "No app pool was passed and not in debugging mode\n"));
  343. fRet = FALSE;
  344. }
  345. if ( _pwszNamedPipeId == NULL )
  346. {
  347. DBGPRINTF((DBG_CONTEXT, "Named pipe id needs to be passed in when not in debugging mode\n"));
  348. fRet = FALSE;
  349. }
  350. if ( _fRegisterWithWAS == FALSE )
  351. {
  352. DBGPRINTF((DBG_CONTEXT, "We needs to register with WAS in when not in debugging mode\n"));
  353. fRet = FALSE;
  354. }
  355. }
  356. }
  357. if (!fRet)
  358. {
  359. PrintUsage();
  360. }
  361. return ( fRet);
  362. } // WP_CONFIG::ParseCommandLine()
  363. /********************************************************************++
  364. Routine Description:
  365. Sets up the control channel for processing requests. It uses
  366. the configuration parameters supplied for initializing the
  367. UL_CONTROL_CHANNEL.
  368. Arguments:
  369. Returns:
  370. Win32 error
  371. --********************************************************************/
  372. ULONG
  373. WP_CONFIG::SetupControlChannel(void)
  374. {
  375. //
  376. // Setup a control channel for our local use now. Used mainly for
  377. // the purpose of debugging.
  378. // In general control channel work is done by the AdminProces.
  379. //
  380. return _ulcc.Initialize( _mszURLList, _pwszAppPoolName, _SiteId );
  381. } // WP_CONFIG::SetupControlChannel()
  382. /********************************************************************++
  383. --********************************************************************/
  384. WP_CONFIG::InsertURLIntoList( LPCWSTR pwszURL )
  385. {
  386. LPCWSTR pwszOriginalURL = pwszURL;
  387. //
  388. // Minimum length: 11 (http://*:1/). Begins with http
  389. //
  390. if ( ( wcslen(pwszURL) < 11 ) || ( 0 != _wcsnicmp(pwszURL, L"http", 4)) )
  391. {
  392. return false;
  393. }
  394. pwszURL += 4;
  395. //
  396. // https
  397. //
  398. if ((L's' == *pwszURL) || (L'S' == *pwszURL))
  399. {
  400. pwszURL++;
  401. }
  402. //
  403. // ://
  404. //
  405. if ( (L':' != *pwszURL) || (L'/' != *(pwszURL+1)) || (L'/' != *(pwszURL+2)) )
  406. {
  407. return false;
  408. }
  409. pwszURL += 3;
  410. //
  411. // Skip host name or Ip Address
  412. //
  413. while ( (0 != *pwszURL) && ( L':' != *pwszURL))
  414. {
  415. pwszURL++;
  416. }
  417. //
  418. // Check port # exists
  419. //
  420. if (0 == *pwszURL)
  421. {
  422. return false;
  423. }
  424. //
  425. // Check port number is numeric
  426. //
  427. pwszURL++;
  428. while ( (0 != *pwszURL) && ( L'/' != *pwszURL) )
  429. {
  430. if (( L'0' > *pwszURL) || ( L'9' < *pwszURL))
  431. {
  432. return false;
  433. }
  434. pwszURL++;
  435. }
  436. //
  437. // Check / after port number exists
  438. //
  439. if (0 == *pwszURL)
  440. {
  441. return false;
  442. }
  443. //
  444. // URL is good.
  445. //
  446. IF_DEBUG( TRACE)
  447. {
  448. DBGPRINTF(( DBG_CONTEXT,
  449. "Inserting URL '%ws' into Config Group List\n",
  450. pwszOriginalURL
  451. ));
  452. }
  453. return ( TRUE == _mszURLList.Append( pwszOriginalURL));
  454. } // WP_CONFIG::InsertURLIntoList()