PeruserAttachments: httpd-2.2.16-peruser-0.4.0rc2.patch

File httpd-2.2.16-peruser-0.4.0rc2.patch, 149.9 KB (added by mephisto23, 18 months ago)
  • modules/generators/mod_status.c

    diff -Nur httpd-2.2.16/modules/generators/mod_status.c httpd-2.2.16-peruser/modules/generators/mod_status.c
    old new  
    201201 
    202202/* ID values for command table */ 
    203203 
    204 #define STAT_OPT_END     -1 
    205 #define STAT_OPT_REFRESH  0 
    206 #define STAT_OPT_NOTABLE  1 
    207 #define STAT_OPT_AUTO     2 
     204#define STAT_OPT_END              -1 
     205#define STAT_OPT_REFRESH          0 
     206#define STAT_OPT_NOTABLE          1 
     207#define STAT_OPT_AUTO             2 
     208#define STAT_OPT_PERUSER_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_PERUSER_STATS, "peruser_stats", NULL}, 
    220222    {STAT_OPT_END, NULL, NULL} 
    221223}; 
    222224 
     
    241243#endif 
    242244    int short_report; 
    243245    int no_table_report; 
     246    int peruser_stats; 
    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; 
     274    peruser_stats=0; 
    271275 
    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)); 
     
    312316                case STAT_OPT_NOTABLE: 
    313317                    no_table_report = 1; 
    314318                    break; 
     319               case STAT_OPT_PERUSER_STATS: 
     320                    peruser_stats = 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            (peruser_stats ? AP_STATUS_PERUSER_STATS : 0); 
    823831 
    824832        ap_run_status_hook(r, flags); 
    825833    } 
  • modules/generators/mod_status.h

    diff -Nur httpd-2.2.16/modules/generators/mod_status.h httpd-2.2.16-peruser/modules/generators/mod_status.h
    old new  
    2929#include "ap_config.h" 
    3030#include "httpd.h" 
    3131 
    32 #define AP_STATUS_SHORT    (0x1)  /* short, non-HTML report requested */ 
    33 #define AP_STATUS_NOTABLE  (0x2)  /* HTML report without tables */ 
    34 #define AP_STATUS_EXTENDED (0x4)  /* detailed report */ 
     32#define AP_STATUS_SHORT            (0x1)  /* short, non-HTML report requested */ 
     33#define AP_STATUS_NOTABLE          (0x2)  /* HTML report without tables */ 
     34#define AP_STATUS_EXTENDED         (0x4)  /* detailed report */ 
     35#define AP_STATUS_PERUSER_STATS    (0x8)  /* peruser mpm extended status */ 
    3536 
    3637#if !defined(WIN32) 
    3738#define STATUS_DECLARE(type)            type 
  • modules/ssl/mod_ssl.h

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

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

    diff -Nur httpd-2.2.16/server/mpm/config.m4 httpd-2.2.16-peruser/server/mpm/config.m4
    old new  
    11AC_MSG_CHECKING(which MPM to use) 
    22AC_ARG_WITH(mpm, 
    33APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use. 
    4                           MPM={beos|event|worker|prefork|mpmt_os2}),[ 
     4                          MPM={beos|event|worker|prefork|mpmt_os2|peruser}),[ 
    55  APACHE_MPM=$withval 
    66],[ 
    77  if test "x$APACHE_MPM" = "x"; then 
     
    2323 
    2424ap_mpm_is_experimental () 
    2525{ 
    26     if test "$apache_cv_mpm" = "event" ; then 
     26    if test "$apache_cv_mpm" = "event" -o "$apache_cv_mpm" = "peruser" ; then 
    2727        return 0 
    2828    else 
    2929        return 1 
  • server/mpm/experimental/peruser/AUTHORS

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

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

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

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

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

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