Gentoo Archives: gentoo-commits

From: "Benedikt Boehm (hollow)" <hollow@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] apache r232 - trunk/dist/2.2/patches
Date: Wed, 01 Sep 2010 05:49:21
Message-Id: 20100901054904.3FBDF20051@flycatcher.gentoo.org
1 Author: hollow
2 Date: 2010-09-01 05:49:03 +0000 (Wed, 01 Sep 2010)
3 New Revision: 232
4
5 Added:
6 trunk/dist/2.2/patches/20_all_peruser_0.4.0-rc1.patch
7 Removed:
8 trunk/dist/2.2/patches/20_all_peruser_0.4.0b1.patch
9 Log:
10 dump peruser to 0.4.0-rc1 wrt #294098
11
12 Copied: trunk/dist/2.2/patches/20_all_peruser_0.4.0-rc1.patch (from rev 231, trunk/dist/2.2/patches/20_all_peruser_0.4.0b1.patch)
13 ===================================================================
14 --- trunk/dist/2.2/patches/20_all_peruser_0.4.0-rc1.patch (rev 0)
15 +++ trunk/dist/2.2/patches/20_all_peruser_0.4.0-rc1.patch 2010-09-01 05:49:03 UTC (rev 232)
16 @@ -0,0 +1,4446 @@
17 +diff -ruN httpd-2.2.14/docs/conf/extra/httpd-mpm.conf.in peruser-0.4rc1/docs/conf/extra/httpd-mpm.conf.in
18 +--- httpd-2.2.14/docs/conf/extra/httpd-mpm.conf.in 2007-12-29 04:08:28.000000000 +0100
19 ++++ peruser-0.4rc1/docs/conf/extra/httpd-mpm.conf.in 2009-11-21 21:38:45.000000000 +0100
20 +@@ -27,6 +27,24 @@
21 + # active mpm.
22 + #
23 +
24 ++# peruser MPM
25 ++# IdleTimeout: maximum time before a child is killed after being idle, 0 to disable
26 ++# ExpireTimeout: maximum time a child can live, 0 to disable
27 ++# MinSpareProcessors: minimum number of idle children, to handle request spikes
28 ++# MaxProcessors: Maximum number of processors per vhost
29 ++# ServerLimit: maximum value of MaxClients for this run of Apache
30 ++# MaxClients: maximum number of children alive at the same time
31 ++# MaxMultiplexers: maximum number of multiplexers the server can have
32 ++<IfModule mpm_peruser_module>
33 ++ IdleTimeout 900
34 ++ ExpireTimeout 1800
35 ++ MinSpareProcessors 2
36 ++ MaxProcessors 10
37 ++ ServerLimit 256
38 ++ MaxClients 256
39 ++ MaxMultiplexers 20
40 ++</IfModule>
41 ++
42 + # prefork MPM
43 + # StartServers: number of server processes to start
44 + # MinSpareServers: minimum number of server processes which are kept spare
45 +diff -ruN httpd-2.2.14/modules/generators/mod_status.c peruser-0.4rc1/modules/generators/mod_status.c
46 +--- httpd-2.2.14/modules/generators/mod_status.c 2008-01-02 10:43:52.000000000 +0100
47 ++++ peruser-0.4rc1/modules/generators/mod_status.c 2009-11-21 21:07:28.000000000 +0100
48 +@@ -205,6 +205,7 @@
49 + #define STAT_OPT_REFRESH 0
50 + #define STAT_OPT_NOTABLE 1
51 + #define STAT_OPT_AUTO 2
52 ++#define STAT_OPT_STATS 3
53 +
54 + struct stat_opt {
55 + int id;
56 +@@ -217,6 +218,7 @@
57 + {STAT_OPT_REFRESH, "refresh", "Refresh"},
58 + {STAT_OPT_NOTABLE, "notable", NULL},
59 + {STAT_OPT_AUTO, "auto", NULL},
60 ++ {STAT_OPT_STATS, "stats", NULL},
61 + {STAT_OPT_END, NULL, NULL}
62 + };
63 +
64 +@@ -241,6 +243,7 @@
65 + #endif
66 + int short_report;
67 + int no_table_report;
68 ++ int stats_report;
69 + worker_score *ws_record;
70 + process_score *ps_record;
71 + char *stat_buffer;
72 +@@ -268,7 +271,8 @@
73 + kbcount = 0;
74 + short_report = 0;
75 + no_table_report = 0;
76 +-
77 ++ stats_report=0;
78 ++
79 + pid_buffer = apr_palloc(r->pool, server_limit * sizeof(pid_t));
80 + stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
81 +
82 +@@ -312,6 +316,9 @@
83 + case STAT_OPT_NOTABLE:
84 + no_table_report = 1;
85 + break;
86 ++ case STAT_OPT_STATS:
87 ++ stats_report = 1;
88 ++ break;
89 + case STAT_OPT_AUTO:
90 + ap_set_content_type(r, "text/plain; charset=ISO-8859-1");
91 + short_report = 1;
92 +@@ -819,7 +826,8 @@
93 + int flags =
94 + (short_report ? AP_STATUS_SHORT : 0) |
95 + (no_table_report ? AP_STATUS_NOTABLE : 0) |
96 +- (ap_extended_status ? AP_STATUS_EXTENDED : 0);
97 ++ (ap_extended_status ? AP_STATUS_EXTENDED : 0) |
98 ++ (stats_report ? AP_STATUS_STATS : 0);
99 +
100 + ap_run_status_hook(r, flags);
101 + }
102 +diff -ruN httpd-2.2.14/modules/generators/mod_status.h peruser-0.4rc1/modules/generators/mod_status.h
103 +--- httpd-2.2.14/modules/generators/mod_status.h 2006-07-12 05:38:44.000000000 +0200
104 ++++ peruser-0.4rc1/modules/generators/mod_status.h 2009-11-21 21:07:28.000000000 +0100
105 +@@ -32,6 +32,7 @@
106 + #define AP_STATUS_SHORT (0x1) /* short, non-HTML report requested */
107 + #define AP_STATUS_NOTABLE (0x2) /* HTML report without tables */
108 + #define AP_STATUS_EXTENDED (0x4) /* detailed report */
109 ++#define AP_STATUS_STATS (0x8) /* extended user statistics report */
110 +
111 + #if !defined(WIN32)
112 + #define STATUS_DECLARE(type) type
113 +diff -ruN httpd-2.2.14/modules/ssl/mod_ssl.h peruser-0.4rc1/modules/ssl/mod_ssl.h
114 +--- httpd-2.2.14/modules/ssl/mod_ssl.h 2006-07-12 05:38:44.000000000 +0200
115 ++++ peruser-0.4rc1/modules/ssl/mod_ssl.h 2009-11-21 14:29:17.000000000 +0100
116 +@@ -50,6 +50,10 @@
117 + * is using SSL/TLS. */
118 + APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
119 +
120 ++/** An optional function which returns non-zero if the given server
121 ++ * is using SSL/TLS. */
122 ++APR_DECLARE_OPTIONAL_FN(int, ssl_server_is_https, (server_rec *));
123 ++
124 + /** The ssl_proxy_enable() and ssl_engine_disable() optional functions
125 + * are used by mod_proxy to enable use of SSL for outgoing
126 + * connections. */
127 +diff -ruN httpd-2.2.14/modules/ssl/ssl_engine_vars.c peruser-0.4rc1/modules/ssl/ssl_engine_vars.c
128 +--- httpd-2.2.14/modules/ssl/ssl_engine_vars.c 2009-09-06 13:19:05.000000000 +0200
129 ++++ peruser-0.4rc1/modules/ssl/ssl_engine_vars.c 2009-11-21 14:33:56.000000000 +0100
130 +@@ -58,6 +58,12 @@
131 + return sslconn && sslconn->ssl;
132 + }
133 +
134 ++static int ssl_server_is_https(server_rec *s)
135 ++{
136 ++ SSLSrvConfigRec *sslsrv = mySrvConfig(s);
137 ++ return sslsrv && sslsrv->enabled;
138 ++}
139 ++
140 + static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION;
141 + static char var_library_interface[] = SSL_LIBRARY_TEXT;
142 + static char *var_library = NULL;
143 +@@ -67,6 +73,7 @@
144 + char *cp, *cp2;
145 +
146 + APR_REGISTER_OPTIONAL_FN(ssl_is_https);
147 ++ APR_REGISTER_OPTIONAL_FN(ssl_server_is_https);
148 + APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
149 + APR_REGISTER_OPTIONAL_FN(ssl_ext_lookup);
150 +
151 +diff -ruN httpd-2.2.14/server/mpm/config.m4 peruser-0.4rc1/server/mpm/config.m4
152 +--- httpd-2.2.14/server/mpm/config.m4 2005-10-30 18:05:26.000000000 +0100
153 ++++ peruser-0.4rc1/server/mpm/config.m4 2009-11-21 14:29:17.000000000 +0100
154 +@@ -1,7 +1,7 @@
155 + AC_MSG_CHECKING(which MPM to use)
156 + AC_ARG_WITH(mpm,
157 + APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use.
158 +- MPM={beos|event|worker|prefork|mpmt_os2}),[
159 ++ MPM={beos|event|worker|prefork|mpmt_os2|peruser}),[
160 + APACHE_MPM=$withval
161 + ],[
162 + if test "x$APACHE_MPM" = "x"; then
163 +@@ -23,7 +23,7 @@
164 +
165 + ap_mpm_is_experimental ()
166 + {
167 +- if test "$apache_cv_mpm" = "event" ; then
168 ++ if test "$apache_cv_mpm" = "event" -o "$apache_cv_mpm" = "peruser" ; then
169 + return 0
170 + else
171 + return 1
172 +diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/AUTHORS peruser-0.4rc1/server/mpm/experimental/peruser/AUTHORS
173 +--- httpd-2.2.14/server/mpm/experimental/peruser/AUTHORS 1970-01-01 01:00:00.000000000 +0100
174 ++++ peruser-0.4rc1/server/mpm/experimental/peruser/AUTHORS 2009-11-21 14:29:17.000000000 +0100
175 +@@ -0,0 +1,11 @@
176 ++Enrico Weigelt <weigelt [at] metux.de> (MetuxMPM maintainer)
177 ++Sean Gabriel Heacock <gabriel [at] telana.com> (Peruser maintainer)
178 ++Stefan Seufert <stefan [at] seuf.de>
179 ++Janno Sannik <janno [at] kood.ee>
180 ++Taavi Sannik <taavi [at] kood.ee>
181 ++Rommer <rommer [at] active.by>
182 ++Bert <bert [at] ev6.net>
183 ++Leen Besselink <leen [at] consolejunkie.net>
184 ++Steve Amerige <mpm [at] fatbear.com>
185 ++Stefan Klingner <stefan.klingner [at] mephisto23.com> (Peruser maintainer)
186 ++Michal Grzedzicki <lazy404 [at] gmail.com>
187 +diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/Makefile.in peruser-0.4rc1/server/mpm/experimental/peruser/Makefile.in
188 +--- httpd-2.2.14/server/mpm/experimental/peruser/Makefile.in 1970-01-01 01:00:00.000000000 +0100
189 ++++ peruser-0.4rc1/server/mpm/experimental/peruser/Makefile.in 2009-11-21 14:29:17.000000000 +0100
190 +@@ -0,0 +1,5 @@
191 ++
192 ++LTLIBRARY_NAME = libperuser.la
193 ++LTLIBRARY_SOURCES = peruser.c
194 ++
195 ++include $(top_srcdir)/build/ltlib.mk
196 +diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/config.m4 peruser-0.4rc1/server/mpm/experimental/peruser/config.m4
197 +--- httpd-2.2.14/server/mpm/experimental/peruser/config.m4 1970-01-01 01:00:00.000000000 +0100
198 ++++ peruser-0.4rc1/server/mpm/experimental/peruser/config.m4 2009-11-21 14:29:17.000000000 +0100
199 +@@ -0,0 +1,3 @@
200 ++if test "$MPM_NAME" = "peruser" ; then
201 ++ APACHE_FAST_OUTPUT(server/mpm/experimental/$MPM_NAME/Makefile)
202 ++fi
203 +diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/mpm.h peruser-0.4rc1/server/mpm/experimental/peruser/mpm.h
204 +--- httpd-2.2.14/server/mpm/experimental/peruser/mpm.h 1970-01-01 01:00:00.000000000 +0100
205 ++++ peruser-0.4rc1/server/mpm/experimental/peruser/mpm.h 2009-11-21 21:10:39.000000000 +0100
206 +@@ -0,0 +1,107 @@
207 ++/* ====================================================================
208 ++ * The Apache Software License, Version 1.1
209 ++ *
210 ++ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
211 ++ * reserved.
212 ++ *
213 ++ * Redistribution and use in source and binary forms, with or without
214 ++ * modification, are permitted provided that the following conditions
215 ++ * are met:
216 ++ *
217 ++ * 1. Redistributions of source code must retain the above copyright
218 ++ * notice, this list of conditions and the following disclaimer.
219 ++ *
220 ++ * 2. Redistributions in binary form must reproduce the above copyright
221 ++ * notice, this list of conditions and the following disclaimer in
222 ++ * the documentation and/or other materials provided with the
223 ++ * distribution.
224 ++ *
225 ++ * 3. The end-user documentation included with the redistribution,
226 ++ * if any, must include the following acknowledgment:
227 ++ * "This product includes software developed by the
228 ++ * Apache Software Foundation (http://www.apache.org/)."
229 ++ * Alternately, this acknowledgment may appear in the software itself,
230 ++ * if and wherever such third-party acknowledgments normally appear.
231 ++ *
232 ++ * 4. The names "Apache" and "Apache Software Foundation" must
233 ++ * not be used to endorse or promote products derived from this
234 ++ * software without prior written permission. For written
235 ++ * permission, please contact apache@××××××.org.
236 ++ *
237 ++ * 5. Products derived from this software may not be called "Apache",
238 ++ * nor may "Apache" appear in their name, without prior written
239 ++ * permission of the Apache Software Foundation.
240 ++ *
241 ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
242 ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
243 ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
244 ++ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
245 ++ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
246 ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
247 ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
248 ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
249 ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
250 ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
251 ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252 ++ * SUCH DAMAGE.
253 ++ * ====================================================================
254 ++ *
255 ++ * This software consists of voluntary contributions made by many
256 ++ * individuals on behalf of the Apache Software Foundation. For more
257 ++ * information on the Apache Software Foundation, please see
258 ++ * <http://www.apache.org/>.
259 ++ *
260 ++ * Portions of this software are based upon public domain software
261 ++ * originally written at the National Center for Supercomputing Applications,
262 ++ * University of Illinois, Urbana-Champaign.
263 ++ */
264 ++
265 ++#include "httpd.h"
266 ++#include "mpm_default.h"
267 ++#include "scoreboard.h"
268 ++#include "unixd.h"
269 ++
270 ++#ifndef APACHE_MPM_PERUSER_H
271 ++#define APACHE_MPM_PERUSER_H
272 ++
273 ++#define PERUSER_MPM
274 ++
275 ++#define MPM_NAME "Peruser"
276 ++
277 ++#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
278 ++#define AP_MPM_WANT_WAIT_OR_TIMEOUT
279 ++#define AP_MPM_WANT_PROCESS_CHILD_STATUS
280 ++#define AP_MPM_WANT_SET_PIDFILE
281 ++#define AP_MPM_WANT_SET_SCOREBOARD
282 ++#define AP_MPM_WANT_SET_LOCKFILE
283 ++#define AP_MPM_WANT_SET_MAX_REQUESTS
284 ++#define AP_MPM_WANT_SET_COREDUMPDIR
285 ++#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
286 ++#define AP_MPM_WANT_SIGNAL_SERVER
287 ++#define AP_MPM_WANT_SET_MAX_MEM_FREE
288 ++#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
289 ++
290 ++#define AP_MPM_USES_POD 1
291 ++#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
292 ++#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
293 ++#define MPM_VALID_PID(p) (getpgid(p) == getpgrp())
294 ++#define MPM_ACCEPT_FUNC unixd_accept
295 ++
296 ++extern int ap_threads_per_child;
297 ++extern int ap_max_daemons_limit;
298 ++extern server_rec *ap_server_conf;
299 ++
300 ++/* Table of child status */
301 ++#define SERVER_DEAD 0
302 ++#define SERVER_DYING 1
303 ++#define SERVER_ALIVE 2
304 ++
305 ++typedef struct ap_ctable {
306 ++ pid_t pid;
307 ++ unsigned char status;
308 ++} ap_ctable;
309 ++
310 ++static const char* child_clone();
311 ++
312 ++
313 ++#endif /* APACHE_MPM_PERUSER_H */
314 +diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/mpm_default.h peruser-0.4rc1/server/mpm/experimental/peruser/mpm_default.h
315 +--- httpd-2.2.14/server/mpm/experimental/peruser/mpm_default.h 1970-01-01 01:00:00.000000000 +0100
316 ++++ peruser-0.4rc1/server/mpm/experimental/peruser/mpm_default.h 2009-11-21 14:29:17.000000000 +0100
317 +@@ -0,0 +1,162 @@
318 ++/* ====================================================================
319 ++ * The Apache Software License, Version 1.1
320 ++ *
321 ++ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
322 ++ * reserved.
323 ++ *
324 ++ * Redistribution and use in source and binary forms, with or without
325 ++ * modification, are permitted provided that the following conditions
326 ++ * are met:
327 ++ *
328 ++ * 1. Redistributions of source code must retain the above copyright
329 ++ * notice, this list of conditions and the following disclaimer.
330 ++ *
331 ++ * 2. Redistributions in binary form must reproduce the above copyright
332 ++ * notice, this list of conditions and the following disclaimer in
333 ++ * the documentation and/or other materials provided with the
334 ++ * distribution.
335 ++ *
336 ++ * 3. The end-user documentation included with the redistribution,
337 ++ * if any, must include the following acknowledgment:
338 ++ * "This product includes software developed by the
339 ++ * Apache Software Foundation (http://www.apache.org/)."
340 ++ * Alternately, this acknowledgment may appear in the software itself,
341 ++ * if and wherever such third-party acknowledgments normally appear.
342 ++ *
343 ++ * 4. The names "Apache" and "Apache Software Foundation" must
344 ++ * not be used to endorse or promote products derived from this
345 ++ * software without prior written permission. For written
346 ++ * permission, please contact apache@××××××.org.
347 ++ *
348 ++ * 5. Products derived from this software may not be called "Apache",
349 ++ * nor may "Apache" appear in their name, without prior written
350 ++ * permission of the Apache Software Foundation.
351 ++ *
352 ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
353 ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
354 ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
355 ++ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
356 ++ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
357 ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
358 ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
359 ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
360 ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
361 ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
362 ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
363 ++ * SUCH DAMAGE.
364 ++ * ====================================================================
365 ++ *
366 ++ * This software consists of voluntary contributions made by many
367 ++ * individuals on behalf of the Apache Software Foundation. For more
368 ++ * information on the Apache Software Foundation, please see
369 ++ * <http://www.apache.org/>.
370 ++ *
371 ++ * Portions of this software are based upon public domain software
372 ++ * originally written at the National Center for Supercomputing Applications,
373 ++ * University of Illinois, Urbana-Champaign.
374 ++ */
375 ++
376 ++#ifndef APACHE_MPM_DEFAULT_H
377 ++#define APACHE_MPM_DEFAULT_H
378 ++
379 ++/* Number of processors to spawn off for each ServerEnvironment by default */
380 ++
381 ++#ifndef DEFAULT_START_PROCESSORS
382 ++#define DEFAULT_START_PROCESSORS 0
383 ++#endif
384 ++
385 ++/* Minimum number of running processors per ServerEnvironment */
386 ++
387 ++#ifndef DEFAULT_MIN_PROCESSORS
388 ++#define DEFAULT_MIN_PROCESSORS 0
389 ++#endif
390 ++
391 ++/* Minimum --- fewer than this, and more will be created */
392 ++
393 ++#ifndef DEFAULT_MIN_FREE_PROCESSORS
394 ++#define DEFAULT_MIN_FREE_PROCESSORS 2
395 ++#endif
396 ++
397 ++/* Maximum --- more than this, and idle processors will be killed (0 = disable) */
398 ++
399 ++#ifndef DEFAULT_MAX_FREE_PROCESSORS
400 ++#define DEFAULT_MAX_FREE_PROCESSORS 0
401 ++#endif
402 ++
403 ++/* Maximum processors per ServerEnvironment */
404 ++
405 ++#ifndef DEFAULT_MAX_PROCESSORS
406 ++#define DEFAULT_MAX_PROCESSORS 10
407 ++#endif
408 ++
409 ++/* File used for accept locking, when we use a file */
410 ++#ifndef DEFAULT_LOCKFILE
411 ++#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock"
412 ++#endif
413 ++
414 ++/* Where the main/parent process's pid is logged */
415 ++#ifndef DEFAULT_PIDLOG
416 ++#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid"
417 ++#endif
418 ++
419 ++/*
420 ++ * Interval, in microseconds, between scoreboard maintenance.
421 ++ */
422 ++#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
423 ++#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
424 ++#endif
425 ++
426 ++/* Number of requests to try to handle in a single process. If <= 0,
427 ++ * the children don't die off.
428 ++ */
429 ++#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
430 ++#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
431 ++#endif
432 ++
433 ++/* Maximum multiplexers */
434 ++
435 ++#ifndef DEFAULT_MAX_MULTIPLEXERS
436 ++#define DEFAULT_MAX_MULTIPLEXERS 20
437 ++#endif
438 ++
439 ++/* Minimum multiplexers */
440 ++
441 ++#ifndef DEFAULT_MIN_MULTIPLEXERS
442 ++#define DEFAULT_MIN_MULTIPLEXERS 3
443 ++#endif
444 ++
445 ++/* Amount of time a child can run before it expires (0 = turn off) */
446 ++
447 ++#ifndef DEFAULT_EXPIRE_TIMEOUT
448 ++#define DEFAULT_EXPIRE_TIMEOUT 1800
449 ++#endif
450 ++
451 ++/* Amount of time a child can stay idle (0 = turn off) */
452 ++
453 ++#ifndef DEFAULT_IDLE_TIMEOUT
454 ++#define DEFAULT_IDLE_TIMEOUT 900
455 ++#endif
456 ++
457 ++/* Amount of time a multiplexer can stay idle (0 = turn off) */
458 ++
459 ++#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT
460 ++#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0
461 ++#endif
462 ++
463 ++/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait)
464 ++ * This is decreased with every busy request
465 ++ */
466 ++
467 ++#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT
468 ++#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5
469 ++#endif
470 ++
471 ++/* The number of different levels there are when a multiplexer is waiting for processor
472 ++ * (between maximum waiting time and no waiting)
473 ++ */
474 ++
475 ++#ifndef DEFAULT_PROCESSOR_WAIT_STEPS
476 ++#define DEFAULT_PROCESSOR_WAIT_STEPS 10
477 ++#endif
478 ++
479 ++#endif /* AP_MPM_DEFAULT_H */
480 +diff -ruN httpd-2.2.14/server/mpm/experimental/peruser/peruser.c peruser-0.4rc1/server/mpm/experimental/peruser/peruser.c
481 +--- httpd-2.2.14/server/mpm/experimental/peruser/peruser.c 1970-01-01 01:00:00.000000000 +0100
482 ++++ peruser-0.4rc1/server/mpm/experimental/peruser/peruser.c 2009-11-21 22:02:27.000000000 +0100
483 +@@ -0,0 +1,3979 @@
484 ++
485 ++/* ====================================================================
486 ++ * The Apache Software License, Version 1.1
487 ++ *
488 ++ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
489 ++ * reserved.
490 ++ *
491 ++ * Redistribution and use in source and binary forms, with or without
492 ++ * modification, are permitted provided that the following conditions
493 ++ * are met:
494 ++ *
495 ++ * 1. Redistributions of source code must retain the above copyright
496 ++ * notice, this list of conditions and the following disclaimer.
497 ++ *
498 ++ * 2. Redistributions in binary form must reproduce the above copyright
499 ++ * notice, this list of conditions and the following disclaimer in
500 ++ * the documentation and/or other materials provided with the
501 ++ * distribution.
502 ++ *
503 ++ * 3. The end-user documentation included with the redistribution,
504 ++ * if any, must include the following acknowledgment:
505 ++ * "This product includes software developed by the
506 ++ * Apache Software Foundation (http://www.apache.org/)."
507 ++ * Alternately, this acknowledgment may appear in the software itself,
508 ++ * if and wherever such third-party acknowledgments normally appear.
509 ++ *
510 ++ * 4. The names "Apache" and "Apache Software Foundation" must
511 ++ * not be used to endorse or promote products derived from this
512 ++ * software without prior written permission. For written
513 ++ * permission, please contact apache@××××××.org.
514 ++ *
515 ++ * 5. Products derived from this software may not be called "Apache",
516 ++ * nor may "Apache" appear in their name, without prior written
517 ++ * permission of the Apache Software Foundation.
518 ++ *
519 ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
520 ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
521 ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
522 ++ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
523 ++ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
524 ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
525 ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
526 ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
527 ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
528 ++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
529 ++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
530 ++ * SUCH DAMAGE.
531 ++ * ====================================================================
532 ++ *
533 ++ * This software consists of voluntary contributions made by many
534 ++ * individuals on behalf of the Apache Software Foundation. For more
535 ++ * information on the Apache Software Foundation, please see
536 ++ * <http://www.apache.org/>.
537 ++ *
538 ++ * Portions of this software are based upon public domain software
539 ++ * originally written at the National Center for Supercomputing Applications,
540 ++ * University of Illinois, Urbana-Champaign.
541 ++ */
542 ++
543 ++/* Peruser version 0.4.0 */
544 ++
545 ++/* #define MPM_PERUSER_DEBUG */
546 ++
547 ++#include "apr.h"
548 ++#include "apr_hash.h"
549 ++#include "apr_pools.h"
550 ++#include "apr_file_io.h"
551 ++#include "apr_portable.h"
552 ++#include "apr_strings.h"
553 ++#include "apr_thread_proc.h"
554 ++#include "apr_signal.h"
555 ++#define APR_WANT_STDIO
556 ++#define APR_WANT_STRFUNC
557 ++#define APR_WANT_IOVEC
558 ++#include "apr_want.h"
559 ++
560 ++#if APR_HAVE_UNISTD_H
561 ++#include <unistd.h>
562 ++#endif
563 ++#if APR_HAVE_SYS_TYPES_H
564 ++#include <sys/types.h>
565 ++#endif
566 ++
567 ++#define CORE_PRIVATE
568 ++
569 ++#include "ap_config.h"
570 ++#include "httpd.h"
571 ++#include "mpm_default.h"
572 ++#include "http_main.h"
573 ++#include "http_log.h"
574 ++#include "http_config.h"
575 ++#include "http_core.h" /* for get_remote_host */
576 ++#include "http_connection.h"
577 ++#include "http_protocol.h" /* for ap_hook_post_read_request */
578 ++#include "http_vhost.h" /* for ap_update_vhost_given_ip */
579 ++#include "scoreboard.h"
580 ++#include "ap_mpm.h"
581 ++#include "unixd.h"
582 ++#include "mpm_common.h"
583 ++#include "ap_listen.h"
584 ++#include "ap_mmn.h"
585 ++#include "apr_poll.h"
586 ++#include "util_ebcdic.h"
587 ++#include "mod_status.h"
588 ++
589 ++#ifdef HAVE_BSTRING_H
590 ++#include <bstring.h> /* for IRIX, FD_SET calls bzero() */
591 ++#endif
592 ++
593 ++#ifdef HAVE_TIME_H
594 ++#include <time.h>
595 ++#endif
596 ++
597 ++#ifdef HAVE_SYS_PROCESSOR_H
598 ++#include <sys/processor.h> /* for bindprocessor() */
599 ++#endif
600 ++
601 ++#if APR_HAS_SHARED_MEMORY
602 ++#include "apr_shm.h"
603 ++#else
604 ++#error "Peruser MPM requres shared memory support."
605 ++#endif
606 ++
607 ++
608 ++/* should be APR-ized */
609 ++#include <grp.h>
610 ++#include <pwd.h>
611 ++#include <sys/stat.h>
612 ++#include <sys/un.h>
613 ++#include <setjmp.h>
614 ++
615 ++#include <signal.h>
616 ++#include <sys/times.h>
617 ++
618 ++
619 ++#ifdef MPM_PERUSER_DEBUG
620 ++# define _DBG(text,par...) \
621 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \
622 ++ "(peruser: pid=%d uid=%d child=%d) %s(): " text, \
623 ++ getpid(), getuid(), my_child_num, __FUNCTION__, ##par, 0)
624 ++
625 ++# define _TRACE_CALL(text,par...) _DBG("calling " text, ##par)
626 ++# define _TRACE_RET(text,par...) _DBG("returned from " text, ##par)
627 ++#else
628 ++# define _DBG(text,par...)
629 ++# define _TRACE_RET(text,par...)
630 ++# define _TRACE_CALL(text,par...)
631 ++#endif /* MPM_PERUSER_DEBUG */
632 ++
633 ++/* char of death - for signalling children to die */
634 ++#define AP_PERUSER_CHAR_OF_DEATH '!'
635 ++
636 ++#define PERUSER_SERVER_CONF(cf) \
637 ++ ((peruser_server_conf *) ap_get_module_config(cf, &mpm_peruser_module))
638 ++
639 ++#define SCOREBOARD_STATUS(i) ap_scoreboard_image->servers[i][0].status
640 ++
641 ++/*
642 ++ * Define some magic numbers that we use for the state of the incomming
643 ++ * request. These must be < 0 so they don't collide with a file descriptor.
644 ++ */
645 ++#define AP_PERUSER_THISCHILD -1
646 ++#define AP_PERUSER_OTHERCHILD -2
647 ++
648 ++
649 ++/* Limit on the total --- clients will be locked out if more servers than
650 ++ * this are needed. It is intended solely to keep the server from crashing
651 ++ * when things get out of hand.
652 ++ *
653 ++ * We keep a hard maximum number of servers, for two reasons --- first off,
654 ++ * in case something goes seriously wrong, we want to stop the fork bomb
655 ++ * short of actually crashing the machine we're running on by filling some
656 ++ * kernel table. Secondly, it keeps the size of the scoreboard file small
657 ++ * enough that we can read the whole thing without worrying too much about
658 ++ * the overhead.
659 ++ */
660 ++#ifndef DEFAULT_SERVER_LIMIT
661 ++#define DEFAULT_SERVER_LIMIT 256
662 ++#endif
663 ++
664 ++/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
665 ++ * some sort of compile-time limit to help catch typos.
666 ++ */
667 ++#ifndef MAX_SERVER_LIMIT
668 ++#define MAX_SERVER_LIMIT 20000
669 ++#endif
670 ++
671 ++#ifndef HARD_THREAD_LIMIT
672 ++#define HARD_THREAD_LIMIT 1
673 ++#endif
674 ++
675 ++#define CHILD_TYPE_UNKNOWN 0
676 ++#define CHILD_TYPE_MULTIPLEXER 1
677 ++#define CHILD_TYPE_PROCESSOR 2
678 ++#define CHILD_TYPE_WORKER 3
679 ++
680 ++#define CHILD_STATUS_STANDBY 0 /* wait for a request before starting */
681 ++#define CHILD_STATUS_STARTING 1 /* wait for socket creation */
682 ++#define CHILD_STATUS_READY 2 /* is ready to take requests */
683 ++#define CHILD_STATUS_ACTIVE 3 /* is currently busy handling requests */
684 ++#define CHILD_STATUS_RESTART 4 /* child about to die and restart */
685 ++
686 ++/* cgroup settings */
687 ++#define CGROUP_TASKS_FILE "/tasks"
688 ++#define CGROUP_TASKS_FILE_LEN 7
689 ++
690 ++/* config globals */
691 ++
692 ++int ap_threads_per_child=0; /* Worker threads per child */
693 ++static apr_proc_mutex_t *accept_mutex;
694 ++static int ap_min_processors=DEFAULT_MIN_PROCESSORS;
695 ++static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS;
696 ++static int ap_max_free_processors=DEFAULT_MAX_FREE_PROCESSORS;
697 ++static int ap_max_processors=DEFAULT_MAX_PROCESSORS;
698 ++static int ap_min_multiplexers=DEFAULT_MIN_MULTIPLEXERS;
699 ++static int ap_max_multiplexers=DEFAULT_MAX_MULTIPLEXERS;
700 ++static int ap_daemons_limit=0; /* MaxClients */
701 ++static int expire_timeout=DEFAULT_EXPIRE_TIMEOUT;
702 ++static int idle_timeout=DEFAULT_IDLE_TIMEOUT;
703 ++static int multiplexer_idle_timeout=DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
704 ++static int processor_wait_timeout=DEFAULT_PROCESSOR_WAIT_TIMEOUT;
705 ++static int processor_wait_steps=DEFAULT_PROCESSOR_WAIT_STEPS;
706 ++static int server_limit = DEFAULT_SERVER_LIMIT;
707 ++static int first_server_limit;
708 ++static int changed_limit_at_restart;
709 ++static int requests_this_child;
710 ++static int mpm_state = AP_MPMQ_STARTING;
711 ++static ap_pod_t *pod;
712 ++
713 ++/* === configuration stuff === */
714 ++
715 ++typedef struct
716 ++{
717 ++ int processor_id;
718 ++
719 ++ const char *name; /* Server environment's unique string identifier */
720 ++
721 ++ /* security settings */
722 ++ uid_t uid; /* user id */
723 ++ gid_t gid; /* group id */
724 ++ const char *chroot; /* directory to chroot() to, can be null */
725 ++ short nice_lvl;
726 ++ const char *cgroup; /* cgroup directory, can be null */
727 ++
728 ++ /* resource settings */
729 ++ int min_processors;
730 ++ int min_free_processors;
731 ++ int max_free_processors;
732 ++ int max_processors;
733 ++ short availability;
734 ++
735 ++ /* sockets */
736 ++ int input; /* The socket descriptor */
737 ++ int output; /* The socket descriptor */
738 ++
739 ++ /* error flags */
740 ++ /* we use these to reduce log clutter (report only on first failure) */
741 ++ short error_cgroup; /* When writing pid to cgroup fails */
742 ++ short error_pass; /* When unable to pass request to the processor (eg all workers busy) */
743 ++} server_env_t;
744 ++
745 ++typedef struct
746 ++{
747 ++ apr_size_t num;
748 ++} server_env_control;
749 ++
750 ++typedef struct
751 ++{
752 ++ server_env_control *control;
753 ++ server_env_t *table;
754 ++} server_env;
755 ++
756 ++
757 ++typedef struct
758 ++{
759 ++ /* identification */
760 ++ int id; /* index in child_info_table */
761 ++ pid_t pid; /* process id */
762 ++ int status; /* status of child */
763 ++ int type; /* multiplexer or processor */
764 ++ server_env_t *senv;
765 ++
766 ++ /* sockets */
767 ++ int sock_fd;
768 ++
769 ++ /* stack context saved state */
770 ++ jmp_buf jmpbuffer;
771 ++} child_info_t;
772 ++
773 ++typedef struct
774 ++{
775 ++ /* identification */
776 ++ int id; /* index in child_info_table */
777 ++ pid_t pid; /* process id */
778 ++ int status; /* status of child */
779 ++ int type; /* multiplexer or processor */
780 ++ apr_time_t last_used;
781 ++} child_grace_info_t;
782 ++
783 ++typedef struct
784 ++{
785 ++ apr_size_t num;
786 ++} child_info_control;
787 ++
788 ++typedef struct
789 ++{
790 ++ child_info_control *control;
791 ++ child_info_t *table;
792 ++} child_info;
793 ++
794 ++typedef struct
795 ++{
796 ++ server_env_t *senv;
797 ++ short missing_senv_reported;
798 ++} peruser_server_conf;
799 ++
800 ++
801 ++typedef struct peruser_header
802 ++{
803 ++ char *headers;
804 ++ apr_pool_t *p;
805 ++} peruser_header;
806 ++
807 ++
808 ++/* Tables used to determine the user and group each child process should
809 ++ * run as. The hash table is used to correlate a server name with a child
810 ++ * process.
811 ++ */
812 ++static apr_size_t child_info_size;
813 ++static child_info *child_info_image = NULL;
814 ++static child_grace_info_t *child_grace_info_table;
815 ++struct ap_ctable *ap_child_table;
816 ++
817 ++#define NUM_CHILDS (child_info_image != NULL ? child_info_image->control->num : 0)
818 ++#define CHILD_INFO_TABLE (child_info_image != NULL ? child_info_image->table : NULL)
819 ++
820 ++static apr_size_t server_env_size;
821 ++static server_env *server_env_image = NULL;
822 ++
823 ++#define NUM_SENV (server_env_image != NULL ? server_env_image->control->num : 0)
824 ++#define SENV (server_env_image != NULL ? server_env_image->table : NULL)
825 ++
826 ++#if APR_HAS_SHARED_MEMORY
827 ++#ifndef WIN32
828 ++static /* but must be exported to mpm_winnt */
829 ++#endif
830 ++ apr_shm_t *child_info_shm = NULL;
831 ++ apr_shm_t *server_env_shm = NULL;
832 ++#endif
833 ++
834 ++/*
835 ++ * The max child slot ever assigned, preserved across restarts. Necessary
836 ++ * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
837 ++ * use this value to optimize routines that have to scan the entire scoreboard.
838 ++ */
839 ++int ap_max_daemons_limit = -1;
840 ++server_rec *ap_server_conf;
841 ++
842 ++module AP_MODULE_DECLARE_DATA mpm_peruser_module;
843 ++
844 ++/* -- replace the pipe-of-death by an control socket -- */
845 ++static apr_file_t *pipe_of_death_in = NULL;
846 ++static apr_file_t *pipe_of_death_out = NULL;
847 ++
848 ++
849 ++/* one_process --- debugging mode variable; can be set from the command line
850 ++ * with the -X flag. If set, this gets you the child_main loop running
851 ++ * in the process which originally started up (no detach, no make_child),
852 ++ * which is a pretty nice debugging environment. (You'll get a SIGHUP
853 ++ * early in standalone_main; just continue through. This is the server
854 ++ * trying to kill off any child processes which it might have lying
855 ++ * around --- Apache doesn't keep track of their pids, it just sends
856 ++ * SIGHUP to the process group, ignoring it in the root process.
857 ++ * Continue through and you'll be fine.).
858 ++ */
859 ++
860 ++static int one_process = 0;
861 ++
862 ++static apr_pool_t *pconf; /* Pool for config stuff */
863 ++static apr_pool_t *pchild; /* Pool for httpd child stuff */
864 ++
865 ++static pid_t ap_my_pid; /* it seems silly to call getpid all the time */
866 ++static pid_t parent_pid;
867 ++static int my_child_num;
868 ++ap_generation_t volatile ap_my_generation=0;
869 ++
870 ++#ifdef TPF
871 ++int tpf_child = 0;
872 ++char tpf_server_name[INETD_SERVNAME_LENGTH+1];
873 ++#endif /* TPF */
874 ++
875 ++static int die_now = 0;
876 ++
877 ++int grace_children = 0;
878 ++int grace_children_alive = 0;
879 ++int server_env_cleanup = 1;
880 ++const char *multiplexer_chroot = NULL;
881 ++
882 ++// function added to mod_ssl and exported (there was nothing useful for us in the current api)
883 ++typedef int (*ssl_server_is_https_t)(server_rec*);
884 ++ssl_server_is_https_t ssl_server_is_https = NULL;
885 ++
886 ++#ifdef GPROF
887 ++/*
888 ++ * change directory for gprof to plop the gmon.out file
889 ++ * configure in httpd.conf:
890 ++ * GprofDir $RuntimeDir/ -> $ServerRoot/$RuntimeDir/gmon.out
891 ++ * GprofDir $RuntimeDir/% -> $ServerRoot/$RuntimeDir/gprof.$pid/gmon.out
892 ++ */
893 ++static void chdir_for_gprof(void)
894 ++{
895 ++ core_server_config *sconf =
896 ++ ap_get_module_config(ap_server_conf->module_config, &core_module);
897 ++ char *dir = sconf->gprof_dir;
898 ++ const char *use_dir;
899 ++
900 ++ if(dir) {
901 ++ apr_status_t res;
902 ++ char buf[512];
903 ++ int len = strlen(sconf->gprof_dir) - 1;
904 ++ if(*(dir + len) == '%') {
905 ++ dir[len] = '\0';
906 ++ apr_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid());
907 ++ }
908 ++ use_dir = ap_server_root_relative(pconf, buf[0] ? buf : dir);
909 ++ res = apr_dir_make(use_dir, 0755, pconf);
910 ++ if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) {
911 ++ ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf,
912 ++ "gprof: error creating directory %s", dir);
913 ++ }
914 ++ }
915 ++ else {
916 ++ use_dir = ap_server_root_relative(pconf, DEFAULT_REL_RUNTIMEDIR);
917 ++ }
918 ++
919 ++ chdir(use_dir);
920 ++}
921 ++#else
922 ++#define chdir_for_gprof()
923 ++#endif
924 ++
925 ++char* child_type_string(int type)
926 ++{
927 ++ switch(type)
928 ++ {
929 ++ case CHILD_TYPE_MULTIPLEXER: return "MULTIPLEXER";
930 ++ case CHILD_TYPE_PROCESSOR: return "PROCESSOR";
931 ++ case CHILD_TYPE_WORKER: return "WORKER";
932 ++ }
933 ++
934 ++ return "UNKNOWN";
935 ++}
936 ++
937 ++char* child_status_string(int status)
938 ++{
939 ++ switch(status)
940 ++ {
941 ++ case CHILD_STATUS_STANDBY: return "STANDBY";
942 ++ case CHILD_STATUS_STARTING: return "STARTING";
943 ++ case CHILD_STATUS_READY: return "READY";
944 ++ case CHILD_STATUS_ACTIVE: return "ACTIVE";
945 ++ case CHILD_STATUS_RESTART: return "RESTART";
946 ++ }
947 ++
948 ++ return "UNKNOWN";
949 ++}
950 ++
951 ++char* scoreboard_status_string(int status) {
952 ++ switch(status)
953 ++ {
954 ++ case SERVER_DEAD: return "DEAD";
955 ++ case SERVER_STARTING: return "STARTING";
956 ++ case SERVER_READY: return "READY";
957 ++ case SERVER_BUSY_READ: return "BUSY_READ";
958 ++ case SERVER_BUSY_WRITE: return "BUSY_WRITE";
959 ++ case SERVER_BUSY_KEEPALIVE: return "BUSY_KEEPALIVE";
960 ++ case SERVER_BUSY_LOG: return "BUSY_LOG";
961 ++ case SERVER_BUSY_DNS: return "BUSY_DNS";
962 ++ case SERVER_CLOSING: return "CLOSING";
963 ++ case SERVER_GRACEFUL: return "GRACEFUL";
964 ++ case SERVER_NUM_STATUS: return "NUM_STATUS";
965 ++ }
966 ++
967 ++ return "UNKNOWN";
968 ++}
969 ++
970 ++void dump_child_table()
971 ++{
972 ++#ifdef MPM_PERUSER_DEBUG
973 ++ int x;
974 ++ server_env_t *senv;
975 ++
976 ++ _DBG("%-3s %-5s %-8s %-12s %-4s %-4s %-25s %5s %6s %7s",
977 ++ "ID", "PID", "STATUS", "TYPE", "UID", "GID", "CHROOT", "INPUT", "OUTPUT", "SOCK_FD");
978 ++
979 ++ for(x = 0; x < NUM_CHILDS; x++)
980 ++ {
981 ++ senv = CHILD_INFO_TABLE[x].senv;
982 ++ _DBG("%-3d %-5d %-8s %-12s %-4d %-4d %-25s %-5d %-6d %-7d",
983 ++ CHILD_INFO_TABLE[x].id,
984 ++ CHILD_INFO_TABLE[x].pid,
985 ++ child_status_string(CHILD_INFO_TABLE[x].status),
986 ++ child_type_string(CHILD_INFO_TABLE[x].type),
987 ++ senv == NULL ? -1 : senv->uid,
988 ++ senv == NULL ? -1 : senv->gid,
989 ++ senv == NULL ? NULL : senv->chroot,
990 ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input,
991 ++ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output,
992 ++ CHILD_INFO_TABLE[x].sock_fd);
993 ++ }
994 ++#endif
995 ++}
996 ++
997 ++void dump_server_env_image()
998 ++{
999 ++#ifdef MPM_PERUSER_DEBUG
1000 ++ int x;
1001 ++ _DBG("%-3s %-7s %-7s %-7s", "N", "INPUT", "OUTPUT", "CHROOT");
1002 ++ for(x = 0; x < NUM_SENV; x++)
1003 ++ {
1004 ++ _DBG("%-3d %-7d %-7d %-7s", x, SENV[x].input, SENV[x].output, SENV[x].chroot);
1005 ++ }
1006 ++#endif
1007 ++}
1008 ++
1009 ++
1010 ++/* XXX - I don't know if TPF will ever use this module or not, so leave
1011 ++ * the ap_check_signals calls in but disable them - manoj */
1012 ++#define ap_check_signals()
1013 ++
1014 ++/* a clean exit from a child with proper cleanup */
1015 ++static inline int clean_child_exit(int code) __attribute__ ((noreturn));
1016 ++static inline int clean_child_exit(int code)
1017 ++{
1018 ++ int retval;
1019 ++
1020 ++ mpm_state = AP_MPMQ_STOPPING;
1021 ++
1022 ++ if (CHILD_INFO_TABLE[my_child_num].type != CHILD_TYPE_MULTIPLEXER &&
1023 ++ CHILD_INFO_TABLE[my_child_num].senv)
1024 ++ {
1025 ++ retval = close(CHILD_INFO_TABLE[my_child_num].senv->input);
1026 ++ _DBG("close(CHILD_INFO_TABLE[%d].senv->input) = %d",
1027 ++ my_child_num, retval);
1028 ++
1029 ++ retval = close(CHILD_INFO_TABLE[my_child_num].senv->output);
1030 ++ _DBG("close(CHILD_INFO_TABLE[%d].senv->output) = %d",
1031 ++ my_child_num, retval);
1032 ++ }
1033 ++
1034 ++ if (pchild) {
1035 ++ apr_pool_destroy(pchild);
1036 ++ }
1037 ++ ap_mpm_pod_close(pod);
1038 ++ chdir_for_gprof();
1039 ++ exit(code);
1040 ++}
1041 ++
1042 ++static void accept_mutex_on(void)
1043 ++{
1044 ++ apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
1045 ++ if (rv != APR_SUCCESS) {
1046 ++ const char *msg = "couldn't grab the accept mutex";
1047 ++
1048 ++ if (ap_my_generation !=
1049 ++ ap_scoreboard_image->global->running_generation) {
1050 ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg);
1051 ++ clean_child_exit(0);
1052 ++ }
1053 ++ else {
1054 ++ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg);
1055 ++ exit(APEXIT_CHILDFATAL);
1056 ++ }
1057 ++ }
1058 ++}
1059 ++
1060 ++static void accept_mutex_off(void)
1061 ++{
1062 ++ apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
1063 ++ if (rv != APR_SUCCESS) {
1064 ++ const char *msg = "couldn't release the accept mutex";
1065 ++
1066 ++ if (ap_my_generation !=
1067 ++ ap_scoreboard_image->global->running_generation) {
1068 ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg);
1069 ++ /* don't exit here... we have a connection to
1070 ++ * process, after which point we'll see that the
1071 ++ * generation changed and we'll exit cleanly
1072 ++ */
1073 ++ }
1074 ++ else {
1075 ++ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg);
1076 ++ exit(APEXIT_CHILDFATAL);
1077 ++ }
1078 ++ }
1079 ++}
1080 ++
1081 ++/* On some architectures it's safe to do unserialized accept()s in the single
1082 ++ * Listen case. But it's never safe to do it in the case where there's
1083 ++ * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
1084 ++ * when it's safe in the single Listen case.
1085 ++ */
1086 ++#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
1087 ++#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
1088 ++#else
1089 ++#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
1090 ++#endif
1091 ++
1092 ++AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
1093 ++{
1094 ++ switch(query_code){
1095 ++ case AP_MPMQ_MAX_DAEMON_USED:
1096 ++ *result = ap_daemons_limit;
1097 ++ return APR_SUCCESS;
1098 ++ case AP_MPMQ_IS_THREADED:
1099 ++ *result = AP_MPMQ_NOT_SUPPORTED;
1100 ++ return APR_SUCCESS;
1101 ++ case AP_MPMQ_IS_FORKED:
1102 ++ *result = AP_MPMQ_DYNAMIC;
1103 ++ return APR_SUCCESS;
1104 ++ case AP_MPMQ_HARD_LIMIT_DAEMONS:
1105 ++ *result = server_limit;
1106 ++ return APR_SUCCESS;
1107 ++ case AP_MPMQ_HARD_LIMIT_THREADS:
1108 ++ *result = HARD_THREAD_LIMIT;
1109 ++ return APR_SUCCESS;
1110 ++ case AP_MPMQ_MAX_THREADS:
1111 ++ *result = 0;
1112 ++ return APR_SUCCESS;
1113 ++ case AP_MPMQ_MIN_SPARE_DAEMONS:
1114 ++ *result = ap_min_free_processors;
1115 ++ return APR_SUCCESS;
1116 ++ case AP_MPMQ_MIN_SPARE_THREADS:
1117 ++ *result = 0;
1118 ++ return APR_SUCCESS;
1119 ++ case AP_MPMQ_MAX_SPARE_THREADS:
1120 ++ *result = 0;
1121 ++ return APR_SUCCESS;
1122 ++ case AP_MPMQ_MAX_REQUESTS_DAEMON:
1123 ++ *result = ap_max_requests_per_child;
1124 ++ return APR_SUCCESS;
1125 ++ case AP_MPMQ_MAX_DAEMONS:
1126 ++ *result = server_limit;
1127 ++ return APR_SUCCESS;
1128 ++ case AP_MPMQ_MPM_STATE:
1129 ++ *result = mpm_state;
1130 ++ return APR_SUCCESS;
1131 ++ }
1132 ++ return APR_ENOTIMPL;
1133 ++}
1134 ++
1135 ++#if defined(NEED_WAITPID)
1136 ++/*
1137 ++ Systems without a real waitpid sometimes lose a child's exit while waiting
1138 ++ for another. Search through the scoreboard for missing children.
1139 ++ */
1140 ++int reap_children(int *exitcode, apr_exit_why_e *status)
1141 ++{
1142 ++ int n, pid;
1143 ++
1144 ++ for (n = 0; n < ap_max_daemons_limit; ++n) {
1145 ++ if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
1146 ++ kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
1147 ++ ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL);
1148 ++ /* just mark it as having a successful exit status */
1149 ++ *status = APR_PROC_EXIT;
1150 ++ *exitcode = 0;
1151 ++ return(pid);
1152 ++ }
1153 ++ }
1154 ++ return 0;
1155 ++}
1156 ++#endif
1157 ++
1158 ++/* handle all varieties of core dumping signals */
1159 ++static void sig_coredump(int sig)
1160 ++{
1161 ++ int retval;
1162 ++ retval = chdir(ap_coredump_dir);
1163 ++ apr_signal(sig, SIG_DFL);
1164 ++ if (ap_my_pid == parent_pid) {
1165 ++ ap_log_error(APLOG_MARK, APLOG_NOTICE,
1166 ++ 0, ap_server_conf,
1167 ++ "seg fault or similar nasty error detected "
1168 ++ "in the parent process");
1169 ++ }
1170 ++ kill(getpid(), sig);
1171 ++ /* At this point we've got sig blocked, because we're still inside
1172 ++ * the signal handler. When we leave the signal handler it will
1173 ++ * be unblocked, and we'll take the signal... and coredump or whatever
1174 ++ * is appropriate for this particular Unix. In addition the parent
1175 ++ * will see the real signal we received -- whereas if we called
1176 ++ * abort() here, the parent would only see SIGABRT.
1177 ++ */
1178 ++}
1179 ++
1180 ++/*****************************************************************
1181 ++ * Connection structures and accounting...
1182 ++ */
1183 ++
1184 ++static void just_die(int sig)
1185 ++{
1186 ++_DBG("function called");
1187 ++ clean_child_exit(0);
1188 ++}
1189 ++
1190 ++/* volatile just in case */
1191 ++static int volatile shutdown_pending;
1192 ++static int volatile restart_pending;
1193 ++static int volatile is_graceful;
1194 ++/* XXX static int volatile child_fatal; */
1195 ++
1196 ++static void sig_term(int sig)
1197 ++{
1198 ++ if (shutdown_pending == 1) {
1199 ++ /* Um, is this _probably_ not an error, if the user has
1200 ++ * tried to do a shutdown twice quickly, so we won't
1201 ++ * worry about reporting it.
1202 ++ */
1203 ++ return;
1204 ++ }
1205 ++ shutdown_pending = 1;
1206 ++}
1207 ++
1208 ++/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL
1209 ++ * in the parent process, unless running in ONE_PROCESS mode
1210 ++ */
1211 ++static void restart(int sig)
1212 ++{
1213 ++ if (restart_pending == 1) {
1214 ++ /* Probably not an error - don't bother reporting it */
1215 ++ return;
1216 ++ }
1217 ++ restart_pending = 1;
1218 ++ is_graceful = (sig == AP_SIG_GRACEFUL);
1219 ++}
1220 ++
1221 ++/* Sets die_now if we received a character on the pipe_of_death */
1222 ++static apr_status_t check_pipe_of_death
1223 ++(
1224 ++ void **csd,
1225 ++ ap_listen_rec *lr,
1226 ++ apr_pool_t *ptrans
1227 ++)
1228 ++{
1229 ++ int ret;
1230 ++ char pipe_read_char;
1231 ++ apr_size_t n = 1;
1232 ++
1233 ++ _DBG("WATCH: die_now=%d", die_now);
1234 ++
1235 ++ if (die_now) return APR_SUCCESS;
1236 ++
1237 ++ /* apr_thread_mutex_lock(pipe_of_death_mutex); */
1238 ++ ret = apr_socket_recv(lr->sd, &pipe_read_char, &n);
1239 ++ if (APR_STATUS_IS_EAGAIN(ret))
1240 ++ {
1241 ++ /* It lost the lottery. It must continue to suffer
1242 ++ * through a life of servitude. */
1243 ++ _DBG("POD read EAGAIN");
1244 ++ return ret;
1245 ++ }
1246 ++ else
1247 ++ {
1248 ++ if (pipe_read_char != AP_PERUSER_CHAR_OF_DEATH)
1249 ++ {
1250 ++ _DBG("got wrong char %c", pipe_read_char);
1251 ++ return APR_SUCCESS;
1252 ++ }
1253 ++ /* It won the lottery (or something else is very
1254 ++ * wrong). Embrace death with open arms. */
1255 ++ die_now = 1;
1256 ++ _DBG("WATCH: die_now=%d", die_now);
1257 ++ }
1258 ++ /* apr_thread_mutex_unlock(pipe_of_death_mutex); */
1259 ++ return APR_SUCCESS;
1260 ++}
1261 ++
1262 ++static void set_signals(void)
1263 ++{
1264 ++#ifndef NO_USE_SIGACTION
1265 ++ struct sigaction sa;
1266 ++
1267 ++ sigemptyset(&sa.sa_mask);
1268 ++ sa.sa_flags = 0;
1269 ++
1270 ++ if (!one_process) {
1271 ++ sa.sa_handler = sig_coredump;
1272 ++#if defined(SA_ONESHOT)
1273 ++ sa.sa_flags = SA_ONESHOT;
1274 ++#elif defined(SA_RESETHAND)
1275 ++ sa.sa_flags = SA_RESETHAND;
1276 ++#endif
1277 ++ if (sigaction(SIGSEGV, &sa, NULL) < 0)
1278 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");
1279 ++#ifdef SIGBUS
1280 ++ if (sigaction(SIGBUS, &sa, NULL) < 0)
1281 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
1282 ++#endif
1283 ++#ifdef SIGABORT
1284 ++ if (sigaction(SIGABORT, &sa, NULL) < 0)
1285 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");
1286 ++#endif
1287 ++#ifdef SIGABRT
1288 ++ if (sigaction(SIGABRT, &sa, NULL) < 0)
1289 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
1290 ++#endif
1291 ++#ifdef SIGILL
1292 ++ if (sigaction(SIGILL, &sa, NULL) < 0)
1293 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)");
1294 ++#endif
1295 ++ sa.sa_flags = 0;
1296 ++ }
1297 ++ sa.sa_handler = sig_term;
1298 ++ if (sigaction(SIGTERM, &sa, NULL) < 0)
1299 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
1300 ++#ifdef SIGINT
1301 ++ if (sigaction(SIGINT, &sa, NULL) < 0)
1302 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
1303 ++#endif
1304 ++#ifdef SIGXCPU
1305 ++ sa.sa_handler = SIG_DFL;
1306 ++ if (sigaction(SIGXCPU, &sa, NULL) < 0)
1307 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)");
1308 ++#endif
1309 ++#ifdef SIGXFSZ
1310 ++ sa.sa_handler = SIG_IGN;
1311 ++ if (sigaction(SIGXFSZ, &sa, NULL) < 0)
1312 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)");
1313 ++#endif
1314 ++#ifdef SIGPIPE
1315 ++ sa.sa_handler = SIG_IGN;
1316 ++ if (sigaction(SIGPIPE, &sa, NULL) < 0)
1317 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");
1318 ++#endif
1319 ++
1320 ++ /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
1321 ++ * processing one */
1322 ++ sigaddset(&sa.sa_mask, SIGHUP);
1323 ++ sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
1324 ++ sa.sa_handler = restart;
1325 ++ if (sigaction(SIGHUP, &sa, NULL) < 0)
1326 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
1327 ++ if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
1328 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
1329 ++#else
1330 ++ if (!one_process) {
1331 ++ apr_signal(SIGSEGV, sig_coredump);
1332 ++#ifdef SIGBUS
1333 ++ apr_signal(SIGBUS, sig_coredump);
1334 ++#endif /* SIGBUS */
1335 ++#ifdef SIGABORT
1336 ++ apr_signal(SIGABORT, sig_coredump);
1337 ++#endif /* SIGABORT */
1338 ++#ifdef SIGABRT
1339 ++ apr_signal(SIGABRT, sig_coredump);
1340 ++#endif /* SIGABRT */
1341 ++#ifdef SIGILL
1342 ++ apr_signal(SIGILL, sig_coredump);
1343 ++#endif /* SIGILL */
1344 ++#ifdef SIGXCPU
1345 ++ apr_signal(SIGXCPU, SIG_DFL);
1346 ++#endif /* SIGXCPU */
1347 ++#ifdef SIGXFSZ
1348 ++ apr_signal(SIGXFSZ, SIG_DFL);
1349 ++#endif /* SIGXFSZ */
1350 ++ }
1351 ++
1352 ++ apr_signal(SIGTERM, sig_term);
1353 ++#ifdef SIGHUP
1354 ++ apr_signal(SIGHUP, restart);
1355 ++#endif /* SIGHUP */
1356 ++#ifdef AP_SIG_GRACEFUL
1357 ++ apr_signal(AP_SIG_GRACEFUL, restart);
1358 ++#endif /* AP_SIG_GRACEFUL */
1359 ++#ifdef SIGPIPE
1360 ++ apr_signal(SIGPIPE, SIG_IGN);
1361 ++#endif /* SIGPIPE */
1362 ++
1363 ++#endif
1364 ++}
1365 ++
1366 ++/*****************************************************************
1367 ++ * Child process main loop.
1368 ++ * The following vars are static to avoid getting clobbered by longjmp();
1369 ++ * they are really private to child_main.
1370 ++ */
1371 ++
1372 ++static int requests_this_child;
1373 ++static int num_listensocks = 0;
1374 ++static ap_listen_rec *listensocks;
1375 ++
1376 ++int ap_graceful_stop_signalled(void)
1377 ++{
1378 ++ /* not ever called anymore... */
1379 ++ return 0;
1380 ++}
1381 ++
1382 ++
1383 ++static int total_processors(int child_num)
1384 ++{
1385 ++ int i, total;
1386 ++
1387 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
1388 ++ {
1389 ++ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv)
1390 ++ total++;
1391 ++ }
1392 ++
1393 ++ return total;
1394 ++}
1395 ++
1396 ++static int active_processors(int child_num)
1397 ++{
1398 ++ int i, total;
1399 ++
1400 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
1401 ++ {
1402 ++ if( (CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv) && (CHILD_INFO_TABLE[i].pid > 0 ) )
1403 ++ total++;
1404 ++ }
1405 ++
1406 ++ return total;
1407 ++}
1408 ++
1409 ++static int active_env_processors(int env_num)
1410 ++{
1411 ++ int i, total;
1412 ++
1413 ++ if(env_num >= NUM_SENV)
1414 ++ return -1;
1415 ++
1416 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
1417 ++ {
1418 ++ if((CHILD_INFO_TABLE[i].senv == &SENV[env_num]) && (CHILD_INFO_TABLE[i].pid > 0))
1419 ++ total++;
1420 ++ }
1421 ++
1422 ++ return total;
1423 ++}
1424 ++
1425 ++static int idle_processors(int child_num)
1426 ++{
1427 ++ int i, total;
1428 ++
1429 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
1430 ++ {
1431 ++ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
1432 ++ (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY))
1433 ++ {
1434 ++ total++;
1435 ++ }
1436 ++ }
1437 ++
1438 ++ return total;
1439 ++}
1440 ++
1441 ++static int idle_env_processors(int env_num)
1442 ++{
1443 ++ int i, total;
1444 ++
1445 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
1446 ++ {
1447 ++ if(CHILD_INFO_TABLE[i].senv == &SENV[env_num] && (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY) )
1448 ++ total++;
1449 ++ }
1450 ++
1451 ++ return total;
1452 ++}
1453 ++
1454 ++
1455 ++static int wait_for_workers(child_info_t *processor) {
1456 ++ int i, wait_step_size, wait_time;
1457 ++
1458 ++ wait_step_size = 100 / processor_wait_steps;
1459 ++
1460 ++ /* Check if the processor is available */
1461 ++ if (total_processors(processor->id) == processor->senv->max_processors &&
1462 ++ idle_processors(processor->id) == 0 && processor_wait_timeout > 0) {
1463 ++ /* The processor is currently busy, try to wait (a little) */
1464 ++ _DBG("processor seems to be busy, trying to wait for it");
1465 ++
1466 ++ if (processor->senv->availability == 0) {
1467 ++ processor->senv->availability = 0;
1468 ++
1469 ++ _DBG("processor is very busy (availability = 0) - not passing request");
1470 ++
1471 ++ if (processor->senv->error_pass == 0) {
1472 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
1473 ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
1474 ++ }
1475 ++
1476 ++ /* No point in waiting for the processor, it's very busy */
1477 ++ return -1;
1478 ++ }
1479 ++
1480 ++ /* We sleep a little (depending how available the processor usually is) */
1481 ++ wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000;
1482 ++
1483 ++ for(i = 0; i <= processor->senv->availability; i += wait_step_size) {
1484 ++ usleep(wait_time);
1485 ++
1486 ++ /* Check if the processor is ready */
1487 ++ if (total_processors(processor->id) < processor->senv->max_processors ||
1488 ++ idle_processors(processor->id) > 0) {
1489 ++ /* The processor has freed - lets use it */
1490 ++ _DBG("processor freed before wait time expired");
1491 ++ break;
1492 ++ }
1493 ++ }
1494 ++
1495 ++ if (processor->senv->availability <= wait_step_size) {
1496 ++ processor->senv->availability = 0;
1497 ++ }
1498 ++ else processor->senv->availability -= wait_step_size;
1499 ++
1500 ++ /* Check if we waited all the time */
1501 ++ if (i > processor->senv->availability) {
1502 ++ _DBG("processor is busy - not passing request (availability = %d)",
1503 ++ processor->senv->availability);
1504 ++
1505 ++ if (processor->senv->error_pass == 0) {
1506 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
1507 ++ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
1508 ++ }
1509 ++
1510 ++ return -1;
1511 ++ }
1512 ++
1513 ++ /* We could increase the availability a little here,
1514 ++ * because the processor got freed eventually
1515 ++ */
1516 ++ }
1517 ++ else {
1518 ++ /* Smoothly increment the availability back to 100 */
1519 ++ if (processor->senv->availability >= 100-wait_step_size) {
1520 ++ processor->senv->availability = 100;
1521 ++ }
1522 ++ else processor->senv->availability += wait_step_size;
1523 ++ }
1524 ++
1525 ++ return 0;
1526 ++}
1527 ++
1528 ++/*
1529 ++ * This function sends a raw socket over to a processor. It uses the same
1530 ++ * on-wire format as pass_request. The recipient can determine if he got
1531 ++ * a socket or a whole request by inspecting the header_length of the
1532 ++ * message. If it is zero then only a socket was sent.
1533 ++ */
1534 ++static int pass_socket(apr_socket_t *thesock, child_info_t *processor, apr_pool_t *pool)
1535 ++{
1536 ++ int rv;
1537 ++ struct msghdr msg;
1538 ++ struct cmsghdr *cmsg;
1539 ++ apr_sockaddr_t *remote_addr;
1540 ++ int sock_fd;
1541 ++ char *body = "";
1542 ++ struct iovec iov[5];
1543 ++ apr_size_t header_len = 0;
1544 ++ apr_size_t body_len = 0;
1545 ++ peruser_header h;
1546 ++
1547 ++ if (!processor)
1548 ++ {
1549 ++ _DBG("server %s in child %d has no child_info associated",
1550 ++ "(unkonwn)", my_child_num);
1551 ++ return -1;
1552 ++ }
1553 ++
1554 ++ /* Make sure there are free workers on the other end */
1555 ++ if (wait_for_workers(processor) == -1) return -1;
1556 ++
1557 ++ _DBG("passing request to another child.", 0);
1558 ++
1559 ++ apr_os_sock_get(&sock_fd, thesock);
1560 ++ /* passing remote_addr too, see comments below */
1561 ++ apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock);
1562 ++
1563 ++ header_len = 0;
1564 ++ body_len = 0;
1565 ++
1566 ++ iov[0].iov_base = &header_len;
1567 ++ iov[0].iov_len = sizeof(header_len);
1568 ++ iov[1].iov_base = &body_len;
1569 ++ iov[1].iov_len = sizeof(body_len);
1570 ++ iov[2].iov_base = remote_addr;
1571 ++ iov[2].iov_len = sizeof(*remote_addr);
1572 ++ iov[3].iov_base = h.headers;
1573 ++ iov[3].iov_len = 0;
1574 ++ iov[4].iov_base = body;
1575 ++ iov[4].iov_len = body_len;
1576 ++
1577 ++ msg.msg_name = NULL;
1578 ++ msg.msg_namelen = 0;
1579 ++ msg.msg_iov = iov;
1580 ++ msg.msg_iovlen = 5;
1581 ++
1582 ++ cmsg = apr_palloc(pool, sizeof(*cmsg) + sizeof(sock_fd));
1583 ++ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd));
1584 ++ cmsg->cmsg_level = SOL_SOCKET;
1585 ++ cmsg->cmsg_type = SCM_RIGHTS;
1586 ++
1587 ++ memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd));
1588 ++
1589 ++ msg.msg_control = cmsg;
1590 ++ msg.msg_controllen = cmsg->cmsg_len;
1591 ++
1592 ++ if (processor->status == CHILD_STATUS_STANDBY)
1593 ++ {
1594 ++ _DBG("Activating child #%d", processor->id);
1595 ++ processor->status = CHILD_STATUS_STARTING;
1596 ++ }
1597 ++
1598 ++ _DBG("Writing message to %d, passing sock_fd: %d", processor->senv->output, sock_fd);
1599 ++ _DBG("header_len=%d headers=\"%s\"", header_len, h.headers);
1600 ++ _DBG("body_len=%d body=\"%s\"", body_len, body);
1601 ++
1602 ++ if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1)
1603 ++ {
1604 ++ apr_pool_destroy(pool);
1605 ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1606 ++ "Writing message failed %d %d", rv, errno);
1607 ++ return -1;
1608 ++ }
1609 ++
1610 ++ _DBG("Writing message succeeded %d", rv);
1611 ++
1612 ++ /* -- close the socket on our side -- */
1613 ++ _DBG("closing socket %d on our side", sock_fd);
1614 ++ apr_socket_close(thesock);
1615 ++
1616 ++ apr_pool_destroy(pool);
1617 ++ return 1;
1618 ++}
1619 ++
1620 ++static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id,
1621 ++ apr_bucket_alloc_t *bucket_alloc, apr_pool_t *pool)
1622 ++{
1623 ++ conn_rec *current_conn;
1624 ++ int sock_fd;
1625 ++ apr_status_t rv;
1626 ++ ap_sb_handle_t *sbh;
1627 ++ child_info_t *processor;
1628 ++ apr_pool_t *ptrans;
1629 ++ peruser_server_conf *sconf;
1630 ++ int ssl_on = 0;
1631 ++
1632 ++ _DBG("Creating dummy connection to use the vhost lookup api", 0);
1633 ++
1634 ++ ap_create_sb_handle(&sbh, p, conn_id, 0);
1635 ++ current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id,
1636 ++ sbh, bucket_alloc);
1637 ++ _DBG("Looking up the right vhost");
1638 ++ if (current_conn) {
1639 ++ ap_update_vhost_given_ip(current_conn);
1640 ++ _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname,
1641 ++ current_conn->vhost_lookup_data ? "on" : "off");
1642 ++
1643 ++ // check for ssl configuration for this server (ssl_server_is_https is NULL if we have no mod_ssl)
1644 ++ if(ssl_server_is_https) ssl_on = ssl_server_is_https(current_conn->base_server);
1645 ++ }
1646 ++
1647 ++ if (current_conn && (!current_conn->vhost_lookup_data || ssl_on) && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
1648 ++ _DBG("We are not using name based vhosts (or SSL is enabled), we'll directly pass the socket.");
1649 ++
1650 ++ sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config);
1651 ++
1652 ++ if (sconf->senv != NULL) {
1653 ++ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id];
1654 ++
1655 ++ _DBG("Forwarding without further inspection, processor %d", processor->id);
1656 ++ if (processor->status == CHILD_STATUS_STANDBY)
1657 ++ {
1658 ++ _DBG("Activating child #%d", processor->id);
1659 ++ processor->status = CHILD_STATUS_STARTING;
1660 ++ }
1661 ++
1662 ++ _DBG("Creating new pool",0);
1663 ++ apr_pool_create(&ptrans, pool);
1664 ++
1665 ++ _DBG("Passing request.",0);
1666 ++ if (pass_socket(sock, processor, ptrans) == -1) {
1667 ++ if (processor->senv->error_pass == 0) {
1668 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
1669 ++ ap_server_conf, "Could not pass request to proper "
1670 ++ "child, request will not be honoured.");
1671 ++ }
1672 ++
1673 ++ processor->senv->error_pass = 1;
1674 ++ }
1675 ++ else {
1676 ++ processor->senv->error_pass = 0;
1677 ++ }
1678 ++ }
1679 ++ else {
1680 ++ _DBG("Base server has no senv set!");
1681 ++
1682 ++ if (sconf->missing_senv_reported == 0) {
1683 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
1684 ++ ap_server_conf, "Virtualhost %s has no server environment set, "
1685 ++ "request will not be honoured.", current_conn->base_server->server_hostname);
1686 ++ }
1687 ++
1688 ++ sconf->missing_senv_reported = 1;
1689 ++ }
1690 ++
1691 ++ if (current_conn)
1692 ++ {
1693 ++ _DBG("freeing connection",0);
1694 ++ ap_lingering_close(current_conn);
1695 ++ }
1696 ++
1697 ++ _DBG("doing longjmp",0);
1698 ++ longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
1699 ++ return;
1700 ++ }
1701 ++
1702 ++ if ((rv = apr_os_sock_get(&sock_fd, sock)) != APR_SUCCESS)
1703 ++ {
1704 ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get");
1705 ++ }
1706 ++
1707 ++ _DBG("child_num=%d sock=%ld sock_fd=%d", my_child_num, sock, sock_fd);
1708 ++ _DBG("type=%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num);
1709 ++
1710 ++#ifdef _OSD_POSIX
1711 ++ if (sock_fd >= FD_SETSIZE)
1712 ++ {
1713 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
1714 ++ "new file descriptor %d is too large; you probably need "
1715 ++ "to rebuild Apache with a larger FD_SETSIZE "
1716 ++ "(currently %d)",
1717 ++ sock_fd, FD_SETSIZE);
1718 ++ apr_socket_close(sock);
1719 ++ _DBG("child_num=%d: exiting with error", my_child_num);
1720 ++ return;
1721 ++ }
1722 ++#endif
1723 ++
1724 ++ if (CHILD_INFO_TABLE[my_child_num].sock_fd < 0)
1725 ++ {
1726 ++ ap_sock_disable_nagle(sock);
1727 ++ }
1728 ++
1729 ++ if (!current_conn) {
1730 ++ ap_create_sb_handle(&sbh, p, conn_id, 0);
1731 ++ current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id,
1732 ++ sbh, bucket_alloc);
1733 ++ }
1734 ++
1735 ++ if (current_conn)
1736 ++ {
1737 ++ ap_process_connection(current_conn, sock);
1738 ++ ap_lingering_close(current_conn);
1739 ++ }
1740 ++}
1741 ++
1742 ++static int peruser_process_connection(conn_rec *conn)
1743 ++{
1744 ++ ap_filter_t *filter;
1745 ++ apr_bucket_brigade *bb;
1746 ++ core_net_rec *net;
1747 ++
1748 ++ _DBG("function entered",0);
1749 ++
1750 ++ /* -- fetch our sockets from the pool -- */
1751 ++ apr_pool_userdata_get((void **)&bb, "PERUSER_SOCKETS", conn->pool);
1752 ++ if (bb != NULL)
1753 ++ {
1754 ++ /* -- find the 'core' filter and give the socket data to it -- */
1755 ++ for (filter = conn->output_filters; filter != NULL; filter = filter->next)
1756 ++ {
1757 ++ if (!strcmp(filter->frec->name, "core")) break;
1758 ++ }
1759 ++ if (filter != NULL)
1760 ++ {
1761 ++ net = filter->ctx;
1762 ++ net->in_ctx = apr_palloc(conn->pool, sizeof(*net->in_ctx));
1763 ++ net->in_ctx->b = bb;
1764 ++ net->in_ctx->tmpbb = apr_brigade_create(net->in_ctx->b->p,
1765 ++ net->in_ctx->b->bucket_alloc);
1766 ++ }
1767 ++ }
1768 ++ _DBG("leaving (DECLINED)", 0);
1769 ++ return DECLINED;
1770 ++}
1771 ++
1772 ++static int pass_request(request_rec *r, child_info_t *processor)
1773 ++{
1774 ++ int rv;
1775 ++ struct msghdr msg;
1776 ++ struct cmsghdr *cmsg;
1777 ++ apr_sockaddr_t *remote_addr;
1778 ++ int sock_fd;
1779 ++ char *body = "";
1780 ++ struct iovec iov[5];
1781 ++ conn_rec *c = r->connection;
1782 ++ apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
1783 ++ apr_bucket_brigade *body_bb = NULL;
1784 ++ apr_size_t len = 0;
1785 ++ apr_size_t header_len = 0;
1786 ++ apr_size_t body_len = 0;
1787 ++ peruser_header h;
1788 ++ apr_bucket *bucket;
1789 ++ const apr_array_header_t *headers_in_array;
1790 ++ const apr_table_entry_t *headers_in;
1791 ++ int counter;
1792 ++
1793 ++ apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module);
1794 ++
1795 ++ if ((!r->the_request) || (!strlen(r->the_request)))
1796 ++ {
1797 ++ _DBG("empty request. dropping it (%ld)", r->the_request);
1798 ++ return -1;
1799 ++ }
1800 ++
1801 ++ if (!processor)
1802 ++ {
1803 ++ _DBG("server %s in child %d has no child_info associated",
1804 ++ r->hostname, my_child_num);
1805 ++ return -1;
1806 ++ }
1807 ++
1808 ++ _DBG("passing request to another child. Vhost: %s, child %d %d",
1809 ++ apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output);
1810 ++ _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request));
1811 ++
1812 ++ /* Make sure there are free workers on the other end */
1813 ++ if (wait_for_workers(processor) == -1) return -1;
1814 ++
1815 ++ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
1816 ++
1817 ++ /* Scan the brigade looking for heap-buckets */
1818 ++
1819 ++ _DBG("Scanning the brigade",0);
1820 ++ bucket = APR_BRIGADE_FIRST(bb);
1821 ++ while (bucket != APR_BRIGADE_SENTINEL(bb) &&
1822 ++ APR_BUCKET_IS_HEAP(bucket)) {
1823 ++ _DBG("HEAP BUCKET is found, length=%d", bucket->length);
1824 ++ bucket = APR_BUCKET_NEXT(bucket);
1825 ++ if (!APR_BUCKET_IS_HEAP(bucket)) {
1826 ++ _DBG("NON-HEAP BUCKET is found, extracting the part of brigade before it",0);
1827 ++ body_bb = bb;
1828 ++ bb = apr_brigade_split(body_bb, bucket);
1829 ++ /* Do we need to apr_destroy_brigade(bb) here?
1830 ++ * Yeah, I know we do apr_pool_destroy(r->pool) before return, but
1831 ++ * ap_get_brigade is in non-blocking mode (however len is zero).
1832 ++ */
1833 ++ if (apr_brigade_pflatten(body_bb, &body, &body_len, r->pool) != APR_SUCCESS) {
1834 ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1835 ++ "Unable to flatten brigade, declining request");
1836 ++ apr_pool_destroy(r->pool);
1837 ++ return DECLINED;
1838 ++ }
1839 ++ _DBG("Brigade is flattened as body (body_len=%d)", body_len);
1840 ++ }
1841 ++ }
1842 ++ _DBG("Scanning is finished",0);
1843 ++
1844 ++ apr_os_sock_get(&sock_fd, thesock);
1845 ++ /* looks like a bug while sending/receiving SCM_RIGHTS related to ipv6
1846 ++ workaround: send remote_addr structure too */
1847 ++ apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock);
1848 ++
1849 ++ h.p = r->pool;
1850 ++
1851 ++ headers_in_array = apr_table_elts(r->headers_in);
1852 ++ headers_in = (const apr_table_entry_t *) headers_in_array->elts;
1853 ++
1854 ++ h.headers = apr_pstrcat(h.p, r->the_request, CRLF, NULL);
1855 ++ for (counter = 0; counter < headers_in_array->nelts; counter++) {
1856 ++ if (headers_in[counter].key == NULL
1857 ++ || headers_in[counter].val == NULL) {
1858 ++ continue;
1859 ++ }
1860 ++ h.headers = apr_pstrcat(h.p, h.headers, headers_in[counter].key, ": ",
1861 ++ headers_in[counter].val, CRLF, NULL);
1862 ++
1863 ++ }
1864 ++ h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL);
1865 ++ ap_xlate_proto_to_ascii(h.headers, strlen(h.headers));
1866 ++
1867 ++ header_len = strlen(h.headers);
1868 ++
1869 ++ iov[0].iov_base = &header_len;
1870 ++ iov[0].iov_len = sizeof(header_len);
1871 ++ iov[1].iov_base = &body_len;
1872 ++ iov[1].iov_len = sizeof(body_len);
1873 ++ iov[2].iov_base = remote_addr;
1874 ++ iov[2].iov_len = sizeof(*remote_addr);
1875 ++ iov[3].iov_base = h.headers;
1876 ++ iov[3].iov_len = strlen(h.headers) + 1;
1877 ++ iov[4].iov_base = body;
1878 ++ iov[4].iov_len = body_len;
1879 ++
1880 ++ msg.msg_name = NULL;
1881 ++ msg.msg_namelen = 0;
1882 ++ msg.msg_iov = iov;
1883 ++ msg.msg_iovlen = 5;
1884 ++
1885 ++ cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sock_fd));
1886 ++ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd));
1887 ++ cmsg->cmsg_level = SOL_SOCKET;
1888 ++ cmsg->cmsg_type = SCM_RIGHTS;
1889 ++
1890 ++ memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd));
1891 ++
1892 ++ msg.msg_control = cmsg;
1893 ++ msg.msg_controllen = cmsg->cmsg_len;
1894 ++
1895 ++ if (processor->status == CHILD_STATUS_STANDBY)
1896 ++ {
1897 ++ _DBG("Activating child #%d", processor->id);
1898 ++ processor->status = CHILD_STATUS_STARTING;
1899 ++ }
1900 ++
1901 ++ _DBG("Writing message to %d, passing sock_fd: %d", processor->senv->output, sock_fd);
1902 ++ _DBG("header_len=%d headers=\"%s\"", header_len, h.headers);
1903 ++ _DBG("body_len=%d body=\"%s\"", body_len, body);
1904 ++
1905 ++ if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1)
1906 ++ {
1907 ++ apr_pool_destroy(r->pool);
1908 ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1909 ++ "Writing message failed %d %d", rv, errno);
1910 ++ return -1;
1911 ++ }
1912 ++
1913 ++ _DBG("Writing message succeeded %d", rv);
1914 ++
1915 ++ /* -- close the socket on our side -- */
1916 ++ _DBG("closing socket %d on our side", sock_fd);
1917 ++ apr_socket_close(thesock);
1918 ++
1919 ++ apr_pool_destroy(r->pool);
1920 ++ return 1;
1921 ++}
1922 ++
1923 ++
1924 ++static apr_status_t receive_from_multiplexer(
1925 ++ void **trans_sock, /* will be filled out w/ the received socket */
1926 ++ ap_listen_rec *lr, /* listener to receive from */
1927 ++ apr_pool_t *ptrans /* transaction wide pool */
1928 ++)
1929 ++{
1930 ++ struct msghdr msg;
1931 ++ struct cmsghdr *cmsg;
1932 ++ char buff[HUGE_STRING_LEN] = "";
1933 ++ char headers[HUGE_STRING_LEN] = "";
1934 ++ char *body = "";
1935 ++ apr_size_t header_len, body_len;
1936 ++ struct iovec iov[4];
1937 ++ int ret, fd_tmp;
1938 ++ apr_os_sock_t ctrl_sock_fd;
1939 ++ apr_os_sock_t trans_sock_fd;
1940 ++ apr_sockaddr_t remote_addr;
1941 ++ apr_os_sock_info_t sockinfo;
1942 ++
1943 ++ /* -- bucket's, brigades and their allocators */
1944 ++ apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans);
1945 ++ apr_bucket_brigade *bb = apr_brigade_create(ptrans, alloc);
1946 ++ apr_bucket *bucket;
1947 ++
1948 ++ /* prepare the buffers for receiving data from remote side */
1949 ++ iov[0].iov_base = &header_len;
1950 ++ iov[0].iov_len = sizeof(header_len);
1951 ++ iov[1].iov_base = &body_len;
1952 ++ iov[1].iov_len = sizeof(body_len);
1953 ++ iov[2].iov_base = &remote_addr;
1954 ++ iov[2].iov_len = sizeof(remote_addr);
1955 ++ iov[3].iov_base = (char*)&buff;
1956 ++ iov[3].iov_len = HUGE_STRING_LEN;
1957 ++
1958 ++ cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd));
1959 ++ cmsg->cmsg_len = CMSG_LEN(sizeof(trans_sock_fd));
1960 ++
1961 ++ msg.msg_name = NULL;
1962 ++ msg.msg_namelen = 0;
1963 ++ msg.msg_iov = iov;
1964 ++ msg.msg_iovlen = 4;
1965 ++ msg.msg_control = cmsg;
1966 ++ msg.msg_controllen = cmsg->cmsg_len;
1967 ++
1968 ++ /* -- receive data from socket -- */
1969 ++ apr_os_sock_get(&ctrl_sock_fd, lr->sd);
1970 ++ _DBG("receiving from sock_fd=%d", ctrl_sock_fd);
1971 ++
1972 ++ // Don't block
1973 ++ ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT);
1974 ++
1975 ++ if (ret == -1 && errno == EAGAIN) {
1976 ++ _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster");
1977 ++
1978 ++ return APR_EAGAIN;
1979 ++ }
1980 ++ else if (ret == -1) {
1981 ++ _DBG("recvmsg failed with error \"%s\"", strerror(errno));
1982 ++
1983 ++ // Error, better kill this child to be on the safe side
1984 ++ return APR_EGENERAL;
1985 ++ }
1986 ++ else _DBG("recvmsg returned %d", ret);
1987 ++
1988 ++ /* -- extract socket from the cmsg -- */
1989 ++ memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd));
1990 ++ /* here *trans_sock always == NULL (socket reset at got_fd), so
1991 ++ we can use apr_os_sock_make() instead of apr_os_sock_put() */
1992 ++ sockinfo.os_sock = &trans_sock_fd;
1993 ++ sockinfo.local = NULL;
1994 ++ sockinfo.remote = (struct sockaddr *)&remote_addr.sa.sin;
1995 ++ sockinfo.family = remote_addr.family;
1996 ++ sockinfo.type = SOCK_STREAM;
1997 ++#ifdef APR_ENABLE_FOR_1_0
1998 ++ sockinfo.protocol = 0;
1999 ++#endif
2000 ++ apr_os_sock_make((apr_socket_t **)trans_sock, &sockinfo, ptrans);
2001 ++ apr_os_sock_get(&fd_tmp, *trans_sock);
2002 ++
2003 ++ _DBG("trans_sock=%ld fdx=%d sock_fd=%d",
2004 ++ *trans_sock, trans_sock_fd, fd_tmp);
2005 ++
2006 ++ apr_cpystrn(headers, buff, header_len + 1);
2007 ++ _DBG("header_len=%d headers=\"%s\"", header_len, headers);
2008 ++
2009 ++ if (header_len) {
2010 ++ _DBG("header_len > 0, we got a request", 0);
2011 ++ /* -- store received data into an brigade and add
2012 ++ it to the current transaction's pool -- */
2013 ++ bucket = apr_bucket_eos_create(alloc);
2014 ++ APR_BRIGADE_INSERT_HEAD(bb, bucket);
2015 ++ bucket = apr_bucket_socket_create(*trans_sock, alloc);
2016 ++ APR_BRIGADE_INSERT_HEAD(bb, bucket);
2017 ++
2018 ++ if (body_len) {
2019 ++ body = (char*)&buff[header_len + 1];
2020 ++ _DBG("body_len=%d body=\"%s\"", body_len, body);
2021 ++
2022 ++ bucket = apr_bucket_heap_create(body, body_len, NULL, alloc);
2023 ++ APR_BRIGADE_INSERT_HEAD(bb, bucket);
2024 ++ } else {
2025 ++ _DBG("There is no body",0);
2026 ++ }
2027 ++
2028 ++ bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc);
2029 ++
2030 ++ APR_BRIGADE_INSERT_HEAD(bb, bucket);
2031 ++ apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans);
2032 ++ } else {
2033 ++ _DBG("header_len == 0, we got a socket only", 0);
2034 ++ }
2035 ++ _DBG("returning 0", 0);
2036 ++ return 0;
2037 ++}
2038 ++
2039 ++
2040 ++/* Set group privileges.
2041 ++ *
2042 ++ * Note that we use the username as set in the config files, rather than
2043 ++ * the lookup of to uid --- the same uid may have multiple passwd entries,
2044 ++ * with different sets of groups for each.
2045 ++ */
2046 ++
2047 ++static int set_group_privs(uid_t uid, gid_t gid)
2048 ++{
2049 ++ if (!geteuid())
2050 ++ {
2051 ++ struct passwd *ent;
2052 ++ const char *name;
2053 ++
2054 ++ /*
2055 ++ * Set the GID before initgroups(), since on some platforms
2056 ++ * setgid() is known to zap the group list.
2057 ++ */
2058 ++ if (setgid(gid) == -1)
2059 ++ {
2060 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2061 ++ "setgid: unable to set group id to Group %u",
2062 ++ (unsigned)gid);
2063 ++ return -1;
2064 ++ }
2065 ++
2066 ++ /* if getpwuid() fails, just skip initgroups() */
2067 ++
2068 ++ if ((ent = getpwuid(uid)) != NULL)
2069 ++ {
2070 ++ name = ent->pw_name;
2071 ++
2072 ++ /* Reset `groups' attributes. */
2073 ++
2074 ++ if (initgroups(name, gid) == -1)
2075 ++ {
2076 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2077 ++ "initgroups: unable to set groups for User %s "
2078 ++ "and Group %u", name, (unsigned)gid);
2079 ++ return -1;
2080 ++ }
2081 ++ }
2082 ++ }
2083 ++ return 0;
2084 ++}
2085 ++
2086 ++static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool)
2087 ++{
2088 ++ apr_file_t *file;
2089 ++ int length;
2090 ++ apr_size_t content_len;
2091 ++ char *tasks_file, *content, *pos;
2092 ++
2093 ++ _DBG("starting to add pid to cgroup %s", senv->cgroup);
2094 ++
2095 ++ length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN;
2096 ++ tasks_file = malloc(length);
2097 ++
2098 ++ if (!tasks_file) return -1;
2099 ++
2100 ++ pos = apr_cpystrn(tasks_file, senv->cgroup, length);
2101 ++ apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN);
2102 ++
2103 ++ /* Prepare the data to be written to tasks file */
2104 ++ content = apr_itoa(pool, ap_my_pid);
2105 ++ content_len = strlen(content);
2106 ++
2107 ++ _DBG("writing pid %s to tasks file %s", content, tasks_file);
2108 ++
2109 ++ if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) {
2110 ++ if (senv->error_cgroup == 0) {
2111 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2112 ++ "cgroup: unable to open file %s",
2113 ++ tasks_file);
2114 ++ }
2115 ++
2116 ++ senv->error_cgroup = 1;
2117 ++ free(tasks_file);
2118 ++ return OK; /* don't fail if cgroup not available */
2119 ++ }
2120 ++
2121 ++ if (apr_file_write(file, content, &content_len)) {
2122 ++ if (senv->error_cgroup == 0) {
2123 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2124 ++ "cgroup: unable to write pid to file %s",
2125 ++ tasks_file);
2126 ++ }
2127 ++ senv->error_cgroup = 1;
2128 ++ }
2129 ++ else {
2130 ++ senv->error_cgroup = 0;
2131 ++ }
2132 ++
2133 ++ apr_file_close(file);
2134 ++
2135 ++ free(tasks_file);
2136 ++
2137 ++ return OK;
2138 ++}
2139 ++
2140 ++static int peruser_setup_child(int childnum, apr_pool_t *pool)
2141 ++{
2142 ++ server_env_t *senv = CHILD_INFO_TABLE[childnum].senv;
2143 ++
2144 ++ _DBG("function called");
2145 ++
2146 ++ if (senv->nice_lvl != 0) {
2147 ++ nice(senv->nice_lvl);
2148 ++ }
2149 ++
2150 ++ if(senv->chroot) {
2151 ++ _DBG("chdir to %s", senv->chroot);
2152 ++
2153 ++ if(chdir(senv->chroot)) {
2154 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2155 ++ "chdir: unable to change to directory: %s",
2156 ++ senv->chroot);
2157 ++ return -1;
2158 ++ }
2159 ++
2160 ++ if(chroot(senv->chroot)) {
2161 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2162 ++ "chroot: unable to chroot to directory: %s",
2163 ++ senv->chroot);
2164 ++ return -1;
2165 ++ }
2166 ++ }
2167 ++
2168 ++ if(senv->cgroup) {
2169 ++ peruser_setup_cgroup(childnum, senv, pool);
2170 ++ }
2171 ++
2172 ++ if (senv->uid == -1 && senv->gid == -1) {
2173 ++ return unixd_setup_child();
2174 ++ }
2175 ++ if (set_group_privs(senv->uid, senv->gid)) {
2176 ++ return -1;
2177 ++ }
2178 ++ /* Only try to switch if we're running as root */
2179 ++ if (!geteuid()
2180 ++ && (
2181 ++#ifdef _OSD_POSIX
2182 ++ os_init_job_environment(ap_server_conf, unixd_config.user_name,
2183 ++ one_process) != 0 ||
2184 ++#endif
2185 ++ setuid(senv->uid) == -1)) {
2186 ++ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
2187 ++ "setuid: unable to change to uid: %ld",
2188 ++ (long) senv->uid);
2189 ++ return -1;
2190 ++ }
2191 ++ return 0;
2192 ++}
2193 ++
2194 ++static int check_signal(int signum)
2195 ++{
2196 ++ _DBG("signum=%d", signum);
2197 ++ switch (signum) {
2198 ++ case SIGTERM:
2199 ++ case SIGINT:
2200 ++ just_die(signum);
2201 ++ return 1;
2202 ++ }
2203 ++ return 0;
2204 ++}
2205 ++
2206 ++/* Send a single HTTP header field to the client. Note that this function
2207 ++ * is used in calls to table_do(), so their interfaces are co-dependent.
2208 ++ * In other words, don't change this one without checking table_do in alloc.c.
2209 ++ * It returns true unless there was a write error of some kind.
2210 ++ */
2211 ++static int peruser_header_field(peruser_header *h,
2212 ++ const char *fieldname, const char *fieldval)
2213 ++{
2214 ++ apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL);
2215 ++ return 1;
2216 ++}
2217 ++
2218 ++static inline ap_listen_rec* listen_add(apr_pool_t* pool, apr_socket_t *sock, void* accept_func)
2219 ++{
2220 ++ ap_listen_rec *lr_walk, *lr_new;
2221 ++
2222 ++ _DBG("function entered", 0);
2223 ++ /* -- create an new listener for this child -- */
2224 ++ lr_new = apr_palloc(pool, sizeof(*lr_new));
2225 ++ lr_new->sd = sock;
2226 ++ lr_new->active = 1;
2227 ++ lr_new->accept_func = accept_func;
2228 ++ lr_new->next = NULL;
2229 ++
2230 ++ /* -- add the new listener_rec into the list -- */
2231 ++ /* FIXME: should we somehow lock this list ? */
2232 ++ lr_walk = ap_listeners;
2233 ++ if (lr_walk)
2234 ++ {
2235 ++ while (lr_walk->next) lr_walk = lr_walk->next;
2236 ++ lr_walk->next = lr_new;
2237 ++ }
2238 ++ else
2239 ++ {
2240 ++ ap_listeners = lr_walk = lr_new;
2241 ++ }
2242 ++ num_listensocks++;
2243 ++ return lr_new;
2244 ++}
2245 ++
2246 ++static inline void listen_clear()
2247 ++{
2248 ++ ap_listen_rec *lr_walk;
2249 ++
2250 ++ _DBG("function entered", 0);
2251 ++
2252 ++ /* FIXME: should we somehow lock this list ? */
2253 ++ while (ap_listeners)
2254 ++ {
2255 ++ lr_walk = ap_listeners->next;
2256 ++ apr_socket_close(ap_listeners->sd);
2257 ++ ap_listeners = lr_walk;
2258 ++ }
2259 ++ num_listensocks=0;
2260 ++}
2261 ++
2262 ++apr_status_t cleanup_child_info(void *d)
2263 ++{
2264 ++ if (child_info_image == NULL) {
2265 ++ return APR_SUCCESS;
2266 ++ }
2267 ++
2268 ++ free(child_info_image);
2269 ++ child_info_image = NULL;
2270 ++ apr_shm_destroy(child_info_shm);
2271 ++
2272 ++ return APR_SUCCESS;
2273 ++}
2274 ++
2275 ++apr_status_t cleanup_server_environments(void *d)
2276 ++{
2277 ++ if (server_env_image == NULL) {
2278 ++ return APR_SUCCESS;
2279 ++ }
2280 ++
2281 ++ free(server_env_image);
2282 ++ server_env_image = NULL;
2283 ++ apr_shm_destroy(server_env_shm);
2284 ++
2285 ++ return APR_SUCCESS;
2286 ++}
2287 ++
2288 ++static void child_main(int child_num_arg)
2289 ++{
2290 ++ apr_pool_t *ptrans;
2291 ++ apr_allocator_t *allocator;
2292 ++ conn_rec *current_conn;
2293 ++ apr_status_t status = APR_EINIT;
2294 ++ int i;
2295 ++ ap_listen_rec *lr;
2296 ++ int curr_pollfd, last_pollfd = 0;
2297 ++ apr_pollfd_t *pollset;
2298 ++ int offset;
2299 ++ ap_sb_handle_t *sbh;
2300 ++ apr_status_t rv;
2301 ++ apr_bucket_alloc_t *bucket_alloc;
2302 ++ int fd;
2303 ++ apr_socket_t *sock = NULL;
2304 ++ apr_socket_t *pod_sock = NULL;
2305 ++
2306 ++ mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
2307 ++ * child initializes
2308 ++ */
2309 ++
2310 ++ my_child_num = child_num_arg;
2311 ++ ap_my_pid = getpid();
2312 ++ requests_this_child = 0;
2313 ++
2314 ++ _DBG("sock_fd_in=%d sock_fd_out=%d",
2315 ++ CHILD_INFO_TABLE[my_child_num].senv->input,
2316 ++ CHILD_INFO_TABLE[my_child_num].senv->output);
2317 ++
2318 ++ /* Get a sub context for global allocations in this child, so that
2319 ++ * we can have cleanups occur when the child exits.
2320 ++ */
2321 ++ apr_allocator_create(&allocator);
2322 ++ apr_allocator_max_free_set(allocator, ap_max_mem_free);
2323 ++ apr_pool_create_ex(&pchild, pconf, NULL, allocator);
2324 ++ apr_allocator_owner_set(allocator, pchild);
2325 ++
2326 ++ apr_pool_create(&ptrans, pchild);
2327 ++ apr_pool_tag(ptrans, "transaction");
2328 ++
2329 ++ /* needs to be done before we switch UIDs so we have permissions */
2330 ++ ap_reopen_scoreboard(pchild, NULL, 0);
2331 ++
2332 ++ rv = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild);
2333 ++ if (rv != APR_SUCCESS) {
2334 ++ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
2335 ++ "Couldn't initialize cross-process lock in child");
2336 ++ clean_child_exit(APEXIT_CHILDFATAL);
2337 ++ }
2338 ++
2339 ++ switch(CHILD_INFO_TABLE[my_child_num].type)
2340 ++ {
2341 ++ case CHILD_TYPE_MULTIPLEXER:
2342 ++ _DBG("MULTIPLEXER %d", my_child_num);
2343 ++ break;
2344 ++
2345 ++ case CHILD_TYPE_PROCESSOR:
2346 ++ case CHILD_TYPE_WORKER:
2347 ++ _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num);
2348 ++
2349 ++ /* -- create new listener to receive from multiplexer -- */
2350 ++ apr_os_sock_put(&sock, &CHILD_INFO_TABLE[my_child_num].senv->input, pconf);
2351 ++ listen_clear();
2352 ++ listen_add(pconf, sock, receive_from_multiplexer);
2353 ++
2354 ++ break;
2355 ++
2356 ++ default:
2357 ++ _DBG("unspecified child type for %d sleeping a while ...", my_child_num);
2358 ++ sleep(5);
2359 ++ return;
2360 ++ }
2361 ++
2362 ++ apr_os_file_get(&fd, pipe_of_death_in);
2363 ++ apr_os_sock_put(&pod_sock, &fd, pconf);
2364 ++ listen_add(pconf, pod_sock, check_pipe_of_death);
2365 ++
2366 ++ if(peruser_setup_child(my_child_num, pchild) != 0)
2367 ++ clean_child_exit(APEXIT_CHILDFATAL);
2368 ++
2369 ++ ap_run_child_init(pchild, ap_server_conf);
2370 ++
2371 ++ ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
2372 ++ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
2373 ++
2374 ++ /* Set up the pollfd array */
2375 ++ listensocks = apr_pcalloc(pchild,
2376 ++ sizeof(*listensocks) * (num_listensocks));
2377 ++ for (lr = ap_listeners, i = 0; i < num_listensocks; lr = lr->next, i++) {
2378 ++ listensocks[i].accept_func = lr->accept_func;
2379 ++ listensocks[i].sd = lr->sd;
2380 ++ }
2381 ++
2382 ++ pollset = apr_palloc(pchild, sizeof(*pollset) * num_listensocks);
2383 ++ pollset[0].p = pchild;
2384 ++ for (i = 0; i < num_listensocks; i++) {
2385 ++ pollset[i].desc.s = listensocks[i].sd;
2386 ++ pollset[i].desc_type = APR_POLL_SOCKET;
2387 ++ pollset[i].reqevents = APR_POLLIN;
2388 ++ }
2389 ++
2390 ++ mpm_state = AP_MPMQ_RUNNING;
2391 ++
2392 ++ bucket_alloc = apr_bucket_alloc_create(pchild);
2393 ++
2394 ++ while (!die_now) {
2395 ++ /*
2396 ++ * (Re)initialize this child to a pre-connection state.
2397 ++ */
2398 ++
2399 ++ current_conn = NULL;
2400 ++
2401 ++ apr_pool_clear(ptrans);
2402 ++
2403 ++ if (CHILD_INFO_TABLE[my_child_num].type != CHILD_TYPE_MULTIPLEXER
2404 ++ && ap_max_requests_per_child > 0
2405 ++ && requests_this_child++ >= ap_max_requests_per_child) {
2406 ++ _DBG("max requests reached, dying now", 0);
2407 ++ clean_child_exit(0);
2408 ++ }
2409 ++
2410 ++ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
2411 ++
2412 ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY;
2413 ++ _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
2414 ++
2415 ++ /*
2416 ++ * Wait for an acceptable connection to arrive.
2417 ++ */
2418 ++
2419 ++ /* Lock around "accept", if necessary */
2420 ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
2421 ++ SAFE_ACCEPT(accept_mutex_on());
2422 ++ }
2423 ++
2424 ++ if (num_listensocks == 1) {
2425 ++ offset = 0;
2426 ++ }
2427 ++ else {
2428 ++ /* multiple listening sockets - need to poll */
2429 ++ for (;;) {
2430 ++ apr_status_t ret;
2431 ++ apr_int32_t n;
2432 ++
2433 ++ ret = apr_poll(pollset, num_listensocks, &n, -1);
2434 ++ if (ret != APR_SUCCESS) {
2435 ++ if (APR_STATUS_IS_EINTR(ret)) {
2436 ++ continue;
2437 ++ }
2438 ++ /* Single Unix documents select as returning errnos
2439 ++ * EBADF, EINTR, and EINVAL... and in none of those
2440 ++ * cases does it make sense to continue. In fact
2441 ++ * on Linux 2.0.x we seem to end up with EFAULT
2442 ++ * occasionally, and we'd loop forever due to it.
2443 ++ */
2444 ++ ap_log_error(APLOG_MARK, APLOG_ERR, ret, ap_server_conf,
2445 ++ "apr_poll: (listen)");
2446 ++ clean_child_exit(1);
2447 ++ }
2448 ++ /* find a listener */
2449 ++ curr_pollfd = last_pollfd;
2450 ++ do {
2451 ++ curr_pollfd++;
2452 ++ if (curr_pollfd >= num_listensocks) {
2453 ++ curr_pollfd = 0;
2454 ++ }
2455 ++ /* XXX: Should we check for POLLERR? */
2456 ++ if (pollset[curr_pollfd].rtnevents & APR_POLLIN) {
2457 ++ last_pollfd = curr_pollfd;
2458 ++ offset = curr_pollfd;
2459 ++ goto got_fd;
2460 ++ }
2461 ++ } while (curr_pollfd != last_pollfd);
2462 ++
2463 ++ continue;
2464 ++ }
2465 ++ }
2466 ++ got_fd:
2467 ++ _DBG("input available ... resetting socket.",0);
2468 ++ sock = NULL; /* important! */
2469 ++
2470 ++ /* if we accept() something we don't want to die, so we have to
2471 ++ * defer the exit
2472 ++ */
2473 ++ status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans);
2474 ++
2475 ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
2476 ++ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
2477 ++ }
2478 ++
2479 ++ if (status == APR_EGENERAL) {
2480 ++ /* resource shortage or should-not-occur occured */
2481 ++ clean_child_exit(1);
2482 ++ }
2483 ++ else if (status != APR_SUCCESS || die_now || sock == NULL) {
2484 ++ continue;
2485 ++ }
2486 ++
2487 ++ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) {
2488 ++ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE;
2489 ++ _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
2490 ++ }
2491 ++
2492 ++ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR ||
2493 ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER ||
2494 ++ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
2495 ++ {
2496 ++ _DBG("CHECKING IF WE SHOULD CLONE A CHILD...");
2497 ++
2498 ++ _DBG("total_processors = %d, max_processors = %d",
2499 ++ total_processors(my_child_num),
2500 ++ CHILD_INFO_TABLE[my_child_num].senv->max_processors);
2501 ++
2502 ++ _DBG("idle_processors = %d, min_free_processors = %d",
2503 ++ idle_processors(my_child_num),
2504 ++ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors);
2505 ++
2506 ++ if(total_processors(my_child_num) <
2507 ++ CHILD_INFO_TABLE[my_child_num].senv->max_processors &&
2508 ++ (idle_processors(my_child_num) <=
2509 ++ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors ||
2510 ++ total_processors(my_child_num) <
2511 ++ CHILD_INFO_TABLE[my_child_num].senv->min_processors
2512 ++ ))
2513 ++ {
2514 ++ _DBG("CLONING CHILD");
2515 ++ child_clone();
2516 ++ }
2517 ++ }
2518 ++
2519 ++ if (!setjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer))
2520 ++ {
2521 ++ _DBG("marked jmpbuffer",0);
2522 ++ _TRACE_CALL("process_socket()",0);
2523 ++ process_socket(ptrans, sock, my_child_num, bucket_alloc, pchild);
2524 ++ _TRACE_RET("process_socket()",0);
2525 ++ }
2526 ++ else
2527 ++ {
2528 ++ _DBG("landed from longjmp",0);
2529 ++ CHILD_INFO_TABLE[my_child_num].sock_fd = AP_PERUSER_THISCHILD;
2530 ++ }
2531 ++
2532 ++ /* Check the pod and the generation number after processing a
2533 ++ * connection so that we'll go away if a graceful restart occurred
2534 ++ * while we were processing the connection or we are the lucky
2535 ++ * idle server process that gets to die.
2536 ++ */
2537 ++ if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */
2538 ++ _DBG("ap_mpm_pod_check(pod) = APR_SUCCESS; dying now", 0);
2539 ++ die_now = 1;
2540 ++ }
2541 ++ else if (ap_my_generation !=
2542 ++ ap_scoreboard_image->global->running_generation) { /* restart? */
2543 ++ /* yeah, this could be non-graceful restart, in which case the
2544 ++ * parent will kill us soon enough, but why bother checking?
2545 ++ */
2546 ++ _DBG("ap_my_generation != ap_scoreboard_image->global->running_generation; dying now", 0);
2547 ++ die_now = 1;
2548 ++ }
2549 ++
2550 ++ if(CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_RESTART)
2551 ++ {
2552 ++ _DBG("restarting", 0);
2553 ++ die_now = 1;
2554 ++ }
2555 ++ }
2556 ++
2557 ++ _DBG("clean_child_exit(0)");
2558 ++ clean_child_exit(0);
2559 ++}
2560 ++
2561 ++static server_env_t* find_senv_by_name(const char *name) {
2562 ++ int i;
2563 ++
2564 ++ if (name == NULL) return NULL;
2565 ++
2566 ++ _DBG("name=%s", name);
2567 ++
2568 ++ for(i = 0; i < NUM_SENV; i++)
2569 ++ {
2570 ++ if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) {
2571 ++ return &SENV[i];
2572 ++ }
2573 ++ }
2574 ++
2575 ++ return NULL;
2576 ++}
2577 ++
2578 ++static server_env_t* find_matching_senv(server_env_t* senv) {
2579 ++ int i;
2580 ++
2581 ++ _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot);
2582 ++
2583 ++ for(i = 0; i < NUM_SENV; i++)
2584 ++ {
2585 ++ if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) ||
2586 ++ (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid &&
2587 ++ (
2588 ++ (SENV[i].chroot == NULL && senv->chroot == NULL) ||
2589 ++ ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot)))
2590 ++ )
2591 ++ ) {
2592 ++ return &SENV[i];
2593 ++ }
2594 ++ }
2595 ++
2596 ++ return NULL;
2597 ++}
2598 ++
2599 ++static server_env_t* senv_add(server_env_t *senv)
2600 ++{
2601 ++ int socks[2];
2602 ++ server_env_t *old_senv;
2603 ++
2604 ++ _DBG("Searching for matching senv...");
2605 ++
2606 ++ old_senv = find_matching_senv(senv);
2607 ++
2608 ++ if (old_senv) {
2609 ++ _DBG("Found existing senv");
2610 ++ senv = old_senv;
2611 ++ return old_senv;
2612 ++ }
2613 ++
2614 ++ if(NUM_SENV >= server_limit)
2615 ++ {
2616 ++ _DBG("server_limit reached!");
2617 ++ return NULL;
2618 ++ }
2619 ++
2620 ++ _DBG("Creating new senv");
2621 ++
2622 ++ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t));
2623 ++
2624 ++ SENV[NUM_SENV].availability = 100;
2625 ++
2626 ++ socketpair(PF_UNIX, SOCK_STREAM, 0, socks);
2627 ++ SENV[NUM_SENV].input = socks[0];
2628 ++ SENV[NUM_SENV].output = socks[1];
2629 ++
2630 ++ senv = &SENV[NUM_SENV];
2631 ++ return &SENV[server_env_image->control->num++];
2632 ++}
2633 ++
2634 ++
2635 ++static const char* child_clone()
2636 ++{
2637 ++ int i;
2638 ++ child_info_t *this;
2639 ++ child_info_t *new;
2640 ++
2641 ++ for(i = 0; i < NUM_CHILDS; i++)
2642 ++ {
2643 ++ if(CHILD_INFO_TABLE[i].pid == 0 &&
2644 ++ CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) break;
2645 ++ }
2646 ++
2647 ++ if(i == NUM_CHILDS && NUM_CHILDS >= server_limit)
2648 ++ {
2649 ++ _DBG("Trying to use more child ID's than ServerLimit. "
2650 ++ "Increase ServerLimit in your config file.");
2651 ++ return NULL;
2652 ++ }
2653 ++
2654 ++ _DBG("cloning child #%d from #%d", i, my_child_num);
2655 ++
2656 ++ this = &CHILD_INFO_TABLE[my_child_num];
2657 ++ new = &CHILD_INFO_TABLE[i];
2658 ++
2659 ++ new->senv = this->senv;
2660 ++
2661 ++ if (this->type == CHILD_TYPE_MULTIPLEXER) {
2662 ++ new->type = CHILD_TYPE_MULTIPLEXER;
2663 ++ }
2664 ++ else {
2665 ++ new->type = CHILD_TYPE_WORKER;
2666 ++ }
2667 ++
2668 ++ new->sock_fd = this->sock_fd;
2669 ++ new->status = CHILD_STATUS_STARTING;
2670 ++
2671 ++ if(i == NUM_CHILDS) child_info_image->control->num++;
2672 ++ return NULL;
2673 ++}
2674 ++
2675 ++static const char* child_add(int type, int status,
2676 ++ apr_pool_t *pool, server_env_t *senv)
2677 ++{
2678 ++ _DBG("adding child #%d", NUM_CHILDS);
2679 ++
2680 ++ if(NUM_CHILDS >= server_limit)
2681 ++ {
2682 ++ return "Trying to use more child ID's than ServerLimit. "
2683 ++ "Increase ServerLimit in your config file.";
2684 ++ }
2685 ++
2686 ++ if (senv->chroot && !ap_is_directory(pool, senv->chroot))
2687 ++ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot);
2688 ++
2689 ++ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv);
2690 ++
2691 ++ if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL)
2692 ++ {
2693 ++ return "Trying to use more server environments than ServerLimit. "
2694 ++ "Increase ServerLimit in your config file.";
2695 ++ }
2696 ++
2697 ++ if(type != CHILD_TYPE_WORKER)
2698 ++ CHILD_INFO_TABLE[NUM_CHILDS].senv->processor_id = NUM_CHILDS;
2699 ++
2700 ++ CHILD_INFO_TABLE[NUM_CHILDS].type = type;
2701 ++ CHILD_INFO_TABLE[NUM_CHILDS].sock_fd = AP_PERUSER_THISCHILD;
2702 ++ CHILD_INFO_TABLE[NUM_CHILDS].status = status;
2703 ++
2704 ++ _DBG("[%d] uid=%d gid=%d type=%d chroot=%s",
2705 ++ NUM_CHILDS, senv->uid, senv->gid, type,
2706 ++ senv->chroot);
2707 ++
2708 ++ if (senv->uid == 0 || senv->gid == 0)
2709 ++ {
2710 ++ _DBG("Assigning root user/group to a child.", 0);
2711 ++ }
2712 ++
2713 ++ child_info_image->control->num++;
2714 ++
2715 ++ return NULL;
2716 ++}
2717 ++
2718 ++static int make_child(server_rec *s, int slot)
2719 ++{
2720 ++ int pid;
2721 ++
2722 ++ _DBG("function entered", 0);
2723 ++ dump_server_env_image();
2724 ++
2725 ++ switch (CHILD_INFO_TABLE[slot].type)
2726 ++ {
2727 ++ case CHILD_TYPE_MULTIPLEXER: break;
2728 ++ case CHILD_TYPE_PROCESSOR: break;
2729 ++ case CHILD_TYPE_WORKER: break;
2730 ++
2731 ++ default:
2732 ++ _DBG("no valid client in slot %d", slot);
2733 ++ /* sleep(1); */
2734 ++ return 0;
2735 ++ }
2736 ++
2737 ++ if (slot + 1 > ap_max_daemons_limit) {
2738 ++ ap_max_daemons_limit = slot + 1;
2739 ++ }
2740 ++
2741 ++ if (one_process) {
2742 ++ apr_signal(SIGHUP, just_die);
2743 ++ /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */
2744 ++ apr_signal(SIGINT, just_die);
2745 ++#ifdef SIGQUIT
2746 ++ apr_signal(SIGQUIT, SIG_DFL);
2747 ++#endif
2748 ++ apr_signal(SIGTERM, just_die);
2749 ++ child_main(slot);
2750 ++ }
2751 ++
2752 ++ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
2753 ++ (request_rec *) NULL);
2754 ++
2755 ++ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY;
2756 ++
2757 ++
2758 ++#ifdef _OSD_POSIX
2759 ++ /* BS2000 requires a "special" version of fork() before a setuid() call */
2760 ++ if ((pid = os_fork(unixd_config.user_name)) == -1) {
2761 ++#elif defined(TPF)
2762 ++ if ((pid = os_fork(s, slot)) == -1) {
2763 ++#else
2764 ++ if ((pid = fork()) == -1) {
2765 ++#endif
2766 ++ ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process");
2767 ++
2768 ++ /* fork didn't succeed. Fix the scoreboard or else
2769 ++ * it will say SERVER_STARTING forever and ever
2770 ++ */
2771 ++ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD,
2772 ++ (request_rec *) NULL);
2773 ++
2774 ++ /* In case system resources are maxxed out, we don't want
2775 ++ Apache running away with the CPU trying to fork over and
2776 ++ over and over again. */
2777 ++ sleep(10);
2778 ++
2779 ++ return -1;
2780 ++ }
2781 ++
2782 ++ if (!pid) {
2783 ++#ifdef HAVE_BINDPROCESSOR
2784 ++ /* by default AIX binds to a single processor
2785 ++ * this bit unbinds children which will then bind to another cpu
2786 ++ */
2787 ++ int status = bindprocessor(BINDPROCESS, (int)getpid(),
2788 ++ PROCESSOR_CLASS_ANY);
2789 ++ if (status != OK) {
2790 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
2791 ++ ap_server_conf, "processor unbind failed %d", status);
2792 ++ }
2793 ++#endif
2794 ++ RAISE_SIGSTOP(MAKE_CHILD);
2795 ++ AP_MONCONTROL(1);
2796 ++ /* Disable the parent's signal handlers and set up proper handling in
2797 ++ * the child.
2798 ++ */
2799 ++ apr_signal(SIGHUP, just_die);
2800 ++ apr_signal(SIGTERM, just_die);
2801 ++ /* The child process doesn't do anything for AP_SIG_GRACEFUL.
2802 ++ * Instead, the pod is used for signalling graceful restart.
2803 ++ */
2804 ++ /* apr_signal(AP_SIG_GRACEFUL, restart); */
2805 ++ child_main(slot);
2806 ++ clean_child_exit(0);
2807 ++ }
2808 ++
2809 ++ ap_scoreboard_image->parent[slot].pid = pid;
2810 ++ CHILD_INFO_TABLE[slot].pid = pid;
2811 ++
2812 ++ ap_child_table[slot].pid = pid;
2813 ++ ap_child_table[slot].status = SERVER_ALIVE;
2814 ++
2815 ++ return 0;
2816 ++}
2817 ++
2818 ++
2819 ++/*
2820 ++ * idle_spawn_rate is the number of children that will be spawned on the
2821 ++ * next maintenance cycle if there aren't enough idle servers. It is
2822 ++ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
2823 ++ * without the need to spawn.
2824 ++ */
2825 ++static int idle_spawn_rate = 1;
2826 ++#ifndef MAX_SPAWN_RATE
2827 ++#define MAX_SPAWN_RATE (32)
2828 ++#endif
2829 ++static int total_processes(int child_num)
2830 ++{
2831 ++ int i, total;
2832 ++ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
2833 ++ {
2834 ++ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
2835 ++ (!(CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR &&
2836 ++ CHILD_INFO_TABLE[i].status == CHILD_STATUS_STANDBY)))
2837 ++ {
2838 ++ total++;
2839 ++ }
2840 ++ }
2841 ++ return total;
2842 ++}
2843 ++
2844 ++static void perform_idle_server_maintenance(apr_pool_t *p)
2845 ++{
2846 ++ int i;
2847 ++ apr_time_t now;
2848 ++
2849 ++ /* _DBG("function entered", 0); */
2850 ++
2851 ++ now = apr_time_now();
2852 ++
2853 ++ for (i = 0; i < NUM_CHILDS; ++i)
2854 ++ {
2855 ++ if(CHILD_INFO_TABLE[i].pid == 0)
2856 ++ {
2857 ++ if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)
2858 ++ make_child(ap_server_conf, i);
2859 ++ }
2860 ++ else if(
2861 ++ (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
2862 ++ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
2863 ++ ap_scoreboard_image->parent[i].pid > 1) &&
2864 ++ (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) &&
2865 ++ total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors &&
2866 ++ (
2867 ++ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
2868 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
2869 ++ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
2870 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) ||
2871 ++ (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY &&
2872 ++ idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors))
2873 ++ )
2874 ++ || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER &&
2875 ++ (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
2876 ++ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) &&
2877 ++ total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors
2878 ++ )
2879 ++ )
2880 ++ {
2881 ++ CHILD_INFO_TABLE[i].pid = 0;
2882 ++ CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY;
2883 ++
2884 ++ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER)
2885 ++ {
2886 ++ /* completely free up this slot */
2887 ++
2888 ++ CHILD_INFO_TABLE[i].senv = (server_env_t*)NULL;
2889 ++ CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN;
2890 ++ CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */
2891 ++ }
2892 ++ if(kill(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1)
2893 ++ {
2894 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
2895 ++ ap_server_conf, "kill SIGTERM");
2896 ++ }
2897 ++
2898 ++
2899 ++ ap_update_child_status_from_indexes(i, 0, SERVER_DEAD, NULL);
2900 ++ }
2901 ++ }
2902 ++
2903 ++ for(i=0;i<grace_children;i++) {
2904 ++ if (child_grace_info_table[i].pid > 0 && expire_timeout > 0 &&
2905 ++ apr_time_sec(now - child_grace_info_table[i].last_used) > expire_timeout) {
2906 ++
2907 ++ _DBG("Killing a child from last graceful (pid=%d,childno=%d,last_used=%d)",
2908 ++ child_grace_info_table[i].pid, child_grace_info_table[i].id,
2909 ++ child_grace_info_table[i].last_used);
2910 ++
2911 ++ if(kill(child_grace_info_table[i].pid, SIGTERM) == -1)
2912 ++ {
2913 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
2914 ++ ap_server_conf, "kill SIGTERM");
2915 ++ }
2916 ++
2917 ++ /* We don't need to do remove_grace_child() here,
2918 ++ * because it will be automatically done once
2919 ++ * the child dies by ap_mpm_run() */
2920 ++ }
2921 ++ }
2922 ++}
2923 ++
2924 ++int remove_grace_child(int slot) {
2925 ++ if (slot < grace_children) {
2926 ++ child_grace_info_table[slot].id = 0;
2927 ++ child_grace_info_table[slot].pid = 0;
2928 ++ child_grace_info_table[slot].status = CHILD_STATUS_STANDBY;
2929 ++ child_grace_info_table[slot].type = CHILD_TYPE_UNKNOWN;
2930 ++ child_grace_info_table[slot].last_used = 0;
2931 ++ grace_children_alive--;
2932 ++
2933 ++ if (grace_children_alive <= 0) { /* All children have returned from graceful */
2934 ++ _DBG("Every child has returned from graceful restart - freeing child_grace_info_table");
2935 ++ grace_children_alive = 0;
2936 ++ is_graceful = 0;
2937 ++ grace_children = 0;
2938 ++ free(child_grace_info_table);
2939 ++ }
2940 ++ return 0;
2941 ++ }
2942 ++ return 1;
2943 ++}
2944 ++
2945 ++/*****************************************************************
2946 ++ * Executive routines.
2947 ++ */
2948 ++
2949 ++int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
2950 ++{
2951 ++ int i;
2952 ++/* int fd; */
2953 ++ apr_status_t rv;
2954 ++ apr_size_t one = 1;
2955 ++/* apr_socket_t *sock = NULL; */
2956 ++
2957 ++ ap_log_pid(pconf, ap_pid_fname);
2958 ++
2959 ++ first_server_limit = server_limit;
2960 ++ if (changed_limit_at_restart) {
2961 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
2962 ++ "WARNING: Attempt to change ServerLimit "
2963 ++ "ignored during restart");
2964 ++ changed_limit_at_restart = 0;
2965 ++ }
2966 ++
2967 ++ ap_server_conf = s;
2968 ++
2969 ++ /* Initialize cross-process accept lock */
2970 ++ ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT,
2971 ++ ap_server_root_relative(_pconf, ap_lock_fname),
2972 ++ ap_my_pid);
2973 ++
2974 ++ rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,
2975 ++ ap_accept_lock_mech, _pconf);
2976 ++ if (rv != APR_SUCCESS) {
2977 ++ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
2978 ++ "Couldn't create accept lock");
2979 ++ mpm_state = AP_MPMQ_STOPPING;
2980 ++ return 1;
2981 ++ }
2982 ++
2983 ++#if APR_USE_SYSVSEM_SERIALIZE
2984 ++ if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
2985 ++ ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
2986 ++#else
2987 ++ if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
2988 ++#endif
2989 ++ rv = unixd_set_proc_mutex_perms(accept_mutex);
2990 ++ if (rv != APR_SUCCESS) {
2991 ++ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
2992 ++ "Couldn't set permissions on cross-process lock; "
2993 ++ "check User and Group directives");
2994 ++ mpm_state = AP_MPMQ_STOPPING;
2995 ++ return 1;
2996 ++ }
2997 ++ }
2998 ++
2999 ++ if (!is_graceful) {
3000 ++ if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
3001 ++ mpm_state = AP_MPMQ_STOPPING;
3002 ++ return 1;
3003 ++ }
3004 ++ /* fix the generation number in the global score; we just got a new,
3005 ++ * cleared scoreboard
3006 ++ */
3007 ++ ap_scoreboard_image->global->running_generation = ap_my_generation;
3008 ++ }
3009 ++
3010 ++ /* Initialize the child table */
3011 ++ if (!is_graceful)
3012 ++ {
3013 ++ for (i = 0; i < server_limit; i++)
3014 ++ {
3015 ++ ap_child_table[i].pid = 0;
3016 ++ }
3017 ++ }
3018 ++
3019 ++ /* We need to put the new listeners at the end of the ap_listeners
3020 ++ * list. If we don't, then the pool will be cleared before the
3021 ++ * open_logs phase is called for the second time, and ap_listeners
3022 ++ * will have only invalid data. If that happens, then the sockets
3023 ++ * that we opened using make_sock() will be lost, and the server
3024 ++ * won't start.
3025 ++ */
3026 ++
3027 ++/*
3028 ++ apr_os_file_get(&fd, pipe_of_death_in);
3029 ++ apr_os_sock_put(&sock, &fd, pconf);
3030 ++
3031 ++ listen_add(pconf, sock, check_pipe_of_death);
3032 ++*/
3033 ++ set_signals();
3034 ++
3035 ++ if (one_process) {
3036 ++ AP_MONCONTROL(1);
3037 ++ }
3038 ++
3039 ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
3040 ++ "%s configured -- resuming normal operations",
3041 ++ ap_get_server_version());
3042 ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
3043 ++ "Server built: %s", ap_get_server_built());
3044 ++#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
3045 ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
3046 ++ "AcceptMutex: %s (default: %s)",
3047 ++ apr_proc_mutex_name(accept_mutex),
3048 ++ apr_proc_mutex_defname());
3049 ++#endif
3050 ++ restart_pending = shutdown_pending = 0;
3051 ++
3052 ++ mpm_state = AP_MPMQ_RUNNING;
3053 ++
3054 ++ _DBG("sizeof(child_info_t) = %d", sizeof(child_info_t));
3055 ++
3056 ++ while (!restart_pending && !shutdown_pending) {
3057 ++ int child_slot;
3058 ++ apr_exit_why_e exitwhy;
3059 ++ int status, processed_status;
3060 ++ /* this is a memory leak, but I'll fix it later. */
3061 ++ apr_proc_t pid;
3062 ++
3063 ++ ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
3064 ++
3065 ++ /* XXX: if it takes longer than 1 second for all our children
3066 ++ * to start up and get into IDLE state then we may spawn an
3067 ++ * extra child
3068 ++ */
3069 ++ if (pid.pid != -1) {
3070 ++ processed_status = ap_process_child_status(&pid, exitwhy, status);
3071 ++ if (processed_status == APEXIT_CHILDFATAL) {
3072 ++ mpm_state = AP_MPMQ_STOPPING;
3073 ++ return 1;
3074 ++ }
3075 ++
3076 ++ if (grace_children > 0) {
3077 ++ for(i=0;i<grace_children;i++) {
3078 ++ if (child_grace_info_table[i].pid == pid.pid) {
3079 ++ break;
3080 ++ }
3081 ++ }
3082 ++ if (i != grace_children) {
3083 ++ _DBG("Child returned from graceful (%d)", i);
3084 ++ remove_grace_child(i);
3085 ++ continue;
3086 ++ }
3087 ++ }
3088 ++
3089 ++ /* non-fatal death... note that it's gone in the scoreboard. */
3090 ++ child_slot = find_child_by_pid(&pid);
3091 ++ _DBG("child #%d has died ...", child_slot);
3092 ++
3093 ++ for (i = 0; i < ap_max_daemons_limit; ++i)
3094 ++ {
3095 ++ if (ap_child_table[i].pid == pid.pid)
3096 ++ {
3097 ++ child_slot = i;
3098 ++ break;
3099 ++ }
3100 ++ }
3101 ++
3102 ++ if (child_slot >= 0) {
3103 ++ ap_child_table[child_slot].pid = 0;
3104 ++ _TRACE_CALL("ap_update_child_status_from_indexes", 0);
3105 ++ (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,
3106 ++ (request_rec *) NULL);
3107 ++ _TRACE_RET("ap_update_child_status_from_indexes", 0);
3108 ++
3109 ++ if (processed_status == APEXIT_CHILDSICK) {
3110 ++ /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)
3111 ++ * cut the fork rate to the minimum
3112 ++ */
3113 ++ _DBG("processed_status = APEXIT_CHILDSICK", 0);
3114 ++ idle_spawn_rate = 1;
3115 ++ }
3116 ++ else if (CHILD_INFO_TABLE[child_slot].status == CHILD_STATUS_STANDBY) {
3117 ++ _DBG("leaving child in standby state", 0);
3118 ++ }
3119 ++ else if (child_slot < ap_daemons_limit &&
3120 ++ CHILD_INFO_TABLE[child_slot].type !=
3121 ++ CHILD_TYPE_UNKNOWN) {
3122 ++ /* we're still doing a 1-for-1 replacement of dead
3123 ++ * children with new children
3124 ++ */
3125 ++ _DBG("replacing by new child ...", 0);
3126 ++ make_child(ap_server_conf, child_slot);
3127 ++ }
3128 ++#if APR_HAS_OTHER_CHILD
3129 ++ }
3130 ++ else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) {
3131 ++ _DBG("Already handled", 0);
3132 ++ /* handled */
3133 ++#endif
3134 ++ }
3135 ++ else if (is_graceful) {
3136 ++ /* Great, we've probably just lost a slot in the
3137 ++ * scoreboard. Somehow we don't know about this
3138 ++ * child.
3139 ++ */
3140 ++ _DBG("long lost child came home, whatever that means", 0);
3141 ++
3142 ++ ap_log_error(APLOG_MARK, APLOG_WARNING,
3143 ++ 0, ap_server_conf,
3144 ++ "long lost child came home! (pid %ld)", (long)pid.pid);
3145 ++ }
3146 ++ /* Don't perform idle maintenance when a child dies,
3147 ++ * only do it when there's a timeout. Remember only a
3148 ++ * finite number of children can die, and it's pretty
3149 ++ * pathological for a lot to die suddenly.
3150 ++ */
3151 ++ continue;
3152 ++ }
3153 ++
3154 ++ perform_idle_server_maintenance(pconf);
3155 ++
3156 ++#ifdef TPF
3157 ++ shutdown_pending = os_check_server(tpf_server_name);
3158 ++ ap_check_signals();
3159 ++ sleep(1);
3160 ++#endif /*TPF */
3161 ++ }
3162 ++
3163 ++ mpm_state = AP_MPMQ_STOPPING;
3164 ++
3165 ++ if (shutdown_pending) {
3166 ++ /* Time to gracefully shut down:
3167 ++ * Kill child processes, tell them to call child_exit, etc...
3168 ++ */
3169 ++ if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
3170 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
3171 ++ }
3172 ++ ap_reclaim_child_processes(1); /* Start with SIGTERM */
3173 ++
3174 ++ /* cleanup pid file on normal shutdown */
3175 ++ {
3176 ++ const char *pidfile = NULL;
3177 ++ pidfile = ap_server_root_relative (pconf, ap_pid_fname);
3178 ++ if ( pidfile != NULL && unlink(pidfile) == 0)
3179 ++ ap_log_error(APLOG_MARK, APLOG_INFO,
3180 ++ 0, ap_server_conf,
3181 ++ "removed PID file %s (pid=%ld)",
3182 ++ pidfile, (long)getpid());
3183 ++ }
3184 ++
3185 ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
3186 ++ "caught SIGTERM, shutting down");
3187 ++ return 1;
3188 ++ }
3189 ++
3190 ++ /* we've been told to restart */
3191 ++ apr_signal(SIGHUP, SIG_IGN);
3192 ++ if (one_process) {
3193 ++ /* not worth thinking about */
3194 ++ return 1;
3195 ++ }
3196 ++
3197 ++ /* advance to the next generation */
3198 ++ /* XXX: we really need to make sure this new generation number isn't in
3199 ++ * use by any of the children.
3200 ++ */
3201 ++ ++ap_my_generation;
3202 ++ ap_scoreboard_image->global->running_generation = ap_my_generation;
3203 ++
3204 ++ /* cleanup sockets */
3205 ++ for (i = 0; i < NUM_SENV; i++) {
3206 ++ close(SENV[i].input);
3207 ++ close(SENV[i].output);
3208 ++ }
3209 ++
3210 ++ if (is_graceful) {
3211 ++ char char_of_death = AP_PERUSER_CHAR_OF_DEATH;
3212 ++
3213 ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
3214 ++ "Graceful restart requested, doing restart");
3215 ++
3216 ++#if 0
3217 ++ /* kill off the idle ones */
3218 ++ ap_mpm_pod_killpg(pod, ap_max_daemons_limit);
3219 ++
3220 ++ /* This is mostly for debugging... so that we know what is still
3221 ++ * gracefully dealing with existing request. This will break
3222 ++ * in a very nasty way if we ever have the scoreboard totally
3223 ++ * file-based (no shared memory)
3224 ++ */
3225 ++ for (i = 0; i < ap_daemons_limit; ++i) {
3226 ++ if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
3227 ++ ap_scoreboard_image->servers[i][0].status = SERVER_GRACEFUL;
3228 ++ }
3229 ++ }
3230 ++#endif
3231 ++
3232 ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
3233 ++ ap_server_conf, AP_SIG_GRACEFUL_STRING " received. "
3234 ++ "Doing graceful restart");
3235 ++
3236 ++ /* This is mostly for debugging... so that we know what is still
3237 ++ * gracefully dealing with existing request.
3238 ++ */
3239 ++
3240 ++ int alivechildren = 0;
3241 ++ child_grace_info_t* old_grace_info;
3242 ++
3243 ++ for (i = 0; i < NUM_CHILDS; ++i)
3244 ++ {
3245 ++ ((ap_child_table[i].pid) && (ap_child_table[i].status = SERVER_DYING));
3246 ++
3247 ++ if (CHILD_INFO_TABLE[i].pid) {
3248 ++ alivechildren++;
3249 ++ }
3250 ++ }
3251 ++
3252 ++ _DBG("Initializing child_grace_info_table", 0);
3253 ++
3254 ++ if (alivechildren > 0) {
3255 ++ if (grace_children > 0) {
3256 ++ old_grace_info = child_grace_info_table;
3257 ++ _DBG("%d children still living from last graceful "
3258 ++ "- adding to new child_grace_info_table",
3259 ++ grace_children);
3260 ++ }
3261 ++
3262 ++ child_grace_info_table = (child_grace_info_t*)calloc(alivechildren+grace_children,
3263 ++ sizeof(child_grace_info_t));
3264 ++
3265 ++ if (grace_children > 0) {
3266 ++ for(i=0;i<grace_children;i++) {
3267 ++ child_grace_info_table[i] = old_grace_info[i];
3268 ++ }
3269 ++ grace_children = i;
3270 ++ free(old_grace_info);
3271 ++ }
3272 ++ else grace_children = 0;
3273 ++
3274 ++ }
3275 ++
3276 ++ /* give the children the signal to die */
3277 ++ for (i = 0; i < NUM_CHILDS;)
3278 ++ {
3279 ++ if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS)
3280 ++ {
3281 ++ if (APR_STATUS_IS_EINTR(rv)) continue;
3282 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
3283 ++ "write pipe_of_death");
3284 ++ }
3285 ++ if (CHILD_INFO_TABLE[i].pid) {
3286 ++ child_grace_info_table[grace_children].id = CHILD_INFO_TABLE[i].id;
3287 ++ child_grace_info_table[grace_children].pid = CHILD_INFO_TABLE[i].pid;
3288 ++ child_grace_info_table[grace_children].status = CHILD_INFO_TABLE[i].status;
3289 ++ child_grace_info_table[grace_children].type = CHILD_INFO_TABLE[i].type;
3290 ++ child_grace_info_table[grace_children].last_used= ap_scoreboard_image->servers[i][0].last_used;
3291 ++ grace_children++;
3292 ++ grace_children_alive++;
3293 ++ }
3294 ++ i++;
3295 ++ }
3296 ++ _DBG("Total children of %d leaving behind for graceful restart (%d living)",
3297 ++ grace_children, grace_children_alive);
3298 ++ }
3299 ++ else {
3300 ++ /* Kill 'em off */
3301 ++ if (unixd_killpg(getpgrp(), SIGHUP) < 0) {
3302 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP");
3303 ++ }
3304 ++ ap_reclaim_child_processes(0); /* Not when just starting up */
3305 ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
3306 ++ "SIGHUP received. Attempting to restart");
3307 ++ }
3308 ++
3309 ++ return 0;
3310 ++}
3311 ++
3312 ++/* == allocate an private server config structure == */
3313 ++static void *peruser_create_config(apr_pool_t *p, server_rec *s)
3314 ++{
3315 ++ peruser_server_conf *c = (peruser_server_conf *)
3316 ++ apr_pcalloc(p, sizeof(peruser_server_conf));
3317 ++
3318 ++ c->senv = NULL;
3319 ++ c->missing_senv_reported = 0;
3320 ++
3321 ++ return c;
3322 ++}
3323 ++
3324 ++/* This really should be a post_config hook, but the error log is already
3325 ++ * redirected by that point, so we need to do this in the open_logs phase.
3326 ++ */
3327 ++static int peruser_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
3328 ++{
3329 ++ apr_status_t rv;
3330 ++
3331 ++ pconf = p;
3332 ++ ap_server_conf = s;
3333 ++
3334 ++ if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
3335 ++ ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
3336 ++ NULL, "no listening sockets available, shutting down");
3337 ++ return DONE;
3338 ++ }
3339 ++
3340 ++ ap_log_pid(pconf, ap_pid_fname);
3341 ++
3342 ++ if ((rv = ap_mpm_pod_open(pconf, &pod))) {
3343 ++ ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL,
3344 ++ "Could not open pipe-of-death.");
3345 ++ return DONE;
3346 ++ }
3347 ++
3348 ++ if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out,
3349 ++ pconf)) != APR_SUCCESS) {
3350 ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
3351 ++ (const server_rec*) ap_server_conf,
3352 ++ "apr_file_pipe_create (pipe_of_death)");
3353 ++ exit(1);
3354 ++ }
3355 ++ if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
3356 ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
3357 ++ (const server_rec*) ap_server_conf,
3358 ++ "apr_file_pipe_timeout_set (pipe_of_death)");
3359 ++ exit(1);
3360 ++ }
3361 ++
3362 ++ return OK;
3363 ++}
3364 ++
3365 ++static int restart_num = 0;
3366 ++static int peruser_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
3367 ++{
3368 ++ int no_detach, debug, foreground, i;
3369 ++ int tmp_server_limit = DEFAULT_SERVER_LIMIT;
3370 ++ ap_directive_t *pdir;
3371 ++ apr_status_t rv;
3372 ++ apr_pool_t *global_pool;
3373 ++ void *shmem;
3374 ++
3375 ++ mpm_state = AP_MPMQ_STARTING;
3376 ++
3377 ++ debug = ap_exists_config_define("DEBUG");
3378 ++
3379 ++ if (debug) {
3380 ++ foreground = one_process = 1;
3381 ++ no_detach = 0;
3382 ++ }
3383 ++ else
3384 ++ {
3385 ++ no_detach = ap_exists_config_define("NO_DETACH");
3386 ++ one_process = ap_exists_config_define("ONE_PROCESS");
3387 ++ foreground = ap_exists_config_define("FOREGROUND");
3388 ++ }
3389 ++
3390 ++ /* sigh, want this only the second time around */
3391 ++ if (restart_num++ == 1) {
3392 ++ if (!one_process && !foreground) {
3393 ++ rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
3394 ++ : APR_PROC_DETACH_DAEMONIZE);
3395 ++ if (rv != APR_SUCCESS) {
3396 ++ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
3397 ++ "apr_proc_detach failed");
3398 ++ return HTTP_INTERNAL_SERVER_ERROR;
3399 ++ }
3400 ++ }
3401 ++
3402 ++ parent_pid = ap_my_pid = getpid();
3403 ++ }
3404 ++
3405 ++ unixd_pre_config(ptemp);
3406 ++ ap_listen_pre_config();
3407 ++ ap_min_processors = DEFAULT_MIN_PROCESSORS;
3408 ++ ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS;
3409 ++ ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS;
3410 ++ ap_max_processors = DEFAULT_MAX_PROCESSORS;
3411 ++ ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS;
3412 ++ ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS;
3413 ++ ap_daemons_limit = server_limit;
3414 ++ ap_pid_fname = DEFAULT_PIDLOG;
3415 ++ ap_lock_fname = DEFAULT_LOCKFILE;
3416 ++ ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
3417 ++ ap_extended_status = 1;
3418 ++#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
3419 ++ ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
3420 ++#endif
3421 ++
3422 ++ expire_timeout = DEFAULT_EXPIRE_TIMEOUT;
3423 ++ idle_timeout = DEFAULT_IDLE_TIMEOUT;
3424 ++ multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
3425 ++ processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT;
3426 ++ processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS;
3427 ++
3428 ++
3429 ++ apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
3430 ++
3431 ++ /* we need to know ServerLimit and ThreadLimit before we start processing
3432 ++ * the tree because we need to already have allocated child_info_table
3433 ++ */
3434 ++ for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next)
3435 ++ {
3436 ++ if (!strcasecmp(pdir->directive, "ServerLimit"))
3437 ++ {
3438 ++ if (atoi(pdir->args) > tmp_server_limit)
3439 ++ {
3440 ++ tmp_server_limit = atoi(pdir->args);
3441 ++ if (tmp_server_limit > MAX_SERVER_LIMIT)
3442 ++ {
3443 ++ tmp_server_limit = MAX_SERVER_LIMIT;
3444 ++ }
3445 ++ }
3446 ++ }
3447 ++ }
3448 ++
3449 ++ /* We don't want to have to recreate the scoreboard after
3450 ++ * restarts, so we'll create a global pool and never clean it.
3451 ++ */
3452 ++ rv = apr_pool_create(&global_pool, NULL);
3453 ++ if (rv != APR_SUCCESS) {
3454 ++ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
3455 ++ "Fatal error: unable to create global pool");
3456 ++ return rv;
3457 ++ }
3458 ++
3459 ++ if (!child_info_image) {
3460 ++ _DBG("Initializing child_info_table", 0);
3461 ++ child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t);
3462 ++
3463 ++ rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool);
3464 ++
3465 ++ /* if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */
3466 ++ if (rv != APR_SUCCESS) {
3467 ++ _DBG("shared memory creation failed", 0);
3468 ++
3469 ++ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
3470 ++ "Unable to create shared memory segment "
3471 ++ "(anonymous shared memory failure)");
3472 ++ }
3473 ++ else if (rv == APR_ENOTIMPL) {
3474 ++ _DBG("anonymous shared memory not available", 0);
3475 ++ /* TODO: make up a filename and do name-based shmem */
3476 ++ }
3477 ++
3478 ++ if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) {
3479 ++ _DBG("apr_shm_baseaddr_get() failed", 0);
3480 ++ return HTTP_INTERNAL_SERVER_ERROR;
3481 ++ }
3482 ++
3483 ++ memset(shmem, 0, child_info_size);
3484 ++ child_info_image = (child_info*)apr_palloc(global_pool, sizeof(child_info));
3485 ++ child_info_image->control = (child_info_control*)shmem;
3486 ++ shmem += sizeof(child_info_control);
3487 ++ child_info_image->table = (child_info_t*)shmem;
3488 ++ }
3489 ++
3490 ++ _DBG("Clearing child_info_table");
3491 ++ child_info_image->control->num = 0;
3492 ++
3493 ++ for (i = 0; i < tmp_server_limit; i++) {
3494 ++ CHILD_INFO_TABLE[i].pid = 0;
3495 ++ CHILD_INFO_TABLE[i].senv = (server_env_t*)NULL;
3496 ++ CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN;
3497 ++ CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY;
3498 ++ CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */
3499 ++ CHILD_INFO_TABLE[i].id = i;
3500 ++ }
3501 ++
3502 ++ if (!server_env_image)
3503 ++ {
3504 ++ _DBG("Initializing server_environments_table", 0);
3505 ++ server_env_size = tmp_server_limit * sizeof(server_env_t) + sizeof(apr_size_t);
3506 ++
3507 ++ rv = apr_shm_create(&server_env_shm, server_env_size, NULL, global_pool);
3508 ++
3509 ++ if (rv != APR_SUCCESS) {
3510 ++ _DBG("shared memory creation failed", 0);
3511 ++
3512 ++ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
3513 ++ "Unable to create shared memory segment "
3514 ++ "(anonymous shared memory failure)");
3515 ++ }
3516 ++ else if (rv == APR_ENOTIMPL) {
3517 ++ _DBG("anonymous shared memory not available", 0);
3518 ++ /* TODO: make up a filename and do name-based shmem */
3519 ++ }
3520 ++
3521 ++ if (rv || !(shmem = apr_shm_baseaddr_get(server_env_shm))) {
3522 ++ _DBG("apr_shm_baseaddr_get() failed", 0);
3523 ++ return HTTP_INTERNAL_SERVER_ERROR;
3524 ++ }
3525 ++
3526 ++ memset(shmem, 0, server_env_size);
3527 ++ server_env_image = (server_env*)apr_palloc(global_pool, sizeof(server_env));
3528 ++ server_env_image->control = (server_env_control*)shmem;
3529 ++ shmem += sizeof(server_env_control);
3530 ++ server_env_image->table = (server_env_t*)shmem;
3531 ++ }
3532 ++
3533 ++ _DBG("Clearing server environment table");
3534 ++ server_env_image->control->num = 0;
3535 ++
3536 ++ for (i = 0; i < tmp_server_limit; i++) {
3537 ++ SENV[i].processor_id = -1;
3538 ++ SENV[i].uid = -1;
3539 ++ SENV[i].gid = -1;
3540 ++ SENV[i].chroot = NULL;
3541 ++ SENV[i].input = -1;
3542 ++ SENV[i].output = -1;
3543 ++ SENV[i].error_cgroup = 0;
3544 ++ SENV[i].error_pass = 0;
3545 ++ }
3546 ++
3547 ++ return OK;
3548 ++}
3549 ++
3550 ++static int peruser_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server_list)
3551 ++{
3552 ++ server_env_t senv;
3553 ++ const char *r;
3554 ++
3555 ++ ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable));
3556 ++
3557 ++ /* Retrieve the function from mod_ssl for detecting SSL virtualhosts */
3558 ++ ssl_server_is_https = (ssl_server_is_https_t) apr_dynamic_fn_retrieve("ssl_server_is_https");
3559 ++
3560 ++ /* Create the server environment for multiplexers */
3561 ++ senv.uid = unixd_config.user_id;
3562 ++ senv.gid = unixd_config.group_id;
3563 ++ senv.chroot = multiplexer_chroot;
3564 ++ senv.cgroup = NULL;
3565 ++ senv.nice_lvl = 0;
3566 ++ senv.name = "Multiplexer";
3567 ++
3568 ++ senv.min_processors = ap_min_multiplexers;
3569 ++ senv.min_free_processors = ap_min_free_processors;
3570 ++ senv.max_free_processors = ap_max_free_processors;
3571 ++ senv.max_processors = ap_max_multiplexers;
3572 ++
3573 ++ r = child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING,
3574 ++ p, &senv);
3575 ++
3576 ++ if (r != NULL) {
3577 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, p, r);
3578 ++ return -1;
3579 ++ }
3580 ++
3581 ++ return OK;
3582 ++}
3583 ++
3584 ++static int peruser_post_read(request_rec *r)
3585 ++{
3586 ++ _DBG("function entered");
3587 ++
3588 ++ peruser_server_conf *sconf = PERUSER_SERVER_CONF(r->server->module_config);
3589 ++ child_info_t *processor;
3590 ++
3591 ++ if (sconf->senv == NULL) {
3592 ++ _DBG("Server environment not set on virtualhost %s", r->server->server_hostname);
3593 ++
3594 ++ if (sconf->missing_senv_reported == 0) {
3595 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
3596 ++ "Virtualhost %s has no server environment set, "
3597 ++ "request will not be honoured.", r->server->server_hostname);
3598 ++ }
3599 ++
3600 ++ sconf->missing_senv_reported = 1;
3601 ++
3602 ++ return HTTP_INTERNAL_SERVER_ERROR;
3603 ++ }
3604 ++
3605 ++ if(CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
3606 ++ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id];
3607 ++ else
3608 ++ processor = &CHILD_INFO_TABLE[r->connection->id];
3609 ++
3610 ++
3611 ++ if (!strlen(r->the_request))
3612 ++ {
3613 ++ _DBG("corrupt request. aborting",0);
3614 ++ return DECLINED;
3615 ++ }
3616 ++
3617 ++ if (processor->sock_fd != AP_PERUSER_THISCHILD)
3618 ++ {
3619 ++ apr_socket_t *sock = NULL;
3620 ++
3621 ++ apr_os_sock_put(&sock, &processor->sock_fd, r->connection->pool);
3622 ++ ap_sock_disable_nagle(sock);
3623 ++ ap_set_module_config(r->connection->conn_config, &core_module, sock);
3624 ++ _DBG("not the right socket?", 0);
3625 ++ return OK;
3626 ++ }
3627 ++
3628 ++ switch (CHILD_INFO_TABLE[my_child_num].type)
3629 ++ {
3630 ++ case CHILD_TYPE_MULTIPLEXER:
3631 ++ {
3632 ++ _DBG("MULTIPLEXER => Determining if request should be passed. "
3633 ++ "Child Num: %d, dest-child: %d, hostname from server: %s r->hostname=%s r->the_request=\"%s\"",
3634 ++ my_child_num, processor->id, r->server->server_hostname, r->hostname, r->the_request);
3635 ++
3636 ++ if (processor->id != my_child_num)
3637 ++ {
3638 ++ if (processor->status == CHILD_STATUS_STANDBY)
3639 ++ {
3640 ++ _DBG("Activating child #%d", processor->id);
3641 ++ processor->status = CHILD_STATUS_STARTING;
3642 ++ }
3643 ++
3644 ++ _DBG("Passing request.",0);
3645 ++ if (pass_request(r, processor) == -1)
3646 ++ {
3647 ++ if (processor->senv->error_pass == 0) {
3648 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
3649 ++ ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.",
3650 ++ processor->senv->name, r->hostname);
3651 ++ }
3652 ++
3653 ++ processor->senv->error_pass = 1;
3654 ++
3655 ++ return HTTP_SERVICE_UNAVAILABLE;
3656 ++ }
3657 ++ else {
3658 ++ processor->senv->error_pass = 0;
3659 ++ }
3660 ++
3661 ++ _DBG("doing longjmp",0);
3662 ++ longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
3663 ++ _DBG("request declined at our site",0);
3664 ++ return DECLINED;
3665 ++ }
3666 ++ _DBG("WTF: the server is assigned to the multiplexer! ... dropping request",0);
3667 ++ return DECLINED;
3668 ++ }
3669 ++ case CHILD_TYPE_PROCESSOR:
3670 ++ case CHILD_TYPE_WORKER:
3671 ++ {
3672 ++ if (sconf->senv != CHILD_INFO_TABLE[my_child_num].senv) {
3673 ++ ap_log_error(APLOG_MARK, APLOG_WARNING,
3674 ++ 0, ap_server_conf,
3675 ++ "invalid virtualhost for this child! (%s)", r->hostname);
3676 ++ ap_lingering_close(r->connection);
3677 ++ return HTTP_REQUEST_TIME_OUT;
3678 ++ }
3679 ++
3680 ++ _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num);
3681 ++ _DBG("request for %s / (server %s) seems to be for us", r->hostname, r->server->server_hostname);
3682 ++
3683 ++ if (server_env_cleanup)
3684 ++ {
3685 ++ int i;
3686 ++ int input = sconf->senv->input;
3687 ++ int output = sconf->senv->output;
3688 ++
3689 ++ _DBG("performing handle cleanup");
3690 ++ for (i = 0; i < NUM_SENV; i++)
3691 ++ {
3692 ++ if (SENV[i].input > 0 && SENV[i].input != input) {
3693 ++ int retval = close(SENV[i].input);
3694 ++ if (retval < 0) {
3695 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
3696 ++ "close(%d) failed", SENV[i].input);
3697 ++ }
3698 ++ }
3699 ++ if (SENV[i].output > 0 && SENV[i].output != output) {
3700 ++ int retval = close(SENV[i].output);
3701 ++ if (retval < 0) {
3702 ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
3703 ++ "close(%d) failed", SENV[i].output);
3704 ++ }
3705 ++ }
3706 ++ }
3707 ++ server_env_cleanup = 0;
3708 ++ }
3709 ++
3710 ++ return OK;
3711 ++ }
3712 ++ default:
3713 ++ {
3714 ++ _DBG("unspecified child type %d in %d, dropping request",
3715 ++ CHILD_INFO_TABLE[my_child_num].type, my_child_num);
3716 ++ return DECLINED;
3717 ++ }
3718 ++ }
3719 ++
3720 ++ _DBG("THIS POINT SHOULD NOT BE REACHED!",0);
3721 ++ return OK;
3722 ++}
3723 ++
3724 ++
3725 ++int senv_active_cmp(const void *a, const void *b) {
3726 ++ _DBG("CMP %d %d", *(int *) a,*(int *) b);
3727 ++ return active_env_processors(*(int *)a)<active_env_processors(*(int *)b);
3728 ++}
3729 ++
3730 ++static int peruser_status_hook(request_rec *r, int flags)
3731 ++{
3732 ++ int x;
3733 ++ server_env_t *senv;
3734 ++
3735 ++ if (flags & AP_STATUS_SHORT)
3736 ++ return OK;
3737 ++
3738 ++
3739 ++ if (flags & AP_STATUS_STATS) {
3740 ++
3741 ++ int *sorted_senv;
3742 ++ int i;
3743 ++ sorted_senv=(int *) apr_palloc(r->pool, NUM_SENV*sizeof(int));
3744 ++
3745 ++ if(!sorted_senv) {
3746 ++ ap_rputs("peruser_status_hook(): Out of memory",r);
3747 ++ return OK;
3748 ++ }
3749 ++ /* Initial senv table */
3750 ++ for(i=0; i < NUM_SENV; i++)
3751 ++ sorted_senv[i]=i;
3752 ++
3753 ++ /* sort env by number of processors */
3754 ++ qsort(sorted_senv, NUM_SENV, sizeof(int), senv_active_cmp);
3755 ++
3756 ++ ap_rputs("<h3>Processors statistics:</h3><table border=\"0\"><tr><th>Environment</th><th>Pss</th><th>Avail</th></tr>", r);
3757 ++ /* just a mockup to se what data will be usefull here will put code layter, yes I know we need to iterate ON ENV[] NUM_ENV times */
3758 ++ for (x = 0; x < NUM_SENV; x++)
3759 ++ {
3760 ++ senv = &SENV[sorted_senv[x]];
3761 ++ if(senv==NULL)
3762 ++ continue;
3763 ++ ap_rprintf(r, "<tr><td nowrap>%s</td><td nowrap>%d/%d/%d</td>"
3764 ++ "<td>%d%%</td></tr>",
3765 ++ senv == NULL ? NULL : ( senv->name == NULL ? "" : senv->name ),
3766 ++ active_env_processors(sorted_senv[x]), idle_env_processors(sorted_senv[x]), senv == NULL ? 0 : senv->max_processors,
3767 ++ senv == NULL ? 0 : senv->availability );
3768 ++ }
3769 ++ ap_rputs("</table><tr/>", r);
3770 ++
3771 ++ ap_rputs("<hr/><table>"
3772 ++ "<tr><th>Pss</th><td>Number of processors active/idle/max</td></tr>"
3773 ++ "</table><hr/>",r);
3774 ++ }else {
3775 ++ ap_rputs("<hr>\n", r);
3776 ++ ap_rputs("<h3>peruser status</h3>\n", r);
3777 ++ ap_rputs("<table border=\"0\">\n", r);
3778 ++ ap_rputs("<tr><th>ID</th><th>PID</th><th>STATUS</th><th>SB STATUS</th><th>Type</th><th>Processor</th>"
3779 ++ "<th>Pss</th>"
3780 ++ "<th>AVAIL</th>"
3781 ++ "</tr>\n", r);
3782 ++ for (x = 0; x < NUM_CHILDS; x++)
3783 ++ {
3784 ++ senv = CHILD_INFO_TABLE[x].senv;
3785 ++ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td><td nowrap>%48s</td>"
3786 ++ "<td>%d/%d/%d</td>"
3787 ++ "<td>%3d%%</td></tr>\n",
3788 ++ CHILD_INFO_TABLE[x].id,
3789 ++ CHILD_INFO_TABLE[x].pid,
3790 ++ child_status_string(CHILD_INFO_TABLE[x].status),
3791 ++ scoreboard_status_string(SCOREBOARD_STATUS(x)),
3792 ++ child_type_string(CHILD_INFO_TABLE[x].type),
3793 ++ senv == NULL ? NULL : ( senv->name == NULL ? "" : senv->name ),
3794 ++ active_processors(x),
3795 ++ idle_processors(x),
3796 ++ senv == NULL ? 0 : CHILD_INFO_TABLE[x].senv->max_processors,
3797 ++ senv == NULL ? 0 : CHILD_INFO_TABLE[x].senv->availability
3798 ++ );
3799 ++ }
3800 ++ ap_rputs("</table>\n", r);
3801 ++
3802 ++ ap_rputs("<hr/><table>"
3803 ++ "<tr><th>STATUS</th><td>Processor status</td></tr>"
3804 ++ "<tr><th>Pss</th><td>Number of processors active/idle/max</td></tr>"
3805 ++ "</table><hr/>",r);
3806 ++ }
3807 ++
3808 ++ if (grace_children > 0) {
3809 ++ ap_rputs("<h2>peruser graceful children status</h2>\n", r);
3810 ++ ap_rprintf(r, "%d of total %d still living<br />\n", grace_children_alive, grace_children);
3811 ++ ap_rputs("<table border=\"0\">\n", r);
3812 ++ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td></tr>\n", r);
3813 ++ for (x = 0; x < grace_children; x++) {
3814 ++ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td></tr>\n",
3815 ++ child_grace_info_table[x].id,
3816 ++ child_grace_info_table[x].pid,
3817 ++ child_status_string(child_grace_info_table[x].status),
3818 ++ child_type_string(child_grace_info_table[x].type)
3819 ++ );
3820 ++ }
3821 ++ ap_rputs("</table>\n", r);
3822 ++ }
3823 ++ return OK;
3824 ++}
3825 ++
3826 ++static void peruser_hooks(apr_pool_t *p)
3827 ++{
3828 ++ /* The peruser open_logs phase must run before the core's, or stderr
3829 ++ * will be redirected to a file, and the messages won't print to the
3830 ++ * console.
3831 ++ */
3832 ++ static const char *const aszSucc[] = {"core.c", NULL};
3833 ++
3834 ++#ifdef AUX3
3835 ++ (void) set42sig();
3836 ++#endif
3837 ++
3838 ++ ap_hook_open_logs(peruser_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
3839 ++ ap_hook_pre_config(peruser_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
3840 ++ ap_hook_post_config(peruser_post_config, NULL, NULL, APR_HOOK_MIDDLE);
3841 ++
3842 ++ /* Both of these must be run absolutely first. If this request isn't for
3843 ++ * this server then we need to forward it to the proper child. No sense
3844 ++ * tying up this server running more post_read request hooks if it is
3845 ++ * just going to be forwarded along. The process_connection hook allows
3846 ++ * peruser to receive the passed request correctly, by automatically
3847 ++ * filling in the core_input_filter's ctx pointer.
3848 ++ */
3849 ++ ap_hook_post_read_request(peruser_post_read, NULL, NULL,
3850 ++ APR_HOOK_REALLY_FIRST);
3851 ++ ap_hook_process_connection(peruser_process_connection, NULL, NULL,
3852 ++ APR_HOOK_REALLY_FIRST);
3853 ++
3854 ++ APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
3855 ++}
3856 ++
3857 ++void senv_init(server_env_t * senv) {
3858 ++ senv->nice_lvl = 0;
3859 ++ senv->chroot = NULL;
3860 ++ senv->cgroup = NULL;
3861 ++ senv->min_processors = ap_min_processors;
3862 ++ senv->min_free_processors = ap_min_free_processors;
3863 ++ senv->max_free_processors = ap_max_free_processors;
3864 ++ senv->max_processors = ap_max_processors;
3865 ++}
3866 ++
3867 ++static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg)
3868 ++{
3869 ++ const char *user_name = NULL, *group_name = NULL, *directive;
3870 ++ server_env_t senv;
3871 ++ ap_directive_t *current;
3872 ++
3873 ++ const char *endp = ap_strrchr_c(arg, '>');
3874 ++
3875 ++ if (endp == NULL) {
3876 ++ return apr_psprintf(cmd->temp_pool,
3877 ++ "Error: Directive %s> missing closing '>'", cmd->cmd->name);
3878 ++ }
3879 ++
3880 ++ arg = apr_pstrndup(cmd->pool, arg, endp - arg);
3881 ++
3882 ++ if (!arg) {
3883 ++ return apr_psprintf(cmd->temp_pool,
3884 ++ "Error: %s> must specify a processor name", cmd->cmd->name);
3885 ++ }
3886 ++
3887 ++ senv.name = ap_getword_conf(cmd->pool, &arg);
3888 ++ _DBG("processor_name: %s", senv.name);
3889 ++
3890 ++ if (strlen(senv.name) == 0) {
3891 ++ return apr_psprintf(cmd->temp_pool,
3892 ++ "Error: Directive %s> takes one argument", cmd->cmd->name);
3893 ++ }
3894 ++
3895 ++ server_env_t *old_senv = find_senv_by_name(senv.name);
3896 ++
3897 ++ if (old_senv) {
3898 ++ return apr_psprintf(cmd->temp_pool,
3899 ++ "Error: Processor %s already defined", senv.name);
3900 ++ }
3901 ++
3902 ++ senv_init(&senv);
3903 ++
3904 ++ current = cmd->directive->first_child;
3905 ++
3906 ++ int proc_temp = 0;
3907 ++ for(; current != NULL; current = current->next) {
3908 ++ directive = current->directive;
3909 ++
3910 ++ if (!strcasecmp(directive, "user")) {
3911 ++ user_name = current->args;
3912 ++ }
3913 ++ else if (!strcasecmp(directive, "group")) {
3914 ++ group_name = current->args;
3915 ++ }
3916 ++ else if (!strcasecmp(directive, "chroot")) {
3917 ++ senv.chroot = ap_getword_conf(cmd->pool, &current->args);
3918 ++ }
3919 ++ else if (!strcasecmp(directive, "nicelevel")) {
3920 ++ senv.nice_lvl = atoi(current->args);
3921 ++ }
3922 ++ else if (!strcasecmp(directive, "maxprocessors")) {
3923 ++ proc_temp = atoi(current->args);
3924 ++
3925 ++ if (proc_temp < 1) {
3926 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3927 ++ "WARNING: Require MaxProcessors > 0, setting to 1");
3928 ++ proc_temp = 1;
3929 ++ }
3930 ++
3931 ++ senv.max_processors = proc_temp;
3932 ++ }
3933 ++ else if (!strcasecmp(directive, "minprocessors")) {
3934 ++ proc_temp = atoi(current->args);
3935 ++
3936 ++ if (proc_temp < 0) {
3937 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3938 ++ "WARNING: Require MinProcessors >= 0, setting to 0");
3939 ++ proc_temp = 0;
3940 ++ }
3941 ++
3942 ++ senv.min_processors = proc_temp;
3943 ++ }
3944 ++ else if (!strcasecmp(directive, "minspareprocessors")) {
3945 ++ proc_temp = atoi(current->args);
3946 ++
3947 ++ if (proc_temp < 0) {
3948 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3949 ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
3950 ++ proc_temp = 0;
3951 ++ }
3952 ++
3953 ++ senv.min_free_processors = proc_temp;
3954 ++ }
3955 ++ else if (!strcasecmp(directive, "maxspareprocessors")) {
3956 ++ proc_temp = atoi(current->args);
3957 ++
3958 ++ if (proc_temp < 0) {
3959 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3960 ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
3961 ++ proc_temp = 0;
3962 ++ }
3963 ++
3964 ++ senv.max_free_processors = proc_temp;
3965 ++ }
3966 ++ else if (!strcasecmp(directive, "cgroup")) {
3967 ++ senv.cgroup = ap_getword_conf(cmd->pool, &current->args);
3968 ++ }
3969 ++ else {
3970 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
3971 ++ "Unknown directive %s in %s>", directive, cmd->cmd->name);
3972 ++ }
3973 ++ }
3974 ++
3975 ++ if (user_name == NULL || group_name == NULL) {
3976 ++ return apr_psprintf(cmd->temp_pool,
3977 ++ "Error: User or Group must be set in %s>", cmd->cmd->name);
3978 ++ }
3979 ++
3980 ++ senv.uid = ap_uname2id(user_name);
3981 ++ senv.gid = ap_gname2id(group_name);
3982 ++
3983 ++ _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d",
3984 ++ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl);
3985 ++
3986 ++ _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d",
3987 ++ senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors);
3988 ++
3989 ++ return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY,
3990 ++ cmd->pool, &senv);
3991 ++}
3992 ++
3993 ++static const char *cf_Processor_depr(cmd_parms *cmd, void *dummy,
3994 ++ const char *user_name, const char *group_name, const char *chroot)
3995 ++{
3996 ++ return NULL;
3997 ++}
3998 ++
3999 ++/* we define an Multiplexer child w/ specific uid/gid */
4000 ++static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy,
4001 ++ const char *user_name, const char *group_name, const char *chroot)
4002 ++{
4003 ++ static short depr_warned = 0;
4004 ++
4005 ++ if (depr_warned == 0) {
4006 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4007 ++ "WARNING: Multiplexer directive is deprecated. Multiplexer user and group is set by User and Group directives.");
4008 ++
4009 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4010 ++ "To set multiplexer chroot, please use MultiplexerChroot.");
4011 ++
4012 ++ depr_warned = 1;
4013 ++ }
4014 ++
4015 ++ if (chroot) {
4016 ++ if (!ap_is_directory(cmd->pool, chroot))
4017 ++ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", chroot);
4018 ++
4019 ++ multiplexer_chroot = chroot;
4020 ++ _DBG("Setting multiplexer chroot to %s", chroot);
4021 ++ }
4022 ++
4023 ++ return NULL;
4024 ++}
4025 ++
4026 ++static const char* cf_MultiplexerChroot(cmd_parms *cmd, void *dummy,
4027 ++ const char *path)
4028 ++{
4029 ++ multiplexer_chroot = path;
4030 ++
4031 ++ if (path && !ap_is_directory(cmd->pool, path))
4032 ++ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", path);
4033 ++
4034 ++ _DBG("setting multiplexer chroot to %s", path);
4035 ++
4036 ++ return NULL;
4037 ++}
4038 ++
4039 ++static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy,
4040 ++ const char *name, const char * group_name, const char * chroot)
4041 ++{
4042 ++ peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
4043 ++ server_env_t senv;
4044 ++ char * processor_name, *tmp;
4045 ++
4046 ++ _DBG("function entered", 0);
4047 ++
4048 ++ /* name of processor env */
4049 ++ processor_name = name;
4050 ++
4051 ++ if(group_name != NULL || chroot != NULL) {
4052 ++ /* deprecated ServerEnvironment user group chroot syntax
4053 ++ * we create simple server env based on user/group/chroot only
4054 ++ */
4055 ++ processor_name = apr_pstrcat(cmd->pool, name, "_",group_name, "_", chroot, NULL);
4056 ++
4057 ++ /* search for previous default server env */
4058 ++ sconf->senv = find_senv_by_name(processor_name);
4059 ++
4060 ++ if(!sconf->senv) {
4061 ++ senv_init(&senv);
4062 ++ senv.uid = ap_uname2id(name);
4063 ++ senv.gid = ap_gname2id(group_name);
4064 ++ senv.chroot = chroot;
4065 ++ senv.name = processor_name;
4066 ++
4067 ++ tmp = child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, cmd->pool, &senv);
4068 ++ /* error handling in case this child can't be created */
4069 ++ if(tmp)
4070 ++ return tmp;
4071 ++ }
4072 ++ }
4073 ++
4074 ++ /* use predefined processor environment or default named "user_group_chroot" */
4075 ++ if(sconf->senv == NULL)
4076 ++ sconf->senv = find_senv_by_name(processor_name);
4077 ++
4078 ++ if (sconf->senv == NULL) {
4079 ++ return apr_psprintf(cmd->pool,
4080 ++ "Error: Processor %s not defined", name);
4081 ++ }
4082 ++
4083 ++ _DBG("user=%d group=%d chroot=%s numchilds=%d",
4084 ++ sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS);
4085 ++
4086 ++ return NULL;
4087 ++}
4088 ++
4089 ++static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const char *arg)
4090 ++{
4091 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4092 ++ if (err != NULL) {
4093 ++ return err;
4094 ++ }
4095 ++
4096 ++ ap_min_free_processors = atoi(arg);
4097 ++ if (ap_min_free_processors <= 0) {
4098 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4099 ++ "WARNING: detected MinSpareServers set to non-positive.");
4100 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4101 ++ "Resetting to 1 to avoid almost certain Apache failure.");
4102 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4103 ++ "Please read the documentation.");
4104 ++ ap_min_free_processors = 1;
4105 ++ }
4106 ++
4107 ++ return NULL;
4108 ++}
4109 ++
4110 ++static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg)
4111 ++{
4112 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4113 ++ if (err != NULL) {
4114 ++ return err;
4115 ++ }
4116 ++
4117 ++ ap_daemons_limit = atoi(arg);
4118 ++ if (ap_daemons_limit > server_limit) {
4119 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4120 ++ "WARNING: MaxClients of %d exceeds ServerLimit value "
4121 ++ "of %d servers,", ap_daemons_limit, server_limit);
4122 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4123 ++ " lowering MaxClients to %d. To increase, please "
4124 ++ "see the ServerLimit", server_limit);
4125 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4126 ++ " directive.");
4127 ++ ap_daemons_limit = server_limit;
4128 ++ }
4129 ++ else if (ap_daemons_limit < 1) {
4130 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4131 ++ "WARNING: Require MaxClients > 0, setting to 1");
4132 ++ ap_daemons_limit = 1;
4133 ++ }
4134 ++ return NULL;
4135 ++}
4136 ++
4137 ++static const char *set_min_processors (cmd_parms *cmd, void *dummy, const char *arg)
4138 ++{
4139 ++ peruser_server_conf *sconf;
4140 ++ int min_procs;
4141 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
4142 ++
4143 ++ if (err != NULL) {
4144 ++ return err;
4145 ++ }
4146 ++
4147 ++ min_procs = atoi(arg);
4148 ++
4149 ++ if (min_procs < 0) {
4150 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4151 ++ "WARNING: Require MinProcessors >= 0, setting to 0");
4152 ++ min_procs = 0;
4153 ++ }
4154 ++
4155 ++ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
4156 ++ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
4157 ++ if(sconf->senv != NULL)
4158 ++ sconf->senv->min_processors = min_procs;
4159 ++ else
4160 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4161 ++ "WARNING: MinProcessors must be set after ServerEnvironment to take effect");
4162 ++ }
4163 ++ else {
4164 ++ ap_min_processors = min_procs;
4165 ++ }
4166 ++
4167 ++ return NULL;
4168 ++}
4169 ++
4170 ++static const char *set_min_free_processors (cmd_parms *cmd, void *dummy, const char *arg)
4171 ++{
4172 ++ peruser_server_conf *sconf;
4173 ++ int min_free_procs;
4174 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
4175 ++
4176 ++ if (err != NULL) {
4177 ++ return err;
4178 ++ }
4179 ++
4180 ++ min_free_procs = atoi(arg);
4181 ++
4182 ++ if (min_free_procs < 0) {
4183 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4184 ++ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
4185 ++ min_free_procs = 0;
4186 ++ }
4187 ++
4188 ++ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
4189 ++ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
4190 ++ if(sconf->senv != NULL)
4191 ++ sconf->senv->min_free_processors = min_free_procs;
4192 ++ else
4193 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4194 ++ "WARNING: MinSpareProcessors must be set after ServerEnvironment to take effect");
4195 ++ }
4196 ++ else {
4197 ++ ap_min_free_processors = min_free_procs;
4198 ++ }
4199 ++
4200 ++ return NULL;
4201 ++}
4202 ++
4203 ++static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg)
4204 ++{
4205 ++ peruser_server_conf *sconf;
4206 ++ int max_free_procs;
4207 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
4208 ++
4209 ++ if (err != NULL) {
4210 ++ return err;
4211 ++ }
4212 ++
4213 ++ max_free_procs = atoi(arg);
4214 ++
4215 ++ if (max_free_procs < 0) {
4216 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4217 ++ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
4218 ++ max_free_procs = 0;
4219 ++ }
4220 ++
4221 ++ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
4222 ++ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
4223 ++ if(sconf!=NULL)
4224 ++ sconf->senv->max_free_processors = max_free_procs;
4225 ++ else
4226 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4227 ++ "WARNING: MaxSpareProcessors must be set after ServerEnvironment to take effect");
4228 ++ }
4229 ++ else {
4230 ++ ap_max_free_processors = max_free_procs;
4231 ++ }
4232 ++
4233 ++ return NULL;
4234 ++}
4235 ++
4236 ++static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg)
4237 ++{
4238 ++ peruser_server_conf *sconf;
4239 ++ int max_procs;
4240 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
4241 ++
4242 ++ if (err != NULL) {
4243 ++ return err;
4244 ++ }
4245 ++
4246 ++ max_procs = atoi(arg);
4247 ++
4248 ++ if (max_procs < 1) {
4249 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4250 ++ "WARNING: Require MaxProcessors > 0, setting to 1");
4251 ++ max_procs = 1;
4252 ++ }
4253 ++
4254 ++ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
4255 ++ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
4256 ++ if(sconf->senv != NULL)
4257 ++ sconf->senv->max_processors = max_procs;
4258 ++ else
4259 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4260 ++ "WARNING: MaxProcessors must be set after ServerEnvironment to take effect");
4261 ++ }
4262 ++ else {
4263 ++ ap_max_processors = max_procs;
4264 ++ }
4265 ++
4266 ++ return NULL;
4267 ++}
4268 ++
4269 ++static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
4270 ++{
4271 ++ int min_multiplexers;
4272 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
4273 ++
4274 ++ if (err != NULL) {
4275 ++ return err;
4276 ++ }
4277 ++
4278 ++ min_multiplexers = atoi(arg);
4279 ++
4280 ++ if (min_multiplexers < 1) {
4281 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4282 ++ "WARNING: Require MinMultiplexers > 0, setting to 1");
4283 ++ min_multiplexers = 1;
4284 ++ }
4285 ++
4286 ++ ap_min_multiplexers = min_multiplexers;
4287 ++
4288 ++ return NULL;
4289 ++}
4290 ++
4291 ++static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
4292 ++{
4293 ++ int max_multiplexers;
4294 ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
4295 ++
4296 ++ if (err != NULL) {
4297 ++ return err;
4298 ++ }
4299 ++
4300 ++ max_multiplexers = atoi(arg);
4301 ++
4302 ++ if (max_multiplexers < 1) {
4303 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4304 ++ "WARNING: Require MaxMultiplexers > 0, setting to 1");
4305 ++ max_multiplexers = 1;
4306 ++ }
4307 ++
4308 ++ ap_max_multiplexers = max_multiplexers;
4309 ++
4310 ++ return NULL;
4311 ++}
4312 ++
4313 ++static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
4314 ++{
4315 ++ int tmp_server_limit;
4316 ++
4317 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4318 ++ if (err != NULL) {
4319 ++ return err;
4320 ++ }
4321 ++
4322 ++ tmp_server_limit = atoi(arg);
4323 ++ /* you cannot change ServerLimit across a restart; ignore
4324 ++ * any such attempts
4325 ++ */
4326 ++ if (first_server_limit &&
4327 ++ tmp_server_limit != server_limit) {
4328 ++ /* how do we log a message? the error log is a bit bucket at this
4329 ++ * point; we'll just have to set a flag so that ap_mpm_run()
4330 ++ * logs a warning later
4331 ++ */
4332 ++ changed_limit_at_restart = 1;
4333 ++ return NULL;
4334 ++ }
4335 ++ server_limit = tmp_server_limit;
4336 ++
4337 ++ if (server_limit > MAX_SERVER_LIMIT) {
4338 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4339 ++ "WARNING: ServerLimit of %d exceeds compile time limit "
4340 ++ "of %d servers,", server_limit, MAX_SERVER_LIMIT);
4341 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4342 ++ " lowering ServerLimit to %d.", MAX_SERVER_LIMIT);
4343 ++ server_limit = MAX_SERVER_LIMIT;
4344 ++ }
4345 ++ else if (server_limit < 1) {
4346 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4347 ++ "WARNING: Require ServerLimit > 0, setting to 1");
4348 ++ server_limit = 1;
4349 ++ }
4350 ++ return NULL;
4351 ++}
4352 ++
4353 ++static const char *set_expire_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
4354 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4355 ++ if (err != NULL) {
4356 ++ return err;
4357 ++ }
4358 ++
4359 ++ expire_timeout = atoi(arg);
4360 ++
4361 ++ return NULL;
4362 ++}
4363 ++
4364 ++static const char *set_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
4365 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4366 ++ if (err != NULL) {
4367 ++ return err;
4368 ++ }
4369 ++
4370 ++ idle_timeout = atoi(arg);
4371 ++
4372 ++ return NULL;
4373 ++}
4374 ++
4375 ++static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
4376 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4377 ++
4378 ++ if (err != NULL) {
4379 ++ return err;
4380 ++ }
4381 ++
4382 ++ multiplexer_idle_timeout = atoi(arg);
4383 ++
4384 ++ return NULL;
4385 ++}
4386 ++
4387 ++static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) {
4388 ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
4389 ++
4390 ++ if (err != NULL) {
4391 ++ return err;
4392 ++ }
4393 ++
4394 ++ processor_wait_timeout = atoi(timeout);
4395 ++
4396 ++ if (steps != NULL) {
4397 ++ int steps_tmp = atoi(steps);
4398 ++
4399 ++ if (steps_tmp < 1) {
4400 ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
4401 ++ "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1");
4402 ++ steps_tmp = 1;
4403 ++ }
4404 ++
4405 ++ processor_wait_steps = steps_tmp;
4406 ++ }
4407 ++
4408 ++ return NULL;
4409 ++}
4410 ++
4411 ++static const command_rec peruser_cmds[] = {
4412 ++UNIX_DAEMON_COMMANDS,
4413 ++LISTEN_COMMANDS,
4414 ++AP_INIT_TAKE1("MinSpareProcessors", set_min_free_processors, NULL, RSRC_CONF,
4415 ++ "Minimum number of idle children, to handle request spikes"),
4416 ++AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF,
4417 ++ "Minimum number of idle children, to handle request spikes"),
4418 ++AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF,
4419 ++ "Maximum number of idle children, 0 to disable"),
4420 ++AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
4421 ++ "Maximum number of children alive at the same time"),
4422 ++AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF,
4423 ++ "Minimum number of processors per vhost"),
4424 ++AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF,
4425 ++ "Maximum number of processors per vhost"),
4426 ++AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF,
4427 ++ "Minimum number of multiplexers the server can have"),
4428 ++AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF,
4429 ++ "Maximum number of multiplexers the server can have"),
4430 ++AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
4431 ++ "Maximum value of MaxClients for this run of Apache"),
4432 ++AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF,
4433 ++ "Maximum time a child can live, 0 to disable"),
4434 ++AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF,
4435 ++ "Maximum time before a child is killed after being idle, 0 to disable"),
4436 ++AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF,
4437 ++ "Maximum time before a multiplexer is killed after being idle, 0 to disable"),
4438 ++AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF,
4439 ++ "Maximum time a multiplexer waits for the processor if it is busy"),
4440 ++AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF,
4441 ++ "Specify an Multiplexer Child configuration."),
4442 ++AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF,
4443 ++ "Specify settings for processor."),
4444 ++AP_INIT_TAKE23("Processor", cf_Processor_depr, NULL, RSRC_CONF,
4445 ++ "A dummy directive for backwards compatibility"),
4446 ++AP_INIT_TAKE123("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
4447 ++ "Specify the server environment for this virtual host."),
4448 ++AP_INIT_TAKE1("MultiplexerChroot", cf_MultiplexerChroot, NULL, RSRC_CONF,
4449 ++ "Specify the multiplexer chroot path for multiplexer"),
4450 ++{ NULL }
4451 ++};
4452 ++
4453 ++module AP_MODULE_DECLARE_DATA mpm_peruser_module = {
4454 ++ MPM20_MODULE_STUFF,
4455 ++ ap_mpm_rewrite_args, /* hook to run before apache parses args */
4456 ++ NULL, /* create per-directory config structure */
4457 ++ NULL, /* merge per-directory config structures */
4458 ++ peruser_create_config, /* create per-server config structure */
4459 ++ NULL, /* merge per-server config structures */
4460 ++ peruser_cmds, /* command apr_table_t */
4461 ++ peruser_hooks, /* register hooks */
4462 ++};
4463
4464 Deleted: trunk/dist/2.2/patches/20_all_peruser_0.4.0b1.patch
4465 ===================================================================
4466 --- trunk/dist/2.2/patches/20_all_peruser_0.4.0b1.patch 2010-09-01 05:49:01 UTC (rev 231)
4467 +++ trunk/dist/2.2/patches/20_all_peruser_0.4.0b1.patch 2010-09-01 05:49:03 UTC (rev 232)
4468 @@ -1,4252 +0,0 @@
4469 -diff -Nur httpd-2.2.13/modules/ssl/mod_ssl.h httpd-2.2.13-peruser/modules/ssl/mod_ssl.h
4470 ---- httpd-2.2.13/modules/ssl/mod_ssl.h 2006-07-12 06:38:44.000000000 +0300
4471 -+++ httpd-2.2.13-peruser/modules/ssl/mod_ssl.h 2009-09-01 16:19:22.000000000 +0300
4472 -@@ -50,6 +50,10 @@
4473 - * is using SSL/TLS. */
4474 - APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
4475 -
4476 -+/** An optional function which returns non-zero if the given server
4477 -+ * is using SSL/TLS. */
4478 -+APR_DECLARE_OPTIONAL_FN(int, ssl_server_is_https, (server_rec *));
4479 -+
4480 - /** The ssl_proxy_enable() and ssl_engine_disable() optional functions
4481 - * are used by mod_proxy to enable use of SSL for outgoing
4482 - * connections. */
4483 -diff -Nur httpd-2.2.13/modules/ssl/ssl_engine_vars.c httpd-2.2.13-peruser/modules/ssl/ssl_engine_vars.c
4484 ---- httpd-2.2.13/modules/ssl/ssl_engine_vars.c 2009-08-06 10:28:47.000000000 +0300
4485 -+++ httpd-2.2.13-peruser/modules/ssl/ssl_engine_vars.c 2009-09-01 16:19:22.000000000 +0300
4486 -@@ -58,6 +58,12 @@
4487 - return sslconn && sslconn->ssl;
4488 - }
4489 -
4490 -+static int ssl_server_is_https(server_rec *s)
4491 -+{
4492 -+ SSLSrvConfigRec *sslsrv = mySrvConfig(s);
4493 -+ return sslsrv && sslsrv->enabled;
4494 -+}
4495 -+
4496 - static const char var_interface[] = "mod_ssl/" MOD_SSL_VERSION;
4497 - static char var_library_interface[] = SSL_LIBRARY_TEXT;
4498 - static char *var_library = NULL;
4499 -@@ -67,6 +73,7 @@
4500 - char *cp, *cp2;
4501 -
4502 - APR_REGISTER_OPTIONAL_FN(ssl_is_https);
4503 -+ APR_REGISTER_OPTIONAL_FN(ssl_server_is_https);
4504 - APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
4505 - APR_REGISTER_OPTIONAL_FN(ssl_ext_lookup);
4506 -
4507 -diff -Nur httpd-2.2.13/server/mpm/config.m4 httpd-2.2.13-peruser/server/mpm/config.m4
4508 ---- httpd-2.2.13/server/mpm/config.m4 2005-10-30 19:05:26.000000000 +0200
4509 -+++ httpd-2.2.13-peruser/server/mpm/config.m4 2009-09-01 16:19:22.000000000 +0300
4510 -@@ -1,7 +1,7 @@
4511 - AC_MSG_CHECKING(which MPM to use)
4512 - AC_ARG_WITH(mpm,
4513 - APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use.
4514 -- MPM={beos|event|worker|prefork|mpmt_os2}),[
4515 -+ MPM={beos|event|worker|prefork|mpmt_os2|peruser}),[
4516 - APACHE_MPM=$withval
4517 - ],[
4518 - if test "x$APACHE_MPM" = "x"; then
4519 -@@ -23,7 +23,7 @@
4520 -
4521 - ap_mpm_is_experimental ()
4522 - {
4523 -- if test "$apache_cv_mpm" = "event" ; then
4524 -+ if test "$apache_cv_mpm" = "event" -o "$apache_cv_mpm" = "peruser" ; then
4525 - return 0
4526 - else
4527 - return 1
4528 -diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/AUTHORS httpd-2.2.13-peruser/server/mpm/experimental/peruser/AUTHORS
4529 ---- httpd-2.2.13/server/mpm/experimental/peruser/AUTHORS 1970-01-01 03:00:00.000000000 +0300
4530 -+++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/AUTHORS 2009-09-01 16:19:22.000000000 +0300
4531 -@@ -0,0 +1,11 @@
4532 -+Enrico Weigelt <weigelt [at] metux.de> (MetuxMPM maintainer)
4533 -+Sean Gabriel Heacock <gabriel [at] telana.com> (Peruser maintainer)
4534 -+Stefan Seufert <stefan [at] seuf.de>
4535 -+Janno Sannik <janno [at] kood.ee>
4536 -+Taavi Sannik <taavi [at] kood.ee>
4537 -+Rommer <rommer [at] active.by>
4538 -+Bert <bert [at] ev6.net>
4539 -+Leen Besselink <leen [at] consolejunkie.net>
4540 -+Steve Amerige <mpm [at] fatbear.com>
4541 -+Stefan Klingner <stefan.klingner [at] mephisto23.com> (Peruser maintainer)
4542 -+Michal Grzedzicki <lazy404 [at] gmail.com>
4543 -diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/config.m4 httpd-2.2.13-peruser/server/mpm/experimental/peruser/config.m4
4544 ---- httpd-2.2.13/server/mpm/experimental/peruser/config.m4 1970-01-01 03:00:00.000000000 +0300
4545 -+++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/config.m4 2009-09-01 16:19:22.000000000 +0300
4546 -@@ -0,0 +1,3 @@
4547 -+if test "$MPM_NAME" = "peruser" ; then
4548 -+ APACHE_FAST_OUTPUT(server/mpm/experimental/$MPM_NAME/Makefile)
4549 -+fi
4550 -diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/Makefile.in httpd-2.2.13-peruser/server/mpm/experimental/peruser/Makefile.in
4551 ---- httpd-2.2.13/server/mpm/experimental/peruser/Makefile.in 1970-01-01 03:00:00.000000000 +0300
4552 -+++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/Makefile.in 2009-09-01 16:19:22.000000000 +0300
4553 -@@ -0,0 +1,5 @@
4554 -+
4555 -+LTLIBRARY_NAME = libperuser.la
4556 -+LTLIBRARY_SOURCES = peruser.c
4557 -+
4558 -+include $(top_srcdir)/build/ltlib.mk
4559 -diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/mpm_default.h httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm_default.h
4560 ---- httpd-2.2.13/server/mpm/experimental/peruser/mpm_default.h 1970-01-01 03:00:00.000000000 +0300
4561 -+++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm_default.h 2009-09-01 16:19:22.000000000 +0300
4562 -@@ -0,0 +1,162 @@
4563 -+/* ====================================================================
4564 -+ * The Apache Software License, Version 1.1
4565 -+ *
4566 -+ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
4567 -+ * reserved.
4568 -+ *
4569 -+ * Redistribution and use in source and binary forms, with or without
4570 -+ * modification, are permitted provided that the following conditions
4571 -+ * are met:
4572 -+ *
4573 -+ * 1. Redistributions of source code must retain the above copyright
4574 -+ * notice, this list of conditions and the following disclaimer.
4575 -+ *
4576 -+ * 2. Redistributions in binary form must reproduce the above copyright
4577 -+ * notice, this list of conditions and the following disclaimer in
4578 -+ * the documentation and/or other materials provided with the
4579 -+ * distribution.
4580 -+ *
4581 -+ * 3. The end-user documentation included with the redistribution,
4582 -+ * if any, must include the following acknowledgment:
4583 -+ * "This product includes software developed by the
4584 -+ * Apache Software Foundation (http://www.apache.org/)."
4585 -+ * Alternately, this acknowledgment may appear in the software itself,
4586 -+ * if and wherever such third-party acknowledgments normally appear.
4587 -+ *
4588 -+ * 4. The names "Apache" and "Apache Software Foundation" must
4589 -+ * not be used to endorse or promote products derived from this
4590 -+ * software without prior written permission. For written
4591 -+ * permission, please contact apache@××××××.org.
4592 -+ *
4593 -+ * 5. Products derived from this software may not be called "Apache",
4594 -+ * nor may "Apache" appear in their name, without prior written
4595 -+ * permission of the Apache Software Foundation.
4596 -+ *
4597 -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
4598 -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4599 -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4600 -+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
4601 -+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4602 -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4603 -+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
4604 -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4605 -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
4606 -+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
4607 -+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4608 -+ * SUCH DAMAGE.
4609 -+ * ====================================================================
4610 -+ *
4611 -+ * This software consists of voluntary contributions made by many
4612 -+ * individuals on behalf of the Apache Software Foundation. For more
4613 -+ * information on the Apache Software Foundation, please see
4614 -+ * <http://www.apache.org/>.
4615 -+ *
4616 -+ * Portions of this software are based upon public domain software
4617 -+ * originally written at the National Center for Supercomputing Applications,
4618 -+ * University of Illinois, Urbana-Champaign.
4619 -+ */
4620 -+
4621 -+#ifndef APACHE_MPM_DEFAULT_H
4622 -+#define APACHE_MPM_DEFAULT_H
4623 -+
4624 -+/* Number of processors to spawn off for each ServerEnvironment by default */
4625 -+
4626 -+#ifndef DEFAULT_START_PROCESSORS
4627 -+#define DEFAULT_START_PROCESSORS 0
4628 -+#endif
4629 -+
4630 -+/* Minimum number of running processors per ServerEnvironment */
4631 -+
4632 -+#ifndef DEFAULT_MIN_PROCESSORS
4633 -+#define DEFAULT_MIN_PROCESSORS 0
4634 -+#endif
4635 -+
4636 -+/* Minimum --- fewer than this, and more will be created */
4637 -+
4638 -+#ifndef DEFAULT_MIN_FREE_PROCESSORS
4639 -+#define DEFAULT_MIN_FREE_PROCESSORS 2
4640 -+#endif
4641 -+
4642 -+/* Maximum --- more than this, and idle processors will be killed (0 = disable) */
4643 -+
4644 -+#ifndef DEFAULT_MAX_FREE_PROCESSORS
4645 -+#define DEFAULT_MAX_FREE_PROCESSORS 0
4646 -+#endif
4647 -+
4648 -+/* Maximum processors per ServerEnvironment */
4649 -+
4650 -+#ifndef DEFAULT_MAX_PROCESSORS
4651 -+#define DEFAULT_MAX_PROCESSORS 10
4652 -+#endif
4653 -+
4654 -+/* File used for accept locking, when we use a file */
4655 -+#ifndef DEFAULT_LOCKFILE
4656 -+#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock"
4657 -+#endif
4658 -+
4659 -+/* Where the main/parent process's pid is logged */
4660 -+#ifndef DEFAULT_PIDLOG
4661 -+#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid"
4662 -+#endif
4663 -+
4664 -+/*
4665 -+ * Interval, in microseconds, between scoreboard maintenance.
4666 -+ */
4667 -+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
4668 -+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
4669 -+#endif
4670 -+
4671 -+/* Number of requests to try to handle in a single process. If <= 0,
4672 -+ * the children don't die off.
4673 -+ */
4674 -+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
4675 -+#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
4676 -+#endif
4677 -+
4678 -+/* Maximum multiplexers */
4679 -+
4680 -+#ifndef DEFAULT_MAX_MULTIPLEXERS
4681 -+#define DEFAULT_MAX_MULTIPLEXERS 20
4682 -+#endif
4683 -+
4684 -+/* Minimum multiplexers */
4685 -+
4686 -+#ifndef DEFAULT_MIN_MULTIPLEXERS
4687 -+#define DEFAULT_MIN_MULTIPLEXERS 3
4688 -+#endif
4689 -+
4690 -+/* Amount of time a child can run before it expires (0 = turn off) */
4691 -+
4692 -+#ifndef DEFAULT_EXPIRE_TIMEOUT
4693 -+#define DEFAULT_EXPIRE_TIMEOUT 1800
4694 -+#endif
4695 -+
4696 -+/* Amount of time a child can stay idle (0 = turn off) */
4697 -+
4698 -+#ifndef DEFAULT_IDLE_TIMEOUT
4699 -+#define DEFAULT_IDLE_TIMEOUT 900
4700 -+#endif
4701 -+
4702 -+/* Amount of time a multiplexer can stay idle (0 = turn off) */
4703 -+
4704 -+#ifndef DEFAULT_MULTIPLEXER_IDLE_TIMEOUT
4705 -+#define DEFAULT_MULTIPLEXER_IDLE_TIMEOUT 0
4706 -+#endif
4707 -+
4708 -+/* Amount of maximum time a multiplexer can wait for processor if it is busy (0 = never wait)
4709 -+ * This is decreased with every busy request
4710 -+ */
4711 -+
4712 -+#ifndef DEFAULT_PROCESSOR_WAIT_TIMEOUT
4713 -+#define DEFAULT_PROCESSOR_WAIT_TIMEOUT 5
4714 -+#endif
4715 -+
4716 -+/* The number of different levels there are when a multiplexer is waiting for processor
4717 -+ * (between maximum waiting time and no waiting)
4718 -+ */
4719 -+
4720 -+#ifndef DEFAULT_PROCESSOR_WAIT_STEPS
4721 -+#define DEFAULT_PROCESSOR_WAIT_STEPS 10
4722 -+#endif
4723 -+
4724 -+#endif /* AP_MPM_DEFAULT_H */
4725 -diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/mpm.h httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm.h
4726 ---- httpd-2.2.13/server/mpm/experimental/peruser/mpm.h 1970-01-01 03:00:00.000000000 +0300
4727 -+++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/mpm.h 2009-09-01 16:19:22.000000000 +0300
4728 -@@ -0,0 +1,104 @@
4729 -+/* ====================================================================
4730 -+ * The Apache Software License, Version 1.1
4731 -+ *
4732 -+ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
4733 -+ * reserved.
4734 -+ *
4735 -+ * Redistribution and use in source and binary forms, with or without
4736 -+ * modification, are permitted provided that the following conditions
4737 -+ * are met:
4738 -+ *
4739 -+ * 1. Redistributions of source code must retain the above copyright
4740 -+ * notice, this list of conditions and the following disclaimer.
4741 -+ *
4742 -+ * 2. Redistributions in binary form must reproduce the above copyright
4743 -+ * notice, this list of conditions and the following disclaimer in
4744 -+ * the documentation and/or other materials provided with the
4745 -+ * distribution.
4746 -+ *
4747 -+ * 3. The end-user documentation included with the redistribution,
4748 -+ * if any, must include the following acknowledgment:
4749 -+ * "This product includes software developed by the
4750 -+ * Apache Software Foundation (http://www.apache.org/)."
4751 -+ * Alternately, this acknowledgment may appear in the software itself,
4752 -+ * if and wherever such third-party acknowledgments normally appear.
4753 -+ *
4754 -+ * 4. The names "Apache" and "Apache Software Foundation" must
4755 -+ * not be used to endorse or promote products derived from this
4756 -+ * software without prior written permission. For written
4757 -+ * permission, please contact apache@××××××.org.
4758 -+ *
4759 -+ * 5. Products derived from this software may not be called "Apache",
4760 -+ * nor may "Apache" appear in their name, without prior written
4761 -+ * permission of the Apache Software Foundation.
4762 -+ *
4763 -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
4764 -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4765 -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4766 -+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
4767 -+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4768 -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4769 -+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
4770 -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4771 -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
4772 -+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
4773 -+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4774 -+ * SUCH DAMAGE.
4775 -+ * ====================================================================
4776 -+ *
4777 -+ * This software consists of voluntary contributions made by many
4778 -+ * individuals on behalf of the Apache Software Foundation. For more
4779 -+ * information on the Apache Software Foundation, please see
4780 -+ * <http://www.apache.org/>.
4781 -+ *
4782 -+ * Portions of this software are based upon public domain software
4783 -+ * originally written at the National Center for Supercomputing Applications,
4784 -+ * University of Illinois, Urbana-Champaign.
4785 -+ */
4786 -+
4787 -+#include "httpd.h"
4788 -+#include "mpm_default.h"
4789 -+#include "scoreboard.h"
4790 -+#include "unixd.h"
4791 -+
4792 -+#ifndef APACHE_MPM_PERUSER_H
4793 -+#define APACHE_MPM_PERUSER_H
4794 -+
4795 -+#define PERUSER_MPM
4796 -+
4797 -+#define MPM_NAME "Peruser"
4798 -+
4799 -+#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
4800 -+#define AP_MPM_WANT_WAIT_OR_TIMEOUT
4801 -+#define AP_MPM_WANT_PROCESS_CHILD_STATUS
4802 -+#define AP_MPM_WANT_SET_PIDFILE
4803 -+#define AP_MPM_WANT_SET_SCOREBOARD
4804 -+#define AP_MPM_WANT_SET_LOCKFILE
4805 -+#define AP_MPM_WANT_SET_MAX_REQUESTS
4806 -+#define AP_MPM_WANT_SET_COREDUMPDIR
4807 -+#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
4808 -+#define AP_MPM_WANT_SIGNAL_SERVER
4809 -+#define AP_MPM_WANT_SET_MAX_MEM_FREE
4810 -+#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
4811 -+
4812 -+#define AP_MPM_USES_POD 1
4813 -+#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
4814 -+#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
4815 -+#define MPM_VALID_PID(p) (getpgid(p) == getpgrp())
4816 -+#define MPM_ACCEPT_FUNC unixd_accept
4817 -+
4818 -+extern int ap_threads_per_child;
4819 -+extern int ap_max_daemons_limit;
4820 -+extern server_rec *ap_server_conf;
4821 -+
4822 -+/* Table of child status */
4823 -+#define SERVER_DEAD 0
4824 -+#define SERVER_DYING 1
4825 -+#define SERVER_ALIVE 2
4826 -+
4827 -+typedef struct ap_ctable {
4828 -+ pid_t pid;
4829 -+ unsigned char status;
4830 -+} ap_ctable;
4831 -+
4832 -+#endif /* APACHE_MPM_PERUSER_H */
4833 -diff -Nur httpd-2.2.13/server/mpm/experimental/peruser/peruser.c httpd-2.2.13-peruser/server/mpm/experimental/peruser/peruser.c
4834 ---- httpd-2.2.13/server/mpm/experimental/peruser/peruser.c 1970-01-01 03:00:00.000000000 +0300
4835 -+++ httpd-2.2.13-peruser/server/mpm/experimental/peruser/peruser.c 2009-09-10 11:52:39.000000000 +0300
4836 -@@ -0,0 +1,3884 @@
4837 -+
4838 -+/* ====================================================================
4839 -+ * The Apache Software License, Version 1.1
4840 -+ *
4841 -+ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
4842 -+ * reserved.
4843 -+ *
4844 -+ * Redistribution and use in source and binary forms, with or without
4845 -+ * modification, are permitted provided that the following conditions
4846 -+ * are met:
4847 -+ *
4848 -+ * 1. Redistributions of source code must retain the above copyright
4849 -+ * notice, this list of conditions and the following disclaimer.
4850 -+ *
4851 -+ * 2. Redistributions in binary form must reproduce the above copyright
4852 -+ * notice, this list of conditions and the following disclaimer in
4853 -+ * the documentation and/or other materials provided with the
4854 -+ * distribution.
4855 -+ *
4856 -+ * 3. The end-user documentation included with the redistribution,
4857 -+ * if any, must include the following acknowledgment:
4858 -+ * "This product includes software developed by the
4859 -+ * Apache Software Foundation (http://www.apache.org/)."
4860 -+ * Alternately, this acknowledgment may appear in the software itself,
4861 -+ * if and wherever such third-party acknowledgments normally appear.
4862 -+ *
4863 -+ * 4. The names "Apache" and "Apache Software Foundation" must
4864 -+ * not be used to endorse or promote products derived from this
4865 -+ * software without prior written permission. For written
4866 -+ * permission, please contact apache@××××××.org.
4867 -+ *
4868 -+ * 5. Products derived from this software may not be called "Apache",
4869 -+ * nor may "Apache" appear in their name, without prior written
4870 -+ * permission of the Apache Software Foundation.
4871 -+ *
4872 -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
4873 -+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4874 -+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4875 -+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
4876 -+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4877 -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
4878 -+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
4879 -+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4880 -+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
4881 -+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
4882 -+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4883 -+ * SUCH DAMAGE.
4884 -+ * ====================================================================
4885 -+ *
4886 -+ * This software consists of voluntary contributions made by many
4887 -+ * individuals on behalf of the Apache Software Foundation. For more
4888 -+ * information on the Apache Software Foundation, please see
4889 -+ * <http://www.apache.org/>.
4890 -+ *
4891 -+ * Portions of this software are based upon public domain software
4892 -+ * originally written at the National Center for Supercomputing Applications,
4893 -+ * University of Illinois, Urbana-Champaign.
4894 -+ */
4895 -+
4896 -+/* Peruser version 0.4.0 */
4897 -+
4898 -+/* #define MPM_PERUSER_DEBUG */
4899 -+
4900 -+#include "apr.h"
4901 -+#include "apr_hash.h"
4902 -+#include "apr_pools.h"
4903 -+#include "apr_file_io.h"
4904 -+#include "apr_portable.h"
4905 -+#include "apr_strings.h"
4906 -+#include "apr_thread_proc.h"
4907 -+#include "apr_signal.h"
4908 -+#define APR_WANT_STDIO
4909 -+#define APR_WANT_STRFUNC
4910 -+#define APR_WANT_IOVEC
4911 -+#include "apr_want.h"
4912 -+
4913 -+#if APR_HAVE_UNISTD_H
4914 -+#include <unistd.h>
4915 -+#endif
4916 -+#if APR_HAVE_SYS_TYPES_H
4917 -+#include <sys/types.h>
4918 -+#endif
4919 -+
4920 -+#define CORE_PRIVATE
4921 -+
4922 -+#include "ap_config.h"
4923 -+#include "httpd.h"
4924 -+#include "mpm_default.h"
4925 -+#include "http_main.h"
4926 -+#include "http_log.h"
4927 -+#include "http_config.h"
4928 -+#include "http_core.h" /* for get_remote_host */
4929 -+#include "http_connection.h"
4930 -+#include "http_protocol.h" /* for ap_hook_post_read_request */
4931 -+#include "http_vhost.h" /* for ap_update_vhost_given_ip */
4932 -+#include "scoreboard.h"
4933 -+#include "ap_mpm.h"
4934 -+#include "unixd.h"
4935 -+#include "mpm_common.h"
4936 -+#include "ap_listen.h"
4937 -+#include "ap_mmn.h"
4938 -+#include "apr_poll.h"
4939 -+#include "util_ebcdic.h"
4940 -+#include "mod_status.h"
4941 -+
4942 -+#ifdef HAVE_BSTRING_H
4943 -+#include <bstring.h> /* for IRIX, FD_SET calls bzero() */
4944 -+#endif
4945 -+
4946 -+#ifdef HAVE_TIME_H
4947 -+#include <time.h>
4948 -+#endif
4949 -+
4950 -+#ifdef HAVE_SYS_PROCESSOR_H
4951 -+#include <sys/processor.h> /* for bindprocessor() */
4952 -+#endif
4953 -+
4954 -+#if APR_HAS_SHARED_MEMORY
4955 -+#include "apr_shm.h"
4956 -+#else
4957 -+#error "Peruser MPM requres shared memory support."
4958 -+#endif
4959 -+
4960 -+
4961 -+/* should be APR-ized */
4962 -+#include <grp.h>
4963 -+#include <pwd.h>
4964 -+#include <sys/stat.h>
4965 -+#include <sys/un.h>
4966 -+#include <setjmp.h>
4967 -+
4968 -+#include <signal.h>
4969 -+#include <sys/times.h>
4970 -+
4971 -+
4972 -+#ifdef MPM_PERUSER_DEBUG
4973 -+# define _DBG(text,par...) \
4974 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \
4975 -+ "(peruser: pid=%d uid=%d child=%d) %s(): " text, \
4976 -+ getpid(), getuid(), my_child_num, __FUNCTION__, ##par, 0)
4977 -+
4978 -+# define _TRACE_CALL(text,par...) _DBG("calling " text, ##par)
4979 -+# define _TRACE_RET(text,par...) _DBG("returned from " text, ##par)
4980 -+#else
4981 -+# define _DBG(text,par...)
4982 -+# define _TRACE_RET(text,par...)
4983 -+# define _TRACE_CALL(text,par...)
4984 -+#endif /* MPM_PERUSER_DEBUG */
4985 -+
4986 -+/* char of death - for signalling children to die */
4987 -+#define AP_PERUSER_CHAR_OF_DEATH '!'
4988 -+
4989 -+#define PERUSER_SERVER_CONF(cf) \
4990 -+ ((peruser_server_conf *) ap_get_module_config(cf, &mpm_peruser_module))
4991 -+
4992 -+#define SCOREBOARD_STATUS(i) ap_scoreboard_image->servers[i][0].status
4993 -+
4994 -+/*
4995 -+ * Define some magic numbers that we use for the state of the incomming
4996 -+ * request. These must be < 0 so they don't collide with a file descriptor.
4997 -+ */
4998 -+#define AP_PERUSER_THISCHILD -1
4999 -+#define AP_PERUSER_OTHERCHILD -2
5000 -+
5001 -+
5002 -+/* Limit on the total --- clients will be locked out if more servers than
5003 -+ * this are needed. It is intended solely to keep the server from crashing
5004 -+ * when things get out of hand.
5005 -+ *
5006 -+ * We keep a hard maximum number of servers, for two reasons --- first off,
5007 -+ * in case something goes seriously wrong, we want to stop the fork bomb
5008 -+ * short of actually crashing the machine we're running on by filling some
5009 -+ * kernel table. Secondly, it keeps the size of the scoreboard file small
5010 -+ * enough that we can read the whole thing without worrying too much about
5011 -+ * the overhead.
5012 -+ */
5013 -+#ifndef DEFAULT_SERVER_LIMIT
5014 -+#define DEFAULT_SERVER_LIMIT 256
5015 -+#endif
5016 -+
5017 -+/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
5018 -+ * some sort of compile-time limit to help catch typos.
5019 -+ */
5020 -+#ifndef MAX_SERVER_LIMIT
5021 -+#define MAX_SERVER_LIMIT 20000
5022 -+#endif
5023 -+
5024 -+#ifndef HARD_THREAD_LIMIT
5025 -+#define HARD_THREAD_LIMIT 1
5026 -+#endif
5027 -+
5028 -+#define CHILD_TYPE_UNKNOWN 0
5029 -+#define CHILD_TYPE_MULTIPLEXER 1
5030 -+#define CHILD_TYPE_PROCESSOR 2
5031 -+#define CHILD_TYPE_WORKER 3
5032 -+
5033 -+#define CHILD_STATUS_STANDBY 0 /* wait for a request before starting */
5034 -+#define CHILD_STATUS_STARTING 1 /* wait for socket creation */
5035 -+#define CHILD_STATUS_READY 2 /* is ready to take requests */
5036 -+#define CHILD_STATUS_ACTIVE 3 /* is currently busy handling requests */
5037 -+#define CHILD_STATUS_RESTART 4 /* child about to die and restart */
5038 -+
5039 -+/* cgroup settings */
5040 -+#define CGROUP_TASKS_FILE "/tasks"
5041 -+#define CGROUP_TASKS_FILE_LEN 7
5042 -+
5043 -+/* config globals */
5044 -+
5045 -+int ap_threads_per_child=0; /* Worker threads per child */
5046 -+static apr_proc_mutex_t *accept_mutex;
5047 -+static int ap_min_processors=DEFAULT_MIN_PROCESSORS;
5048 -+static int ap_min_free_processors=DEFAULT_MIN_FREE_PROCESSORS;
5049 -+static int ap_max_free_processors=DEFAULT_MAX_FREE_PROCESSORS;
5050 -+static int ap_max_processors=DEFAULT_MAX_PROCESSORS;
5051 -+static int ap_min_multiplexers=DEFAULT_MIN_MULTIPLEXERS;
5052 -+static int ap_max_multiplexers=DEFAULT_MAX_MULTIPLEXERS;
5053 -+static int ap_daemons_limit=0; /* MaxClients */
5054 -+static int expire_timeout=DEFAULT_EXPIRE_TIMEOUT;
5055 -+static int idle_timeout=DEFAULT_IDLE_TIMEOUT;
5056 -+static int multiplexer_idle_timeout=DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
5057 -+static int processor_wait_timeout=DEFAULT_PROCESSOR_WAIT_TIMEOUT;
5058 -+static int processor_wait_steps=DEFAULT_PROCESSOR_WAIT_STEPS;
5059 -+static int server_limit = DEFAULT_SERVER_LIMIT;
5060 -+static int first_server_limit;
5061 -+static int changed_limit_at_restart;
5062 -+static int requests_this_child;
5063 -+static int mpm_state = AP_MPMQ_STARTING;
5064 -+static ap_pod_t *pod;
5065 -+
5066 -+/* === configuration stuff === */
5067 -+
5068 -+typedef struct
5069 -+{
5070 -+ int processor_id;
5071 -+
5072 -+ const char *name; /* Server environment's unique string identifier */
5073 -+
5074 -+ /* security settings */
5075 -+ uid_t uid; /* user id */
5076 -+ gid_t gid; /* group id */
5077 -+ const char *chroot; /* directory to chroot() to, can be null */
5078 -+ short nice_lvl;
5079 -+ const char *cgroup; /* cgroup directory, can be null */
5080 -+
5081 -+ /* resource settings */
5082 -+ int min_processors;
5083 -+ int min_free_processors;
5084 -+ int max_free_processors;
5085 -+ int max_processors;
5086 -+ short availability;
5087 -+
5088 -+ /* sockets */
5089 -+ int input; /* The socket descriptor */
5090 -+ int output; /* The socket descriptor */
5091 -+
5092 -+ /* error flags */
5093 -+ /* we use these to reduce log clutter (report only on first failure) */
5094 -+ short error_cgroup; /* When writing pid to cgroup fails */
5095 -+ short error_pass; /* When unable to pass request to the processor (eg all workers busy) */
5096 -+} server_env_t;
5097 -+
5098 -+typedef struct
5099 -+{
5100 -+ apr_size_t num;
5101 -+} server_env_control;
5102 -+
5103 -+typedef struct
5104 -+{
5105 -+ server_env_control *control;
5106 -+ server_env_t *table;
5107 -+} server_env;
5108 -+
5109 -+
5110 -+typedef struct
5111 -+{
5112 -+ /* identification */
5113 -+ int id; /* index in child_info_table */
5114 -+ pid_t pid; /* process id */
5115 -+ int status; /* status of child */
5116 -+ int type; /* multiplexer or processor */
5117 -+ server_env_t *senv;
5118 -+
5119 -+ /* sockets */
5120 -+ int sock_fd;
5121 -+
5122 -+ /* stack context saved state */
5123 -+ jmp_buf jmpbuffer;
5124 -+} child_info_t;
5125 -+
5126 -+typedef struct
5127 -+{
5128 -+ /* identification */
5129 -+ int id; /* index in child_info_table */
5130 -+ pid_t pid; /* process id */
5131 -+ int status; /* status of child */
5132 -+ int type; /* multiplexer or processor */
5133 -+ apr_time_t last_used;
5134 -+} child_grace_info_t;
5135 -+
5136 -+typedef struct
5137 -+{
5138 -+ apr_size_t num;
5139 -+} child_info_control;
5140 -+
5141 -+typedef struct
5142 -+{
5143 -+ child_info_control *control;
5144 -+ child_info_t *table;
5145 -+} child_info;
5146 -+
5147 -+typedef struct
5148 -+{
5149 -+ server_env_t *senv;
5150 -+ short missing_senv_reported;
5151 -+} peruser_server_conf;
5152 -+
5153 -+
5154 -+typedef struct peruser_header
5155 -+{
5156 -+ char *headers;
5157 -+ apr_pool_t *p;
5158 -+} peruser_header;
5159 -+
5160 -+
5161 -+/* Tables used to determine the user and group each child process should
5162 -+ * run as. The hash table is used to correlate a server name with a child
5163 -+ * process.
5164 -+ */
5165 -+static apr_size_t child_info_size;
5166 -+static child_info *child_info_image = NULL;
5167 -+static child_grace_info_t *child_grace_info_table;
5168 -+struct ap_ctable *ap_child_table;
5169 -+
5170 -+#define NUM_CHILDS (child_info_image != NULL ? child_info_image->control->num : 0)
5171 -+#define CHILD_INFO_TABLE (child_info_image != NULL ? child_info_image->table : NULL)
5172 -+
5173 -+static apr_size_t server_env_size;
5174 -+static server_env *server_env_image = NULL;
5175 -+
5176 -+#define NUM_SENV (server_env_image != NULL ? server_env_image->control->num : 0)
5177 -+#define SENV (server_env_image != NULL ? server_env_image->table : NULL)
5178 -+
5179 -+#if APR_HAS_SHARED_MEMORY
5180 -+#ifndef WIN32
5181 -+static /* but must be exported to mpm_winnt */
5182 -+#endif
5183 -+ apr_shm_t *child_info_shm = NULL;
5184 -+ apr_shm_t *server_env_shm = NULL;
5185 -+#endif
5186 -+
5187 -+/*
5188 -+ * The max child slot ever assigned, preserved across restarts. Necessary
5189 -+ * to deal with MaxClients changes across AP_SIG_GRACEFUL restarts. We
5190 -+ * use this value to optimize routines that have to scan the entire scoreboard.
5191 -+ */
5192 -+int ap_max_daemons_limit = -1;
5193 -+server_rec *ap_server_conf;
5194 -+
5195 -+module AP_MODULE_DECLARE_DATA mpm_peruser_module;
5196 -+
5197 -+/* -- replace the pipe-of-death by an control socket -- */
5198 -+static apr_file_t *pipe_of_death_in = NULL;
5199 -+static apr_file_t *pipe_of_death_out = NULL;
5200 -+
5201 -+
5202 -+/* one_process --- debugging mode variable; can be set from the command line
5203 -+ * with the -X flag. If set, this gets you the child_main loop running
5204 -+ * in the process which originally started up (no detach, no make_child),
5205 -+ * which is a pretty nice debugging environment. (You'll get a SIGHUP
5206 -+ * early in standalone_main; just continue through. This is the server
5207 -+ * trying to kill off any child processes which it might have lying
5208 -+ * around --- Apache doesn't keep track of their pids, it just sends
5209 -+ * SIGHUP to the process group, ignoring it in the root process.
5210 -+ * Continue through and you'll be fine.).
5211 -+ */
5212 -+
5213 -+static int one_process = 0;
5214 -+
5215 -+static apr_pool_t *pconf; /* Pool for config stuff */
5216 -+static apr_pool_t *pchild; /* Pool for httpd child stuff */
5217 -+
5218 -+static pid_t ap_my_pid; /* it seems silly to call getpid all the time */
5219 -+static pid_t parent_pid;
5220 -+static int my_child_num;
5221 -+ap_generation_t volatile ap_my_generation=0;
5222 -+
5223 -+#ifdef TPF
5224 -+int tpf_child = 0;
5225 -+char tpf_server_name[INETD_SERVNAME_LENGTH+1];
5226 -+#endif /* TPF */
5227 -+
5228 -+static int die_now = 0;
5229 -+
5230 -+int grace_children = 0;
5231 -+int grace_children_alive = 0;
5232 -+int server_env_cleanup = 1;
5233 -+const char *multiplexer_chroot = NULL;
5234 -+
5235 -+// function added to mod_ssl and exported (there was nothing useful for us in the current api)
5236 -+typedef int (*ssl_server_is_https_t)(server_rec*);
5237 -+ssl_server_is_https_t ssl_server_is_https = NULL;
5238 -+
5239 -+#ifdef GPROF
5240 -+/*
5241 -+ * change directory for gprof to plop the gmon.out file
5242 -+ * configure in httpd.conf:
5243 -+ * GprofDir $RuntimeDir/ -> $ServerRoot/$RuntimeDir/gmon.out
5244 -+ * GprofDir $RuntimeDir/% -> $ServerRoot/$RuntimeDir/gprof.$pid/gmon.out
5245 -+ */
5246 -+static void chdir_for_gprof(void)
5247 -+{
5248 -+ core_server_config *sconf =
5249 -+ ap_get_module_config(ap_server_conf->module_config, &core_module);
5250 -+ char *dir = sconf->gprof_dir;
5251 -+ const char *use_dir;
5252 -+
5253 -+ if(dir) {
5254 -+ apr_status_t res;
5255 -+ char buf[512];
5256 -+ int len = strlen(sconf->gprof_dir) - 1;
5257 -+ if(*(dir + len) == '%') {
5258 -+ dir[len] = '\0';
5259 -+ apr_snprintf(buf, sizeof(buf), "%sgprof.%d", dir, (int)getpid());
5260 -+ }
5261 -+ use_dir = ap_server_root_relative(pconf, buf[0] ? buf : dir);
5262 -+ res = apr_dir_make(use_dir, 0755, pconf);
5263 -+ if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) {
5264 -+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf,
5265 -+ "gprof: error creating directory %s", dir);
5266 -+ }
5267 -+ }
5268 -+ else {
5269 -+ use_dir = ap_server_root_relative(pconf, DEFAULT_REL_RUNTIMEDIR);
5270 -+ }
5271 -+
5272 -+ chdir(use_dir);
5273 -+}
5274 -+#else
5275 -+#define chdir_for_gprof()
5276 -+#endif
5277 -+
5278 -+char* child_type_string(int type)
5279 -+{
5280 -+ switch(type)
5281 -+ {
5282 -+ case CHILD_TYPE_MULTIPLEXER: return "MULTIPLEXER";
5283 -+ case CHILD_TYPE_PROCESSOR: return "PROCESSOR";
5284 -+ case CHILD_TYPE_WORKER: return "WORKER";
5285 -+ }
5286 -+
5287 -+ return "UNKNOWN";
5288 -+}
5289 -+
5290 -+char* child_status_string(int status)
5291 -+{
5292 -+ switch(status)
5293 -+ {
5294 -+ case CHILD_STATUS_STANDBY: return "STANDBY";
5295 -+ case CHILD_STATUS_STARTING: return "STARTING";
5296 -+ case CHILD_STATUS_READY: return "READY";
5297 -+ case CHILD_STATUS_ACTIVE: return "ACTIVE";
5298 -+ case CHILD_STATUS_RESTART: return "RESTART";
5299 -+ }
5300 -+
5301 -+ return "UNKNOWN";
5302 -+}
5303 -+
5304 -+char* scoreboard_status_string(int status) {
5305 -+ switch(status)
5306 -+ {
5307 -+ case SERVER_DEAD: return "DEAD";
5308 -+ case SERVER_STARTING: return "STARTING";
5309 -+ case SERVER_READY: return "READY";
5310 -+ case SERVER_BUSY_READ: return "BUSY_READ";
5311 -+ case SERVER_BUSY_WRITE: return "BUSY_WRITE";
5312 -+ case SERVER_BUSY_KEEPALIVE: return "BUSY_KEEPALIVE";
5313 -+ case SERVER_BUSY_LOG: return "BUSY_LOG";
5314 -+ case SERVER_BUSY_DNS: return "BUSY_DNS";
5315 -+ case SERVER_CLOSING: return "CLOSING";
5316 -+ case SERVER_GRACEFUL: return "GRACEFUL";
5317 -+ case SERVER_NUM_STATUS: return "NUM_STATUS";
5318 -+ }
5319 -+
5320 -+ return "UNKNOWN";
5321 -+}
5322 -+
5323 -+void dump_child_table()
5324 -+{
5325 -+#ifdef MPM_PERUSER_DEBUG
5326 -+ int x;
5327 -+ server_env_t *senv;
5328 -+
5329 -+ _DBG("%-3s %-5s %-8s %-12s %-4s %-4s %-25s %5s %6s %7s",
5330 -+ "ID", "PID", "STATUS", "TYPE", "UID", "GID", "CHROOT", "INPUT", "OUTPUT", "SOCK_FD");
5331 -+
5332 -+ for(x = 0; x < NUM_CHILDS; x++)
5333 -+ {
5334 -+ senv = CHILD_INFO_TABLE[x].senv;
5335 -+ _DBG("%-3d %-5d %-8s %-12s %-4d %-4d %-25s %-5d %-6d %-7d",
5336 -+ CHILD_INFO_TABLE[x].id,
5337 -+ CHILD_INFO_TABLE[x].pid,
5338 -+ child_status_string(CHILD_INFO_TABLE[x].status),
5339 -+ child_type_string(CHILD_INFO_TABLE[x].type),
5340 -+ senv == NULL ? -1 : senv->uid,
5341 -+ senv == NULL ? -1 : senv->gid,
5342 -+ senv == NULL ? NULL : senv->chroot,
5343 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input,
5344 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output,
5345 -+ CHILD_INFO_TABLE[x].sock_fd);
5346 -+ }
5347 -+#endif
5348 -+}
5349 -+
5350 -+void dump_server_env_image()
5351 -+{
5352 -+#ifdef MPM_PERUSER_DEBUG
5353 -+ int x;
5354 -+ _DBG("%-3s %-7s %-7s %-7s", "N", "INPUT", "OUTPUT", "CHROOT");
5355 -+ for(x = 0; x < NUM_SENV; x++)
5356 -+ {
5357 -+ _DBG("%-3d %-7d %-7d %-7s", x, SENV[x].input, SENV[x].output, SENV[x].chroot);
5358 -+ }
5359 -+#endif
5360 -+}
5361 -+
5362 -+
5363 -+/* XXX - I don't know if TPF will ever use this module or not, so leave
5364 -+ * the ap_check_signals calls in but disable them - manoj */
5365 -+#define ap_check_signals()
5366 -+
5367 -+/* a clean exit from a child with proper cleanup */
5368 -+static inline int clean_child_exit(int code) __attribute__ ((noreturn));
5369 -+static inline int clean_child_exit(int code)
5370 -+{
5371 -+ int retval;
5372 -+
5373 -+ mpm_state = AP_MPMQ_STOPPING;
5374 -+
5375 -+ if (CHILD_INFO_TABLE[my_child_num].type != CHILD_TYPE_MULTIPLEXER &&
5376 -+ CHILD_INFO_TABLE[my_child_num].senv)
5377 -+ {
5378 -+ retval = close(CHILD_INFO_TABLE[my_child_num].senv->input);
5379 -+ _DBG("close(CHILD_INFO_TABLE[%d].senv->input) = %d",
5380 -+ my_child_num, retval);
5381 -+
5382 -+ retval = close(CHILD_INFO_TABLE[my_child_num].senv->output);
5383 -+ _DBG("close(CHILD_INFO_TABLE[%d].senv->output) = %d",
5384 -+ my_child_num, retval);
5385 -+ }
5386 -+
5387 -+ if (pchild) {
5388 -+ apr_pool_destroy(pchild);
5389 -+ }
5390 -+ ap_mpm_pod_close(pod);
5391 -+ chdir_for_gprof();
5392 -+ exit(code);
5393 -+}
5394 -+
5395 -+static void accept_mutex_on(void)
5396 -+{
5397 -+ apr_status_t rv = apr_proc_mutex_lock(accept_mutex);
5398 -+ if (rv != APR_SUCCESS) {
5399 -+ const char *msg = "couldn't grab the accept mutex";
5400 -+
5401 -+ if (ap_my_generation !=
5402 -+ ap_scoreboard_image->global->running_generation) {
5403 -+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg);
5404 -+ clean_child_exit(0);
5405 -+ }
5406 -+ else {
5407 -+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg);
5408 -+ exit(APEXIT_CHILDFATAL);
5409 -+ }
5410 -+ }
5411 -+}
5412 -+
5413 -+static void accept_mutex_off(void)
5414 -+{
5415 -+ apr_status_t rv = apr_proc_mutex_unlock(accept_mutex);
5416 -+ if (rv != APR_SUCCESS) {
5417 -+ const char *msg = "couldn't release the accept mutex";
5418 -+
5419 -+ if (ap_my_generation !=
5420 -+ ap_scoreboard_image->global->running_generation) {
5421 -+ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, NULL, msg);
5422 -+ /* don't exit here... we have a connection to
5423 -+ * process, after which point we'll see that the
5424 -+ * generation changed and we'll exit cleanly
5425 -+ */
5426 -+ }
5427 -+ else {
5428 -+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, NULL, msg);
5429 -+ exit(APEXIT_CHILDFATAL);
5430 -+ }
5431 -+ }
5432 -+}
5433 -+
5434 -+/* On some architectures it's safe to do unserialized accept()s in the single
5435 -+ * Listen case. But it's never safe to do it in the case where there's
5436 -+ * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
5437 -+ * when it's safe in the single Listen case.
5438 -+ */
5439 -+#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT
5440 -+#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0)
5441 -+#else
5442 -+#define SAFE_ACCEPT(stmt) do {stmt;} while(0)
5443 -+#endif
5444 -+
5445 -+AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
5446 -+{
5447 -+ switch(query_code){
5448 -+ case AP_MPMQ_MAX_DAEMON_USED:
5449 -+ *result = ap_daemons_limit;
5450 -+ return APR_SUCCESS;
5451 -+ case AP_MPMQ_IS_THREADED:
5452 -+ *result = AP_MPMQ_NOT_SUPPORTED;
5453 -+ return APR_SUCCESS;
5454 -+ case AP_MPMQ_IS_FORKED:
5455 -+ *result = AP_MPMQ_DYNAMIC;
5456 -+ return APR_SUCCESS;
5457 -+ case AP_MPMQ_HARD_LIMIT_DAEMONS:
5458 -+ *result = server_limit;
5459 -+ return APR_SUCCESS;
5460 -+ case AP_MPMQ_HARD_LIMIT_THREADS:
5461 -+ *result = HARD_THREAD_LIMIT;
5462 -+ return APR_SUCCESS;
5463 -+ case AP_MPMQ_MAX_THREADS:
5464 -+ *result = 0;
5465 -+ return APR_SUCCESS;
5466 -+ case AP_MPMQ_MIN_SPARE_DAEMONS:
5467 -+ *result = ap_min_free_processors;
5468 -+ return APR_SUCCESS;
5469 -+ case AP_MPMQ_MIN_SPARE_THREADS:
5470 -+ *result = 0;
5471 -+ return APR_SUCCESS;
5472 -+ case AP_MPMQ_MAX_SPARE_THREADS:
5473 -+ *result = 0;
5474 -+ return APR_SUCCESS;
5475 -+ case AP_MPMQ_MAX_REQUESTS_DAEMON:
5476 -+ *result = ap_max_requests_per_child;
5477 -+ return APR_SUCCESS;
5478 -+ case AP_MPMQ_MAX_DAEMONS:
5479 -+ *result = server_limit;
5480 -+ return APR_SUCCESS;
5481 -+ case AP_MPMQ_MPM_STATE:
5482 -+ *result = mpm_state;
5483 -+ return APR_SUCCESS;
5484 -+ }
5485 -+ return APR_ENOTIMPL;
5486 -+}
5487 -+
5488 -+#if defined(NEED_WAITPID)
5489 -+/*
5490 -+ Systems without a real waitpid sometimes lose a child's exit while waiting
5491 -+ for another. Search through the scoreboard for missing children.
5492 -+ */
5493 -+int reap_children(int *exitcode, apr_exit_why_e *status)
5494 -+{
5495 -+ int n, pid;
5496 -+
5497 -+ for (n = 0; n < ap_max_daemons_limit; ++n) {
5498 -+ if (ap_scoreboard_image->servers[n][0].status != SERVER_DEAD &&
5499 -+ kill((pid = ap_scoreboard_image->parent[n].pid), 0) == -1) {
5500 -+ ap_update_child_status_from_indexes(n, 0, SERVER_DEAD, NULL);
5501 -+ /* just mark it as having a successful exit status */
5502 -+ *status = APR_PROC_EXIT;
5503 -+ *exitcode = 0;
5504 -+ return(pid);
5505 -+ }
5506 -+ }
5507 -+ return 0;
5508 -+}
5509 -+#endif
5510 -+
5511 -+/* handle all varieties of core dumping signals */
5512 -+static void sig_coredump(int sig)
5513 -+{
5514 -+ int retval;
5515 -+ retval = chdir(ap_coredump_dir);
5516 -+ apr_signal(sig, SIG_DFL);
5517 -+ if (ap_my_pid == parent_pid) {
5518 -+ ap_log_error(APLOG_MARK, APLOG_NOTICE,
5519 -+ 0, ap_server_conf,
5520 -+ "seg fault or similar nasty error detected "
5521 -+ "in the parent process");
5522 -+ }
5523 -+ kill(getpid(), sig);
5524 -+ /* At this point we've got sig blocked, because we're still inside
5525 -+ * the signal handler. When we leave the signal handler it will
5526 -+ * be unblocked, and we'll take the signal... and coredump or whatever
5527 -+ * is appropriate for this particular Unix. In addition the parent
5528 -+ * will see the real signal we received -- whereas if we called
5529 -+ * abort() here, the parent would only see SIGABRT.
5530 -+ */
5531 -+}
5532 -+
5533 -+/*****************************************************************
5534 -+ * Connection structures and accounting...
5535 -+ */
5536 -+
5537 -+static void just_die(int sig)
5538 -+{
5539 -+_DBG("function called");
5540 -+ clean_child_exit(0);
5541 -+}
5542 -+
5543 -+/* volatile just in case */
5544 -+static int volatile shutdown_pending;
5545 -+static int volatile restart_pending;
5546 -+static int volatile is_graceful;
5547 -+/* XXX static int volatile child_fatal; */
5548 -+
5549 -+static void sig_term(int sig)
5550 -+{
5551 -+ if (shutdown_pending == 1) {
5552 -+ /* Um, is this _probably_ not an error, if the user has
5553 -+ * tried to do a shutdown twice quickly, so we won't
5554 -+ * worry about reporting it.
5555 -+ */
5556 -+ return;
5557 -+ }
5558 -+ shutdown_pending = 1;
5559 -+}
5560 -+
5561 -+/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL
5562 -+ * in the parent process, unless running in ONE_PROCESS mode
5563 -+ */
5564 -+static void restart(int sig)
5565 -+{
5566 -+ if (restart_pending == 1) {
5567 -+ /* Probably not an error - don't bother reporting it */
5568 -+ return;
5569 -+ }
5570 -+ restart_pending = 1;
5571 -+ is_graceful = (sig == AP_SIG_GRACEFUL);
5572 -+}
5573 -+
5574 -+/* Sets die_now if we received a character on the pipe_of_death */
5575 -+static apr_status_t check_pipe_of_death
5576 -+(
5577 -+ void **csd,
5578 -+ ap_listen_rec *lr,
5579 -+ apr_pool_t *ptrans
5580 -+)
5581 -+{
5582 -+ int ret;
5583 -+ char pipe_read_char;
5584 -+ apr_size_t n = 1;
5585 -+
5586 -+ _DBG("WATCH: die_now=%d", die_now);
5587 -+
5588 -+ if (die_now) return APR_SUCCESS;
5589 -+
5590 -+ /* apr_thread_mutex_lock(pipe_of_death_mutex); */
5591 -+ ret = apr_socket_recv(lr->sd, &pipe_read_char, &n);
5592 -+ if (APR_STATUS_IS_EAGAIN(ret))
5593 -+ {
5594 -+ /* It lost the lottery. It must continue to suffer
5595 -+ * through a life of servitude. */
5596 -+ _DBG("POD read EAGAIN");
5597 -+ return ret;
5598 -+ }
5599 -+ else
5600 -+ {
5601 -+ if (pipe_read_char != AP_PERUSER_CHAR_OF_DEATH)
5602 -+ {
5603 -+ _DBG("got wrong char %c", pipe_read_char);
5604 -+ return APR_SUCCESS;
5605 -+ }
5606 -+ /* It won the lottery (or something else is very
5607 -+ * wrong). Embrace death with open arms. */
5608 -+ die_now = 1;
5609 -+ _DBG("WATCH: die_now=%d", die_now);
5610 -+ }
5611 -+ /* apr_thread_mutex_unlock(pipe_of_death_mutex); */
5612 -+ return APR_SUCCESS;
5613 -+}
5614 -+
5615 -+static void set_signals(void)
5616 -+{
5617 -+#ifndef NO_USE_SIGACTION
5618 -+ struct sigaction sa;
5619 -+
5620 -+ sigemptyset(&sa.sa_mask);
5621 -+ sa.sa_flags = 0;
5622 -+
5623 -+ if (!one_process) {
5624 -+ sa.sa_handler = sig_coredump;
5625 -+#if defined(SA_ONESHOT)
5626 -+ sa.sa_flags = SA_ONESHOT;
5627 -+#elif defined(SA_RESETHAND)
5628 -+ sa.sa_flags = SA_RESETHAND;
5629 -+#endif
5630 -+ if (sigaction(SIGSEGV, &sa, NULL) < 0)
5631 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");
5632 -+#ifdef SIGBUS
5633 -+ if (sigaction(SIGBUS, &sa, NULL) < 0)
5634 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
5635 -+#endif
5636 -+#ifdef SIGABORT
5637 -+ if (sigaction(SIGABORT, &sa, NULL) < 0)
5638 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");
5639 -+#endif
5640 -+#ifdef SIGABRT
5641 -+ if (sigaction(SIGABRT, &sa, NULL) < 0)
5642 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
5643 -+#endif
5644 -+#ifdef SIGILL
5645 -+ if (sigaction(SIGILL, &sa, NULL) < 0)
5646 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)");
5647 -+#endif
5648 -+ sa.sa_flags = 0;
5649 -+ }
5650 -+ sa.sa_handler = sig_term;
5651 -+ if (sigaction(SIGTERM, &sa, NULL) < 0)
5652 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
5653 -+#ifdef SIGINT
5654 -+ if (sigaction(SIGINT, &sa, NULL) < 0)
5655 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
5656 -+#endif
5657 -+#ifdef SIGXCPU
5658 -+ sa.sa_handler = SIG_DFL;
5659 -+ if (sigaction(SIGXCPU, &sa, NULL) < 0)
5660 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXCPU)");
5661 -+#endif
5662 -+#ifdef SIGXFSZ
5663 -+ sa.sa_handler = SIG_IGN;
5664 -+ if (sigaction(SIGXFSZ, &sa, NULL) < 0)
5665 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGXFSZ)");
5666 -+#endif
5667 -+#ifdef SIGPIPE
5668 -+ sa.sa_handler = SIG_IGN;
5669 -+ if (sigaction(SIGPIPE, &sa, NULL) < 0)
5670 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGPIPE)");
5671 -+#endif
5672 -+
5673 -+ /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
5674 -+ * processing one */
5675 -+ sigaddset(&sa.sa_mask, SIGHUP);
5676 -+ sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
5677 -+ sa.sa_handler = restart;
5678 -+ if (sigaction(SIGHUP, &sa, NULL) < 0)
5679 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
5680 -+ if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
5681 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
5682 -+#else
5683 -+ if (!one_process) {
5684 -+ apr_signal(SIGSEGV, sig_coredump);
5685 -+#ifdef SIGBUS
5686 -+ apr_signal(SIGBUS, sig_coredump);
5687 -+#endif /* SIGBUS */
5688 -+#ifdef SIGABORT
5689 -+ apr_signal(SIGABORT, sig_coredump);
5690 -+#endif /* SIGABORT */
5691 -+#ifdef SIGABRT
5692 -+ apr_signal(SIGABRT, sig_coredump);
5693 -+#endif /* SIGABRT */
5694 -+#ifdef SIGILL
5695 -+ apr_signal(SIGILL, sig_coredump);
5696 -+#endif /* SIGILL */
5697 -+#ifdef SIGXCPU
5698 -+ apr_signal(SIGXCPU, SIG_DFL);
5699 -+#endif /* SIGXCPU */
5700 -+#ifdef SIGXFSZ
5701 -+ apr_signal(SIGXFSZ, SIG_DFL);
5702 -+#endif /* SIGXFSZ */
5703 -+ }
5704 -+
5705 -+ apr_signal(SIGTERM, sig_term);
5706 -+#ifdef SIGHUP
5707 -+ apr_signal(SIGHUP, restart);
5708 -+#endif /* SIGHUP */
5709 -+#ifdef AP_SIG_GRACEFUL
5710 -+ apr_signal(AP_SIG_GRACEFUL, restart);
5711 -+#endif /* AP_SIG_GRACEFUL */
5712 -+#ifdef SIGPIPE
5713 -+ apr_signal(SIGPIPE, SIG_IGN);
5714 -+#endif /* SIGPIPE */
5715 -+
5716 -+#endif
5717 -+}
5718 -+
5719 -+/*****************************************************************
5720 -+ * Child process main loop.
5721 -+ * The following vars are static to avoid getting clobbered by longjmp();
5722 -+ * they are really private to child_main.
5723 -+ */
5724 -+
5725 -+static int requests_this_child;
5726 -+static int num_listensocks = 0;
5727 -+static ap_listen_rec *listensocks;
5728 -+
5729 -+int ap_graceful_stop_signalled(void)
5730 -+{
5731 -+ /* not ever called anymore... */
5732 -+ return 0;
5733 -+}
5734 -+
5735 -+
5736 -+static int total_processors(int child_num)
5737 -+{
5738 -+ int i, total;
5739 -+
5740 -+ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
5741 -+ {
5742 -+ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv)
5743 -+ total++;
5744 -+ }
5745 -+
5746 -+ return total;
5747 -+}
5748 -+
5749 -+static int idle_processors(int child_num)
5750 -+{
5751 -+ int i, total;
5752 -+
5753 -+ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
5754 -+ {
5755 -+ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
5756 -+ (CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY))
5757 -+ {
5758 -+ total++;
5759 -+ }
5760 -+ }
5761 -+
5762 -+ return total;
5763 -+}
5764 -+
5765 -+static int wait_for_workers(child_info_t *processor) {
5766 -+ int i, wait_step_size, wait_time;
5767 -+
5768 -+ wait_step_size = 100 / processor_wait_steps;
5769 -+
5770 -+ /* Check if the processor is available */
5771 -+ if (total_processors(processor->id) == processor->senv->max_processors &&
5772 -+ idle_processors(processor->id) == 0 && processor_wait_timeout > 0) {
5773 -+ /* The processor is currently busy, try to wait (a little) */
5774 -+ _DBG("processor seems to be busy, trying to wait for it");
5775 -+
5776 -+ if (processor->senv->availability == 0) {
5777 -+ processor->senv->availability = 0;
5778 -+
5779 -+ _DBG("processor is very busy (availability = 0) - not passing request");
5780 -+
5781 -+ if (processor->senv->error_pass == 0) {
5782 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
5783 -+ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
5784 -+ }
5785 -+
5786 -+ /* No point in waiting for the processor, it's very busy */
5787 -+ return -1;
5788 -+ }
5789 -+
5790 -+ /* We sleep a little (depending how available the processor usually is) */
5791 -+ wait_time = (processor_wait_timeout / processor_wait_steps) * 1000000;
5792 -+
5793 -+ for(i = 0; i <= processor->senv->availability; i += wait_step_size) {
5794 -+ usleep(wait_time);
5795 -+
5796 -+ /* Check if the processor is ready */
5797 -+ if (total_processors(processor->id) < processor->senv->max_processors ||
5798 -+ idle_processors(processor->id) > 0) {
5799 -+ /* The processor has freed - lets use it */
5800 -+ _DBG("processor freed before wait time expired");
5801 -+ break;
5802 -+ }
5803 -+ }
5804 -+
5805 -+ if (processor->senv->availability <= wait_step_size) {
5806 -+ processor->senv->availability = 0;
5807 -+ }
5808 -+ else processor->senv->availability -= wait_step_size;
5809 -+
5810 -+ /* Check if we waited all the time */
5811 -+ if (i > processor->senv->availability) {
5812 -+ _DBG("processor is busy - not passing request (availability = %d)",
5813 -+ processor->senv->availability);
5814 -+
5815 -+ if (processor->senv->error_pass == 0) {
5816 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf,
5817 -+ "Too many requests for processor %s, increase MaxProcessors", processor->senv->name);
5818 -+ }
5819 -+
5820 -+ return -1;
5821 -+ }
5822 -+
5823 -+ /* We could increase the availability a little here,
5824 -+ * because the processor got freed eventually
5825 -+ */
5826 -+ }
5827 -+ else {
5828 -+ /* Smoothly increment the availability back to 100 */
5829 -+ if (processor->senv->availability >= 100-wait_step_size) {
5830 -+ processor->senv->availability = 100;
5831 -+ }
5832 -+ else processor->senv->availability += wait_step_size;
5833 -+ }
5834 -+
5835 -+ return 0;
5836 -+}
5837 -+
5838 -+/*
5839 -+ * This function sends a raw socket over to a processor. It uses the same
5840 -+ * on-wire format as pass_request. The recipient can determine if he got
5841 -+ * a socket or a whole request by inspecting the header_length of the
5842 -+ * message. If it is zero then only a socket was sent.
5843 -+ */
5844 -+static int pass_socket(apr_socket_t *thesock, child_info_t *processor, apr_pool_t *pool)
5845 -+{
5846 -+ int rv;
5847 -+ struct msghdr msg;
5848 -+ struct cmsghdr *cmsg;
5849 -+ apr_sockaddr_t *remote_addr;
5850 -+ int sock_fd;
5851 -+ char *body = "";
5852 -+ struct iovec iov[5];
5853 -+ apr_size_t header_len = 0;
5854 -+ apr_size_t body_len = 0;
5855 -+ peruser_header h;
5856 -+
5857 -+ if (!processor)
5858 -+ {
5859 -+ _DBG("server %s in child %d has no child_info associated",
5860 -+ "(unkonwn)", my_child_num);
5861 -+ return -1;
5862 -+ }
5863 -+
5864 -+ /* Make sure there are free workers on the other end */
5865 -+ if (wait_for_workers(processor) == -1) return -1;
5866 -+
5867 -+ _DBG("passing request to another child.", 0);
5868 -+
5869 -+ apr_os_sock_get(&sock_fd, thesock);
5870 -+ /* passing remote_addr too, see comments below */
5871 -+ apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock);
5872 -+
5873 -+ header_len = 0;
5874 -+ body_len = 0;
5875 -+
5876 -+ iov[0].iov_base = &header_len;
5877 -+ iov[0].iov_len = sizeof(header_len);
5878 -+ iov[1].iov_base = &body_len;
5879 -+ iov[1].iov_len = sizeof(body_len);
5880 -+ iov[2].iov_base = remote_addr;
5881 -+ iov[2].iov_len = sizeof(*remote_addr);
5882 -+ iov[3].iov_base = h.headers;
5883 -+ iov[3].iov_len = 0;
5884 -+ iov[4].iov_base = body;
5885 -+ iov[4].iov_len = body_len;
5886 -+
5887 -+ msg.msg_name = NULL;
5888 -+ msg.msg_namelen = 0;
5889 -+ msg.msg_iov = iov;
5890 -+ msg.msg_iovlen = 5;
5891 -+
5892 -+ cmsg = apr_palloc(pool, sizeof(*cmsg) + sizeof(sock_fd));
5893 -+ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd));
5894 -+ cmsg->cmsg_level = SOL_SOCKET;
5895 -+ cmsg->cmsg_type = SCM_RIGHTS;
5896 -+
5897 -+ memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd));
5898 -+
5899 -+ msg.msg_control = cmsg;
5900 -+ msg.msg_controllen = cmsg->cmsg_len;
5901 -+
5902 -+ if (processor->status == CHILD_STATUS_STANDBY)
5903 -+ {
5904 -+ _DBG("Activating child #%d", processor->id);
5905 -+ processor->status = CHILD_STATUS_STARTING;
5906 -+ }
5907 -+
5908 -+ _DBG("Writing message to %d, passing sock_fd: %d", processor->senv->output, sock_fd);
5909 -+ _DBG("header_len=%d headers=\"%s\"", header_len, h.headers);
5910 -+ _DBG("body_len=%d body=\"%s\"", body_len, body);
5911 -+
5912 -+ if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1)
5913 -+ {
5914 -+ apr_pool_destroy(pool);
5915 -+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
5916 -+ "Writing message failed %d %d", rv, errno);
5917 -+ return -1;
5918 -+ }
5919 -+
5920 -+ _DBG("Writing message succeeded %d", rv);
5921 -+
5922 -+ /* -- close the socket on our side -- */
5923 -+ _DBG("closing socket %d on our side", sock_fd);
5924 -+ apr_socket_close(thesock);
5925 -+
5926 -+ apr_pool_destroy(pool);
5927 -+ return 1;
5928 -+}
5929 -+
5930 -+static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id,
5931 -+ apr_bucket_alloc_t *bucket_alloc, apr_pool_t *pool)
5932 -+{
5933 -+ conn_rec *current_conn;
5934 -+ int sock_fd;
5935 -+ apr_status_t rv;
5936 -+ ap_sb_handle_t *sbh;
5937 -+ child_info_t *processor;
5938 -+ apr_pool_t *ptrans;
5939 -+ peruser_server_conf *sconf;
5940 -+ int ssl_on;
5941 -+
5942 -+ _DBG("Creating dummy connection to use the vhost lookup api", 0);
5943 -+
5944 -+ ap_create_sb_handle(&sbh, p, conn_id, 0);
5945 -+ current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id,
5946 -+ sbh, bucket_alloc);
5947 -+ _DBG("Looking up the right vhost");
5948 -+ if (current_conn) {
5949 -+ ap_update_vhost_given_ip(current_conn);
5950 -+ _DBG("Base server is %s, name based vhosts %s", current_conn->base_server->server_hostname,
5951 -+ current_conn->vhost_lookup_data ? "on" : "off");
5952 -+ }
5953 -+
5954 -+ // check for ssl configuration for this server (ssl_server_is_https is NULL if we have no mod_ssl)
5955 -+ if(ssl_server_is_https) ssl_on = ssl_server_is_https(current_conn->base_server);
5956 -+ else ssl_on = 0;
5957 -+
5958 -+ if (current_conn && (!current_conn->vhost_lookup_data || ssl_on) && CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
5959 -+ _DBG("We are not using name based vhosts (or SSL is enabled), we'll directly pass the socket.");
5960 -+
5961 -+ sconf = PERUSER_SERVER_CONF(current_conn->base_server->module_config);
5962 -+
5963 -+ if (sconf->senv != NULL) {
5964 -+ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id];
5965 -+
5966 -+ _DBG("Forwarding without further inspection, processor %d", processor->id);
5967 -+ if (processor->status == CHILD_STATUS_STANDBY)
5968 -+ {
5969 -+ _DBG("Activating child #%d", processor->id);
5970 -+ processor->status = CHILD_STATUS_STARTING;
5971 -+ }
5972 -+
5973 -+ _DBG("Creating new pool",0);
5974 -+ apr_pool_create(&ptrans, pool);
5975 -+
5976 -+ _DBG("Passing request.",0);
5977 -+ if (pass_socket(sock, processor, ptrans) == -1) {
5978 -+ if (processor->senv->error_pass == 0) {
5979 -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
5980 -+ ap_server_conf, "Could not pass request to proper "
5981 -+ "child, request will not be honoured.");
5982 -+ }
5983 -+
5984 -+ processor->senv->error_pass = 1;
5985 -+ }
5986 -+ else {
5987 -+ processor->senv->error_pass = 0;
5988 -+ }
5989 -+ }
5990 -+ else {
5991 -+ _DBG("Base server has no senv set!");
5992 -+
5993 -+ if (sconf->missing_senv_reported == 0) {
5994 -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
5995 -+ ap_server_conf, "Virtualhost %s has no server environment set, "
5996 -+ "request will not be honoured.", current_conn->base_server->server_hostname);
5997 -+ }
5998 -+
5999 -+ sconf->missing_senv_reported = 1;
6000 -+ }
6001 -+
6002 -+ if (current_conn)
6003 -+ {
6004 -+ _DBG("freeing connection",0);
6005 -+ ap_lingering_close(current_conn);
6006 -+ }
6007 -+
6008 -+ _DBG("doing longjmp",0);
6009 -+ longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
6010 -+ return;
6011 -+ }
6012 -+
6013 -+ if ((rv = apr_os_sock_get(&sock_fd, sock)) != APR_SUCCESS)
6014 -+ {
6015 -+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get");
6016 -+ }
6017 -+
6018 -+ _DBG("child_num=%d sock=%ld sock_fd=%d", my_child_num, sock, sock_fd);
6019 -+ _DBG("type=%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num);
6020 -+
6021 -+#ifdef _OSD_POSIX
6022 -+ if (sock_fd >= FD_SETSIZE)
6023 -+ {
6024 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
6025 -+ "new file descriptor %d is too large; you probably need "
6026 -+ "to rebuild Apache with a larger FD_SETSIZE "
6027 -+ "(currently %d)",
6028 -+ sock_fd, FD_SETSIZE);
6029 -+ apr_socket_close(sock);
6030 -+ _DBG("child_num=%d: exiting with error", my_child_num);
6031 -+ return;
6032 -+ }
6033 -+#endif
6034 -+
6035 -+ if (CHILD_INFO_TABLE[my_child_num].sock_fd < 0)
6036 -+ {
6037 -+ ap_sock_disable_nagle(sock);
6038 -+ }
6039 -+
6040 -+ if (!current_conn) {
6041 -+ ap_create_sb_handle(&sbh, p, conn_id, 0);
6042 -+ current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id,
6043 -+ sbh, bucket_alloc);
6044 -+ }
6045 -+
6046 -+ if (current_conn)
6047 -+ {
6048 -+ ap_process_connection(current_conn, sock);
6049 -+ ap_lingering_close(current_conn);
6050 -+ }
6051 -+}
6052 -+
6053 -+static int peruser_process_connection(conn_rec *conn)
6054 -+{
6055 -+ ap_filter_t *filter;
6056 -+ apr_bucket_brigade *bb;
6057 -+ core_net_rec *net;
6058 -+
6059 -+ _DBG("function entered",0);
6060 -+
6061 -+ /* -- fetch our sockets from the pool -- */
6062 -+ apr_pool_userdata_get((void **)&bb, "PERUSER_SOCKETS", conn->pool);
6063 -+ if (bb != NULL)
6064 -+ {
6065 -+ /* -- find the 'core' filter and give the socket data to it -- */
6066 -+ for (filter = conn->output_filters; filter != NULL; filter = filter->next)
6067 -+ {
6068 -+ if (!strcmp(filter->frec->name, "core")) break;
6069 -+ }
6070 -+ if (filter != NULL)
6071 -+ {
6072 -+ net = filter->ctx;
6073 -+ net->in_ctx = apr_palloc(conn->pool, sizeof(*net->in_ctx));
6074 -+ net->in_ctx->b = bb;
6075 -+ net->in_ctx->tmpbb = apr_brigade_create(net->in_ctx->b->p,
6076 -+ net->in_ctx->b->bucket_alloc);
6077 -+ }
6078 -+ }
6079 -+ _DBG("leaving (DECLINED)", 0);
6080 -+ return DECLINED;
6081 -+}
6082 -+
6083 -+static int pass_request(request_rec *r, child_info_t *processor)
6084 -+{
6085 -+ int rv;
6086 -+ struct msghdr msg;
6087 -+ struct cmsghdr *cmsg;
6088 -+ apr_sockaddr_t *remote_addr;
6089 -+ int sock_fd;
6090 -+ char *body = "";
6091 -+ struct iovec iov[5];
6092 -+ conn_rec *c = r->connection;
6093 -+ apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
6094 -+ apr_bucket_brigade *body_bb = NULL;
6095 -+ apr_size_t len = 0;
6096 -+ apr_size_t header_len = 0;
6097 -+ apr_size_t body_len = 0;
6098 -+ peruser_header h;
6099 -+ apr_bucket *bucket;
6100 -+ const apr_array_header_t *headers_in_array;
6101 -+ const apr_table_entry_t *headers_in;
6102 -+ int counter;
6103 -+
6104 -+ apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module);
6105 -+
6106 -+ if ((!r->the_request) || (!strlen(r->the_request)))
6107 -+ {
6108 -+ _DBG("empty request. dropping it (%ld)", r->the_request);
6109 -+ return -1;
6110 -+ }
6111 -+
6112 -+ if (!processor)
6113 -+ {
6114 -+ _DBG("server %s in child %d has no child_info associated",
6115 -+ r->hostname, my_child_num);
6116 -+ return -1;
6117 -+ }
6118 -+
6119 -+ _DBG("passing request to another child. Vhost: %s, child %d %d",
6120 -+ apr_table_get(r->headers_in, "Host"), my_child_num, processor->senv->output);
6121 -+ _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request));
6122 -+
6123 -+ /* Make sure there are free workers on the other end */
6124 -+ if (wait_for_workers(processor) == -1) return -1;
6125 -+
6126 -+ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
6127 -+
6128 -+ /* Scan the brigade looking for heap-buckets */
6129 -+
6130 -+ _DBG("Scanning the brigade",0);
6131 -+ bucket = APR_BRIGADE_FIRST(bb);
6132 -+ while (bucket != APR_BRIGADE_SENTINEL(bb) &&
6133 -+ APR_BUCKET_IS_HEAP(bucket)) {
6134 -+ _DBG("HEAP BUCKET is found, length=%d", bucket->length);
6135 -+ bucket = APR_BUCKET_NEXT(bucket);
6136 -+ if (!APR_BUCKET_IS_HEAP(bucket)) {
6137 -+ _DBG("NON-HEAP BUCKET is found, extracting the part of brigade before it",0);
6138 -+ body_bb = bb;
6139 -+ bb = apr_brigade_split(body_bb, bucket);
6140 -+ /* Do we need to apr_destroy_brigade(bb) here?
6141 -+ * Yeah, I know we do apr_pool_destroy(r->pool) before return, but
6142 -+ * ap_get_brigade is in non-blocking mode (however len is zero).
6143 -+ */
6144 -+ if (apr_brigade_pflatten(body_bb, &body, &body_len, r->pool) != APR_SUCCESS) {
6145 -+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
6146 -+ "Unable to flatten brigade, declining request");
6147 -+ apr_pool_destroy(r->pool);
6148 -+ return DECLINED;
6149 -+ }
6150 -+ _DBG("Brigade is flattened as body (body_len=%d)", body_len);
6151 -+ }
6152 -+ }
6153 -+ _DBG("Scanning is finished",0);
6154 -+
6155 -+ apr_os_sock_get(&sock_fd, thesock);
6156 -+ /* looks like a bug while sending/receiving SCM_RIGHTS related to ipv6
6157 -+ workaround: send remote_addr structure too */
6158 -+ apr_socket_addr_get(&remote_addr, APR_REMOTE, thesock);
6159 -+
6160 -+ h.p = r->pool;
6161 -+
6162 -+ headers_in_array = apr_table_elts(r->headers_in);
6163 -+ headers_in = (const apr_table_entry_t *) headers_in_array->elts;
6164 -+
6165 -+ h.headers = apr_pstrcat(h.p, r->the_request, CRLF, NULL);
6166 -+ for (counter = 0; counter < headers_in_array->nelts; counter++) {
6167 -+ if (headers_in[counter].key == NULL
6168 -+ || headers_in[counter].val == NULL) {
6169 -+ continue;
6170 -+ }
6171 -+ h.headers = apr_pstrcat(h.p, h.headers, headers_in[counter].key, ": ",
6172 -+ headers_in[counter].val, CRLF, NULL);
6173 -+
6174 -+ }
6175 -+ h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL);
6176 -+ ap_xlate_proto_to_ascii(h.headers, strlen(h.headers));
6177 -+
6178 -+ header_len = strlen(h.headers);
6179 -+
6180 -+ iov[0].iov_base = &header_len;
6181 -+ iov[0].iov_len = sizeof(header_len);
6182 -+ iov[1].iov_base = &body_len;
6183 -+ iov[1].iov_len = sizeof(body_len);
6184 -+ iov[2].iov_base = remote_addr;
6185 -+ iov[2].iov_len = sizeof(*remote_addr);
6186 -+ iov[3].iov_base = h.headers;
6187 -+ iov[3].iov_len = strlen(h.headers) + 1;
6188 -+ iov[4].iov_base = body;
6189 -+ iov[4].iov_len = body_len;
6190 -+
6191 -+ msg.msg_name = NULL;
6192 -+ msg.msg_namelen = 0;
6193 -+ msg.msg_iov = iov;
6194 -+ msg.msg_iovlen = 5;
6195 -+
6196 -+ cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sock_fd));
6197 -+ cmsg->cmsg_len = CMSG_LEN(sizeof(sock_fd));
6198 -+ cmsg->cmsg_level = SOL_SOCKET;
6199 -+ cmsg->cmsg_type = SCM_RIGHTS;
6200 -+
6201 -+ memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd));
6202 -+
6203 -+ msg.msg_control = cmsg;
6204 -+ msg.msg_controllen = cmsg->cmsg_len;
6205 -+
6206 -+ if (processor->status == CHILD_STATUS_STANDBY)
6207 -+ {
6208 -+ _DBG("Activating child #%d", processor->id);
6209 -+ processor->status = CHILD_STATUS_STARTING;
6210 -+ }
6211 -+
6212 -+ _DBG("Writing message to %d, passing sock_fd: %d", processor->senv->output, sock_fd);
6213 -+ _DBG("header_len=%d headers=\"%s\"", header_len, h.headers);
6214 -+ _DBG("body_len=%d body=\"%s\"", body_len, body);
6215 -+
6216 -+ if ((rv = sendmsg(processor->senv->output, &msg, 0)) == -1)
6217 -+ {
6218 -+ apr_pool_destroy(r->pool);
6219 -+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
6220 -+ "Writing message failed %d %d", rv, errno);
6221 -+ return -1;
6222 -+ }
6223 -+
6224 -+ _DBG("Writing message succeeded %d", rv);
6225 -+
6226 -+ /* -- close the socket on our side -- */
6227 -+ _DBG("closing socket %d on our side", sock_fd);
6228 -+ apr_socket_close(thesock);
6229 -+
6230 -+ apr_pool_destroy(r->pool);
6231 -+ return 1;
6232 -+}
6233 -+
6234 -+
6235 -+static apr_status_t receive_from_multiplexer(
6236 -+ void **trans_sock, /* will be filled out w/ the received socket */
6237 -+ ap_listen_rec *lr, /* listener to receive from */
6238 -+ apr_pool_t *ptrans /* transaction wide pool */
6239 -+)
6240 -+{
6241 -+ struct msghdr msg;
6242 -+ struct cmsghdr *cmsg;
6243 -+ char buff[HUGE_STRING_LEN] = "";
6244 -+ char headers[HUGE_STRING_LEN] = "";
6245 -+ char *body = "";
6246 -+ apr_size_t header_len, body_len;
6247 -+ struct iovec iov[4];
6248 -+ int ret, fd_tmp;
6249 -+ apr_os_sock_t ctrl_sock_fd;
6250 -+ apr_os_sock_t trans_sock_fd;
6251 -+ apr_sockaddr_t remote_addr;
6252 -+ apr_os_sock_info_t sockinfo;
6253 -+
6254 -+ /* -- bucket's, brigades and their allocators */
6255 -+ apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans);
6256 -+ apr_bucket_brigade *bb = apr_brigade_create(ptrans, alloc);
6257 -+ apr_bucket *bucket;
6258 -+
6259 -+ /* prepare the buffers for receiving data from remote side */
6260 -+ iov[0].iov_base = &header_len;
6261 -+ iov[0].iov_len = sizeof(header_len);
6262 -+ iov[1].iov_base = &body_len;
6263 -+ iov[1].iov_len = sizeof(body_len);
6264 -+ iov[2].iov_base = &remote_addr;
6265 -+ iov[2].iov_len = sizeof(remote_addr);
6266 -+ iov[3].iov_base = (char*)&buff;
6267 -+ iov[3].iov_len = HUGE_STRING_LEN;
6268 -+
6269 -+ cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd));
6270 -+ cmsg->cmsg_len = CMSG_LEN(sizeof(trans_sock_fd));
6271 -+
6272 -+ msg.msg_name = NULL;
6273 -+ msg.msg_namelen = 0;
6274 -+ msg.msg_iov = iov;
6275 -+ msg.msg_iovlen = 4;
6276 -+ msg.msg_control = cmsg;
6277 -+ msg.msg_controllen = cmsg->cmsg_len;
6278 -+
6279 -+ /* -- receive data from socket -- */
6280 -+ apr_os_sock_get(&ctrl_sock_fd, lr->sd);
6281 -+ _DBG("receiving from sock_fd=%d", ctrl_sock_fd);
6282 -+
6283 -+ // Don't block
6284 -+ ret = recvmsg(ctrl_sock_fd, &msg, MSG_DONTWAIT);
6285 -+
6286 -+ if (ret == -1 && errno == EAGAIN) {
6287 -+ _DBG("receive_from_multiplexer recvmsg() EAGAIN, someone was faster");
6288 -+
6289 -+ return APR_EAGAIN;
6290 -+ }
6291 -+ else if (ret == -1) {
6292 -+ _DBG("recvmsg failed with error \"%s\"", strerror(errno));
6293 -+
6294 -+ // Error, better kill this child to be on the safe side
6295 -+ return APR_EGENERAL;
6296 -+ }
6297 -+ else _DBG("recvmsg returned %d", ret);
6298 -+
6299 -+ /* -- extract socket from the cmsg -- */
6300 -+ memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd));
6301 -+ /* here *trans_sock always == NULL (socket reset at got_fd), so
6302 -+ we can use apr_os_sock_make() instead of apr_os_sock_put() */
6303 -+ sockinfo.os_sock = &trans_sock_fd;
6304 -+ sockinfo.local = NULL;
6305 -+ sockinfo.remote = (struct sockaddr *)&remote_addr.sa.sin;
6306 -+ sockinfo.family = remote_addr.family;
6307 -+ sockinfo.type = SOCK_STREAM;
6308 -+#ifdef APR_ENABLE_FOR_1_0
6309 -+ sockinfo.protocol = 0;
6310 -+#endif
6311 -+ apr_os_sock_make((apr_socket_t **)trans_sock, &sockinfo, ptrans);
6312 -+ apr_os_sock_get(&fd_tmp, *trans_sock);
6313 -+
6314 -+ _DBG("trans_sock=%ld fdx=%d sock_fd=%d",
6315 -+ *trans_sock, trans_sock_fd, fd_tmp);
6316 -+
6317 -+ apr_cpystrn(headers, buff, header_len + 1);
6318 -+ _DBG("header_len=%d headers=\"%s\"", header_len, headers);
6319 -+
6320 -+ if (header_len) {
6321 -+ _DBG("header_len > 0, we got a request", 0);
6322 -+ /* -- store received data into an brigade and add
6323 -+ it to the current transaction's pool -- */
6324 -+ bucket = apr_bucket_eos_create(alloc);
6325 -+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
6326 -+ bucket = apr_bucket_socket_create(*trans_sock, alloc);
6327 -+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
6328 -+
6329 -+ if (body_len) {
6330 -+ body = (char*)&buff[header_len + 1];
6331 -+ _DBG("body_len=%d body=\"%s\"", body_len, body);
6332 -+
6333 -+ bucket = apr_bucket_heap_create(body, body_len, NULL, alloc);
6334 -+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
6335 -+ } else {
6336 -+ _DBG("There is no body",0);
6337 -+ }
6338 -+
6339 -+ bucket = apr_bucket_heap_create(headers, header_len, NULL, alloc);
6340 -+
6341 -+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
6342 -+ apr_pool_userdata_set(bb, "PERUSER_SOCKETS", NULL, ptrans);
6343 -+ } else {
6344 -+ _DBG("header_len == 0, we got a socket only", 0);
6345 -+ }
6346 -+ _DBG("returning 0", 0);
6347 -+ return 0;
6348 -+}
6349 -+
6350 -+
6351 -+/* Set group privileges.
6352 -+ *
6353 -+ * Note that we use the username as set in the config files, rather than
6354 -+ * the lookup of to uid --- the same uid may have multiple passwd entries,
6355 -+ * with different sets of groups for each.
6356 -+ */
6357 -+
6358 -+static int set_group_privs(uid_t uid, gid_t gid)
6359 -+{
6360 -+ if (!geteuid())
6361 -+ {
6362 -+ struct passwd *ent;
6363 -+ const char *name;
6364 -+
6365 -+ /*
6366 -+ * Set the GID before initgroups(), since on some platforms
6367 -+ * setgid() is known to zap the group list.
6368 -+ */
6369 -+ if (setgid(gid) == -1)
6370 -+ {
6371 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
6372 -+ "setgid: unable to set group id to Group %u",
6373 -+ (unsigned)gid);
6374 -+ return -1;
6375 -+ }
6376 -+
6377 -+ /* if getpwuid() fails, just skip initgroups() */
6378 -+
6379 -+ if ((ent = getpwuid(uid)) != NULL)
6380 -+ {
6381 -+ name = ent->pw_name;
6382 -+
6383 -+ /* Reset `groups' attributes. */
6384 -+
6385 -+ if (initgroups(name, gid) == -1)
6386 -+ {
6387 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
6388 -+ "initgroups: unable to set groups for User %s "
6389 -+ "and Group %u", name, (unsigned)gid);
6390 -+ return -1;
6391 -+ }
6392 -+ }
6393 -+ }
6394 -+ return 0;
6395 -+}
6396 -+
6397 -+static int peruser_setup_cgroup(int childnum, server_env_t *senv, apr_pool_t *pool)
6398 -+{
6399 -+ apr_file_t *file;
6400 -+ int length;
6401 -+ apr_size_t content_len;
6402 -+ char *tasks_file, *content, *pos;
6403 -+
6404 -+ _DBG("starting to add pid to cgroup %s", senv->cgroup);
6405 -+
6406 -+ length = strlen(senv->cgroup) + CGROUP_TASKS_FILE_LEN;
6407 -+ tasks_file = malloc(length);
6408 -+
6409 -+ if (!tasks_file) return -1;
6410 -+
6411 -+ pos = apr_cpystrn(tasks_file, senv->cgroup, length);
6412 -+ apr_cpystrn(pos, CGROUP_TASKS_FILE, CGROUP_TASKS_FILE_LEN);
6413 -+
6414 -+ /* Prepare the data to be written to tasks file */
6415 -+ content = apr_itoa(pool, ap_my_pid);
6416 -+ content_len = strlen(content);
6417 -+
6418 -+ _DBG("writing pid %s to tasks file %s", content, tasks_file);
6419 -+
6420 -+ if (apr_file_open(&file, tasks_file, APR_WRITE, APR_OS_DEFAULT, pool)) {
6421 -+ if (senv->error_cgroup == 0) {
6422 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
6423 -+ "cgroup: unable to open file %s",
6424 -+ tasks_file);
6425 -+ }
6426 -+
6427 -+ senv->error_cgroup = 1;
6428 -+ free(tasks_file);
6429 -+ return OK; /* don't fail if cgroup not available */
6430 -+ }
6431 -+
6432 -+ if (apr_file_write(file, content, &content_len)) {
6433 -+ if (senv->error_cgroup == 0) {
6434 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
6435 -+ "cgroup: unable to write pid to file %s",
6436 -+ tasks_file);
6437 -+ }
6438 -+ senv->error_cgroup = 1;
6439 -+ }
6440 -+ else {
6441 -+ senv->error_cgroup = 0;
6442 -+ }
6443 -+
6444 -+ apr_file_close(file);
6445 -+
6446 -+ free(tasks_file);
6447 -+
6448 -+ return OK;
6449 -+}
6450 -+
6451 -+static int peruser_setup_child(int childnum, apr_pool_t *pool)
6452 -+{
6453 -+ server_env_t *senv = CHILD_INFO_TABLE[childnum].senv;
6454 -+
6455 -+ _DBG("function called");
6456 -+
6457 -+ if (senv->nice_lvl != 0) {
6458 -+ nice(senv->nice_lvl);
6459 -+ }
6460 -+
6461 -+ if(senv->chroot) {
6462 -+ _DBG("chdir to %s", senv->chroot);
6463 -+
6464 -+ if(chdir(senv->chroot)) {
6465 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
6466 -+ "chdir: unable to change to directory: %s",
6467 -+ senv->chroot);
6468 -+ return -1;
6469 -+ }
6470 -+
6471 -+ if(chroot(senv->chroot)) {
6472 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
6473 -+ "chroot: unable to chroot to directory: %s",
6474 -+ senv->chroot);
6475 -+ return -1;
6476 -+ }
6477 -+ }
6478 -+
6479 -+ if(senv->cgroup) {
6480 -+ peruser_setup_cgroup(childnum, senv, pool);
6481 -+ }
6482 -+
6483 -+ if (senv->uid == -1 && senv->gid == -1) {
6484 -+ return unixd_setup_child();
6485 -+ }
6486 -+ if (set_group_privs(senv->uid, senv->gid)) {
6487 -+ return -1;
6488 -+ }
6489 -+ /* Only try to switch if we're running as root */
6490 -+ if (!geteuid()
6491 -+ && (
6492 -+#ifdef _OSD_POSIX
6493 -+ os_init_job_environment(ap_server_conf, unixd_config.user_name,
6494 -+ one_process) != 0 ||
6495 -+#endif
6496 -+ setuid(senv->uid) == -1)) {
6497 -+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
6498 -+ "setuid: unable to change to uid: %ld",
6499 -+ (long) senv->uid);
6500 -+ return -1;
6501 -+ }
6502 -+ return 0;
6503 -+}
6504 -+
6505 -+static int check_signal(int signum)
6506 -+{
6507 -+ _DBG("signum=%d", signum);
6508 -+ switch (signum) {
6509 -+ case SIGTERM:
6510 -+ case SIGINT:
6511 -+ just_die(signum);
6512 -+ return 1;
6513 -+ }
6514 -+ return 0;
6515 -+}
6516 -+
6517 -+/* Send a single HTTP header field to the client. Note that this function
6518 -+ * is used in calls to table_do(), so their interfaces are co-dependent.
6519 -+ * In other words, don't change this one without checking table_do in alloc.c.
6520 -+ * It returns true unless there was a write error of some kind.
6521 -+ */
6522 -+static int peruser_header_field(peruser_header *h,
6523 -+ const char *fieldname, const char *fieldval)
6524 -+{
6525 -+ apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL);
6526 -+ return 1;
6527 -+}
6528 -+
6529 -+static inline ap_listen_rec* listen_add(apr_pool_t* pool, apr_socket_t *sock, void* accept_func)
6530 -+{
6531 -+ ap_listen_rec *lr_walk, *lr_new;
6532 -+
6533 -+ _DBG("function entered", 0);
6534 -+ /* -- create an new listener for this child -- */
6535 -+ lr_new = apr_palloc(pool, sizeof(*lr_new));
6536 -+ lr_new->sd = sock;
6537 -+ lr_new->active = 1;
6538 -+ lr_new->accept_func = accept_func;
6539 -+ lr_new->next = NULL;
6540 -+
6541 -+ /* -- add the new listener_rec into the list -- */
6542 -+ /* FIXME: should we somehow lock this list ? */
6543 -+ lr_walk = ap_listeners;
6544 -+ if (lr_walk)
6545 -+ {
6546 -+ while (lr_walk->next) lr_walk = lr_walk->next;
6547 -+ lr_walk->next = lr_new;
6548 -+ }
6549 -+ else
6550 -+ {
6551 -+ ap_listeners = lr_walk = lr_new;
6552 -+ }
6553 -+ num_listensocks++;
6554 -+ return lr_new;
6555 -+}
6556 -+
6557 -+static inline void listen_clear()
6558 -+{
6559 -+ ap_listen_rec *lr_walk;
6560 -+
6561 -+ _DBG("function entered", 0);
6562 -+
6563 -+ /* FIXME: should we somehow lock this list ? */
6564 -+ while (ap_listeners)
6565 -+ {
6566 -+ lr_walk = ap_listeners->next;
6567 -+ apr_socket_close(ap_listeners->sd);
6568 -+ ap_listeners = lr_walk;
6569 -+ }
6570 -+ num_listensocks=0;
6571 -+}
6572 -+
6573 -+apr_status_t cleanup_child_info(void *d)
6574 -+{
6575 -+ if (child_info_image == NULL) {
6576 -+ return APR_SUCCESS;
6577 -+ }
6578 -+
6579 -+ free(child_info_image);
6580 -+ child_info_image = NULL;
6581 -+ apr_shm_destroy(child_info_shm);
6582 -+
6583 -+ return APR_SUCCESS;
6584 -+}
6585 -+
6586 -+apr_status_t cleanup_server_environments(void *d)
6587 -+{
6588 -+ if (server_env_image == NULL) {
6589 -+ return APR_SUCCESS;
6590 -+ }
6591 -+
6592 -+ free(server_env_image);
6593 -+ server_env_image = NULL;
6594 -+ apr_shm_destroy(server_env_shm);
6595 -+
6596 -+ return APR_SUCCESS;
6597 -+}
6598 -+
6599 -+static const char* child_clone();
6600 -+
6601 -+static void child_main(int child_num_arg)
6602 -+{
6603 -+ apr_pool_t *ptrans;
6604 -+ apr_allocator_t *allocator;
6605 -+ conn_rec *current_conn;
6606 -+ apr_status_t status = APR_EINIT;
6607 -+ int i;
6608 -+ ap_listen_rec *lr;
6609 -+ int curr_pollfd, last_pollfd = 0;
6610 -+ apr_pollfd_t *pollset;
6611 -+ int offset;
6612 -+ ap_sb_handle_t *sbh;
6613 -+ apr_status_t rv;
6614 -+ apr_bucket_alloc_t *bucket_alloc;
6615 -+ int fd;
6616 -+ apr_socket_t *sock = NULL;
6617 -+ apr_socket_t *pod_sock = NULL;
6618 -+
6619 -+ mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this
6620 -+ * child initializes
6621 -+ */
6622 -+
6623 -+ my_child_num = child_num_arg;
6624 -+ ap_my_pid = getpid();
6625 -+ requests_this_child = 0;
6626 -+
6627 -+ _DBG("sock_fd_in=%d sock_fd_out=%d",
6628 -+ CHILD_INFO_TABLE[my_child_num].senv->input,
6629 -+ CHILD_INFO_TABLE[my_child_num].senv->output);
6630 -+
6631 -+ /* Get a sub context for global allocations in this child, so that
6632 -+ * we can have cleanups occur when the child exits.
6633 -+ */
6634 -+ apr_allocator_create(&allocator);
6635 -+ apr_allocator_max_free_set(allocator, ap_max_mem_free);
6636 -+ apr_pool_create_ex(&pchild, pconf, NULL, allocator);
6637 -+ apr_allocator_owner_set(allocator, pchild);
6638 -+
6639 -+ apr_pool_create(&ptrans, pchild);
6640 -+ apr_pool_tag(ptrans, "transaction");
6641 -+
6642 -+ /* needs to be done before we switch UIDs so we have permissions */
6643 -+ ap_reopen_scoreboard(pchild, NULL, 0);
6644 -+
6645 -+ rv = apr_proc_mutex_child_init(&accept_mutex, ap_lock_fname, pchild);
6646 -+ if (rv != APR_SUCCESS) {
6647 -+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
6648 -+ "Couldn't initialize cross-process lock in child");
6649 -+ clean_child_exit(APEXIT_CHILDFATAL);
6650 -+ }
6651 -+
6652 -+ switch(CHILD_INFO_TABLE[my_child_num].type)
6653 -+ {
6654 -+ case CHILD_TYPE_MULTIPLEXER:
6655 -+ _DBG("MULTIPLEXER %d", my_child_num);
6656 -+ break;
6657 -+
6658 -+ case CHILD_TYPE_PROCESSOR:
6659 -+ case CHILD_TYPE_WORKER:
6660 -+ _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num);
6661 -+
6662 -+ /* -- create new listener to receive from multiplexer -- */
6663 -+ apr_os_sock_put(&sock, &CHILD_INFO_TABLE[my_child_num].senv->input, pconf);
6664 -+ listen_clear();
6665 -+ listen_add(pconf, sock, receive_from_multiplexer);
6666 -+
6667 -+ break;
6668 -+
6669 -+ default:
6670 -+ _DBG("unspecified child type for %d sleeping a while ...", my_child_num);
6671 -+ sleep(5);
6672 -+ return;
6673 -+ }
6674 -+
6675 -+ apr_os_file_get(&fd, pipe_of_death_in);
6676 -+ apr_os_sock_put(&pod_sock, &fd, pconf);
6677 -+ listen_add(pconf, pod_sock, check_pipe_of_death);
6678 -+
6679 -+ if(peruser_setup_child(my_child_num, pchild) != 0)
6680 -+ clean_child_exit(APEXIT_CHILDFATAL);
6681 -+
6682 -+ ap_run_child_init(pchild, ap_server_conf);
6683 -+
6684 -+ ap_create_sb_handle(&sbh, pchild, my_child_num, 0);
6685 -+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
6686 -+
6687 -+ /* Set up the pollfd array */
6688 -+ listensocks = apr_pcalloc(pchild,
6689 -+ sizeof(*listensocks) * (num_listensocks));
6690 -+ for (lr = ap_listeners, i = 0; i < num_listensocks; lr = lr->next, i++) {
6691 -+ listensocks[i].accept_func = lr->accept_func;
6692 -+ listensocks[i].sd = lr->sd;
6693 -+ }
6694 -+
6695 -+ pollset = apr_palloc(pchild, sizeof(*pollset) * num_listensocks);
6696 -+ pollset[0].p = pchild;
6697 -+ for (i = 0; i < num_listensocks; i++) {
6698 -+ pollset[i].desc.s = listensocks[i].sd;
6699 -+ pollset[i].desc_type = APR_POLL_SOCKET;
6700 -+ pollset[i].reqevents = APR_POLLIN;
6701 -+ }
6702 -+
6703 -+ mpm_state = AP_MPMQ_RUNNING;
6704 -+
6705 -+ bucket_alloc = apr_bucket_alloc_create(pchild);
6706 -+
6707 -+ while (!die_now) {
6708 -+ /*
6709 -+ * (Re)initialize this child to a pre-connection state.
6710 -+ */
6711 -+
6712 -+ current_conn = NULL;
6713 -+
6714 -+ apr_pool_clear(ptrans);
6715 -+
6716 -+ if (CHILD_INFO_TABLE[my_child_num].type != CHILD_TYPE_MULTIPLEXER
6717 -+ && ap_max_requests_per_child > 0
6718 -+ && requests_this_child++ >= ap_max_requests_per_child) {
6719 -+ _DBG("max requests reached, dying now", 0);
6720 -+ clean_child_exit(0);
6721 -+ }
6722 -+
6723 -+ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
6724 -+
6725 -+ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_READY;
6726 -+ _DBG("Child %d (%s) is now ready", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
6727 -+
6728 -+ /*
6729 -+ * Wait for an acceptable connection to arrive.
6730 -+ */
6731 -+
6732 -+ /* Lock around "accept", if necessary */
6733 -+ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
6734 -+ SAFE_ACCEPT(accept_mutex_on());
6735 -+ }
6736 -+
6737 -+ if (num_listensocks == 1) {
6738 -+ offset = 0;
6739 -+ }
6740 -+ else {
6741 -+ /* multiple listening sockets - need to poll */
6742 -+ for (;;) {
6743 -+ apr_status_t ret;
6744 -+ apr_int32_t n;
6745 -+
6746 -+ ret = apr_poll(pollset, num_listensocks, &n, -1);
6747 -+ if (ret != APR_SUCCESS) {
6748 -+ if (APR_STATUS_IS_EINTR(ret)) {
6749 -+ continue;
6750 -+ }
6751 -+ /* Single Unix documents select as returning errnos
6752 -+ * EBADF, EINTR, and EINVAL... and in none of those
6753 -+ * cases does it make sense to continue. In fact
6754 -+ * on Linux 2.0.x we seem to end up with EFAULT
6755 -+ * occasionally, and we'd loop forever due to it.
6756 -+ */
6757 -+ ap_log_error(APLOG_MARK, APLOG_ERR, ret, ap_server_conf,
6758 -+ "apr_poll: (listen)");
6759 -+ clean_child_exit(1);
6760 -+ }
6761 -+ /* find a listener */
6762 -+ curr_pollfd = last_pollfd;
6763 -+ do {
6764 -+ curr_pollfd++;
6765 -+ if (curr_pollfd >= num_listensocks) {
6766 -+ curr_pollfd = 0;
6767 -+ }
6768 -+ /* XXX: Should we check for POLLERR? */
6769 -+ if (pollset[curr_pollfd].rtnevents & APR_POLLIN) {
6770 -+ last_pollfd = curr_pollfd;
6771 -+ offset = curr_pollfd;
6772 -+ goto got_fd;
6773 -+ }
6774 -+ } while (curr_pollfd != last_pollfd);
6775 -+
6776 -+ continue;
6777 -+ }
6778 -+ }
6779 -+ got_fd:
6780 -+ _DBG("input available ... resetting socket.",0);
6781 -+ sock = NULL; /* important! */
6782 -+
6783 -+ /* if we accept() something we don't want to die, so we have to
6784 -+ * defer the exit
6785 -+ */
6786 -+ status = listensocks[offset].accept_func((void *)&sock, &listensocks[offset], ptrans);
6787 -+
6788 -+ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER) {
6789 -+ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */
6790 -+ }
6791 -+
6792 -+ if (status == APR_EGENERAL) {
6793 -+ /* resource shortage or should-not-occur occured */
6794 -+ clean_child_exit(1);
6795 -+ }
6796 -+ else if (status != APR_SUCCESS || die_now || sock == NULL) {
6797 -+ continue;
6798 -+ }
6799 -+
6800 -+ if (CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_READY) {
6801 -+ CHILD_INFO_TABLE[my_child_num].status = CHILD_STATUS_ACTIVE;
6802 -+ _DBG("Child %d (%s) is now active", my_child_num, child_type_string(CHILD_INFO_TABLE[my_child_num].type));
6803 -+ }
6804 -+
6805 -+ if (CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_PROCESSOR ||
6806 -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_WORKER ||
6807 -+ CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
6808 -+ {
6809 -+ _DBG("CHECKING IF WE SHOULD CLONE A CHILD...");
6810 -+
6811 -+ _DBG("total_processors = %d, max_processors = %d",
6812 -+ total_processors(my_child_num),
6813 -+ CHILD_INFO_TABLE[my_child_num].senv->max_processors);
6814 -+
6815 -+ _DBG("idle_processors = %d, min_free_processors = %d",
6816 -+ idle_processors(my_child_num),
6817 -+ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors);
6818 -+
6819 -+ if(total_processors(my_child_num) <
6820 -+ CHILD_INFO_TABLE[my_child_num].senv->max_processors &&
6821 -+ (idle_processors(my_child_num) <=
6822 -+ CHILD_INFO_TABLE[my_child_num].senv->min_free_processors ||
6823 -+ total_processors(my_child_num) <
6824 -+ CHILD_INFO_TABLE[my_child_num].senv->min_processors
6825 -+ ))
6826 -+ {
6827 -+ _DBG("CLONING CHILD");
6828 -+ child_clone();
6829 -+ }
6830 -+ }
6831 -+
6832 -+ if (!setjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer))
6833 -+ {
6834 -+ _DBG("marked jmpbuffer",0);
6835 -+ _TRACE_CALL("process_socket()",0);
6836 -+ process_socket(ptrans, sock, my_child_num, bucket_alloc, pchild);
6837 -+ _TRACE_RET("process_socket()",0);
6838 -+ }
6839 -+ else
6840 -+ {
6841 -+ _DBG("landed from longjmp",0);
6842 -+ CHILD_INFO_TABLE[my_child_num].sock_fd = AP_PERUSER_THISCHILD;
6843 -+ }
6844 -+
6845 -+ /* Check the pod and the generation number after processing a
6846 -+ * connection so that we'll go away if a graceful restart occurred
6847 -+ * while we were processing the connection or we are the lucky
6848 -+ * idle server process that gets to die.
6849 -+ */
6850 -+ if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */
6851 -+ _DBG("ap_mpm_pod_check(pod) = APR_SUCCESS; dying now", 0);
6852 -+ die_now = 1;
6853 -+ }
6854 -+ else if (ap_my_generation !=
6855 -+ ap_scoreboard_image->global->running_generation) { /* restart? */
6856 -+ /* yeah, this could be non-graceful restart, in which case the
6857 -+ * parent will kill us soon enough, but why bother checking?
6858 -+ */
6859 -+ _DBG("ap_my_generation != ap_scoreboard_image->global->running_generation; dying now", 0);
6860 -+ die_now = 1;
6861 -+ }
6862 -+
6863 -+ if(CHILD_INFO_TABLE[my_child_num].status == CHILD_STATUS_RESTART)
6864 -+ {
6865 -+ _DBG("restarting", 0);
6866 -+ die_now = 1;
6867 -+ }
6868 -+ }
6869 -+
6870 -+ _DBG("clean_child_exit(0)");
6871 -+ clean_child_exit(0);
6872 -+}
6873 -+
6874 -+static server_env_t* find_senv_by_name(const char *name) {
6875 -+ int i;
6876 -+
6877 -+ if (name == NULL) return NULL;
6878 -+
6879 -+ _DBG("name=%s", name);
6880 -+
6881 -+ for(i = 0; i < NUM_SENV; i++)
6882 -+ {
6883 -+ if(SENV[i].name != NULL && !strcmp(SENV[i].name, name)) {
6884 -+ return &SENV[i];
6885 -+ }
6886 -+ }
6887 -+
6888 -+ return NULL;
6889 -+}
6890 -+
6891 -+static server_env_t* find_matching_senv(server_env_t* senv) {
6892 -+ int i;
6893 -+
6894 -+ _DBG("name=%s uid=%d gid=%d chroot=%s", senv->name, senv->uid, senv->gid, senv->chroot);
6895 -+
6896 -+ for(i = 0; i < NUM_SENV; i++)
6897 -+ {
6898 -+ if((senv->name != NULL && SENV[i].name != NULL && !strcmp(SENV[i].name, senv->name)) ||
6899 -+ (senv->name == NULL && SENV[i].uid == senv->uid && SENV[i].gid == senv->gid &&
6900 -+ (
6901 -+ (SENV[i].chroot == NULL && senv->chroot == NULL) ||
6902 -+ ((SENV[i].chroot != NULL || senv->chroot != NULL) && !strcmp(SENV[i].chroot, senv->chroot)))
6903 -+ )
6904 -+ ) {
6905 -+ return &SENV[i];
6906 -+ }
6907 -+ }
6908 -+
6909 -+ return NULL;
6910 -+}
6911 -+
6912 -+static server_env_t* senv_add(server_env_t *senv)
6913 -+{
6914 -+ int socks[2];
6915 -+ server_env_t *old_senv;
6916 -+
6917 -+ _DBG("Searching for matching senv...");
6918 -+
6919 -+ old_senv = find_matching_senv(senv);
6920 -+
6921 -+ if (old_senv) {
6922 -+ _DBG("Found existing senv");
6923 -+ senv = old_senv;
6924 -+ return old_senv;
6925 -+ }
6926 -+
6927 -+ if(NUM_SENV >= server_limit)
6928 -+ {
6929 -+ _DBG("server_limit reached!");
6930 -+ return NULL;
6931 -+ }
6932 -+
6933 -+ _DBG("Creating new senv");
6934 -+
6935 -+ memcpy(&SENV[NUM_SENV], senv, sizeof(server_env_t));
6936 -+
6937 -+ SENV[NUM_SENV].availability = 100;
6938 -+
6939 -+ socketpair(PF_UNIX, SOCK_STREAM, 0, socks);
6940 -+ SENV[NUM_SENV].input = socks[0];
6941 -+ SENV[NUM_SENV].output = socks[1];
6942 -+
6943 -+ senv = &SENV[NUM_SENV];
6944 -+ return &SENV[server_env_image->control->num++];
6945 -+}
6946 -+
6947 -+
6948 -+static const char* child_clone()
6949 -+{
6950 -+ int i;
6951 -+ child_info_t *this;
6952 -+ child_info_t *new;
6953 -+
6954 -+ for(i = 0; i < NUM_CHILDS; i++)
6955 -+ {
6956 -+ if(CHILD_INFO_TABLE[i].pid == 0 &&
6957 -+ CHILD_INFO_TABLE[i].type == CHILD_TYPE_UNKNOWN) break;
6958 -+ }
6959 -+
6960 -+ if(i == NUM_CHILDS && NUM_CHILDS >= server_limit)
6961 -+ {
6962 -+ _DBG("Trying to use more child ID's than ServerLimit. "
6963 -+ "Increase ServerLimit in your config file.");
6964 -+ return NULL;
6965 -+ }
6966 -+
6967 -+ _DBG("cloning child #%d from #%d", i, my_child_num);
6968 -+
6969 -+ this = &CHILD_INFO_TABLE[my_child_num];
6970 -+ new = &CHILD_INFO_TABLE[i];
6971 -+
6972 -+ new->senv = this->senv;
6973 -+
6974 -+ if (this->type == CHILD_TYPE_MULTIPLEXER) {
6975 -+ new->type = CHILD_TYPE_MULTIPLEXER;
6976 -+ }
6977 -+ else {
6978 -+ new->type = CHILD_TYPE_WORKER;
6979 -+ }
6980 -+
6981 -+ new->sock_fd = this->sock_fd;
6982 -+ new->status = CHILD_STATUS_STARTING;
6983 -+
6984 -+ if(i == NUM_CHILDS) child_info_image->control->num++;
6985 -+ return NULL;
6986 -+}
6987 -+
6988 -+static const char* child_add(int type, int status,
6989 -+ apr_pool_t *pool, server_env_t *senv)
6990 -+{
6991 -+ _DBG("adding child #%d", NUM_CHILDS);
6992 -+
6993 -+ if(NUM_CHILDS >= server_limit)
6994 -+ {
6995 -+ return "Trying to use more child ID's than ServerLimit. "
6996 -+ "Increase ServerLimit in your config file.";
6997 -+ }
6998 -+
6999 -+ if (senv->chroot && !ap_is_directory(pool, senv->chroot))
7000 -+ return apr_psprintf(pool, "Error: chroot directory [%s] does not exist", senv->chroot);
7001 -+
7002 -+ CHILD_INFO_TABLE[NUM_CHILDS].senv = senv_add(senv);
7003 -+
7004 -+ if(CHILD_INFO_TABLE[NUM_CHILDS].senv == NULL)
7005 -+ {
7006 -+ return "Trying to use more server environments than ServerLimit. "
7007 -+ "Increase ServerLimit in your config file.";
7008 -+ }
7009 -+
7010 -+ if(type != CHILD_TYPE_WORKER)
7011 -+ CHILD_INFO_TABLE[NUM_CHILDS].senv->processor_id = NUM_CHILDS;
7012 -+
7013 -+ CHILD_INFO_TABLE[NUM_CHILDS].type = type;
7014 -+ CHILD_INFO_TABLE[NUM_CHILDS].sock_fd = AP_PERUSER_THISCHILD;
7015 -+ CHILD_INFO_TABLE[NUM_CHILDS].status = status;
7016 -+
7017 -+ _DBG("[%d] uid=%d gid=%d type=%d chroot=%s",
7018 -+ NUM_CHILDS, senv->uid, senv->gid, type,
7019 -+ senv->chroot);
7020 -+
7021 -+ if (senv->uid == 0 || senv->gid == 0)
7022 -+ {
7023 -+ _DBG("Assigning root user/group to a child.", 0);
7024 -+ }
7025 -+
7026 -+ child_info_image->control->num++;
7027 -+
7028 -+ return NULL;
7029 -+}
7030 -+
7031 -+static int make_child(server_rec *s, int slot)
7032 -+{
7033 -+ int pid;
7034 -+
7035 -+ _DBG("function entered", 0);
7036 -+ dump_server_env_image();
7037 -+
7038 -+ switch (CHILD_INFO_TABLE[slot].type)
7039 -+ {
7040 -+ case CHILD_TYPE_MULTIPLEXER: break;
7041 -+ case CHILD_TYPE_PROCESSOR: break;
7042 -+ case CHILD_TYPE_WORKER: break;
7043 -+
7044 -+ default:
7045 -+ _DBG("no valid client in slot %d", slot);
7046 -+ /* sleep(1); */
7047 -+ return 0;
7048 -+ }
7049 -+
7050 -+ if (slot + 1 > ap_max_daemons_limit) {
7051 -+ ap_max_daemons_limit = slot + 1;
7052 -+ }
7053 -+
7054 -+ if (one_process) {
7055 -+ apr_signal(SIGHUP, just_die);
7056 -+ /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */
7057 -+ apr_signal(SIGINT, just_die);
7058 -+#ifdef SIGQUIT
7059 -+ apr_signal(SIGQUIT, SIG_DFL);
7060 -+#endif
7061 -+ apr_signal(SIGTERM, just_die);
7062 -+ child_main(slot);
7063 -+ }
7064 -+
7065 -+ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
7066 -+ (request_rec *) NULL);
7067 -+
7068 -+ CHILD_INFO_TABLE[slot].status = CHILD_STATUS_READY;
7069 -+
7070 -+
7071 -+#ifdef _OSD_POSIX
7072 -+ /* BS2000 requires a "special" version of fork() before a setuid() call */
7073 -+ if ((pid = os_fork(unixd_config.user_name)) == -1) {
7074 -+#elif defined(TPF)
7075 -+ if ((pid = os_fork(s, slot)) == -1) {
7076 -+#else
7077 -+ if ((pid = fork()) == -1) {
7078 -+#endif
7079 -+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, "fork: Unable to fork new process");
7080 -+
7081 -+ /* fork didn't succeed. Fix the scoreboard or else
7082 -+ * it will say SERVER_STARTING forever and ever
7083 -+ */
7084 -+ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD,
7085 -+ (request_rec *) NULL);
7086 -+
7087 -+ /* In case system resources are maxxed out, we don't want
7088 -+ Apache running away with the CPU trying to fork over and
7089 -+ over and over again. */
7090 -+ sleep(10);
7091 -+
7092 -+ return -1;
7093 -+ }
7094 -+
7095 -+ if (!pid) {
7096 -+#ifdef HAVE_BINDPROCESSOR
7097 -+ /* by default AIX binds to a single processor
7098 -+ * this bit unbinds children which will then bind to another cpu
7099 -+ */
7100 -+ int status = bindprocessor(BINDPROCESS, (int)getpid(),
7101 -+ PROCESSOR_CLASS_ANY);
7102 -+ if (status != OK) {
7103 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
7104 -+ ap_server_conf, "processor unbind failed %d", status);
7105 -+ }
7106 -+#endif
7107 -+ RAISE_SIGSTOP(MAKE_CHILD);
7108 -+ AP_MONCONTROL(1);
7109 -+ /* Disable the parent's signal handlers and set up proper handling in
7110 -+ * the child.
7111 -+ */
7112 -+ apr_signal(SIGHUP, just_die);
7113 -+ apr_signal(SIGTERM, just_die);
7114 -+ /* The child process doesn't do anything for AP_SIG_GRACEFUL.
7115 -+ * Instead, the pod is used for signalling graceful restart.
7116 -+ */
7117 -+ /* apr_signal(AP_SIG_GRACEFUL, restart); */
7118 -+ child_main(slot);
7119 -+ clean_child_exit(0);
7120 -+ }
7121 -+
7122 -+ ap_scoreboard_image->parent[slot].pid = pid;
7123 -+ CHILD_INFO_TABLE[slot].pid = pid;
7124 -+
7125 -+ ap_child_table[slot].pid = pid;
7126 -+ ap_child_table[slot].status = SERVER_ALIVE;
7127 -+
7128 -+ return 0;
7129 -+}
7130 -+
7131 -+
7132 -+/*
7133 -+ * idle_spawn_rate is the number of children that will be spawned on the
7134 -+ * next maintenance cycle if there aren't enough idle servers. It is
7135 -+ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
7136 -+ * without the need to spawn.
7137 -+ */
7138 -+static int idle_spawn_rate = 1;
7139 -+#ifndef MAX_SPAWN_RATE
7140 -+#define MAX_SPAWN_RATE (32)
7141 -+#endif
7142 -+static int total_processes(int child_num)
7143 -+{
7144 -+ int i, total;
7145 -+ for(i = 0, total = 0; i < NUM_CHILDS; ++i)
7146 -+ {
7147 -+ if(CHILD_INFO_TABLE[i].senv == CHILD_INFO_TABLE[child_num].senv &&
7148 -+ (!(CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR &&
7149 -+ CHILD_INFO_TABLE[i].status == CHILD_STATUS_STANDBY)))
7150 -+ {
7151 -+ total++;
7152 -+ }
7153 -+ }
7154 -+ return total;
7155 -+}
7156 -+
7157 -+static void perform_idle_server_maintenance(apr_pool_t *p)
7158 -+{
7159 -+ int i;
7160 -+ apr_time_t now;
7161 -+
7162 -+ /* _DBG("function entered", 0); */
7163 -+
7164 -+ now = apr_time_now();
7165 -+
7166 -+ for (i = 0; i < NUM_CHILDS; ++i)
7167 -+ {
7168 -+ if(CHILD_INFO_TABLE[i].pid == 0)
7169 -+ {
7170 -+ if(CHILD_INFO_TABLE[i].status == CHILD_STATUS_STARTING)
7171 -+ make_child(ap_server_conf, i);
7172 -+ }
7173 -+ else if(
7174 -+ (((CHILD_INFO_TABLE[i].type == CHILD_TYPE_PROCESSOR ||
7175 -+ CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER) &&
7176 -+ ap_scoreboard_image->parent[i].pid > 1) &&
7177 -+ (idle_processors (i) > CHILD_INFO_TABLE[i].senv->min_free_processors || CHILD_INFO_TABLE[i].senv->min_free_processors == 0) &&
7178 -+ total_processes (i) > CHILD_INFO_TABLE[i].senv->min_processors &&
7179 -+ (
7180 -+ (expire_timeout > 0 && ap_scoreboard_image->servers[i][0].status != SERVER_DEAD &&
7181 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > expire_timeout) ||
7182 -+ (idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
7183 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > idle_timeout) ||
7184 -+ (CHILD_INFO_TABLE[i].senv->max_free_processors > 0 && CHILD_INFO_TABLE[i].status == CHILD_STATUS_READY &&
7185 -+ idle_processors(i) > CHILD_INFO_TABLE[i].senv->max_free_processors))
7186 -+ )
7187 -+ || (CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER &&
7188 -+ (multiplexer_idle_timeout > 0 && ap_scoreboard_image->servers[i][0].status == SERVER_READY &&
7189 -+ apr_time_sec(now - ap_scoreboard_image->servers[i][0].last_used) > multiplexer_idle_timeout) &&
7190 -+ total_processors(i) > CHILD_INFO_TABLE[i].senv->min_processors
7191 -+ )
7192 -+ )
7193 -+ {
7194 -+ CHILD_INFO_TABLE[i].pid = 0;
7195 -+ CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY;
7196 -+
7197 -+ if(CHILD_INFO_TABLE[i].type == CHILD_TYPE_WORKER || CHILD_INFO_TABLE[i].type == CHILD_TYPE_MULTIPLEXER)
7198 -+ {
7199 -+ /* completely free up this slot */
7200 -+
7201 -+ CHILD_INFO_TABLE[i].senv = (server_env_t*)NULL;
7202 -+ CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN;
7203 -+ CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */
7204 -+ }
7205 -+ if(kill(ap_scoreboard_image->parent[i].pid, SIGTERM) == -1)
7206 -+ {
7207 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
7208 -+ ap_server_conf, "kill SIGTERM");
7209 -+ }
7210 -+
7211 -+
7212 -+ ap_update_child_status_from_indexes(i, 0, SERVER_DEAD, NULL);
7213 -+ }
7214 -+ }
7215 -+
7216 -+ for(i=0;i<grace_children;i++) {
7217 -+ if (child_grace_info_table[i].pid > 0 && expire_timeout > 0 &&
7218 -+ apr_time_sec(now - child_grace_info_table[i].last_used) > expire_timeout) {
7219 -+
7220 -+ _DBG("Killing a child from last graceful (pid=%d,childno=%d,last_used=%d)",
7221 -+ child_grace_info_table[i].pid, child_grace_info_table[i].id,
7222 -+ child_grace_info_table[i].last_used);
7223 -+
7224 -+ if(kill(child_grace_info_table[i].pid, SIGTERM) == -1)
7225 -+ {
7226 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
7227 -+ ap_server_conf, "kill SIGTERM");
7228 -+ }
7229 -+
7230 -+ /* We don't need to do remove_grace_child() here,
7231 -+ * because it will be automatically done once
7232 -+ * the child dies by ap_mpm_run() */
7233 -+ }
7234 -+ }
7235 -+}
7236 -+
7237 -+int remove_grace_child(int slot) {
7238 -+ if (slot < grace_children) {
7239 -+ child_grace_info_table[slot].id = 0;
7240 -+ child_grace_info_table[slot].pid = 0;
7241 -+ child_grace_info_table[slot].status = CHILD_STATUS_STANDBY;
7242 -+ child_grace_info_table[slot].type = CHILD_TYPE_UNKNOWN;
7243 -+ child_grace_info_table[slot].last_used = 0;
7244 -+ grace_children_alive--;
7245 -+
7246 -+ if (grace_children_alive <= 0) { /* All children have returned from graceful */
7247 -+ _DBG("Every child has returned from graceful restart - freeing child_grace_info_table");
7248 -+ grace_children_alive = 0;
7249 -+ is_graceful = 0;
7250 -+ grace_children = 0;
7251 -+ free(child_grace_info_table);
7252 -+ }
7253 -+ return 0;
7254 -+ }
7255 -+ return 1;
7256 -+}
7257 -+
7258 -+/*****************************************************************
7259 -+ * Executive routines.
7260 -+ */
7261 -+
7262 -+int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
7263 -+{
7264 -+ int i;
7265 -+/* int fd; */
7266 -+ apr_status_t rv;
7267 -+ apr_size_t one = 1;
7268 -+/* apr_socket_t *sock = NULL; */
7269 -+
7270 -+ ap_log_pid(pconf, ap_pid_fname);
7271 -+
7272 -+ first_server_limit = server_limit;
7273 -+ if (changed_limit_at_restart) {
7274 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
7275 -+ "WARNING: Attempt to change ServerLimit "
7276 -+ "ignored during restart");
7277 -+ changed_limit_at_restart = 0;
7278 -+ }
7279 -+
7280 -+ ap_server_conf = s;
7281 -+
7282 -+ /* Initialize cross-process accept lock */
7283 -+ ap_lock_fname = apr_psprintf(_pconf, "%s.%" APR_PID_T_FMT,
7284 -+ ap_server_root_relative(_pconf, ap_lock_fname),
7285 -+ ap_my_pid);
7286 -+
7287 -+ rv = apr_proc_mutex_create(&accept_mutex, ap_lock_fname,
7288 -+ ap_accept_lock_mech, _pconf);
7289 -+ if (rv != APR_SUCCESS) {
7290 -+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
7291 -+ "Couldn't create accept lock");
7292 -+ mpm_state = AP_MPMQ_STOPPING;
7293 -+ return 1;
7294 -+ }
7295 -+
7296 -+#if APR_USE_SYSVSEM_SERIALIZE
7297 -+ if (ap_accept_lock_mech == APR_LOCK_DEFAULT ||
7298 -+ ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
7299 -+#else
7300 -+ if (ap_accept_lock_mech == APR_LOCK_SYSVSEM) {
7301 -+#endif
7302 -+ rv = unixd_set_proc_mutex_perms(accept_mutex);
7303 -+ if (rv != APR_SUCCESS) {
7304 -+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
7305 -+ "Couldn't set permissions on cross-process lock; "
7306 -+ "check User and Group directives");
7307 -+ mpm_state = AP_MPMQ_STOPPING;
7308 -+ return 1;
7309 -+ }
7310 -+ }
7311 -+
7312 -+ if (!is_graceful) {
7313 -+ if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) {
7314 -+ mpm_state = AP_MPMQ_STOPPING;
7315 -+ return 1;
7316 -+ }
7317 -+ /* fix the generation number in the global score; we just got a new,
7318 -+ * cleared scoreboard
7319 -+ */
7320 -+ ap_scoreboard_image->global->running_generation = ap_my_generation;
7321 -+ }
7322 -+
7323 -+ /* Initialize the child table */
7324 -+ if (!is_graceful)
7325 -+ {
7326 -+ for (i = 0; i < server_limit; i++)
7327 -+ {
7328 -+ ap_child_table[i].pid = 0;
7329 -+ }
7330 -+ }
7331 -+
7332 -+ /* We need to put the new listeners at the end of the ap_listeners
7333 -+ * list. If we don't, then the pool will be cleared before the
7334 -+ * open_logs phase is called for the second time, and ap_listeners
7335 -+ * will have only invalid data. If that happens, then the sockets
7336 -+ * that we opened using make_sock() will be lost, and the server
7337 -+ * won't start.
7338 -+ */
7339 -+
7340 -+/*
7341 -+ apr_os_file_get(&fd, pipe_of_death_in);
7342 -+ apr_os_sock_put(&sock, &fd, pconf);
7343 -+
7344 -+ listen_add(pconf, sock, check_pipe_of_death);
7345 -+*/
7346 -+ set_signals();
7347 -+
7348 -+ if (one_process) {
7349 -+ AP_MONCONTROL(1);
7350 -+ }
7351 -+
7352 -+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
7353 -+ "%s configured -- resuming normal operations",
7354 -+ ap_get_server_version());
7355 -+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
7356 -+ "Server built: %s", ap_get_server_built());
7357 -+#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
7358 -+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
7359 -+ "AcceptMutex: %s (default: %s)",
7360 -+ apr_proc_mutex_name(accept_mutex),
7361 -+ apr_proc_mutex_defname());
7362 -+#endif
7363 -+ restart_pending = shutdown_pending = 0;
7364 -+
7365 -+ mpm_state = AP_MPMQ_RUNNING;
7366 -+
7367 -+ _DBG("sizeof(child_info_t) = %d", sizeof(child_info_t));
7368 -+
7369 -+ while (!restart_pending && !shutdown_pending) {
7370 -+ int child_slot;
7371 -+ apr_exit_why_e exitwhy;
7372 -+ int status, processed_status;
7373 -+ /* this is a memory leak, but I'll fix it later. */
7374 -+ apr_proc_t pid;
7375 -+
7376 -+ ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
7377 -+
7378 -+ /* XXX: if it takes longer than 1 second for all our children
7379 -+ * to start up and get into IDLE state then we may spawn an
7380 -+ * extra child
7381 -+ */
7382 -+ if (pid.pid != -1) {
7383 -+ processed_status = ap_process_child_status(&pid, exitwhy, status);
7384 -+ if (processed_status == APEXIT_CHILDFATAL) {
7385 -+ mpm_state = AP_MPMQ_STOPPING;
7386 -+ return 1;
7387 -+ }
7388 -+
7389 -+ if (grace_children > 0) {
7390 -+ for(i=0;i<grace_children;i++) {
7391 -+ if (child_grace_info_table[i].pid == pid.pid) {
7392 -+ break;
7393 -+ }
7394 -+ }
7395 -+ if (i != grace_children) {
7396 -+ _DBG("Child returned from graceful (%d)", i);
7397 -+ remove_grace_child(i);
7398 -+ continue;
7399 -+ }
7400 -+ }
7401 -+
7402 -+ /* non-fatal death... note that it's gone in the scoreboard. */
7403 -+ child_slot = find_child_by_pid(&pid);
7404 -+ _DBG("child #%d has died ...", child_slot);
7405 -+
7406 -+ for (i = 0; i < ap_max_daemons_limit; ++i)
7407 -+ {
7408 -+ if (ap_child_table[i].pid == pid.pid)
7409 -+ {
7410 -+ child_slot = i;
7411 -+ break;
7412 -+ }
7413 -+ }
7414 -+
7415 -+ if (child_slot >= 0) {
7416 -+ ap_child_table[child_slot].pid = 0;
7417 -+ _TRACE_CALL("ap_update_child_status_from_indexes", 0);
7418 -+ (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,
7419 -+ (request_rec *) NULL);
7420 -+ _TRACE_RET("ap_update_child_status_from_indexes", 0);
7421 -+
7422 -+ if (processed_status == APEXIT_CHILDSICK) {
7423 -+ /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)
7424 -+ * cut the fork rate to the minimum
7425 -+ */
7426 -+ _DBG("processed_status = APEXIT_CHILDSICK", 0);
7427 -+ idle_spawn_rate = 1;
7428 -+ }
7429 -+ else if (CHILD_INFO_TABLE[child_slot].status == CHILD_STATUS_STANDBY) {
7430 -+ _DBG("leaving child in standby state", 0);
7431 -+ }
7432 -+ else if (child_slot < ap_daemons_limit &&
7433 -+ CHILD_INFO_TABLE[child_slot].type !=
7434 -+ CHILD_TYPE_UNKNOWN) {
7435 -+ /* we're still doing a 1-for-1 replacement of dead
7436 -+ * children with new children
7437 -+ */
7438 -+ _DBG("replacing by new child ...", 0);
7439 -+ make_child(ap_server_conf, child_slot);
7440 -+ }
7441 -+#if APR_HAS_OTHER_CHILD
7442 -+ }
7443 -+ else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) {
7444 -+ _DBG("Already handled", 0);
7445 -+ /* handled */
7446 -+#endif
7447 -+ }
7448 -+ else if (is_graceful) {
7449 -+ /* Great, we've probably just lost a slot in the
7450 -+ * scoreboard. Somehow we don't know about this
7451 -+ * child.
7452 -+ */
7453 -+ _DBG("long lost child came home, whatever that means", 0);
7454 -+
7455 -+ ap_log_error(APLOG_MARK, APLOG_WARNING,
7456 -+ 0, ap_server_conf,
7457 -+ "long lost child came home! (pid %ld)", (long)pid.pid);
7458 -+ }
7459 -+ /* Don't perform idle maintenance when a child dies,
7460 -+ * only do it when there's a timeout. Remember only a
7461 -+ * finite number of children can die, and it's pretty
7462 -+ * pathological for a lot to die suddenly.
7463 -+ */
7464 -+ continue;
7465 -+ }
7466 -+
7467 -+ perform_idle_server_maintenance(pconf);
7468 -+#ifdef TPF
7469 -+ shutdown_pending = os_check_server(tpf_server_name);
7470 -+ ap_check_signals();
7471 -+ sleep(1);
7472 -+#endif /*TPF */
7473 -+ }
7474 -+
7475 -+ mpm_state = AP_MPMQ_STOPPING;
7476 -+
7477 -+ if (shutdown_pending) {
7478 -+ /* Time to gracefully shut down:
7479 -+ * Kill child processes, tell them to call child_exit, etc...
7480 -+ */
7481 -+ if (unixd_killpg(getpgrp(), SIGTERM) < 0) {
7482 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGTERM");
7483 -+ }
7484 -+ ap_reclaim_child_processes(1); /* Start with SIGTERM */
7485 -+
7486 -+ /* cleanup pid file on normal shutdown */
7487 -+ {
7488 -+ const char *pidfile = NULL;
7489 -+ pidfile = ap_server_root_relative (pconf, ap_pid_fname);
7490 -+ if ( pidfile != NULL && unlink(pidfile) == 0)
7491 -+ ap_log_error(APLOG_MARK, APLOG_INFO,
7492 -+ 0, ap_server_conf,
7493 -+ "removed PID file %s (pid=%ld)",
7494 -+ pidfile, (long)getpid());
7495 -+ }
7496 -+
7497 -+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
7498 -+ "caught SIGTERM, shutting down");
7499 -+ return 1;
7500 -+ }
7501 -+
7502 -+ /* we've been told to restart */
7503 -+ apr_signal(SIGHUP, SIG_IGN);
7504 -+ if (one_process) {
7505 -+ /* not worth thinking about */
7506 -+ return 1;
7507 -+ }
7508 -+
7509 -+ /* advance to the next generation */
7510 -+ /* XXX: we really need to make sure this new generation number isn't in
7511 -+ * use by any of the children.
7512 -+ */
7513 -+ ++ap_my_generation;
7514 -+ ap_scoreboard_image->global->running_generation = ap_my_generation;
7515 -+
7516 -+ /* cleanup sockets */
7517 -+ for (i = 0; i < NUM_SENV; i++) {
7518 -+ close(SENV[i].input);
7519 -+ close(SENV[i].output);
7520 -+ }
7521 -+
7522 -+ if (is_graceful) {
7523 -+ char char_of_death = AP_PERUSER_CHAR_OF_DEATH;
7524 -+
7525 -+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
7526 -+ "Graceful restart requested, doing restart");
7527 -+
7528 -+#if 0
7529 -+ /* kill off the idle ones */
7530 -+ ap_mpm_pod_killpg(pod, ap_max_daemons_limit);
7531 -+
7532 -+ /* This is mostly for debugging... so that we know what is still
7533 -+ * gracefully dealing with existing request. This will break
7534 -+ * in a very nasty way if we ever have the scoreboard totally
7535 -+ * file-based (no shared memory)
7536 -+ */
7537 -+ for (i = 0; i < ap_daemons_limit; ++i) {
7538 -+ if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) {
7539 -+ ap_scoreboard_image->servers[i][0].status = SERVER_GRACEFUL;
7540 -+ }
7541 -+ }
7542 -+#endif
7543 -+
7544 -+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
7545 -+ ap_server_conf, AP_SIG_GRACEFUL_STRING " received. "
7546 -+ "Doing graceful restart");
7547 -+
7548 -+ /* This is mostly for debugging... so that we know what is still
7549 -+ * gracefully dealing with existing request.
7550 -+ */
7551 -+
7552 -+ int alivechildren = 0;
7553 -+ child_grace_info_t* old_grace_info;
7554 -+
7555 -+ for (i = 0; i < NUM_CHILDS; ++i)
7556 -+ {
7557 -+ ((ap_child_table[i].pid) && (ap_child_table[i].status = SERVER_DYING));
7558 -+
7559 -+ if (CHILD_INFO_TABLE[i].pid) {
7560 -+ alivechildren++;
7561 -+ }
7562 -+ }
7563 -+
7564 -+ _DBG("Initializing child_grace_info_table", 0);
7565 -+
7566 -+ if (alivechildren > 0) {
7567 -+ if (grace_children > 0) {
7568 -+ old_grace_info = child_grace_info_table;
7569 -+ _DBG("%d children still living from last graceful "
7570 -+ "- adding to new child_grace_info_table",
7571 -+ grace_children);
7572 -+ }
7573 -+
7574 -+ child_grace_info_table = (child_grace_info_t*)calloc(alivechildren+grace_children,
7575 -+ sizeof(child_grace_info_t));
7576 -+
7577 -+ if (grace_children > 0) {
7578 -+ for(i=0;i<grace_children;i++) {
7579 -+ child_grace_info_table[i] = old_grace_info[i];
7580 -+ }
7581 -+ grace_children = i;
7582 -+ free(old_grace_info);
7583 -+ }
7584 -+ else grace_children = 0;
7585 -+
7586 -+ }
7587 -+
7588 -+ /* give the children the signal to die */
7589 -+ for (i = 0; i < NUM_CHILDS;)
7590 -+ {
7591 -+ if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS)
7592 -+ {
7593 -+ if (APR_STATUS_IS_EINTR(rv)) continue;
7594 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
7595 -+ "write pipe_of_death");
7596 -+ }
7597 -+ if (CHILD_INFO_TABLE[i].pid) {
7598 -+ child_grace_info_table[grace_children].id = CHILD_INFO_TABLE[i].id;
7599 -+ child_grace_info_table[grace_children].pid = CHILD_INFO_TABLE[i].pid;
7600 -+ child_grace_info_table[grace_children].status = CHILD_INFO_TABLE[i].status;
7601 -+ child_grace_info_table[grace_children].type = CHILD_INFO_TABLE[i].type;
7602 -+ child_grace_info_table[grace_children].last_used= ap_scoreboard_image->servers[i][0].last_used;
7603 -+ grace_children++;
7604 -+ grace_children_alive++;
7605 -+ }
7606 -+ i++;
7607 -+ }
7608 -+ _DBG("Total children of %d leaving behind for graceful restart (%d living)",
7609 -+ grace_children, grace_children_alive);
7610 -+ }
7611 -+ else {
7612 -+ /* Kill 'em off */
7613 -+ if (unixd_killpg(getpgrp(), SIGHUP) < 0) {
7614 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "killpg SIGHUP");
7615 -+ }
7616 -+ ap_reclaim_child_processes(0); /* Not when just starting up */
7617 -+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
7618 -+ "SIGHUP received. Attempting to restart");
7619 -+ }
7620 -+
7621 -+ return 0;
7622 -+}
7623 -+
7624 -+/* == allocate an private server config structure == */
7625 -+static void *peruser_create_config(apr_pool_t *p, server_rec *s)
7626 -+{
7627 -+ peruser_server_conf *c = (peruser_server_conf *)
7628 -+ apr_pcalloc(p, sizeof(peruser_server_conf));
7629 -+
7630 -+ c->senv = NULL;
7631 -+ c->missing_senv_reported = 0;
7632 -+
7633 -+ return c;
7634 -+}
7635 -+
7636 -+/* This really should be a post_config hook, but the error log is already
7637 -+ * redirected by that point, so we need to do this in the open_logs phase.
7638 -+ */
7639 -+static int peruser_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
7640 -+{
7641 -+ apr_status_t rv;
7642 -+
7643 -+ pconf = p;
7644 -+ ap_server_conf = s;
7645 -+
7646 -+ if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
7647 -+ ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
7648 -+ NULL, "no listening sockets available, shutting down");
7649 -+ return DONE;
7650 -+ }
7651 -+
7652 -+ ap_log_pid(pconf, ap_pid_fname);
7653 -+
7654 -+ if ((rv = ap_mpm_pod_open(pconf, &pod))) {
7655 -+ ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL,
7656 -+ "Could not open pipe-of-death.");
7657 -+ return DONE;
7658 -+ }
7659 -+
7660 -+ if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out,
7661 -+ pconf)) != APR_SUCCESS) {
7662 -+ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
7663 -+ (const server_rec*) ap_server_conf,
7664 -+ "apr_file_pipe_create (pipe_of_death)");
7665 -+ exit(1);
7666 -+ }
7667 -+ if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
7668 -+ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
7669 -+ (const server_rec*) ap_server_conf,
7670 -+ "apr_file_pipe_timeout_set (pipe_of_death)");
7671 -+ exit(1);
7672 -+ }
7673 -+
7674 -+ return OK;
7675 -+}
7676 -+
7677 -+static int restart_num = 0;
7678 -+static int peruser_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
7679 -+{
7680 -+ int no_detach, debug, foreground, i;
7681 -+ int tmp_server_limit = DEFAULT_SERVER_LIMIT;
7682 -+ ap_directive_t *pdir;
7683 -+ apr_status_t rv;
7684 -+ apr_pool_t *global_pool;
7685 -+ void *shmem;
7686 -+
7687 -+ mpm_state = AP_MPMQ_STARTING;
7688 -+
7689 -+ debug = ap_exists_config_define("DEBUG");
7690 -+
7691 -+ if (debug) {
7692 -+ foreground = one_process = 1;
7693 -+ no_detach = 0;
7694 -+ }
7695 -+ else
7696 -+ {
7697 -+ no_detach = ap_exists_config_define("NO_DETACH");
7698 -+ one_process = ap_exists_config_define("ONE_PROCESS");
7699 -+ foreground = ap_exists_config_define("FOREGROUND");
7700 -+ }
7701 -+
7702 -+ /* sigh, want this only the second time around */
7703 -+ if (restart_num++ == 1) {
7704 -+ if (!one_process && !foreground) {
7705 -+ rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
7706 -+ : APR_PROC_DETACH_DAEMONIZE);
7707 -+ if (rv != APR_SUCCESS) {
7708 -+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
7709 -+ "apr_proc_detach failed");
7710 -+ return HTTP_INTERNAL_SERVER_ERROR;
7711 -+ }
7712 -+ }
7713 -+
7714 -+ parent_pid = ap_my_pid = getpid();
7715 -+ }
7716 -+
7717 -+ unixd_pre_config(ptemp);
7718 -+ ap_listen_pre_config();
7719 -+ ap_min_processors = DEFAULT_MIN_PROCESSORS;
7720 -+ ap_min_free_processors = DEFAULT_MIN_FREE_PROCESSORS;
7721 -+ ap_max_free_processors = DEFAULT_MAX_FREE_PROCESSORS;
7722 -+ ap_max_processors = DEFAULT_MAX_PROCESSORS;
7723 -+ ap_min_multiplexers = DEFAULT_MIN_MULTIPLEXERS;
7724 -+ ap_max_multiplexers = DEFAULT_MAX_MULTIPLEXERS;
7725 -+ ap_daemons_limit = server_limit;
7726 -+ ap_pid_fname = DEFAULT_PIDLOG;
7727 -+ ap_lock_fname = DEFAULT_LOCKFILE;
7728 -+ ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
7729 -+ ap_extended_status = 1;
7730 -+#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
7731 -+ ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
7732 -+#endif
7733 -+
7734 -+ expire_timeout = DEFAULT_EXPIRE_TIMEOUT;
7735 -+ idle_timeout = DEFAULT_IDLE_TIMEOUT;
7736 -+ multiplexer_idle_timeout = DEFAULT_MULTIPLEXER_IDLE_TIMEOUT;
7737 -+ processor_wait_timeout = DEFAULT_PROCESSOR_WAIT_TIMEOUT;
7738 -+ processor_wait_steps = DEFAULT_PROCESSOR_WAIT_STEPS;
7739 -+
7740 -+
7741 -+ apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
7742 -+
7743 -+ /* we need to know ServerLimit and ThreadLimit before we start processing
7744 -+ * the tree because we need to already have allocated child_info_table
7745 -+ */
7746 -+ for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next)
7747 -+ {
7748 -+ if (!strcasecmp(pdir->directive, "ServerLimit"))
7749 -+ {
7750 -+ if (atoi(pdir->args) > tmp_server_limit)
7751 -+ {
7752 -+ tmp_server_limit = atoi(pdir->args);
7753 -+ if (tmp_server_limit > MAX_SERVER_LIMIT)
7754 -+ {
7755 -+ tmp_server_limit = MAX_SERVER_LIMIT;
7756 -+ }
7757 -+ }
7758 -+ }
7759 -+ }
7760 -+
7761 -+ /* We don't want to have to recreate the scoreboard after
7762 -+ * restarts, so we'll create a global pool and never clean it.
7763 -+ */
7764 -+ rv = apr_pool_create(&global_pool, NULL);
7765 -+ if (rv != APR_SUCCESS) {
7766 -+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
7767 -+ "Fatal error: unable to create global pool");
7768 -+ return rv;
7769 -+ }
7770 -+
7771 -+ if (!child_info_image) {
7772 -+ _DBG("Initializing child_info_table", 0);
7773 -+ child_info_size = tmp_server_limit * sizeof(child_info_t) + sizeof(apr_size_t);
7774 -+
7775 -+ rv = apr_shm_create(&child_info_shm, child_info_size, NULL, global_pool);
7776 -+
7777 -+ /* if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { */
7778 -+ if (rv != APR_SUCCESS) {
7779 -+ _DBG("shared memory creation failed", 0);
7780 -+
7781 -+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
7782 -+ "Unable to create shared memory segment "
7783 -+ "(anonymous shared memory failure)");
7784 -+ }
7785 -+ else if (rv == APR_ENOTIMPL) {
7786 -+ _DBG("anonymous shared memory not available", 0);
7787 -+ /* TODO: make up a filename and do name-based shmem */
7788 -+ }
7789 -+
7790 -+ if (rv || !(shmem = apr_shm_baseaddr_get(child_info_shm))) {
7791 -+ _DBG("apr_shm_baseaddr_get() failed", 0);
7792 -+ return HTTP_INTERNAL_SERVER_ERROR;
7793 -+ }
7794 -+
7795 -+ memset(shmem, 0, child_info_size);
7796 -+ child_info_image = (child_info*)apr_palloc(global_pool, sizeof(child_info));
7797 -+ child_info_image->control = (child_info_control*)shmem;
7798 -+ shmem += sizeof(child_info_control);
7799 -+ child_info_image->table = (child_info_t*)shmem;
7800 -+ }
7801 -+
7802 -+ _DBG("Clearing child_info_table");
7803 -+ child_info_image->control->num = 0;
7804 -+
7805 -+ for (i = 0; i < tmp_server_limit; i++) {
7806 -+ CHILD_INFO_TABLE[i].pid = 0;
7807 -+ CHILD_INFO_TABLE[i].senv = (server_env_t*)NULL;
7808 -+ CHILD_INFO_TABLE[i].type = CHILD_TYPE_UNKNOWN;
7809 -+ CHILD_INFO_TABLE[i].status = CHILD_STATUS_STANDBY;
7810 -+ CHILD_INFO_TABLE[i].sock_fd = -3; /* -1 and -2 are taken */
7811 -+ CHILD_INFO_TABLE[i].id = i;
7812 -+ }
7813 -+
7814 -+ if (!server_env_image)
7815 -+ {
7816 -+ _DBG("Initializing server_environments_table", 0);
7817 -+ server_env_size = tmp_server_limit * sizeof(server_env_t) + sizeof(apr_size_t);
7818 -+
7819 -+ rv = apr_shm_create(&server_env_shm, server_env_size, NULL, global_pool);
7820 -+
7821 -+ if (rv != APR_SUCCESS) {
7822 -+ _DBG("shared memory creation failed", 0);
7823 -+
7824 -+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
7825 -+ "Unable to create shared memory segment "
7826 -+ "(anonymous shared memory failure)");
7827 -+ }
7828 -+ else if (rv == APR_ENOTIMPL) {
7829 -+ _DBG("anonymous shared memory not available", 0);
7830 -+ /* TODO: make up a filename and do name-based shmem */
7831 -+ }
7832 -+
7833 -+ if (rv || !(shmem = apr_shm_baseaddr_get(server_env_shm))) {
7834 -+ _DBG("apr_shm_baseaddr_get() failed", 0);
7835 -+ return HTTP_INTERNAL_SERVER_ERROR;
7836 -+ }
7837 -+
7838 -+ memset(shmem, 0, server_env_size);
7839 -+ server_env_image = (server_env*)apr_palloc(global_pool, sizeof(server_env));
7840 -+ server_env_image->control = (server_env_control*)shmem;
7841 -+ shmem += sizeof(server_env_control);
7842 -+ server_env_image->table = (server_env_t*)shmem;
7843 -+ }
7844 -+
7845 -+ _DBG("Clearing server environment table");
7846 -+ server_env_image->control->num = 0;
7847 -+
7848 -+ for (i = 0; i < tmp_server_limit; i++) {
7849 -+ SENV[i].processor_id = -1;
7850 -+ SENV[i].uid = -1;
7851 -+ SENV[i].gid = -1;
7852 -+ SENV[i].chroot = NULL;
7853 -+ SENV[i].input = -1;
7854 -+ SENV[i].output = -1;
7855 -+ SENV[i].error_cgroup = 0;
7856 -+ SENV[i].error_pass = 0;
7857 -+ }
7858 -+
7859 -+ return OK;
7860 -+}
7861 -+
7862 -+static int peruser_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server_list)
7863 -+{
7864 -+ server_env_t senv;
7865 -+ const char *r;
7866 -+
7867 -+ ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable));
7868 -+
7869 -+ /* Retrieve the function from mod_ssl for detecting SSL virtualhosts */
7870 -+ ssl_server_is_https = (ssl_server_is_https_t) apr_dynamic_fn_retrieve("ssl_server_is_https");
7871 -+
7872 -+ /* Create the server environment for multiplexers */
7873 -+ senv.uid = unixd_config.user_id;
7874 -+ senv.gid = unixd_config.group_id;
7875 -+ senv.chroot = multiplexer_chroot;
7876 -+ senv.cgroup = NULL;
7877 -+ senv.nice_lvl = 0;
7878 -+ senv.name = NULL;
7879 -+
7880 -+ senv.min_processors = ap_min_multiplexers;
7881 -+ senv.min_free_processors = ap_min_free_processors;
7882 -+ senv.max_free_processors = ap_max_free_processors;
7883 -+ senv.max_processors = ap_max_multiplexers;
7884 -+
7885 -+ r = child_add(CHILD_TYPE_MULTIPLEXER, CHILD_STATUS_STARTING,
7886 -+ p, &senv);
7887 -+
7888 -+ if (r != NULL) {
7889 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, p, r);
7890 -+ return -1;
7891 -+ }
7892 -+
7893 -+ return OK;
7894 -+}
7895 -+
7896 -+static int peruser_post_read(request_rec *r)
7897 -+{
7898 -+ _DBG("function entered");
7899 -+
7900 -+ peruser_server_conf *sconf = PERUSER_SERVER_CONF(r->server->module_config);
7901 -+ child_info_t *processor;
7902 -+
7903 -+ if (sconf->senv == NULL) {
7904 -+ _DBG("Server environment not set on virtualhost %s", r->server->server_hostname);
7905 -+
7906 -+ if (sconf->missing_senv_reported == 0) {
7907 -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf,
7908 -+ "Virtualhost %s has no server environment set, "
7909 -+ "request will not be honoured.", r->server->server_hostname);
7910 -+ }
7911 -+
7912 -+ sconf->missing_senv_reported = 1;
7913 -+
7914 -+ return HTTP_INTERNAL_SERVER_ERROR;
7915 -+ }
7916 -+
7917 -+ if(CHILD_INFO_TABLE[my_child_num].type == CHILD_TYPE_MULTIPLEXER)
7918 -+ processor = &CHILD_INFO_TABLE[sconf->senv->processor_id];
7919 -+ else
7920 -+ processor = &CHILD_INFO_TABLE[r->connection->id];
7921 -+
7922 -+
7923 -+ if (!strlen(r->the_request))
7924 -+ {
7925 -+ _DBG("corrupt request. aborting",0);
7926 -+ return DECLINED;
7927 -+ }
7928 -+
7929 -+ if (processor->sock_fd != AP_PERUSER_THISCHILD)
7930 -+ {
7931 -+ apr_socket_t *sock = NULL;
7932 -+
7933 -+ apr_os_sock_put(&sock, &processor->sock_fd, r->connection->pool);
7934 -+ ap_sock_disable_nagle(sock);
7935 -+ ap_set_module_config(r->connection->conn_config, &core_module, sock);
7936 -+ _DBG("not the right socket?", 0);
7937 -+ return OK;
7938 -+ }
7939 -+
7940 -+ switch (CHILD_INFO_TABLE[my_child_num].type)
7941 -+ {
7942 -+ case CHILD_TYPE_MULTIPLEXER:
7943 -+ {
7944 -+ _DBG("MULTIPLEXER => Determining if request should be passed. "
7945 -+ "Child Num: %d, dest-child: %d, hostname from server: %s r->hostname=%s r->the_request=\"%s\"",
7946 -+ my_child_num, processor->id, r->server->server_hostname, r->hostname, r->the_request);
7947 -+
7948 -+ if (processor->id != my_child_num)
7949 -+ {
7950 -+ if (processor->status == CHILD_STATUS_STANDBY)
7951 -+ {
7952 -+ _DBG("Activating child #%d", processor->id);
7953 -+ processor->status = CHILD_STATUS_STARTING;
7954 -+ }
7955 -+
7956 -+ _DBG("Passing request.",0);
7957 -+ if (pass_request(r, processor) == -1)
7958 -+ {
7959 -+ if (processor->senv->error_pass == 0) {
7960 -+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
7961 -+ ap_server_conf, "Could not pass request to processor %s (virtualhost %s), request will not be honoured.",
7962 -+ processor->senv->name, r->hostname);
7963 -+ }
7964 -+
7965 -+ processor->senv->error_pass = 1;
7966 -+
7967 -+ return HTTP_SERVICE_UNAVAILABLE;
7968 -+ }
7969 -+ else {
7970 -+ processor->senv->error_pass = 0;
7971 -+ }
7972 -+
7973 -+ _DBG("doing longjmp",0);
7974 -+ longjmp(CHILD_INFO_TABLE[my_child_num].jmpbuffer, 1);
7975 -+ _DBG("request declined at our site",0);
7976 -+ return DECLINED;
7977 -+ }
7978 -+ _DBG("WTF: the server is assigned to the multiplexer! ... dropping request",0);
7979 -+ return DECLINED;
7980 -+ }
7981 -+ case CHILD_TYPE_PROCESSOR:
7982 -+ case CHILD_TYPE_WORKER:
7983 -+ {
7984 -+ if (sconf->senv != CHILD_INFO_TABLE[my_child_num].senv) {
7985 -+ ap_log_error(APLOG_MARK, APLOG_WARNING,
7986 -+ 0, ap_server_conf,
7987 -+ "invalid virtualhost for this child! (%s)", r->hostname);
7988 -+ ap_lingering_close(r->connection);
7989 -+ return HTTP_REQUEST_TIME_OUT;
7990 -+ }
7991 -+
7992 -+ _DBG("%s %d", child_type_string(CHILD_INFO_TABLE[my_child_num].type), my_child_num);
7993 -+ _DBG("request for %s / (server %s) seems to be for us", r->hostname, r->server->server_hostname);
7994 -+
7995 -+ if (server_env_cleanup)
7996 -+ {
7997 -+ int i;
7998 -+ int input = sconf->senv->input;
7999 -+ int output = sconf->senv->output;
8000 -+
8001 -+ _DBG("performing handle cleanup");
8002 -+ for (i = 0; i < NUM_SENV; i++)
8003 -+ {
8004 -+ if (SENV[i].input > 0 && SENV[i].input != input) {
8005 -+ int retval = close(SENV[i].input);
8006 -+ if (retval < 0) {
8007 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
8008 -+ "close(%d) failed", SENV[i].input);
8009 -+ }
8010 -+ }
8011 -+ if (SENV[i].output > 0 && SENV[i].output != output) {
8012 -+ int retval = close(SENV[i].output);
8013 -+ if (retval < 0) {
8014 -+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
8015 -+ "close(%d) failed", SENV[i].output);
8016 -+ }
8017 -+ }
8018 -+ }
8019 -+ server_env_cleanup = 0;
8020 -+ }
8021 -+
8022 -+ return OK;
8023 -+ }
8024 -+ default:
8025 -+ {
8026 -+ _DBG("unspecified child type %d in %d, dropping request",
8027 -+ CHILD_INFO_TABLE[my_child_num].type, my_child_num);
8028 -+ return DECLINED;
8029 -+ }
8030 -+ }
8031 -+
8032 -+ _DBG("THIS POINT SHOULD NOT BE REACHED!",0);
8033 -+ return OK;
8034 -+}
8035 -+
8036 -+static int peruser_status_hook(request_rec *r, int flags)
8037 -+{
8038 -+ int x;
8039 -+ server_env_t *senv;
8040 -+
8041 -+ if (flags & AP_STATUS_SHORT)
8042 -+ return OK;
8043 -+
8044 -+ ap_rputs("<hr>\n", r);
8045 -+ ap_rputs("<h2>peruser status</h2>\n", r);
8046 -+ ap_rputs("<table border=\"0\">\n", r);
8047 -+ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>SB STATUS</td><td>TYPE</td><td>UID</td>"
8048 -+ "<td>GID</td><td>CHROOT</td><td>NICE</td><td>INPUT</td>"
8049 -+ "<td>OUTPUT</td><td>SOCK_FD</td>"
8050 -+ "<td>TOTAL PROCESSORS</td><td>MAX PROCESSORS</td>"
8051 -+ "<td>IDLE PROCESSORS</td><td>MIN FREE PROCESSORS</td>"
8052 -+ "<td>AVAIL</td>"
8053 -+ "</tr>\n", r);
8054 -+ for (x = 0; x < NUM_CHILDS; x++)
8055 -+ {
8056 -+ senv = CHILD_INFO_TABLE[x].senv;
8057 -+ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%8s</td><td>%12s</td>"
8058 -+ "<td>%4d</td><td>%4d</td><td>%25s</td><td>%3d</td><td>%5d</td>"
8059 -+ "<td>%6d</td><td>%7d</td><td>%d</td><td>%d</td>"
8060 -+ "<td>%d</td><td>%d</td><td>%3d</td></tr>\n",
8061 -+ CHILD_INFO_TABLE[x].id,
8062 -+ CHILD_INFO_TABLE[x].pid,
8063 -+ child_status_string(CHILD_INFO_TABLE[x].status),
8064 -+ scoreboard_status_string(SCOREBOARD_STATUS(x)),
8065 -+ child_type_string(CHILD_INFO_TABLE[x].type),
8066 -+ senv == NULL ? -1 : senv->uid,
8067 -+ senv == NULL ? -1 : senv->gid,
8068 -+ senv == NULL ? NULL : senv->chroot,
8069 -+ senv == NULL ? 0 : senv->nice_lvl,
8070 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->input,
8071 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->output,
8072 -+ CHILD_INFO_TABLE[x].sock_fd,
8073 -+ total_processors(x),
8074 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->max_processors,
8075 -+ idle_processors(x),
8076 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->min_free_processors,
8077 -+ senv == NULL ? -1 : CHILD_INFO_TABLE[x].senv->availability
8078 -+ );
8079 -+ }
8080 -+ ap_rputs("</table>\n", r);
8081 -+
8082 -+ if (grace_children > 0) {
8083 -+ ap_rputs("<h2>peruser graceful children status</h2>\n", r);
8084 -+ ap_rprintf(r, "%d of total %d still living<br />\n", grace_children_alive, grace_children);
8085 -+ ap_rputs("<table border=\"0\">\n", r);
8086 -+ ap_rputs("<tr><td>ID</td><td>PID</td><td>STATUS</td><td>TYPE</td></tr>\n", r);
8087 -+ for (x = 0; x < grace_children; x++) {
8088 -+ ap_rprintf(r, "<tr><td>%3d</td><td>%5d</td><td>%8s</td><td>%12s</td></tr>\n",
8089 -+ child_grace_info_table[x].id,
8090 -+ child_grace_info_table[x].pid,
8091 -+ child_status_string(child_grace_info_table[x].status),
8092 -+ child_type_string(child_grace_info_table[x].type)
8093 -+ );
8094 -+ }
8095 -+ ap_rputs("</table>\n", r);
8096 -+ }
8097 -+ return OK;
8098 -+}
8099 -+
8100 -+static void peruser_hooks(apr_pool_t *p)
8101 -+{
8102 -+ /* The peruser open_logs phase must run before the core's, or stderr
8103 -+ * will be redirected to a file, and the messages won't print to the
8104 -+ * console.
8105 -+ */
8106 -+ static const char *const aszSucc[] = {"core.c", NULL};
8107 -+
8108 -+#ifdef AUX3
8109 -+ (void) set42sig();
8110 -+#endif
8111 -+
8112 -+ ap_hook_open_logs(peruser_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
8113 -+ ap_hook_pre_config(peruser_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
8114 -+ ap_hook_post_config(peruser_post_config, NULL, NULL, APR_HOOK_MIDDLE);
8115 -+
8116 -+ /* Both of these must be run absolutely first. If this request isn't for
8117 -+ * this server then we need to forward it to the proper child. No sense
8118 -+ * tying up this server running more post_read request hooks if it is
8119 -+ * just going to be forwarded along. The process_connection hook allows
8120 -+ * peruser to receive the passed request correctly, by automatically
8121 -+ * filling in the core_input_filter's ctx pointer.
8122 -+ */
8123 -+ ap_hook_post_read_request(peruser_post_read, NULL, NULL,
8124 -+ APR_HOOK_REALLY_FIRST);
8125 -+ ap_hook_process_connection(peruser_process_connection, NULL, NULL,
8126 -+ APR_HOOK_REALLY_FIRST);
8127 -+
8128 -+ APR_OPTIONAL_HOOK(ap, status_hook, peruser_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
8129 -+}
8130 -+
8131 -+void senv_init(server_env_t * senv) {
8132 -+ senv->nice_lvl = 0;
8133 -+ senv->chroot = NULL;
8134 -+ senv->cgroup = NULL;
8135 -+ senv->min_processors = ap_min_processors;
8136 -+ senv->min_free_processors = ap_min_free_processors;
8137 -+ senv->max_free_processors = ap_max_free_processors;
8138 -+ senv->max_processors = ap_max_processors;
8139 -+}
8140 -+
8141 -+static const char *cf_Processor(cmd_parms *cmd, void *dummy, const char *arg)
8142 -+{
8143 -+ const char *user_name = NULL, *group_name = NULL, *directive;
8144 -+ server_env_t senv;
8145 -+ ap_directive_t *current;
8146 -+
8147 -+ const char *endp = ap_strrchr_c(arg, '>');
8148 -+
8149 -+ if (endp == NULL) {
8150 -+ return apr_psprintf(cmd->temp_pool,
8151 -+ "Error: Directive %s> missing closing '>'", cmd->cmd->name);
8152 -+ }
8153 -+
8154 -+ arg = apr_pstrndup(cmd->pool, arg, endp - arg);
8155 -+
8156 -+ if (!arg) {
8157 -+ return apr_psprintf(cmd->temp_pool,
8158 -+ "Error: %s> must specify a processor name", cmd->cmd->name);
8159 -+ }
8160 -+
8161 -+ senv.name = ap_getword_conf(cmd->pool, &arg);
8162 -+ _DBG("processor_name: %s", senv.name);
8163 -+
8164 -+ if (strlen(senv.name) == 0) {
8165 -+ return apr_psprintf(cmd->temp_pool,
8166 -+ "Error: Directive %s> takes one argument", cmd->cmd->name);
8167 -+ }
8168 -+
8169 -+ server_env_t *old_senv = find_senv_by_name(senv.name);
8170 -+
8171 -+ if (old_senv) {
8172 -+ return apr_psprintf(cmd->temp_pool,
8173 -+ "Error: Processor %s already defined", senv.name);
8174 -+ }
8175 -+
8176 -+ senv_init(&senv);
8177 -+
8178 -+ current = cmd->directive->first_child;
8179 -+
8180 -+ int proc_temp = 0;
8181 -+ for(; current != NULL; current = current->next) {
8182 -+ directive = current->directive;
8183 -+
8184 -+ if (!strcasecmp(directive, "user")) {
8185 -+ user_name = current->args;
8186 -+ }
8187 -+ else if (!strcasecmp(directive, "group")) {
8188 -+ group_name = current->args;
8189 -+ }
8190 -+ else if (!strcasecmp(directive, "chroot")) {
8191 -+ senv.chroot = ap_getword_conf(cmd->pool, &current->args);
8192 -+ }
8193 -+ else if (!strcasecmp(directive, "nicelevel")) {
8194 -+ senv.nice_lvl = atoi(current->args);
8195 -+ }
8196 -+ else if (!strcasecmp(directive, "maxprocessors")) {
8197 -+ proc_temp = atoi(current->args);
8198 -+
8199 -+ if (proc_temp < 1) {
8200 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8201 -+ "WARNING: Require MaxProcessors > 0, setting to 1");
8202 -+ proc_temp = 1;
8203 -+ }
8204 -+
8205 -+ senv.max_processors = proc_temp;
8206 -+ }
8207 -+ else if (!strcasecmp(directive, "minprocessors")) {
8208 -+ proc_temp = atoi(current->args);
8209 -+
8210 -+ if (proc_temp < 0) {
8211 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8212 -+ "WARNING: Require MinProcessors >= 0, setting to 0");
8213 -+ proc_temp = 0;
8214 -+ }
8215 -+
8216 -+ senv.min_processors = proc_temp;
8217 -+ }
8218 -+ else if (!strcasecmp(directive, "minspareprocessors")) {
8219 -+ proc_temp = atoi(current->args);
8220 -+
8221 -+ if (proc_temp < 0) {
8222 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8223 -+ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
8224 -+ proc_temp = 0;
8225 -+ }
8226 -+
8227 -+ senv.min_free_processors = proc_temp;
8228 -+ }
8229 -+ else if (!strcasecmp(directive, "maxspareprocessors")) {
8230 -+ proc_temp = atoi(current->args);
8231 -+
8232 -+ if (proc_temp < 0) {
8233 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8234 -+ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
8235 -+ proc_temp = 0;
8236 -+ }
8237 -+
8238 -+ senv.max_free_processors = proc_temp;
8239 -+ }
8240 -+ else if (!strcasecmp(directive, "cgroup")) {
8241 -+ senv.cgroup = ap_getword_conf(cmd->pool, &current->args);
8242 -+ }
8243 -+ else {
8244 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8245 -+ "Unknown directive %s in %s>", directive, cmd->cmd->name);
8246 -+ }
8247 -+ }
8248 -+
8249 -+ if (user_name == NULL || group_name == NULL) {
8250 -+ return apr_psprintf(cmd->temp_pool,
8251 -+ "Error: User or Group must be set in %s>", cmd->cmd->name);
8252 -+ }
8253 -+
8254 -+ senv.uid = ap_uname2id(user_name);
8255 -+ senv.gid = ap_gname2id(group_name);
8256 -+
8257 -+ _DBG("name=%s user=%s:%d group=%s:%d chroot=%s nice_lvl=%d",
8258 -+ senv.name, user_name, senv.uid, group_name, senv.gid, senv.chroot, senv.nice_lvl);
8259 -+
8260 -+ _DBG("min_processors=%d min_free_processors=%d max_spare_processors=%d max_processors=%d",
8261 -+ senv.min_processors, senv.min_free_processors, senv.max_free_processors, senv.max_processors);
8262 -+
8263 -+ return child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY,
8264 -+ cmd->pool, &senv);
8265 -+}
8266 -+
8267 -+static const char *cf_Processor_depr(cmd_parms *cmd, void *dummy,
8268 -+ const char *user_name, const char *group_name, const char *chroot)
8269 -+{
8270 -+ return NULL;
8271 -+}
8272 -+
8273 -+/* we define an Multiplexer child w/ specific uid/gid */
8274 -+static const char *cf_Multiplexer(cmd_parms *cmd, void *dummy,
8275 -+ const char *user_name, const char *group_name, const char *chroot)
8276 -+{
8277 -+ static short depr_warned = 0;
8278 -+
8279 -+ if (depr_warned == 0) {
8280 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8281 -+ "WARNING: Multiplexer directive is deprecated. Multiplexer user and group is set by User and Group directives.");
8282 -+
8283 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8284 -+ "To set multiplexer chroot, please use MultiplexerChroot.");
8285 -+
8286 -+ depr_warned = 1;
8287 -+ }
8288 -+
8289 -+ if (chroot) {
8290 -+ if (!ap_is_directory(cmd->pool, chroot))
8291 -+ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", chroot);
8292 -+
8293 -+ multiplexer_chroot = chroot;
8294 -+ _DBG("Setting multiplexer chroot to %s", chroot);
8295 -+ }
8296 -+
8297 -+ return NULL;
8298 -+}
8299 -+
8300 -+static const char* cf_MultiplexerChroot(cmd_parms *cmd, void *dummy,
8301 -+ const char *path)
8302 -+{
8303 -+ multiplexer_chroot = path;
8304 -+
8305 -+ if (path && !ap_is_directory(cmd->pool, path))
8306 -+ return apr_psprintf(cmd->pool, "Error: multiplexer chroot directory [%s] does not exist", path);
8307 -+
8308 -+ _DBG("setting multiplexer chroot to %s", path);
8309 -+
8310 -+ return NULL;
8311 -+}
8312 -+
8313 -+static const char* cf_ServerEnvironment(cmd_parms *cmd, void *dummy,
8314 -+ const char *name, const char * group_name, const char * chroot)
8315 -+{
8316 -+ peruser_server_conf *sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
8317 -+ server_env_t senv;
8318 -+ char * processor_name, *tmp;
8319 -+
8320 -+ _DBG("function entered", 0);
8321 -+
8322 -+ /* name of processor env */
8323 -+ processor_name = name;
8324 -+
8325 -+ if(group_name != NULL || chroot != NULL) {
8326 -+ /* deprecated ServerEnvironment user group chroot syntax
8327 -+ * we create simple server env based on user/group/chroot only
8328 -+ */
8329 -+ processor_name = apr_pstrcat(cmd->pool, name, "_",group_name, "_", chroot, NULL);
8330 -+
8331 -+ /* search for previous default server env */
8332 -+ sconf->senv = find_senv_by_name(processor_name);
8333 -+
8334 -+ if(!sconf->senv) {
8335 -+ senv_init(&senv);
8336 -+ senv.uid = ap_uname2id(name);
8337 -+ senv.gid = ap_gname2id(group_name);
8338 -+ senv.chroot = chroot;
8339 -+ senv.name = processor_name;
8340 -+
8341 -+ tmp = child_add(CHILD_TYPE_PROCESSOR, CHILD_STATUS_STANDBY, cmd->pool, &senv);
8342 -+ /* error handling in case this child can't be created */
8343 -+ if(tmp)
8344 -+ return tmp;
8345 -+ }
8346 -+ }
8347 -+
8348 -+ /* use predefined processor environment or default named "user_group_chroot" */
8349 -+ if(sconf->senv == NULL)
8350 -+ sconf->senv = find_senv_by_name(processor_name);
8351 -+
8352 -+ if (sconf->senv == NULL) {
8353 -+ return apr_psprintf(cmd->pool,
8354 -+ "Error: Processor %s not defined", name);
8355 -+ }
8356 -+
8357 -+ _DBG("user=%d group=%d chroot=%s numchilds=%d",
8358 -+ sconf->senv->uid, sconf->senv->gid, sconf->senv->chroot, NUM_CHILDS);
8359 -+
8360 -+ return NULL;
8361 -+}
8362 -+
8363 -+static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const char *arg)
8364 -+{
8365 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
8366 -+ if (err != NULL) {
8367 -+ return err;
8368 -+ }
8369 -+
8370 -+ ap_min_free_processors = atoi(arg);
8371 -+ if (ap_min_free_processors <= 0) {
8372 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8373 -+ "WARNING: detected MinSpareServers set to non-positive.");
8374 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8375 -+ "Resetting to 1 to avoid almost certain Apache failure.");
8376 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8377 -+ "Please read the documentation.");
8378 -+ ap_min_free_processors = 1;
8379 -+ }
8380 -+
8381 -+ return NULL;
8382 -+}
8383 -+
8384 -+static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg)
8385 -+{
8386 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
8387 -+ if (err != NULL) {
8388 -+ return err;
8389 -+ }
8390 -+
8391 -+ ap_daemons_limit = atoi(arg);
8392 -+ if (ap_daemons_limit > server_limit) {
8393 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8394 -+ "WARNING: MaxClients of %d exceeds ServerLimit value "
8395 -+ "of %d servers,", ap_daemons_limit, server_limit);
8396 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8397 -+ " lowering MaxClients to %d. To increase, please "
8398 -+ "see the ServerLimit", server_limit);
8399 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8400 -+ " directive.");
8401 -+ ap_daemons_limit = server_limit;
8402 -+ }
8403 -+ else if (ap_daemons_limit < 1) {
8404 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8405 -+ "WARNING: Require MaxClients > 0, setting to 1");
8406 -+ ap_daemons_limit = 1;
8407 -+ }
8408 -+ return NULL;
8409 -+}
8410 -+
8411 -+static const char *set_min_processors (cmd_parms *cmd, void *dummy, const char *arg)
8412 -+{
8413 -+ peruser_server_conf *sconf;
8414 -+ int min_procs;
8415 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
8416 -+
8417 -+ if (err != NULL) {
8418 -+ return err;
8419 -+ }
8420 -+
8421 -+ min_procs = atoi(arg);
8422 -+
8423 -+ if (min_procs < 0) {
8424 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8425 -+ "WARNING: Require MinProcessors >= 0, setting to 0");
8426 -+ min_procs = 0;
8427 -+ }
8428 -+
8429 -+ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
8430 -+ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
8431 -+ sconf->senv->min_processors = min_procs;
8432 -+ }
8433 -+ else {
8434 -+ ap_min_processors = min_procs;
8435 -+ }
8436 -+
8437 -+ return NULL;
8438 -+}
8439 -+
8440 -+static const char *set_min_free_processors (cmd_parms *cmd, void *dummy, const char *arg)
8441 -+{
8442 -+ peruser_server_conf *sconf;
8443 -+ int min_free_procs;
8444 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
8445 -+
8446 -+ if (err != NULL) {
8447 -+ return err;
8448 -+ }
8449 -+
8450 -+ min_free_procs = atoi(arg);
8451 -+
8452 -+ if (min_free_procs < 0) {
8453 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8454 -+ "WARNING: Require MinSpareProcessors >= 0, setting to 0");
8455 -+ min_free_procs = 0;
8456 -+ }
8457 -+
8458 -+ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
8459 -+ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
8460 -+ sconf->senv->min_free_processors = min_free_procs;
8461 -+ }
8462 -+ else {
8463 -+ ap_min_free_processors = min_free_procs;
8464 -+ }
8465 -+
8466 -+ return NULL;
8467 -+}
8468 -+
8469 -+static const char *set_max_free_processors (cmd_parms *cmd, void *dummy, const char *arg)
8470 -+{
8471 -+ peruser_server_conf *sconf;
8472 -+ int max_free_procs;
8473 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
8474 -+
8475 -+ if (err != NULL) {
8476 -+ return err;
8477 -+ }
8478 -+
8479 -+ max_free_procs = atoi(arg);
8480 -+
8481 -+ if (max_free_procs < 0) {
8482 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8483 -+ "WARNING: Require MaxSpareProcessors >= 0, setting to 0");
8484 -+ max_free_procs = 0;
8485 -+ }
8486 -+
8487 -+ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
8488 -+ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
8489 -+ sconf->senv->max_free_processors = max_free_procs;
8490 -+ }
8491 -+ else {
8492 -+ ap_max_free_processors = max_free_procs;
8493 -+ }
8494 -+
8495 -+ return NULL;
8496 -+}
8497 -+
8498 -+static const char *set_max_processors (cmd_parms *cmd, void *dummy, const char *arg)
8499 -+{
8500 -+ peruser_server_conf *sconf;
8501 -+ int max_procs;
8502 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
8503 -+
8504 -+ if (err != NULL) {
8505 -+ return err;
8506 -+ }
8507 -+
8508 -+ max_procs = atoi(arg);
8509 -+
8510 -+ if (max_procs < 1) {
8511 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8512 -+ "WARNING: Require MaxProcessors > 0, setting to 1");
8513 -+ max_procs = 1;
8514 -+ }
8515 -+
8516 -+ if (ap_check_cmd_context(cmd, NOT_IN_VIRTUALHOST) != NULL) {
8517 -+ sconf = PERUSER_SERVER_CONF(cmd->server->module_config);
8518 -+ sconf->senv->max_processors = max_procs;
8519 -+ }
8520 -+ else {
8521 -+ ap_max_processors = max_procs;
8522 -+ }
8523 -+
8524 -+ return NULL;
8525 -+}
8526 -+
8527 -+static const char *set_min_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
8528 -+{
8529 -+ int min_multiplexers;
8530 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
8531 -+
8532 -+ if (err != NULL) {
8533 -+ return err;
8534 -+ }
8535 -+
8536 -+ min_multiplexers = atoi(arg);
8537 -+
8538 -+ if (min_multiplexers < 1) {
8539 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8540 -+ "WARNING: Require MinMultiplexers > 0, setting to 1");
8541 -+ min_multiplexers = 1;
8542 -+ }
8543 -+
8544 -+ ap_min_multiplexers = min_multiplexers;
8545 -+
8546 -+ return NULL;
8547 -+}
8548 -+
8549 -+static const char *set_max_multiplexers (cmd_parms *cmd, void *dummy, const char *arg)
8550 -+{
8551 -+ int max_multiplexers;
8552 -+ const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
8553 -+
8554 -+ if (err != NULL) {
8555 -+ return err;
8556 -+ }
8557 -+
8558 -+ max_multiplexers = atoi(arg);
8559 -+
8560 -+ if (max_multiplexers < 1) {
8561 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8562 -+ "WARNING: Require MaxMultiplexers > 0, setting to 1");
8563 -+ max_multiplexers = 1;
8564 -+ }
8565 -+
8566 -+ ap_max_multiplexers = max_multiplexers;
8567 -+
8568 -+ return NULL;
8569 -+}
8570 -+
8571 -+static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg)
8572 -+{
8573 -+ int tmp_server_limit;
8574 -+
8575 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
8576 -+ if (err != NULL) {
8577 -+ return err;
8578 -+ }
8579 -+
8580 -+ tmp_server_limit = atoi(arg);
8581 -+ /* you cannot change ServerLimit across a restart; ignore
8582 -+ * any such attempts
8583 -+ */
8584 -+ if (first_server_limit &&
8585 -+ tmp_server_limit != server_limit) {
8586 -+ /* how do we log a message? the error log is a bit bucket at this
8587 -+ * point; we'll just have to set a flag so that ap_mpm_run()
8588 -+ * logs a warning later
8589 -+ */
8590 -+ changed_limit_at_restart = 1;
8591 -+ return NULL;
8592 -+ }
8593 -+ server_limit = tmp_server_limit;
8594 -+
8595 -+ if (server_limit > MAX_SERVER_LIMIT) {
8596 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8597 -+ "WARNING: ServerLimit of %d exceeds compile time limit "
8598 -+ "of %d servers,", server_limit, MAX_SERVER_LIMIT);
8599 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8600 -+ " lowering ServerLimit to %d.", MAX_SERVER_LIMIT);
8601 -+ server_limit = MAX_SERVER_LIMIT;
8602 -+ }
8603 -+ else if (server_limit < 1) {
8604 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8605 -+ "WARNING: Require ServerLimit > 0, setting to 1");
8606 -+ server_limit = 1;
8607 -+ }
8608 -+ return NULL;
8609 -+}
8610 -+
8611 -+static const char *set_expire_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
8612 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
8613 -+ if (err != NULL) {
8614 -+ return err;
8615 -+ }
8616 -+
8617 -+ expire_timeout = atoi(arg);
8618 -+
8619 -+ return NULL;
8620 -+}
8621 -+
8622 -+static const char *set_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
8623 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
8624 -+ if (err != NULL) {
8625 -+ return err;
8626 -+ }
8627 -+
8628 -+ idle_timeout = atoi(arg);
8629 -+
8630 -+ return NULL;
8631 -+}
8632 -+
8633 -+static const char *set_multiplexer_idle_timeout (cmd_parms *cmd, void *dummy, const char *arg) {
8634 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
8635 -+
8636 -+ if (err != NULL) {
8637 -+ return err;
8638 -+ }
8639 -+
8640 -+ multiplexer_idle_timeout = atoi(arg);
8641 -+
8642 -+ return NULL;
8643 -+}
8644 -+
8645 -+static const char *set_processor_wait_timeout (cmd_parms *cmd, void *dummy, const char *timeout, const char *steps) {
8646 -+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
8647 -+
8648 -+ if (err != NULL) {
8649 -+ return err;
8650 -+ }
8651 -+
8652 -+ processor_wait_timeout = atoi(timeout);
8653 -+
8654 -+ if (steps != NULL) {
8655 -+ int steps_tmp = atoi(steps);
8656 -+
8657 -+ if (steps_tmp < 1) {
8658 -+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
8659 -+ "WARNING: Require ProcessorWaitTimeout steps > 0, setting to 1");
8660 -+ steps_tmp = 1;
8661 -+ }
8662 -+
8663 -+ processor_wait_steps = steps_tmp;
8664 -+ }
8665 -+
8666 -+ return NULL;
8667 -+}
8668 -+
8669 -+static const command_rec peruser_cmds[] = {
8670 -+UNIX_DAEMON_COMMANDS,
8671 -+LISTEN_COMMANDS,
8672 -+AP_INIT_TAKE1("MinSpareProcessors", set_min_free_processors, NULL, RSRC_CONF,
8673 -+ "Minimum number of idle children, to handle request spikes"),
8674 -+AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF,
8675 -+ "Minimum number of idle children, to handle request spikes"),
8676 -+AP_INIT_TAKE1("MaxSpareProcessors", set_max_free_processors, NULL, RSRC_CONF,
8677 -+ "Maximum number of idle children, 0 to disable"),
8678 -+AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF,
8679 -+ "Maximum number of children alive at the same time"),
8680 -+AP_INIT_TAKE1("MinProcessors", set_min_processors, NULL, RSRC_CONF,
8681 -+ "Minimum number of processors per vhost"),
8682 -+AP_INIT_TAKE1("MaxProcessors", set_max_processors, NULL, RSRC_CONF,
8683 -+ "Maximum number of processors per vhost"),
8684 -+AP_INIT_TAKE1("MinMultiplexers", set_min_multiplexers, NULL, RSRC_CONF,
8685 -+ "Minimum number of multiplexers the server can have"),
8686 -+AP_INIT_TAKE1("MaxMultiplexers", set_max_multiplexers, NULL, RSRC_CONF,
8687 -+ "Maximum number of multiplexers the server can have"),
8688 -+AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF,
8689 -+ "Maximum value of MaxClients for this run of Apache"),
8690 -+AP_INIT_TAKE1("ExpireTimeout", set_expire_timeout, NULL, RSRC_CONF,
8691 -+ "Maximum time a child can live, 0 to disable"),
8692 -+AP_INIT_TAKE1("IdleTimeout", set_idle_timeout, NULL, RSRC_CONF,
8693 -+ "Maximum time before a child is killed after being idle, 0 to disable"),
8694 -+AP_INIT_TAKE1("MultiplexerIdleTimeout", set_multiplexer_idle_timeout, NULL, RSRC_CONF,
8695 -+ "Maximum time before a multiplexer is killed after being idle, 0 to disable"),
8696 -+AP_INIT_TAKE12("ProcessorWaitTimeout", set_processor_wait_timeout, NULL, RSRC_CONF,
8697 -+ "Maximum time a multiplexer waits for the processor if it is busy"),
8698 -+AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF,
8699 -+ "Specify an Multiplexer Child configuration."),
8700 -+AP_INIT_RAW_ARGS("<Processor", cf_Processor, NULL, RSRC_CONF,
8701 -+ "Specify settings for processor."),
8702 -+AP_INIT_TAKE23("Processor", cf_Processor_depr, NULL, RSRC_CONF,
8703 -+ "A dummy directive for backwards compatibility"),
8704 -+AP_INIT_TAKE123("ServerEnvironment", cf_ServerEnvironment, NULL, RSRC_CONF,
8705 -+ "Specify the server environment for this virtual host."),
8706 -+AP_INIT_TAKE1("MultiplexerChroot", cf_MultiplexerChroot, NULL, RSRC_CONF,
8707 -+ "Specify the multiplexer chroot path for multiplexer"),
8708 -+{ NULL }
8709 -+};
8710 -+
8711 -+module AP_MODULE_DECLARE_DATA mpm_peruser_module = {
8712 -+ MPM20_MODULE_STUFF,
8713 -+ ap_mpm_rewrite_args, /* hook to run before apache parses args */
8714 -+ NULL, /* create per-directory config structure */
8715 -+ NULL, /* merge per-directory config structures */
8716 -+ peruser_create_config, /* create per-server config structure */
8717 -+ NULL, /* merge per-server config structures */
8718 -+ peruser_cmds, /* command apr_table_t */
8719 -+ peruser_hooks, /* register hooks */
8720 -+};