PeruserAttachments: httpd-2.0.61-peruser-0.3.0.patch

File httpd-2.0.61-peruser-0.3.0.patch, 117.3 KB (added by gabriel, 2 years ago)

Peruser 0.3.0 patch for Apache 2.0.61

  • server/mpm/config.m4

    diff -Nur httpd-2.0.61/server/mpm/config.m4 httpd-2.0.61-peruser/server/mpm/config.m4
    old new  
    11AC_MSG_CHECKING(which MPM to use) 
    22AC_ARG_WITH(mpm, 
    33APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use. 
    4                           MPM={beos|worker|prefork|mpmt_os2|perchild|leader|threadpool}),[ 
     4                          MPM={beos|worker|prefork|mpmt_os2|perchild|leader|threadpool|peruser}),[ 
    55  APACHE_MPM=$withval 
    66],[ 
    77  if test "x$APACHE_MPM" = "x"; then 
     
    2626APACHE_FAST_OUTPUT(server/mpm/Makefile) 
    2727 
    2828MPM_NAME=$apache_cv_mpm 
    29 if test "$MPM_NAME" = "leader" -o "$MPM_NAME" = "threadpool" -o "$MPM_NAME" = "perchild"; then 
     29if test "$MPM_NAME" = "leader" -o "$MPM_NAME" = "threadpool" -o "$MPM_NAME" = "perchild" -o "$MPM_NAME" = "peruser"; then 
    3030  AC_MSG_WARN(You have selected an EXPERIMENTAL MPM.  Be warned!) 
    3131  MPM_SUBDIR_NAME=experimental/$MPM_NAME 
    3232else 
  • server/mpm/experimental/peruser/AUTHORS

    diff -Nur httpd-2.0.61/server/mpm/experimental/peruser/AUTHORS httpd-2.0.61-peruser/server/mpm/experimental/peruser/AUTHORS
    old new  
     1Enrico Weigelt <weigelt [at] metux.de> (MetuxMPM maintainer) 
     2Sean Gabriel Heacock <gabriel [at] telana.com> (Peruser maintainer) 
     3Stefan Seufert <stefan [at] seuf.de> 
     4Janno Sannik <janno [at] kood.ee> 
     5Taavi Sannik <taavi [at] kood.ee> 
     6Rommer <rommer [at] active.by> 
     7Bert <bert [at] ev6.net> 
     8Leen Besselink <leen [at] consolejunkie.net> 
     9Steve Amerige <mpm [at] fatbear.com> 
  • server/mpm/experimental/peruser/Makefile.in

    diff -Nur httpd-2.0.61/server/mpm/experimental/peruser/Makefile.in httpd-2.0.61-peruser/server/mpm/experimental/peruser/Makefile.in
    old new  
     1 
     2LTLIBRARY_NAME    = libperuser.la 
     3LTLIBRARY_SOURCES = peruser.c 
     4 
     5include $(top_srcdir)/build/ltlib.mk 
  • server/mpm/experimental/peruser/config.m4

    diff -Nur httpd-2.0.61/server/mpm/experimental/peruser/config.m4 httpd-2.0.61-peruser/server/mpm/experimental/peruser/config.m4
    old new  
     1if test "$MPM_NAME" = "peruser" ; then 
     2    APACHE_FAST_OUTPUT(server/mpm/experimental/$MPM_NAME/Makefile) 
     3fi 
  • server/mpm/experimental/peruser/mpm.h

    diff -Nur httpd-2.0.61/server/mpm/experimental/peruser/mpm.h httpd-2.0.61-peruser/server/mpm/experimental/peruser/mpm.h
    old new  
     1/* ==================================================================== 
     2 * The Apache Software License, Version 1.1 
     3 * 
     4 * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights 
     5 * reserved. 
     6 * 
     7 * Redistribution and use in source and binary forms, with or without 
     8 * modification, are permitted provided that the following conditions 
     9 * are met: 
     10 * 
     11 * 1. Redistributions of source code must retain the above copyright 
     12 *    notice, this list of conditions and the following disclaimer. 
     13 * 
     14 * 2. Redistributions in binary form must reproduce the above copyright 
     15 *    notice, this list of conditions and the following disclaimer in 
     16 *    the documentation and/or other materials provided with the 
     17 *    distribution. 
     18 * 
     19 * 3. The end-user documentation included with the redistribution, 
     20 *    if any, must include the following acknowledgment: 
     21 *       "This product includes software developed by the 
     22 *        Apache Software Foundation (http://www.apache.org/)." 
     23 *    Alternately, this acknowledgment may appear in the software itself, 
     24 *    if and wherever such third-party acknowledgments normally appear. 
     25 * 
     26 * 4. The names "Apache" and "Apache Software Foundation" must 
     27 *    not be used to endorse or promote products derived from this 
     28 *    software without prior written permission. For written 
     29 *    permission, please contact apache@apache.org. 
     30 * 
     31 * 5. Products derived from this software may not be called "Apache", 
     32 *    nor may "Apache" appear in their name, without prior written 
     33 *    permission of the Apache Software Foundation. 
     34 * 
     35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
     36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
     37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
     38 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 
     39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
     42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
     43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
     44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
     45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
     46 * SUCH DAMAGE. 
     47 * ==================================================================== 
     48 * 
     49 * This software consists of voluntary contributions made by many 
     50 * individuals on behalf of the Apache Software Foundation.  For more 
     51 * information on the Apache Software Foundation, please see 
     52 * <http://www.apache.org/>. 
     53 * 
     54 * Portions of this software are based upon public domain software 
     55 * originally written at the National Center for Supercomputing Applications, 
     56 * University of Illinois, Urbana-Champaign. 
     57 */ 
     58 
     59#include "httpd.h" 
     60#include "mpm_default.h" 
     61#include "scoreboard.h" 
     62#include "unixd.h" 
     63 
     64#ifndef APACHE_MPM_PERUSER_H 
     65#define APACHE_MPM_PERUSER_H 
     66 
     67#define PERUSER_MPM 
     68 
     69#define MPM_NAME "Peruser" 
     70 
     71#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES 
     72#define AP_MPM_WANT_WAIT_OR_TIMEOUT 
     73#define AP_MPM_WANT_PROCESS_CHILD_STATUS 
     74#define AP_MPM_WANT_SET_PIDFILE 
     75#define AP_MPM_WANT_SET_SCOREBOARD 
     76#define AP_MPM_WANT_SET_LOCKFILE 
     77#define AP_MPM_WANT_SET_MAX_REQUESTS 
     78#define AP_MPM_WANT_SET_COREDUMPDIR 
     79#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH 
     80#define AP_MPM_WANT_SIGNAL_SERVER 
     81#define AP_MPM_WANT_SET_MAX_MEM_FREE 
     82#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK 
     83 
     84#define AP_MPM_USES_POD 1 
     85#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) 
     86#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0) 
     87#define MPM_ACCEPT_FUNC unixd_accept 
     88 
     89extern int ap_threads_per_child; 
     90extern int ap_max_daemons_limit; 
     91extern server_rec *ap_server_conf; 
     92 
     93/* Table of child status */ 
     94#define SERVER_DEAD 0 
     95#define SERVER_DYING 1 
     96#define SERVER_ALIVE 2 
     97 
     98typedef struct ap_ctable { 
     99    pid_t pid; 
     100    unsigned char status; 
     101} ap_ctable; 
     102 
     103#endif /* APACHE_MPM_PERUSER_H */ 
  • server/mpm/experimental/peruser/mpm_default.h

    diff -Nur httpd-2.0.61/server/mpm/experimental/peruser/mpm_default.h httpd-2.0.61-peruser/server/mpm/experimental/peruser/mpm_default.h
    old new  
     1/* ==================================================================== 
     2 * The Apache Software License, Version 1.1 
     3 * 
     4 * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights 
     5 * reserved. 
     6 * 
     7 * Redistribution and use in source and binary forms, with or without 
     8 * modification, are permitted provided that the following conditions 
     9 * are met: 
     10 * 
     11 * 1. Redistributions of source code must retain the above copyright 
     12 *    notice, this list of conditions and the following disclaimer. 
     13 * 
     14 * 2. Redistributions in binary form must reproduce the above copyright 
     15 *    notice, this list of conditions and the following disclaimer in 
     16 *    the documentation and/or other materials provided with the 
     17 *    distribution. 
     18 * 
     19 * 3. The end-user documentation included with the redistribution, 
     20 *    if any, must include the following acknowledgment: 
     21 *       "This product includes software developed by the 
     22 *        Apache Software Foundation (http://www.apache.org/)." 
     23 *    Alternately, this acknowledgment may appear in the software itself, 
     24 *    if and wherever such third-party acknowledgments normally appear. 
     25 * 
     26 * 4. The names "Apache" and "Apache Software Foundation" must 
     27 *    not be used to endorse or promote products derived from this 
     28 *    software without prior written permission. For written 
     29 *    permission, please contact apache@apache.org. 
     30 * 
     31 * 5. Products derived from this software may not be called "Apache", 
     32 *    nor may "Apache" appear in their name, without prior written 
     33 *    permission of the Apache Software Foundation. 
     34 * 
     35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
     36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
     37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
     38 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 
     39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
     42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
     43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
     44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
     45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
     46 * SUCH DAMAGE. 
     47 * ==================================================================== 
     48 * 
     49 * This software consists of voluntary contributions made by many 
     50 * individuals on behalf of the Apache Software Foundation.  For more 
     51 * information on the Apache Software Foundation, please see 
     52 * <http://www.apache.org/>. 
     53 * 
     54 * Portions of this software are based upon public domain software 
     55 * originally written at the National Center for Supercomputing Applications, 
     56 * University of Illinois, Urbana-Champaign. 
     57 */ 
     58 
     59#ifndef APACHE_MPM_DEFAULT_H 
     60#define APACHE_MPM_DEFAULT_H 
     61 
     62/* Number of processors to spawn off for each ServerEnvironment by default */ 
     63 
     64#ifndef DEFAULT_START_PROCESSORS 
     65#define DEFAULT_START_PROCESSORS 0 
     66#endif 
     67 
     68/* Minimum number of running processors per ServerEnvironment */ 
     69 
     70#ifndef DEFAULT_MIN_PROCESSORS 
     71#define DEFAULT_MIN_PROCESSORS 0 
     72#endif 
     73 
     74/* Minimum --- fewer than this, and more will be created */ 
     75 
     76#ifndef DEFAULT_MIN_FREE_PROCESSORS 
     77#define DEFAULT_MIN_FREE_PROCESSORS 2 
     78#endif 
     79 
     80/* Maximum processors per ServerEnvironment */ 
     81 
     82#ifndef DEFAULT_MAX_PROCESSORS 
     83#define DEFAULT_MAX_PROCESSORS 10 
     84#endif 
     85 
     86/* File used for accept locking, when we use a file */ 
     87#ifndef DEFAULT_LOCKFILE 
     88#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" 
     89#endif 
     90 
     91/* Where the main/parent process's pid is logged */ 
     92#ifndef DEFAULT_PIDLOG 
     93#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid" 
     94#endif 
     95 
     96/* 
     97 * Interval, in microseconds, between scoreboard maintenance. 
     98 */ 
     99#ifndef SCOREBOARD_MAINTENANCE_INTERVAL 
     100#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 
     101#endif 
     102 
     103/* Number of requests to try to handle in a single process.  If <= 0, 
     104 * the children don't die off. 
     105 */ 
     106#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD 
     107#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 
     108#endif 
     109 
     110#endif /* AP_MPM_DEFAULT_H */ 
  • server/mpm/experimental/peruser/peruser.c

    diff -Nur httpd-2.0.61/server/mpm/experimental/peruser/peruser.c httpd-2.0.61-peruser/server/mpm/experimental/peruser/peruser.c
    old new  
     1/* ==================================================================== 
     2 * The Apache Software License, Version 1.1 
     3 * 
     4 * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights 
     5 * reserved. 
     6 * 
     7 * Redistribution and use in source and binary forms, with or without 
     8 * modification, are permitted provided that the following conditions 
     9 * are met: 
     10 * 
     11 * 1. Redistributions of source code must retain the above copyright 
     12 *    notice, this list of conditions and the following disclaimer. 
     13 * 
     14 * 2. Redistributions in binary form must reproduce the above copyright 
     15 *    notice, this list of conditions and the following disclaimer in 
     16 *    the documentation and/or other materials provided with the 
     17 *    distribution. 
     18 * 
     19 * 3. The end-user documentation included with the redistribution, 
     20 *    if any, must include the following acknowledgment: 
     21 *       "This product includes software developed by the 
     22 *        Apache Software Foundation (http://www.apache.org/)." 
     23 *    Alternately, this acknowledgment may appear in the software itself, 
     24 *    if and wherever such third-party acknowledgments normally appear. 
     25 * 
     26 * 4. The names "Apache" and "Apache Software Foundation" must 
     27 *    not be used to endorse or promote products derived from this 
     28 *    software without prior written permission. For written 
     29 *    permission, please contact apache@apache.org. 
     30 * 
     31 * 5. Products derived from this software may not be called "Apache", 
     32 *    nor may "Apache" appear in their name, without prior written 
     33 *    permission of the Apache Software Foundation. 
     34 * 
     35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
     36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
     37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
     38 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 
     39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
     40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
     41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
     42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
     43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
     44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
     45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
     46 * SUCH DAMAGE. 
     47 * ==================================================================== 
     48 * 
     49 * This software consists of voluntary contributions made by many 
     50 * individuals on behalf of the Apache Software Foundation.  For more 
     51 * information on the Apache Software Foundation, please see 
     52 * <http://www.apache.org/>. 
     53 * 
     54 * Portions of this software are based upon public domain software 
     55 * originally written at the National Center for Supercomputing Applications, 
     56 * University of Illinois, Urbana-Champaign. 
     57 */ 
     58 
     59/* Peruser version 0.3.0 */ 
     60 
     61/* #define MPM_PERUSER_DEBUG */ 
     62 
     63#include "apr.h" 
     64#include "apr_hash.h" 
     65#include "apr_pools.h" 
     66#include "apr_file_io.h" 
     67#include "apr_portable.h" 
     68#include "apr_strings.h" 
     69#include "apr_thread_proc.h" 
     70#include "apr_signal.h" 
     71#define APR_WANT_STDIO 
     72#define APR_WANT_STRFUNC 
     73#define APR_WANT_IOVEC 
     74#include "apr_want.h" 
     75 
     76#if APR_HAVE_UNISTD_H 
     77#include <unistd.h> 
     78#endif 
     79#if APR_HAVE_SYS_TYPES_H 
     80#include <sys/types.h> 
     81#endif 
     82 
     83#define CORE_PRIVATE 
     84 
     85#include "ap_config.h" 
     86#include "httpd.h" 
     87#include "mpm_default.h" 
     88#include "http_main.h" 
     89#include "http_log.h" 
     90#include "http_config.h" 
     91#include "http_core.h"          /* for get_remote_host */ 
     92#include "http_connection.h" 
     93#include "http_protocol.h"      /* for ap_hook_post_read_request */ 
     94#include "http_vhost.h"         /* for ap_update_vhost_given_ip */ 
     95#include "scoreboard.h" 
     96#include "ap_mpm.h" 
     97#include "unixd.h" 
     98#include "mpm_common.h" 
     99#include "ap_listen.h" 
     100#include "ap_mmn.h" 
     101#include "apr_poll.h" 
     102#include "util_ebcdic.h" 
     103#include "mod_status.h" 
     104 
     105#ifdef HAVE_BSTRING_H 
     106#include <bstring.h>            /* for IRIX, FD_SET calls bzero() */ 
     107#endif 
     108 
     109#ifdef HAVE_TIME_H 
     110#include <time.h> 
     111#endif 
     112 
     113#ifdef HAVE_SYS_PROCESSOR_H 
     114#include <sys/processor.h> /* for bindprocessor() */ 
     115#endif 
     116 
     117#if APR_HAS_SHARED_MEMORY 
     118#include "apr_shm.h" 
     119#else 
     120#error "Peruser MPM requres shared memory support." 
     121#endif 
     122 
     123 
     124/* should be APR-ized */ 
     125#include <grp.h> 
     126#include <pwd.h> 
     127#include <sys/stat.h> 
     128#include <sys/un.h> 
     129#include <setjmp.h> 
     130 
     131#include <signal.h> 
     132#include <sys/times.h> 
     133 
     134 
     135#ifdef MPM_PERUSER_DEBUG 
     136# define _DBG(text,par...) \ 
     137    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \ 
     138                 "(peruser: pid=%d uid=%d child=%d) %s(): " text, \ 
     139                 getpid(), getuid(), my_child_num, __FUNCTION__, ##par, 0) 
     140 
     141# define _TRACE_CALL(text,par...) _DBG("calling " text, ##par) 
     142# define _TRACE_RET(text,par...) _DBG("returned from " text, ##par) 
     143#else 
     144# define _DBG(text,par...) 
     145# define _TRACE_RET(text,par...) 
     146# define _TRACE_CALL(text,par...) 
     147#endif /* MPM_PERUSER_DEBUG */ 
     148 
     149/* char of death - for signalling children to die */ 
     150#define AP_PERUSER_CHAR_OF_DEATH        '!' 
     151 
     152#define PERUSER_SERVER_CONF(cf)        \ 
     153    ((peruser_server_conf *) ap_get_module_config(cf, &mpm_peruser_module)) 
     154 
     155#define SCOREBOARD_STATUS(i)    ap_scoreboard_image->servers[i][0].status 
     156 
     157/* 
     158 * Define some magic numbers that we use for the state of the incomming 
     159 * request. These must be < 0 so they don't collide with a file descriptor. 
     160 */ 
     161#define AP_PERUSER_THISCHILD -1 
     162#define AP_PERUSER_OTHERCHILD -2 
     163 
     164 
     165/* Limit on the total --- clients will be locked out if more servers than 
     166 * this are needed.  It is intended solely to keep the server from crashing 
     167 * when things get out of hand. 
     168 * 
     169 * We keep a hard maximum number of servers, for two reasons --- first off, 
     170 * in case something goes seriously wrong, we want to stop the fork bomb 
     171 * short of actually crashing the machine we're running on by filling some 
     172 * kernel table.  Secondly, it keeps the size of the scoreboard file small 
     173 * enough that we can read the whole thing without worrying too much about 
     174 * the overhead. 
     175 */ 
     176#ifndef DEFAULT_SERVER_LIMIT 
     177#define DEFAULT_SERVER_LIMIT 256 
     178#endif 
     179 
     180/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT.  We want 
     181 * some sort of compile-time limit to help catch typos. 
     182 */ 
     183#ifndef MAX_SERVER_LIMIT 
     184#define MAX_SERVER_LIMIT 20000 
     185#endif 
     186 
     187#ifndef HARD_THREAD_LIMIT 
     188#define HARD_THREAD_LIMIT 1 
     189#endif 
     190 
     191#define CHILD_TYPE_UNKNOWN      0 
     192#define CHILD_TYPE_MULTIPLEXER  1 
     193#define CHILD_TYPE_PROCESSOR    2 
     194#define CHILD_TYPE_WORKER       3 
     195 
     196#define CHILD_STATUS_STANDBY  0  /* wait for a request before starting */ 
     197#define CHILD_STATUS_STARTING 1  /* wait for socket creation */ 
     198#define CHILD_STATUS_READY    2  /* wait for mux to restart */ 
     199#define CHILD_STATUS_ACTIVE   3  /* ready to take requests */ 
     200#define CHILD_STATUS_RESTART  4  /* child about to die and restart */ 
     201 
     202/* config globals */ 
     203 
     204int ap_threads_per_child=0;         /* Worker threads per child */ 
     205static apr_proc_mutex_t *accept_mutex; 
     206static int ap_min_processors=DEFAULT_MIN_PROCESSORS; 
     207static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS; 
     208static int ap_max_processors=DEFAULT_MAX_PROCESSORS; 
     209static int ap_daemons_limit=0;      /* MaxClients */ 
     210static int expire_timeout=1800; 
     211static int idle_timeout=900; 
     212static int server_limit = DEFAULT_SERVER_LIMIT; 
     213static int first_server_limit; 
     214static int changed_limit_at_restart; 
     215static int requests_this_child; 
     216static int mpm_state = AP_MPMQ_STARTING; 
     217static ap_pod_t *pod; 
     218 
     219/* === configuration stuff === */ 
     220 
     221typedef struct 
     222{ 
     223    int processor_id; 
     224 
     225    /* security settings */ 
     226    uid_t uid;          /* user id */ 
     227    gid_t gid;          /* group id */ 
     228    const char *chroot; /* directory to chroot() to, can be null */ 
     229 
     230    /* resource settings */ 
     231    int min_processors; 
     232    int min_free_processors; 
     233    int max_processors; 
     234 
     235    /* sockets */ 
     236    int input;          /* The socket descriptor */ 
     237    int output;         /* The socket descriptor */ 
     238} server_env_t; 
     239 
     240typedef struct 
     241{ 
     242    apr_size_t num; 
     243} server_env_control; 
     244 
     245typedef struct 
     246{ 
     247    server_env_control *control; 
     248    server_env_t *table; 
     249} server_env; 
     250 
     251 
     252typedef struct 
     253{ 
     254    /* identification */ 
     255    int id;             /* index in child_info_table */ 
     256    pid_t pid;          /* process id */ 
     257    int status;         /* status of child */ 
     258    int type;           /* multiplexer or processor */ 
     259    server_env_t *senv; 
     260 
     261    /* sockets */ 
     262    int sock_fd; 
     263 
     264    /* stack context saved state */ 
     265    jmp_buf jmpbuffer; 
     266} child_info_t; 
     267 
     268typedef struct 
     269{ 
     270    /* identification */ 
     271    int id;            /* index in child_info_table */ 
     272    pid_t pid;         /* process id */ 
     273    int status;                /* status of child */ 
     274    int type;           /* multiplexer or processor */ 
     275    apr_time_t last_used; 
     276} child_grace_info_t; 
     277 
     278typedef struct 
     279{ 
     280    apr_size_t num; 
     281} child_info_control; 
     282 
     283typedef struct 
     284{ 
     285    child_info_control *control; 
     286    child_info_t *table; 
     287} child_info; 
     288 
     289typedef struct 
     290{ 
     291    server_env_t *senv; 
     292} peruser_server_conf; 
     293 
     294 
     295typedef struct peruser_header 
     296{ 
     297    char *headers; 
     298    apr_pool_t *p; 
     299} peruser_header; 
     300 
     301 
     302/* Tables used to determine the user and group each child process should 
     303 * run as.  The hash table is used to correlate a server name with a child 
     304 * process. 
     305 */ 
     306static apr_size_t child_info_size; 
     307static child_info *child_info_image; 
     308static child_grace_info_t *child_grace_info_table; 
     309struct ap_ctable *ap_child_table; 
     310 
     311#define NUM_CHILDS (child_info_image != NULL ? child_info_image->control->num : 0) 
     312#define CHILD_INFO_TABLE (child_info_image != NULL ? child_info_image->table : NULL) 
     313 
     314static apr_size_t server_env_size; 
     315static server_env *server_env_image = NULL; 
     316 
     317#define NUM_SENV (server_env_image != NULL ? server_env_image->control->num : 0) 
     318#define SENV (server_env_image != NULL ? server_env_image->table : NULL) 
     319 
     320#if APR_HAS_SHARED_MEMORY 
     321#ifndef WIN32 
     322static /* but must be exported to mpm_winnt */ 
     323#endif 
     324        apr_shm_t *child_info_shm = NULL; 
     325        apr_shm_t *server_env_shm = NULL; 
     326#endif 
     327 
     328/* 
     329 * The max child slot ever assigned, preserved across restarts.  Necessary 
     330 * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts.  We  
     331 * use this value to optimize routines that have to scan the entire scoreboard. 
     332 */ 
     333int ap_max_daemons_limit = -1; 
     334server_rec *ap_server_conf; 
     335 
     336module AP_MODULE_DECLARE_DATA mpm_peruser_module; 
     337 
     338/* -- replace the pipe-of-death by an control socket -- */ 
     339static apr_file_t *pipe_of_death_in = NULL; 
     340static apr_file_t *pipe_of_death_out = NULL; 
     341 
     342 
     343/* one_process --- debugging mode variable; can be set from the command line 
     344 * with the -X flag.  If set, this gets you the child_main loop running 
     345 * in the process which originally started up (no detach, no make_child), 
     346 * which is a pretty nice debugging environment.  (You'll get a SIGHUP 
     347 * early in standalone_main; just continue through.  This is the server 
     348 * trying to kill off any child processes which it might have lying 
     349 * around --- Apache doesn't keep track of their pids, it just sends 
     350 * SIGHUP to the process group, ignoring it in the root process. 
     351 * Continue through and you'll be fine.). 
     352 */ 
     353 
     354static int one_process = 0; 
     355 
     356static apr_pool_t *pconf;               /* Pool for config stuff */ 
     357static apr_pool_t *pchild;              /* Pool for httpd child stuff */ 
     358 
     359static pid_t ap_my_pid; /* it seems silly to call getpid all the time */ 
     360static pid_t parent_pid; 
     361static int my_child_num; 
     362ap_generation_t volatile ap_my_generation=0; 
     363 
     364#ifdef TPF 
     365int tpf_child = 0; 
     366char tpf_server_name[INETD_SERVNAME_LENGTH+1]; 
     367#endif /* TPF */ 
     368 
     369static int die_now = 0; 
     370 
     371int grace_children = 0; 
     372int grace_children_alive = 0; 
     373int server_env_cleanup = 1; 
     374 
     375#ifdef GPROF 
     376/*  
     377 * change directory for gprof to plop the gmon.out file 
     378 * configure in httpd.conf: 
     379 * GprofDir $RuntimeDir/   -> $ServerRoot/$RuntimeDir/gmon.out 
     380 * GprofDir $RuntimeDir/%  -> $ServerRoot/$RuntimeDir/gprof.$pid/gmon.out 
     381 */ 
     382static void chdir_for_gprof(void) 
     383{ 
     384    core_server_config *sconf =  
     385        ap_get_module_config(ap_server_conf->module_config, &core_module);     
     386    char *dir = sconf->gprof_dir; 
     387    const char *use_dir; 
     388 
     389    if(dir) { 
     390        apr_status_t res; 
     391        char buf[512]; 
     392        int len = strlen(sconf->gprof_dir) - 1; 
     393        if(*(dir + len) == '%') { 
     394            dir[len] = '\0'; 
     395            apr_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid()); 
     396        }  
     397        use_dir = ap_server_root_relative(pconf, buf[0] ? buf : dir); 
     398        res = apr_dir_make(use_dir, 0755, pconf); 
     399        if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) { 
     400            ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, 
     401                         "gprof: error creating directory %s", dir); 
     402        } 
     403    } 
     404    else { 
     405        use_dir = ap_server_root_relative(pconf, DEFAULT_REL_RUNTIMEDIR); 
     406    } 
     407 
     408    chdir(use_dir); 
     409} 
     410#else 
     411#define chdir_for_gprof() 
     412#endif 
     413 
     414char* child_type_string(int type) 
     415{ 
     416    switch(type) 
     417    { 
     418        case CHILD_TYPE_MULTIPLEXER: return "MULTIPLEXER"; 
     419        case CHILD_TYPE_PROCESSOR:   return "PROCESSOR"; 
     420        case CHILD_TYPE_WORKER:      return "WORKER"; 
     421    } 
     422 
     423    return "UNKNOWN"; 
     424} 
     425 
     426char* child_status_string(int status) 
     427{ 
     428    switch(status) 
     429    { 
     430        case CHILD_STATUS_STANDBY:  return "STANDBY"; 
     431        case CHILD_STATUS_STARTING: return "STARTING"; 
     432        case CHILD_STATUS_READY:    return "READY"; 
     433        case CHILD_STATUS_ACTIVE:   return "ACTIVE"; 
     434        case CHILD_STATUS_RESTART:  return "RESTART"; 
     435    } 
     436 
     437    return "UNKNOWN"; 
     438} 
     439 
     440void dump_child_table() 
     441{ 
     442#ifdef MPM_PERUSER_DEBUG 
     443  int x; 
     444  server_env_t *senv; 
     445 
     446  _DBG("%-3s %-5s %-8s %-12s %-4s %-4s %-25s %5s %6s %7s", 
     447    "ID", "PID", "STATUS", "TYPE", "UID", "GID", "CHROOT", "INPUT", "OUTPUT", "SOCK_FD"); 
     448 
     449  for(x = 0; x < NUM_CHILDS; x++) 
     450  { 
     451    senv = CHILD_INFO_TABLE[x].senv; 
     452    _DBG("%-3d %-5d %-8s %-12s %-4d %-4d %-25s %-5d %-6d %-7d", 
     453      CHILD_INFO_TABLE[x].id, 
     454      CHILD_INFO_TABLE[x].pid, 
     455      child_status_string(CHILD_INFO_TABLE[x].status), 
     456      child_type_string(CHILD_INFO_TABLE[x].type), 
     457      senv == NULL ? -1 : senv->uid, 
     458      senv == NULL ? -1 : senv->gid, 
     459      senv == NULL ? NULL : senv->chroot, 
     460      senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input, 
     461      senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output, 
     462      CHILD_INFO_TABLE[x].sock_fd); 
     463  } 
     464#endif 
     465} 
     466 
     467void dump_server_env_image() 
     468{ 
     469#ifdef MPM_PERUSER_DEBUG 
     470  int x; 
     471  _DBG("%-3s %-7s %-7s", "N", "INPUT", "OUTPUT"); 
     472  for(x = 0; x < NUM_SENV; x++) 
     473  { 
     474    _DBG("%-3d %-7d %-7d", x, SENV[x].input, SENV[x].output); 
     475  } 
     476#endif 
     477} 
     478 
     479 
     480/* XXX - I don't know if TPF will ever use this module or not, so leave 
     481 * the ap_check_signals calls in but disable them - manoj */ 
     482#define ap_check_signals()  
     483 
     484/* a clean exit from a child with proper cleanup */ 
     485static inline int clean_child_exit(int code) __attribute__ ((noreturn)); 
     486static inline int clean_child_exit(int code) 
     487{ 
     488    int retval; 
     489 
     490    mpm_state = AP_MPMQ_STOPPING; 
     491 
     492    if (CHILD_INFO_TABLE[my_child_num].type != CHILD_TYPE_MULTIPLEXER && 
     493        CHILD_INFO_TABLE[my_child_num].senv) 
     494    { 
     495      retval = close(CHILD_INFO_TABLE[my_child_num].senv->input); 
     496      _DBG("close(CHILD_INFO_TABLE[%d].senv->input) = %d", 
     497           my_child_num, retval); 
     498 
     499      retval = close(CHILD_INFO_TABLE[my_child_num].senv->output); 
     500      _DBG("close(CHILD_INFO_TABLE[%d].senv->output) = %d", 
     501           my_child_num, retval); 
     502    } 
     503 
     504    if (pchild) { 
     505        apr_pool_destroy(pchild); 
     506    } 
     507    ap_mpm_pod_close(pod); 
     508    chdir_for_gprof(); 
     509    exit(code); 
     510} 
     511 
     512static void accept_mutex_on(void) 
     513{ 
     514/* for some reason this fails if we listen on the pipe_of_death. 
     515   fortunately I don't think we currently need it */ 
     516 
     517#if 0 
     518    apr_status_t rv = apr_proc_mutex_lock(accept_mutex); 
     519    if (rv != APR_SUCCESS) { 
     520        const char *msg = "couldn't grab the accept mutex"; 
     521 
     522        if (ap_my_generation !=  
     523            ap_scoreboard_image->global->running_generation) { 
     524            ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg); 
     525            clean_child_exit(0); 
     526        } 
     527        else { 
     528            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg); 
     529            exit(APEXIT_CHILDFATAL); 
     530        } 
     531    } 
     532#endif 
     533} 
     534 
     535static void accept_mutex_off(void) 
     536{ 
     537#if 0 
     538    apr_status_t rv = apr_proc_mutex_unlock(accept_mutex); 
     539    if (rv != APR_SUCCESS) { 
     540        const char *msg = "couldn't release the accept mutex"; 
     541 
     542        if (ap_my_generation !=  
     543            ap_scoreboard_image->global->running_generation) { 
     544            ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg); 
     545            /* don't exit here... we have a connection to 
     546             * process, after which point we'll see that the 
     547             * generation changed and we'll exit cleanly 
     548             */ 
     549        } 
     550        else { 
     551            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg); 
     552            exit(APEXIT_CHILDFATAL); 
     553        } 
     554    } 
     555#endif 
     556} 
     557 
     558/* On some architectures it's safe to do unserialized accept()s in the single 
     559 * Listen case.  But it's never safe to do it in the case where there's 
     560 * multiple Listen statements.  Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT 
     561 * when it's safe in the single Listen case. 
     562 */ 
     563#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT 
     564#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0) 
     565#else 
     566#define SAFE_ACCEPT(stmt) do {stmt;} while(0) 
     567#endif 
     568 
     569AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result) 
     570{ 
     571    switch(query_code){ 
     572        case AP_MPMQ_MAX_DAEMON_USED: 
     573            *result = ap_daemons_limit; 
     574            return APR_SUCCESS; 
     575        case AP_MPMQ_IS_THREADED: 
     576            *result = AP_MPMQ_NOT_SUPPORTED; 
     577            return APR_SUCCESS; 
     578        case AP_MPMQ_IS_FORKED: 
     579            *result = AP_MPMQ_DYNAMIC; 
     580            return APR_SUCCESS; 
     581        case AP_MPMQ_HARD_LIMIT_DAEMONS: 
     582            *result = server_limit; 
     583            return APR_SUCCESS; 
     584        case AP_MPMQ_HARD_LIMIT_THREADS: 
     585            *result = HARD_THREAD_LIMIT; 
     586            return APR_SUCCESS; 
     587        case AP_MPMQ_MAX_THREADS: 
     588            *result = 0; 
     589            return APR_SUCCESS; 
     590        case AP_MPMQ_MIN_SPARE_DAEMONS: 
     591            *result = ap_min_free_processors; 
     592            return APR_SUCCESS; 
     593        case AP_MPMQ_MIN_SPARE_THREADS: 
     594            *result = 0; 
     595            return APR_SUCCESS; 
     596        case AP_MPMQ_MAX_SPARE_THREADS: 
     597            *result = 0; 
     598            return APR_SUCCESS; 
     599        case AP_MPMQ_MAX_REQUESTS_DAEMON: 
     600            *result = ap_max_requests_per_child; 
     601            return APR_SUCCESS; 
     602        case AP_MPMQ_MAX_DAEMONS: 
     603            *result = server_limit; 
     604            return APR_SUCCESS; 
     605        case AP_MPMQ_MPM_STATE: 
     606            *result = mpm_state; 
     607            return APR_SUCCESS; 
     608    } 
     609    return APR_ENOTIMPL; 
     610} 
     611 
     612#if defined(NEED_WAITPID) 
     613/* 
     614   Systems without a real waitpid sometimes lose a child's exit while waiting 
     615   for another.  Search through the scoreboard for missing children. 
     616 */ 
     617int reap_children(int *exitcode, apr_exit_why_e *status) 
     618{ 
     619    int n, pid; 
     620 
     621    for (n = 0; n < ap_max_daemons_limit; ++n) { 
     622        if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD && 
     623                kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) { 
     624            ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL); 
     625            /* just mark it as having a successful exit status */ 
     626            *status = APR_PROC_EXIT; 
     627            *exitcode = 0; 
     628            return(pid); 
     629        } 
     630    } 
     631    return 0; 
     632} 
     633#endif 
     634 
     635/* handle all varieties of core dumping signals */ 
     636static void sig_coredump(int sig) 
     637{ 
     638    int retval; 
     639    retval = chdir(ap_coredump_dir); 
     640    apr_signal(sig, SIG_DFL); 
     641    if (ap_my_pid == parent_pid) { 
     642            ap_log_error(APLOG_MARK, APLOG_NOTICE, 
     643                         0, ap_server_conf, 
     644                         "seg fault or similar nasty error detected " 
     645                         "in the parent process"); 
     646    } 
     647    kill(getpid(), sig); 
     648    /* At this point we've got sig blocked, because we're still inside 
     649     * the signal handler.  When we leave the signal handler it will 
     650     * be unblocked, and we'll take the signal... and coredump or whatever 
     651     * is appropriate for this particular Unix.  In addition the parent 
     652     * will see the real signal we received -- whereas if we called 
     653     * abort() here, the parent would only see SIGABRT. 
     654     */ 
     655} 
     656 
     657/***************************************************************** 
     658 * Connection structures and accounting... 
     659 */ 
     660 
     661static void just_die(int sig) 
     662{ 
     663_DBG("function called"); 
     664    clean_child_exit(0); 
     665} 
     666 
     667/* volatile just in case */ 
     668static int volatile shutdown_pending; 
     669static int volatile restart_pending; 
     670static int volatile is_graceful; 
     671/* XXX static int volatile child_fatal; */ 
     672 
     673static void sig_term(int sig) 
     674{ 
     675    if (shutdown_pending == 1) { 
     676        /* Um, is this _probably_ not an error, if the user has 
     677         * tried to do a shutdown twice quickly, so we won't 
     678         * worry about reporting it. 
     679         */ 
     680        return; 
     681    } 
     682    shutdown_pending = 1; 
     683} 
     684 
     685/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL 
     686 * in the parent process, unless running in ONE_PROCESS mode 
     687 */ 
     688static void restart(int sig) 
     689{ 
     690    if (restart_pending == 1) { 
     691        /* Probably not an error - don't bother reporting it */ 
     692        return; 
     693    } 
     694    restart_pending = 1; 
     695    is_graceful = (sig == AP_SIG_GRACEFUL); 
     696} 
     697 
     698/* Sets die_now if we received a character on the pipe_of_death */ 
     699static apr_status_t check_pipe_of_death 
     700( 
     701    void **csd, 
     702    ap_listen_rec *lr, 
     703    apr_pool_t *ptrans 
     704) 
     705{ 
     706    int ret; 
     707    char pipe_read_char; 
     708    apr_size_t n = 1; 
     709 
     710    _DBG("WATCH: die_now=%d", die_now); 
     711 
     712    if (die_now) return APR_SUCCESS; 
     713 
     714    /* apr_thread_mutex_lock(pipe_of_death_mutex); */ 
     715    ret = apr_socket_recv(lr->sd, &pipe_read_char, &n); 
     716    if (APR_STATUS_IS_EAGAIN(ret)) 
     717    { 
     718            /* It lost the lottery. It must continue to suffer 
     719             * through a life of servitude. */ 
     720    } 
     721    else 
     722    { 
     723       if (pipe_read_char != AP_PERUSER_CHAR_OF_DEATH) 
     724       { 
     725           _DBG("got wrong char %c", pipe_read_char); 
     726           return APR_SUCCESS; 
     727       } 
     728        /* It won the lottery (or something else is very 
     729         * wrong). Embrace death with open arms. */ 
     730        die_now = 1; 
     731        _DBG("WATCH: die_now=%d", die_now); 
     732    } 
     733    /* apr_thread_mutex_unlock(pipe_of_death_mutex); */ 
     734    return APR_SUCCESS; 
     735} 
     736 
     737static void set_signals(void) 
     738{ 
     739#ifndef NO_USE_SIGACTION 
     740    struct sigaction sa; 
     741 
     742    sigemptyset(&sa.sa_mask); 
     743    sa.sa_flags = 0; 
     744 
     745    if (!one_process) { 
     746        sa.sa_handler = sig_coredump; 
     747#if defined(SA_ONESHOT) 
     748        sa.sa_flags = SA_ONESHOT; 
     749#elif defined(SA_RESETHAND) 
     750        sa.sa_flags = SA_RESETHAND; 
     751#endif 
     752        if (sigaction(SIGSEGV, &sa, NULL) < 0) 
     753            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)"); 
     754#ifdef SIGBUS 
     755        if (sigaction(SIGBUS, &sa, NULL) < 0) 
     756            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)"); 
     757#endif 
     758#ifdef SIGABORT 
     759        if (sigaction(SIGABORT, &sa, NULL) < 0) 
     760            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)"); 
     761#endif 
     762#ifdef SIGABRT 
     763        if (sigaction(SIGABRT, &sa, NULL) < 0) 
     764            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)"); 
     765#endif 
     766#ifdef SIGILL 
     767        if (sigaction(SIGILL, &sa, NULL) < 0) 
     768            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)"); 
     769#endif 
     770        sa.sa_flags = 0; 
     771    } 
     772    sa.sa_handler = sig_term; 
     773    if (sigaction(SIGTERM, &sa, NULL) < 0) 
     774        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)"); 
     775#ifdef SIGINT 
     776    if (sigaction(SIGINT, &sa, NULL) < 0) 
     777        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)"); 
     778#endif 
     779#ifdef SIGXCPU 
     780    sa.sa_handler = SIG_DFL; 
     781    if (sigaction(SIGXCPU, &sa, NULL) < 0) 
     782        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)"); 
     783#endif 
     784#ifdef SIGXFSZ 
     785    sa.sa_handler = SIG_IGN; 
     786    if (sigaction(SIGXFSZ, &sa, NULL) < 0) 
     787        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)"); 
     788#endif 
     789#ifdef SIGPIPE 
     790    sa.sa_handler = SIG_IGN; 
     791    if (sigaction(SIGPIPE, &sa, NULL) < 0) 
     792        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)"); 
     793#endif 
     794 
     795    /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy  
     796     * processing one */ 
     797    sigaddset(&sa.sa_mask, SIGHUP); 
     798    sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); 
     799    sa.sa_handler = restart; 
     800    if (sigaction(SIGHUP, &sa, NULL) < 0) 
     801        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)"); 
     802    if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) 
     803        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")"); 
     804#else 
     805    if (!one_process) { 
     806        apr_signal(SIGSEGV, sig_coredump); 
     807#ifdef SIGBUS 
     808        apr_signal(SIGBUS, sig_coredump); 
     809#endif /* SIGBUS */ 
     810#ifdef SIGABORT 
     811        apr_signal(SIGABORT, sig_coredump); 
     812#endif /* SIGABORT */ 
     813#ifdef SIGABRT 
     814        apr_signal(SIGABRT, sig_coredump); 
     815#endif /* SIGABRT */ 
     816#ifdef SIGILL 
     817        apr_signal(SIGILL, sig_coredump); 
     818#endif /* SIGILL */ 
     819#ifdef SIGXCPU 
     820        apr_signal(SIGXCPU, SIG_DFL); 
     821#endif /* SIGXCPU */ 
     822#ifdef SIGXFSZ 
     823        apr_signal(SIGXFSZ, SIG_DFL); 
     824#endif /* SIGXFSZ */ 
     825    } 
     826 
     827    apr_signal(SIGTERM, sig_term); 
     828#ifdef SIGHUP 
     829    apr_signal(SIGHUP, restart); 
     830#endif /* SIGHUP */ 
     831#ifdef AP_SIG_GRACEFUL 
     832    apr_signal(AP_SIG_GRACEFUL, restart); 
     833#endif /* AP_SIG_GRACEFUL */ 
     834#ifdef SIGPIPE 
     835    apr_signal(SIGPIPE, SIG_IGN); 
     836#endif /* SIGPIPE */ 
     837 
     838#endif 
     839} 
     840 
     841/***************************************************************** 
     842 * Child process main loop. 
     843 * The following vars are static to avoid getting clobbered by longjmp(); 
     844 * they are really private to child_main. 
     845 */ 
     846 
     847static int requests_this_child; 
     848static int num_listensocks = 0; 
     849static ap_listen_rec *listensocks; 
     850 
     851int ap_graceful_stop_signalled(void) 
     852{ 
     853    /* not ever called anymore... */ 
     854    return 0; 
     855} 
     856 
     857/* 
     858 * This function sends a raw socket over to a processor. It uses the same 
     859 * on-wire format as pass_request. The recipient can determine if he got 
     860 * a socket or a whole request by inspecting the header_length of the 
     861 * message. If it is zero then only a socket was sent. 
     862 */ 
     863static int pass_socket(apr_socket_t *thesock, child_info_t *processor, apr_pool_t *pool) 
     864{ 
     865    int rv; 
     866    struct msghdr msg; 
     867    struct cmsghdr *cmsg; 
     868    apr_sockaddr_t *remote_addr; 
     869    int sock_fd; 
     870    char *body = ""; 
     871    struct iovec iov[5]; 
     872    apr_size_t header_len = 0; 
     873    apr_size_t body_len = 0; 
     874    peruser_header h; 
     875 
     876    if (!processor) 
     877    { 
     878        _DBG("server %s in child %d has no child_info associated", 
     879                "(unkonwn)", my_child_num); 
     880        return -1; 
     881    } 
     882 
     883    _DBG("passing request to another child.", 0); 
     884 
     885    apr_os_sock_get(&sock_fd, thesock); 
     886    /* passing remote_addr too, see comments below */ 
     887    apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock); 
     888     
     889    header_len = 0; 
     890    body_len = 0; 
     891 
     892    iov[0].iov_base = &header_len; 
     893    iov[0].iov_len  = sizeof(header_len); 
     894    iov[1].iov_base = &body_len; 
     895    iov[1].iov_len  = sizeof(body_len); 
     896    iov[2].iov_base = remote_addr; 
     897    iov[2].iov_len  = sizeof(*remote_addr); 
     898    iov[3].iov_base = h.headers; 
     899    iov[3].iov_len  = 0; 
     900    iov[4].iov_base = body; 
     901    iov[4].iov_len  = body_len; 
     902 
     903    msg.msg_name    = NULL; 
     904    msg.msg_namelen = 0; 
     905    msg.msg_iov     = iov; 
     906    msg.msg_iovlen  = 5; 
     907 
     908    cmsg = apr_palloc(pool, sizeof(*cmsg) + sizeof(sock_fd)); 
     909    cmsg->cmsg_len   = sizeof(*cmsg) + sizeof(sock_fd); 
     910    cmsg->cmsg_level = SOL_SOCKET; 
     911    cmsg->cmsg_type  = SCM_RIGHTS; 
     912 
     913    memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd)); 
     914 
     915    msg.msg_control    = cmsg; 
     916    msg.msg_controllen = cmsg->cmsg_len; 
     917 
     918    if (processor->status == CHILD_STATUS_STANDBY) 
     919    { 
     920        _DBG("Activating child #%d", processor->id); 
     921        processor->status = CHILD_STATUS_STARTING; 
     922    } 
     923 
     924    _DBG("Writing message to %d, passing sock_fd:  %d", processor->senv->output, sock_fd); 
     925    _DBG("header_len=%d headers=\"%s\"", header_len, h.headers); 
     926    _DBG("body_len=%d body=\"%s\"", body_len, body); 
     927 
     928    if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1) 
     929    { 
     930        apr_pool_destroy(pool); 
     931        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     932                     "Writing message failed %d %d", rv, errno); 
     933        return -1; 
     934    } 
     935 
     936    _DBG("Writing message succeeded %d", rv); 
     937 
     938    /* -- close the socket on our side -- */ 
     939    _DBG("closing socket %d on our side", sock_fd); 
     940    apr_socket_close(thesock); 
     941 
     942    apr_pool_destroy(pool); 
     943    return 1; 
     944} 
     945 
     946static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id, 
     947                           apr_bucket_alloc_t *bucket_alloc, apr_pool_t *pool) 
     948{ 
     949    conn_rec *current_conn; 
     950    int sock_fd; 
     951    apr_status_t rv; 
     952    ap_sb_handle_t *sbh; 
     953    child_info_t *processor; 
     954    apr_pool_t *ptrans; 
     955    peruser_server_conf *sconf; 
     956 
     957    _DBG("Creating dummy connection to use the vhost lookup api", 0); 
     958 
     959    ap_create_sb_handle(&sbh, p, conn_id, 0); 
     960    current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, 
     961                                            sbh, bucket_alloc); 
     962    _DBG("Looking up the right vhost"); 
     963    if (current_conn) { 
     964            ap_update_vhost_given_ip(current_conn); 
     965            _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname, 
     966                    current_conn->vhost_lookup_data ? "on" : "off"); 
     967    } 
     968 
     969    if (current_conn && !current_conn->vhost_lookup_data && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { 
     970        _DBG("We are not using name based vhosts, we'll directly pass the socket."); 
     971         
     972        sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config); 
     973        processor = &CHILD_INFO_TABLE[sconf->senv->processor_id]; 
     974 
     975        _DBG("Forwarding without further inspection, processor %d", processor->id); 
     976        if (processor->status == CHILD_STATUS_STANDBY) 
     977        { 
     978             _DBG("Activating child #%d", processor->id); 
     979             processor->status = CHILD_STATUS_STARTING; 
     980        } 
     981 
     982        _DBG("Creating new pool",0); 
     983        apr_pool_create(&ptrans, pool); 
     984        _DBG("Passing request.",0); 
     985        if (pass_socket(sock, processor, ptrans) == -1) 
     986        { 
     987            ap_log_error(APLOG_MARK, APLOG_ERR, 0, 
     988                  ap_server_conf, "Could not pass request to proper "                              
     989                  "child, request will not be honoured."); 
     990             return; 
     991        } 
     992        if (current_conn) 
     993        { 
     994            _DBG("freeing connection",0); 
     995            ap_lingering_close(current_conn); 
     996        } 
     997        _DBG("doing longjmp",0); 
     998        longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1); 
     999        return; 
     1000    } 
     1001 
     1002    if ((rv = apr_os_sock_get(&sock_fd, sock)) != APR_SUCCESS) 
     1003    { 
     1004        ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); 
     1005    } 
     1006 
     1007    _DBG("child_num=%d sock=%ld sock_fd=%d\n", my_child_num, sock, sock_fd); 
     1008    _DBG("type=%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num); 
     1009 
     1010    if (sock_fd >= FD_SETSIZE) 
     1011    { 
     1012        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, 
     1013                     "new file descriptor %d is too large; you probably need " 
     1014                     "to rebuild Apache with a larger FD_SETSIZE " 
     1015                     "(currently %d)", 
     1016                     sock_fd, FD_SETSIZE); 
     1017        apr_socket_close(sock); 
     1018        _DBG("child_num=%d: exiting with error", my_child_num); 
     1019        return; 
     1020    } 
     1021 
     1022    if (CHILD_INFO_TABLE[my_child_num].sock_fd < 0) 
     1023    { 
     1024        ap_sock_disable_nagle(sock); 
     1025    } 
     1026 
     1027    if (!current_conn) { 
     1028        ap_create_sb_handle(&sbh, p, conn_id, 0); 
     1029        current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, 
     1030                                                sbh, bucket_alloc); 
     1031    } 
     1032 
     1033    if (current_conn) 
     1034    { 
     1035        ap_process_connection(current_conn, sock); 
     1036        ap_lingering_close(current_conn); 
     1037    } 
     1038} 
     1039 
     1040static int peruser_process_connection(conn_rec *conn) 
     1041{ 
     1042    ap_filter_t *filter; 
     1043    apr_bucket_brigade *bb; 
     1044    core_net_rec *net; 
     1045 
     1046    _DBG("function entered",0); 
     1047 
     1048    /* -- fetch our sockets from the pool -- */ 
     1049    apr_pool_userdata_get((void **)&bb, "PERUSER_SOCKETS", conn->pool); 
     1050    if (bb != NULL) 
     1051    { 
     1052        /* -- find the 'core' filter and give the socket data to it -- */ 
     1053        for (filter = conn->output_filters; filter != NULL; filter = filter->next) 
     1054        { 
     1055            if (!strcmp(filter->frec->name, "core")) break; 
     1056        } 
     1057        if (filter != NULL) 
     1058        { 
     1059            net = filter->ctx; 
     1060            net->in_ctx = apr_palloc(conn->pool, sizeof(*net->in_ctx)); 
     1061            net->in_ctx->b = bb; 
     1062            net->in_ctx->tmpbb = apr_brigade_create(net->in_ctx->b->p,  
     1063                net->in_ctx->b->bucket_alloc); 
     1064        } 
     1065    } 
     1066    _DBG("leaving (DECLINED)", 0); 
     1067    return DECLINED; 
     1068} 
     1069 
     1070static int total_processors(int child_num) 
     1071{ 
     1072    int i, total; 
     1073 
     1074    for(i = 0, total = 0; i < NUM_CHILDS; ++i) 
     1075    { 
     1076        if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv) 
     1077            total++; 
     1078    } 
     1079 
     1080    return total; 
     1081} 
     1082 
     1083static int idle_processors(int child_num) 
     1084{ 
     1085    int i, total; 
     1086 
     1087    for(i = 0, total = 0; i < NUM_CHILDS; ++i) 
     1088    { 
     1089        if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv && 
     1090           (SCOREBOARD_STATUS(i) == SERVER_STARTING || 
     1091            SCOREBOARD_STATUS(i) == SERVER_READY)) 
     1092        { 
     1093            total++; 
     1094        } 
     1095    } 
     1096 
     1097    return total; 
     1098} 
     1099 
     1100static int pass_request(request_rec *r, child_info_t *processor) 
     1101{ 
     1102    int rv; 
     1103    struct msghdr msg; 
     1104    struct cmsghdr *cmsg; 
     1105    apr_sockaddr_t *remote_addr; 
     1106    int sock_fd; 
     1107    char *body = ""; 
     1108    struct iovec iov[5]; 
     1109    conn_rec *c = r->connection; 
     1110    apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc); 
     1111    apr_bucket_brigade *body_bb = NULL; 
     1112    apr_size_t len = 0; 
     1113    apr_size_t header_len = 0; 
     1114    apr_size_t body_len = 0; 
     1115    peruser_header h; 
     1116    apr_bucket *bucket; 
     1117    const apr_array_header_t *headers_in_array; 
     1118    const apr_table_entry_t *headers_in; 
     1119    int counter; 
     1120 
     1121    apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module); 
     1122 
     1123    if ((!r->the_request) || (!strlen(r->the_request))) 
     1124    { 
     1125        _DBG("empty request. dropping it (%ld)", r->the_request); 
     1126        return -1; 
     1127    } 
     1128 
     1129    if (!processor) 
     1130    { 
     1131        _DBG("server %s in child %d has no child_info associated", 
     1132                r->hostname, my_child_num); 
     1133        return -1; 
     1134    } 
     1135 
     1136    _DBG("passing request to another child.  Vhost: %s, child %d %d", 
     1137      apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output); 
     1138    _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request)); 
     1139 
     1140    ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len); 
     1141 
     1142    /* Scan the brigade looking for heap-buckets */ 
     1143 
     1144    _DBG("Scanning the brigade",0); 
     1145    bucket = APR_BRIGADE_FIRST(bb); 
     1146    while (bucket != APR_BRIGADE_SENTINEL(bb) && 
     1147           APR_BUCKET_IS_HEAP(bucket)) { 
     1148       _DBG("HEAP BUCKET is found, length=%d", bucket->length); 
     1149        bucket = APR_BUCKET_NEXT(bucket); 
     1150        if (!APR_BUCKET_IS_HEAP(bucket)) { 
     1151            _DBG("NON-HEAP BUCKET is found, extracting the part of brigade before it",0); 
     1152            body_bb = bb; 
     1153            bb = apr_brigade_split(body_bb, bucket); 
     1154            /* Do we need to apr_destroy_brigade(bb) here? 
     1155             * Yeah, I know we do apr_pool_destroy(r->pool) before return, but 
     1156             * ap_get_brigade is in non-blocking mode (however len is zero). 
     1157             */ 
     1158            if (apr_brigade_pflatten(body_bb, &body, &body_len, r->pool) != APR_SUCCESS) { 
     1159                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     1160                     "Unable to flatten brigade, declining request"); 
     1161                apr_pool_destroy(r->pool); 
     1162                return DECLINED; 
     1163            } 
     1164            _DBG("Brigade is flattened as body (body_len=%d)", body_len); 
     1165        } 
     1166    } 
     1167    _DBG("Scanning is finished",0); 
     1168 
     1169    apr_os_sock_get(&sock_fd, thesock); 
     1170    /* looks like a bug while sending/receiving SCM_RIGHTS related to ipv6 
     1171       workaround: send remote_addr structure too */ 
     1172    apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock); 
     1173 
     1174    h.p = r->pool; 
     1175 
     1176    headers_in_array = apr_table_elts(r->headers_in); 
     1177    headers_in = (const apr_table_entry_t *) headers_in_array->elts; 
     1178 
     1179    h.headers = apr_pstrcat(h.p, r->the_request, CRLF, NULL); 
     1180    for (counter = 0; counter < headers_in_array->nelts; counter++) { 
     1181        if (headers_in[counter].key == NULL 
     1182         || headers_in[counter].val == NULL) { 
     1183             continue; 
     1184         } 
     1185         h.headers = apr_pstrcat(h.p, h.headers, headers_in[counter].key, ": ", 
     1186                                 headers_in[counter].val, CRLF, NULL); 
     1187 
     1188    } 
     1189    h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL); 
     1190    ap_xlate_proto_to_ascii(h.headers, strlen(h.headers)); 
     1191 
     1192    header_len = strlen(h.headers); 
     1193 
     1194    iov[0].iov_base = &header_len; 
     1195    iov[0].iov_len  = sizeof(header_len); 
     1196    iov[1].iov_base = &body_len; 
     1197    iov[1].iov_len  = sizeof(body_len); 
     1198    iov[2].iov_base = remote_addr; 
     1199    iov[2].iov_len  = sizeof(*remote_addr); 
     1200    iov[3].iov_base = h.headers; 
     1201    iov[3].iov_len  = strlen(h.headers) + 1; 
     1202    iov[4].iov_base = body; 
     1203    iov[4].iov_len  = body_len; 
     1204 
     1205    msg.msg_name    = NULL; 
     1206    msg.msg_namelen = 0; 
     1207    msg.msg_iov     = iov; 
     1208    msg.msg_iovlen  = 5; 
     1209 
     1210    cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sock_fd)); 
     1211    cmsg->cmsg_len   = sizeof(*cmsg) + sizeof(sock_fd); 
     1212    cmsg->cmsg_level = SOL_SOCKET; 
     1213    cmsg->cmsg_type  = SCM_RIGHTS; 
     1214 
     1215    memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd)); 
     1216 
     1217    msg.msg_control    = cmsg; 
     1218    msg.msg_controllen = cmsg->cmsg_len; 
     1219 
     1220 
     1221    if (processor->status == CHILD_STATUS_STANDBY) 
     1222    { 
     1223        _DBG("Activating child #%d", processor->id); 
     1224        processor->status = CHILD_STATUS_STARTING; 
     1225    } 
     1226 
     1227    _DBG("Writing message to %d, passing sock_fd:  %d", processor->senv->output, sock_fd); 
     1228    _DBG("header_len=%d headers=\"%s\"", header_len, h.headers); 
     1229    _DBG("body_len=%d body=\"%s\"", body_len, body); 
     1230 
     1231    if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1) 
     1232    { 
     1233        apr_pool_destroy(r->pool); 
     1234        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     1235                     "Writing message failed %d %d", rv, errno); 
     1236        return -1; 
     1237    } 
     1238 
     1239    _DBG("Writing message succeeded %d", rv); 
     1240 
     1241    /* -- close the socket on our side -- */ 
     1242    _DBG("closing socket %d on our side", sock_fd); 
     1243    apr_socket_close(thesock); 
     1244 
     1245    apr_pool_destroy(r->pool); 
     1246    return 1; 
     1247} 
     1248 
     1249 
     1250static apr_status_t receive_from_multiplexer( 
     1251    void **trans_sock,  /* will be filled out w/ the received socket */ 
     1252    ap_listen_rec *lr,  /* listener to receive from */ 
     1253    apr_pool_t *ptrans  /* transaction wide pool */ 
     1254) 
     1255{ 
     1256    struct msghdr msg; 
     1257    struct cmsghdr *cmsg; 
     1258    char buff[HUGE_STRING_LEN] = ""; 
     1259    char headers[HUGE_STRING_LEN] = ""; 
     1260    char *body = ""; 
     1261    apr_size_t header_len, body_len; 
     1262    struct iovec iov[4]; 
     1263    int ret, fd_tmp; 
     1264    apr_os_sock_t ctrl_sock_fd; 
     1265    apr_os_sock_t trans_sock_fd; 
     1266    apr_sockaddr_t remote_addr; 
     1267    apr_os_sock_info_t sockinfo; 
     1268 
     1269    /* -- bucket's, brigades and their allocators */ 
     1270    apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans); 
     1271    apr_bucket_brigade *bb    = apr_brigade_create(ptrans, alloc); 
     1272    apr_bucket         *bucket; 
     1273 
     1274    /* prepare the buffers for receiving data from remote side */ 
     1275    iov[0].iov_base = &header_len; 
     1276    iov[0].iov_len  = sizeof(header_len); 
     1277    iov[1].iov_base = &body_len; 
     1278    iov[1].iov_len  = sizeof(body_len); 
     1279    iov[2].iov_base = &remote_addr; 
     1280    iov[2].iov_len  = sizeof(remote_addr); 
     1281    iov[3].iov_base = (char*)&buff; 
     1282    iov[3].iov_len  = HUGE_STRING_LEN; 
     1283 
     1284    cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd)); 
     1285    cmsg->cmsg_len = sizeof(*cmsg) + sizeof(trans_sock_fd); 
     1286 
     1287    msg.msg_name       = NULL; 
     1288    msg.msg_namelen    = 0; 
     1289    msg.msg_iov        = iov; 
     1290    msg.msg_iovlen     = 4; 
     1291    msg.msg_control    = cmsg; 
     1292    msg.msg_controllen = cmsg->cmsg_len; 
     1293 
     1294    /* -- receive data from socket -- */ 
     1295    apr_os_sock_get(&ctrl_sock_fd, lr->sd); 
     1296    _DBG("receiving from sock_fd=%d", ctrl_sock_fd); 
     1297    ret = recvmsg(ctrl_sock_fd, &msg, 0); 
     1298 
     1299    if(ret == -1) 
     1300      _DBG("recvmsg failed with error \"%s\"", strerror(errno)); 
     1301    else 
     1302      _DBG("recvmsg returned %d", ret); 
     1303 
     1304    /* -- extract socket from the cmsg -- */ 
     1305    memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd)); 
     1306    /* here *trans_sock always == NULL (socket reset at got_fd), so 
     1307       we can use apr_os_sock_make() instead of apr_os_sock_put() */ 
     1308    sockinfo.os_sock  = &trans_sock_fd; 
     1309    sockinfo.local    = NULL; 
     1310    sockinfo.remote   = (struct sockaddr *)&remote_addr.sa.sin; 
     1311    sockinfo.family   = remote_addr.family; 
     1312    sockinfo.type     = SOCK_STREAM; 
     1313#ifdef APR_ENABLE_FOR_1_0 
     1314    sockinfo.protocol = 0; 
     1315#endif 
     1316    apr_os_sock_make((apr_socket_t **)trans_sock, &sockinfo, ptrans); 
     1317    apr_os_sock_get(&fd_tmp, *trans_sock); 
     1318 
     1319    _DBG("trans_sock=%ld fdx=%d sock_fd=%d", 
     1320         *trans_sock, trans_sock_fd, fd_tmp); 
     1321 
     1322    apr_cpystrn(headers, buff, header_len + 1); 
     1323    _DBG("header_len=%d headers=\"%s\"", header_len, headers); 
     1324 
     1325if (header_len) {     
     1326    _DBG("header_len > 0, we got a request", 0); 
     1327    /* -- store received data into an brigade and add 
     1328          it to the current transaction's pool -- */ 
     1329    bucket = apr_bucket_eos_create(alloc); 
     1330    APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1331    bucket = apr_bucket_socket_create(*trans_sock, alloc); 
     1332    APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1333 
     1334    if (body_len) { 
     1335        body = (char*)&buff[header_len + 1]; 
     1336        _DBG("body_len=%d body=\"%s\"", body_len, body); 
     1337 
     1338        bucket = apr_bucket_heap_create(body, body_len, NULL, alloc); 
     1339        APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1340    } else { 
     1341        _DBG("There is no body",0); 
     1342    } 
     1343 
     1344    bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc); 
     1345 
     1346    APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1347    apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans); 
     1348} else { 
     1349    _DBG("header_len == 0, we got a socket only", 0); 
     1350} 
     1351    _DBG("returning 0", 0); 
     1352    return 0; 
     1353} 
     1354 
     1355 
     1356/* Set group privileges. 
     1357 * 
     1358 * Note that we use the username as set in the config files, rather than 
     1359 * the lookup of to uid --- the same uid may have multiple passwd entries, 
     1360 * with different sets of groups for each. 
     1361 */ 
     1362 
     1363static int set_group_privs(uid_t uid, gid_t gid) 
     1364{ 
     1365    if (!geteuid()) 
     1366    { 
     1367        struct passwd *ent; 
     1368        const char *name; 
     1369 
     1370        /* 
     1371         * Set the GID before initgroups(), since on some platforms 
     1372         * setgid() is known to zap the group list. 
     1373         */ 
     1374        if (setgid(gid) == -1) 
     1375        { 
     1376            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1377                         "setgid: unable to set group id to Group %u", 
     1378                         (unsigned)gid); 
     1379            return -1; 
     1380        } 
     1381 
     1382        /* if getpwuid() fails, just skip initgroups() */ 
     1383 
     1384        if ((ent = getpwuid(uid)) != NULL) 
     1385        { 
     1386            name = ent->pw_name; 
     1387 
     1388            /* Reset `groups' attributes. */ 
     1389 
     1390            if (initgroups(name, gid) == -1) 
     1391            { 
     1392                ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1393                             "initgroups: unable to set groups for User %s " 
     1394                             "and Group %u", name, (unsigned)gid); 
     1395                return -1; 
     1396            } 
     1397        } 
     1398    } 
     1399    return 0; 
     1400} 
     1401 
     1402static int peruser_setup_child(int childnum) 
     1403{ 
     1404    server_env_t *senv = CHILD_INFO_TABLE[childnum].senv; 
     1405 
     1406    if(senv->chroot) { 
     1407      _DBG("chdir to %s", senv->chroot); 
     1408      if(chdir(senv->chroot)) { 
     1409        ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1410                     "chdir: unable to change to directory: %s", 
     1411                     senv->chroot); 
     1412        return -1; 
     1413      } 
     1414 
     1415      _DBG("chroot to %s", senv->chroot); 
     1416      if(chroot(senv->chroot)) { 
     1417        ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1418                     "chroot: unable to change root to: %s", 
     1419                     senv->chroot); 
     1420        return -1; 
     1421      } 
     1422    } 
     1423 
     1424    if (senv->uid == -1 && senv->gid == -1) { 
     1425        return unixd_setup_child(); 
     1426    } 
     1427    if (set_group_privs(senv->uid, senv->gid)) { 
     1428        return -1; 
     1429    } 
     1430    /* Only try to switch if we're running as root */ 
     1431    if (!geteuid() 
     1432        && ( 
     1433#ifdef _OSD_POSIX 
     1434            os_init_job_environment(ap_server_conf, unixd_config.user_name, 
     1435                                    one_process) != 0 || 
     1436#endif 
     1437            setuid(senv->uid) == -1)) { 
     1438        ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1439                     "setuid: unable to change to uid: %ld", 
     1440                     (long) senv->uid); 
     1441        return -1; 
     1442    } 
     1443    return 0; 
     1444} 
     1445 
     1446static int check_signal(int signum) 
     1447{ 
     1448    _DBG("signum=%d", signum); 
     1449    switch (signum) { 
     1450    case SIGTERM: 
     1451    case SIGINT: 
     1452        just_die(signum); 
     1453        return 1; 
     1454    } 
     1455    return 0; 
     1456} 
     1457 
     1458/* Send a single HTTP header field to the client.  Note that this function 
     1459 * is used in calls to table_do(), so their interfaces are co-dependent. 
     1460 * In other words, don't change this one without checking table_do in alloc.c. 
     1461 * It returns true unless there was a write error of some kind. 
     1462 */ 
     1463static int peruser_header_field(peruser_header *h, 
     1464                             const char *fieldname, const char *fieldval) 
     1465{ 
     1466    apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL); 
     1467    return 1; 
     1468} 
     1469 
     1470static inline ap_listen_rec* listen_add(apr_pool_t* pool, apr_socket_t *sock, void* accept_func) 
     1471{ 
     1472    ap_listen_rec *lr_walk, *lr_new; 
     1473 
     1474    _DBG("function entered", 0); 
     1475    /* -- create an new listener for this child -- */ 
     1476    lr_new = apr_palloc(pool, sizeof(*lr_new)); 
     1477    lr_new->sd          = sock; 
     1478    lr_new->active      = 1; 
     1479    lr_new->accept_func = accept_func; 
     1480    lr_new->next        = NULL; 
     1481 
     1482    /* -- add the new listener_rec into the list -- */ 
     1483    /* FIXME: should we somehow lock this list ? */ 
     1484    lr_walk = ap_listeners; 
     1485    if (lr_walk) 
     1486    { 
     1487        while (lr_walk->next) lr_walk = lr_walk->next; 
     1488        lr_walk->next = lr_new; 
     1489    } 
     1490    else 
     1491    { 
     1492        ap_listeners = lr_walk = lr_new; 
     1493    } 
     1494    num_listensocks++; 
     1495    return lr_new; 
     1496} 
     1497 
     1498static inline void listen_clear() 
     1499{ 
     1500    ap_listen_rec *lr_walk; 
     1501 
     1502    _DBG("function entered", 0); 
     1503 
     1504    /* FIXME: should we somehow lock this list ? */ 
     1505    while (ap_listeners) 
     1506    { 
     1507        lr_walk = ap_listeners->next; 
     1508        apr_socket_close(ap_listeners->sd); 
     1509        ap_listeners = lr_walk; 
     1510    } 
     1511    num_listensocks=0; 
     1512} 
     1513 
     1514apr_status_t cleanup_child_info(void *d) 
     1515{ 
     1516    if (child_info_image == NULL) { 
     1517        return APR_SUCCESS; 
     1518    } 
     1519 
     1520    free(child_info_image); 
     1521    child_info_image = NULL; 
     1522    apr_shm_destroy(child_info_shm); 
     1523 
     1524    return APR_SUCCESS; 
     1525} 
     1526 
     1527apr_status_t cleanup_server_environments(void *d) 
     1528{ 
     1529    if (server_env_image == NULL) { 
     1530        return APR_SUCCESS; 
     1531    } 
     1532 
     1533    free(server_env_image); 
     1534    server_env_image = NULL; 
     1535    apr_shm_destroy(server_env_shm); 
     1536 
     1537    return APR_SUCCESS; 
     1538} 
     1539 
     1540static const char* child_clone(); 
     1541 
     1542static void child_main(int child_num_arg) 
     1543{ 
     1544    apr_pool_t *ptrans; 
     1545    apr_allocator_t *allocator; 
     1546    conn_rec *current_conn; 
     1547    apr_status_t status = APR_EINIT; 
     1548    int i; 
     1549    ap_listen_rec *lr; 
     1550    int curr_pollfd, last_pollfd = 0; 
     1551    apr_pollfd_t *pollset; 
     1552    int offset; 
     1553    ap_sb_handle_t *sbh; 
     1554    apr_status_t rv; 
     1555    apr_bucket_alloc_t *bucket_alloc; 
     1556    int fd; 
     1557    apr_socket_t *sock = NULL; 
     1558    apr_socket_t *pod_sock = NULL; 
     1559 
     1560    mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this 
     1561                                  * child initializes 
     1562                                  */ 
     1563 
     1564    my_child_num = child_num_arg; 
     1565    ap_my_pid = getpid(); 
     1566    requests_this_child = 0; 
     1567 
     1568    _DBG("sock_fd_in=%d sock_fd_out=%d", 
     1569         CHILD_INFO_TABLE[my_child_num].senv->input, 
     1570         CHILD_INFO_TABLE[my_child_num].senv->output); 
     1571 
     1572    /* Get a sub context for global allocations in this child, so that 
     1573     * we can have cleanups occur when the child exits. 
     1574     */ 
     1575    apr_allocator_create(&allocator); 
     1576    apr_allocator_max_free_set(allocator, ap_max_mem_free); 
     1577    apr_pool_create_ex(&pchild, pconf, NULL, allocator); 
     1578    apr_allocator_owner_set(allocator, pchild); 
     1579 
     1580    apr_pool_create(&ptrans, pchild); 
     1581    apr_pool_tag(ptrans, "transaction"); 
     1582 
     1583    /* needs to be done before we switch UIDs so we have permissions */ 
     1584    ap_reopen_scoreboard(pchild, NULL, 0); 
     1585 
     1586    rv = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild); 
     1587    if (rv != APR_SUCCESS) { 
     1588        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, 
     1589                     "Couldn't initialize cross-process lock in child"); 
     1590        clean_child_exit(APEXIT_CHILDFATAL); 
     1591    } 
     1592 
     1593    switch(CHILD_INFO_TABLE[my_child_num].type) 
     1594    { 
     1595        case CHILD_TYPE_MULTIPLEXER: 
     1596            _DBG("MULTIPLEXER %d", my_child_num); 
     1597 
     1598            /* update status on processors that are ready to accept requests */ 
     1599            _DBG("updating processor stati", 0); 
     1600            for(i = 0; i < NUM_CHILDS; ++i) 
     1601            { 
     1602                if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY) 
     1603                    CHILD_INFO_TABLE[i].status = CHILD_STATUS_ACTIVE; 
     1604            } 
     1605 
     1606            break; 
     1607 
     1608        case CHILD_TYPE_PROCESSOR: 
     1609        case CHILD_TYPE_WORKER: 
     1610            _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num); 
     1611 
     1612            /* -- create new listener to receive from multiplexer -- */ 
     1613            apr_os_sock_put(&sock, &CHILD_INFO_TABLE[my_child_num].senv->input, pconf); 
     1614            listen_clear(); 
     1615            listen_add(pconf, sock, receive_from_multiplexer); 
     1616 
     1617            break; 
     1618 
     1619        default: 
     1620            _DBG("unspecified child type for %d sleeping a while ...", my_child_num); 
     1621            sleep(5); 
     1622            return; 
     1623    } 
     1624 
     1625    apr_os_file_get(&fd, pipe_of_death_in); 
     1626    apr_os_sock_put(&pod_sock, &fd, pconf); 
     1627    listen_add(pconf, pod_sock, check_pipe_of_death); 
     1628 
     1629    if(peruser_setup_child(my_child_num) != 0) 
     1630        clean_child_exit(APEXIT_CHILDFATAL); 
     1631 
     1632    ap_run_child_init(pchild, ap_server_conf); 
     1633 
     1634    ap_create_sb_handle(&sbh, pchild, my_child_num, 0); 
     1635    (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); 
     1636 
     1637    /* Set up the pollfd array */ 
     1638    listensocks = apr_pcalloc(pchild, 
     1639                            sizeof(*listensocks) * (num_listensocks)); 
     1640    for (lr = ap_listeners, i = 0; i < num_listensocks; lr = lr->next, i++) { 
     1641        listensocks[i].accept_func = lr->accept_func; 
     1642        listensocks[i].sd = lr->sd; 
     1643    } 
     1644 
     1645    pollset = apr_palloc(pchild, sizeof(*pollset) * num_listensocks); 
     1646    pollset[0].p = pchild; 
     1647    for (i = 0; i < num_listensocks; i++) { 
     1648        pollset[i].desc.s = listensocks[i].sd; 
     1649        pollset[i].desc_type = APR_POLL_SOCKET; 
     1650        pollset[i].reqevents = APR_POLLIN; 
     1651    } 
     1652 
     1653    mpm_state = AP_MPMQ_RUNNING; 
     1654 
     1655    bucket_alloc = apr_bucket_alloc_create(pchild); 
     1656 
     1657    while (!die_now) { 
     1658        /* 
     1659         * (Re)initialize this child to a pre-connection state. 
     1660         */ 
     1661 
     1662        current_conn = NULL; 
     1663 
     1664        apr_pool_clear(ptrans); 
     1665 
     1666        if (CHILD_INFO_TABLE[my_child_num].type != CHILD_TYPE_MULTIPLEXER 
     1667             && ap_max_requests_per_child > 0 
     1668             && requests_this_child++ >= ap_max_requests_per_child) { 
     1669            _DBG("max requests reached, dying now", 0); 
     1670            clean_child_exit(0); 
     1671        } 
     1672 
     1673        (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); 
     1674 
     1675        /* 
     1676         * Wait for an acceptable connection to arrive. 
     1677         */ 
     1678 
     1679        /* Lock around "accept", if necessary */ 
     1680        SAFE_ACCEPT(accept_mutex_on()); 
     1681 
     1682        if (num_listensocks == 1) { 
     1683            offset = 0; 
     1684        } 
     1685        else { 
     1686            /* multiple listening sockets - need to poll */ 
     1687            for (;;) { 
     1688                apr_status_t ret; 
     1689                apr_int32_t n; 
     1690 
     1691                ret = apr_poll(pollset, num_listensocks, &n, -1); 
     1692                if (ret != APR_SUCCESS) { 
     1693                    if (APR_STATUS_IS_EINTR(ret)) { 
     1694                        continue; 
     1695                    } 
     1696                    /* Single Unix documents select as returning errnos 
     1697                     * EBADF, EINTR, and EINVAL... and in none of those 
     1698                     * cases does it make sense to continue.  In fact 
     1699                     * on Linux 2.0.x we seem to end up with EFAULT 
     1700                     * occasionally, and we'd loop forever due to it. 
     1701                     */ 
     1702                    ap_log_error(APLOG_MARK, APLOG_ERR, ret, ap_server_conf, 
     1703                             "apr_poll: (listen)"); 
     1704                    clean_child_exit(1); 
     1705                } 
     1706                /* find a listener */ 
     1707                curr_pollfd = last_pollfd; 
     1708                do { 
     1709                    curr_pollfd++; 
     1710                    if (curr_pollfd >= num_listensocks) { 
     1711                        curr_pollfd = 0; 
     1712                    } 
     1713                    /* XXX: Should we check for POLLERR? */ 
     1714                    if (pollset[curr_pollfd].rtnevents & APR_POLLIN) { 
     1715                        last_pollfd = curr_pollfd; 
     1716                        offset = curr_pollfd; 
     1717                        goto got_fd; 
     1718                    } 
     1719                } while (curr_pollfd != last_pollfd); 
     1720 
     1721                continue; 
     1722            } 
     1723        } 
     1724    got_fd: 
     1725        _DBG("input available ... resetting socket.",0); 
     1726        sock = NULL;    /* important! */ 
     1727 
     1728        /* if we accept() something we don't want to die, so we have to 
     1729         * defer the exit 
     1730         */ 
     1731        status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans); 
     1732        SAFE_ACCEPT(accept_mutex_off());        /* unlock after "accept" */ 
     1733 
     1734        if (status == APR_EGENERAL) { 
     1735            /* resource shortage or should-not-occur occured */ 
     1736            clean_child_exit(1); 
     1737        } 
     1738        else if (status != APR_SUCCESS || die_now) { 
     1739            continue; 
     1740        } 
     1741 
     1742        if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR || 
     1743            CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER) 
     1744        { 
     1745          _DBG("CHECKING IF WE SHOULD CLONE A CHILD..."); 
     1746 
     1747          _DBG("total_processors = %d, max_processors = %d", 
     1748            total_processors(my_child_num), 
     1749            CHILD_INFO_TABLE[my_child_num].senv->max_processors); 
     1750 
     1751          _DBG("idle_processors = %d, min_free_processors = %d", 
     1752            idle_processors(my_child_num), 
     1753            CHILD_INFO_TABLE[my_child_num].senv->min_free_processors); 
     1754 
     1755          if(total_processors(my_child_num) < 
     1756              CHILD_INFO_TABLE[my_child_num].senv->max_processors && 
     1757            idle_processors(my_child_num) <= 
     1758              CHILD_INFO_TABLE[my_child_num].senv->min_free_processors) 
     1759          { 
     1760              _DBG("CLONING CHILD"); 
     1761              child_clone(); 
     1762          } 
     1763        } 
     1764 
     1765        if (!setjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer)) 
     1766        { 
     1767            _DBG("marked jmpbuffer",0); 
     1768            _TRACE_CALL("process_socket()",0); 
     1769            process_socket(ptrans, sock, my_child_num, bucket_alloc, pchild); 
     1770            _TRACE_RET("process_socket()",0); 
     1771        } 
     1772        else 
     1773        { 
     1774            _DBG("landed from longjmp",0); 
     1775            CHILD_INFO_TABLE[my_child_num].sock_fd = AP_PERUSER_THISCHILD; 
     1776        } 
     1777 
     1778        /* Check the pod and the generation number after processing a 
     1779         * connection so that we'll go away if a graceful restart occurred 
     1780         * while we were processing the connection or we are the lucky 
     1781         * idle server process that gets to die. 
     1782         */ 
     1783        if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ 
     1784            _DBG("ap_mpm_pod_check(pod) = APR_SUCCESS; dying now", 0); 
     1785            die_now = 1; 
     1786        } 
     1787        else if (ap_my_generation != 
     1788                 ap_scoreboard_image->global->running_generation) { /* restart? */ 
     1789            /* yeah, this could be non-graceful restart, in which case the 
     1790             * parent will kill us soon enough, but why bother checking? 
     1791             */ 
     1792            _DBG("ap_my_generation != ap_scoreboard_image->global->running_generation; dying now", 0); 
     1793            die_now = 1; 
     1794        } 
     1795 
     1796        if(CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_RESTART) 
     1797        { 
     1798            _DBG("restarting", 0); 
     1799            die_now = 1; 
     1800        } 
     1801    } 
     1802 
     1803    _DBG("clean_child_exit(0)"); 
     1804    clean_child_exit(0); 
     1805} 
     1806 
     1807static server_env_t* senv_add(int uid, int gid, const char* chroot) 
     1808{ 
     1809    int i; 
     1810    int socks[2]; 
     1811 
     1812    _DBG("Searching for matching senv..."); 
     1813 
     1814    for(i = 0; i < NUM_SENV; i++) 
     1815    { 
     1816      if(SENV[i].uid == uid && SENV[i].gid == gid && 
     1817         (SENV[i].chroot == NULL || !strcmp(SENV[i].chroot, chroot))) 
     1818      { 
     1819          _DBG("Found existing senv: %i", i); 
     1820          return &SENV[i]; 
     1821      } 
     1822    } 
     1823 
     1824    if(NUM_SENV >= server_limit) 
     1825    { 
     1826      _DBG("server_limit reached!"); 
     1827      return NULL; 
     1828    } 
     1829 
     1830    _DBG("Creating new senv"); 
     1831 
     1832    SENV[NUM_SENV].uid = uid; 
     1833    SENV[NUM_SENV].gid = gid; 
     1834    SENV[NUM_SENV].chroot = chroot; 
     1835 
     1836    SENV[NUM_SENV].min_processors = ap_min_processors; 
     1837    SENV[NUM_SENV].min_free_processors = ap_min_free_processors; 
     1838    SENV[NUM_SENV].max_processors = ap_max_processors; 
     1839 
     1840    socketpair(PF_UNIX, SOCK_STREAM, 0, socks); 
     1841    SENV[NUM_SENV].input  = socks[0]; 
     1842    SENV[NUM_SENV].output = socks[1]; 
     1843 
     1844    return &SENV[server_env_image->control->num++]; 
     1845} 
     1846 
     1847static const char* child_clone() 
     1848{ 
     1849    int i; 
     1850    child_info_t *this; 
     1851    child_info_t *new; 
     1852 
     1853    for(i = 0; i < NUM_CHILDS; i++) 
     1854    { 
     1855      if(CHILD_INFO_TABLE[i].pid == 0 && 
     1856         CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) break; 
     1857    } 
     1858     
     1859    if(i == NUM_CHILDS && NUM_CHILDS >= server_limit) 
     1860    { 
     1861        _DBG("Trying to use more child ID's than NumServers.  " 
     1862               "Increase NumServers in your config file."); 
     1863        return NULL; 
     1864    }     
     1865 
     1866    _DBG("cloning child #%d from #%d", i, my_child_num); 
     1867 
     1868    this = &CHILD_INFO_TABLE[my_child_num]; 
     1869    new = &CHILD_INFO_TABLE[i]; 
     1870 
     1871    new->senv = this->senv; 
     1872    new->type = CHILD_TYPE_WORKER; 
     1873    new->sock_fd = this->sock_fd; 
     1874    new->status = CHILD_STATUS_STARTING; 
     1875 
     1876    if(i == NUM_CHILDS) child_info_image->control->num++; 
     1877    return NULL; 
     1878} 
     1879 
     1880static const char* child_add(int type, int status, 
     1881                             apr_pool_t *pool, uid_t uid, gid_t gid, const char* chroot) 
     1882{ 
     1883    _DBG("adding child #%d", NUM_CHILDS); 
     1884 
     1885    if(NUM_CHILDS >= server_limit) 
     1886    { 
     1887        return "Trying to use more child ID's than NumServers.  " 
     1888               "Increase NumServers in your config file."; 
     1889    } 
     1890 
     1891       if (chroot && !ap_is_directory(pool, chroot)) 
     1892               return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", chroot); 
     1893 
     1894    CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(uid, gid, chroot); 
     1895 
     1896    if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL) 
     1897    { 
     1898        return "Trying to use more server environments than NumServers.  " 
     1899               "Increase NumServers in your config file."; 
     1900    } 
     1901 
     1902    if(type != CHILD_TYPE_WORKER) 
     1903        CHILD_INFO_TABLE[NUM_CHILDS].senv->processor_id = NUM_CHILDS; 
     1904 
     1905    CHILD_INFO_TABLE[NUM_CHILDS].type = type; 
     1906    CHILD_INFO_TABLE[NUM_CHILDS].sock_fd = AP_PERUSER_THISCHILD; 
     1907    CHILD_INFO_TABLE[NUM_CHILDS].status = status; 
     1908 
     1909    _DBG("[%d] uid=%d gid=%d type=%d chroot=%s", 
     1910         NUM_CHILDS, uid, gid, type, 
     1911         chroot); 
     1912 
     1913    if (uid == 0 || gid == 0) 
     1914    { 
     1915        _DBG("Assigning root user/group to a child.", 0); 
     1916    } 
     1917 
     1918    child_info_image->control->num++; 
     1919 
     1920    return NULL; 
     1921} 
     1922 
     1923static int make_child(server_rec *s, int slot) 
     1924{ 
     1925    int pid; 
     1926 
     1927    _DBG("function entered", 0); 
     1928    dump_server_env_image(); 
     1929 
     1930    switch (CHILD_INFO_TABLE[slot].type) 
     1931    { 
     1932        case CHILD_TYPE_MULTIPLEXER: break; 
     1933        case CHILD_TYPE_PROCESSOR: break; 
     1934        case CHILD_TYPE_WORKER: break; 
     1935 
     1936        default: 
     1937            _DBG("no valid client in slot %d", slot); 
     1938            /* sleep(1); */ 
     1939            return 0; 
     1940    } 
     1941 
     1942    if (slot + 1 > ap_max_daemons_limit) { 
     1943        ap_max_daemons_limit = slot + 1; 
     1944    } 
     1945 
     1946    if (one_process) { 
     1947        apr_signal(SIGHUP, just_die); 
     1948        /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */ 
     1949        apr_signal(SIGINT, just_die); 
     1950#ifdef SIGQUIT 
     1951        apr_signal(SIGQUIT, SIG_DFL); 
     1952#endif 
     1953        apr_signal(SIGTERM, just_die); 
     1954        child_main(slot); 
     1955    } 
     1956 
     1957    (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, 
     1958                                               (request_rec *) NULL); 
     1959 
     1960    CHILD_INFO_TABLE[slot].status = CHILD_STATUS_ACTIVE; 
     1961 
     1962 
     1963#ifdef _OSD_POSIX 
     1964    /* BS2000 requires a "special" version of fork() before a setuid() call */ 
     1965    if ((pid = os_fork(unixd_config.user_name)) == -1) { 
     1966#elif defined(TPF) 
     1967    if ((pid = os_fork(s, slot)) == -1) { 
     1968#else 
     1969    if ((pid = fork()) == -1) { 
     1970#endif 
     1971        ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process"); 
     1972 
     1973        /* fork didn't succeed. Fix the scoreboard or else 
     1974         * it will say SERVER_STARTING forever and ever 
     1975         */ 
     1976        (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, 
     1977                                                   (request_rec *) NULL); 
     1978 
     1979        /* In case system resources are maxxed out, we don't want 
     1980           Apache running away with the CPU trying to fork over and 
     1981           over and over again. */ 
     1982        sleep(10); 
     1983 
     1984        return -1; 
     1985    } 
     1986 
     1987    if (!pid) { 
     1988#ifdef HAVE_BINDPROCESSOR 
     1989        /* by default AIX binds to a single processor 
     1990         * this bit unbinds children which will then bind to another cpu 
     1991         */ 
     1992        int status = bindprocessor(BINDPROCESS, (int)getpid(),  
     1993                                   PROCESSOR_CLASS_ANY); 
     1994        if (status != OK) { 
     1995            ap_log_error(APLOG_MARK, APLOG_WARNING, errno,  
     1996                         ap_server_conf, "processor unbind failed %d", status); 
     1997        } 
     1998#endif 
     1999        RAISE_SIGSTOP(MAKE_CHILD); 
     2000        AP_MONCONTROL(1); 
     2001        /* Disable the parent's signal handlers and set up proper handling in 
     2002         * the child. 
     2003         */ 
     2004        apr_signal(SIGHUP, just_die); 
     2005        apr_signal(SIGTERM, just_die); 
     2006        /* The child process doesn't do anything for AP_SIG_GRACEFUL.   
     2007         * Instead, the pod is used for signalling graceful restart. 
     2008         */ 
     2009        /* apr_signal(AP_SIG_GRACEFUL, restart); */ 
     2010        child_main(slot); 
     2011        clean_child_exit(0); 
     2012    } 
     2013 
     2014    ap_scoreboard_image->parent[slot].pid = pid; 
     2015    CHILD_INFO_TABLE[slot].pid    = pid; 
     2016 
     2017    ap_child_table[slot].pid    = pid; 
     2018    ap_child_table[slot].status = SERVER_ALIVE; 
     2019 
     2020    return 0; 
     2021} 
     2022 
     2023 
     2024/* 
     2025 * idle_spawn_rate is the number of children that will be spawned on the 
     2026 * next maintenance cycle if there aren't enough idle servers.  It is 
     2027 * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by 
     2028 * without the need to spawn. 
     2029 */ 
     2030static int idle_spawn_rate = 1; 
     2031#ifndef MAX_SPAWN_RATE 
     2032#define MAX_SPAWN_RATE  (32) 
     2033#endif 
     2034static int total_processes(int child_num) 
     2035{ 
     2036    int i, total; 
     2037    for(i = 0, total = 0; i < NUM_CHILDS; ++i) 
     2038    { 
     2039        if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv && 
     2040           (!(CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR && 
     2041           CHILD_INFO_TABLE[i].status == CHILD_STATUS_STANDBY))) 
     2042        { 
     2043           total++; 
     2044        } 
     2045    } 
     2046    return total; 
     2047} 
     2048 
     2049static void perform_idle_server_maintenance(apr_pool_t *p) 
     2050{ 
     2051    int i; 
     2052    apr_time_t now; 
     2053 
     2054    /* _DBG("function entered", 0); */ 
     2055 
     2056    now = apr_time_now(); 
     2057 
     2058    for (i = 0; i < NUM_CHILDS; ++i) 
     2059    { 
     2060      if(CHILD_INFO_TABLE[i].pid == 0) 
     2061      { 
     2062        if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) 
     2063          make_child(ap_server_conf, i); 
     2064      } 
     2065      else if(((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||  
     2066               CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER)  && 
     2067               ap_scoreboard_image->parent[i].pid > 1) && 
     2068               (idle_processors (i) > 1 || total_processes (i) == 1) && ( 
     2069                   (expire_timeout > 0 &&  ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&  
     2070                   apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) || 
     2071                   (idle_timeout >   0 &&  ap_scoreboard_image->servers[i][0].status == SERVER_READY &&   
     2072                   apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout))) 
     2073      { 
     2074        CHILD_INFO_TABLE[i].pid = 0; 
     2075        CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY; 
     2076 
     2077        if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) 
     2078        { 
     2079          /* completely free up this slot */ 
     2080 
     2081          CHILD_INFO_TABLE[i].senv    = (server_env_t*)NULL; 
     2082          CHILD_INFO_TABLE[i].type    = CHILD_TYPE_UNKNOWN; 
     2083          CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */ 
     2084        } 
     2085        if(kill(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1) 
     2086        { 
     2087          ap_log_error(APLOG_MARK, APLOG_WARNING, errno, 
     2088            ap_server_conf, "kill SIGTERM"); 
     2089        } 
     2090        
     2091 
     2092        ap_update_child_status_from_indexes(i, 0, SERVER_DEAD, NULL); 
     2093      } 
     2094    } 
     2095     
     2096    for(i=0;i<grace_children;i++) { 
     2097       if (child_grace_info_table[i].pid > 0 && expire_timeout > 0 && 
     2098                       apr_time_sec(now - child_grace_info_table[i].last_used) > expire_timeout) { 
     2099                
     2100               _DBG("Killing a child from last graceful (pid=%d,childno=%d,last_used=%d)",  
     2101                               child_grace_info_table[i].pid, child_grace_info_table[i].id, 
     2102                               child_grace_info_table[i].last_used); 
     2103             
     2104               if(kill(child_grace_info_table[i].pid, SIGTERM) == -1) 
     2105            { 
     2106              ap_log_error(APLOG_MARK, APLOG_WARNING, errno, 
     2107                ap_server_conf, "kill SIGTERM"); 
     2108            } 
     2109                
     2110               /*      We don't need to do remove_grace_child() here, 
     2111                *  because it will be automatically done once  
     2112                *  the child dies by ap_mpm_run() */ 
     2113       } 
     2114    } 
     2115} 
     2116 
     2117int remove_grace_child(int slot) { 
     2118       if (slot < grace_children) { 
     2119               child_grace_info_table[slot].id = 0; 
     2120               child_grace_info_table[slot].pid = 0; 
     2121               child_grace_info_table[slot].status = CHILD_STATUS_STANDBY; 
     2122               child_grace_info_table[slot].type = CHILD_TYPE_UNKNOWN; 
     2123               child_grace_info_table[slot].last_used = 0; 
     2124               grace_children_alive--; 
     2125                
     2126               if (grace_children_alive <= 0) { /*     All children have returned from graceful        */ 
     2127                       _DBG("Every child has returned from graceful restart - freeing child_grace_info_table"); 
     2128                       grace_children_alive = 0; 
     2129                       is_graceful = 0; 
     2130                       grace_children = 0; 
     2131                       free(child_grace_info_table); 
     2132               } 
     2133               return 0; 
     2134       } 
     2135       return 1; 
     2136} 
     2137 
     2138/***************************************************************** 
     2139 * Executive routines. 
     2140 */ 
     2141 
     2142int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) 
     2143{ 
     2144    int i; 
     2145/*    int fd; */ 
     2146    apr_status_t rv; 
     2147    apr_size_t one = 1; 
     2148/*    apr_socket_t *sock = NULL; */ 
     2149 
     2150    ap_log_pid(pconf, ap_pid_fname); 
     2151 
     2152    first_server_limit = server_limit; 
     2153    if (changed_limit_at_restart) { 
     2154        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, 
     2155                     "WARNING: Attempt to change ServerLimit " 
     2156                     "ignored during restart"); 
     2157        changed_limit_at_restart = 0; 
     2158    } 
     2159 
     2160    ap_server_conf = s; 
     2161 
     2162    /* Initialize cross-process accept lock */ 
     2163    ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, 
     2164                                 ap_server_root_relative(_pconf, ap_lock_fname), 
     2165                                 ap_my_pid); 
     2166 
     2167    rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,  
     2168                               ap_accept_lock_mech, _pconf); 
     2169    if (rv != APR_SUCCESS) { 
     2170        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 
     2171                     "Couldn't create accept lock"); 
     2172        mpm_state = AP_MPMQ_STOPPING; 
     2173        return 1; 
     2174    } 
     2175 
     2176#if 0 
     2177#if APR_USE_SYSVSEM_SERIALIZE 
     2178    if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||  
     2179        ap_accept_lock_mech == APR_LOCK_SYSVSEM) { 
     2180#else 
     2181    if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) { 
     2182#endif 
     2183        rv = unixd_set_proc_mutex_perms(accept_mutex); 
     2184        if (rv != APR_SUCCESS) { 
     2185            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 
     2186                         "Couldn't set permissions on cross-process lock; " 
     2187                         "check User and Group directives"); 
     2188            mpm_state = AP_MPMQ_STOPPING; 
     2189            return 1; 
     2190        } 
     2191    } 
     2192#endif 
     2193 
     2194    if (!is_graceful) { 
     2195        if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { 
     2196            mpm_state = AP_MPMQ_STOPPING; 
     2197            return 1; 
     2198        } 
     2199        /* fix the generation number in the global score; we just got a new, 
     2200         * cleared scoreboard 
     2201         */ 
     2202        ap_scoreboard_image->global->running_generation = ap_my_generation; 
     2203    } 
     2204 
     2205    /* Initialize the child table */ 
     2206    if (!is_graceful) 
     2207    { 
     2208        for (i = 0; i < server_limit; i++) 
     2209        { 
     2210            ap_child_table[i].pid = 0; 
     2211        } 
     2212    } 
     2213 
     2214    /* We need to put the new listeners at the end of the ap_listeners 
     2215     * list.  If we don't, then the pool will be cleared before the 
     2216     * open_logs phase is called for the second time, and ap_listeners 
     2217     * will have only invalid data.  If that happens, then the sockets 
     2218     * that we opened using make_sock() will be lost, and the server 
     2219     * won't start. 
     2220     */ 
     2221 
     2222/* 
     2223    apr_os_file_get(&fd, pipe_of_death_in); 
     2224    apr_os_sock_put(&sock, &fd, pconf); 
     2225 
     2226    listen_add(pconf, sock, check_pipe_of_death); 
     2227*/ 
     2228    set_signals(); 
     2229 
     2230    if (one_process) { 
     2231        AP_MONCONTROL(1); 
     2232    } 
     2233 
     2234    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2235                "%s configured -- resuming normal operations", 
     2236                ap_get_server_version()); 
     2237    ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, 
     2238                "Server built: %s", ap_get_server_built()); 
     2239#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH 
     2240    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     2241                "AcceptMutex: %s (default: %s)", 
     2242                apr_proc_mutex_name(accept_mutex), 
     2243                apr_proc_mutex_defname()); 
     2244#endif 
     2245    restart_pending = shutdown_pending = 0; 
     2246 
     2247    mpm_state = AP_MPMQ_RUNNING; 
     2248 
     2249    _DBG("sizeof(child_info_t) = %d", sizeof(child_info_t)); 
     2250 
     2251    while (!restart_pending && !shutdown_pending) { 
     2252        int child_slot; 
     2253        apr_exit_why_e exitwhy; 
     2254        int status, processed_status; 
     2255        /* this is a memory leak, but I'll fix it later. */ 
     2256        apr_proc_t pid; 
     2257 
     2258        ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); 
     2259 
     2260        /* XXX: if it takes longer than 1 second for all our children 
     2261         * to start up and get into IDLE state then we may spawn an 
     2262         * extra child 
     2263         */ 
     2264        if (pid.pid != -1) { 
     2265            processed_status = ap_process_child_status(&pid, exitwhy, status); 
     2266            if (processed_status == APEXIT_CHILDFATAL) { 
     2267                mpm_state = AP_MPMQ_STOPPING; 
     2268                return 1; 
     2269            } 
     2270             
     2271            if (grace_children > 0) { 
     2272               for(i=0;i<grace_children;i++) { 
     2273                       if (child_grace_info_table[i].pid == pid.pid) { 
     2274                               break; 
     2275                       } 
     2276               } 
     2277               if (i != grace_children) { 
     2278                       _DBG("Child returned from graceful (%d)", i); 
     2279                       remove_grace_child(i); 
     2280                       continue; 
     2281               } 
     2282            } 
     2283 
     2284            /* non-fatal death... note that it's gone in the scoreboard. */ 
     2285            child_slot = find_child_by_pid(&pid); 
     2286            _DBG("child #%d has died ...", child_slot); 
     2287 
     2288            for (i = 0; i < ap_max_daemons_limit; ++i) 
     2289            { 
     2290                if (ap_child_table[i].pid == pid.pid) 
     2291                { 
     2292                    child_slot = i; 
     2293                    break; 
     2294                } 
     2295            } 
     2296 
     2297            if (child_slot >= 0) { 
     2298                ap_child_table[child_slot].pid = 0; 
     2299                _TRACE_CALL("ap_update_child_status_from_indexes", 0); 
     2300                (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD, 
     2301                                                           (request_rec *) NULL); 
     2302                _TRACE_RET("ap_update_child_status_from_indexes", 0); 
     2303 
     2304                if (processed_status == APEXIT_CHILDSICK) { 
     2305                    /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc) 
     2306                     * cut the fork rate to the minimum  
     2307                     */ 
     2308                    _DBG("processed_status = APEXIT_CHILDSICK", 0); 
     2309                    idle_spawn_rate = 1;  
     2310                } 
     2311                else if (CHILD_INFO_TABLE[child_slot].status == CHILD_STATUS_STANDBY) { 
     2312                    _DBG("leaving child in standby state", 0); 
     2313                } 
     2314                else if (child_slot < ap_daemons_limit && 
     2315                         CHILD_INFO_TABLE[child_slot].type != 
     2316                           CHILD_TYPE_UNKNOWN) { 
     2317                    /* we're still doing a 1-for-1 replacement of dead 
     2318                        * children with new children 
     2319                        */ 
     2320                    _DBG("replacing by new child ...", 0); 
     2321                    make_child(ap_server_conf, child_slot); 
     2322                } 
     2323#if APR_HAS_OTHER_CHILD 
     2324            } 
     2325            else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) { 
     2326                _DBG("Already handled", 0); 
     2327                /* handled */ 
     2328#endif 
     2329            } 
     2330            else if (is_graceful) { 
     2331                /* Great, we've probably just lost a slot in the 
     2332                    * scoreboard.  Somehow we don't know about this 
     2333                    * child. 
     2334                    */ 
     2335                _DBG("long lost child came home, whatever that means", 0); 
     2336 
     2337                ap_log_error(APLOG_MARK, APLOG_WARNING,  
     2338                            0, ap_server_conf, 
     2339                            "long lost child came home! (pid %ld)", (long)pid.pid); 
     2340            } 
     2341            /* Don't perform idle maintenance when a child dies, 
     2342                * only do it when there's a timeout.  Remember only a 
     2343                * finite number of children can die, and it's pretty 
     2344                * pathological for a lot to die suddenly. 
     2345                */ 
     2346            continue; 
     2347        } 
     2348 
     2349        perform_idle_server_maintenance(pconf); 
     2350#ifdef TPF 
     2351        shutdown_pending = os_check_server(tpf_server_name); 
     2352        ap_check_signals(); 
     2353        sleep(1); 
     2354#endif /*TPF */ 
     2355    } 
     2356 
     2357    mpm_state = AP_MPMQ_STOPPING; 
     2358 
     2359    if (shutdown_pending) { 
     2360        /* Time to gracefully shut down: 
     2361         * Kill child processes, tell them to call child_exit, etc... 
     2362         */ 
     2363        if (unixd_killpg(getpgrp(), SIGTERM) < 0) { 
     2364            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); 
     2365        } 
     2366        ap_reclaim_child_processes(1);          /* Start with SIGTERM */ 
     2367 
     2368        /* cleanup pid file on normal shutdown */ 
     2369        { 
     2370            const char *pidfile = NULL; 
     2371            pidfile = ap_server_root_relative (pconf, ap_pid_fname); 
     2372            if ( pidfile != NULL && unlink(pidfile) == 0) 
     2373                ap_log_error(APLOG_MARK, APLOG_INFO, 
     2374                                0, ap_server_conf, 
     2375                                "removed PID file %s (pid=%ld)", 
     2376                                pidfile, (long)getpid()); 
     2377        } 
     2378 
     2379        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2380                    "caught SIGTERM, shutting down"); 
     2381        return 1; 
     2382    } 
     2383 
     2384    /* we've been told to restart */ 
     2385    apr_signal(SIGHUP, SIG_IGN); 
     2386    if (one_process) { 
     2387        /* not worth thinking about */ 
     2388        return 1; 
     2389    } 
     2390 
     2391    /* advance to the next generation */ 
     2392    /* XXX: we really need to make sure this new generation number isn't in 
     2393     * use by any of the children. 
     2394     */ 
     2395    ++ap_my_generation; 
     2396    ap_scoreboard_image->global->running_generation = ap_my_generation; 
     2397     
     2398    if (is_graceful) { 
     2399        char char_of_death = AP_PERUSER_CHAR_OF_DEATH; 
     2400 
     2401        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2402                    "Graceful restart requested, doing restart"); 
     2403 
     2404#if 0 
     2405        /* kill off the idle ones */ 
     2406        ap_mpm_pod_killpg(pod, ap_max_daemons_limit); 
     2407 
     2408        /* This is mostly for debugging... so that we know what is still 
     2409            * gracefully dealing with existing request.  This will break 
     2410            * in a very nasty way if we ever have the scoreboard totally 
     2411            * file-based (no shared memory) 
     2412            */ 
     2413        for (i = 0; i < ap_daemons_limit; ++i) { 
     2414            if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { 
     2415                ap_scoreboard_image->servers[i][0].status = SERVER_GRACEFUL; 
     2416            } 
     2417        } 
     2418#endif 
     2419 
     2420        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, 
     2421                     ap_server_conf, AP_SIG_GRACEFUL_STRING " received.  " 
     2422                     "Doing graceful restart"); 
     2423 
     2424        /* This is mostly for debugging... so that we know what is still 
     2425         * gracefully dealing with existing request. 
     2426         */ 
     2427 
     2428        int alivechildren = 0; 
     2429        child_grace_info_t* old_grace_info; 
     2430 
     2431        for (i = 0; i < NUM_CHILDS; ++i) 
     2432        { 
     2433            ((ap_child_table[i].pid) && (ap_child_table[i].status = SERVER_DYING)); 
     2434             
     2435            if (CHILD_INFO_TABLE[i].pid) { 
     2436               alivechildren++; 
     2437            } 
     2438        } 
     2439         
     2440        _DBG("Initializing child_grace_info_table", 0); 
     2441         
     2442        if (alivechildren > 0) { 
     2443               if (grace_children > 0) { 
     2444                       old_grace_info = child_grace_info_table; 
     2445                       _DBG("%d children still living from last graceful " 
     2446                                       "- adding to new child_grace_info_table",  
     2447                                       grace_children); 
     2448               } 
     2449                
     2450               child_grace_info_table = (child_grace_info_t*)calloc(alivechildren+grace_children, 
     2451                               sizeof(child_grace_info_t)); 
     2452                
     2453               if (grace_children > 0) { 
     2454                       for(i=0;i<grace_children;i++) { 
     2455                               child_grace_info_table[i] = old_grace_info[i]; 
     2456                       } 
     2457                       grace_children = i; 
     2458                       free(old_grace_info); 
     2459               } 
     2460               else grace_children = 0; 
     2461                
     2462        } 
     2463 
     2464        /* give the children the signal to die */ 
     2465        for (i = 0; i < NUM_CHILDS;) 
     2466        { 
     2467            if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) 
     2468            { 
     2469                if (APR_STATUS_IS_EINTR(rv)) continue; 
     2470                ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, 
     2471                             "write pipe_of_death"); 
     2472            } 
     2473            if (CHILD_INFO_TABLE[i].pid) { 
     2474               child_grace_info_table[grace_children].id               = CHILD_INFO_TABLE[i].id; 
     2475               child_grace_info_table[grace_children].pid              = CHILD_INFO_TABLE[i].pid; 
     2476               child_grace_info_table[grace_children].status   = CHILD_INFO_TABLE[i].status; 
     2477               child_grace_info_table[grace_children].type     = CHILD_INFO_TABLE[i].type; 
     2478               child_grace_info_table[grace_children].last_used= ap_scoreboard_image->servers[i][0].last_used; 
     2479               grace_children++; 
     2480               grace_children_alive++; 
     2481            } 
     2482            i++; 
     2483        } 
     2484        _DBG("Total children of %d leaving behind for graceful restart (%d living)",  
     2485                       grace_children, grace_children_alive); 
     2486 
     2487       /* destroy server_env_image */ 
     2488        for (i = 0; i < NUM_SENV; i++) 
     2489        { 
     2490            close(SENV[i].input); 
     2491            close(SENV[i].output); 
     2492        } 
     2493       cleanup_server_environments(NULL); 
     2494    } 
     2495    else { 
     2496        /* Kill 'em off */ 
     2497        if (unixd_killpg(getpgrp(), SIGHUP) < 0) { 
     2498            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP"); 
     2499        } 
     2500        ap_reclaim_child_processes(0);          /* Not when just starting up */ 
     2501        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2502                    "SIGHUP received.  Attempting to restart"); 
     2503    } 
     2504 
     2505    return 0; 
     2506} 
     2507 
     2508/* == allocate an private server config structure == */ 
     2509static void *peruser_create_config(apr_pool_t *p, server_rec *s) 
     2510{ 
     2511    peruser_server_conf *c = (peruser_server_conf *) 
     2512                                  apr_pcalloc(p, sizeof(peruser_server_conf)); 
     2513    return c; 
     2514} 
     2515 
     2516/* This really should be a post_config hook, but the error log is already 
     2517 * redirected by that point, so we need to do this in the open_logs phase. 
     2518 */ 
     2519static int peruser_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) 
     2520{ 
     2521    apr_status_t rv; 
     2522 
     2523    pconf = p; 
     2524    ap_server_conf = s; 
     2525 
     2526    if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { 
     2527        ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,  
     2528                     NULL, "no listening sockets available, shutting down"); 
     2529        return DONE; 
     2530    } 
     2531 
     2532    ap_log_pid(pconf, ap_pid_fname); 
     2533 
     2534    if ((rv = ap_mpm_pod_open(pconf, &pod))) { 
     2535        ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, 
     2536                "Could not open pipe-of-death."); 
     2537        return DONE; 
     2538    } 
     2539 
     2540    if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, 
     2541                                   pconf)) != APR_SUCCESS) { 
     2542        ap_log_error(APLOG_MARK, APLOG_ERR, rv, 
     2543                     (const server_rec*) ap_server_conf, 
     2544                     "apr_file_pipe_create (pipe_of_death)"); 
     2545        exit(1); 
     2546    } 
     2547    if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) { 
     2548        ap_log_error(APLOG_MARK, APLOG_ERR, rv, 
     2549                     (const server_rec*) ap_server_conf, 
     2550                     "apr_file_pipe_timeout_set (pipe_of_death)"); 
     2551        exit(1); 
     2552    } 
     2553 
     2554    return OK; 
     2555} 
     2556 
     2557static int restart_num = 0; 
     2558static int peruser_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) 
     2559{ 
     2560    int no_detach, debug, foreground, i; 
     2561    int tmp_server_limit = DEFAULT_SERVER_LIMIT; 
     2562    ap_directive_t *pdir; 
     2563    apr_status_t rv; 
     2564    apr_pool_t *global_pool; 
     2565    void *shmem; 
     2566 
     2567    mpm_state = AP_MPMQ_STARTING; 
     2568 
     2569    debug = ap_exists_config_define("DEBUG"); 
     2570 
     2571    if (debug) { 
     2572        foreground = one_process = 1; 
     2573        no_detach = 0; 
     2574    } 
     2575    else 
     2576    { 
     2577        no_detach = ap_exists_config_define("NO_DETACH"); 
     2578        one_process = ap_exists_config_define("ONE_PROCESS"); 
     2579        foreground = ap_exists_config_define("FOREGROUND"); 
     2580    } 
     2581 
     2582    /* sigh, want this only the second time around */ 
     2583    if (restart_num++ == 1) { 
     2584        if (!one_process && !foreground) { 
     2585            rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND 
     2586                                           : APR_PROC_DETACH_DAEMONIZE); 
     2587            if (rv != APR_SUCCESS) { 
     2588                ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     2589                             "apr_proc_detach failed"); 
     2590                return HTTP_INTERNAL_SERVER_ERROR; 
     2591            } 
     2592        } 
     2593 
     2594        parent_pid = ap_my_pid = getpid(); 
     2595    } 
     2596 
     2597    unixd_pre_config(ptemp); 
     2598    ap_listen_pre_config(); 
     2599    ap_min_processors = DEFAULT_MIN_PROCESSORS; 
     2600    ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS; 
     2601    ap_max_processors = DEFAULT_MAX_PROCESSORS; 
     2602    ap_daemons_limit = server_limit; 
     2603    ap_pid_fname = DEFAULT_PIDLOG; 
     2604    ap_lock_fname = DEFAULT_LOCKFILE; 
     2605    ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; 
     2606    ap_extended_status = 1; 
     2607#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE 
     2608        ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; 
     2609#endif 
     2610 
     2611    apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); 
     2612 
     2613    /* we need to know ServerLimit and ThreadLimit before we start processing 
     2614     * the tree because we need to already have allocated child_info_table 
     2615     */ 
     2616    for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) 
     2617    { 
     2618        if (!strcasecmp(pdir->directive, "ServerLimit")) 
     2619        { 
     2620            if (atoi(pdir->args) > tmp_server_limit) 
     2621            { 
     2622                tmp_server_limit = atoi(pdir->args); 
     2623                if (tmp_server_limit > MAX_SERVER_LIMIT) 
     2624                { 
     2625                    tmp_server_limit = MAX_SERVER_LIMIT; 
     2626                } 
     2627            } 
     2628        } 
     2629    } 
     2630 
     2631    /* We don't want to have to recreate the scoreboard after 
     2632     * restarts, so we'll create a global pool and never clean it. 
     2633     */ 
     2634    rv = apr_pool_create(&global_pool, NULL); 
     2635    if (rv != APR_SUCCESS) { 
     2636        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     2637                     "Fatal error: unable to create global pool"); 
     2638        return rv; 
     2639    } 
     2640 
     2641 
     2642    _DBG("Initializing child_info_table", 0); 
     2643    child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t); 
     2644 
     2645    rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool); 
     2646 
     2647/*  if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */ 
     2648    if (rv != APR_SUCCESS) { 
     2649        _DBG("shared memory creation failed", 0); 
     2650 
     2651        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     2652                     "Unable to create shared memory segment " 
     2653                     "(anonymous shared memory failure)"); 
     2654    } 
     2655    else if (rv == APR_ENOTIMPL) { 
     2656        _DBG("anonymous shared memory not available", 0); 
     2657        /* TODO: make up a filename and do name-based shmem */ 
     2658    } 
     2659 
     2660    if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) { 
     2661        _DBG("apr_shm_baseaddr_get() failed", 0); 
     2662        return HTTP_INTERNAL_SERVER_ERROR; 
     2663    } 
     2664 
     2665    memset(shmem, 0, sizeof(child_info_size)); 
     2666    child_info_image = (child_info*)calloc(1, sizeof(child_info_size)); 
     2667    child_info_image->control = (child_info_control*)shmem; 
     2668    shmem += sizeof(child_info_control*); 
     2669    child_info_image->table = (child_info_t*)shmem; 
     2670 
     2671    child_info_image->control->num = 0; 
     2672 
     2673    for (i = 0; i < tmp_server_limit; i++) 
     2674    { 
     2675        CHILD_INFO_TABLE[i].pid     = 0; 
     2676        CHILD_INFO_TABLE[i].senv    = (server_env_t*)NULL; 
     2677        CHILD_INFO_TABLE[i].type    = CHILD_TYPE_UNKNOWN; 
     2678        CHILD_INFO_TABLE[i].status  = CHILD_STATUS_STANDBY; 
     2679        CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */ 
     2680        CHILD_INFO_TABLE[i].id      = i; 
     2681    } 
     2682 
     2683    if (!server_env_image) 
     2684    { 
     2685       _DBG("Initializing server_environments_table", 0); 
     2686       server_env_size = tmp_server_limit * sizeof(server_env_t) + sizeof(apr_size_t); 
     2687 
     2688       rv = apr_shm_create(&server_env_shm, server_env_size, NULL, global_pool); 
     2689 
     2690       if (rv != APR_SUCCESS) { 
     2691           _DBG("shared memory creation failed", 0); 
     2692 
     2693           ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     2694                        "Unable to create shared memory segment " 
     2695                        "(anonymous shared memory failure)"); 
     2696        } 
     2697        else if (rv == APR_ENOTIMPL) { 
     2698            _DBG("anonymous shared memory not available", 0); 
     2699            /* TODO: make up a filename and do name-based shmem */ 
     2700        } 
     2701 
     2702        if (rv || !(shmem = apr_shm_baseaddr_get(server_env_shm))) { 
     2703            _DBG("apr_shm_baseaddr_get() failed", 0); 
     2704            return HTTP_INTERNAL_SERVER_ERROR; 
     2705        } 
     2706 
     2707        memset(shmem, 0, sizeof(server_env_size)); 
     2708        server_env_image = (server_env*)calloc(1, sizeof(server_env_size)); 
     2709        server_env_image->control = (server_env_control*)shmem; 
     2710        shmem += sizeof(server_env_control*); 
     2711        server_env_image->table = (server_env_t*)shmem; 
     2712 
     2713        server_env_image->control->num = 0; 
     2714 
     2715        for (i = 0; i < tmp_server_limit; i++) 
     2716        { 
     2717            SENV[i].processor_id = -1; 
     2718            SENV[i].uid          = -1; 
     2719            SENV[i].gid          = -1; 
     2720            SENV[i].chroot       = NULL; 
     2721            SENV[i].input        = -1; 
     2722            SENV[i].output       = -1; 
     2723        } 
     2724    } 
     2725 
     2726    return OK; 
     2727} 
     2728 
     2729static int peruser_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server_list) 
     2730{ 
     2731    ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable)); 
     2732 
     2733    return OK; 
     2734} 
     2735 
     2736static int peruser_post_read(request_rec *r) 
     2737{ 
     2738    peruser_server_conf *sconf = PERUSER_SERVER_CONF(r->server->module_config); 
     2739    child_info_t *processor; 
     2740 
     2741    if(CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) 
     2742        processor = &CHILD_INFO_TABLE[sconf->senv->processor_id]; 
     2743    else 
     2744        processor = &CHILD_INFO_TABLE[r->connection->id]; 
     2745 
     2746 
     2747    if (!strlen(r->the_request)) 
     2748    { 
     2749        _DBG("corrupt request. aborting",0); 
     2750        return DECLINED; 
     2751    } 
     2752 
     2753    if (processor->sock_fd != AP_PERUSER_THISCHILD) 
     2754    { 
     2755        apr_socket_t *sock = NULL; 
     2756 
     2757        apr_os_sock_put(&sock, &processor->sock_fd, r->connection->pool); 
     2758        ap_sock_disable_nagle(sock); 
     2759        ap_set_module_config(r->connection->conn_config, &core_module, sock); 
     2760        _DBG("not the right socket?", 0); 
     2761        return OK; 
     2762    } 
     2763 
     2764    switch (CHILD_INFO_TABLE[my_child_num].type) 
     2765    { 
     2766        case CHILD_TYPE_MULTIPLEXER: 
     2767        { 
     2768            _DBG("MULTIPLEXER => Determining if request should be passed. " 
     2769                 "Child Num: %d, dest-child: %d, hostname from server: %s r->hostname=%s r->the_request=\"%s\"", 
     2770                my_child_num, processor->id, r->server->server_hostname, r->hostname, r->the_request); 
     2771 
     2772            if (processor->id != my_child_num) 
     2773            { 
     2774                if (processor->status == CHILD_STATUS_STANDBY) 
     2775                { 
     2776                    _DBG("Activating child #%d", processor->id); 
     2777                    processor->status = CHILD_STATUS_STARTING; 
     2778                } 
     2779 
     2780                _DBG("Passing request.",0); 
     2781                if (pass_request(r, processor) == -1) 
     2782                { 
     2783                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, 
     2784                             ap_server_conf, "Could not pass request to proper "                             "child, request will not be honoured."); 
     2785                    return DECLINED; 
     2786                } 
     2787                _DBG("doing longjmp",0); 
     2788                longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1); 
     2789                _DBG("request declined at our site",0); 
     2790                return DECLINED; 
     2791                _DBG("OUH! we should never reach this point",0); 
     2792            } 
     2793            _DBG("WTF: the server is assigned to the multiplexer! ... dropping request",0); 
     2794            return DECLINED; 
     2795        } 
     2796        case CHILD_TYPE_PROCESSOR: 
     2797        case CHILD_TYPE_WORKER: 
     2798        { 
     2799               if (sconf->senv != CHILD_INFO_TABLE[my_child_num].senv) { 
     2800                       ap_log_error(APLOG_MARK, APLOG_WARNING,  
     2801                                    0, ap_server_conf, 
     2802                                   "invalid virtualhost for this child! (%s)", r->hostname); 
     2803                       ap_lingering_close(r->connection); 
     2804                       return HTTP_REQUEST_TIME_OUT; 
     2805               } 
     2806                
     2807            _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num); 
     2808            _DBG("request for %s / (server %s) seems to be for us", r->hostname, r->server->server_hostname); 
     2809 
     2810            if (server_env_cleanup) 
     2811            { 
     2812                int i; 
     2813                int input = sconf->senv->input; 
     2814                int output = sconf->senv->output; 
     2815 
     2816                _DBG("performing handle cleanup"); 
     2817                for (i = 0; i < NUM_SENV; i++) 
     2818                { 
     2819                    if (SENV[i].input > 0 && SENV[i].input != input) { 
     2820                        int retval = close(SENV[i].input); 
     2821                        if (retval < 0) { 
     2822                            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
     2823                                         "close(%d) failed", SENV[i].input); 
     2824                        } 
     2825                    } 
     2826                    if (SENV[i].output > 0 && SENV[i].output != output) { 
     2827                        int retval = close(SENV[i].output); 
     2828                        if (retval < 0) { 
     2829                            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
     2830                                         "close(%d) failed", SENV[i].output); 
     2831                        } 
     2832                    } 
     2833                } 
     2834                server_env_cleanup = 0; 
     2835            } 
     2836 
     2837            return OK; 
     2838        } 
     2839        default: 
     2840        { 
     2841            _DBG("unspecified child type %d in %d, dropping request", 
     2842                 CHILD_INFO_TABLE[my_child_num].type, my_child_num); 
     2843            return DECLINED; 
     2844        } 
     2845    } 
     2846 
     2847    _DBG("THIS POINT SHOULD NOT BE REACHED!",0); 
     2848    return OK; 
     2849} 
     2850 
     2851static int peruser_status_hook(request_rec *r, int flags) 
     2852{ 
     2853    int x; 
     2854    server_env_t *senv; 
     2855 
     2856    if (flags & AP_STATUS_SHORT) 
     2857           return OK; 
     2858     
     2859    ap_rputs("<hr>\n", r); 
     2860    ap_rputs("<h2>peruser status</h2>\n", r); 
     2861    ap_rputs("<table border=\"0\">\n", r); 
     2862    ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td><td>UID</td>" 
     2863                   "<td>GID</td><td>CHROOT</td><td>INPUT</td>" 
     2864                   "<td>OUTPUT</td><td>SOCK_FD</td>" 
     2865                   "<td>TOTAL PROCESSORS</td><td>MAX PROCESSORS</td>" 
     2866                   "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td></tr>\n", r); 
     2867    for (x = 0; x < NUM_CHILDS; x++) 
     2868        { 
     2869        senv = CHILD_INFO_TABLE[x].senv; 
     2870        ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td>" 
     2871                       "<td>%4d</td><td>%4d</td><td>%25s</td><td>%5d</td>" 
     2872                       "<td>%6d</td><td>%7d</td><td>%d</td><td>%d</td>" 
     2873                       "<td>%d</td><td>%d</td></tr>\n",  
     2874                       CHILD_INFO_TABLE[x].id,  
     2875                       CHILD_INFO_TABLE[x].pid,  
     2876                       child_status_string(CHILD_INFO_TABLE[x].status),  
     2877                       child_type_string(CHILD_INFO_TABLE[x].type),  
     2878                       senv == NULL ? -1 : senv->uid,  
     2879                       senv == NULL ? -1 : senv->gid,  
     2880                       senv == NULL ? NULL : senv->chroot,  
     2881                       senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input,  
     2882                       senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output,  
     2883                       CHILD_INFO_TABLE[x].sock_fd, 
     2884                       total_processors(x),  
     2885                       senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->max_processors, 
     2886                       idle_processors(x), 
     2887                       senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors 
     2888                       ); 
     2889       } 
     2890    ap_rputs("</table>\n", r); 
     2891     
     2892    if (grace_children > 0) { 
     2893       ap_rputs("<h2>peruser graceful children status</h2>\n", r); 
     2894       ap_rprintf(r, "%d of total %d still living<br />\n", grace_children_alive, grace_children); 
     2895        ap_rputs("<table border=\"0\">\n", r); 
     2896        ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td></tr>\n", r); 
     2897        for (x = 0; x < grace_children; x++) { 
     2898            ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td></tr>\n",  
     2899                           child_grace_info_table[x].id,  
     2900                           child_grace_info_table[x].pid,  
     2901                           child_status_string(child_grace_info_table[x].status),  
     2902                           child_type_string(child_grace_info_table[x].type) 
     2903                           ); 
     2904        } 
     2905        ap_rputs("</table>\n", r); 
     2906    } 
     2907    return OK; 
     2908} 
     2909 
     2910static void peruser_hooks(apr_pool_t *p) 
     2911{ 
     2912    /* The peruser open_logs phase must run before the core's, or stderr 
     2913     * will be redirected to a file, and the messages won't print to the 
     2914     * console. 
     2915     */ 
     2916    static const char *const aszSucc[] = {"core.c", NULL}; 
     2917 
     2918#ifdef AUX3 
     2919    (void) set42sig(); 
     2920#endif 
     2921 
     2922    ap_hook_open_logs(peruser_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); 
     2923    ap_hook_pre_config(peruser_pre_config, NULL, NULL, APR_HOOK_MIDDLE); 
     2924    ap_hook_post_config(peruser_post_config, NULL, NULL, APR_HOOK_MIDDLE); 
     2925 
     2926    /* Both of these must be run absolutely first.  If this request isn't for 
     2927     * this server then we need to forward it to the proper child.  No sense 
     2928     * tying up this server running more post_read request hooks if it is 
     2929     * just going to be forwarded along.  The process_connection hook allows 
     2930     * peruser to receive the passed request correctly, by automatically 
     2931     * filling in the core_input_filter's ctx pointer. 
     2932     */ 
     2933    ap_hook_post_read_request(peruser_post_read, NULL, NULL, 
     2934                              APR_HOOK_REALLY_FIRST); 
     2935    ap_hook_process_connection(peruser_process_connection, NULL, NULL, 
     2936                               APR_HOOK_REALLY_FIRST); 
     2937 
     2938    APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE); 
     2939} 
     2940 
     2941/* we define an Processor w/ specific uid/gid */ 
     2942static const char *cf_Processor(cmd_parms *cmd, void *dummy, 
     2943    const char *user_name, const char *group_name, const char *chroot) 
     2944{ 
     2945    uid_t uid = ap_uname2id(user_name); 
     2946    gid_t gid = ap_gname2id(group_name); 
     2947 
     2948    _DBG("user=%s:%d group=%s:%d chroot=%s", 
     2949        user_name, uid, group_name, gid, chroot); 
     2950 
     2951    return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, 
     2952                     cmd->pool, uid, gid, chroot); 
     2953} 
     2954 
     2955/* we define an Multiplexer child w/ specific uid/gid */ 
     2956static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy, 
     2957    const char *user_name, const char *group_name, const char *chroot) 
     2958{ 
     2959    uid_t uid = ap_uname2id(user_name); 
     2960    gid_t gid = ap_gname2id(group_name); 
     2961 
     2962    _DBG("user=%s:%d group=%s:%d chroot=%s [multiplexer id %d]", 
     2963        user_name, uid, group_name, gid, chroot, NUM_CHILDS); 
     2964 
     2965    return child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING, 
     2966                     cmd->pool, uid, gid, chroot); 
     2967} 
     2968 
     2969static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy, 
     29