]> git.pld-linux.org Git - packages/apache.git/blame - httpd-2.0.48-metuxmpm-r8.patch
- provide full path to --pidfile as start-stop-daemon doesn't handle
[packages/apache.git] / httpd-2.0.48-metuxmpm-r8.patch
CommitLineData
81a3ef12
AM
1diff -urN httpd-2.2.0.org/server/mpm/config.m4 httpd-2.2.0/server/mpm/config.m4
2--- httpd-2.2.0.org/server/mpm/config.m4 2005-10-30 18:05:26.000000000 +0100
8ccd60d9 3+++ httpd-2.2.0/server/mpm/config.m4 2005-12-12 11:37:00.900963000 +0100
4a17dc3c
AM
4@@ -1,7 +1,7 @@
5 AC_MSG_CHECKING(which MPM to use)
6 AC_ARG_WITH(mpm,
7 APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use.
81a3ef12
AM
8- MPM={beos|event|worker|prefork|mpmt_os2}),[
9+ MPM={beos|event|worker|prefork|mpmt_os2|metuxmpm}),[
4a17dc3c
AM
10 APACHE_MPM=$withval
11 ],[
12 if test "x$APACHE_MPM" = "x"; then
81a3ef12 13@@ -14,7 +14,7 @@
4a17dc3c 14
81a3ef12
AM
15 ap_mpm_is_threaded ()
16 {
17- if test "$apache_cv_mpm" = "worker" -o "$apache_cv_mpm" = "event" ; then
18+ if test "$apache_cv_mpm" = "worker" -o "$apache_cv_mpm" = "event" -o "$apache_cv_mpm" = "metuxmpm"; then
19 return 0
20 else
21 return 1
22@@ -23,7 +23,7 @@
4a17dc3c 23
81a3ef12
AM
24 ap_mpm_is_experimental ()
25 {
26- if test "$apache_cv_mpm" = "event" ; then
27+ if test "$apache_cv_mpm" = "event" -o "$apache_cv_mpm" = "metuxmpm"; then
28 return 0
29 else
30 return 1
31diff -urN httpd-2.2.0.org/server/mpm/experimental/metuxmpm/config5.m4 httpd-2.2.0/server/mpm/experimental/metuxmpm/config5.m4
32--- httpd-2.2.0.org/server/mpm/experimental/metuxmpm/config5.m4 1970-01-01 01:00:00.000000000 +0100
8ccd60d9 33+++ httpd-2.2.0/server/mpm/experimental/metuxmpm/config5.m4 2005-12-12 11:37:00.900963000 +0100
4a17dc3c
AM
34@@ -0,0 +1,6 @@
35+dnl ## XXX - Need a more thorough check of the proper flags to use
36+
37+if test "$MPM_NAME" = "metuxmpm" ; then
38+ AC_CHECK_FUNCS(pthread_kill)
39+ APACHE_FAST_OUTPUT(server/mpm/$MPM_SUBDIR_NAME/Makefile)
40+fi
81a3ef12
AM
41diff -urN httpd-2.2.0.org/server/mpm/experimental/metuxmpm/Makefile.in httpd-2.2.0/server/mpm/experimental/metuxmpm/Makefile.in
42--- httpd-2.2.0.org/server/mpm/experimental/metuxmpm/Makefile.in 1970-01-01 01:00:00.000000000 +0100
8ccd60d9 43+++ httpd-2.2.0/server/mpm/experimental/metuxmpm/Makefile.in 2005-12-12 11:37:00.900963000 +0100
81a3ef12
AM
44@@ -0,0 +1,5 @@
45+
46+LTLIBRARY_NAME = libmetuxmpm.la
47+LTLIBRARY_SOURCES = metuxmpm.c
48+
49+include $(top_srcdir)/build/ltlib.mk
50diff -urN httpd-2.2.0.org/server/mpm/experimental/metuxmpm/metuxmpm.c httpd-2.2.0/server/mpm/experimental/metuxmpm/metuxmpm.c
51--- httpd-2.2.0.org/server/mpm/experimental/metuxmpm/metuxmpm.c 1970-01-01 01:00:00.000000000 +0100
8ccd60d9
AM
52+++ httpd-2.2.0/server/mpm/experimental/metuxmpm/metuxmpm.c 2005-12-12 11:35:35.000000000 +0100
53@@ -0,0 +1,2627 @@
4a17dc3c
AM
54+/* ====================================================================
55+ * The Apache Software License, Version 1.1
56+ *
57+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
58+ * reserved.
59+ *
60+ * Redistribution and use in source and binary forms, with or without
61+ * modification, are permitted provided that the following conditions
62+ * are met:
63+ *
64+ * 1. Redistributions of source code must retain the above copyright
65+ * notice, this list of conditions and the following disclaimer.
66+ *
67+ * 2. Redistributions in binary form must reproduce the above copyright
68+ * notice, this list of conditions and the following disclaimer in
69+ * the documentation and/or other materials provided with the
70+ * distribution.
71+ *
72+ * 3. The end-user documentation included with the redistribution,
73+ * if any, must include the following acknowledgment:
74+ * "This product includes software developed by the
75+ * Apache Software Foundation (http://www.apache.org/)."
76+ * Alternately, this acknowledgment may appear in the software itself,
77+ * if and wherever such third-party acknowledgments normally appear.
78+ *
79+ * 4. The names "Apache" and "Apache Software Foundation" must
80+ * not be used to endorse or promote products derived from this
81+ * software without prior written permission. For written
82+ * permission, please contact apache@apache.org.
83+ *
84+ * 5. Products derived from this software may not be called "Apache",
85+ * nor may "Apache" appear in their name, without prior written
86+ * permission of the Apache Software Foundation.
87+ *
88+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
89+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
90+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
91+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
92+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
93+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
94+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
95+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
96+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
97+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
98+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99+ * SUCH DAMAGE.
100+ * ====================================================================
101+ *
102+ * This software consists of voluntary contributions made by many
103+ * individuals on behalf of the Apache Software Foundation. For more
104+ * information on the Apache Software Foundation, please see
105+ * <http://www.apache.org/>.
106+ *
107+ * Portions of this software are based upon public domain software
108+ * originally written at the National Center for Supercomputing Applications,
109+ * University of Illinois, Urbana-Champaign.
110+ */
111+
112+/* TODO:
113+ + replace pipe_of_death by an generic command interface
114+ + also use this interface for child->child communications
115+ + add support for runtime configuration over this if.
116+ + what to do w/ unassigned vhosts ? who should handle them ?
117+ perhaps we shoudda add an DefaultProcessor option ?
118+ + test, test, test, and test, especially under high load.
119+ + what about persistent links w/ changing vhost ?
120+ should the client then give it back to the multiplexer ?
121+ + add timeouts in multiplexer to prevent local dos attacks
122+ + think about possible vulnarabilities. note that the vhost's user
123+ could ptrace the processor child and play nice games with it.
124+*/
125+
126+/* -- build configuration -- manly for debugging -- */
127+
128+/* #define MPM_METUXMPM_DEBUG */
129+
130+#define MPM_THREAD_ACCEPT_LOCK
131+
132+#include "apr_hash.h"
133+#include "apr_strings.h"
134+#include "apr_pools.h"
135+#include "apr_portable.h"
136+#include "apr_file_io.h"
137+#include "apr_signal.h"
138+
139+#define APR_WANT_IOVEC
140+#include "apr_want.h"
141+
142+#if APR_HAVE_UNISTD_H
143+#include <unistd.h>
144+#endif
145+#if APR_HAVE_SYS_SOCKET_H
146+#include <sys/socket.h>
147+#endif
148+
149+#if !APR_HAS_THREADS
150+#error The metuxmpm MPM requires APR threads, but they are unavailable.
151+#endif
152+
153+#define CORE_PRIVATE
154+
155+#include "ap_config.h"
156+#include "httpd.h"
157+#include "http_main.h"
158+#include "http_log.h"
159+#include "http_config.h" /* for read_config */
160+#include "http_core.h" /* for get_remote_host */
161+#include "http_protocol.h"
162+#include "http_connection.h"
163+#include "ap_mpm.h"
164+#include "unixd.h"
165+#include "mpm_common.h"
166+#include "ap_listen.h"
167+#include "mpm_default.h"
168+#include "mpm.h"
169+#include "scoreboard.h"
170+#include "util_filter.h"
171+#include "apr_poll.h"
172+
173+#include "util_ebcdic.h"
174+
175+#ifdef HAVE_POLL_H
176+#include <poll.h>
177+#endif
178+#ifdef HAVE_SYS_POLL_H
179+#include <sys/poll.h>
180+#endif
181+
182+/* ### should be APR-ized */
183+#include <grp.h>
184+#include <pwd.h>
185+#include <sys/stat.h>
186+#include <sys/un.h>
187+#include <setjmp.h>
188+#ifdef HAVE_SYS_PROCESSOR_H
189+#include <sys/processor.h> /* for bindprocessor() */
190+#endif
191+
192+#ifdef MPM_METUXMPM_DEBUG
193+# define _DBG(text,par...) \
194+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \
195+ "(metuxmpm: pid=%d uid=%d) %s(): " text, \
196+ getpid(), getuid(), __FUNCTION__, ##par, 0)
197+
198+# define _TRACE_CALL(text,par...) _DBG("calling " text, ##par)
199+# define _TRACE_RET(text,par...) _DBG("returned from " text, ##par)
200+#else
201+# define _DBG(text,par...)
202+# define _TRACE_RET(text,par...)
203+# define _TRACE_CALL(text,par...)
204+#endif /* MPM_METUXMPM_DEBUG */
205+
206+/* char of death - for signalling children to die */
207+#define AP_metuxmpm_CHAR_OF_DEATH '!'
208+
209+#define metuxmpm_SERVER_CONF(cf) \
210+ ((metuxmpm_server_conf *) ap_get_module_config(cf,&mpm_metuxmpm_module))
211+
212+
213+/*
214+ * Define some magic numbers that we use for the state of the incomming
215+ * request. These must be < 0 so they don't collide with a file descriptor.
216+ */
217+#define AP_metuxmpm_THISCHILD -1
218+#define AP_metuxmpm_OTHERCHILD -2
219+
220+/* Limit on the threads per process. Clients will be locked out if more than
221+ * this * server_limit are needed.
222+ *
223+ * We keep this for one reason it keeps the size of the scoreboard file small
224+ * enough that we can read the whole thing without worrying too much about
225+ * the overhead.
226+ */
227+#ifndef DEFAULT_THREAD_LIMIT
228+#define DEFAULT_THREAD_LIMIT 64
229+#endif
230+
231+/* Admin can't tune ThreadLimit beyond MAX_THREAD_LIMIT. We want
232+ * some sort of compile-time limit to help catch typos.
233+ */
234+#ifndef MAX_THREAD_LIMIT
235+#define MAX_THREAD_LIMIT 20000
236+#endif
237+
238+/* Limit on the total --- clients will be locked out if more servers than
239+ * this are needed. It is intended solely to keep the server from crashing
240+ * when things get out of hand.
241+ *
242+ * We keep a hard maximum number of servers, for two reasons --- first off,
243+ * in case something goes seriously wrong, we want to stop the fork bomb
244+ * short of actually crashing the machine we're running on by filling some
245+ * kernel table. Secondly, it keeps the size of the scoreboard file small
246+ * enough that we can read the whole thing without worrying too much about
247+ * the overhead.
248+ */
249+#ifndef DEFAULT_SERVER_LIMIT
250+#define DEFAULT_SERVER_LIMIT 256
251+#endif
252+
253+/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want
254+ * some sort of compile-time limit to help catch typos.
255+ */
256+#ifndef MAX_SERVER_LIMIT
257+#define MAX_SERVER_LIMIT 20000
258+#endif
259+
260+/*
261+ * Actual definitions of config globals
262+ */
263+
264+static int threads_to_start = 0; /* Worker threads per child */
265+static int min_spare_threads = 0;
266+static int max_spare_threads = 0;
267+static int max_threads = 0;
268+static int server_limit = DEFAULT_SERVER_LIMIT;
269+static int first_server_limit;
270+static int thread_limit = DEFAULT_THREAD_LIMIT;
271+static int first_thread_limit;
272+static int changed_limit_at_restart;
273+static int num_childs = 0;
274+static int workers_may_exit = 0;
275+static int requests_this_child;
276+static int num_listensocks = 0;
277+static ap_pod_t *pod;
278+static jmp_buf jmpbuffer;
279+static int thread_overflow_reported = 0;
280+
281+/* === configuration stuff === */
282+/* the server limit is also the size of the server table */
283+static int cf_server_limit = DEFAULT_SERVER_LIMIT;
284+
285+/* -- server process information -- */
286+typedef struct
287+{
288+ uid_t uid;
289+ gid_t gid;
290+ int input; /* The socket descriptor */
291+ int output; /* The socket descriptor */
292+ int type;
293+ int id; /* index in child_info_table */
294+ const char *chroot_dir; /* can be null */
295+} child_info_t;
296+
297+#define CHILD_TYPE_MULTIPLEXER 1
298+#define CHILD_TYPE_PROCESSOR 2
299+
300+typedef struct
301+{
302+ const char *sockname; /* The base name for the socket */
303+ const char *fullsockname; /* socket base name + extension */
304+ child_info_t* child; /* The client which processes this server */
305+} metuxmpm_server_conf;
306+
307+typedef struct
308+{
309+ int sock_fd;
310+ int status;
311+ jmp_buf jmpbuffer;
312+} thread_info_t;
313+
314+/* Tables used to determine the user and group each child process should
315+ * run as. The hash table is used to correlate a server name with a child
316+ * process.
317+ */
318+static int child_info_table_size;
319+static child_info_t *child_info_table;
320+static thread_info_t *thread_info_table;
321+struct ap_ctable *ap_child_table;
322+
323+/*
324+ * The max child slot ever assigned, preserved across restarts. Necessary
325+ * to deal with NumServers changes across AP_SIG_GRACEFUL restarts. We
326+ * use this value to optimize routines that have to scan the entire child
327+ * table.
328+ *
329+ * XXX - It might not be worth keeping this code in. There aren't very
330+ * many child processes in this MPM.
331+ */
332+int ap_max_daemons_limit = -1;
333+int ap_threads_per_child; /* XXX not part of API! axe it! */
334+
335+module AP_MODULE_DECLARE_DATA mpm_metuxmpm_module;
336+
337+/* -- replace the pipe-of-death by an control socket -- */
338+static apr_file_t *pipe_of_death_in = NULL;
339+static apr_file_t *pipe_of_death_out = NULL;
340+static apr_thread_mutex_t *pipe_of_death_mutex;
341+
342+/* *Non*-shared http_main globals... */
343+
344+server_rec *ap_server_conf;
345+
346+/* one_process --- debugging mode variable; can be set from the command line
347+ * with the -X flag. If set, this gets you the child_main loop running
348+ * in the process which originally started up (no detach, no make_child),
349+ * which is a pretty nice debugging environment. (You'll get a SIGHUP
350+ * early in standalone_main; just continue through. This is the server
351+ * trying to kill off any child processes which it might have lying
352+ * around --- Apache doesn't keep track of their pids, it just sends
353+ * SIGHUP to the process group, ignoring it in the root process.
354+ * Continue through and you'll be fine.).
355+ */
356+
357+static int one_process = 0;
358+
359+#ifdef DEBUG_SIGSTOP
360+int raise_sigstop_flags;
361+#endif
362+
363+static apr_pool_t *pconf; /* Pool for config stuff */
364+static apr_pool_t *pchild; /* Pool for httpd child stuff */
365+static apr_pool_t *thread_pool_parent; /* Parent of per-thread pools */
366+static apr_thread_mutex_t *thread_pool_parent_mutex;
367+
368+static int child_num;
369+static unsigned int my_pid; /* Linux getpid() doesn't work except in
370+ main thread. Use this instead */
371+
372+/* -- stack w/ free thread slot IDs */
373+static int *worker_thread_free_ids;
374+static apr_threadattr_t *worker_thread_attr;
375+
376+/* Keep track of the number of idle worker threads */
377+static int idle_thread_count;
378+static apr_thread_mutex_t *idle_thread_count_mutex;
379+
380+/* Locks for accept serialization */
381+#ifdef NO_SERIALIZED_ACCEPT
382+
383+#define ACCEPT_PROC_MUTEX_INIT APR_SUCCESS
384+#define ACCEPT_PROC_MUTEX_LOCK APR_SUCCESS
385+#define ACCEPT_PROC_MUTEX_UNLOCK APR_SUCCESS
386+#define ACCEPT_PROC_MUTEX_CREATE APR_SUCCESS
387+
388+#else
389+
390+static apr_proc_mutex_t *process_accept_mutex;
391+
392+#define ACCEPT_PROC_MUTEX_LOCK (apr_proc_mutex_lock(process_accept_mutex))
393+#define ACCEPT_PROC_MUTEX_UNLOCK (apr_proc_mutex_unlock(process_accept_mutex))
394+#define ACCEPT_PROC_MUTEX_CREATE (apr_proc_mutex_create(&process_accept_mutex,ap_lock_fname, ap_accept_lock_mech,_pconf))
395+#define ACCEPT_PROC_MUTEX_INIT (apr_proc_mutex_child_init(&process_accept_mutex, ap_lock_fname, pchild));
396+
397+#endif /* NO_SERIALIZED_ACCEPT */
398+
399+static apr_thread_mutex_t *thread_accept_mutex;
400+
401+#ifdef MPM_metuxmpm_THREAD_ACCEPT_LOCK
402+
403+#define THREAD_ACCEPT_LOCK \
404+ _DBG("locking thread_accept_mutex",0); \
405+ apr_thread_mutex_lock(thread_accept_mutex); \
406+ _DBG("got thread_accept_mutex locked",0);
407+
408+#define THREAD_ACCEPT_UNLOCK \
409+ _DBG("unlocking thread_accept_mutex",0); \
410+ apr_thread_mutex_unlock(thread_accept_mutex); \
411+ _DBG("got thread_accept_mutex unlocked",0);
412+#else
413+
414+#define THREAD_ACCEPT_LOCK \
415+ _DBG("omitted locking thread_accept_mutex",0);
416+
417+#define THREAD_ACCEPT_UNLOCK \
418+ _DBG("omitted unlocking thread_accept_mutex",0);
419+
420+#endif
8ccd60d9
AM
421+
422+
423+static apr_pollfd_t *find_poll_sock(apr_pollfd_t *aprset, apr_socket_t *sock)
424+{
425+ apr_pollfd_t *curr = aprset;
426+
427+ while (curr->desc.s != sock) {
428+ if (curr->desc_type == APR_POLL_LASTDESC) {
429+ return NULL;
430+ }
431+ curr++;
432+ }
433+
434+ return curr;
435+}
436+
437+static apr_status_t apr_poll_revents_get(apr_int16_t *event, apr_socket_t *sock, apr_pollfd_t *aprset)
438+{
439+ apr_pollfd_t *curr = find_poll_sock(aprset, sock);
440+ if (curr == NULL) {
441+ return APR_NOTFOUND;
442+ }
443+
444+ (*event) = curr->rtnevents;
445+ return APR_SUCCESS;
446+}
447+
448+
4a17dc3c
AM
449+/* == Keep track of the number of worker threads currently active == */
450+static int worker_thread_count = 0;
451+static apr_thread_mutex_t *worker_thread_count_mutex;
452+
453+static inline int worker_thread_count_get ()
454+{
455+ int x;
456+ apr_thread_mutex_lock(worker_thread_count_mutex);
457+ x = worker_thread_count;
458+ apr_thread_mutex_unlock(worker_thread_count_mutex);
459+ _DBG("worker_thread_count=%d", x);
460+ return x;
461+}
462+
463+static inline int worker_thread_count_add ( int x )
464+{
465+ int y;
466+ apr_thread_mutex_lock(worker_thread_count_mutex);
467+ worker_thread_count += x;
468+ y = worker_thread_count;
469+ apr_thread_mutex_unlock(worker_thread_count_mutex);
470+ _DBG("worker_thread_count=%d (+%d)", y, x);
471+ return y;
472+}
473+
474+/* ------------------------------------------------------------------- */
475+
476+AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
477+{
478+ switch(query_code){
479+ case AP_MPMQ_MAX_DAEMON_USED:
480+ *result = ap_max_daemons_limit;
481+ return APR_SUCCESS;
482+ case AP_MPMQ_IS_THREADED:
483+ *result = AP_MPMQ_DYNAMIC;
484+ return APR_SUCCESS;
485+ case AP_MPMQ_IS_FORKED:
486+ *result = AP_MPMQ_STATIC;
487+ return APR_SUCCESS;
488+ case AP_MPMQ_HARD_LIMIT_DAEMONS:
489+ *result = cf_server_limit;
490+ return APR_SUCCESS;
491+ case AP_MPMQ_HARD_LIMIT_THREADS:
492+ *result = thread_limit;
493+ return APR_SUCCESS;
494+ case AP_MPMQ_MAX_THREADS:
495+ *result = max_threads;
496+ return APR_SUCCESS;
497+ case AP_MPMQ_MIN_SPARE_DAEMONS:
498+ *result = 0;
499+ return APR_SUCCESS;
500+ case AP_MPMQ_MIN_SPARE_THREADS:
501+ *result = min_spare_threads;
502+ return APR_SUCCESS;
503+ case AP_MPMQ_MAX_SPARE_DAEMONS:
504+ *result = 0;
505+ return APR_SUCCESS;
506+ case AP_MPMQ_MAX_SPARE_THREADS:
507+ *result = max_spare_threads;
508+ return APR_SUCCESS;
509+ case AP_MPMQ_MAX_REQUESTS_DAEMON:
510+ *result = ap_max_requests_per_child;
511+ return APR_SUCCESS;
512+ case AP_MPMQ_MAX_DAEMONS:
513+ *result = num_childs;
514+ return APR_SUCCESS;
515+ }
516+ return APR_ENOTIMPL;
517+}
518+
519+/* a clean exit from a child with proper cleanup */
520+static inline int clean_child_exit(int code)
521+{
522+ if (pchild) apr_pool_destroy(pchild);
523+ exit(code);
524+}
525+
526+/* handle all varieties of core dumping signals */
527+static void sig_coredump(int sig)
528+{
529+ chdir(ap_coredump_dir);
530+ apr_signal(sig, SIG_DFL);
531+ kill(getpid(), sig);
532+ /* At this point we've got sig blocked, because we're still inside
533+ * the signal handler. When we leave the signal handler it will
534+ * be unblocked, and we'll take the signal... and coredump or whatever
535+ * is appropriate for this particular Unix. In addition the parent
536+ * will see the real signal we received -- whereas if we called
537+ * abort() here, the parent would only see SIGABRT.
538+ */
539+}
540+
541+static void just_die(int sig)
542+{
543+ clean_child_exit(0);
544+}
545+
546+/*****************************************************************
547+ * Connection structures and accounting...
548+ */
549+
550+/* volatile just in case */
551+static int volatile shutdown_pending;
552+static int volatile restart_pending;
553+static int volatile is_graceful;
554+static int volatile child_fatal;
555+/* we don't currently track ap_my_generation, but mod_status
556+ * references it so it must be defined */
557+ap_generation_t volatile ap_my_generation=0;
558+
559+/*
560+ * ap_start_shutdown() and ap_start_restart(), below, are a first stab at
561+ * functions to initiate shutdown or restart without relying on signals.
562+ * Previously this was initiated in sig_term() and restart() signal handlers,
563+ * but we want to be able to start a shutdown/restart from other sources --
564+ * e.g. on Win32, from the service manager. Now the service manager can
565+ * call ap_start_shutdown() or ap_start_restart() as appropiate. Note that
566+ * these functions can also be called by the child processes, since global
567+ * variables are no longer used to pass on the required action to the parent.
568+ *
569+ * These should only be called from the parent process itself, since the
570+ * parent process will use the shutdown_pending and restart_pending variables
571+ * to determine whether to shutdown or restart. The child process should
572+ * call signal_parent() directly to tell the parent to die -- this will
573+ * cause neither of those variable to be set, which the parent will
574+ * assume means something serious is wrong (which it will be, for the
575+ * child to force an exit) and so do an exit anyway.
576+ */
577+
578+static void ap_start_shutdown(void)
579+{
580+ if (shutdown_pending == 1)
581+ {
582+ /* Um, is this _probably_ not an error, if the user has
583+ * tried to do a shutdown twice quickly, so we won't
584+ * worry about reporting it.
585+ */
586+ return;
587+ }
588+ shutdown_pending = 1;
589+}
590+
591+/* do a graceful restart if graceful == 1 */
592+static void ap_start_restart(int graceful)
593+{
594+ if (restart_pending == 1)
595+ {
596+ /* Probably not an error - don't bother reporting it */
597+ return;
598+ }
599+ restart_pending = 1;
600+ is_graceful = graceful;
601+}
602+
603+static void sig_term(int sig)
604+{
605+ ap_start_shutdown();
606+}
607+
608+static void restart(int sig)
609+{
610+ ap_start_restart(sig == AP_SIG_GRACEFUL);
611+}
612+
613+static void set_signals(void)
614+{
615+#ifndef NO_USE_SIGACTION
616+ struct sigaction sa;
617+
618+ sigemptyset(&sa.sa_mask);
619+ sa.sa_flags = 0;
620+
621+ if (!one_process) {
622+ sa.sa_handler = sig_coredump;
623+#if defined(SA_ONESHOT)
624+ sa.sa_flags = SA_ONESHOT;
625+#elif defined(SA_RESETHAND)
626+ sa.sa_flags = SA_RESETHAND;
627+#endif
628+ if (sigaction(SIGSEGV, &sa, NULL) < 0)
629+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
630+ "sigaction(SIGSEGV)");
631+#ifdef SIGBUS
632+ if (sigaction(SIGBUS, &sa, NULL) < 0)
633+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
634+ "sigaction(SIGBUS)");
635+#endif
636+#ifdef SIGABORT
637+ if (sigaction(SIGABORT, &sa, NULL) < 0)
638+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
639+ "sigaction(SIGABORT)");
640+#endif
641+#ifdef SIGABRT
642+ if (sigaction(SIGABRT, &sa, NULL) < 0)
643+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
644+ "sigaction(SIGABRT)");
645+#endif
646+#ifdef SIGILL
647+ if (sigaction(SIGILL, &sa, NULL) < 0)
648+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
649+ "sigaction(SIGILL)");
650+#endif
651+ sa.sa_flags = 0;
652+ }
653+ sa.sa_handler = sig_term;
654+ if (sigaction(SIGTERM, &sa, NULL) < 0)
655+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
656+ "sigaction(SIGTERM)");
657+#ifdef SIGINT
658+ if (sigaction(SIGINT, &sa, NULL) < 0)
659+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
660+ "sigaction(SIGINT)");
661+#endif
662+#ifdef SIGXCPU
663+ sa.sa_handler = SIG_DFL;
664+ if (sigaction(SIGXCPU, &sa, NULL) < 0)
665+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
666+ "sigaction(SIGXCPU)");
667+#endif
668+#ifdef SIGXFSZ
669+ sa.sa_handler = SIG_DFL;
670+ if (sigaction(SIGXFSZ, &sa, NULL) < 0)
671+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
672+ "sigaction(SIGXFSZ)");
673+#endif
674+#ifdef SIGPIPE
675+ sa.sa_handler = SIG_IGN;
676+ if (sigaction(SIGPIPE, &sa, NULL) < 0)
677+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
678+ "sigaction(SIGPIPE)");
679+#endif
680+
681+ /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy
682+ * processing one */
683+ sigaddset(&sa.sa_mask, SIGHUP);
684+ sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL);
685+ sa.sa_handler = restart;
686+ if (sigaction(SIGHUP, &sa, NULL) < 0)
687+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
688+ "sigaction(SIGHUP)");
689+ if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0)
690+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
691+ "sigaction(" AP_SIG_GRACEFUL_STRING ")");
692+#else
693+ if (!one_process)
694+ {
695+ apr_signal(SIGSEGV, sig_coredump);
696+#ifdef SIGBUS
697+ apr_signal(SIGBUS, sig_coredump);
698+#endif /* SIGBUS */
699+#ifdef SIGABORT
700+ apr_signal(SIGABORT, sig_coredump);
701+#endif /* SIGABORT */
702+#ifdef SIGABRT
703+ apr_signal(SIGABRT, sig_coredump);
704+#endif /* SIGABRT */
705+#ifdef SIGILL
706+ apr_signal(SIGILL, sig_coredump);
707+#endif /* SIGILL */
708+#ifdef SIGXCPU
709+ apr_signal(SIGXCPU, SIG_DFL);
710+#endif /* SIGXCPU */
711+#ifdef SIGXFSZ
712+ apr_signal(SIGXFSZ, SIG_DFL);
713+#endif /* SIGXFSZ */
714+ }
715+
716+ apr_signal(SIGTERM, sig_term);
717+#ifdef SIGHUP
718+ apr_signal(SIGHUP, restart);
719+#endif /* SIGHUP */
720+#ifdef AP_SIG_GRACEFUL
721+ apr_signal(AP_SIG_GRACEFUL, restart);
722+#endif /* AP_SIG_GRACEFUL */
723+#ifdef SIGPIPE
724+ apr_signal(SIGPIPE, SIG_IGN);
725+#endif /* SIGPIPE */
726+
727+#endif
728+}
729+
730+/*****************************************************************
731+ * Here follows a long bunch of generic server bookkeeping stuff...
732+ */
733+
734+int ap_graceful_stop_signalled(void)
735+{
736+ /* XXX - Does this really work? - Manoj */
737+ return is_graceful;
738+}
739+
740+/*****************************************************************
741+ * Child process main loop.
742+ */
743+
744+static void process_socket(apr_pool_t *p, apr_socket_t *sock, long conn_id,
745+ apr_bucket_alloc_t *bucket_alloc)
746+{
747+ conn_rec *current_conn;
748+ int sock_fd;
749+ apr_status_t rv;
750+ int thread_num = conn_id % thread_limit;
751+ ap_sb_handle_t *sbh;
752+
753+ if ((rv = apr_os_sock_get(&sock_fd, sock)) != APR_SUCCESS)
754+ {
755+ ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, "apr_os_sock_get");
756+ }
757+
758+ _DBG("thread_num=%d sock=%ld sock_fd=%d\n", thread_num, sock, sock_fd);
759+
760+ switch (child_info_table[child_num].type)
761+ {
762+ case CHILD_TYPE_MULTIPLEXER:
763+ _DBG("type=MULTIPLEXER %d",child_num);
764+ break;
765+ case CHILD_TYPE_PROCESSOR:
766+ _DBG("type=PROCESSOR %d",child_num);
767+ break;
768+ default:
769+ _DBG("type UNKNOWN! %d",child_num);
770+ }
771+
772+ if (sock_fd >= FD_SETSIZE)
773+ {
774+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
775+ "new file descriptor %d is too large; you probably need "
776+ "to rebuild Apache with a larger FD_SETSIZE "
777+ "(currently %d)",
778+ sock_fd, FD_SETSIZE);
779+ apr_socket_close(sock);
780+ _DBG("thread_num=%d: exiting with error", thread_num);
781+ return;
782+ }
783+
784+ if (thread_info_table[thread_num].sock_fd < 0)
785+ {
786+ ap_sock_disable_nagle(sock);
787+ }
788+
789+ ap_create_sb_handle(&sbh, p, conn_id / thread_limit, thread_num);
790+ _TRACE_CALL("ap_run_create_connection() [thread_num=%d]", thread_num);
791+ current_conn = ap_run_create_connection(p, ap_server_conf, sock, conn_id,
792+ sbh, bucket_alloc);
793+ _TRACE_RET("ap_run_create_connection() [thread_num=%d]", thread_num);
794+ if (current_conn)
795+ {
796+ _TRACE_CALL("ap_process_connection() [thread_num=%d]", thread_num);
797+ ap_process_connection(current_conn, sock);
798+ _TRACE_RET("ap_process_connection() [thread_num=%d]", thread_num);
799+ _TRACE_CALL("ap_lingering_close() [thread_num=%d]", thread_num);
800+ ap_lingering_close(current_conn);
801+ _TRACE_RET("ap_lingering_close() [thread_num=%d]", thread_num);
802+ }
803+}
804+
805+static metuxmpm_process_connection(conn_rec *conn)
806+{
807+ ap_filter_t *filter;
808+ apr_bucket_brigade *bb;
809+ core_net_rec *net;
810+
811+ _DBG("function entered",0);
812+
813+ /* -- fetch our sockets from the pool -- */
814+ apr_pool_userdata_get((void **)&bb, "metuxmpm_SOCKETS", conn->pool);
815+ if (bb != NULL)
816+ {
817+ /* -- find the 'core' filter and give the socket data to it -- */
818+ for (filter = conn->output_filters; filter != NULL; filter = filter->next)
819+ {
820+ if (!strcmp(filter->frec->name, "core")) break;
821+ }
822+ if (filter != NULL)
823+ {
824+ net = filter->ctx;
825+ net->in_ctx = apr_palloc(conn->pool, sizeof(*net->in_ctx));
826+ net->in_ctx->b = bb;
827+ }
828+ }
829+ _DBG("leaving (DECLINED)", 0);
830+ return DECLINED;
831+}
832+
833+
834+static void *worker_thread_proc(apr_thread_t *, void *);
835+
836+/* Starts a thread as long as we're below max_threads */
837+static int start_thread(void)
838+{
839+ apr_thread_t *thread;
840+ int rc;
841+ int cnt;
842+
843+ cnt = worker_thread_count_get ();
844+
845+ _DBG("thread count currently: %d", cnt);
846+
847+ if (cnt < max_threads - 1)
848+ {
849+ _TRACE_CALL("apr_thread_create()",0);
850+ rc = apr_thread_create(&thread, worker_thread_attr, worker_thread_proc,
851+ &worker_thread_free_ids[worker_thread_count], pchild);
852+ _TRACE_RET("apr_thread_create()",0);
853+ if (rc != APR_SUCCESS)
854+ {
855+ ap_log_error(APLOG_MARK, APLOG_ALERT, rc, ap_server_conf,
856+ "apr_thread_create: unable to create worker thread");
857+ /* In case system resources are maxxed out, we don't want
858+ Apache running away with the CPU trying to fork over and
859+ over and over again if we exit. */
860+ sleep(10);
861+ workers_may_exit = 1;
862+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
863+ return 0;
864+ }
865+ worker_thread_count_add ( 1 );
866+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
867+ _DBG("ok",0);
868+ return 1;
869+ }
870+
871+ /* we already have too many threads running */
872+ _DBG("too many running threads. aborting",0);
873+ if (!thread_overflow_reported)
874+ {
875+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
876+ ap_server_conf,
877+ "server reached MaxThreadsPerChild setting, "
878+ "consider raising the MaxThreadsPerChild or "
879+ "NumServers settings");
880+ thread_overflow_reported = 1;
881+ }
882+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
883+ return 0;
884+}
885+
886+/* Sets workers_may_exit if we received a character on the pipe_of_death */
887+static apr_status_t check_pipe_of_death
888+(
889+ void **csd,
890+ ap_listen_rec *lr,
891+ apr_pool_t *ptrans
892+)
893+{
894+ int ret;
895+ char pipe_read_char;
896+ apr_size_t n = 1;
897+
898+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
899+
900+ if (workers_may_exit) return APR_SUCCESS;
901+
902+ apr_thread_mutex_lock(pipe_of_death_mutex);
81a3ef12 903+ ret = apr_socket_recv(lr->sd, &pipe_read_char, &n);
4a17dc3c
AM
904+ if (APR_STATUS_IS_EAGAIN(ret))
905+ {
906+ /* It lost the lottery. It must continue to suffer
907+ * through a life of servitude. */
908+ }
909+ else
910+ {
911+ if (pipe_read_char != AP_metuxmpm_CHAR_OF_DEATH)
912+ {
913+ _DBG("got wrong char %c", pipe_read_char);
914+ return APR_SUCCESS;
915+ }
916+ /* It won the lottery (or something else is very
917+ * wrong). Embrace death with open arms. */
918+ workers_may_exit = 1;
919+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
920+ }
921+ apr_thread_mutex_unlock(pipe_of_death_mutex);
922+ return APR_SUCCESS;
923+}
924+
925+static apr_status_t receive_from_multiplexer
926+(
927+ void **trans_sock, /* will be filled out w/ the received socket */
928+ ap_listen_rec *lr, /* listener to receive from */
929+ apr_pool_t *ptrans /* transaction wide pool */
930+)
931+{
932+ struct msghdr msg;
933+ struct cmsghdr *cmsg;
934+ char headers[HUGE_STRING_LEN];
935+ char *bodypart;
936+ apr_size_t bodypart_len;
937+ struct iovec iov[2];
938+ int ret, fd_tmp;
939+ apr_os_sock_t ctrl_sock_fd;
940+ apr_os_sock_t trans_sock_fd;
941+
942+ /* -- bucket's, brigades and their allocators */
943+ apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(ptrans);
944+ apr_bucket_brigade *bb = apr_brigade_create(ptrans, alloc);
945+ apr_bucket *bucket;
946+
947+ /* prepare the buffers for receiving data from remote side */
948+ iov[0].iov_base = &bodypart_len;
949+ iov[0].iov_len = sizeof(bodypart_len);
950+ iov[1].iov_base = headers;
951+ iov[1].iov_len = HUGE_STRING_LEN;
952+
953+ cmsg = apr_palloc(ptrans, sizeof(*cmsg) + sizeof(trans_sock_fd));
954+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(trans_sock_fd);
955+
956+ msg.msg_name = NULL;
957+ msg.msg_namelen = 0;
958+ msg.msg_iov = iov;
959+ msg.msg_iovlen = 2;
960+ msg.msg_control = cmsg;
961+ msg.msg_controllen = cmsg->cmsg_len;
962+
963+ /* -- receive data from socket -- */
964+ apr_os_sock_get(&ctrl_sock_fd, lr->sd);
965+ _DBG("receiving from sock_fd=%d", ctrl_sock_fd);
966+ ret = recvmsg(ctrl_sock_fd, &msg, 0);
967+
968+ /* -- extract socket from the cmsg -- */
969+ memcpy(&trans_sock_fd, CMSG_DATA(cmsg), sizeof(trans_sock_fd));
970+ apr_os_sock_put((apr_socket_t **)trans_sock, &trans_sock_fd, ptrans);
971+ apr_os_sock_get(&fd_tmp, *trans_sock);
972+
973+
974+ _DBG("trans_sock=%ld fdx=%d sock_fd=%d",
975+ *trans_sock, trans_sock_fd, fd_tmp);
976+
977+ _DBG("headers=\"%s\"", headers);
978+
979+ /* -- store received data into an brigade and add
980+ it to the current transaction's pool -- */
981+ bucket = apr_bucket_eos_create(alloc);
982+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
983+ bucket = apr_bucket_socket_create(*trans_sock, alloc);
984+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
985+
986+ /* Receive the bodypart (if there is one) and insert it in the brigade */
987+ if (bodypart_len) {
988+ _DBG("Receiving the bodypart (bodypart_len=%d)", bodypart_len);
989+ bodypart = apr_palloc(ptrans, bodypart_len);
990+ ret = recv(ctrl_sock_fd, bodypart, HUGE_STRING_LEN, 0);
991+
992+ _DBG("bodypart=\"%s\"", bodypart);
993+ bucket = apr_bucket_heap_create(bodypart,
994+ bodypart_len, NULL, alloc);
995+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
996+ } else {
997+ _DBG("There is no bodypart",0);
998+ }
999+
1000+ bucket = apr_bucket_heap_create(headers,
1001+ strlen(headers), NULL, alloc);
1002+ /* DS: I really don't like that strlen here */
1003+
1004+ APR_BRIGADE_INSERT_HEAD(bb, bucket);
1005+
1006+ apr_pool_userdata_set(bb, "metuxmpm_SOCKETS", NULL, ptrans);
1007+ _DBG("returning 0",0);
1008+ return 0;
1009+}
1010+
1011+/* idle_thread_count should be incremented before starting a worker_thread */
1012+
1013+static void *worker_thread_proc(apr_thread_t *thd, void *arg)
1014+{
1015+ apr_socket_t *sock;
1016+ apr_pool_t *tpool; /* Pool for this thread */
1017+ apr_pool_t *ptrans; /* Pool for per-transaction stuff */
1018+ int srv;
1019+ int thread_num = *((int *) arg);
1020+ long conn_id = child_num * thread_limit + thread_num;
1021+ apr_pollfd_t *pollset;
1022+ apr_status_t rv;
1023+ ap_listen_rec *lr_walk;
1024+ int n;
1025+ int thread_cnt;
1026+ apr_bucket_alloc_t *bucket_alloc;
1027+
1028+ _DBG("function starting",0);
1029+
1030+ /* === allocate thread pools etc === */
1031+ apr_thread_mutex_lock(thread_pool_parent_mutex);
1032+ apr_pool_create(&tpool, thread_pool_parent);
1033+ apr_thread_mutex_unlock(thread_pool_parent_mutex);
1034+ apr_pool_create(&ptrans, tpool);
1035+
1036+ (void) ap_update_child_status_from_indexes(child_num, thread_num,
1037+ SERVER_STARTING,
1038+ (request_rec *) NULL);
1039+
1040+ bucket_alloc = apr_bucket_alloc_create(apr_thread_pool_get(thd));
1041+
1042+ apr_thread_mutex_lock(idle_thread_count_mutex);
1043+ if (idle_thread_count < max_spare_threads)
1044+ {
1045+ idle_thread_count++;
1046+ _DBG("idle_thread_count: %d", idle_thread_count);
1047+ apr_thread_mutex_unlock(idle_thread_count_mutex);
1048+ }
1049+ else
1050+ {
1051+ _DBG("too many idle threads: %d (max %d)", idle_thread_count, max_spare_threads );
1052+ apr_thread_mutex_unlock(idle_thread_count_mutex);
1053+ goto worker_out;
1054+ }
1055+
1056+ while (!workers_may_exit)
1057+ {
1058+ apr_int16_t event;
1059+
1060+ _DBG("loop. conn_id=%d req_max=%d req_remain=%d",
1061+ conn_id, ap_max_requests_per_child, requests_this_child);
1062+
1063+ ((ap_max_requests_per_child != 0) &&
1064+ (requests_this_child < 1) && (workers_may_exit=1));
1065+
1066+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
1067+ if (workers_may_exit) goto worker_out;
1068+
1069+ (void) ap_update_child_status_from_indexes(child_num, thread_num,
1070+ SERVER_READY,
1071+ (request_rec *) NULL);
1072+
1073+ THREAD_ACCEPT_LOCK;
1074+
1075+ /* -- setup pollset -- */
1076+ /* NOTE: we do _not_ do this upwards anylonger */
81a3ef12
AM
1077+ apr_pollset_create(&pollset, num_listensocks, tpool, 0);
1078+ apr_pollset_create(&pollset, num_listensocks, ptrans, 0);
4a17dc3c
AM
1079+ for(lr_walk = ap_listeners; lr_walk != NULL; lr_walk = lr_walk->next)
1080+ {
1081+ int fd;
81a3ef12
AM
1082+ apr_pollfd_t new_pollfd;
1083+ new_pollfd.desc_type = APR_POLL_SOCKET;
1084+ new_pollfd.reqevents = APR_POLLIN;
1085+ new_pollfd.desc.s = lr_walk->sd;
1086+ new_pollfd.client_data = lr_walk;
1087+ apr_pollset_add(pollset, &new_pollfd);
4a17dc3c
AM
1088+ apr_os_sock_get(&fd, lr_walk->sd);
1089+ _DBG("adding fd %d to pollset", fd);
1090+ }
1091+
1092+ if (workers_may_exit) goto worker_out;
1093+ _TRACE_CALL("apr_poll()",0);
1094+ srv = apr_poll(pollset, num_listensocks, &n, -1);
1095+ _TRACE_RET("apr_poll()",0);
1096+
1097+ if (srv != APR_SUCCESS)
1098+ {
1099+ if (APR_STATUS_IS_EINTR(srv))
1100+ {
1101+ _DBG("apr_poll() has been interrupted", 0);
1102+ THREAD_ACCEPT_UNLOCK;
1103+ continue;
1104+ }
1105+
1106+ /* apr_poll() will only return errors in catastrophic
1107+ * circumstances. Let's try exiting gracefully, for now. */
1108+ ap_log_error(APLOG_MARK, APLOG_ERR, srv, (const server_rec *)
1109+ ap_server_conf, "apr_poll: (listen)");
1110+ workers_may_exit = 1;
1111+ _DBG("poll error!",0);
1112+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
1113+ THREAD_ACCEPT_UNLOCK;
1114+ goto worker_out;
1115+ }
1116+
1117+ /* find a listener */
1118+ _DBG("looking for an listener",0);
1119+ for (lr_walk=ap_listeners; lr_walk!=NULL; lr_walk = lr_walk->next)
1120+ {
1121+ int fd_tmp;
1122+ apr_os_sock_get(&fd_tmp, lr_walk->sd);
1123+ _DBG(" ... trying w/ fd=%d", fd_tmp);
1124+ apr_poll_revents_get(&event, lr_walk->sd, pollset);
1125+ if (event & (APR_POLLIN))
1126+ {
1127+ THREAD_ACCEPT_UNLOCK;
1128+ goto got_fd;
1129+ }
1130+ if (event & (APR_POLLERR))
1131+ {
1132+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
1133+ "got POLLERR in line 870");
1134+ }
1135+ }
1136+
1137+ THREAD_ACCEPT_UNLOCK;
1138+ _DBG("WARN: did not find the right listener",0);
1139+ sleep ( 1 );
1140+ continue;
1141+
1142+ got_fd:
1143+ _DBG("input available ... resetting socket.",0);
1144+ sock = NULL; /* important! */
1145+
1146+ _TRACE_CALL("accept_func()",0);
1147+ rv = lr_walk->accept_func((void*)&sock, lr_walk, ptrans);
1148+ _TRACE_RET("accept_func()",0);
1149+
1150+ if (rv == APR_EGENERAL)
1151+ {
1152+ /* E[NM]FILE, ENOMEM, etc */
1153+ _DBG("there was some error." ,0);
1154+ workers_may_exit = 1;
1155+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
1156+ break;
1157+ }
1158+
1159+ apr_thread_mutex_lock(idle_thread_count_mutex);
1160+ if (idle_thread_count > min_spare_threads)
1161+ {
1162+ idle_thread_count--;
1163+ }
1164+ else
1165+ {
1166+ if (!start_thread())
1167+ {
1168+ idle_thread_count--;
1169+ }
1170+ }
1171+ apr_thread_mutex_unlock(idle_thread_count_mutex);
1172+
1173+ if (!setjmp(thread_info_table[thread_num].jmpbuffer))
1174+ {
1175+ _DBG("marked jmpbufffer",0);
1176+ _TRACE_CALL("process_socket()",0);
1177+ process_socket(ptrans, sock, conn_id, bucket_alloc);
1178+ _TRACE_RET("process_socket()",0);
1179+ }
1180+ else
1181+ {
1182+ _DBG("landed from longjmp",0);
1183+ thread_info_table[thread_num].sock_fd = AP_metuxmpm_THISCHILD;
1184+ }
1185+ requests_this_child--;
1186+ apr_pool_clear(ptrans);
1187+ }
1188+
1189+ _DBG("thread loop finished",0);
1190+worker_out:
1191+ _DBG("this thread's work is done ... workers_may_exit=%d",workers_may_exit);
1192+
1193+ /* == think about it == */
1194+ apr_thread_mutex_lock(idle_thread_count_mutex);
1195+ idle_thread_count--;
1196+ apr_thread_mutex_unlock(idle_thread_count_mutex);
1197+
1198+ /* == */
1199+ apr_thread_mutex_lock(thread_pool_parent_mutex);
1200+ ap_update_child_status_from_indexes(child_num, thread_num, SERVER_DEAD,
1201+ (request_rec *) NULL);
1202+ apr_pool_destroy(tpool);
1203+ apr_thread_mutex_unlock(thread_pool_parent_mutex);
1204+
1205+ thread_cnt = worker_thread_count_add ( -1 );
1206+ worker_thread_free_ids[thread_cnt] = thread_num;
1207+ if (!thread_cnt)
1208+ {
1209+ /* All the threads have exited, now finish the shutdown process
1210+ * by signalling the sigwait thread */
1211+ _DBG("all workers have quit. killing myself (%d) with SIGTERM", my_pid);
1212+ kill(my_pid, SIGTERM);
1213+ }
1214+ else
1215+ {
1216+ _DBG("this is not the time to die - %d threads are still alive", thread_cnt);
1217+ _DBG("WATCH: workers_may_exit=%d", workers_may_exit);
1218+ }
1219+
1220+ apr_bucket_alloc_destroy(bucket_alloc);
1221+ _DBG("leaving. good bye",0);
1222+ return NULL;
1223+}
1224+
1225+
1226+
1227+/* Set group privileges.
1228+ *
1229+ * Note that we use the username as set in the config files, rather than
1230+ * the lookup of to uid --- the same uid may have multiple passwd entries,
1231+ * with different sets of groups for each.
1232+ */
1233+
1234+static int set_group_privs(uid_t uid, gid_t gid)
1235+{
1236+ if (!geteuid())
1237+ {
1238+ const char *name;
1239+
1240+ /* Get username if passed as a uid */
1241+
1242+ struct passwd *ent;
1243+
1244+ if ((ent = getpwuid(uid)) == NULL)
1245+ {
1246+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1247+ "getpwuid: couldn't determine user name from uid %u, "
1248+ "you probably need to modify the User directive",
1249+ (unsigned)uid);
1250+ return -1;
1251+ }
1252+
1253+ name = ent->pw_name;
1254+
1255+ /*
1256+ * Set the GID before initgroups(), since on some platforms
1257+ * setgid() is known to zap the group list.
1258+ */
1259+ if (setgid(gid) == -1)
1260+ {
1261+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1262+ "setgid: unable to set group id to Group %u",
1263+ (unsigned)gid);
1264+ return -1;
1265+ }
1266+
1267+ /* Reset `groups' attributes. */
1268+
1269+ if (initgroups(name, gid) == -1)
1270+ {
1271+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1272+ "initgroups: unable to set groups for User %s "
1273+ "and Group %u", name, (unsigned)gid);
1274+ return -1;
1275+ }
1276+ }
1277+ return 0;
1278+}
1279+
1280+
1281+static int metuxmpm_setup_child(int childnum)
1282+{
1283+ child_info_t *ug = &child_info_table[childnum];
1284+
1285+ if (ug->uid == -1 && ug->gid == -1) {
1286+ return unixd_setup_child();
1287+ }
1288+ if (set_group_privs(ug->uid, ug->gid)) {
1289+ return -1;
1290+ }
1291+ /* Only try to switch if we're running as root */
1292+ if (!geteuid()
1293+ && (
1294+#ifdef _OSD_POSIX
1295+ os_init_job_environment(server_conf, unixd_config.user_name,
1296+ one_process) != 0 ||
1297+#endif
1298+ setuid(ug->uid) == -1)) {
1299+ ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
1300+ "setuid: unable to change to uid: %ld",
1301+ (long) ug->uid);
1302+ return -1;
1303+ }
1304+ return 0;
1305+}
1306+
1307+static int check_signal(int signum)
1308+{
1309+ _DBG("signum=%d", signum);
1310+ switch (signum) {
1311+ case SIGTERM:
1312+ case SIGINT:
1313+ just_die(signum);
1314+ return 1;
1315+ }
1316+ return 0;
1317+}
1318+
1319+typedef struct metuxmpm_header
1320+{
1321+ char *headers;
1322+ apr_pool_t *p;
1323+} metuxmpm_header;
1324+
1325+/* Send a single HTTP header field to the client. Note that this function
1326+ * is used in calls to table_do(), so their interfaces are co-dependent.
1327+ * In other words, don't change this one without checking table_do in alloc.c.
1328+ * It returns true unless there was a write error of some kind.
1329+ */
1330+static int metuxmpm_header_field(metuxmpm_header *h,
1331+ const char *fieldname, const char *fieldval)
1332+{
1333+ apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL);
1334+ return 1;
1335+}
1336+
1337+static inline ap_listen_rec* listen_add ( apr_pool_t* pool, apr_socket_t *sock, void* accept_func )
1338+{
1339+ ap_listen_rec *lr_walk, *lr_new;
1340+
1341+ _DBG("function started",0);
1342+ /* -- create an new listener for this child -- */
1343+ lr_new = apr_palloc(pool, sizeof(*lr_new));
1344+ lr_new->sd = sock;
1345+ lr_new->active = 1;
1346+ lr_new->accept_func = accept_func;
1347+ lr_new->next = NULL;
1348+
1349+ /* -- add the new listener_rec into the list -- */
1350+ /* FIXME: should we somehow lock this list ? */
1351+ if (lr_walk = ap_listeners)
1352+ {
1353+ while (lr_walk->next) lr_walk = lr_walk->next;
1354+ lr_walk->next = lr_new;
1355+ }
1356+ else
1357+ {
1358+ ap_listeners = lr_walk = lr_new;
1359+ }
1360+ num_listensocks++;
1361+ return lr_new;
1362+}
1363+
1364+static inline void listen_clear ()
1365+{
1366+ ap_listen_rec *lr_walk;
1367+
1368+ _DBG("function started",0);
1369+
1370+ /* FIXME: should we somehow lock this list ? */
1371+ while (ap_listeners)
1372+ {
1373+ lr_walk = ap_listeners->next;
1374+ apr_socket_close(ap_listeners->sd);
1375+ ap_listeners = lr_walk;
1376+ }
1377+ num_listensocks=0;
1378+}
1379+
1380+/* -- main routine of an child process -- */
1381+static void child_main(int child_num_arg)
1382+{
1383+ int i;
1384+ apr_status_t rv;
1385+ apr_socket_t *sock = NULL;
1386+
1387+ my_pid = getpid();
1388+ child_num = child_num_arg;
1389+
1390+ _DBG("sock_fd_in=%d sock_fd_out=%d", child_info_table[child_num].input, child_info_table[child_num].output );
1391+
1392+ /* -- allocate an new pool for us -- */
1393+ apr_pool_create(&pchild, pconf);
1394+ if (child_info_table[child_num].chroot_dir){
1395+ _DBG("chroot to %s",child_info_table[child_num].chroot_dir);
1396+ if (chroot(child_info_table[child_num].chroot_dir)){
1397+ _DBG("chroot failure %s",child_info_table[child_num].chroot_dir);
1398+ return;
1399+ }
1400+ }
1401+
1402+ switch (child_info_table[child_num].type)
1403+ {
1404+ case CHILD_TYPE_MULTIPLEXER:
1405+ _DBG("MULTIPLEXER %d", child_num);
1406+ break;
1407+
1408+ case CHILD_TYPE_PROCESSOR:
1409+ _DBG("PROCESSOR %d", child_num);
1410+
1411+ /* -- create new listener to receive from multiplexer -- */
1412+ apr_os_sock_put(&sock, &child_info_table[child_num].input, pconf);
1413+ listen_clear ();
1414+ listen_add ( pconf, sock, receive_from_multiplexer );
1415+ break;
1416+
1417+ default:
1418+ _DBG("unspecified child type for %d sleeping a while ...", child_num);
1419+ sleep ( 5 );
1420+ return;
1421+ }
1422+ /*stuff to do before we switch id's, so we have permissions.*/
1423+
1424+ /* -- init child process (uid switching etc) -- */
1425+ (metuxmpm_setup_child(child_num) && clean_child_exit(APEXIT_CHILDFATAL));
1426+ ap_run_child_init(pchild, ap_server_conf);
1427+
1428+ /*done with init critical section */
1429+
1430+ apr_setup_signal_thread();
1431+
1432+ requests_this_child = ap_max_requests_per_child;
1433+
1434+ /* Setup worker threads */
1435+
1436+ _DBG("setting up worker threads ... " ,0);
1437+ ((threads_to_start > max_threads) && (threads_to_start = max_threads));
1438+ idle_thread_count = threads_to_start;
1439+ workers_may_exit = 0;
1440+ worker_thread_count = 0;
1441+ worker_thread_free_ids = (int *)apr_pcalloc(pchild, thread_limit * sizeof(int));
1442+ for (i = 0; i < max_threads; i++)
1443+ {
1444+ worker_thread_free_ids[i] = i;
1445+ }
1446+ apr_pool_create(&thread_pool_parent, pchild);
1447+ apr_thread_mutex_create(&thread_pool_parent_mutex,
1448+ APR_THREAD_MUTEX_DEFAULT, pchild);
1449+ apr_thread_mutex_create(&idle_thread_count_mutex,
1450+ APR_THREAD_MUTEX_DEFAULT, pchild);
1451+ apr_thread_mutex_create(&worker_thread_count_mutex,
1452+ APR_THREAD_MUTEX_DEFAULT, pchild);
1453+ apr_thread_mutex_create(&pipe_of_death_mutex,
1454+ APR_THREAD_MUTEX_DEFAULT, pchild);
1455+ apr_thread_mutex_create(&thread_accept_mutex,
1456+ APR_THREAD_MUTEX_DEFAULT, pchild);
1457+
1458+ apr_threadattr_create(&worker_thread_attr, pchild);
1459+ apr_threadattr_detach_set(worker_thread_attr, 1);
1460+
1461+ /* We are creating worker threads right now */
1462+ for (i=0; i < threads_to_start; i++)
1463+ {
1464+ /* start_thread shouldn't fail here */
1465+ _TRACE_CALL("start_thread()",0);
1466+ if (!start_thread()) break;
1467+ _TRACE_RET("start_thread()",0);
1468+ }
1469+
1470+ _TRACE_CALL("apr_signal_thread()",0);
1471+ apr_signal_thread(check_signal);
1472+ _TRACE_RET("apr_signal_thread",0);
1473+}
1474+
1475+static int make_child(server_rec *s, int slot)
1476+{
1477+ int pid;
1478+
1479+ switch (child_info_table[slot].type)
1480+ {
1481+ case CHILD_TYPE_MULTIPLEXER: break;
1482+ case CHILD_TYPE_PROCESSOR: break;
1483+ default:
1484+ _DBG("no valid client in slot %d", slot);
1485+ sleep(1);
1486+ return 0;
1487+ }
1488+
1489+ if (slot + 1 > ap_max_daemons_limit)
1490+ {
1491+ ap_max_daemons_limit = slot + 1;
1492+ }
1493+
1494+ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING,
1495+ (request_rec *) NULL);
1496+
1497+ if ((pid = fork()) == -1)
1498+ {
1499+ ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,
1500+ "fork: Unable to fork new process");
1501+ /* In case system resources are maxxed out, we don't want
1502+ * Apache running away with the CPU trying to fork over and
1503+ * over and over again. */
1504+ sleep(10);
1505+
1506+ return -1;
1507+ }
1508+
1509+ if (!pid)
1510+ {
1511+#ifdef HAVE_BINDPROCESSOR
1512+ /* By default, AIX binds to a single processor. This bit unbinds
1513+ * children which will then bind to another CPU.
1514+ */
1515+ int status = bindprocessor(BINDPROCESS, (int)getpid(),
1516+ PROCESSOR_CLASS_ANY);
1517+ if (status != OK) {
1518+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno,
1519+ ap_server_conf, "processor unbind failed %d", status);
1520+ }
1521+#endif
1522+
1523+ RAISE_SIGSTOP(MAKE_CHILD);
1524+
1525+ /* XXX - For an unthreaded server, a signal handler will be necessary
1526+ * apr_signal(SIGTERM, just_die);
1527+ */
1528+ child_main(slot);
1529+ clean_child_exit(0);
1530+ }
1531+ /* else */
1532+ ap_scoreboard_image->parent[slot].pid = pid;
1533+
1534+ ap_child_table[slot].pid = pid;
1535+ ap_child_table[slot].status = SERVER_ALIVE;
1536+
1537+ return 0;
1538+}
1539+
1540+/* start up a bunch of children */
1541+static int startup_children(int number_to_start)
1542+{
1543+ int i;
1544+
1545+ for (i = 0; number_to_start && i < num_childs; ++i)
1546+ {
1547+ if (ap_child_table[i].pid) continue;
1548+ if (make_child(ap_server_conf, i) < 0) break;
1549+ --number_to_start;
1550+ }
1551+ return number_to_start;
1552+}
1553+
1554+
1555+/*
1556+ * spawn_rate is the number of children that will be spawned on the
1557+ * next maintenance cycle if there aren't enough servers. It is
1558+ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
1559+ * without the need to spawn.
1560+ */
1561+static int spawn_rate = 1;
1562+#ifndef MAX_SPAWN_RATE
1563+#define MAX_SPAWN_RATE (32)
1564+#endif
1565+static int hold_off_on_exponential_spawning;
1566+
1567+static void perform_child_maintenance(void)
1568+{
1569+ int i;
1570+ int free_length;
1571+ int free_slots[MAX_SPAWN_RATE];
1572+ int last_non_dead = -1;
1573+
1574+ /* initialize the free_list */
1575+ free_length = 0;
1576+
1577+ for (i = 0; i < num_childs; ++i)
1578+ {
1579+ if (ap_child_table[i].pid == 0)
1580+ {
1581+ if (free_length < spawn_rate)
1582+ {
1583+ free_slots[free_length] = i;
1584+ ++free_length;
1585+ }
1586+ }
1587+ else
1588+ {
1589+ last_non_dead = i;
1590+ }
1591+
1592+ if (i >= ap_max_daemons_limit && free_length >= spawn_rate)
1593+ {
1594+ break;
1595+ }
1596+ }
1597+ ap_max_daemons_limit = last_non_dead + 1;
1598+
1599+ if (free_length > 0)
1600+ {
1601+ for (i = 0; i < free_length; ++i)
1602+ {
1603+ _TRACE_CALL("make_child()",0);
1604+ make_child(ap_server_conf, free_slots[i]);
1605+ _TRACE_RET("make_child()",0);
1606+ }
1607+ /* the next time around we want to spawn twice as many if this
1608+ * wasn't good enough, but not if we've just done a graceful
1609+ */
1610+ if (hold_off_on_exponential_spawning)
1611+ {
1612+ --hold_off_on_exponential_spawning;
1613+ }
1614+ else if (spawn_rate < MAX_SPAWN_RATE)
1615+ {
1616+ spawn_rate *= 2;
1617+ }
1618+ }
1619+ else
1620+ {
1621+ spawn_rate = 1;
1622+ }
1623+}
1624+
1625+static void server_main_loop(int remaining_children_to_start)
1626+{
1627+ apr_exit_why_e exitwhy;
1628+ apr_proc_t pid;
1629+ int child_slot;
1630+ int status;
1631+ int i;
1632+ static int l=0;
1633+
1634+ while (!restart_pending && !shutdown_pending)
1635+ {
1636+ ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
1637+
1638+ if (pid.pid != -1)
1639+ {
1640+ if (ap_process_child_status(&pid, exitwhy, status)==APEXIT_CHILDFATAL)
1641+ {
1642+ _DBG("shutdown pending ...",0);
1643+ shutdown_pending = 1;
1644+ child_fatal = 1;
1645+ return;
1646+ }
1647+ /* non-fatal death... note that it's gone in the child table and
1648+ * clean out the status table. */
1649+ _DBG("child has #%d died ...", child_slot);
1650+ child_slot = -1;
1651+ for (i = 0; i < ap_max_daemons_limit; ++i)
1652+ {
1653+ if (ap_child_table[i].pid == pid.pid)
1654+ {
1655+ child_slot = i;
1656+ break;
1657+ }
1658+ }
1659+ if (child_slot >= 0)
1660+ {
1661+ ap_child_table[child_slot].pid = 0;
1662+ ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD,
1663+ (request_rec *) NULL);
1664+
1665+
1666+ if (remaining_children_to_start && (child_slot < num_childs))
1667+ {
1668+ /* we're still doing a 1-for-1 replacement of dead
1669+ * children with new children
1670+ */
1671+ _DBG("replacing by new child ...",0);
1672+ make_child(ap_server_conf, child_slot);
1673+ --remaining_children_to_start;
1674+ }
1675+#if APR_HAS_OTHER_CHILD
1676+ }
81a3ef12 1677+ else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == 0)
4a17dc3c
AM
1678+ {
1679+ /* handled */
1680+#endif
1681+ }
1682+ else if (is_graceful)
1683+ {
1684+ /* Great, we've probably just lost a slot in the
1685+ * child table. Somehow we don't know about this
1686+ * child.
1687+ */
1688+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
1689+ ap_server_conf,
1690+ "long lost child came home! (pid %ld)",
1691+ (long)pid.pid);
1692+ }
1693+ /* Don't perform idle maintenance when a child dies,
1694+ * only do it when there's a timeout. Remember only a
1695+ * finite number of children can die, and it's pretty
1696+ * pathological for a lot to die suddenly.
1697+ */
1698+ continue;
1699+ }
1700+ else if (remaining_children_to_start)
1701+ {
1702+ /* we hit a 1 second timeout in which none of the previous
1703+ * generation of children needed to be reaped... so assume
1704+ * they're all done, and pick up the slack if any is left.
1705+ */
1706+ _TRACE_CALL("startup_children()",0);
1707+ remaining_children_to_start = startup_children(remaining_children_to_start);
1708+ _TRACE_RET("startup_children()",0);
1709+ /* In any event we really shouldn't do the code below because
1710+ * few of the servers we just started are in the IDLE state
1711+ * yet, so we'd mistakenly create an extra server.
1712+ */
1713+ continue;
1714+ }
1715+
1716+ perform_child_maintenance();
1717+ }
1718+}
1719+
1720+int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
1721+{
1722+ int remaining_children_to_start;
1723+ int i;
1724+ int fd;
1725+ apr_status_t rv;
1726+ apr_size_t one = 1;
1727+ apr_socket_t *sock = NULL;
1728+
1729+ ap_log_pid(pconf, ap_pid_fname);
1730+
1731+ first_server_limit = server_limit;
1732+ first_thread_limit = thread_limit;
1733+ if (changed_limit_at_restart)
1734+ {
1735+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
1736+ "WARNING: Attempt to change ServerLimit or ThreadLimit "
1737+ "ignored during restart");
1738+ changed_limit_at_restart = 0;
1739+ }
1740+
1741+ ap_server_conf = s;
1742+
1743+ /* Initialize cross-process accept lock */
1744+ ap_lock_fname = apr_psprintf(_pconf, "%s.%u",
1745+ ap_server_root_relative(_pconf, ap_lock_fname),
1746+ my_pid);
1747+ rv = ACCEPT_PROC_MUTEX_CREATE;
1748+ if (rv != APR_SUCCESS)
1749+ {
1750+ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
1751+ "Couldn't create cross-process lock");
1752+ return 1;
1753+ }
1754+
1755+ if (!is_graceful)
1756+ {
1757+ if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK)
1758+ {
1759+ return 1;
1760+ }
1761+ }
1762+ /* Initialize the child table */
1763+ if (!is_graceful)
1764+ {
1765+ for (i = 0; i < server_limit; i++)
1766+ {
1767+ ap_child_table[i].pid = 0;
1768+ }
1769+ }
1770+
1771+ /* We need to put the new listeners at the end of the ap_listeners
1772+ * list. If we don't, then the pool will be cleared before the
1773+ * open_logs phase is called for the second time, and ap_listeners
1774+ * will have only invalid data. If that happens, then the sockets
1775+ * that we opened using make_sock() will be lost, and the server
1776+ * won't start.
1777+ */
1778+ apr_os_file_get(&fd, pipe_of_death_in);
1779+ apr_os_sock_put(&sock, &fd, pconf);
1780+
1781+ listen_add ( pconf, sock, check_pipe_of_death );
1782+ set_signals();
1783+
1784+ /* If we're doing a graceful_restart then we're going to see a lot
1785+ * of children exiting immediately when we get into the main loop
1786+ * below (because we just sent them AP_SIG_GRACEFUL). This happens
1787+ * pretty rapidly... and for each one that exits we'll start a new one
1788+ * until we reach at least daemons_min_free. But we may be permitted to
1789+ * start more than that, so we'll just keep track of how many we're
1790+ * supposed to start up without the 1 second penalty between each fork.
1791+ */
1792+ remaining_children_to_start = num_childs;
1793+ if (!is_graceful) {
1794+ remaining_children_to_start = \
1795+ startup_children(remaining_children_to_start);
1796+ }
1797+ else {
1798+ /* give the system some time to recover before kicking into
1799+ * exponential mode */
1800+ hold_off_on_exponential_spawning = 10;
1801+ }
1802+
1803+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
1804+ "%s configured -- resuming normal operations",
1805+ ap_get_server_version());
1806+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
1807+ "Server built: %s", ap_get_server_built());
1808+#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
1809+#ifdef NO_SERIALIZED_ACCEPT
1810+ _DBG("AcceptMutex: n/a (compiled w/ NO_SERIALIZED_ACCEPT)", 0 );
1811+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1812+ "AcceptMutex: n/a (compiled w/ NO_SERIALIZED_ACCEPT)" );
1813+#else
1814+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
1815+ "AcceptMutex: %s (default: %s)",
1816+ apr_proc_mutex_name(process_accept_mutex),
1817+ apr_proc_mutex_defname());
1818+#endif
1819+#endif
1820+ restart_pending = shutdown_pending = 0;
1821+
1822+ server_main_loop(remaining_children_to_start);
1823+
1824+ if (shutdown_pending)
1825+ {
1826+ /* Time to gracefully shut down:
1827+ * Kill child processes, tell them to call child_exit, etc...
1828+ */
1829+ if (unixd_killpg(getpgrp(), SIGTERM) < 0)
1830+ {
1831+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
1832+ "killpg SIGTERM");
1833+ }
1834+ ap_reclaim_child_processes(1); /* Start with SIGTERM */
1835+
1836+ if (!child_fatal)
1837+ {
1838+ /* cleanup pid file on normal shutdown */
1839+ const char *pidfile = NULL;
1840+ pidfile = ap_server_root_relative (pconf, ap_pid_fname);
1841+ if (pidfile != NULL && unlink(pidfile) == 0) {
1842+ ap_log_error(APLOG_MARK, APLOG_INFO, 0,
1843+ ap_server_conf,
1844+ "removed PID file %s (pid=%ld)",
1845+ pidfile, (long)getpid());
1846+ }
1847+
1848+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
1849+ ap_server_conf, "caught SIGTERM, shutting down");
1850+ }
1851+ return 1;
1852+ }
1853+
1854+ /* we've been told to restart */
1855+ apr_signal(SIGHUP, SIG_IGN);
1856+
1857+ if (one_process) return 1; /* not worth thinking about */
1858+
1859+ if (is_graceful)
1860+ {
1861+ char char_of_death = AP_metuxmpm_CHAR_OF_DEATH;
1862+
1863+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
1864+ ap_server_conf, AP_SIG_GRACEFUL_STRING " received. "
1865+ "Doing graceful restart");
1866+
1867+ /* This is mostly for debugging... so that we know what is still
1868+ * gracefully dealing with existing request.
1869+ */
1870+
1871+ for (i = 0; i < num_childs; ++i)
1872+ {
1873+ ((ap_child_table[i].pid) && (ap_child_table[i].status = SERVER_DYING));
1874+ }
1875+
1876+ /* give the children the signal to die */
1877+ for (i = 0; i < num_childs;)
1878+ {
1879+ if ((rv = apr_file_write(pipe_of_death_out, &char_of_death,&one)) != APR_SUCCESS)
1880+ {
1881+ if (APR_STATUS_IS_EINTR(rv)) continue;
1882+ ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,
1883+ "write pipe_of_death");
1884+ }
1885+ i++;
1886+ }
1887+ }
1888+ else
1889+ {
1890+ /* Kill 'em all. Since the child acts the same on the parents SIGTERM
1891+ * and a SIGHUP, we may as well use the same signal, because some user
1892+ * pthreads are stealing signals from us left and right.
1893+ */
1894+ if (unixd_killpg(getpgrp(), SIGTERM) < 0)
1895+ {
1896+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
1897+ "killpg SIGTERM");
1898+ }
1899+ ap_reclaim_child_processes(1); /* Start with SIGTERM */
1900+ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0,
1901+ ap_server_conf, "SIGHUP received. Attempting to restart");
1902+ }
1903+ return 0;
1904+}
1905+
1906+/* This really should be a post_config hook, but the error log is already
1907+ * redirected by that point, so we need to do this in the open_logs phase.
1908+ */
1909+static int metuxmpm_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
1910+{
1911+ apr_status_t rv;
1912+
1913+ pconf = p;
1914+ ap_server_conf = s;
1915+
1916+ _DBG("port=%d", ap_server_conf->port);
1917+
1918+ if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) {
1919+ ap_log_error(APLOG_MARK, APLOG_ALERT|APLOG_STARTUP, 0,
1920+ NULL, "metuxmpm_open_logs(): no listening sockets available, shutting down");
1921+ return DONE;
1922+ }
1923+
1924+ ap_log_pid(pconf, ap_pid_fname);
1925+
1926+ if ((rv = ap_mpm_pod_open(pconf, &pod))) {
1927+ ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_STARTUP, rv, NULL,
1928+ "Could not open pipe-of-death.");
1929+ return DONE;
1930+ }
1931+
1932+ if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out,
1933+ pconf)) != APR_SUCCESS) {
1934+ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
1935+ (const server_rec*) ap_server_conf,
1936+ "apr_file_pipe_create (apipe_of_death)");
1937+ exit(1);
1938+ }
1939+ if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {
1940+ ap_log_error(APLOG_MARK, APLOG_ERR, rv,
1941+ (const server_rec*) ap_server_conf,
1942+ "apr_file_pipe_timeout_set (pipe_of_death)");
1943+ exit(1);
1944+ }
1945+
1946+ return OK;
1947+}
1948+
1949+static int metuxmpm_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
1950+{
1951+ static int restart_num = 0;
1952+ int no_detach, debug, foreground;
1953+ ap_directive_t *pdir;
1954+ int i;
1955+ int tmp_server_limit = DEFAULT_SERVER_LIMIT;
1956+ int tmp_thread_limit = DEFAULT_THREAD_LIMIT;
1957+ apr_status_t rv;
1958+
1959+ debug = ap_exists_config_define("DEBUG");
1960+
1961+ if (debug) {
1962+ foreground = one_process = 1;
1963+ no_detach = 0;
1964+ }
1965+ else {
1966+ one_process = ap_exists_config_define("ONE_PROCESS");
1967+ no_detach = ap_exists_config_define("NO_DETACH");
1968+ foreground = ap_exists_config_define("FOREGROUND");
1969+ }
1970+
1971+ /* FIXME */
1972+/* no_detach = 0;
1973+ foreground = 0; */
1974+
1975+ /* sigh, want this only the second time around */
1976+ if (restart_num++ == 1)
1977+ {
1978+ is_graceful = 0;
1979+
1980+ if (!one_process && !foreground)
1981+ {
1982+ rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND
1983+ : APR_PROC_DETACH_DAEMONIZE);
1984+ if (rv != APR_SUCCESS) {
1985+ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
1986+ "apr_proc_detach failed");
1987+ return HTTP_INTERNAL_SERVER_ERROR;
1988+ }
1989+ }
1990+
1991+ my_pid = getpid();
1992+ }
1993+
1994+ unixd_pre_config(ptemp);
1995+ ap_listen_pre_config();
1996+// num_childs = DEFAULT_NUM_DAEMON;
1997+ num_childs = 0;
1998+ threads_to_start = DEFAULT_START_THREAD;
1999+ min_spare_threads = DEFAULT_MIN_SPARE_THREAD;
2000+ max_spare_threads = DEFAULT_MAX_SPARE_THREAD;
2001+ max_threads = thread_limit;
2002+ ap_pid_fname = DEFAULT_PIDLOG;
2003+ ap_lock_fname = DEFAULT_LOCKFILE;
2004+ ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
2005+
2006+ apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
2007+
2008+ /* we need to know ServerLimit and ThreadLimit before we start processing
2009+ * the tree because we need to already have allocated child_info_table
2010+ */
2011+ for (pdir = ap_conftree; pdir != NULL; pdir = pdir->next)
2012+ {
2013+ if (!strcasecmp(pdir->directive, "ServerLimit"))
2014+ {
2015+ if (atoi(pdir->args) > tmp_server_limit)
2016+ {
2017+ tmp_server_limit = atoi(pdir->args);
2018+ if (tmp_server_limit > MAX_SERVER_LIMIT)
2019+ {
2020+ tmp_server_limit = MAX_SERVER_LIMIT;
2021+ }
2022+ }
2023+ }
2024+ else if (!strcasecmp(pdir->directive, "ThreadLimit"))
2025+ {
2026+ if (atoi(pdir->args) > tmp_thread_limit)
2027+ {
2028+ tmp_thread_limit = atoi(pdir->args);
2029+ if (tmp_thread_limit > MAX_THREAD_LIMIT)
2030+ {
2031+ tmp_thread_limit = MAX_THREAD_LIMIT;
2032+ }
2033+ }
2034+ }
2035+ }
2036+
2037+ /* -- now setup the child information table -- */
2038+ child_info_table = (child_info_t *)apr_pcalloc(p, tmp_server_limit * sizeof(child_info_t));
2039+ child_info_table_size = tmp_server_limit; /* FIXME: remove tmp_server_limit */
2040+ for (i = 0; i < tmp_server_limit; i++)
2041+ {
2042+ child_info_table[i].uid = -1;
2043+ child_info_table[i].gid = -1;
2044+ child_info_table[i].input = -1;
2045+ child_info_table[i].output = -1;
2046+ child_info_table[i].type = -1;
2047+ child_info_table[i].id = i;
2048+ }
2049+
2050+ return OK;
2051+}
2052+
2053+#undef NO_BODY
2054+
2055+static int pass_request(request_rec *r)
2056+{
2057+ int rv;
2058+ struct msghdr msg;
2059+ struct cmsghdr *cmsg;
2060+ int sock_fd;
2061+ char *bodypart = NULL;
2062+ struct iovec iov[2];
2063+ conn_rec *c = r->connection;
2064+ apr_bucket_brigade *bb = apr_brigade_create(r->pool, c->bucket_alloc);
2065+ apr_bucket_brigade *bodypart_bb = NULL;
2066+ apr_size_t len = 0;
2067+ apr_size_t bodypart_len = 0;
2068+ metuxmpm_header h;
2069+ apr_bucket *bucket;
2070+ const apr_array_header_t *headers_in_array;
2071+ const apr_table_entry_t *headers_in;
2072+ int counter;
2073+
2074+ apr_socket_t *thesock = ap_get_module_config(r->connection->conn_config, &core_module);
2075+ metuxmpm_server_conf *sconf = metuxmpm_SERVER_CONF(r->server->module_config);
2076+
2077+ if ((!r->the_request) || (!strlen(r->the_request)))
2078+ {
2079+ _DBG("empty request. dropping it (%ld)", r->the_request);
2080+ return -1;
2081+ }
2082+
2083+ if (!sconf->child)
2084+ {
2085+ _DBG("server %s in child %d has no child_info assiocated",
2086+ r->hostname, child_num);
2087+ return -1;
2088+ }
2089+
2090+ _DBG("passing request to another child. Vhost: %s, child %d %d",
2091+ apr_table_get(r->headers_in, "Host"), child_num, sconf->child->output);
2092+ _DBG("r->the_request=\"%s\" len=%d", r->the_request, strlen(r->the_request));
2093+
2094+ ap_get_brigade(r->connection->input_filters, bb, AP_MODE_EXHAUSTIVE, APR_NONBLOCK_READ, len);
2095+
2096+ /* Scan the brigade looking for heap-buckets */
2097+
2098+ _DBG("Scanning the brigade",0);
2099+ bucket = APR_BRIGADE_FIRST(bb);
2100+ while (bucket != APR_BRIGADE_SENTINEL(bb) &&
2101+ APR_BUCKET_IS_HEAP(bucket)) {
2102+ _DBG("HEAP BUCKET is found, length=%d", bucket->length);
2103+ bucket = APR_BUCKET_NEXT(bucket);
2104+ if (!APR_BUCKET_IS_HEAP(bucket)) {
2105+ _DBG("NON-HEAP BUCKET is found, extracting the part of brigade before it",0);
2106+ bodypart_bb = bb;
2107+ bb = apr_brigade_split(bodypart_bb, bucket);
2108+ /* Do we need to apr_destroy_brigade(bb) here?
2109+ * Yeah, I know we do apr_pool_destroy(r->pool) before return, but
2110+ * ap_get_brigade is in non-blocking mode (however len is zero).
2111+ */
2112+ if (apr_brigade_pflatten(bodypart_bb, &bodypart, &bodypart_len, r->pool) != APR_SUCCESS) {
2113+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
2114+ "Unable to flatten brigade, declining request");
2115+ apr_pool_destroy(r->pool);
2116+ return DECLINED;
2117+ }
2118+ _DBG("Brigade is flattened as bodypart (bodypart_len=%d)", bodypart_len);
2119+ }
2120+ }
2121+ _DBG("Scanning is finished",0);
2122+
2123+ apr_os_sock_get(&sock_fd, thesock);
2124+
2125+ h.p = r->pool;
2126+
2127+ headers_in_array = apr_table_elts(r->headers_in);
2128+ headers_in = (const apr_table_entry_t *) headers_in_array->elts;
2129+
2130+ h.headers = apr_pstrcat(h.p, r->the_request, CRLF, NULL);
2131+ for (counter = 0; counter < headers_in_array->nelts; counter++) {
2132+ if (headers_in[counter].key == NULL
2133+ || headers_in[counter].val == NULL) {
2134+ continue;
2135+ }
2136+ h.headers = apr_pstrcat(h.p, h.headers, headers_in[counter].key, ": ",
2137+ headers_in[counter].val, CRLF, NULL);
2138+
2139+ }
2140+ h.headers = apr_pstrcat(h.p, h.headers, CRLF, NULL);
2141+ ap_xlate_proto_to_ascii(h.headers, strlen(h.headers));
2142+
2143+ iov[0].iov_base = &bodypart_len;
2144+ iov[0].iov_len = sizeof(bodypart_len);
2145+ iov[1].iov_base = h.headers;
2146+ iov[1].iov_len = strlen(h.headers) + 1;
2147+
2148+ msg.msg_name = NULL;
2149+ msg.msg_namelen = 0;
2150+ msg.msg_iov = iov;
2151+ msg.msg_iovlen = 2;
2152+
2153+ cmsg = apr_palloc(r->pool, sizeof(*cmsg) + sizeof(sock_fd));
2154+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(sock_fd);
2155+ cmsg->cmsg_level = SOL_SOCKET;
2156+ cmsg->cmsg_type = SCM_RIGHTS;
2157+
2158+ memcpy(CMSG_DATA(cmsg), &sock_fd, sizeof(sock_fd));
2159+
2160+ msg.msg_control = cmsg;
2161+ msg.msg_controllen = cmsg->cmsg_len;
2162+
2163+ _DBG("Writing message to %d, passing sock_fd: %d", sconf->child->output, sock_fd);
2164+ _DBG("headers=\"%s\"", h.headers);
2165+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
2166+ "Writing message to %d, passing sd: %d", sconf->child->output, sock_fd);
2167+
2168+ if ((rv = sendmsg(sconf->child->output, &msg, 0)) == -1)
2169+ {
2170+ apr_pool_destroy(r->pool);
2171+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
2172+ "Writing message failed %d %d", rv, errno);
2173+ return -1;
2174+ }
2175+
2176+ _DBG("Writing message succeeded %d", rv);
2177+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
2178+ "Writing message succeeded %d", rv);
2179+
2180+ if (bodypart_len) {
2181+ _DBG("Passing bodypart (bodypart_len=%d) \"%s\"", bodypart_len, bodypart);
2182+ if ((rv = send(sconf->child->output, bodypart, bodypart_len, 0)) == -1) {
2183+ apr_pool_destroy(r->pool);
2184+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
2185+ "Writing message failed %d %d", rv, errno);
2186+ return -1;
2187+ }
2188+ _DBG("Writing message succeeded %d", rv);
2189+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
2190+ "Writing message succeeded %d", rv);
2191+ } else {
2192+ _DBG("No bodypart",0);
2193+ }
2194+
2195+ /* -- close the socket at our site -- */
2196+ apr_socket_close(thesock);
2197+ /* DS: What is the purpose of this?
2198+ * apr_socket_close(sconf->child->output) seems more reasonable
2199+ */
2200+ _DBG("closing socket %d at our side", sock_fd);
2201+ apr_pool_destroy(r->pool);
2202+ return 1;
2203+}
2204+
2205+static int metuxmpm_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server_list)
2206+{
2207+ int i;
2208+ server_rec *sr_walk;
2209+ metuxmpm_server_conf *sconf;
2210+
2211+ for (sr_walk = server_list; sr_walk; sr_walk = sr_walk->next)
2212+ {
2213+ sconf = metuxmpm_SERVER_CONF(sr_walk->module_config);
2214+ if (sconf->child)
2215+ {
2216+ _DBG("server \"%s\" child=%d fd_in=%d fd_out=%d",
2217+ sr_walk->server_hostname,
2218+ sconf->child->id,
2219+ sconf->child->input,
2220+ sconf->child->output );
2221+ }
2222+ else
2223+ {
2224+ _DBG("server \"%s\" has no child assiocated.",
2225+ sr_walk->server_hostname);
2226+ }
2227+ }
2228+
2229+ thread_info_table = (thread_info_t *)apr_pcalloc(p, thread_limit * sizeof(thread_info_t));
2230+ for (i = 0; i < thread_limit; i++)
2231+ {
2232+ thread_info_table[i].sock_fd = AP_metuxmpm_THISCHILD;
2233+ thread_info_table[i].status = 0;
2234+ }
2235+ ap_child_table = (ap_ctable *)apr_pcalloc(p, server_limit * sizeof(ap_ctable));
2236+
2237+ return OK;
2238+}
2239+
2240+static int metuxmpm_post_read(request_rec *r)
2241+{
2242+ int thread_num = r->connection->id % thread_limit;
2243+ metuxmpm_server_conf *sconf = metuxmpm_SERVER_CONF(r->server->module_config);
2244+
2245+ if (!strlen(r->the_request))
2246+ {
2247+ _DBG("corrupt request. aborting",0);
2248+ return DECLINED;
2249+ }
2250+
2251+ if (thread_info_table[thread_num].sock_fd != AP_metuxmpm_THISCHILD)
2252+ {
2253+ apr_socket_t *sock = NULL;
2254+
2255+ apr_os_sock_put(&sock, &thread_info_table[thread_num].sock_fd,
2256+ r->connection->pool);
2257+ ap_sock_disable_nagle(sock);
2258+ ap_set_module_config(r->connection->conn_config, &core_module, sock);
2259+ _DBG("not the right socket? ",0);
2260+ return OK;
2261+ }
2262+
2263+ switch (child_info_table[child_num].type)
2264+ {
2265+ case CHILD_TYPE_MULTIPLEXER:
2266+ {
2267+ _DBG("MULTIPLEXER => Determining if request should be passed. "
2268+ "Child Num: %d, dest-child: %d, hostname from server: %s r->hostname=%s r->the_request=\"%s\"",
2269+ child_num, sconf->child->id, r->server->server_hostname, r->hostname, r->the_request);
2270+
2271+ if (sconf->child->id != child_num)
2272+ {
2273+ _DBG("Passing request.",0);
2274+ if (pass_request(r) == -1)
2275+ {
2276+ ap_log_error(APLOG_MARK, APLOG_ERR, 0,
2277+ ap_server_conf, "Could not pass request to proper "
2278+ "child, request will not be honoured.");
2279+ return DECLINED;
2280+ }
2281+ _DBG("doing longjmp",0);
2282+ longjmp(thread_info_table[thread_num].jmpbuffer, 1);
2283+ _DBG("request declined at our site",0);
2284+ return DECLINED;
2285+ _DBG("OUH! we should never reach this point",0);
2286+ }
2287+ _DBG("eeeh?! the server is assigned to the multiplexer! ... dropping request",0);
2288+ return DECLINED;
2289+ }
2290+ case CHILD_TYPE_PROCESSOR:
2291+ {
2292+ _DBG("PROCESSOR %d", child_num );
2293+ if (sconf->child->id != child_num)
2294+ {
2295+ _DBG("hmmpf! this server is not assigned to us! what did the mux have smoked ?!",0);
2296+ }
2297+ _DBG("request for %s / (server %s) seems to be for us", r->hostname, r->server->server_hostname );
2298+ return OK;
2299+ }
2300+ default:
2301+ {
2302+ _DBG("unspecified child type %d in %d, dropping request", child_info_table[child_num].type, child_num );
2303+ return OK;
2304+ }
2305+ }
2306+ _DBG("THIS POINT SHOULD NOT BE REACHED!",0);
2307+ return OK;
2308+}
2309+
2310+static void metuxmpm_hooks(apr_pool_t *p)
2311+{
2312+ /* The metuxmpm open_logs phase must run before the core's, or stderr
2313+ * will be redirected to a file, and the messages won't print to the
2314+ * console.
2315+ */
2316+ static const char *const aszSucc[] = {"core.c", NULL};
2317+ one_process = 0;
2318+
2319+ ap_hook_open_logs(metuxmpm_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
2320+ ap_hook_pre_config(metuxmpm_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
2321+ ap_hook_post_config(metuxmpm_post_config, NULL, NULL, APR_HOOK_MIDDLE);
2322+
2323+ /* Both of these must be run absolutely first. If this request isn't for
2324+ * this server then we need to forward it to the proper child. No sense
2325+ * tying up this server running more post_read request hooks if it is
2326+ * just going to be forwarded along. The process_connection hook allows
2327+ * metuxmpm to receive the passed request correctly, by automatically
2328+ * filling in the core_input_filter's ctx pointer.
2329+ */
2330+ ap_hook_post_read_request(metuxmpm_post_read, NULL, NULL,
2331+ APR_HOOK_REALLY_FIRST);
2332+ ap_hook_process_connection(metuxmpm_process_connection, NULL, NULL,
2333+ APR_HOOK_REALLY_FIRST);
2334+}
2335+
2336+//static const char *cf_NumServers(cmd_parms *cmd, void *dummy,
2337+// const char *arg)
2338+//{
2339+// const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2340+// if (err != NULL) return err;
2341+//
2342+// num_childs = atoi(arg);
2343+// if (num_childs > server_limit) {
2344+// ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2345+// "WARNING: NumServers of %d exceeds ServerLimit value "
2346+// "of %d servers,", num_childs, server_limit);
2347+// ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2348+// " lowering NumServers to %d. To increase, please "
2349+// "see the", server_limit);
2350+// ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2351+// " ServerLimit directive.");
2352+// num_childs = server_limit;
2353+// }
2354+// else if (num_childs < 1)
2355+// {
2356+// ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2357+// "WARNING: Require NumServers > 0, setting to 1");
2358+// num_childs = 1;
2359+// }
2360+// return NULL;
2361+//}
2362+
2363+static const char *cf_StartThreads(cmd_parms *cmd, void *dummy,
2364+ const char *arg)
2365+{
2366+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2367+ if (err != NULL) return err;
2368+
2369+ threads_to_start = atoi(arg);
2370+ if (threads_to_start > thread_limit) {
2371+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2372+ "WARNING: StartThreads of %d exceeds ThreadLimit value"
2373+ " of %d threads,", threads_to_start,
2374+ thread_limit);
2375+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2376+ " lowering StartThreads to %d. To increase, please"
2377+ " see the", thread_limit);
2378+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2379+ " ThreadLimit directive.");
2380+ }
2381+ else if (threads_to_start < 1) {
2382+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2383+ "WARNING: Require StartThreads > 0, setting to 1");
2384+ threads_to_start = 1;
2385+ }
2386+ return NULL;
2387+}
2388+
2389+static const char *cf_MinSpareThreads(cmd_parms *cmd, void *dummy,
2390+ const char *arg)
2391+{
2392+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2393+ if (err != NULL) return err;
2394+
2395+ min_spare_threads = atoi(arg);
2396+ if (min_spare_threads <= 0)
2397+ {
2398+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2399+ "WARNING: detected MinSpareThreads set to non-positive.");
2400+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2401+ "Resetting to 1 to avoid almost certain Apache failure.");
2402+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2403+ "Please read the documentation.");
2404+ min_spare_threads = 1;
2405+ }
2406+
2407+ return NULL;
2408+}
2409+
2410+static const char *cf_MaxSpareThreads(cmd_parms *cmd, void *dummy,
2411+ const char *arg)
2412+{
2413+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2414+ if (err != NULL) return err;
2415+
2416+ max_spare_threads = atoi(arg);
2417+ if (max_spare_threads >= thread_limit)
2418+ {
2419+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2420+ "WARNING: detected MinSpareThreads set higher than");
2421+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2422+ "ThreadLimit. Resetting to %d", thread_limit);
2423+ max_spare_threads = thread_limit;
2424+ }
2425+ return NULL;
2426+}
2427+
2428+static const char *cf_MaxThreadsPerChild(cmd_parms *cmd, void *dummy, const char *arg)
2429+{
2430+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2431+ if (err != NULL) return err;
2432+
2433+ max_threads = atoi(arg);
2434+ if (max_threads > thread_limit)
2435+ {
2436+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2437+ "WARNING: detected MaxThreadsPerChild set higher than");
2438+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2439+ "ThreadLimit. Resetting to %d", thread_limit);
2440+ max_threads = thread_limit;
2441+ }
2442+ return NULL;
2443+}
2444+
2445+static const char* child_add ( int type, const char* user_name, const char* group_name ,const char* chroot_dir )
2446+{
2447+ _DBG("%d: %s.%s %s", num_childs, user_name, group_name, chroot_dir);
2448+ if (num_childs<server_limit)
2449+ {
2450+ int socks[2];
2451+ int l;
2452+
2453+ child_info_table[num_childs].uid = ap_uname2id(user_name);
2454+ child_info_table[num_childs].gid = ap_gname2id(group_name);
2455+ child_info_table[num_childs].type = type;
2456+ socketpair(PF_UNIX, SOCK_STREAM, 0, socks);
2457+ child_info_table[num_childs].input = socks[0];
2458+ child_info_table[num_childs].output = socks[1];
2459+ child_info_table[num_childs].chroot_dir = 0;
2460+ if (chroot_dir){
2461+ l = strlen(chroot_dir);
2462+ if (l > 0){
2463+ child_info_table[num_childs].chroot_dir = chroot_dir;
2464+ /* should copy the contents */
2465+ /* do we need to check its existence? */
2466+ }
2467+ }
2468+
2469+ _DBG("[%d] uid=%d gid=%d type=%d fd_in=%d fd_out=%d,chroot_dir=%s",
2470+ num_childs,
2471+ child_info_table[num_childs].uid,
2472+ child_info_table[num_childs].gid,
2473+ child_info_table[num_childs].type,
2474+ child_info_table[num_childs].input,
2475+ child_info_table[num_childs].output,
2476+ child_info_table[num_childs].chroot_dir
2477+ );
2478+
2479+ if (child_info_table[num_childs].uid == 0 ||
2480+ child_info_table[num_childs].gid == 0)
2481+ {
2482+ _DBG("Assigning root user/group to a child.",0);
2483+ }
2484+ num_childs++;
2485+ return NULL;
2486+ }
2487+
2488+ return "Trying to use more child ID's than NumServers. "
2489+ "Increase NumServers in your config file.";
2490+}
2491+
2492+/* we define an Processor w/ specific uid/gid */
2493+static const char *cf_Processor(
2494+ cmd_parms *cmd, void *dummy, const char *user_name, const char *group_name, const char *chroot_dir)
2495+{
2496+ _DBG("%d: %s.%s %s", num_childs, user_name, group_name, chroot_dir);
2497+ return child_add ( CHILD_TYPE_PROCESSOR, user_name, group_name, chroot_dir );
2498+}
2499+
2500+/* we define an Multiplexer child w/ specific uid/gid */
2501+static const char *cf_Multiplexer(
2502+ cmd_parms *cmd, void *dummy, const char *user_name, const char *group_name, const char *chroot_dir)
2503+{
2504+ _DBG("%d: %s.%s %s", num_childs, user_name, group_name, chroot_dir);
2505+ return child_add ( CHILD_TYPE_MULTIPLEXER, user_name, group_name, chroot_dir );
2506+}
2507+
2508+/* process the config file option AssignUserId */
2509+/* -- FIXME: perhaps we could add childs from here automatically -- */
2510+static const char * cf_AssignUserId
2511+(
2512+ cmd_parms *cmd,
2513+ void *dummy,
2514+ const char *user_name,
2515+ const char *group_name
2516+)
2517+{
2518+ int i;
2519+ int matching = 0;
2520+ int uid = ap_uname2id(user_name);
2521+ int gid = ap_gname2id(group_name);
2522+ const char *errstr;
2523+
2524+ metuxmpm_server_conf *sconf
2525+ = metuxmpm_SERVER_CONF(cmd->server->module_config);
2526+
2527+ sconf->fullsockname =
2528+ apr_pstrcat(cmd->pool, sconf->sockname, ".", user_name,":", group_name, NULL);
2529+
2530+ _DBG("user=\"%s\" (%d) group=\"%s\" (%d) numchilds=%d", user_name, uid, group_name, gid, num_childs );
2531+
2532+ for (i = 0; i < num_childs; i++)
2533+ {
2534+ _DBG("trying %d: %d.%d / %d", i,
2535+ child_info_table[i].uid, child_info_table[i].gid, child_info_table[i].type );
2536+
2537+ if ((uid == child_info_table[i].uid) &&
2538+ (gid == child_info_table[i].gid) &&
2539+ (child_info_table[i].type == CHILD_TYPE_PROCESSOR))
2540+ {
2541+ /* create an socket for this child, if it has no one */
2542+ /* FIXME: we should do it anywhere else, for _all_ childs */
2543+ sconf->child = &child_info_table[i];
2544+ _DBG("assigning server to child %d; "
2545+ "UID: %d, GID: %d, input=%d, output=%d",
2546+ i, uid, gid, sconf->child->input, sconf->child->output);
2547+ return NULL;
2548+ }
2549+ }
2550+
2551+ _DBG("assigning server to child FAILED %d; UID: %d, GID: %d ", i, uid, gid);
2552+ return "Unable to find process with matching uid/gid.";
2553+}
2554+
2555+static const char *cf_ServerLimit (cmd_parms *cmd, void *dummy, const char *arg)
2556+{
2557+ int tmp_server_limit;
2558+
2559+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2560+ if (err != NULL) return err;
2561+
2562+ tmp_server_limit = atoi(arg);
2563+ /* you cannot change ServerLimit across a restart; ignore
2564+ * any such attempts
2565+ */
2566+ if (first_server_limit && tmp_server_limit != server_limit)
2567+ {
2568+ /* how do we log a message? the error log is a bit bucket at this
2569+ * point; we'll just have to set a flag so that ap_mpm_run()
2570+ * logs a warning later
2571+ */
2572+ changed_limit_at_restart = 1;
2573+ return NULL;
2574+ }
2575+ server_limit = tmp_server_limit;
2576+
2577+ if (server_limit > MAX_SERVER_LIMIT)
2578+ {
2579+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2580+ "WARNING: ServerLimit of %d exceeds compile time limit "
2581+ "of %d servers,", server_limit, MAX_SERVER_LIMIT);
2582+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2583+ " lowering ServerLimit to %d.", MAX_SERVER_LIMIT);
2584+ server_limit = MAX_SERVER_LIMIT;
2585+ }
2586+ else if (server_limit < 1)
2587+ {
2588+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2589+ "WARNING: Require ServerLimit > 0, setting to 1");
2590+ server_limit = 1;
2591+ }
2592+ return NULL;
2593+}
2594+
2595+static const char *cf_ThreadLimit (cmd_parms *cmd, void *dummy, const char *arg)
2596+{
2597+ int tmp_thread_limit;
2598+
2599+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
2600+ if (err != NULL) return err;
2601+
2602+ tmp_thread_limit = atoi(arg);
2603+ /* you cannot change ThreadLimit across a restart; ignore
2604+ * any such attempts
2605+ */
2606+ if (first_thread_limit && tmp_thread_limit != thread_limit)
2607+ {
2608+ /* how do we log a message? the error log is a bit bucket at this
2609+ * point; we'll just have to set a flag so that ap_mpm_run()
2610+ * logs a warning later
2611+ */
2612+ changed_limit_at_restart = 1;
2613+ return NULL;
2614+ }
2615+ thread_limit = tmp_thread_limit;
2616+
2617+ if (thread_limit > MAX_THREAD_LIMIT)
2618+ {
2619+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2620+ "WARNING: ThreadLimit of %d exceeds compile time limit "
2621+ "of %d servers,", thread_limit, MAX_THREAD_LIMIT);
2622+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2623+ " lowering ThreadLimit to %d.", MAX_THREAD_LIMIT);
2624+ thread_limit = MAX_THREAD_LIMIT;
2625+ }
2626+ else if (thread_limit < 1)
2627+ {
2628+ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
2629+ "WARNING: Require ThreadLimit > 0, setting to 1");
2630+ thread_limit = 1;
2631+ }
2632+ return NULL;
2633+}
2634+
2635+static const command_rec metuxmpm_cmds[] = {
2636+UNIX_DAEMON_COMMANDS,
2637+LISTEN_COMMANDS,
2638+AP_INIT_TAKE1("StartThreads", cf_StartThreads, NULL, RSRC_CONF,
2639+ "Number of threads each child creates"),
2640+AP_INIT_TAKE1("MinSpareThreads", cf_MinSpareThreads, NULL, RSRC_CONF,
2641+ "Minimum number of idle threads per child, to handle "
2642+ "request spikes"),
2643+AP_INIT_TAKE1("MaxSpareThreads", cf_MaxSpareThreads, NULL, RSRC_CONF,
2644+ "Maximum number of idle threads per child"),
2645+AP_INIT_TAKE1("MaxThreadsPerChild", cf_MaxThreadsPerChild, NULL, RSRC_CONF,
2646+ "Maximum number of threads per child"),
2647+AP_INIT_TAKE23("Multiplexer", cf_Multiplexer, NULL, RSRC_CONF,
2648+ "Specify an Multiplexer Child configuration."),
2649+AP_INIT_TAKE23("Processor", cf_Processor, NULL, RSRC_CONF,
2650+ "Specify a User and Group for a specific child process."),
2651+AP_INIT_TAKE2("AssignUserID", cf_AssignUserId, NULL, RSRC_CONF,
2652+ "Tie a virtual host to a specific child process."),
2653+AP_INIT_TAKE1("ServerLimit", cf_ServerLimit, NULL, RSRC_CONF,
2654+ "Maximum value of NumServers for this run of Apache"),
2655+AP_INIT_TAKE1("ThreadLimit", cf_ThreadLimit, NULL, RSRC_CONF,
2656+ "Maximum worker threads in a server for this run of Apache"),
2657+{ NULL }
2658+};
2659+
2660+/* == allocate an private server config structure == */
2661+static void *metuxmpm_create_config(apr_pool_t *p, server_rec *s)
2662+{
2663+ metuxmpm_server_conf *c = (metuxmpm_server_conf *)
2664+ apr_pcalloc(p, sizeof(metuxmpm_server_conf));
2665+ c->child = NULL;
2666+ return c;
2667+}
2668+
2669+module AP_MODULE_DECLARE_DATA mpm_metuxmpm_module =
2670+{
2671+ MPM20_MODULE_STUFF,
2672+ ap_mpm_rewrite_args, /* hook to run before apache parses args */
2673+ NULL, /* create per-directory config structure */
2674+ NULL, /* merge per-directory config structures */
2675+ metuxmpm_create_config, /* create per-server config structure */
2676+ NULL, /* merge per-server config structures */
2677+ metuxmpm_cmds, /* command apr_table_t */
2678+ metuxmpm_hooks /* register_hooks */
2679+};
2680+
81a3ef12
AM
2681diff -urN httpd-2.2.0.org/server/mpm/experimental/metuxmpm/mpm_default.h httpd-2.2.0/server/mpm/experimental/metuxmpm/mpm_default.h
2682--- httpd-2.2.0.org/server/mpm/experimental/metuxmpm/mpm_default.h 1970-01-01 01:00:00.000000000 +0100
8ccd60d9 2683+++ httpd-2.2.0/server/mpm/experimental/metuxmpm/mpm_default.h 2005-12-12 11:37:00.910963000 +0100
81a3ef12 2684@@ -0,0 +1,115 @@
4a17dc3c
AM
2685+/* ====================================================================
2686+ * The Apache Software License, Version 1.1
2687+ *
2688+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
2689+ * reserved.
2690+ *
2691+ * Redistribution and use in source and binary forms, with or without
2692+ * modification, are permitted provided that the following conditions
2693+ * are met:
2694+ *
2695+ * 1. Redistributions of source code must retain the above copyright
2696+ * notice, this list of conditions and the following disclaimer.
2697+ *
2698+ * 2. Redistributions in binary form must reproduce the above copyright
2699+ * notice, this list of conditions and the following disclaimer in
2700+ * the documentation and/or other materials provided with the
2701+ * distribution.
2702+ *
2703+ * 3. The end-user documentation included with the redistribution,
2704+ * if any, must include the following acknowledgment:
2705+ * "This product includes software developed by the
2706+ * Apache Software Foundation (http://www.apache.org/)."
2707+ * Alternately, this acknowledgment may appear in the software itself,
2708+ * if and wherever such third-party acknowledgments normally appear.
2709+ *
2710+ * 4. The names "Apache" and "Apache Software Foundation" must
2711+ * not be used to endorse or promote products derived from this
2712+ * software without prior written permission. For written
2713+ * permission, please contact apache@apache.org.
2714+ *
2715+ * 5. Products derived from this software may not be called "Apache",
2716+ * nor may "Apache" appear in their name, without prior written
2717+ * permission of the Apache Software Foundation.
2718+ *
2719+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
2720+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2721+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2722+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
2723+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2724+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2725+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2726+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2727+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2728+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2729+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2730+ * SUCH DAMAGE.
2731+ * ====================================================================
2732+ *
2733+ * This software consists of voluntary contributions made by many
2734+ * individuals on behalf of the Apache Software Foundation. For more
2735+ * information on the Apache Software Foundation, please see
2736+ * <http://www.apache.org/>.
2737+ *
2738+ * Portions of this software are based upon public domain software
2739+ * originally written at the National Center for Supercomputing Applications,
2740+ * University of Illinois, Urbana-Champaign.
2741+ */
2742+
81a3ef12
AM
2743+#ifndef APACHE_MPM_DEFAULT_H
2744+#define APACHE_MPM_DEFAULT_H
4a17dc3c 2745+
81a3ef12 2746+#define NO_SERIALIZED_ACCEPT
4a17dc3c 2747+
81a3ef12
AM
2748+/* Number of threads to spawn off by default --- also, if fewer than
2749+ * this free when the caretaker checks, it will spawn more.
2750+ */
2751+#ifndef DEFAULT_START_THREAD
2752+#define DEFAULT_START_THREAD 5
2753+#endif
4a17dc3c 2754+
81a3ef12
AM
2755+/* Maximum number of *free* server threads --- more than this, and
2756+ * they will die off.
2757+ */
4a17dc3c 2758+
81a3ef12
AM
2759+#ifndef DEFAULT_MAX_SPARE_THREAD
2760+#define DEFAULT_MAX_SPARE_THREAD 10
2761+#endif
4a17dc3c 2762+
81a3ef12 2763+/* Minimum --- fewer than this, and more will be created */
4a17dc3c 2764+
81a3ef12
AM
2765+#ifndef DEFAULT_MIN_SPARE_THREAD
2766+#define DEFAULT_MIN_SPARE_THREAD 5
2767+#endif
4a17dc3c 2768+
81a3ef12
AM
2769+/* Number of servers to spawn off by default
2770+ */
2771+#ifndef DEFAULT_NUM_DAEMON
2772+#define DEFAULT_NUM_DAEMON 2
2773+#endif
4a17dc3c 2774+
81a3ef12
AM
2775+/* File used for accept locking, when we use a file */
2776+#ifndef DEFAULT_LOCKFILE
2777+#define DEFAULT_LOCKFILE DEFAULT_REL_RUNTIMEDIR "/accept.lock"
2778+#endif
4a17dc3c 2779+
81a3ef12
AM
2780+/* Where the main/parent process's pid is logged */
2781+#ifndef DEFAULT_PIDLOG
2782+#define DEFAULT_PIDLOG DEFAULT_REL_RUNTIMEDIR "/httpd.pid"
2783+#endif
2784+
2785+/*
2786+ * Interval, in microseconds, between scoreboard maintenance.
2787+ */
2788+#ifndef SCOREBOARD_MAINTENANCE_INTERVAL
2789+#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000
2790+#endif
2791+
2792+/* Number of requests to try to handle in a single process. If <= 0,
2793+ * the children don't die off.
2794+ */
2795+#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD
2796+#define DEFAULT_MAX_REQUESTS_PER_CHILD 10000
2797+#endif
2798+
2799+#endif /* AP_MPM_DEFAULT_H */
2800diff -urN httpd-2.2.0.org/server/mpm/experimental/metuxmpm/mpm.h httpd-2.2.0/server/mpm/experimental/metuxmpm/mpm.h
2801--- httpd-2.2.0.org/server/mpm/experimental/metuxmpm/mpm.h 1970-01-01 01:00:00.000000000 +0100
8ccd60d9 2802+++ httpd-2.2.0/server/mpm/experimental/metuxmpm/mpm.h 2005-12-12 11:37:00.910963000 +0100
81a3ef12 2803@@ -0,0 +1,100 @@
4a17dc3c
AM
2804+/* ====================================================================
2805+ * The Apache Software License, Version 1.1
2806+ *
2807+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
2808+ * reserved.
2809+ *
2810+ * Redistribution and use in source and binary forms, with or without
2811+ * modification, are permitted provided that the following conditions
2812+ * are met:
2813+ *
2814+ * 1. Redistributions of source code must retain the above copyright
2815+ * notice, this list of conditions and the following disclaimer.
2816+ *
2817+ * 2. Redistributions in binary form must reproduce the above copyright
2818+ * notice, this list of conditions and the following disclaimer in
2819+ * the documentation and/or other materials provided with the
2820+ * distribution.
2821+ *
2822+ * 3. The end-user documentation included with the redistribution,
2823+ * if any, must include the following acknowledgment:
2824+ * "This product includes software developed by the
2825+ * Apache Software Foundation (http://www.apache.org/)."
2826+ * Alternately, this acknowledgment may appear in the software itself,
2827+ * if and wherever such third-party acknowledgments normally appear.
2828+ *
2829+ * 4. The names "Apache" and "Apache Software Foundation" must
2830+ * not be used to endorse or promote products derived from this
2831+ * software without prior written permission. For written
2832+ * permission, please contact apache@apache.org.
2833+ *
2834+ * 5. Products derived from this software may not be called "Apache",
2835+ * nor may "Apache" appear in their name, without prior written
2836+ * permission of the Apache Software Foundation.
2837+ *
2838+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
2839+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2840+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2841+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
2842+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2843+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2844+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2845+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2846+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2847+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
2848+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2849+ * SUCH DAMAGE.
2850+ * ====================================================================
2851+ *
2852+ * This software consists of voluntary contributions made by many
2853+ * individuals on behalf of the Apache Software Foundation. For more
2854+ * information on the Apache Software Foundation, please see
2855+ * <http://www.apache.org/>.
2856+ *
2857+ * Portions of this software are based upon public domain software
2858+ * originally written at the National Center for Supercomputing Applications,
2859+ * University of Illinois, Urbana-Champaign.
2860+ */
2861+
81a3ef12
AM
2862+#include "httpd.h"
2863+#include "mpm_default.h"
2864+#include "unixd.h"
4a17dc3c 2865+
81a3ef12
AM
2866+#ifndef APACHE_MPM_METUXMPM_H
2867+#define APACHE_MPM_METUXMPM_H
4a17dc3c 2868+
81a3ef12 2869+#define METUXMPM_MPM
4a17dc3c 2870+
81a3ef12 2871+#define MPM_NAME "metuxmpm"
4a17dc3c 2872+
81a3ef12
AM
2873+#define AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
2874+#define AP_MPM_WANT_WAIT_OR_TIMEOUT
2875+#define AP_MPM_WANT_PROCESS_CHILD_STATUS
2876+#define AP_MPM_WANT_SET_PIDFILE
2877+#define AP_MPM_WANT_SET_SCOREBOARD
2878+#define AP_MPM_WANT_SET_LOCKFILE
2879+#define AP_MPM_WANT_SET_MAX_REQUESTS
2880+#define AP_MPM_WANT_SET_COREDUMPDIR
2881+#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
2882+#define AP_MPM_WANT_SIGNAL_SERVER
2883+#define AP_MPM_USES_POD
4a17dc3c 2884+
81a3ef12
AM
2885+#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
2886+#define MPM_NOTE_CHILD_KILLED(i) (MPM_CHILD_PID(i) = 0)
2887+#define MPM_ACCEPT_FUNC unixd_accept
4a17dc3c 2888+
81a3ef12
AM
2889+/* Table of child status */
2890+#define SERVER_DEAD 0
2891+#define SERVER_DYING 1
2892+#define SERVER_ALIVE 2
4a17dc3c 2893+
81a3ef12
AM
2894+typedef struct ap_ctable{
2895+ pid_t pid;
2896+ unsigned char status;
2897+} ap_ctable;
4a17dc3c 2898+
81a3ef12
AM
2899+extern int ap_threads_per_child;
2900+extern int ap_max_daemons_limit;
2901+extern server_rec *ap_server_conf;
4a17dc3c 2902+
81a3ef12
AM
2903+#endif /* APACHE_MPM_METUXMPM_H */
2904diff -urN httpd-2.2.0.org/srclib/apr/network_io/unix/sockets.c httpd-2.2.0/srclib/apr/network_io/unix/sockets.c
2905--- httpd-2.2.0.org/srclib/apr/network_io/unix/sockets.c 2005-09-09 10:21:17.000000000 +0200
8ccd60d9 2906+++ httpd-2.2.0/srclib/apr/network_io/unix/sockets.c 2005-12-12 11:37:00.910963000 +0100
81a3ef12 2907@@ -416,7 +416,36 @@
4a17dc3c
AM
2908 set_socket_vars(*sock, APR_INET, SOCK_STREAM, 0);
2909 (*sock)->timeout = -1;
2910 }
2911- (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1;
2912+// (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 1;
2913+ if (1)
2914+ {
2915+ /* fixup socket's peer information.
2916+ we need it for the muxmpm. enrico weigelt, metux ITS
2917+ <weigelt@metux.de>
2918+ */
2919+ /* XXX next line looks bogus w.r.t. AF_INET6 support */
2920+
2921+ /* adjust remote address */
2922+ (*sock)->remote_addr->salen = sizeof((*sock)->remote_addr->sa);
2923+ getpeername(
2924+ *thesock,
2925+ (struct sockaddr*)&((*sock)->remote_addr->sa),
2926+ &((*sock)->remote_addr->salen)
2927+ );
2928+ (*sock)->remote_addr->port = ntohs((*sock)->remote_addr->sa.sin.sin_port);
2929+
2930+ /* XXX assumes sin_port and sin6_port at same offset */
2931+
2932+ /* adjust local address */
2933+ getsockname(
2934+ *thesock,
2935+ (struct sockaddr*)&((*sock)->local_addr->sa),
2936+ &((*sock)->local_addr->salen)
2937+ );
2938+ (*sock)->local_addr->port = ntohs((*sock)->local_addr->sa.sin.sin_port);
2939+ (*sock)->local_port_unknown = (*sock)->local_interface_unknown = 0;
2940+ }
2941+
2942 (*sock)->remote_addr_unknown = 1;
2943 (*sock)->socketdes = *thesock;
2944 return APR_SUCCESS;
This page took 1.024957 seconds and 4 git commands to generate.