]> granicus.if.org Git - apache/blobdiff - server/mpm/winnt/mpm_winnt.c
apr_proc_mutex.h is called for by this very header
[apache] / server / mpm / winnt / mpm_winnt.c
index 8568f1cc732b9617bf8ccd16f13b3e1d754255b6..45ac052b83779009a10ce3a7f4535c347c7d681e 100644 (file)
@@ -16,7 +16,6 @@
 
 #ifdef WIN32
 
-#define CORE_PRIVATE
 #include "httpd.h"
 #include "http_main.h"
 #include "http_log.h"
@@ -44,7 +43,9 @@
  * score by moving a handle down the pipe into the child's stdin.
  */
 extern apr_shm_t *ap_scoreboard_shm;
-server_rec *ap_server_conf;
+
+/* ap_my_generation are used by the scoreboard code */
+ap_generation_t volatile ap_my_generation=0;
 
 /* Definitions of WINNT MPM specific config globals */
 static HANDLE shutdown_event;  /* used to signal the parent to shutdown */
@@ -57,34 +58,34 @@ static char const* signal_arg = NULL;
 
 OSVERSIONINFO osver; /* VER_PLATFORM_WIN32_NT */
 
+/* set by child_main to STACK_SIZE_PARAM_IS_A_RESERVATION for NT >= 5.1 (XP/2003) */
+DWORD stack_res_flag;
+
 static DWORD parent_pid;
 DWORD my_pid;
 
+/* used by parent to signal the child to start and exit */
+apr_proc_mutex_t *start_mutex;
+HANDLE exit_event;
+
 int ap_threads_per_child = 0;
-int use_acceptex = 1;
 static int thread_limit = 0;
 static int first_thread_limit = 0;
 int winnt_mpm_state = AP_MPMQ_STARTING;
-/* ap_my_generation are used by the scoreboard code */
-ap_generation_t volatile ap_my_generation=0;
-
 
 /* shared by service.c as global, although
  * perhaps it should be private.
  */
 apr_pool_t *pconf;
 
+/* on several occasions we don't have the global server context
+ * although it's needed for logging, etc.
+ */
+server_rec *ap_server_conf;
 
 /* definitions from child.c */
 void child_main(apr_pool_t *pconf);
 
-/* used by parent to signal the child to start and exit
- * NOTE: these are not sophisticated enough for multiple children
- * so they ultimately should not be shared with child.c
- */
-extern apr_proc_mutex_t *start_mutex;
-extern HANDLE exit_event;
-
 /* Only one of these, the pipe from our parent, ment only for
  * one child worker's consumption (not to be inherited!)
  * XXX: decorate this name for the trunk branch, was left simplified
@@ -135,19 +136,6 @@ static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *ar
     thread_limit = atoi(arg);
     return NULL;
 }
-static const char *set_disable_acceptex(cmd_parms *cmd, void *dummy, char *arg)
-{
-    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
-    if (err != NULL) {
-        return err;
-    }
-    if (use_acceptex) {
-        use_acceptex = 0;
-        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
-                     "Disabled use of AcceptEx() WinSock2 API");
-    }
-    return NULL;
-}
 
 static const command_rec winnt_cmds[] = {
 LISTEN_COMMANDS,
@@ -155,9 +143,6 @@ AP_INIT_TAKE1("ThreadsPerChild", set_threads_per_child, NULL, RSRC_CONF,
   "Number of threads each child creates" ),
 AP_INIT_TAKE1("ThreadLimit", set_thread_limit, NULL, RSRC_CONF,
   "Maximum worker threads in a server for this run of Apache"),
-AP_INIT_NO_ARGS("Win32DisableAcceptEx", set_disable_acceptex, NULL, RSRC_CONF,
-  "Disable use of the high performance AcceptEx WinSock2 API to work around buggy VPN or Firewall software"),
-
 { NULL }
 };
 
@@ -207,13 +192,6 @@ void setup_signal_names(char *prefix)
         "%s_restart", signal_name_prefix);
 }
 
-int volatile is_graceful = 0;
-
-AP_DECLARE(int) ap_graceful_stop_signalled(void)
-{
-    return is_graceful;
-}
-
 AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type)
 {
     HANDLE e;
@@ -230,7 +208,6 @@ AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type)
            case SIGNAL_PARENT_RESTART:
            case SIGNAL_PARENT_RESTART_GRACEFUL:
            {
-               is_graceful = 1;
                SetEvent(restart_event);
                break;
            }
@@ -249,7 +226,6 @@ AP_DECLARE(void) ap_signal_parent(ap_signal_parent_e type)
        case SIGNAL_PARENT_RESTART_GRACEFUL:
        {
            signal_name = signal_restart_name;
-           is_graceful = 1;
            break;
        }
        default:
@@ -456,6 +432,8 @@ void get_listeners_from_parent(server_rec *s)
     DWORD BytesRead;
     int lcnt = 0;
     SOCKET nsd;
+    HANDLE hProcess = GetCurrentProcess();
+    HANDLE dup;
 
     /* Set up a default listener if necessary */
     if (ap_listeners == NULL) {
@@ -479,6 +457,7 @@ void get_listeners_from_parent(server_rec *s)
                          "setup_inherited_listeners: Unable to read socket data from parent");
             exit(APEXIT_CHILDINIT);
         }
+
         nsd = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
                         &WSAProtocolInfo, 0, 0);
         if (nsd == INVALID_SOCKET) {
@@ -487,30 +466,12 @@ void get_listeners_from_parent(server_rec *s)
             exit(APEXIT_CHILDINIT);
         }
 
-        if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
-            HANDLE hProcess = GetCurrentProcess();
-            HANDLE dup;
-            if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup,
-                                0, FALSE, DUPLICATE_SAME_ACCESS)) {
-                closesocket(nsd);
-                nsd = (SOCKET) dup;
-            }
-        }
-        else {
-            /* A different approach.  Many users report errors such as
-             * (32538)An operation was attempted on something that is not
-             * a socket.  : Parent: WSADuplicateSocket failed...
-             *
-             * This appears that the duplicated handle is no longer recognized
-             * as a socket handle.  SetHandleInformation should overcome that
-             * problem by not altering the handle identifier.  But this won't
-             * work on 9x - it's unsupported.
-             */
-            if (!SetHandleInformation((HANDLE)nsd, HANDLE_FLAG_INHERIT, 0)) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, apr_get_os_error(), ap_server_conf,
-                             "set_listeners_noninheritable: SetHandleInformation failed.");
-            }
+        if (DuplicateHandle(hProcess, (HANDLE) nsd, hProcess, &dup,
+                            0, FALSE, DUPLICATE_SAME_ACCESS)) {
+            closesocket(nsd);
+            nsd = (SOCKET) dup;
         }
+
         apr_os_sock_put(&lr->sd, &nsd, s->process->pool);
     }
 
@@ -571,7 +532,6 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
     /* These NEVER change for the lifetime of this parent
      */
     static char **args = NULL;
-    static char **env = NULL;
     static char pidbuf[28];
 
     apr_status_t rv;
@@ -582,11 +542,13 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
     HANDLE waitlist[2];  /* see waitlist_e */
     char *cmd;
     char *cwd;
+    char **env;
+    int envc;
 
     apr_pool_create_ex(&ptemp, p, NULL, NULL);
 
     /* Build the command line. Should look something like this:
-     * C:/apache/bin/apache.exe -f ap_server_confname
+     * C:/apache/bin/httpd.exe -f ap_server_confname
      * First, get the path to the executable...
      */
     apr_procattr_create(&attr, ptemp);
@@ -650,21 +612,15 @@ static int create_process(apr_pool_t *p, HANDLE *child_proc, HANDLE *child_exit_
         return -1;
     }
 
-    if (!env)
-    {
-        /* Build the env array, only once since it won't change
-         * for the lifetime of this parent process.
-         */
-        int envc;
-        for (envc = 0; _environ[envc]; ++envc) {
-            ;
-        }
-        env = malloc((envc + 2) * sizeof (char*));
-        memcpy(env, _environ, envc * sizeof (char*));
-        apr_snprintf(pidbuf, sizeof(pidbuf), "AP_PARENT_PID=%i", parent_pid);
-        env[envc] = pidbuf;
-        env[envc + 1] = NULL;
+    /* Build the env array */
+    for (envc = 0; _environ[envc]; ++envc) {
+        ;
     }
+    env = apr_palloc(ptemp, (envc + 2) * sizeof (char*));  
+    memcpy(env, _environ, envc * sizeof (char*));
+    apr_snprintf(pidbuf, sizeof(pidbuf), "AP_PARENT_PID=%i", parent_pid);
+    env[envc] = pidbuf;
+    env[envc + 1] = NULL;
 
     rv = apr_proc_create(&new_child, cmd, args, env, attr, ptemp);
     if (rv != APR_SUCCESS) {
@@ -1003,7 +959,7 @@ void winnt_rewrite_args(process_rec *process)
 {
     /* Handle the following SCM aspects in this phase:
      *
-     *   -k runservice [transition for WinNT, nothing for Win9x]
+     *   -k runservice [transition in service context only]
      *   -k install
      *   -k config
      *   -k uninstall
@@ -1026,12 +982,22 @@ void winnt_rewrite_args(process_rec *process)
     apr_getopt_t *opt;
     int running_as_service = 1;
     int errout = 0;
+    apr_file_t *nullfile;
 
     pconf = process->pconf;
 
     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
     GetVersionEx(&osver);
 
+    /* We wish this was *always* a reservation, but sadly it wasn't so and
+     * we couldn't break a hard limit prior to NT Kernel 5.1
+     */
+    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT 
+        && ((osver.dwMajorVersion > 5)
+         || ((osver.dwMajorVersion == 5) && (osver.dwMinorVersion > 0)))) {
+        stack_res_flag = STACK_SIZE_PARAM_IS_A_RESERVATION;
+    }
+
     /* AP_PARENT_PID is only valid in the child */
     pid = getenv("AP_PARENT_PID");
     if (pid)
@@ -1220,33 +1186,28 @@ void winnt_rewrite_args(process_rec *process)
          * We hold the return value so that we can die in pre_config
          * after logging begins, and the failure can land in the log.
          */
-        if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
-        {
-            apr_file_t *nullfile;
-
-            if (!errout) {
-                mpm_nt_eventlog_stderr_open(service_name, process->pool);
-            }
-            service_to_start_success = mpm_service_to_start(&service_name,
-                                                            process->pool);
-            if (service_to_start_success == APR_SUCCESS) {
-                service_set = APR_SUCCESS;
-            }
+        if (!errout) {
+            mpm_nt_eventlog_stderr_open(service_name, process->pool);
+        }
+        service_to_start_success = mpm_service_to_start(&service_name,
+                                                        process->pool);
+        if (service_to_start_success == APR_SUCCESS) {
+            service_set = APR_SUCCESS;
+        }
 
-            /* Open a null handle to soak stdout in this process.
-             * Windows service processes are missing any file handle
-             * usable for stdin/out/err.  This was the cause of later 
-             * trouble with invocations of apr_file_open_stdout()
-             */
-            if ((rv = apr_file_open(&nullfile, "NUL",
-                                    APR_READ | APR_WRITE, APR_OS_DEFAULT,
-                                    process->pool)) == APR_SUCCESS) {
-                apr_file_t *nullstdout;
-                if (apr_file_open_stdout(&nullstdout, process->pool)
-                        == APR_SUCCESS)
-                    apr_file_dup2(nullstdout, nullfile, process->pool);
-                apr_file_close(nullfile);
-            }
+        /* Open a null handle to soak stdout in this process.
+         * Windows service processes are missing any file handle
+         * usable for stdin/out/err.  This was the cause of later 
+         * trouble with invocations of apr_file_open_stdout()
+         */
+        if ((rv = apr_file_open(&nullfile, "NUL",
+                                APR_READ | APR_WRITE, APR_OS_DEFAULT,
+                                process->pool)) == APR_SUCCESS) {
+            apr_file_t *nullstdout;
+            if (apr_file_open_stdout(&nullstdout, process->pool)
+                    == APR_SUCCESS)
+                apr_file_dup2(nullstdout, nullfile, process->pool);
+            apr_file_close(nullfile);
         }
     }
 
@@ -1364,8 +1325,13 @@ static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *pt
         ap_exists_config_define("DEBUG"))
         one_process = -1;
 
+    /* XXX: presume proper privilages; one nice thing would be
+     * a loud emit if running as "LocalSystem"/"SYSTEM" to indicate
+     * they should change to a user with write access to logs/ alone.
+     */
+    ap_sys_privileges_handlers(1);
+
     if (!strcasecmp(signal_arg, "runservice")
-            && (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
             && (service_to_start_success != APR_SUCCESS)) {
         ap_log_error(APLOG_MARK,APLOG_CRIT, service_to_start_success, NULL,
                      "%s: Unable to start the service manager.",
@@ -1393,20 +1359,12 @@ static int winnt_pre_config(apr_pool_t *pconf_, apr_pool_t *plog, apr_pool_t *pt
         }
     }
 
-    /* use_acceptex (enabled by default) is not available on Win9x.
-     */
-    if (osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
-        use_acceptex = 0;
-    }
-
     ap_listen_pre_config();
     thread_limit = DEFAULT_THREAD_LIMIT;
     ap_threads_per_child = DEFAULT_THREADS_PER_CHILD;
     ap_pid_fname = DEFAULT_PIDLOG;
     ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
-#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
-        ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
-#endif
+    ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
 
     apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
 
@@ -1603,30 +1561,6 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
             }
             CleanNullACL((void *)sa);
 
-            /* Now that we are flying at 15000 feet...
-             * wipe out the Win95 service console,
-             * signal the SCM the WinNT service started, or
-             * if not a service, setup console handlers instead.
-             */
-            if (!strcasecmp(signal_arg, "runservice"))
-            {
-                if (osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
-                {
-                    rv = mpm_service_to_start(&service_name,
-                                              s->process->pool);
-                    if (rv != APR_SUCCESS) {
-                        ap_log_error(APLOG_MARK,APLOG_ERR, rv, ap_server_conf,
-                                     "%s: Unable to start the service manager.",
-                                     service_name);
-                        return HTTP_INTERNAL_SERVER_ERROR;
-                    }
-                }
-            }
-            else /* ! -k runservice */
-            {
-                mpm_start_console_handler();
-            }
-
             /* Create the start mutex, as an unnamed object for security.
              * Ths start mutex is used during a restart to prevent more than
              * one child process from entering the accept loop at once.
@@ -1641,6 +1575,12 @@ static int winnt_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pt
                 return HTTP_INTERNAL_SERVER_ERROR;
             }
         }
+        /* Always reset our console handler to be the first, even on a restart
+        *  because some modules (e.g. mod_perl) might have set a console 
+        *  handler to terminate the process.
+        */
+        if (strcasecmp(signal_arg, "runservice"))
+            mpm_start_console_handler();
     }
     else /* parent_pid != my_pid */
     {