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, ¤t->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, ¤t->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, ¤t->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, ¤t->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 |
-+}; |