PeruserAttachments: httpd-2.2.14-peruser-0.4rc1.patch

File httpd-2.2.14-peruser-0.4rc1.patch, 149.3 KB (added by lazy, 2 years ago)

httpd-2.2.14-peruser-0.4rc1.patch

  • docs/conf/extra/httpd-mpm.conf.in

    diff -ruN httpd-2.2.14/docs/conf/extra/httpd-mpm.conf.in peruser-0.4rc1/docs/conf/extra/httpd-mpm.conf.in
    old new  
    2727# active mpm. 
    2828# 
    2929 
     30# peruser MPM 
     31# IdleTimeout: maximum time before a child is killed after being idle, 0 to disable 
     32# ExpireTimeout: maximum time a child can live, 0 to disable 
     33# MinSpareProcessors: minimum number of idle children, to handle request spikes 
     34# MaxProcessors: Maximum number of processors per vhost 
     35# ServerLimit: maximum value of MaxClients for this run of Apache 
     36# MaxClients: maximum number of children alive at the same time 
     37# MaxMultiplexers: maximum number of multiplexers the server can have 
     38<IfModule mpm_peruser_module> 
     39    IdleTimeout 900 
     40    ExpireTimeout 1800 
     41    MinSpareProcessors 2 
     42    MaxProcessors 10 
     43    ServerLimit 256 
     44    MaxClients 256 
     45    MaxMultiplexers 20 
     46</IfModule> 
     47 
    3048# prefork MPM 
    3149# StartServers: number of server processes to start 
    3250# MinSpareServers: minimum number of server processes which are kept spare 
  • modules/generators/mod_status.c

    diff -ruN httpd-2.2.14/modules/generators/mod_status.c peruser-0.4rc1/modules/generators/mod_status.c
    old new  
    205205#define STAT_OPT_REFRESH  0 
    206206#define STAT_OPT_NOTABLE  1 
    207207#define STAT_OPT_AUTO     2 
     208#define STAT_OPT_STATS    3 
    208209 
    209210struct stat_opt { 
    210211    int id; 
     
    217218    {STAT_OPT_REFRESH, "refresh", "Refresh"}, 
    218219    {STAT_OPT_NOTABLE, "notable", NULL}, 
    219220    {STAT_OPT_AUTO, "auto", NULL}, 
     221    {STAT_OPT_STATS, "stats", NULL}, 
    220222    {STAT_OPT_END, NULL, NULL} 
    221223}; 
    222224 
     
    241243#endif 
    242244    int short_report; 
    243245    int no_table_report; 
     246        int stats_report; 
    244247    worker_score *ws_record; 
    245248    process_score *ps_record; 
    246249    char *stat_buffer; 
     
    268271    kbcount = 0; 
    269272    short_report = 0; 
    270273    no_table_report = 0; 
    271  
     274        stats_report=0; 
     275         
    272276    pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t)); 
    273277    stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char)); 
    274278 
     
    312316                case STAT_OPT_NOTABLE: 
    313317                    no_table_report = 1; 
    314318                    break; 
     319               case STAT_OPT_STATS: 
     320                    stats_report = 1; 
     321                    break; 
    315322                case STAT_OPT_AUTO: 
    316323                    ap_set_content_type(r, "text/plain; charset=ISO-8859-1"); 
    317324                    short_report = 1; 
     
    819826        int flags = 
    820827            (short_report ? AP_STATUS_SHORT : 0) | 
    821828            (no_table_report ? AP_STATUS_NOTABLE : 0) | 
    822             (ap_extended_status ? AP_STATUS_EXTENDED : 0); 
     829            (ap_extended_status ? AP_STATUS_EXTENDED : 0) | 
     830            (stats_report ? AP_STATUS_STATS : 0); 
    823831 
    824832        ap_run_status_hook(r, flags); 
    825833    } 
  • modules/generators/mod_status.h

    diff -ruN httpd-2.2.14/modules/generators/mod_status.h peruser-0.4rc1/modules/generators/mod_status.h
    old new  
    3232#define AP_STATUS_SHORT    (0x1)  /* short, non-HTML report requested */ 
    3333#define AP_STATUS_NOTABLE  (0x2)  /* HTML report without tables */ 
    3434#define AP_STATUS_EXTENDED (0x4)  /* detailed report */ 
     35#define AP_STATUS_STATS    (0x8)  /* extended user statistics report */ 
    3536 
    3637#if !defined(WIN32) 
    3738#define STATUS_DECLARE(type)            type 
  • modules/ssl/mod_ssl.h

    diff -ruN httpd-2.2.14/modules/ssl/mod_ssl.h peruser-0.4rc1/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 -ruN httpd-2.2.14/modules/ssl/ssl_engine_vars.c peruser-0.4rc1/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 -ruN httpd-2.2.14/server/mpm/config.m4 peruser-0.4rc1/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 -ruN httpd-2.2.14/server/mpm/experimental/peruser/AUTHORS peruser-0.4rc1/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/Makefile.in

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

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

    diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/mpm.h peruser-0.4rc1/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 
     104static const char* child_clone(); 
     105 
     106 
     107#endif /* APACHE_MPM_PERUSER_H */ 
  • server/mpm/experimental/peruser/mpm_default.h

    diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/mpm_default.h peruser-0.4rc1/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/peruser.c

    diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/peruser.c peruser-0.4rc1/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 active_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) && (CHILD_INFO_TABLE[i].pid > 0 ) ) 
     920            total++; 
     921    } 
     922 
     923    return total; 
     924} 
     925 
     926static int active_env_processors(int env_num) 
     927{ 
     928    int i, total; 
     929 
     930    if(env_num >= NUM_SENV) 
     931      return -1; 
     932 
     933    for(i = 0, total = 0; i < NUM_CHILDS; ++i) 
     934    { 
     935        if((CHILD_INFO_TABLE[i].senv == &SENV[env_num]) && (CHILD_INFO_TABLE[i].pid > 0)) 
     936            total++; 
     937    } 
     938 
     939    return total; 
     940} 
     941 
     942static int idle_processors(int child_num) 
     943{ 
     944    int i, total; 
     945 
     946    for(i = 0, total = 0; i < NUM_CHILDS; ++i) 
     947    { 
     948        if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv && 
     949           (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY)) 
     950        { 
     951            total++; 
     952        } 
     953    } 
     954 
     955    return total; 
     956} 
     957 
     958static int idle_env_processors(int env_num) 
     959{ 
     960    int i, total; 
     961 
     962    for(i = 0, total = 0; i < NUM_CHILDS; ++i) 
     963    { 
     964        if(CHILD_INFO_TABLE[i].senv == &SENV[env_num] && (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY) ) 
     965            total++; 
     966    } 
     967 
     968    return total; 
     969} 
     970 
     971 
     972static int wait_for_workers(child_info_t *processor) { 
     973    int i, wait_step_size, wait_time; 
     974     
     975    wait_step_size = 100 / processor_wait_steps; 
     976 
     977    /*  Check if the processor is available */ 
     978    if (total_processors(processor->id) == processor->senv->max_processors && 
     979        idle_processors(processor->id) == 0 && processor_wait_timeout > 0) { 
     980        /* The processor is currently busy, try to wait (a little) */ 
     981        _DBG("processor seems to be busy, trying to wait for it"); 
     982 
     983        if (processor->senv->availability == 0) { 
     984            processor->senv->availability = 0; 
     985 
     986            _DBG("processor is very busy (availability = 0) - not passing request"); 
     987 
     988            if (processor->senv->error_pass == 0) { 
     989                ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, 
     990                             "Too many requests for processor %s, increase MaxProcessors", processor->senv->name); 
     991            } 
     992             
     993            /* No point in waiting for the processor, it's very busy */ 
     994            return -1; 
     995        } 
     996         
     997        /* We sleep a little (depending how available the processor usually is) */ 
     998        wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000; 
     999 
     1000        for(i = 0; i <= processor->senv->availability; i += wait_step_size) { 
     1001            usleep(wait_time); 
     1002 
     1003            /* Check if the processor is ready */ 
     1004            if (total_processors(processor->id) < processor->senv->max_processors || 
     1005                idle_processors(processor->id) > 0) { 
     1006                /* The processor has freed - lets use it */ 
     1007                _DBG("processor freed before wait time expired"); 
     1008                break; 
     1009            } 
     1010        } 
     1011         
     1012        if (processor->senv->availability <= wait_step_size) { 
     1013            processor->senv->availability = 0; 
     1014        } 
     1015        else processor->senv->availability -= wait_step_size; 
     1016         
     1017        /* Check if we waited all the time */ 
     1018        if (i > processor->senv->availability) { 
     1019            _DBG("processor is busy - not passing request (availability = %d)", 
     1020                 processor->senv->availability); 
     1021 
     1022            if (processor->senv->error_pass == 0) { 
     1023                ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, 
     1024                             "Too many requests for processor %s, increase MaxProcessors", processor->senv->name); 
     1025            } 
     1026 
     1027            return -1; 
     1028        } 
     1029 
     1030        /* We could increase the availability a little here, 
     1031         * because the processor got freed eventually 
     1032         */ 
     1033    } 
     1034    else { 
     1035        /* Smoothly increment the availability back to 100 */ 
     1036        if (processor->senv->availability >= 100-wait_step_size) { 
     1037            processor->senv->availability = 100; 
     1038        } 
     1039        else processor->senv->availability += wait_step_size; 
     1040    } 
     1041 
     1042    return 0; 
     1043} 
     1044 
     1045/* 
     1046 * This function sends a raw socket over to a processor. It uses the same 
     1047 * on-wire format as pass_request. The recipient can determine if he got 
     1048 * a socket or a whole request by inspecting the header_length of the 
     1049 * message. If it is zero then only a socket was sent. 
     1050 */ 
     1051static int pass_socket(apr_socket_t *thesock, child_info_t *processor, apr_pool_t *pool) 
     1052{ 
     1053    int rv; 
     1054    struct msghdr msg; 
     1055    struct cmsghdr *cmsg; 
     1056    apr_sockaddr_t *remote_addr; 
     1057    int sock_fd; 
     1058    char *body = ""; 
     1059    struct iovec iov[5]; 
     1060    apr_size_t header_len = 0; 
     1061    apr_size_t body_len = 0; 
     1062    peruser_header h; 
     1063 
     1064    if (!processor) 
     1065    { 
     1066        _DBG("server %s in child %d has no child_info associated", 
     1067                "(unkonwn)", my_child_num); 
     1068        return -1; 
     1069    } 
     1070     
     1071    /* Make sure there are free workers on the other end */ 
     1072    if (wait_for_workers(processor) == -1) return -1; 
     1073 
     1074    _DBG("passing request to another child.", 0); 
     1075 
     1076    apr_os_sock_get(&sock_fd, thesock); 
     1077    /* passing remote_addr too, see comments below */ 
     1078    apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock); 
     1079     
     1080    header_len = 0; 
     1081    body_len = 0; 
     1082 
     1083    iov[0].iov_base = &header_len; 
     1084    iov[0].iov_len  = sizeof(header_len); 
     1085    iov[1].iov_base = &body_len; 
     1086    iov[1].iov_len  = sizeof(body_len); 
     1087    iov[2].iov_base = remote_addr; 
     1088    iov[2].iov_len  = sizeof(*remote_addr); 
     1089    iov[3].iov_base = h.headers; 
     1090    iov[3].iov_len  = 0; 
     1091    iov[4].iov_base = body; 
     1092    iov[4].iov_len  = body_len; 
     1093 
     1094    msg.msg_name    = NULL; 
     1095    msg.msg_namelen = 0; 
     1096    msg.msg_iov     = iov; 
     1097    msg.msg_iovlen  = 5; 
     1098 
     1099    cmsg = apr_palloc(pool, sizeof(*cmsg) + sizeof(sock_fd)); 
     1100    cmsg->cmsg_len   = CMSG_LEN(sizeof(sock_fd)); 
     1101    cmsg->cmsg_level = SOL_SOCKET; 
     1102    cmsg->cmsg_type  = SCM_RIGHTS; 
     1103 
     1104    memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd)); 
     1105 
     1106    msg.msg_control    = cmsg; 
     1107    msg.msg_controllen = cmsg->cmsg_len; 
     1108 
     1109    if (processor->status == CHILD_STATUS_STANDBY) 
     1110    { 
     1111        _DBG("Activating child #%d", processor->id); 
     1112        processor->status = CHILD_STATUS_STARTING; 
     1113    } 
     1114 
     1115    _DBG("Writing message to %d, passing sock_fd:  %d", processor->senv->output, sock_fd); 
     1116    _DBG("header_len=%d headers=\"%s\"", header_len, h.headers); 
     1117    _DBG("body_len=%d body=\"%s\"", body_len, body); 
     1118 
     1119    if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1) 
     1120    { 
     1121        apr_pool_destroy(pool); 
     1122        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     1123                     "Writing message failed %d %d", rv, errno); 
     1124        return -1; 
     1125    } 
     1126 
     1127    _DBG("Writing message succeeded %d", rv); 
     1128 
     1129    /* -- close the socket on our side -- */ 
     1130    _DBG("closing socket %d on our side", sock_fd); 
     1131    apr_socket_close(thesock); 
     1132 
     1133    apr_pool_destroy(pool); 
     1134    return 1; 
     1135} 
     1136 
     1137static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id, 
     1138                           apr_bucket_alloc_t *bucket_alloc, apr_pool_t *pool) 
     1139{ 
     1140    conn_rec *current_conn; 
     1141    int sock_fd; 
     1142    apr_status_t rv; 
     1143    ap_sb_handle_t *sbh; 
     1144    child_info_t *processor; 
     1145    apr_pool_t *ptrans; 
     1146    peruser_server_conf *sconf; 
     1147    int ssl_on = 0; 
     1148 
     1149    _DBG("Creating dummy connection to use the vhost lookup api", 0); 
     1150 
     1151    ap_create_sb_handle(&sbh, p, conn_id, 0); 
     1152    current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, 
     1153                                            sbh, bucket_alloc); 
     1154    _DBG("Looking up the right vhost"); 
     1155    if (current_conn) { 
     1156        ap_update_vhost_given_ip(current_conn); 
     1157        _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname, 
     1158             current_conn->vhost_lookup_data ? "on" : "off"); 
     1159         
     1160        // check for ssl configuration for this server (ssl_server_is_https is NULL if we have no mod_ssl) 
     1161        if(ssl_server_is_https) ssl_on = ssl_server_is_https(current_conn->base_server); 
     1162    } 
     1163 
     1164    if (current_conn && (!current_conn->vhost_lookup_data || ssl_on) && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { 
     1165        _DBG("We are not using name based vhosts (or SSL is enabled), we'll directly pass the socket."); 
     1166 
     1167        sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config); 
     1168 
     1169        if (sconf->senv != NULL) { 
     1170            processor = &CHILD_INFO_TABLE[sconf->senv->processor_id]; 
     1171 
     1172            _DBG("Forwarding without further inspection, processor %d", processor->id); 
     1173            if (processor->status == CHILD_STATUS_STANDBY) 
     1174              { 
     1175                  _DBG("Activating child #%d", processor->id); 
     1176                  processor->status = CHILD_STATUS_STARTING; 
     1177              } 
     1178             
     1179            _DBG("Creating new pool",0); 
     1180            apr_pool_create(&ptrans, pool); 
     1181 
     1182            _DBG("Passing request.",0); 
     1183            if (pass_socket(sock, processor, ptrans) == -1) { 
     1184                if (processor->senv->error_pass == 0) { 
     1185                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, 
     1186                                 ap_server_conf, "Could not pass request to proper "                              
     1187                                 "child, request will not be honoured."); 
     1188                } 
     1189                 
     1190                processor->senv->error_pass = 1; 
     1191            } 
     1192            else { 
     1193                processor->senv->error_pass = 0; 
     1194            } 
     1195        } 
     1196        else { 
     1197            _DBG("Base server has no senv set!"); 
     1198 
     1199            if (sconf->missing_senv_reported == 0) { 
     1200                ap_log_error(APLOG_MARK, APLOG_ERR, 0, 
     1201                             ap_server_conf, "Virtualhost %s has no server environment set, "                              
     1202                             "request will not be honoured.", current_conn->base_server->server_hostname); 
     1203            } 
     1204 
     1205            sconf->missing_senv_reported = 1; 
     1206        } 
     1207 
     1208        if (current_conn) 
     1209        { 
     1210            _DBG("freeing connection",0); 
     1211            ap_lingering_close(current_conn); 
     1212        } 
     1213 
     1214        _DBG("doing longjmp",0); 
     1215        longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1); 
     1216        return; 
     1217    } 
     1218 
     1219    if ((rv = apr_os_sock_get(&sock_fd, sock)) != APR_SUCCESS) 
     1220    { 
     1221        ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get"); 
     1222    } 
     1223 
     1224    _DBG("child_num=%d sock=%ld sock_fd=%d", my_child_num, sock, sock_fd); 
     1225    _DBG("type=%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num); 
     1226 
     1227#ifdef _OSD_POSIX 
     1228    if (sock_fd >= FD_SETSIZE) 
     1229    { 
     1230        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, 
     1231                     "new file descriptor %d is too large; you probably need " 
     1232                     "to rebuild Apache with a larger FD_SETSIZE " 
     1233                     "(currently %d)", 
     1234                     sock_fd, FD_SETSIZE); 
     1235        apr_socket_close(sock); 
     1236        _DBG("child_num=%d: exiting with error", my_child_num); 
     1237        return; 
     1238    } 
     1239#endif 
     1240 
     1241    if (CHILD_INFO_TABLE[my_child_num].sock_fd < 0) 
     1242    { 
     1243        ap_sock_disable_nagle(sock); 
     1244    } 
     1245 
     1246    if (!current_conn) { 
     1247        ap_create_sb_handle(&sbh, p, conn_id, 0); 
     1248        current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id, 
     1249                                                sbh, bucket_alloc); 
     1250    } 
     1251 
     1252    if (current_conn) 
     1253    { 
     1254        ap_process_connection(current_conn, sock); 
     1255        ap_lingering_close(current_conn); 
     1256    } 
     1257} 
     1258 
     1259static int peruser_process_connection(conn_rec *conn) 
     1260{ 
     1261    ap_filter_t *filter; 
     1262    apr_bucket_brigade *bb; 
     1263    core_net_rec *net; 
     1264 
     1265    _DBG("function entered",0); 
     1266 
     1267    /* -- fetch our sockets from the pool -- */ 
     1268    apr_pool_userdata_get((void **)&bb, "PERUSER_SOCKETS", conn->pool); 
     1269    if (bb != NULL) 
     1270    { 
     1271        /* -- find the 'core' filter and give the socket data to it -- */ 
     1272        for (filter = conn->output_filters; filter != NULL; filter = filter->next) 
     1273        { 
     1274            if (!strcmp(filter->frec->name, "core")) break; 
     1275        } 
     1276        if (filter != NULL) 
     1277        { 
     1278            net = filter->ctx; 
     1279            net->in_ctx = apr_palloc(conn->pool, sizeof(*net->in_ctx)); 
     1280            net->in_ctx->b = bb; 
     1281            net->in_ctx->tmpbb = apr_brigade_create(net->in_ctx->b->p,  
     1282                net->in_ctx->b->bucket_alloc); 
     1283        } 
     1284    } 
     1285    _DBG("leaving (DECLINED)", 0); 
     1286    return DECLINED; 
     1287} 
     1288 
     1289static int pass_request(request_rec *r, child_info_t *processor) 
     1290{ 
     1291    int rv; 
     1292    struct msghdr msg; 
     1293    struct cmsghdr *cmsg; 
     1294    apr_sockaddr_t *remote_addr; 
     1295    int sock_fd; 
     1296    char *body = ""; 
     1297    struct iovec iov[5]; 
     1298    conn_rec *c = r->connection; 
     1299    apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc); 
     1300    apr_bucket_brigade *body_bb = NULL; 
     1301    apr_size_t len = 0; 
     1302    apr_size_t header_len = 0; 
     1303    apr_size_t body_len = 0; 
     1304    peruser_header h; 
     1305    apr_bucket *bucket; 
     1306    const apr_array_header_t *headers_in_array; 
     1307    const apr_table_entry_t *headers_in; 
     1308    int counter; 
     1309 
     1310    apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module); 
     1311 
     1312    if ((!r->the_request) || (!strlen(r->the_request))) 
     1313    { 
     1314        _DBG("empty request. dropping it (%ld)", r->the_request); 
     1315        return -1; 
     1316    } 
     1317 
     1318    if (!processor) 
     1319    { 
     1320        _DBG("server %s in child %d has no child_info associated", 
     1321                r->hostname, my_child_num); 
     1322        return -1; 
     1323    } 
     1324 
     1325    _DBG("passing request to another child.  Vhost: %s, child %d %d", 
     1326      apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output); 
     1327    _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request)); 
     1328 
     1329    /* Make sure there are free workers on the other end */ 
     1330    if (wait_for_workers(processor) == -1) return -1; 
     1331 
     1332    ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len); 
     1333     
     1334    /* Scan the brigade looking for heap-buckets */ 
     1335     
     1336    _DBG("Scanning the brigade",0); 
     1337    bucket = APR_BRIGADE_FIRST(bb); 
     1338    while (bucket != APR_BRIGADE_SENTINEL(bb) && 
     1339           APR_BUCKET_IS_HEAP(bucket)) { 
     1340       _DBG("HEAP BUCKET is found, length=%d", bucket->length); 
     1341        bucket = APR_BUCKET_NEXT(bucket); 
     1342        if (!APR_BUCKET_IS_HEAP(bucket)) { 
     1343            _DBG("NON-HEAP BUCKET is found, extracting the part of brigade before it",0); 
     1344            body_bb = bb; 
     1345            bb = apr_brigade_split(body_bb, bucket); 
     1346            /* Do we need to apr_destroy_brigade(bb) here? 
     1347             * Yeah, I know we do apr_pool_destroy(r->pool) before return, but 
     1348             * ap_get_brigade is in non-blocking mode (however len is zero). 
     1349             */ 
     1350            if (apr_brigade_pflatten(body_bb, &body, &body_len, r->pool) != APR_SUCCESS) { 
     1351                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     1352                     "Unable to flatten brigade, declining request"); 
     1353                apr_pool_destroy(r->pool); 
     1354                return DECLINED; 
     1355            } 
     1356            _DBG("Brigade is flattened as body (body_len=%d)", body_len); 
     1357        } 
     1358    } 
     1359    _DBG("Scanning is finished",0); 
     1360 
     1361    apr_os_sock_get(&sock_fd, thesock); 
     1362    /* looks like a bug while sending/receiving SCM_RIGHTS related to ipv6 
     1363       workaround: send remote_addr structure too */ 
     1364    apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock); 
     1365 
     1366    h.p = r->pool; 
     1367 
     1368    headers_in_array = apr_table_elts(r->headers_in); 
     1369    headers_in = (const apr_table_entry_t *) headers_in_array->elts; 
     1370 
     1371    h.headers = apr_pstrcat(h.p, r->the_request, CRLF, NULL); 
     1372    for (counter = 0; counter < headers_in_array->nelts; counter++) { 
     1373        if (headers_in[counter].key == NULL 
     1374         || headers_in[counter].val == NULL) { 
     1375             continue; 
     1376         } 
     1377         h.headers = apr_pstrcat(h.p, h.headers, headers_in[counter].key, ": ", 
     1378                                 headers_in[counter].val, CRLF, NULL); 
     1379 
     1380    } 
     1381    h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL); 
     1382    ap_xlate_proto_to_ascii(h.headers, strlen(h.headers)); 
     1383 
     1384    header_len = strlen(h.headers); 
     1385 
     1386    iov[0].iov_base = &header_len; 
     1387    iov[0].iov_len  = sizeof(header_len); 
     1388    iov[1].iov_base = &body_len; 
     1389    iov[1].iov_len  = sizeof(body_len); 
     1390    iov[2].iov_base = remote_addr; 
     1391    iov[2].iov_len  = sizeof(*remote_addr); 
     1392    iov[3].iov_base = h.headers; 
     1393    iov[3].iov_len  = strlen(h.headers) + 1; 
     1394    iov[4].iov_base = body; 
     1395    iov[4].iov_len  = body_len; 
     1396 
     1397    msg.msg_name    = NULL; 
     1398    msg.msg_namelen = 0; 
     1399    msg.msg_iov     = iov; 
     1400    msg.msg_iovlen  = 5; 
     1401 
     1402    cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sock_fd)); 
     1403    cmsg->cmsg_len   = CMSG_LEN(sizeof(sock_fd)); 
     1404    cmsg->cmsg_level = SOL_SOCKET; 
     1405    cmsg->cmsg_type  = SCM_RIGHTS; 
     1406 
     1407    memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd)); 
     1408 
     1409    msg.msg_control    = cmsg; 
     1410    msg.msg_controllen = cmsg->cmsg_len; 
     1411 
     1412    if (processor->status == CHILD_STATUS_STANDBY) 
     1413    { 
     1414        _DBG("Activating child #%d", processor->id); 
     1415        processor->status = CHILD_STATUS_STARTING; 
     1416    } 
     1417 
     1418    _DBG("Writing message to %d, passing sock_fd:  %d", processor->senv->output, sock_fd); 
     1419    _DBG("header_len=%d headers=\"%s\"", header_len, h.headers); 
     1420    _DBG("body_len=%d body=\"%s\"", body_len, body); 
     1421 
     1422    if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1) 
     1423    { 
     1424        apr_pool_destroy(r->pool); 
     1425        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     1426                     "Writing message failed %d %d", rv, errno); 
     1427        return -1; 
     1428    } 
     1429 
     1430    _DBG("Writing message succeeded %d", rv); 
     1431 
     1432    /* -- close the socket on our side -- */ 
     1433    _DBG("closing socket %d on our side", sock_fd); 
     1434    apr_socket_close(thesock); 
     1435 
     1436    apr_pool_destroy(r->pool); 
     1437    return 1; 
     1438} 
     1439 
     1440 
     1441static apr_status_t receive_from_multiplexer( 
     1442    void **trans_sock,  /* will be filled out w/ the received socket */ 
     1443    ap_listen_rec *lr,  /* listener to receive from */ 
     1444    apr_pool_t *ptrans  /* transaction wide pool */ 
     1445) 
     1446{ 
     1447    struct msghdr msg; 
     1448    struct cmsghdr *cmsg; 
     1449    char buff[HUGE_STRING_LEN] = ""; 
     1450    char headers[HUGE_STRING_LEN] = ""; 
     1451    char *body = ""; 
     1452    apr_size_t header_len, body_len; 
     1453    struct iovec iov[4]; 
     1454    int ret, fd_tmp; 
     1455    apr_os_sock_t ctrl_sock_fd; 
     1456    apr_os_sock_t trans_sock_fd; 
     1457    apr_sockaddr_t remote_addr; 
     1458    apr_os_sock_info_t sockinfo; 
     1459 
     1460    /* -- bucket's, brigades and their allocators */ 
     1461    apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans); 
     1462    apr_bucket_brigade *bb    = apr_brigade_create(ptrans, alloc); 
     1463    apr_bucket         *bucket; 
     1464 
     1465    /* prepare the buffers for receiving data from remote side */ 
     1466    iov[0].iov_base = &header_len; 
     1467    iov[0].iov_len  = sizeof(header_len); 
     1468    iov[1].iov_base = &body_len; 
     1469    iov[1].iov_len  = sizeof(body_len); 
     1470    iov[2].iov_base = &remote_addr; 
     1471    iov[2].iov_len  = sizeof(remote_addr); 
     1472    iov[3].iov_base = (char*)&buff; 
     1473    iov[3].iov_len  = HUGE_STRING_LEN; 
     1474 
     1475    cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd)); 
     1476    cmsg->cmsg_len = CMSG_LEN(sizeof(trans_sock_fd)); 
     1477 
     1478    msg.msg_name       = NULL; 
     1479    msg.msg_namelen    = 0; 
     1480    msg.msg_iov        = iov; 
     1481    msg.msg_iovlen     = 4; 
     1482    msg.msg_control    = cmsg; 
     1483    msg.msg_controllen = cmsg->cmsg_len; 
     1484 
     1485    /* -- receive data from socket -- */ 
     1486    apr_os_sock_get(&ctrl_sock_fd, lr->sd); 
     1487    _DBG("receiving from sock_fd=%d", ctrl_sock_fd); 
     1488 
     1489    // Don't block 
     1490    ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT); 
     1491 
     1492    if (ret == -1 && errno == EAGAIN) { 
     1493        _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster"); 
     1494         
     1495        return APR_EAGAIN; 
     1496    } 
     1497    else if (ret == -1) { 
     1498        _DBG("recvmsg failed with error \"%s\"", strerror(errno)); 
     1499         
     1500        // Error, better kill this child to be on the safe side 
     1501        return APR_EGENERAL; 
     1502    } 
     1503    else _DBG("recvmsg returned %d", ret); 
     1504 
     1505    /* -- extract socket from the cmsg -- */ 
     1506    memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd)); 
     1507    /* here *trans_sock always == NULL (socket reset at got_fd), so 
     1508       we can use apr_os_sock_make() instead of apr_os_sock_put() */ 
     1509    sockinfo.os_sock  = &trans_sock_fd; 
     1510    sockinfo.local    = NULL; 
     1511    sockinfo.remote   = (struct sockaddr *)&remote_addr.sa.sin; 
     1512    sockinfo.family   = remote_addr.family; 
     1513    sockinfo.type     = SOCK_STREAM; 
     1514#ifdef APR_ENABLE_FOR_1_0 
     1515    sockinfo.protocol = 0; 
     1516#endif 
     1517    apr_os_sock_make((apr_socket_t **)trans_sock, &sockinfo, ptrans); 
     1518    apr_os_sock_get(&fd_tmp, *trans_sock); 
     1519 
     1520    _DBG("trans_sock=%ld fdx=%d sock_fd=%d", 
     1521         *trans_sock, trans_sock_fd, fd_tmp); 
     1522 
     1523    apr_cpystrn(headers, buff, header_len + 1); 
     1524    _DBG("header_len=%d headers=\"%s\"", header_len, headers); 
     1525 
     1526    if (header_len) {     
     1527        _DBG("header_len > 0, we got a request", 0); 
     1528        /* -- store received data into an brigade and add 
     1529           it to the current transaction's pool -- */ 
     1530        bucket = apr_bucket_eos_create(alloc); 
     1531        APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1532        bucket = apr_bucket_socket_create(*trans_sock, alloc); 
     1533        APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1534         
     1535        if (body_len) { 
     1536            body = (char*)&buff[header_len + 1]; 
     1537            _DBG("body_len=%d body=\"%s\"", body_len, body); 
     1538             
     1539            bucket = apr_bucket_heap_create(body, body_len, NULL, alloc); 
     1540            APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1541        } else { 
     1542            _DBG("There is no body",0); 
     1543        } 
     1544         
     1545        bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc); 
     1546         
     1547        APR_BRIGADE_INSERT_HEAD(bb, bucket); 
     1548        apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans); 
     1549    } else { 
     1550        _DBG("header_len == 0, we got a socket only", 0); 
     1551    } 
     1552    _DBG("returning 0", 0); 
     1553    return 0; 
     1554} 
     1555 
     1556 
     1557/* Set group privileges. 
     1558 * 
     1559 * Note that we use the username as set in the config files, rather than 
     1560 * the lookup of to uid --- the same uid may have multiple passwd entries, 
     1561 * with different sets of groups for each. 
     1562 */ 
     1563 
     1564static int set_group_privs(uid_t uid, gid_t gid) 
     1565{ 
     1566    if (!geteuid()) 
     1567    { 
     1568        struct passwd *ent; 
     1569        const char *name; 
     1570 
     1571        /* 
     1572         * Set the GID before initgroups(), since on some platforms 
     1573         * setgid() is known to zap the group list. 
     1574         */ 
     1575        if (setgid(gid) == -1) 
     1576        { 
     1577            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1578                         "setgid: unable to set group id to Group %u", 
     1579                         (unsigned)gid); 
     1580            return -1; 
     1581        } 
     1582 
     1583        /* if getpwuid() fails, just skip initgroups() */ 
     1584 
     1585        if ((ent = getpwuid(uid)) != NULL) 
     1586        { 
     1587            name = ent->pw_name; 
     1588 
     1589            /* Reset `groups' attributes. */ 
     1590 
     1591            if (initgroups(name, gid) == -1) 
     1592            { 
     1593                ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1594                             "initgroups: unable to set groups for User %s " 
     1595                             "and Group %u", name, (unsigned)gid); 
     1596                return -1; 
     1597            } 
     1598        } 
     1599    } 
     1600    return 0; 
     1601} 
     1602 
     1603static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool) 
     1604{ 
     1605    apr_file_t *file; 
     1606    int length; 
     1607    apr_size_t content_len; 
     1608    char *tasks_file, *content, *pos; 
     1609 
     1610    _DBG("starting to add pid to cgroup %s", senv->cgroup); 
     1611 
     1612    length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN; 
     1613    tasks_file = malloc(length); 
     1614 
     1615    if (!tasks_file) return -1; 
     1616 
     1617    pos = apr_cpystrn(tasks_file, senv->cgroup, length); 
     1618    apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN); 
     1619 
     1620    /* Prepare the data to be written to tasks file */ 
     1621    content = apr_itoa(pool, ap_my_pid); 
     1622    content_len  = strlen(content); 
     1623 
     1624    _DBG("writing pid %s to tasks file %s", content, tasks_file); 
     1625 
     1626    if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) { 
     1627        if (senv->error_cgroup == 0) { 
     1628            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1629                         "cgroup: unable to open file %s", 
     1630                         tasks_file); 
     1631        } 
     1632 
     1633        senv->error_cgroup = 1; 
     1634        free(tasks_file); 
     1635        return OK; /* don't fail if cgroup not available */ 
     1636    } 
     1637 
     1638    if (apr_file_write(file, content, &content_len)) { 
     1639        if (senv->error_cgroup == 0) { 
     1640            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1641                         "cgroup: unable to write pid to file %s", 
     1642                         tasks_file); 
     1643        } 
     1644        senv->error_cgroup = 1; 
     1645    } 
     1646    else { 
     1647        senv->error_cgroup = 0; 
     1648    } 
     1649 
     1650    apr_file_close(file); 
     1651 
     1652    free(tasks_file); 
     1653 
     1654    return OK; 
     1655} 
     1656 
     1657static int peruser_setup_child(int childnum, apr_pool_t *pool) 
     1658{ 
     1659    server_env_t *senv = CHILD_INFO_TABLE[childnum].senv; 
     1660 
     1661    _DBG("function called"); 
     1662 
     1663    if (senv->nice_lvl != 0) { 
     1664        nice(senv->nice_lvl); 
     1665    } 
     1666 
     1667    if(senv->chroot) { 
     1668        _DBG("chdir to %s", senv->chroot); 
     1669 
     1670        if(chdir(senv->chroot)) { 
     1671            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1672                         "chdir: unable to change to directory: %s", 
     1673                         senv->chroot); 
     1674            return -1; 
     1675        } 
     1676 
     1677        if(chroot(senv->chroot)) { 
     1678            ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1679                         "chroot: unable to chroot to directory: %s", 
     1680                         senv->chroot); 
     1681            return -1; 
     1682        } 
     1683    } 
     1684 
     1685    if(senv->cgroup) { 
     1686        peruser_setup_cgroup(childnum, senv, pool); 
     1687    } 
     1688 
     1689    if (senv->uid == -1 && senv->gid == -1) { 
     1690        return unixd_setup_child(); 
     1691    } 
     1692    if (set_group_privs(senv->uid, senv->gid)) { 
     1693        return -1; 
     1694    } 
     1695    /* Only try to switch if we're running as root */ 
     1696    if (!geteuid() 
     1697        && ( 
     1698#ifdef _OSD_POSIX 
     1699            os_init_job_environment(ap_server_conf, unixd_config.user_name, 
     1700                                    one_process) != 0 || 
     1701#endif 
     1702            setuid(senv->uid) == -1)) { 
     1703        ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, 
     1704                     "setuid: unable to change to uid: %ld", 
     1705                     (long) senv->uid); 
     1706        return -1; 
     1707    } 
     1708    return 0; 
     1709} 
     1710 
     1711static int check_signal(int signum) 
     1712{ 
     1713    _DBG("signum=%d", signum); 
     1714    switch (signum) { 
     1715    case SIGTERM: 
     1716    case SIGINT: 
     1717        just_die(signum); 
     1718        return 1; 
     1719    } 
     1720    return 0; 
     1721} 
     1722 
     1723/* Send a single HTTP header field to the client.  Note that this function 
     1724 * is used in calls to table_do(), so their interfaces are co-dependent. 
     1725 * In other words, don't change this one without checking table_do in alloc.c. 
     1726 * It returns true unless there was a write error of some kind. 
     1727 */ 
     1728static int peruser_header_field(peruser_header *h, 
     1729                             const char *fieldname, const char *fieldval) 
     1730{ 
     1731    apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL); 
     1732    return 1; 
     1733} 
     1734 
     1735static inline ap_listen_rec* listen_add(apr_pool_t* pool, apr_socket_t *sock, void* accept_func) 
     1736{ 
     1737    ap_listen_rec *lr_walk, *lr_new; 
     1738 
     1739    _DBG("function entered", 0); 
     1740    /* -- create an new listener for this child -- */ 
     1741    lr_new = apr_palloc(pool, sizeof(*lr_new)); 
     1742    lr_new->sd          = sock; 
     1743    lr_new->active      = 1; 
     1744    lr_new->accept_func = accept_func; 
     1745    lr_new->next        = NULL; 
     1746 
     1747    /* -- add the new listener_rec into the list -- */ 
     1748    /* FIXME: should we somehow lock this list ? */ 
     1749    lr_walk = ap_listeners; 
     1750    if (lr_walk) 
     1751    { 
     1752        while (lr_walk->next) lr_walk = lr_walk->next; 
     1753        lr_walk->next = lr_new; 
     1754    } 
     1755    else 
     1756    { 
     1757        ap_listeners = lr_walk = lr_new; 
     1758    } 
     1759    num_listensocks++; 
     1760    return lr_new; 
     1761} 
     1762 
     1763static inline void listen_clear() 
     1764{ 
     1765    ap_listen_rec *lr_walk; 
     1766 
     1767    _DBG("function entered", 0); 
     1768 
     1769    /* FIXME: should we somehow lock this list ? */ 
     1770    while (ap_listeners) 
     1771    { 
     1772        lr_walk = ap_listeners->next; 
     1773        apr_socket_close(ap_listeners->sd); 
     1774        ap_listeners = lr_walk; 
     1775    } 
     1776    num_listensocks=0; 
     1777} 
     1778 
     1779apr_status_t cleanup_child_info(void *d) 
     1780{ 
     1781    if (child_info_image == NULL) { 
     1782        return APR_SUCCESS; 
     1783    } 
     1784 
     1785    free(child_info_image); 
     1786    child_info_image = NULL; 
     1787    apr_shm_destroy(child_info_shm); 
     1788 
     1789    return APR_SUCCESS; 
     1790} 
     1791 
     1792apr_status_t cleanup_server_environments(void *d) 
     1793{ 
     1794    if (server_env_image == NULL) { 
     1795        return APR_SUCCESS; 
     1796    } 
     1797 
     1798    free(server_env_image); 
     1799    server_env_image = NULL; 
     1800    apr_shm_destroy(server_env_shm); 
     1801 
     1802    return APR_SUCCESS; 
     1803} 
     1804 
     1805static void child_main(int child_num_arg) 
     1806{ 
     1807    apr_pool_t *ptrans; 
     1808    apr_allocator_t *allocator; 
     1809    conn_rec *current_conn; 
     1810    apr_status_t status = APR_EINIT; 
     1811    int i; 
     1812    ap_listen_rec *lr; 
     1813    int curr_pollfd, last_pollfd = 0; 
     1814    apr_pollfd_t *pollset; 
     1815    int offset; 
     1816    ap_sb_handle_t *sbh; 
     1817    apr_status_t rv; 
     1818    apr_bucket_alloc_t *bucket_alloc; 
     1819    int fd; 
     1820    apr_socket_t *sock = NULL; 
     1821    apr_socket_t *pod_sock = NULL; 
     1822 
     1823    mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this 
     1824                                  * child initializes 
     1825                                  */ 
     1826 
     1827    my_child_num = child_num_arg; 
     1828    ap_my_pid = getpid(); 
     1829    requests_this_child = 0; 
     1830 
     1831    _DBG("sock_fd_in=%d sock_fd_out=%d", 
     1832         CHILD_INFO_TABLE[my_child_num].senv->input, 
     1833         CHILD_INFO_TABLE[my_child_num].senv->output); 
     1834 
     1835    /* Get a sub context for global allocations in this child, so that 
     1836     * we can have cleanups occur when the child exits. 
     1837     */ 
     1838    apr_allocator_create(&allocator); 
     1839    apr_allocator_max_free_set(allocator, ap_max_mem_free); 
     1840    apr_pool_create_ex(&pchild, pconf, NULL, allocator); 
     1841    apr_allocator_owner_set(allocator, pchild); 
     1842 
     1843    apr_pool_create(&ptrans, pchild); 
     1844    apr_pool_tag(ptrans, "transaction"); 
     1845 
     1846    /* needs to be done before we switch UIDs so we have permissions */ 
     1847    ap_reopen_scoreboard(pchild, NULL, 0); 
     1848 
     1849    rv = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild); 
     1850    if (rv != APR_SUCCESS) { 
     1851        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, 
     1852                     "Couldn't initialize cross-process lock in child"); 
     1853        clean_child_exit(APEXIT_CHILDFATAL); 
     1854    } 
     1855 
     1856    switch(CHILD_INFO_TABLE[my_child_num].type) 
     1857    { 
     1858        case CHILD_TYPE_MULTIPLEXER: 
     1859            _DBG("MULTIPLEXER %d", my_child_num); 
     1860            break; 
     1861 
     1862        case CHILD_TYPE_PROCESSOR: 
     1863        case CHILD_TYPE_WORKER: 
     1864            _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num); 
     1865 
     1866            /* -- create new listener to receive from multiplexer -- */ 
     1867            apr_os_sock_put(&sock, &CHILD_INFO_TABLE[my_child_num].senv->input, pconf); 
     1868            listen_clear(); 
     1869            listen_add(pconf, sock, receive_from_multiplexer); 
     1870 
     1871            break; 
     1872 
     1873        default: 
     1874            _DBG("unspecified child type for %d sleeping a while ...", my_child_num); 
     1875            sleep(5); 
     1876            return; 
     1877    } 
     1878 
     1879    apr_os_file_get(&fd, pipe_of_death_in); 
     1880    apr_os_sock_put(&pod_sock, &fd, pconf); 
     1881    listen_add(pconf, pod_sock, check_pipe_of_death); 
     1882 
     1883    if(peruser_setup_child(my_child_num, pchild) != 0) 
     1884        clean_child_exit(APEXIT_CHILDFATAL); 
     1885 
     1886    ap_run_child_init(pchild, ap_server_conf); 
     1887 
     1888    ap_create_sb_handle(&sbh, pchild, my_child_num, 0); 
     1889    (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); 
     1890 
     1891    /* Set up the pollfd array */ 
     1892    listensocks = apr_pcalloc(pchild, 
     1893                            sizeof(*listensocks) * (num_listensocks)); 
     1894    for (lr = ap_listeners, i = 0; i < num_listensocks; lr = lr->next, i++) { 
     1895        listensocks[i].accept_func = lr->accept_func; 
     1896        listensocks[i].sd = lr->sd; 
     1897    } 
     1898 
     1899    pollset = apr_palloc(pchild, sizeof(*pollset) * num_listensocks); 
     1900    pollset[0].p = pchild; 
     1901    for (i = 0; i < num_listensocks; i++) { 
     1902        pollset[i].desc.s = listensocks[i].sd; 
     1903        pollset[i].desc_type = APR_POLL_SOCKET; 
     1904        pollset[i].reqevents = APR_POLLIN; 
     1905    } 
     1906 
     1907    mpm_state = AP_MPMQ_RUNNING; 
     1908 
     1909    bucket_alloc = apr_bucket_alloc_create(pchild); 
     1910 
     1911    while (!die_now) { 
     1912        /* 
     1913         * (Re)initialize this child to a pre-connection state. 
     1914         */ 
     1915 
     1916        current_conn = NULL; 
     1917 
     1918        apr_pool_clear(ptrans); 
     1919 
     1920        if (CHILD_INFO_TABLE[my_child_num].type != CHILD_TYPE_MULTIPLEXER 
     1921             && ap_max_requests_per_child > 0 
     1922             && requests_this_child++ >= ap_max_requests_per_child) { 
     1923            _DBG("max requests reached, dying now", 0); 
     1924            clean_child_exit(0); 
     1925        } 
     1926 
     1927        (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); 
     1928 
     1929        CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY; 
     1930        _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); 
     1931 
     1932        /* 
     1933         * Wait for an acceptable connection to arrive. 
     1934         */ 
     1935 
     1936        /* Lock around "accept", if necessary */ 
     1937        if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { 
     1938            SAFE_ACCEPT(accept_mutex_on()); 
     1939        } 
     1940 
     1941        if (num_listensocks == 1) { 
     1942            offset = 0; 
     1943        } 
     1944        else { 
     1945            /* multiple listening sockets - need to poll */ 
     1946            for (;;) { 
     1947                apr_status_t ret; 
     1948                apr_int32_t n; 
     1949 
     1950                ret = apr_poll(pollset, num_listensocks, &n, -1); 
     1951                if (ret != APR_SUCCESS) { 
     1952                    if (APR_STATUS_IS_EINTR(ret)) { 
     1953                        continue; 
     1954                    } 
     1955                    /* Single Unix documents select as returning errnos 
     1956                     * EBADF, EINTR, and EINVAL... and in none of those 
     1957                     * cases does it make sense to continue.  In fact 
     1958                     * on Linux 2.0.x we seem to end up with EFAULT 
     1959                     * occasionally, and we'd loop forever due to it. 
     1960                     */ 
     1961                    ap_log_error(APLOG_MARK, APLOG_ERR, ret, ap_server_conf, 
     1962                             "apr_poll: (listen)"); 
     1963                    clean_child_exit(1); 
     1964                } 
     1965                /* find a listener */ 
     1966                curr_pollfd = last_pollfd; 
     1967                do { 
     1968                    curr_pollfd++; 
     1969                    if (curr_pollfd >= num_listensocks) { 
     1970                        curr_pollfd = 0; 
     1971                    } 
     1972                    /* XXX: Should we check for POLLERR? */ 
     1973                    if (pollset[curr_pollfd].rtnevents & APR_POLLIN) { 
     1974                        last_pollfd = curr_pollfd; 
     1975                        offset = curr_pollfd; 
     1976                        goto got_fd; 
     1977                    } 
     1978                } while (curr_pollfd != last_pollfd); 
     1979 
     1980                continue; 
     1981            } 
     1982        } 
     1983    got_fd: 
     1984        _DBG("input available ... resetting socket.",0); 
     1985        sock = NULL;    /* important! */ 
     1986 
     1987        /* if we accept() something we don't want to die, so we have to 
     1988         * defer the exit 
     1989         */ 
     1990        status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans); 
     1991 
     1992        if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) { 
     1993            SAFE_ACCEPT(accept_mutex_off());    /* unlock after "accept" */ 
     1994        } 
     1995 
     1996        if (status == APR_EGENERAL) { 
     1997            /* resource shortage or should-not-occur occured */ 
     1998            clean_child_exit(1); 
     1999        } 
     2000        else if (status != APR_SUCCESS || die_now || sock == NULL) { 
     2001            continue; 
     2002        } 
     2003 
     2004        if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) { 
     2005            CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE; 
     2006            _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type)); 
     2007        } 
     2008 
     2009        if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR || 
     2010            CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER || 
     2011            CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) 
     2012        { 
     2013          _DBG("CHECKING IF WE SHOULD CLONE A CHILD..."); 
     2014 
     2015          _DBG("total_processors = %d, max_processors = %d", 
     2016            total_processors(my_child_num), 
     2017            CHILD_INFO_TABLE[my_child_num].senv->max_processors); 
     2018 
     2019          _DBG("idle_processors = %d, min_free_processors = %d", 
     2020            idle_processors(my_child_num), 
     2021            CHILD_INFO_TABLE[my_child_num].senv->min_free_processors); 
     2022 
     2023          if(total_processors(my_child_num) < 
     2024              CHILD_INFO_TABLE[my_child_num].senv->max_processors && 
     2025            (idle_processors(my_child_num) <= 
     2026              CHILD_INFO_TABLE[my_child_num].senv->min_free_processors || 
     2027             total_processors(my_child_num) < 
     2028              CHILD_INFO_TABLE[my_child_num].senv->min_processors 
     2029            )) 
     2030          { 
     2031              _DBG("CLONING CHILD"); 
     2032              child_clone(); 
     2033          } 
     2034        } 
     2035 
     2036        if (!setjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer)) 
     2037        { 
     2038            _DBG("marked jmpbuffer",0); 
     2039            _TRACE_CALL("process_socket()",0); 
     2040            process_socket(ptrans, sock, my_child_num, bucket_alloc, pchild); 
     2041            _TRACE_RET("process_socket()",0); 
     2042        } 
     2043        else 
     2044        { 
     2045            _DBG("landed from longjmp",0); 
     2046            CHILD_INFO_TABLE[my_child_num].sock_fd = AP_PERUSER_THISCHILD; 
     2047        } 
     2048 
     2049        /* Check the pod and the generation number after processing a 
     2050         * connection so that we'll go away if a graceful restart occurred 
     2051         * while we were processing the connection or we are the lucky 
     2052         * idle server process that gets to die. 
     2053         */ 
     2054        if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ 
     2055            _DBG("ap_mpm_pod_check(pod) = APR_SUCCESS; dying now", 0); 
     2056            die_now = 1; 
     2057        } 
     2058        else if (ap_my_generation != 
     2059                 ap_scoreboard_image->global->running_generation) { /* restart? */ 
     2060            /* yeah, this could be non-graceful restart, in which case the 
     2061             * parent will kill us soon enough, but why bother checking? 
     2062             */ 
     2063            _DBG("ap_my_generation != ap_scoreboard_image->global->running_generation; dying now", 0); 
     2064            die_now = 1; 
     2065        } 
     2066 
     2067        if(CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_RESTART) 
     2068        { 
     2069            _DBG("restarting", 0); 
     2070            die_now = 1; 
     2071        } 
     2072    } 
     2073 
     2074    _DBG("clean_child_exit(0)"); 
     2075    clean_child_exit(0); 
     2076} 
     2077 
     2078static server_env_t* find_senv_by_name(const char *name) { 
     2079    int i; 
     2080 
     2081    if (name == NULL) return NULL; 
     2082 
     2083    _DBG("name=%s", name); 
     2084 
     2085    for(i = 0; i < NUM_SENV; i++) 
     2086      { 
     2087          if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) { 
     2088              return &SENV[i]; 
     2089          } 
     2090      } 
     2091 
     2092    return NULL; 
     2093} 
     2094 
     2095static server_env_t* find_matching_senv(server_env_t* senv) { 
     2096    int i; 
     2097 
     2098    _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot); 
     2099 
     2100    for(i = 0; i < NUM_SENV; i++) 
     2101      { 
     2102          if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) || 
     2103             (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid && 
     2104              ( 
     2105               (SENV[i].chroot == NULL && senv->chroot == NULL) || 
     2106               ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot))) 
     2107              ) 
     2108             ) { 
     2109              return &SENV[i]; 
     2110          } 
     2111      } 
     2112 
     2113    return NULL; 
     2114} 
     2115 
     2116static server_env_t* senv_add(server_env_t *senv) 
     2117{ 
     2118    int socks[2]; 
     2119    server_env_t *old_senv; 
     2120 
     2121    _DBG("Searching for matching senv..."); 
     2122 
     2123    old_senv = find_matching_senv(senv); 
     2124 
     2125    if (old_senv) { 
     2126        _DBG("Found existing senv"); 
     2127        senv = old_senv; 
     2128        return old_senv; 
     2129    } 
     2130 
     2131    if(NUM_SENV >= server_limit) 
     2132      { 
     2133          _DBG("server_limit reached!"); 
     2134          return NULL; 
     2135      } 
     2136 
     2137    _DBG("Creating new senv"); 
     2138 
     2139    memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t)); 
     2140 
     2141    SENV[NUM_SENV].availability = 100; 
     2142 
     2143    socketpair(PF_UNIX, SOCK_STREAM, 0, socks); 
     2144    SENV[NUM_SENV].input  = socks[0]; 
     2145    SENV[NUM_SENV].output = socks[1]; 
     2146 
     2147    senv = &SENV[NUM_SENV]; 
     2148    return &SENV[server_env_image->control->num++]; 
     2149} 
     2150 
     2151 
     2152static const char* child_clone() 
     2153{ 
     2154    int i; 
     2155    child_info_t *this; 
     2156    child_info_t *new; 
     2157 
     2158    for(i = 0; i < NUM_CHILDS; i++) 
     2159    { 
     2160      if(CHILD_INFO_TABLE[i].pid == 0 && 
     2161         CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) break; 
     2162    } 
     2163     
     2164    if(i == NUM_CHILDS && NUM_CHILDS >= server_limit) 
     2165    { 
     2166        _DBG("Trying to use more child ID's than ServerLimit.  " 
     2167               "Increase ServerLimit in your config file."); 
     2168        return NULL; 
     2169    }     
     2170 
     2171    _DBG("cloning child #%d from #%d", i, my_child_num); 
     2172 
     2173    this = &CHILD_INFO_TABLE[my_child_num]; 
     2174    new = &CHILD_INFO_TABLE[i]; 
     2175 
     2176    new->senv = this->senv; 
     2177 
     2178    if (this->type == CHILD_TYPE_MULTIPLEXER) { 
     2179        new->type = CHILD_TYPE_MULTIPLEXER; 
     2180    } 
     2181    else { 
     2182        new->type = CHILD_TYPE_WORKER; 
     2183    } 
     2184 
     2185    new->sock_fd = this->sock_fd; 
     2186    new->status = CHILD_STATUS_STARTING; 
     2187 
     2188    if(i == NUM_CHILDS) child_info_image->control->num++; 
     2189    return NULL; 
     2190} 
     2191 
     2192static const char* child_add(int type, int status, 
     2193                             apr_pool_t *pool, server_env_t *senv) 
     2194{ 
     2195    _DBG("adding child #%d", NUM_CHILDS); 
     2196 
     2197    if(NUM_CHILDS >= server_limit) 
     2198    { 
     2199        return "Trying to use more child ID's than ServerLimit.  " 
     2200               "Increase ServerLimit in your config file."; 
     2201    } 
     2202 
     2203       if (senv->chroot && !ap_is_directory(pool, senv->chroot)) 
     2204               return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot); 
     2205 
     2206    CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv); 
     2207 
     2208    if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL) 
     2209    { 
     2210        return "Trying to use more server environments than ServerLimit.  " 
     2211               "Increase ServerLimit in your config file."; 
     2212    } 
     2213 
     2214    if(type != CHILD_TYPE_WORKER) 
     2215        CHILD_INFO_TABLE[NUM_CHILDS].senv->processor_id = NUM_CHILDS; 
     2216 
     2217    CHILD_INFO_TABLE[NUM_CHILDS].type = type; 
     2218    CHILD_INFO_TABLE[NUM_CHILDS].sock_fd = AP_PERUSER_THISCHILD; 
     2219    CHILD_INFO_TABLE[NUM_CHILDS].status = status; 
     2220 
     2221    _DBG("[%d] uid=%d gid=%d type=%d chroot=%s", 
     2222         NUM_CHILDS, senv->uid, senv->gid, type, 
     2223         senv->chroot); 
     2224 
     2225    if (senv->uid == 0 || senv->gid == 0) 
     2226    { 
     2227        _DBG("Assigning root user/group to a child.", 0); 
     2228    } 
     2229 
     2230    child_info_image->control->num++; 
     2231 
     2232    return NULL; 
     2233} 
     2234 
     2235static int make_child(server_rec *s, int slot) 
     2236{ 
     2237    int pid; 
     2238 
     2239    _DBG("function entered", 0); 
     2240    dump_server_env_image(); 
     2241 
     2242    switch (CHILD_INFO_TABLE[slot].type) 
     2243    { 
     2244        case CHILD_TYPE_MULTIPLEXER: break; 
     2245        case CHILD_TYPE_PROCESSOR: break; 
     2246        case CHILD_TYPE_WORKER: break; 
     2247 
     2248        default: 
     2249            _DBG("no valid client in slot %d", slot); 
     2250            /* sleep(1); */ 
     2251            return 0; 
     2252    } 
     2253 
     2254    if (slot + 1 > ap_max_daemons_limit) { 
     2255        ap_max_daemons_limit = slot + 1; 
     2256    } 
     2257 
     2258    if (one_process) { 
     2259        apr_signal(SIGHUP, just_die); 
     2260        /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */ 
     2261        apr_signal(SIGINT, just_die); 
     2262#ifdef SIGQUIT 
     2263        apr_signal(SIGQUIT, SIG_DFL); 
     2264#endif 
     2265        apr_signal(SIGTERM, just_die); 
     2266        child_main(slot); 
     2267    } 
     2268 
     2269    (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, 
     2270                                               (request_rec *) NULL); 
     2271 
     2272    CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY; 
     2273 
     2274 
     2275#ifdef _OSD_POSIX 
     2276    /* BS2000 requires a "special" version of fork() before a setuid() call */ 
     2277    if ((pid = os_fork(unixd_config.user_name)) == -1) { 
     2278#elif defined(TPF) 
     2279    if ((pid = os_fork(s, slot)) == -1) { 
     2280#else 
     2281    if ((pid = fork()) == -1) { 
     2282#endif 
     2283        ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process"); 
     2284 
     2285        /* fork didn't succeed. Fix the scoreboard or else 
     2286         * it will say SERVER_STARTING forever and ever 
     2287         */ 
     2288        (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, 
     2289                                                   (request_rec *) NULL); 
     2290 
     2291        /* In case system resources are maxxed out, we don't want 
     2292           Apache running away with the CPU trying to fork over and 
     2293           over and over again. */ 
     2294        sleep(10); 
     2295 
     2296        return -1; 
     2297    } 
     2298 
     2299    if (!pid) { 
     2300#ifdef HAVE_BINDPROCESSOR 
     2301        /* by default AIX binds to a single processor 
     2302         * this bit unbinds children which will then bind to another cpu 
     2303         */ 
     2304        int status = bindprocessor(BINDPROCESS, (int)getpid(),  
     2305                                   PROCESSOR_CLASS_ANY); 
     2306        if (status != OK) { 
     2307            ap_log_error(APLOG_MARK, APLOG_WARNING, errno,  
     2308                         ap_server_conf, "processor unbind failed %d", status); 
     2309        } 
     2310#endif 
     2311        RAISE_SIGSTOP(MAKE_CHILD); 
     2312        AP_MONCONTROL(1); 
     2313        /* Disable the parent's signal handlers and set up proper handling in 
     2314         * the child. 
     2315         */ 
     2316        apr_signal(SIGHUP, just_die); 
     2317        apr_signal(SIGTERM, just_die); 
     2318        /* The child process doesn't do anything for AP_SIG_GRACEFUL.   
     2319         * Instead, the pod is used for signalling graceful restart. 
     2320         */ 
     2321        /* apr_signal(AP_SIG_GRACEFUL, restart); */ 
     2322        child_main(slot); 
     2323        clean_child_exit(0); 
     2324    } 
     2325 
     2326    ap_scoreboard_image->parent[slot].pid = pid; 
     2327    CHILD_INFO_TABLE[slot].pid    = pid; 
     2328 
     2329    ap_child_table[slot].pid    = pid; 
     2330    ap_child_table[slot].status = SERVER_ALIVE; 
     2331 
     2332    return 0; 
     2333} 
     2334 
     2335 
     2336/* 
     2337 * idle_spawn_rate is the number of children that will be spawned on the 
     2338 * next maintenance cycle if there aren't enough idle servers.  It is 
     2339 * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by 
     2340 * without the need to spawn. 
     2341 */ 
     2342static int idle_spawn_rate = 1; 
     2343#ifndef MAX_SPAWN_RATE 
     2344#define MAX_SPAWN_RATE  (32) 
     2345#endif 
     2346static int total_processes(int child_num) 
     2347{ 
     2348    int i, total; 
     2349    for(i = 0, total = 0; i < NUM_CHILDS; ++i) 
     2350    { 
     2351        if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv && 
     2352           (!(CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR && 
     2353           CHILD_INFO_TABLE[i].status == CHILD_STATUS_STANDBY))) 
     2354        { 
     2355           total++; 
     2356        } 
     2357    } 
     2358    return total; 
     2359} 
     2360 
     2361static void perform_idle_server_maintenance(apr_pool_t *p) 
     2362{ 
     2363    int i; 
     2364    apr_time_t now; 
     2365 
     2366    /* _DBG("function entered", 0); */ 
     2367 
     2368    now = apr_time_now(); 
     2369 
     2370    for (i = 0; i < NUM_CHILDS; ++i) 
     2371    { 
     2372      if(CHILD_INFO_TABLE[i].pid == 0) 
     2373      { 
     2374        if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING) 
     2375          make_child(ap_server_conf, i); 
     2376      } 
     2377      else if( 
     2378              (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR || 
     2379                 CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER)  && 
     2380                ap_scoreboard_image->parent[i].pid > 1) && 
     2381               (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) && 
     2382               total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors &&  
     2383               ( 
     2384                (expire_timeout > 0 &&  ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&  
     2385                 apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) || 
     2386                (idle_timeout >   0 &&  ap_scoreboard_image->servers[i][0].status == SERVER_READY &&   
     2387                 apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) || 
     2388                (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY && 
     2389                 idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors)) 
     2390               ) 
     2391              || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER && 
     2392                  (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY && 
     2393                   apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) && 
     2394                  total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors 
     2395                  ) 
     2396            ) 
     2397      { 
     2398        CHILD_INFO_TABLE[i].pid = 0; 
     2399        CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY; 
     2400 
     2401        if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER) 
     2402        { 
     2403          /* completely free up this slot */ 
     2404 
     2405          CHILD_INFO_TABLE[i].senv    = (server_env_t*)NULL; 
     2406          CHILD_INFO_TABLE[i].type    = CHILD_TYPE_UNKNOWN; 
     2407          CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */ 
     2408        } 
     2409        if(kill(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1) 
     2410        { 
     2411          ap_log_error(APLOG_MARK, APLOG_WARNING, errno, 
     2412            ap_server_conf, "kill SIGTERM"); 
     2413        } 
     2414        
     2415 
     2416        ap_update_child_status_from_indexes(i, 0, SERVER_DEAD, NULL); 
     2417      } 
     2418    } 
     2419     
     2420    for(i=0;i<grace_children;i++) { 
     2421       if (child_grace_info_table[i].pid > 0 && expire_timeout > 0 && 
     2422                       apr_time_sec(now - child_grace_info_table[i].last_used) > expire_timeout) { 
     2423                
     2424               _DBG("Killing a child from last graceful (pid=%d,childno=%d,last_used=%d)",  
     2425                               child_grace_info_table[i].pid, child_grace_info_table[i].id, 
     2426                               child_grace_info_table[i].last_used); 
     2427             
     2428               if(kill(child_grace_info_table[i].pid, SIGTERM) == -1) 
     2429            { 
     2430              ap_log_error(APLOG_MARK, APLOG_WARNING, errno, 
     2431                ap_server_conf, "kill SIGTERM"); 
     2432            } 
     2433                
     2434               /*      We don't need to do remove_grace_child() here, 
     2435                *  because it will be automatically done once  
     2436                *  the child dies by ap_mpm_run() */ 
     2437       } 
     2438    } 
     2439} 
     2440 
     2441int remove_grace_child(int slot) { 
     2442       if (slot < grace_children) { 
     2443               child_grace_info_table[slot].id = 0; 
     2444               child_grace_info_table[slot].pid = 0; 
     2445               child_grace_info_table[slot].status = CHILD_STATUS_STANDBY; 
     2446               child_grace_info_table[slot].type = CHILD_TYPE_UNKNOWN; 
     2447               child_grace_info_table[slot].last_used = 0; 
     2448               grace_children_alive--; 
     2449                
     2450               if (grace_children_alive <= 0) { /*     All children have returned from graceful        */ 
     2451                       _DBG("Every child has returned from graceful restart - freeing child_grace_info_table"); 
     2452                       grace_children_alive = 0; 
     2453                       is_graceful = 0; 
     2454                       grace_children = 0; 
     2455                       free(child_grace_info_table); 
     2456               } 
     2457               return 0; 
     2458       } 
     2459       return 1; 
     2460} 
     2461 
     2462/***************************************************************** 
     2463 * Executive routines. 
     2464 */ 
     2465 
     2466int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) 
     2467{ 
     2468    int i; 
     2469/*    int fd; */ 
     2470    apr_status_t rv; 
     2471    apr_size_t one = 1; 
     2472/*    apr_socket_t *sock = NULL; */ 
     2473 
     2474    ap_log_pid(pconf, ap_pid_fname); 
     2475 
     2476    first_server_limit = server_limit; 
     2477    if (changed_limit_at_restart) { 
     2478        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, 
     2479                     "WARNING: Attempt to change ServerLimit " 
     2480                     "ignored during restart"); 
     2481        changed_limit_at_restart = 0; 
     2482    } 
     2483 
     2484    ap_server_conf = s; 
     2485 
     2486    /* Initialize cross-process accept lock */ 
     2487    ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT, 
     2488                                 ap_server_root_relative(_pconf, ap_lock_fname), 
     2489                                 ap_my_pid); 
     2490 
     2491    rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,  
     2492                               ap_accept_lock_mech, _pconf); 
     2493    if (rv != APR_SUCCESS) { 
     2494        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 
     2495                     "Couldn't create accept lock"); 
     2496        mpm_state = AP_MPMQ_STOPPING; 
     2497        return 1; 
     2498    } 
     2499 
     2500#if APR_USE_SYSVSEM_SERIALIZE 
     2501    if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||  
     2502        ap_accept_lock_mech == APR_LOCK_SYSVSEM) { 
     2503#else 
     2504    if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) { 
     2505#endif 
     2506        rv = unixd_set_proc_mutex_perms(accept_mutex); 
     2507        if (rv != APR_SUCCESS) { 
     2508            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 
     2509                         "Couldn't set permissions on cross-process lock; " 
     2510                         "check User and Group directives"); 
     2511            mpm_state = AP_MPMQ_STOPPING; 
     2512            return 1; 
     2513        } 
     2514    } 
     2515 
     2516    if (!is_graceful) { 
     2517        if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { 
     2518            mpm_state = AP_MPMQ_STOPPING; 
     2519            return 1; 
     2520        } 
     2521        /* fix the generation number in the global score; we just got a new, 
     2522         * cleared scoreboard 
     2523         */ 
     2524        ap_scoreboard_image->global->running_generation = ap_my_generation; 
     2525    } 
     2526 
     2527    /* Initialize the child table */ 
     2528    if (!is_graceful) 
     2529    { 
     2530        for (i = 0; i < server_limit; i++) 
     2531        { 
     2532            ap_child_table[i].pid = 0; 
     2533        } 
     2534    } 
     2535 
     2536    /* We need to put the new listeners at the end of the ap_listeners 
     2537     * list.  If we don't, then the pool will be cleared before the 
     2538     * open_logs phase is called for the second time, and ap_listeners 
     2539     * will have only invalid data.  If that happens, then the sockets 
     2540     * that we opened using make_sock() will be lost, and the server 
     2541     * won't start. 
     2542     */ 
     2543 
     2544/* 
     2545    apr_os_file_get(&fd, pipe_of_death_in); 
     2546    apr_os_sock_put(&sock, &fd, pconf); 
     2547 
     2548    listen_add(pconf, sock, check_pipe_of_death); 
     2549*/ 
     2550    set_signals(); 
     2551 
     2552    if (one_process) { 
     2553        AP_MONCONTROL(1); 
     2554    } 
     2555 
     2556    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2557                "%s configured -- resuming normal operations", 
     2558                ap_get_server_version()); 
     2559    ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, 
     2560                "Server built: %s", ap_get_server_built()); 
     2561#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH 
     2562    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 
     2563                "AcceptMutex: %s (default: %s)", 
     2564                apr_proc_mutex_name(accept_mutex), 
     2565                apr_proc_mutex_defname()); 
     2566#endif 
     2567    restart_pending = shutdown_pending = 0; 
     2568 
     2569    mpm_state = AP_MPMQ_RUNNING; 
     2570 
     2571    _DBG("sizeof(child_info_t) = %d", sizeof(child_info_t)); 
     2572 
     2573    while (!restart_pending && !shutdown_pending) { 
     2574        int child_slot; 
     2575        apr_exit_why_e exitwhy; 
     2576        int status, processed_status; 
     2577        /* this is a memory leak, but I'll fix it later. */ 
     2578        apr_proc_t pid; 
     2579 
     2580        ap_wait_or_timeout(&exitwhy, &status, &pid, pconf); 
     2581 
     2582        /* XXX: if it takes longer than 1 second for all our children 
     2583         * to start up and get into IDLE state then we may spawn an 
     2584         * extra child 
     2585         */ 
     2586        if (pid.pid != -1) { 
     2587            processed_status = ap_process_child_status(&pid, exitwhy, status); 
     2588            if (processed_status == APEXIT_CHILDFATAL) { 
     2589                mpm_state = AP_MPMQ_STOPPING; 
     2590                return 1; 
     2591            } 
     2592             
     2593            if (grace_children > 0) { 
     2594               for(i=0;i<grace_children;i++) { 
     2595                       if (child_grace_info_table[i].pid == pid.pid) { 
     2596                               break; 
     2597                       } 
     2598               } 
     2599               if (i != grace_children) { 
     2600                       _DBG("Child returned from graceful (%d)", i); 
     2601                       remove_grace_child(i); 
     2602                       continue; 
     2603               } 
     2604            } 
     2605 
     2606            /* non-fatal death... note that it's gone in the scoreboard. */ 
     2607            child_slot = find_child_by_pid(&pid); 
     2608            _DBG("child #%d has died ...", child_slot); 
     2609 
     2610            for (i = 0; i < ap_max_daemons_limit; ++i) 
     2611            { 
     2612                if (ap_child_table[i].pid == pid.pid) 
     2613                { 
     2614                    child_slot = i; 
     2615                    break; 
     2616                } 
     2617            } 
     2618 
     2619            if (child_slot >= 0) { 
     2620                ap_child_table[child_slot].pid = 0; 
     2621                _TRACE_CALL("ap_update_child_status_from_indexes", 0); 
     2622                (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD, 
     2623                                                           (request_rec *) NULL); 
     2624                _TRACE_RET("ap_update_child_status_from_indexes", 0); 
     2625 
     2626                if (processed_status == APEXIT_CHILDSICK) { 
     2627                    /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc) 
     2628                     * cut the fork rate to the minimum  
     2629                     */ 
     2630                    _DBG("processed_status = APEXIT_CHILDSICK", 0); 
     2631                    idle_spawn_rate = 1;  
     2632                } 
     2633                else if (CHILD_INFO_TABLE[child_slot].status == CHILD_STATUS_STANDBY) { 
     2634                    _DBG("leaving child in standby state", 0); 
     2635                } 
     2636                else if (child_slot < ap_daemons_limit && 
     2637                         CHILD_INFO_TABLE[child_slot].type != 
     2638                           CHILD_TYPE_UNKNOWN) { 
     2639                    /* we're still doing a 1-for-1 replacement of dead 
     2640                        * children with new children 
     2641                        */ 
     2642                    _DBG("replacing by new child ...", 0); 
     2643                    make_child(ap_server_conf, child_slot); 
     2644                } 
     2645#if APR_HAS_OTHER_CHILD 
     2646            } 
     2647            else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) { 
     2648                _DBG("Already handled", 0); 
     2649                /* handled */ 
     2650#endif 
     2651            } 
     2652            else if (is_graceful) { 
     2653                /* Great, we've probably just lost a slot in the 
     2654                    * scoreboard.  Somehow we don't know about this 
     2655                    * child. 
     2656                    */ 
     2657                _DBG("long lost child came home, whatever that means", 0); 
     2658 
     2659                ap_log_error(APLOG_MARK, APLOG_WARNING,  
     2660                            0, ap_server_conf, 
     2661                            "long lost child came home! (pid %ld)", (long)pid.pid); 
     2662            } 
     2663            /* Don't perform idle maintenance when a child dies, 
     2664                * only do it when there's a timeout.  Remember only a 
     2665                * finite number of children can die, and it's pretty 
     2666                * pathological for a lot to die suddenly. 
     2667                */ 
     2668            continue; 
     2669        } 
     2670 
     2671        perform_idle_server_maintenance(pconf); 
     2672         
     2673#ifdef TPF 
     2674        shutdown_pending = os_check_server(tpf_server_name); 
     2675        ap_check_signals(); 
     2676        sleep(1); 
     2677#endif /*TPF */ 
     2678    } 
     2679 
     2680    mpm_state = AP_MPMQ_STOPPING; 
     2681 
     2682    if (shutdown_pending) { 
     2683        /* Time to gracefully shut down: 
     2684         * Kill child processes, tell them to call child_exit, etc... 
     2685         */ 
     2686        if (unixd_killpg(getpgrp(), SIGTERM) < 0) { 
     2687            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM"); 
     2688        } 
     2689        ap_reclaim_child_processes(1);          /* Start with SIGTERM */ 
     2690 
     2691        /* cleanup pid file on normal shutdown */ 
     2692        { 
     2693            const char *pidfile = NULL; 
     2694            pidfile = ap_server_root_relative (pconf, ap_pid_fname); 
     2695            if ( pidfile != NULL && unlink(pidfile) == 0) 
     2696                ap_log_error(APLOG_MARK, APLOG_INFO, 
     2697                                0, ap_server_conf, 
     2698                                "removed PID file %s (pid=%ld)", 
     2699                                pidfile, (long)getpid()); 
     2700        } 
     2701 
     2702        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2703                    "caught SIGTERM, shutting down"); 
     2704        return 1; 
     2705    } 
     2706 
     2707    /* we've been told to restart */ 
     2708    apr_signal(SIGHUP, SIG_IGN); 
     2709    if (one_process) { 
     2710        /* not worth thinking about */ 
     2711        return 1; 
     2712    } 
     2713 
     2714    /* advance to the next generation */ 
     2715    /* XXX: we really need to make sure this new generation number isn't in 
     2716     * use by any of the children. 
     2717     */ 
     2718    ++ap_my_generation; 
     2719    ap_scoreboard_image->global->running_generation = ap_my_generation; 
     2720     
     2721    /* cleanup sockets */ 
     2722    for (i = 0; i < NUM_SENV; i++) { 
     2723        close(SENV[i].input); 
     2724        close(SENV[i].output); 
     2725    } 
     2726 
     2727    if (is_graceful) { 
     2728        char char_of_death = AP_PERUSER_CHAR_OF_DEATH; 
     2729 
     2730        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2731                    "Graceful restart requested, doing restart"); 
     2732 
     2733#if 0 
     2734        /* kill off the idle ones */ 
     2735        ap_mpm_pod_killpg(pod, ap_max_daemons_limit); 
     2736 
     2737        /* This is mostly for debugging... so that we know what is still 
     2738            * gracefully dealing with existing request.  This will break 
     2739            * in a very nasty way if we ever have the scoreboard totally 
     2740            * file-based (no shared memory) 
     2741            */ 
     2742        for (i = 0; i < ap_daemons_limit; ++i) { 
     2743            if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { 
     2744                ap_scoreboard_image->servers[i][0].status = SERVER_GRACEFUL; 
     2745            } 
     2746        } 
     2747#endif 
     2748 
     2749        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, 
     2750                     ap_server_conf, AP_SIG_GRACEFUL_STRING " received.  " 
     2751                     "Doing graceful restart"); 
     2752 
     2753        /* This is mostly for debugging... so that we know what is still 
     2754         * gracefully dealing with existing request. 
     2755         */ 
     2756 
     2757        int alivechildren = 0; 
     2758        child_grace_info_t* old_grace_info; 
     2759 
     2760        for (i = 0; i < NUM_CHILDS; ++i) 
     2761        { 
     2762            ((ap_child_table[i].pid) && (ap_child_table[i].status = SERVER_DYING)); 
     2763             
     2764            if (CHILD_INFO_TABLE[i].pid) { 
     2765               alivechildren++; 
     2766            } 
     2767        } 
     2768         
     2769        _DBG("Initializing child_grace_info_table", 0); 
     2770         
     2771        if (alivechildren > 0) { 
     2772               if (grace_children > 0) { 
     2773                       old_grace_info = child_grace_info_table; 
     2774                       _DBG("%d children still living from last graceful " 
     2775                                       "- adding to new child_grace_info_table",  
     2776                                       grace_children); 
     2777               } 
     2778                
     2779               child_grace_info_table = (child_grace_info_t*)calloc(alivechildren+grace_children, 
     2780                               sizeof(child_grace_info_t)); 
     2781                
     2782               if (grace_children > 0) { 
     2783                       for(i=0;i<grace_children;i++) { 
     2784                               child_grace_info_table[i] = old_grace_info[i]; 
     2785                       } 
     2786                       grace_children = i; 
     2787                       free(old_grace_info); 
     2788               } 
     2789               else grace_children = 0; 
     2790                
     2791        } 
     2792 
     2793        /* give the children the signal to die */ 
     2794        for (i = 0; i < NUM_CHILDS;) 
     2795        { 
     2796            if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) 
     2797            { 
     2798                if (APR_STATUS_IS_EINTR(rv)) continue; 
     2799                ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, 
     2800                             "write pipe_of_death"); 
     2801            } 
     2802            if (CHILD_INFO_TABLE[i].pid) { 
     2803               child_grace_info_table[grace_children].id               = CHILD_INFO_TABLE[i].id; 
     2804               child_grace_info_table[grace_children].pid              = CHILD_INFO_TABLE[i].pid; 
     2805               child_grace_info_table[grace_children].status   = CHILD_INFO_TABLE[i].status; 
     2806               child_grace_info_table[grace_children].type     = CHILD_INFO_TABLE[i].type; 
     2807               child_grace_info_table[grace_children].last_used= ap_scoreboard_image->servers[i][0].last_used; 
     2808               grace_children++; 
     2809               grace_children_alive++; 
     2810            } 
     2811            i++; 
     2812        } 
     2813        _DBG("Total children of %d leaving behind for graceful restart (%d living)",  
     2814                       grace_children, grace_children_alive); 
     2815    } 
     2816    else { 
     2817        /* Kill 'em off */ 
     2818        if (unixd_killpg(getpgrp(), SIGHUP) < 0) { 
     2819            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP"); 
     2820        } 
     2821        ap_reclaim_child_processes(0);          /* Not when just starting up */ 
     2822        ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, 
     2823                    "SIGHUP received.  Attempting to restart"); 
     2824    } 
     2825 
     2826    return 0; 
     2827} 
     2828 
     2829/* == allocate an private server config structure == */ 
     2830static void *peruser_create_config(apr_pool_t *p, server_rec *s) 
     2831{ 
     2832    peruser_server_conf *c = (peruser_server_conf *) 
     2833                                  apr_pcalloc(p, sizeof(peruser_server_conf)); 
     2834 
     2835    c->senv = NULL; 
     2836    c->missing_senv_reported = 0; 
     2837 
     2838    return c; 
     2839} 
     2840 
     2841/* This really should be a post_config hook, but the error log is already 
     2842 * redirected by that point, so we need to do this in the open_logs phase. 
     2843 */ 
     2844static int peruser_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) 
     2845{ 
     2846    apr_status_t rv; 
     2847 
     2848    pconf = p; 
     2849    ap_server_conf = s; 
     2850 
     2851    if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { 
     2852        ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,  
     2853                     NULL, "no listening sockets available, shutting down"); 
     2854        return DONE; 
     2855    } 
     2856 
     2857    ap_log_pid(pconf, ap_pid_fname); 
     2858 
     2859    if ((rv = ap_mpm_pod_open(pconf, &pod))) { 
     2860        ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL, 
     2861                "Could not open pipe-of-death."); 
     2862        return DONE; 
     2863    } 
     2864 
     2865    if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, 
     2866                                   pconf)) != APR_SUCCESS) { 
     2867        ap_log_error(APLOG_MARK, APLOG_ERR, rv, 
     2868                     (const server_rec*) ap_server_conf, 
     2869                     "apr_file_pipe_create (pipe_of_death)"); 
     2870        exit(1); 
     2871    } 
     2872    if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) { 
     2873        ap_log_error(APLOG_MARK, APLOG_ERR, rv, 
     2874                     (const server_rec*) ap_server_conf, 
     2875                     "apr_file_pipe_timeout_set (pipe_of_death)"); 
     2876        exit(1); 
     2877    } 
     2878 
     2879    return OK; 
     2880} 
     2881 
     2882static int restart_num = 0; 
     2883static int peruser_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) 
     2884{ 
     2885    int no_detach, debug, foreground, i; 
     2886    int tmp_server_limit = DEFAULT_SERVER_LIMIT; 
     2887    ap_directive_t *pdir; 
     2888    apr_status_t rv; 
     2889    apr_pool_t *global_pool; 
     2890    void *shmem; 
     2891 
     2892    mpm_state = AP_MPMQ_STARTING; 
     2893 
     2894    debug = ap_exists_config_define("DEBUG"); 
     2895 
     2896    if (debug) { 
     2897        foreground = one_process = 1; 
     2898        no_detach = 0; 
     2899    } 
     2900    else 
     2901    { 
     2902        no_detach = ap_exists_config_define("NO_DETACH"); 
     2903        one_process = ap_exists_config_define("ONE_PROCESS"); 
     2904        foreground = ap_exists_config_define("FOREGROUND"); 
     2905    } 
     2906 
     2907    /* sigh, want this only the second time around */ 
     2908    if (restart_num++ == 1) { 
     2909        if (!one_process && !foreground) { 
     2910            rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND 
     2911                                           : APR_PROC_DETACH_DAEMONIZE); 
     2912            if (rv != APR_SUCCESS) { 
     2913                ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     2914                             "apr_proc_detach failed"); 
     2915                return HTTP_INTERNAL_SERVER_ERROR; 
     2916            } 
     2917        } 
     2918 
     2919        parent_pid = ap_my_pid = getpid(); 
     2920    } 
     2921 
     2922    unixd_pre_config(ptemp); 
     2923    ap_listen_pre_config(); 
     2924    ap_min_processors = DEFAULT_MIN_PROCESSORS; 
     2925    ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS; 
     2926    ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS; 
     2927    ap_max_processors = DEFAULT_MAX_PROCESSORS; 
     2928    ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS; 
     2929    ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS; 
     2930    ap_daemons_limit = server_limit; 
     2931    ap_pid_fname = DEFAULT_PIDLOG; 
     2932    ap_lock_fname = DEFAULT_LOCKFILE; 
     2933    ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD; 
     2934    ap_extended_status = 1; 
     2935#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE 
     2936        ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED; 
     2937#endif 
     2938 
     2939    expire_timeout = DEFAULT_EXPIRE_TIMEOUT; 
     2940    idle_timeout = DEFAULT_IDLE_TIMEOUT; 
     2941    multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT; 
     2942    processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT; 
     2943    processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS; 
     2944 
     2945 
     2946    apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir)); 
     2947 
     2948    /* we need to know ServerLimit and ThreadLimit before we start processing 
     2949     * the tree because we need to already have allocated child_info_table 
     2950     */ 
     2951    for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next) 
     2952    { 
     2953        if (!strcasecmp(pdir->directive, "ServerLimit")) 
     2954        { 
     2955            if (atoi(pdir->args) > tmp_server_limit) 
     2956            { 
     2957                tmp_server_limit = atoi(pdir->args); 
     2958                if (tmp_server_limit > MAX_SERVER_LIMIT) 
     2959                { 
     2960                    tmp_server_limit = MAX_SERVER_LIMIT; 
     2961                } 
     2962            } 
     2963        } 
     2964    } 
     2965 
     2966    /* We don't want to have to recreate the scoreboard after 
     2967     * restarts, so we'll create a global pool and never clean it. 
     2968     */ 
     2969    rv = apr_pool_create(&global_pool, NULL); 
     2970    if (rv != APR_SUCCESS) { 
     2971        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     2972                     "Fatal error: unable to create global pool"); 
     2973        return rv; 
     2974    } 
     2975 
     2976    if (!child_info_image) { 
     2977        _DBG("Initializing child_info_table", 0); 
     2978        child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t); 
     2979 
     2980        rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool); 
     2981 
     2982        /*  if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */ 
     2983        if (rv != APR_SUCCESS) { 
     2984            _DBG("shared memory creation failed", 0); 
     2985 
     2986            ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     2987                         "Unable to create shared memory segment " 
     2988                         "(anonymous shared memory failure)"); 
     2989        } 
     2990        else if (rv == APR_ENOTIMPL) { 
     2991            _DBG("anonymous shared memory not available", 0); 
     2992            /* TODO: make up a filename and do name-based shmem */ 
     2993        } 
     2994 
     2995        if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) { 
     2996            _DBG("apr_shm_baseaddr_get() failed", 0); 
     2997            return HTTP_INTERNAL_SERVER_ERROR; 
     2998        } 
     2999 
     3000        memset(shmem, 0, child_info_size); 
     3001        child_info_image = (child_info*)apr_palloc(global_pool, sizeof(child_info)); 
     3002        child_info_image->control = (child_info_control*)shmem; 
     3003        shmem += sizeof(child_info_control); 
     3004        child_info_image->table = (child_info_t*)shmem; 
     3005    } 
     3006 
     3007    _DBG("Clearing child_info_table"); 
     3008    child_info_image->control->num = 0; 
     3009 
     3010    for (i = 0; i < tmp_server_limit; i++) { 
     3011        CHILD_INFO_TABLE[i].pid     = 0; 
     3012        CHILD_INFO_TABLE[i].senv    = (server_env_t*)NULL; 
     3013        CHILD_INFO_TABLE[i].type    = CHILD_TYPE_UNKNOWN; 
     3014        CHILD_INFO_TABLE[i].status  = CHILD_STATUS_STANDBY; 
     3015        CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */ 
     3016        CHILD_INFO_TABLE[i].id      = i; 
     3017    } 
     3018 
     3019    if (!server_env_image) 
     3020    { 
     3021       _DBG("Initializing server_environments_table", 0); 
     3022       server_env_size = tmp_server_limit * sizeof(server_env_t) + sizeof(apr_size_t); 
     3023 
     3024       rv = apr_shm_create(&server_env_shm, server_env_size, NULL, global_pool); 
     3025 
     3026       if (rv != APR_SUCCESS) { 
     3027           _DBG("shared memory creation failed", 0); 
     3028 
     3029           ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, 
     3030                        "Unable to create shared memory segment " 
     3031                        "(anonymous shared memory failure)"); 
     3032        } 
     3033        else if (rv == APR_ENOTIMPL) { 
     3034            _DBG("anonymous shared memory not available", 0); 
     3035            /* TODO: make up a filename and do name-based shmem */ 
     3036        } 
     3037 
     3038        if (rv || !(shmem = apr_shm_baseaddr_get(server_env_shm))) { 
     3039            _DBG("apr_shm_baseaddr_get() failed", 0); 
     3040            return HTTP_INTERNAL_SERVER_ERROR; 
     3041        } 
     3042 
     3043        memset(shmem, 0, server_env_size); 
     3044        server_env_image = (server_env*)apr_palloc(global_pool, sizeof(server_env)); 
     3045        server_env_image->control = (server_env_control*)shmem; 
     3046        shmem += sizeof(server_env_control); 
     3047        server_env_image->table = (server_env_t*)shmem; 
     3048    } 
     3049     
     3050    _DBG("Clearing server environment table"); 
     3051    server_env_image->control->num = 0;     
     3052 
     3053    for (i = 0; i < tmp_server_limit; i++) { 
     3054        SENV[i].processor_id = -1; 
     3055        SENV[i].uid          = -1; 
     3056        SENV[i].gid          = -1; 
     3057        SENV[i].chroot       = NULL; 
     3058        SENV[i].input        = -1; 
     3059        SENV[i].output       = -1; 
     3060        SENV[i].error_cgroup = 0; 
     3061        SENV[i].error_pass   = 0; 
     3062    } 
     3063 
     3064    return OK; 
     3065} 
     3066 
     3067static int peruser_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server_list) 
     3068{ 
     3069    server_env_t senv; 
     3070    const char *r; 
     3071 
     3072    ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable)); 
     3073 
     3074    /* Retrieve the function from mod_ssl for detecting SSL virtualhosts */ 
     3075    ssl_server_is_https = (ssl_server_is_https_t) apr_dynamic_fn_retrieve("ssl_server_is_https"); 
     3076 
     3077    /* Create the server environment for multiplexers */ 
     3078    senv.uid = unixd_config.user_id; 
     3079    senv.gid = unixd_config.group_id; 
     3080    senv.chroot = multiplexer_chroot; 
     3081    senv.cgroup = NULL; 
     3082    senv.nice_lvl = 0; 
     3083    senv.name = "Multiplexer"; 
     3084 
     3085    senv.min_processors         = ap_min_multiplexers; 
     3086    senv.min_free_processors    = ap_min_free_processors; 
     3087    senv.max_free_processors    = ap_max_free_processors; 
     3088    senv.max_processors         = ap_max_multiplexers; 
     3089 
     3090    r = child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING, 
     3091                     p, &senv); 
     3092 
     3093    if (r != NULL) { 
     3094        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, p, r); 
     3095        return -1; 
     3096    } 
     3097 
     3098    return OK; 
     3099} 
     3100 
     3101static int peruser_post_read(request_rec *r) 
     3102{ 
     3103    _DBG("function entered"); 
     3104 
     3105    peruser_server_conf *sconf = PERUSER_SERVER_CONF(r->server->module_config); 
     3106    child_info_t *processor; 
     3107 
     3108    if (sconf->senv == NULL) { 
     3109        _DBG("Server environment not set on virtualhost %s", r->server->server_hostname); 
     3110 
     3111        if (sconf->missing_senv_reported == 0) { 
     3112            ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, 
     3113                         "Virtualhost %s has no server environment set, " 
     3114                         "request will not be honoured.", r->server->server_hostname); 
     3115        } 
     3116         
     3117        sconf->missing_senv_reported = 1; 
     3118 
     3119        return HTTP_INTERNAL_SERVER_ERROR; 
     3120    } 
     3121 
     3122    if(CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) 
     3123        processor = &CHILD_INFO_TABLE[sconf->senv->processor_id]; 
     3124    else 
     3125        processor = &CHILD_INFO_TABLE[r->connection->id]; 
     3126 
     3127 
     3128    if (!strlen(r->the_request)) 
     3129    { 
     3130        _DBG("corrupt request. aborting",0); 
     3131        return DECLINED; 
     3132    } 
     3133 
     3134    if (processor->sock_fd != AP_PERUSER_THISCHILD) 
     3135    { 
     3136        apr_socket_t *sock = NULL; 
     3137 
     3138        apr_os_sock_put(&sock, &processor->sock_fd, r->connection->pool); 
     3139        ap_sock_disable_nagle(sock); 
     3140        ap_set_module_config(r->connection->conn_config, &core_module, sock); 
     3141        _DBG("not the right socket?", 0); 
     3142        return OK; 
     3143    } 
     3144 
     3145    switch (CHILD_INFO_TABLE[my_child_num].type) 
     3146    { 
     3147        case CHILD_TYPE_MULTIPLEXER: 
     3148        { 
     3149            _DBG("MULTIPLEXER => Determining if request should be passed. " 
     3150                 "Child Num: %d, dest-child: %d, hostname from server: %s r->hostname=%s r->the_request=\"%s\"", 
     3151                my_child_num, processor->id, r->server->server_hostname, r->hostname, r->the_request); 
     3152 
     3153            if (processor->id != my_child_num) 
     3154            { 
     3155                if (processor->status == CHILD_STATUS_STANDBY) 
     3156                { 
     3157                    _DBG("Activating child #%d", processor->id); 
     3158                    processor->status = CHILD_STATUS_STARTING; 
     3159                } 
     3160 
     3161                _DBG("Passing request.",0); 
     3162                if (pass_request(r, processor) == -1) 
     3163                { 
     3164                    if (processor->senv->error_pass == 0) { 
     3165                        ap_log_error(APLOG_MARK, APLOG_ERR, 0, 
     3166                                     ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.", 
     3167                                     processor->senv->name, r->hostname); 
     3168                    } 
     3169 
     3170                    processor->senv->error_pass = 1; 
     3171 
     3172                    return HTTP_SERVICE_UNAVAILABLE; 
     3173                } 
     3174                else { 
     3175                    processor->senv->error_pass = 0; 
     3176                } 
     3177 
     3178                _DBG("doing longjmp",0); 
     3179                longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1); 
     3180                _DBG("request declined at our site",0); 
     3181                return DECLINED; 
     3182            } 
     3183            _DBG("WTF: the server is assigned to the multiplexer! ... dropping request",0); 
     3184            return DECLINED; 
     3185        } 
     3186        case CHILD_TYPE_PROCESSOR: 
     3187        case CHILD_TYPE_WORKER: 
     3188        { 
     3189               if (sconf->senv != CHILD_INFO_TABLE[my_child_num].senv) { 
     3190                       ap_log_error(APLOG_MARK, APLOG_WARNING,  
     3191                                    0, ap_server_conf, 
     3192                                   "invalid virtualhost for this child! (%s)", r->hostname); 
     3193                       ap_lingering_close(r->connection); 
     3194                       return HTTP_REQUEST_TIME_OUT; 
     3195               } 
     3196                
     3197            _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num); 
     3198            _DBG("request for %s / (server %s) seems to be for us", r->hostname, r->server->server_hostname); 
     3199 
     3200            if (server_env_cleanup) 
     3201            { 
     3202                int i; 
     3203                int input = sconf->senv->input; 
     3204                int output = sconf->senv->output; 
     3205 
     3206                _DBG("performing handle cleanup"); 
     3207                for (i = 0; i < NUM_SENV; i++) 
     3208                { 
     3209                    if (SENV[i].input > 0 && SENV[i].input != input) { 
     3210                        int retval = close(SENV[i].input); 
     3211                        if (retval < 0) { 
     3212                            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
     3213                                         "close(%d) failed", SENV[i].input); 
     3214                        } 
     3215                    } 
     3216                    if (SENV[i].output > 0 && SENV[i].output != output) { 
     3217                        int retval = close(SENV[i].output); 
     3218                        if (retval < 0) { 
     3219                            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, 
     3220                                         "close(%d) failed", SENV[i].output); 
     3221                        } 
     3222                    } 
     3223                } 
     3224                server_env_cleanup = 0; 
     3225            } 
     3226 
     3227            return OK; 
     3228        } 
     3229        default: 
     3230        { 
     3231            _DBG("unspecified child type %d in %d, dropping request", 
     3232                 CHILD_INFO_TABLE[my_child_num].type, my_child_num); 
     3233            return DECLINED; 
     3234        } 
     3235    } 
     3236 
     3237    _DBG("THIS POINT SHOULD NOT BE REACHED!",0); 
     3238    return OK; 
     3239} 
     3240 
     3241 
     3242int senv_active_cmp(const void *a, const void *b) { 
     3243  _DBG("CMP %d %d", *(int *) a,*(int *)  b); 
     3244  return active_env_processors(*(int *)a)<active_env_processors(*(int *)b); 
     3245} 
     3246 
     3247static int peruser_status_hook(request_rec *r, int flags) 
     3248{ 
     3249    int x; 
     3250    server_env_t *senv; 
     3251 
     3252    if (flags & AP_STATUS_SHORT) 
     3253           return OK; 
     3254 
     3255 
     3256        if (flags & AP_STATUS_STATS) { 
     3257                 
     3258                int *sorted_senv; 
     3259                int i; 
     3260                sorted_senv=(int *) apr_palloc(r->pool, NUM_SENV*sizeof(int)); 
     3261                 
     3262                if(!sorted_senv) { 
     3263                        ap_rputs("peruser_status_hook(): Out of memory",r); 
     3264                        return OK; 
     3265                } 
     3266                /* Initial senv table */ 
     3267                for(i=0; i < NUM_SENV; i++) 
     3268                        sorted_senv[i]=i; 
     3269 
     3270                /* sort env by number of processors */ 
     3271                qsort(sorted_senv, NUM_SENV, sizeof(int), senv_active_cmp); 
     3272 
     3273                ap_rputs("<h3>Processors statistics:</h3><table border=\"0\"><tr><th>Environment</th><th>Pss</th><th>Avail</th></tr>", r); 
     3274                /* just a mockup to se what data will be usefull here will put code layter, yes I know we need to iterate ON ENV[] NUM_ENV times */ 
     3275                for (x = 0; x < NUM_SENV; x++) 
     3276                { 
     3277                        senv = &SENV[sorted_senv[x]]; 
     3278                        if(senv==NULL) 
     3279                                continue; 
     3280                        ap_rprintf(r, "<tr><td nowrap>%s</td><td nowrap>%d/%d/%d</td>" 
     3281                                        "<td>%d%%</td></tr>", 
     3282                                        senv == NULL ? NULL : ( senv->name == NULL ? "" : senv->name ), 
     3283                                        active_env_processors(sorted_senv[x]), idle_env_processors(sorted_senv[x]), senv == NULL ? 0 : senv->max_processors, 
     3284                                        senv == NULL ? 0 : senv->availability ); 
     3285                        } 
     3286                        ap_rputs("</table><tr/>", r); 
     3287                         
     3288                        ap_rputs("<hr/><table>" 
     3289                                        "<tr><th>Pss</th><td>Number of processors active/idle/max</td></tr>" 
     3290                                        "</table><hr/>",r); 
     3291        }else { 
     3292    ap_rputs("<hr>\n", r); 
     3293    ap_rputs("<h3>peruser status</h3>\n", r); 
     3294    ap_rputs("<table border=\"0\">\n", r); 
     3295    ap_rputs("<tr><th>ID</th><th>PID</th><th>STATUS</th><th>SB STATUS</th><th>Type</th><th>Processor</th>" 
     3296                   "<th>Pss</th>" 
     3297                   "<th>AVAIL</th>" 
     3298                   "</tr>\n", r); 
     3299    for (x = 0; x < NUM_CHILDS; x++) 
     3300        { 
     3301        senv = CHILD_INFO_TABLE[x].senv; 
     3302        ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td><td nowrap>%48s</td>" 
     3303                       "<td>%d/%d/%d</td>" 
     3304                       "<td>%3d%%</td></tr>\n", 
     3305                       CHILD_INFO_TABLE[x].id,  
     3306                       CHILD_INFO_TABLE[x].pid,  
     3307                       child_status_string(CHILD_INFO_TABLE[x].status),  
     3308                       scoreboard_status_string(SCOREBOARD_STATUS(x)), 
     3309                       child_type_string(CHILD_INFO_TABLE[x].type),  
     3310                       senv == NULL ? NULL : ( senv->name == NULL ? "" : senv->name ),  
     3311                       active_processors(x), 
     3312                       idle_processors(x), 
     3313                       senv == NULL ? 0 : CHILD_INFO_TABLE[x].senv->max_processors, 
     3314                       senv == NULL ? 0 : CHILD_INFO_TABLE[x].senv->availability 
     3315                       ); 
     3316       } 
     3317    ap_rputs("</table>\n", r); 
     3318 
     3319    ap_rputs("<hr/><table>" 
     3320                        "<tr><th>STATUS</th><td>Processor status</td></tr>" 
     3321                        "<tr><th>Pss</th><td>Number of processors active/idle/max</td></tr>" 
     3322                        "</table><hr/>",r); 
     3323        } 
     3324                 
     3325    if (grace_children > 0) { 
     3326       ap_rputs("<h2>peruser graceful children status</h2>\n", r); 
     3327       ap_rprintf(r, "%d of total %d still living<br />\n", grace_children_alive, grace_children); 
     3328        ap_rputs("<table border=\"0\">\n", r); 
     3329        ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td></tr>\n", r); 
     3330        for (x = 0; x < grace_children; x++) { 
     3331            ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td></tr>\n",  
     3332                           child_grace_info_table[x].id,  
     3333                           child_grace_info_table[x].pid,  
     3334                           child_status_string(child_grace_info_table[x].status),  
     3335                           child_type_string(child_grace_info_table[x].type) 
     3336                           ); 
     3337        } 
     3338        ap_rputs("</table>\n", r); 
     3339    } 
     3340    return OK; 
     3341} 
     3342 
     3343static void peruser_hooks(apr_pool_t *p) 
     3344{ 
     3345    /* The peruser open_logs phase must run before the core's, or stderr 
     3346     * will be redirected to a file, and the messages won't print to the 
     3347     * console. 
     3348     */ 
     3349    static const char *const aszSucc[] = {"core.c", NULL}; 
     3350 
     3351#ifdef AUX3 
     3352    (void) set42sig(); 
     3353#endif 
     3354 
     3355    ap_hook_open_logs(peruser_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE); 
     3356    ap_hook_pre_config(peruser_pre_config, NULL, NULL, APR_HOOK_MIDDLE); 
     3357    ap_hook_post_config(peruser_post_config, NULL, NULL, APR_HOOK_MIDDLE); 
     3358 
     3359    /* Both of these must be run absolutely first.  If this request isn't for 
     3360     * this server then we need to forward it to the proper child.  No sense 
     3361     * tying up this server running more post_read request hooks if it is 
     3362     * just going to be forwarded along.  The process_connection hook allows 
     3363     * peruser to receive the passed request correctly, by automatically 
     3364     * filling in the core_input_filter's ctx pointer. 
     3365     */ 
     3366    ap_hook_post_read_request(peruser_post_read, NULL, NULL, 
     3367                              APR_HOOK_REALLY_FIRST); 
     3368    ap_hook_process_connection(peruser_process_connection, NULL, NULL, 
     3369                               APR_HOOK_REALLY_FIRST); 
     3370 
     3371    APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE); 
     3372} 
     3373 
     3374void senv_init(server_env_t * senv) { 
     3375    senv->nice_lvl              = 0; 
     3376    senv->chroot                = NULL; 
     3377    senv->cgroup                = NULL; 
     3378    senv->min_processors        = ap_min_processors; 
     3379    senv->min_free_processors   = ap_min_free_processors; 
     3380    senv->max_free_processors   = ap_max_free_processors; 
     3381    senv->max_processors        = ap_max_processors; 
     3382} 
     3383 
     3384static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg) 
     3385{ 
     3386    const char *user_name = NULL, *group_name = NULL, *directive; 
     3387    server_env_t senv; 
     3388    ap_directive_t *current; 
     3389 
     3390    const char *endp = ap_strrchr_c(arg, '>'); 
     3391 
     3392    if (endp == NULL) { 
     3393        return apr_psprintf(cmd->temp_pool, 
     3394                            "Error: Directive %s> missing closing '>'", cmd->cmd->name); 
     3395    } 
     3396 
     3397    arg = apr_pstrndup(cmd->pool, arg, endp - arg); 
     3398 
     3399    if (!arg) { 
     3400        return apr_psprintf(cmd->temp_pool, 
     3401                            "Error: %s> must specify a processor name", cmd->cmd->name); 
     3402    } 
     3403 
     3404    senv.name = ap_getword_conf(cmd->pool, &arg); 
     3405    _DBG("processor_name: %s", senv.name); 
     3406 
     3407    if (strlen(senv.name) == 0) { 
     3408        return apr_psprintf(cmd->temp_pool, 
     3409                            "Error: Directive %s> takes one argument", cmd->cmd->name); 
     3410    } 
     3411 
     3412    server_env_t *old_senv = find_senv_by_name(senv.name); 
     3413 
     3414    if (old_senv) { 
     3415        return apr_psprintf(cmd->temp_pool, 
     3416                            "Error: Processor %s already defined", senv.name); 
     3417    } 
     3418 
     3419    senv_init(&senv); 
     3420 
     3421    current = cmd->directive->first_child; 
     3422 
     3423    int proc_temp = 0; 
     3424    for(; current != NULL; current = current->next) { 
     3425        directive = current->directive; 
     3426         
     3427        if (!strcasecmp(directive, "user")) { 
     3428            user_name = current->args; 
     3429        } 
     3430        else if (!strcasecmp(directive, "group")) { 
     3431            group_name = current->args; 
     3432        } 
     3433        else if (!strcasecmp(directive, "chroot")) { 
     3434            senv.chroot = ap_getword_conf(cmd->pool, &current->args); 
     3435        } 
     3436        else if (!strcasecmp(directive, "nicelevel")) { 
     3437            senv.nice_lvl = atoi(current->args); 
     3438        } 
     3439        else if (!strcasecmp(directive, "maxprocessors")) { 
     3440            proc_temp = atoi(current->args); 
     3441 
     3442            if (proc_temp < 1) { 
     3443                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3444                             "WARNING: Require MaxProcessors > 0, setting to 1"); 
     3445                proc_temp = 1; 
     3446            } 
     3447 
     3448            senv.max_processors = proc_temp; 
     3449        } 
     3450        else if (!strcasecmp(directive, "minprocessors")) { 
     3451            proc_temp = atoi(current->args); 
     3452 
     3453            if (proc_temp < 0) { 
     3454                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3455                             "WARNING: Require MinProcessors >= 0, setting to 0"); 
     3456                proc_temp = 0; 
     3457            } 
     3458 
     3459            senv.min_processors = proc_temp; 
     3460        } 
     3461        else if (!strcasecmp(directive, "minspareprocessors")) { 
     3462            proc_temp = atoi(current->args); 
     3463 
     3464            if (proc_temp < 0) { 
     3465                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3466                             "WARNING: Require MinSpareProcessors >= 0, setting to 0"); 
     3467                proc_temp = 0; 
     3468            } 
     3469 
     3470            senv.min_free_processors = proc_temp; 
     3471        } 
     3472        else if (!strcasecmp(directive, "maxspareprocessors")) { 
     3473            proc_temp = atoi(current->args); 
     3474             
     3475            if (proc_temp < 0) { 
     3476                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3477                             "WARNING: Require MaxSpareProcessors >= 0, setting to 0"); 
     3478                proc_temp = 0; 
     3479            } 
     3480 
     3481            senv.max_free_processors = proc_temp; 
     3482        } 
     3483        else if (!strcasecmp(directive, "cgroup")) { 
     3484            senv.cgroup = ap_getword_conf(cmd->pool, &current->args); 
     3485        } 
     3486        else { 
     3487            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3488                         "Unknown directive %s in %s>", directive, cmd->cmd->name); 
     3489        } 
     3490    } 
     3491 
     3492    if (user_name == NULL || group_name == NULL) { 
     3493        return apr_psprintf(cmd->temp_pool, 
     3494                            "Error: User or Group must be set in %s>", cmd->cmd->name); 
     3495    } 
     3496 
     3497    senv.uid = ap_uname2id(user_name); 
     3498    senv.gid = ap_gname2id(group_name); 
     3499 
     3500    _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d", 
     3501         senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl); 
     3502 
     3503    _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d", 
     3504         senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors); 
     3505 
     3506    return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, 
     3507                     cmd->pool, &senv); 
     3508} 
     3509 
     3510static const char *cf_Processor_depr(cmd_parms *cmd, void *dummy, 
     3511    const char *user_name, const char *group_name, const char *chroot) 
     3512{ 
     3513    return NULL; 
     3514} 
     3515 
     3516/* we define an Multiplexer child w/ specific uid/gid */ 
     3517static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy, 
     3518    const char *user_name, const char *group_name, const char *chroot) 
     3519{ 
     3520    static short depr_warned = 0; 
     3521     
     3522    if (depr_warned == 0) { 
     3523        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3524                     "WARNING: Multiplexer directive is deprecated. Multiplexer user and group is set by User and Group directives.");     
     3525         
     3526        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3527                     "To set multiplexer chroot, please use MultiplexerChroot."); 
     3528 
     3529        depr_warned = 1; 
     3530    } 
     3531 
     3532    if (chroot) { 
     3533        if (!ap_is_directory(cmd->pool, chroot)) 
     3534            return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", chroot); 
     3535 
     3536        multiplexer_chroot = chroot; 
     3537        _DBG("Setting multiplexer chroot to %s", chroot); 
     3538    } 
     3539 
     3540    return NULL; 
     3541} 
     3542 
     3543static const char* cf_MultiplexerChroot(cmd_parms *cmd, void *dummy, 
     3544                                         const char *path) 
     3545{ 
     3546    multiplexer_chroot = path; 
     3547 
     3548    if (path && !ap_is_directory(cmd->pool, path)) 
     3549        return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", path); 
     3550 
     3551    _DBG("setting multiplexer chroot to %s", path); 
     3552 
     3553    return NULL; 
     3554} 
     3555 
     3556static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy, 
     3557    const char *name, const char * group_name, const char * chroot) 
     3558{ 
     3559    peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config); 
     3560    server_env_t senv; 
     3561    char * processor_name, *tmp; 
     3562         
     3563    _DBG("function entered", 0); 
     3564         
     3565    /* name of processor env */ 
     3566    processor_name = name; 
     3567     
     3568    if(group_name != NULL || chroot != NULL) { 
     3569        /* deprecated ServerEnvironment user group chroot syntax 
     3570         * we create simple server env based on user/group/chroot only 
     3571         */ 
     3572        processor_name = apr_pstrcat(cmd->pool, name, "_",group_name, "_", chroot, NULL); 
     3573         
     3574        /* search for previous default server env */ 
     3575        sconf->senv = find_senv_by_name(processor_name); 
     3576         
     3577        if(!sconf->senv) { 
     3578            senv_init(&senv); 
     3579            senv.uid = ap_uname2id(name); 
     3580            senv.gid = ap_gname2id(group_name); 
     3581            senv.chroot = chroot; 
     3582            senv.name = processor_name; 
     3583             
     3584            tmp = child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, cmd->pool, &senv); 
     3585            /* error handling in case this child can't be created */ 
     3586            if(tmp) 
     3587                return tmp; 
     3588        } 
     3589    } 
     3590     
     3591    /* use predefined processor environment or default named "user_group_chroot" */ 
     3592    if(sconf->senv == NULL) 
     3593        sconf->senv = find_senv_by_name(processor_name); 
     3594     
     3595    if (sconf->senv == NULL) { 
     3596        return apr_psprintf(cmd->pool, 
     3597                            "Error: Processor %s not defined", name); 
     3598    } 
     3599 
     3600    _DBG("user=%d group=%d chroot=%s numchilds=%d", 
     3601        sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS); 
     3602 
     3603    return NULL; 
     3604} 
     3605 
     3606static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const char *arg) 
     3607{ 
     3608    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 
     3609    if (err != NULL) { 
     3610        return err; 
     3611    } 
     3612 
     3613    ap_min_free_processors = atoi(arg); 
     3614    if (ap_min_free_processors <= 0) { 
     3615       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3616                    "WARNING: detected MinSpareServers set to non-positive."); 
     3617       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3618                    "Resetting to 1 to avoid almost certain Apache failure."); 
     3619       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3620                    "Please read the documentation."); 
     3621       ap_min_free_processors = 1; 
     3622    } 
     3623        
     3624    return NULL; 
     3625} 
     3626 
     3627static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg)  
     3628{ 
     3629    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 
     3630    if (err != NULL) { 
     3631        return err; 
     3632    } 
     3633 
     3634    ap_daemons_limit = atoi(arg); 
     3635    if (ap_daemons_limit > server_limit) { 
     3636       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3637                    "WARNING: MaxClients of %d exceeds ServerLimit value " 
     3638                    "of %d servers,", ap_daemons_limit, server_limit); 
     3639       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3640                    " lowering MaxClients to %d.  To increase, please " 
     3641                    "see the ServerLimit", server_limit); 
     3642       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3643                    " directive."); 
     3644       ap_daemons_limit = server_limit; 
     3645    }  
     3646    else if (ap_daemons_limit < 1) { 
     3647        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3648                     "WARNING: Require MaxClients > 0, setting to 1"); 
     3649        ap_daemons_limit = 1; 
     3650    } 
     3651    return NULL; 
     3652} 
     3653 
     3654static const char *set_min_processors (cmd_parms *cmd, void *dummy, const char *arg) 
     3655{ 
     3656    peruser_server_conf *sconf; 
     3657    int min_procs; 
     3658    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); 
     3659 
     3660    if (err != NULL) { 
     3661        return err; 
     3662    } 
     3663 
     3664    min_procs = atoi(arg); 
     3665 
     3666    if (min_procs < 0) { 
     3667        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3668                     "WARNING: Require MinProcessors >= 0, setting to 0"); 
     3669        min_procs = 0; 
     3670    } 
     3671 
     3672    if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { 
     3673        sconf = PERUSER_SERVER_CONF(cmd->server->module_config); 
     3674        if(sconf->senv != NULL) 
     3675                        sconf->senv->min_processors = min_procs; 
     3676                else 
     3677                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3678                             "WARNING: MinProcessors must be set after ServerEnvironment to take effect"); 
     3679    } 
     3680    else { 
     3681        ap_min_processors = min_procs; 
     3682    } 
     3683 
     3684    return NULL; 
     3685} 
     3686 
     3687static const char *set_min_free_processors (cmd_parms *cmd, void *dummy, const char *arg) 
     3688{ 
     3689    peruser_server_conf *sconf; 
     3690    int min_free_procs; 
     3691    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); 
     3692 
     3693    if (err != NULL) { 
     3694        return err; 
     3695    } 
     3696 
     3697    min_free_procs = atoi(arg); 
     3698 
     3699    if (min_free_procs < 0) { 
     3700        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3701                     "WARNING: Require MinSpareProcessors >= 0, setting to 0"); 
     3702        min_free_procs = 0; 
     3703    } 
     3704 
     3705    if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { 
     3706        sconf = PERUSER_SERVER_CONF(cmd->server->module_config); 
     3707        if(sconf->senv != NULL) 
     3708                        sconf->senv->min_free_processors = min_free_procs; 
     3709                else 
     3710                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3711                             "WARNING: MinSpareProcessors must be set after ServerEnvironment to take effect"); 
     3712    } 
     3713    else { 
     3714        ap_min_free_processors = min_free_procs; 
     3715    } 
     3716 
     3717    return NULL; 
     3718} 
     3719 
     3720static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg) 
     3721{ 
     3722     peruser_server_conf *sconf; 
     3723     int max_free_procs; 
     3724     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); 
     3725 
     3726     if (err != NULL) { 
     3727         return err; 
     3728     } 
     3729 
     3730     max_free_procs = atoi(arg); 
     3731 
     3732     if (max_free_procs < 0) { 
     3733         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3734                      "WARNING: Require MaxSpareProcessors >= 0, setting to 0"); 
     3735         max_free_procs = 0; 
     3736     } 
     3737 
     3738     if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { 
     3739         sconf = PERUSER_SERVER_CONF(cmd->server->module_config); 
     3740                 if(sconf!=NULL) 
     3741                        sconf->senv->max_free_processors = max_free_procs; 
     3742                 else 
     3743                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3744                             "WARNING: MaxSpareProcessors must be set after ServerEnvironment to take effect"); 
     3745     } 
     3746     else { 
     3747         ap_max_free_processors = max_free_procs; 
     3748     } 
     3749 
     3750     return NULL; 
     3751} 
     3752 
     3753static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg) 
     3754{ 
     3755    peruser_server_conf *sconf; 
     3756    int max_procs; 
     3757    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); 
     3758 
     3759    if (err != NULL) { 
     3760        return err; 
     3761    } 
     3762 
     3763    max_procs = atoi(arg); 
     3764 
     3765    if (max_procs < 1) { 
     3766        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3767                     "WARNING: Require MaxProcessors > 0, setting to 1"); 
     3768        max_procs = 1; 
     3769    } 
     3770 
     3771    if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) { 
     3772        sconf = PERUSER_SERVER_CONF(cmd->server->module_config); 
     3773                if(sconf->senv != NULL) 
     3774                sconf->senv->max_processors = max_procs; 
     3775                else 
     3776                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3777                             "WARNING: MaxProcessors must be set after ServerEnvironment to take effect"); 
     3778    } 
     3779    else { 
     3780        ap_max_processors = max_procs; 
     3781    } 
     3782 
     3783    return NULL; 
     3784} 
     3785 
     3786static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg) 
     3787{ 
     3788    int min_multiplexers; 
     3789    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); 
     3790 
     3791    if (err != NULL) { 
     3792        return err; 
     3793    } 
     3794 
     3795    min_multiplexers = atoi(arg); 
     3796 
     3797    if (min_multiplexers < 1) { 
     3798        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3799                     "WARNING: Require MinMultiplexers > 0, setting to 1"); 
     3800        min_multiplexers = 1; 
     3801    } 
     3802 
     3803    ap_min_multiplexers = min_multiplexers; 
     3804 
     3805    return NULL; 
     3806} 
     3807 
     3808static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg) 
     3809{ 
     3810    int max_multiplexers; 
     3811    const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); 
     3812 
     3813    if (err != NULL) { 
     3814        return err; 
     3815    } 
     3816 
     3817    max_multiplexers = atoi(arg); 
     3818 
     3819    if (max_multiplexers < 1) { 
     3820        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3821                     "WARNING: Require MaxMultiplexers > 0, setting to 1"); 
     3822        max_multiplexers = 1; 
     3823    } 
     3824 
     3825    ap_max_multiplexers = max_multiplexers; 
     3826 
     3827    return NULL; 
     3828} 
     3829 
     3830static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)  
     3831{ 
     3832    int tmp_server_limit; 
     3833     
     3834    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 
     3835    if (err != NULL) { 
     3836        return err; 
     3837    } 
     3838 
     3839    tmp_server_limit = atoi(arg); 
     3840    /* you cannot change ServerLimit across a restart; ignore 
     3841     * any such attempts 
     3842     */ 
     3843    if (first_server_limit && 
     3844        tmp_server_limit != server_limit) { 
     3845        /* how do we log a message?  the error log is a bit bucket at this 
     3846         * point; we'll just have to set a flag so that ap_mpm_run() 
     3847         * logs a warning later 
     3848         */ 
     3849        changed_limit_at_restart = 1; 
     3850        return NULL; 
     3851    } 
     3852    server_limit = tmp_server_limit; 
     3853     
     3854    if (server_limit > MAX_SERVER_LIMIT) { 
     3855       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3856                    "WARNING: ServerLimit of %d exceeds compile time limit " 
     3857                    "of %d servers,", server_limit, MAX_SERVER_LIMIT); 
     3858       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3859                    " lowering ServerLimit to %d.", MAX_SERVER_LIMIT); 
     3860       server_limit = MAX_SERVER_LIMIT; 
     3861    }  
     3862    else if (server_limit < 1) { 
     3863        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,  
     3864                     "WARNING: Require ServerLimit > 0, setting to 1"); 
     3865        server_limit = 1; 
     3866    } 
     3867    return NULL; 
     3868} 
     3869 
     3870static const char *set_expire_timeout (cmd_parms *cmd, void *dummy, const char *arg) { 
     3871    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 
     3872    if (err != NULL) { 
     3873        return err; 
     3874    } 
     3875 
     3876    expire_timeout = atoi(arg); 
     3877 
     3878    return NULL; 
     3879} 
     3880 
     3881static const char *set_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) { 
     3882    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 
     3883    if (err != NULL) { 
     3884        return err; 
     3885    } 
     3886 
     3887    idle_timeout = atoi(arg); 
     3888 
     3889    return NULL; 
     3890} 
     3891 
     3892static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) { 
     3893    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 
     3894 
     3895    if (err != NULL) { 
     3896        return err; 
     3897    } 
     3898 
     3899    multiplexer_idle_timeout = atoi(arg); 
     3900 
     3901    return NULL; 
     3902} 
     3903 
     3904static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) { 
     3905    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 
     3906     
     3907    if (err != NULL) { 
     3908        return err; 
     3909    } 
     3910 
     3911    processor_wait_timeout = atoi(timeout); 
     3912 
     3913    if (steps != NULL) { 
     3914        int steps_tmp = atoi(steps); 
     3915 
     3916        if (steps_tmp < 1) { 
     3917            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, 
     3918                         "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1"); 
     3919            steps_tmp = 1; 
     3920        } 
     3921 
     3922        processor_wait_steps = steps_tmp; 
     3923    } 
     3924 
     3925    return NULL; 
     3926} 
     3927 
     3928static const command_rec peruser_cmds[] = { 
     3929UNIX_DAEMON_COMMANDS, 
     3930LISTEN_COMMANDS, 
     3931AP_INIT_TAKE1("MinSpareProcessors", set_min_free_processors, NULL, RSRC_CONF, 
     3932              "Minimum number of idle children, to handle request spikes"), 
     3933AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, 
     3934              "Minimum number of idle children, to handle request spikes"), 
     3935AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF, 
     3936              "Maximum number of idle children, 0 to disable"), 
     3937AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, 
     3938              "Maximum number of children alive at the same time"), 
     3939AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF, 
     3940              "Minimum number of processors per vhost"), 
     3941AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF, 
     3942              "Maximum number of processors per vhost"), 
     3943AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF, 
     3944              "Minimum number of multiplexers the server can have"), 
     3945AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF, 
     3946              "Maximum number of multiplexers the server can have"), 
     3947AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, 
     3948              "Maximum value of MaxClients for this run of Apache"), 
     3949AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF, 
     3950              "Maximum time a child can live, 0 to disable"), 
     3951AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF, 
     3952              "Maximum time before a child is killed after being idle, 0 to disable"), 
     3953AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF, 
     3954              "Maximum time before a multiplexer is killed after being idle, 0 to disable"), 
     3955AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF, 
     3956              "Maximum time a multiplexer waits for the processor if it is busy"), 
     3957AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF, 
     3958              "Specify an Multiplexer Child configuration."), 
     3959AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF, 
     3960              "Specify settings for processor."), 
     3961AP_INIT_TAKE23("Processor", cf_Processor_depr, NULL, RSRC_CONF, 
     3962              "A dummy directive for backwards compatibility"), 
     3963AP_INIT_TAKE123("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF, 
     3964              "Specify the server environment for this virtual host."), 
     3965AP_INIT_TAKE1("MultiplexerChroot", cf_MultiplexerChroot, NULL, RSRC_CONF, 
     3966              "Specify the multiplexer chroot path for multiplexer"), 
     3967{ NULL } 
     3968}; 
     3969 
     3970module AP_MODULE_DECLARE_DATA mpm_peruser_module = { 
     3971    MPM20_MODULE_STUFF, 
     3972    ap_mpm_rewrite_args,        /* hook to run before apache parses args */ 
     3973    NULL,                       /* create per-directory config structure */ 
     3974    NULL,                       /* merge per-directory config structures */ 
     3975    peruser_create_config,      /* create per-server config structure */ 
     3976    NULL,                       /* merge per-server config structures */ 
     3977    peruser_cmds,               /* command apr_table_t */ 
     3978    peruser_hooks,              /* register hooks */ 
     3979};