PeruserAttachments: httpd-2.2.13-peruser-0.4.0b1.patch

File httpd-2.2.13-peruser-0.4.0b1.patch, 143.3 KB (added by TaaviSannik, 3 years ago)

Peruser MPM 0.4.0 first beta release

  • modules/ssl/mod_ssl.h

    diff -Nur httpd-2.2.13/modules/ssl/mod_ssl.h httpd-2.2.13-peruser/modules/ssl/mod_ssl.h
    old new  
    5050 * is using SSL/TLS. */ 
    5151APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); 
    5252 
     53/** An optional function which returns non-zero if the given server 
     54 * is using SSL/TLS. */ 
     55APR_DECLARE_OPTIONAL_FN(int, ssl_server_is_https, (server_rec *)); 
     56 
    5357/** The ssl_proxy_enable() and ssl_engine_disable() optional functions 
    5458 * are used by mod_proxy to enable use of SSL for outgoing 
    5559 * connections. */ 
  • modules/ssl/ssl_engine_vars.c

    diff -Nur httpd-2.2.13/modules/ssl/ssl_engine_vars.c httpd-2.2.13-peruser/modules/ssl/ssl_engine_vars.c
    old new  
    5858    return sslconn && sslconn->ssl; 
    5959} 
    6060 
     61static int ssl_server_is_https(server_rec *s) 
     62{ 
     63    SSLSrvConfigRec *sslsrv = mySrvConfig(s); 
     64    return sslsrv && sslsrv->enabled; 
     65} 
     66 
    6167static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION; 
    6268static char var_library_interface[] = SSL_LIBRARY_TEXT; 
    6369static char *var_library = NULL; 
     
    6773    char *cp, *cp2; 
    6874 
    6975    APR_REGISTER_OPTIONAL_FN(ssl_is_https); 
     76    APR_REGISTER_OPTIONAL_FN(ssl_server_is_https); 
    7077    APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); 
    7178    APR_REGISTER_OPTIONAL_FN(ssl_ext_lookup); 
    7279 
  • server/mpm/config.m4

    diff -Nur httpd-2.2.13/server/mpm/config.m4 httpd-2.2.13-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|event|worker|prefork|mpmt_os2}),[ 
     4                          MPM={beos|event|worker|prefork|mpmt_os2|peruser}),[ 
    55  APACHE_MPM=$withval 
    66],[ 
    77  if test "x$APACHE_MPM" = "x"; then 
     
    2323 
    2424ap_mpm_is_experimental () 
    2525{ 
    26     if test "$apache_cv_mpm" = "event" ; then 
     26    if test "$apache_cv_mpm" = "event" -o "$apache_cv_mpm" = "peruser" ; then 
    2727        return 0 
    2828    else 
    2929        return 1 
  • server/mpm/experimental/peruser/AUTHORS

    diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/AUTHORS httpd-2.2.13-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> 
     10Stefan Klingner <stefan.klingner [at] mephisto23.com> (Peruser maintainer) 
     11Michal Grzedzicki <lazy404 [at] gmail.com> 
  • server/mpm/experimental/peruser/config.m4

    diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/config.m4 httpd-2.2.13-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/Makefile.in

    diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/Makefile.in httpd-2.2.13-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/mpm_default.h

    diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/mpm_default.h httpd-2.2.13-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 --- more than this, and idle processors will be killed (0 = disable) */ 
     81 
     82#ifndef DEFAULT_MAX_FREE_PROCESSORS 
     83#define DEFAULT_MAX_FREE_PROCESSORS 0 
     84#endif 
     85 
     86/* Maximum processors per ServerEnvironment */ 
     87 
     88#ifndef DEFAULT_MAX_PROCESSORS 
     89#define DEFAULT_MAX_PROCESSORS 10 
     90#endif 
     91 
     92/* File used for accept locking, when we use a file */ 
     93#ifndef DEFAULT_LOCKFILE 
     94#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock" 
     95#endif 
     96 
     97/* Where the main/parent process's pid is logged */ 
     98#ifndef DEFAULT_PIDLOG 
     99#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid" 
     100#endif 
     101 
     102/* 
     103 * Interval, in microseconds, between scoreboard maintenance. 
     104 */ 
     105#ifndef SCOREBOARD_MAINTENANCE_INTERVAL 
     106#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 
     107#endif 
     108 
     109/* Number of requests to try to handle in a single process.  If <= 0, 
     110 * the children don't die off. 
     111 */ 
     112#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD 
     113#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000 
     114#endif 
     115 
     116/* Maximum multiplexers */ 
     117 
     118#ifndef DEFAULT_MAX_MULTIPLEXERS 
     119#define DEFAULT_MAX_MULTIPLEXERS 20 
     120#endif 
     121 
     122/* Minimum multiplexers */ 
     123 
     124#ifndef DEFAULT_MIN_MULTIPLEXERS 
     125#define DEFAULT_MIN_MULTIPLEXERS 3 
     126#endif 
     127 
     128/* Amount of time a child can run before it expires (0 = turn off) */ 
     129 
     130#ifndef DEFAULT_EXPIRE_TIMEOUT 
     131#define DEFAULT_EXPIRE_TIMEOUT 1800 
     132#endif 
     133 
     134/* Amount of time a child can stay idle (0 = turn off) */ 
     135 
     136#ifndef DEFAULT_IDLE_TIMEOUT 
     137#define DEFAULT_IDLE_TIMEOUT 900 
     138#endif 
     139 
     140/* Amount of time a multiplexer can stay idle (0 = turn off) */ 
     141 
     142#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 
     143#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0 
     144#endif 
     145 
     146/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait) 
     147 * This is decreased with every busy request 
     148 */ 
     149 
     150#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT 
     151#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5 
     152#endif 
     153 
     154/* The number of different levels there are when a multiplexer is waiting for processor 
     155 * (between maximum waiting time and no waiting) 
     156 */ 
     157 
     158#ifndef DEFAULT_PROCESSOR_WAIT_STEPS 
     159#define DEFAULT_PROCESSOR_WAIT_STEPS 10 
     160#endif 
     161 
     162#endif /* AP_MPM_DEFAULT_H */ 
  • server/mpm/experimental/peruser/mpm.h

    diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/mpm.h httpd-2.2.13-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_VALID_PID(p) (getpgid(p) == getpgrp()) 
     88#define MPM_ACCEPT_FUNC unixd_accept 
     89 
     90extern int ap_threads_per_child; 
     91extern int ap_max_daemons_limit; 
     92extern server_rec *ap_server_conf; 
     93 
     94/* Table of child status */ 
     95#define SERVER_DEAD 0 
     96#define SERVER_DYING 1 
     97#define SERVER_ALIVE 2 
     98 
     99typedef struct ap_ctable { 
     100    pid_t pid; 
     101    unsigned char status; 
     102} ap_ctable; 
     103 
     104#endif /* APACHE_MPM_PERUSER_H */ 
  • server/mpm/experimental/peruser/peruser.c

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