/*++ Copyright (c) 1998 Microsoft Corporation Module Name : WpConfig.cxx Abstract: Module implementing the Worker Process Configuration Data structure. WP_CONFIG object encapsulates configuration supplied from the commandline as well as remotely supplied from the admin process. Author: Murali R. Krishnan ( MuraliK ) 21-Oct-1998 Environment: Win32 - User Mode Project: IIS Worker Process --*/ /************************************************************ * Include Headers ************************************************************/ #include "precomp.hxx" /* Usage: \bin\iisrearc\inetsrv\iiswp [options] APN APN -- AppPool Name -d -- Indicates that the process should register the given namespace itself. This mode is for running worker process in stand alone mode (for debugging) -l -- Log errors that stop the worker process into the eventlog -ld -- Disables logging the errors of worker process to eventlog (default is not write to eventlog) -a -- Look for web admin service and register with the same (default is look for web admin service) -ad -- Do not look for web admin service and do registration -r -- Restart the worker process after n requests. -t -- Shutdown the worker process if idle for n milliseconds. uses the syntax: {http[s]://IP:port/URL | http[s]://hostname:port/URL }+ with space as separator eg: -d http://localhost:80/ => listen for all HTTP requests on port 80 eg: -d http://localhost:80/ http://localhost:81/ => listen on port 80 & 81 */ const CHAR g_rgchUsage[] = "Usage: %ws [options] APN\n" "\tAPN -- AppPool Name\n" "\t-d -- Indicates that the process should register the given \n" "\t\tnamespace itself. This mode is for running worker process in\n" "\t\tstand alone mode (for debugging)\n" "\t-l -- Log errors that stop the worker process into the eventlog\n" "\t-ld -- Disables logging the errors of worker process to eventlog\n" "\t\t(default is not write to eventlog)\n" "\t-a -- Look for web admin service and register with the same\n" "\t\t(default is look for web admin service)\n" "\t-ad -- Do not look for web admin service and do registration\n" "\t-r -- Restart the worker process after n requests\n" "\t-t -- Shutdown the worker process if idle for n milliseconds\n" "\t-p -- Tell COR to add IceCAP instrumentation\n" "\t uses the syntax: {http[s]://IP:port/URL | http[s]://hostname:port/URL }+\n" "\t\twith space as separator\n" "\t\t eg: -d http://*:80/ => listen for all HTTP requests on port 80\n" "\t\t eg: -d http://localhost:80/ http://localhost:81/ => listen on port 80 & 81\n" ; /************************************************************ * Member functions of WP_CONFIG ************************************************************/ WP_CONFIG::WP_CONFIG(void) : _pwszAppPoolName (AP_NAME), _fSetupControlChannel(false), _fLogErrorsToEventLog(false), _fRegisterWithWAS (true), _RestartCount (0), _NamedPipeId (0), _IdleTime (0) { lstrcpy( _pwszProgram, L"WP"); } WP_CONFIG::~WP_CONFIG() { _ulcc.Cleanup(); } void WP_CONFIG::PrintUsage() const { DBGPRINTF((DBG_CONTEXT, g_rgchUsage, _pwszProgram)); } /********************************************************************++ Routine Description: Parses the command line to read in all configuration supplied. This function updates the state variables inside WP_CONFIG for use in starting up the Worker process. See g_rgchUsage[] for details on the arguments that can be supplied Arguments: argc - count of arguments supplied argv - pointer to strings containing the arguments. Returns: Boolean --********************************************************************/ BOOL WP_CONFIG::ParseCommandLine(int argc, PWSTR argv[]) { BOOL fRet = true; int iArg; lstrcpyn( _pwszProgram, argv[0], sizeof _pwszProgram / sizeof _pwszProgram[0]); if ( argc < 2) { DBGPRINTF((DBG_CONTEXT, "Invalid number of parameters (%d)\n", argc)); PrintUsage(); return (false); } for( iArg = 1; iArg < argc; iArg++) { if ( (argv[iArg][0] == L'-') || (argv[iArg][0] == L'/')) { switch (argv[iArg][1]) { case L'c': case L'C': DBGPRINTF((DBG_CONTEXT, "-C: obsolete\n")); break; case L'd': case L'D': _fSetupControlChannel = true; iArg++; while ( (iArg < argc-1) && (argv[iArg][0] != L'-') && (argv[iArg][0] != L'/')) { if ( !InsertURLIntoList(argv[iArg]) ) { DBGPRINTF((DBG_CONTEXT, "Invalid URL: %ws\n", argv[iArg])); } iArg++; } iArg--; break; case L'a': case L'A': if ( (L'd' == argv[iArg][2]) || (L'D' == argv[iArg][2])) { _fRegisterWithWAS = false; } else { // -a NamedPipeId if (L'\0' == argv[iArg][2]) { iArg++; } _NamedPipeId = wcstoul(argv[iArg], NULL, 0); DBGPRINTF((DBG_CONTEXT, "NamedPipe Id, %lu\n", _NamedPipeId)); if (0 == _NamedPipeId) { DBGPRINTF((DBG_CONTEXT, "Invalid NamedPipe Id, %ws\n", argv[iArg])); fRet = false; } } break; case L'l': case L'L': DBGPRINTF((DBG_CONTEXT, "Warning: This option is not supported presently\n")); if (L' ' == argv[iArg][0]) { _fLogErrorsToEventLog = true; } break; case L'r': case L'R': _RestartCount = wcstoul(argv[++iArg], NULL, 0); if (_RestartCount == 0) { DBGPRINTF((DBG_CONTEXT, "Invalid maximum requests %ws\n", argv[iArg])); return false; } else { DBGPRINTF((DBG_CONTEXT, "Maximum requests is %lu\n", _RestartCount)); } break; case L't': case L'T': _IdleTime = wcstoul(argv[++iArg], NULL, 0); if (_IdleTime == 0) { DBGPRINTF((DBG_CONTEXT, "Invalid idle time %ws\n", argv[iArg])); return false; } else { DBGPRINTF((DBG_CONTEXT, "The idle time value is %lu\n", _IdleTime)); } break; case L'p': case L'P': SetEnvironmentVariable(L"CORDBG_ENABLE", L"0x20"); SetEnvironmentVariable(L"COR_PROFILER", L"\"ComPlusIcecapProfile.CorIcecapProfiler\""); SetEnvironmentVariable(L"PROF_CONFIG", L"/callcap"); break; default: case L'?': fRet = false; break; } // switch } else { // // Take the next item as the NSG name and bail out here // _pwszAppPoolName = argv[iArg]; if ( iArg != (argc - 1)) { // // this is not the last argument => unwanted parameters exist // give warning and ignore // DBGPRINTF((DBG_CONTEXT, "Warning: Too many arguments supplied\n")); } break; // get out of here. } } if (!_fRegisterWithWAS) { _RestartCount = 0; _IdleTime = 0; } if (!fRet) { PrintUsage(); } return ( fRet); } // WP_CONFIG::ParseCommandLine() /********************************************************************++ Routine Description: Sets up the control channel for processing requests. It uses the configuration parameters supplied for initializing the UL_CONTROL_CHANNEL. See g_rgchUsage[] for details on the arguments that can be supplied Arguments: Returns: Win32 error --********************************************************************/ ULONG WP_CONFIG::SetupControlChannel(void) { // // Setup a control channel for our local use now. Used mainly for // the purpose of debugging. // In general control channel work is done by the AdminProces. // return _ulcc.Initialize( _mszURLList, _pwszAppPoolName); } // WP_CONFIG::SetupControlChannel() /********************************************************************++ --********************************************************************/ WP_CONFIG::InsertURLIntoList( LPCWSTR pwszURL ) { LPCWSTR pwszOriginalURL = pwszURL; // // Minimum length: 11 (http://*:1/). Begins with http // if ( ( wcslen(pwszURL) < 11 ) || ( 0 != _wcsnicmp(pwszURL, L"http", 4)) ) { return false; } pwszURL += 4; // // https // if ((L's' == *pwszURL) || (L'S' == *pwszURL)) { pwszURL++; } // // :// // if ( (L':' != *pwszURL) || (L'/' != *(pwszURL+1)) || (L'/' != *(pwszURL+2)) ) { return false; } pwszURL += 3; // // Skip host name or Ip Address // while ( (0 != *pwszURL) && ( L':' != *pwszURL)) { pwszURL++; } // // Check port # exists // if (0 == *pwszURL) { return false; } // // Check port number is numeric // pwszURL++; while ( (0 != *pwszURL) && ( L'/' != *pwszURL) ) { if (( L'0' > *pwszURL) || ( L'9' < *pwszURL)) { return false; } pwszURL++; } // // Check / after port number exists // if (0 == *pwszURL) { return false; } // // URL is good. // IF_DEBUG( TRACE) { DBGPRINTF(( DBG_CONTEXT, "Inserting URL '%ws' into Config Group List\n", pwszOriginalURL )); } return ( TRUE == _mszURLList.Append( pwszOriginalURL)); } // WP_CONFIG::InsertURLIntoList()