]> granicus.if.org Git - apache/blob - server/mpm_common.c
Correct build order. Seems mod_session was misimplemented to require
[apache] / server / mpm_common.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* The purpose of this file is to store the code that MOST mpm's will need
18  * this does not mean a function only goes into this file if every MPM needs
19  * it.  It means that if a function is needed by more than one MPM, and
20  * future maintenance would be served by making the code common, then the
21  * function belongs here.
22  *
23  * This is going in src/main because it is not platform specific, it is
24  * specific to multi-process servers, but NOT to Unix.  Which is why it
25  * does not belong in src/os/unix
26  */
27
28 #include "apr.h"
29 #include "apr_thread_proc.h"
30 #include "apr_signal.h"
31 #include "apr_strings.h"
32 #define APR_WANT_STRFUNC
33 #include "apr_want.h"
34 #include "apr_getopt.h"
35 #include "apr_optional.h"
36 #include "apr_allocator.h"
37
38 #include "httpd.h"
39 #include "http_config.h"
40 #include "http_log.h"
41 #include "http_main.h"
42 #include "mpm_common.h"
43 #include "ap_mpm.h"
44 #include "ap_listen.h"
45 #include "util_mutex.h"
46
47 #include "scoreboard.h"
48
49 #ifdef HAVE_PWD_H
50 #include <pwd.h>
51 #endif
52 #ifdef HAVE_GRP_H
53 #include <grp.h>
54 #endif
55 #if APR_HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58
59 APLOG_USE_MODULE(core);
60
61 #if AP_ENABLE_EXCEPTION_HOOK
62 APR_HOOK_STRUCT(
63     APR_HOOK_LINK(fatal_exception)
64     APR_HOOK_LINK(monitor)
65     APR_HOOK_LINK(drop_privileges)
66     APR_HOOK_LINK(mpm)
67     APR_HOOK_LINK(mpm_query)
68     APR_HOOK_LINK(mpm_note_child_killed)
69     APR_HOOK_LINK(mpm_register_timed_callback)
70     APR_HOOK_LINK(mpm_get_name)
71 )
72 AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
73                           (ap_exception_info_t *ei), (ei), OK, DECLINED)
74 #else
75 APR_HOOK_STRUCT(
76     APR_HOOK_LINK(monitor)
77     APR_HOOK_LINK(drop_privileges)
78     APR_HOOK_LINK(mpm)
79     APR_HOOK_LINK(mpm_query)
80     APR_HOOK_LINK(mpm_note_child_killed)
81     APR_HOOK_LINK(mpm_register_timed_callback)
82     APR_HOOK_LINK(mpm_get_name)
83 )
84 #endif
85 AP_IMPLEMENT_HOOK_RUN_ALL(int, monitor,
86                           (apr_pool_t *p, server_rec *s), (p, s), OK, DECLINED)
87 AP_IMPLEMENT_HOOK_RUN_ALL(int, drop_privileges,
88                           (apr_pool_t * pchild, server_rec * s),
89                           (pchild, s), OK, DECLINED)
90 AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm,
91                             (apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
92                             (pconf, plog, s), DECLINED)
93 AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm_query,
94                             (int query_code, int *result, apr_status_t *_rv),
95                             (query_code, result, _rv), DECLINED)
96 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_note_child_killed,
97                             (int childnum),
98                             (childnum), APR_ENOTIMPL)
99 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback,
100                             (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton),
101                             (t, cbfn, baton), APR_ENOTIMPL)
102 AP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
103                             (void),
104                             (), NULL)
105
106 /* variables representing config directives implemented here */
107 const char *ap_pid_fname;
108 int ap_max_requests_per_child;
109 char ap_coredump_dir[MAX_STRING_LEN];
110 int ap_coredumpdir_configured;
111 int ap_graceful_shutdown_timeout;
112 apr_uint32_t ap_max_mem_free;
113 apr_size_t ap_thread_stacksize;
114
115 /* Set defaults for config directives implemented here.  This is
116  * called from core's pre-config hook, so MPMs which need to override
117  * one of these should run their pre-config hook after that of core.
118  */
119 void mpm_common_pre_config(apr_pool_t *pconf)
120 {
121     ap_pid_fname = DEFAULT_PIDLOG;
122     ap_max_requests_per_child = 0; /* unlimited */
123     apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
124     ap_coredumpdir_configured = 0;
125     ap_graceful_shutdown_timeout = 0; /* unlimited */
126     ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
127     ap_thread_stacksize = 0; /* use system default */
128 }
129
130 /* number of calls to wait_or_timeout between writable probes */
131 #ifndef INTERVAL_OF_WRITABLE_PROBES
132 #define INTERVAL_OF_WRITABLE_PROBES 10
133 #endif
134 static int wait_or_timeout_counter;
135
136 void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret,
137                         apr_pool_t *p, server_rec *s)
138 {
139     apr_status_t rv;
140
141     ++wait_or_timeout_counter;
142     if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
143         wait_or_timeout_counter = 0;
144         ap_run_monitor(p, s);
145     }
146
147     rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
148     if (APR_STATUS_IS_EINTR(rv)) {
149         ret->pid = -1;
150         return;
151     }
152
153     if (APR_STATUS_IS_CHILD_DONE(rv)) {
154         return;
155     }
156
157     apr_sleep(apr_time_from_sec(1));
158     ret->pid = -1;
159     return;
160 }
161
162 #if defined(TCP_NODELAY)
163 void ap_sock_disable_nagle(apr_socket_t *s)
164 {
165     /* The Nagle algorithm says that we should delay sending partial
166      * packets in hopes of getting more data.  We don't want to do
167      * this; we are not telnet.  There are bad interactions between
168      * persistent connections and Nagle's algorithm that have very severe
169      * performance penalties.  (Failing to disable Nagle is not much of a
170      * problem with simple HTTP.)
171      *
172      * In spite of these problems, failure here is not a shooting offense.
173      */
174     apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
175
176     if (status != APR_SUCCESS) {
177         ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf,
178                      "apr_socket_opt_set: (TCP_NODELAY)");
179     }
180 }
181 #endif
182
183 #ifdef HAVE_GETPWNAM
184 AP_DECLARE(uid_t) ap_uname2id(const char *name)
185 {
186     struct passwd *ent;
187
188     if (name[0] == '#')
189         return (atoi(&name[1]));
190
191     if (!(ent = getpwnam(name))) {
192         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
193                      "%s: bad user name %s", ap_server_argv0, name);
194         exit(1);
195     }
196
197     return (ent->pw_uid);
198 }
199 #endif
200
201 #ifdef HAVE_GETGRNAM
202 AP_DECLARE(gid_t) ap_gname2id(const char *name)
203 {
204     struct group *ent;
205
206     if (name[0] == '#')
207         return (atoi(&name[1]));
208
209     if (!(ent = getgrnam(name))) {
210         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
211                      "%s: bad group name %s", ap_server_argv0, name);
212         exit(1);
213     }
214
215     return (ent->gr_gid);
216 }
217 #endif
218
219 #ifndef HAVE_INITGROUPS
220 int initgroups(const char *name, gid_t basegid)
221 {
222 #if defined(_OSD_POSIX) || defined(OS2) || defined(WIN32) || defined(NETWARE)
223     return 0;
224 #else
225     gid_t groups[NGROUPS_MAX];
226     struct group *g;
227     int index = 0;
228
229     setgrent();
230
231     groups[index++] = basegid;
232
233     while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) {
234         if (g->gr_gid != basegid) {
235             char **names;
236
237             for (names = g->gr_mem; *names != NULL; ++names) {
238                 if (!strcmp(*names, name))
239                     groups[index++] = g->gr_gid;
240             }
241         }
242     }
243
244     endgrent();
245
246     return setgroups(index, groups);
247 #endif
248 }
249 #endif /* def HAVE_INITGROUPS */
250
251 /* standard mpm configuration handling */
252
253 const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy,
254                                const char *arg)
255 {
256     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
257     if (err != NULL) {
258         return err;
259     }
260
261     if (cmd->server->is_virtual) {
262         return "PidFile directive not allowed in <VirtualHost>";
263     }
264
265     ap_pid_fname = arg;
266     return NULL;
267 }
268
269 const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy,
270                                     const char *arg)
271 {
272     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
273     if (err != NULL) {
274         return err;
275     }
276
277     if (!strcasecmp(cmd->cmd->name, "MaxRequestsPerChild")) {
278         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
279                      "MaxRequestsPerChild is deprecated, use "
280                      "MaxConnectionsPerChild instead.");
281     }
282
283     ap_max_requests_per_child = atoi(arg);
284
285     return NULL;
286 }
287
288 const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
289                                    const char *arg)
290 {
291     apr_finfo_t finfo;
292     const char *fname;
293     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
294     if (err != NULL) {
295         return err;
296     }
297
298     fname = ap_server_root_relative(cmd->pool, arg);
299     if (!fname) {
300         return apr_pstrcat(cmd->pool, "Invalid CoreDumpDirectory path ",
301                            arg, NULL);
302     }
303     if (apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) {
304         return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
305                            " does not exist", NULL);
306     }
307     if (finfo.filetype != APR_DIR) {
308         return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
309                            " is not a directory", NULL);
310     }
311     apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
312     ap_coredumpdir_configured = 1;
313     return NULL;
314 }
315
316 const char * ap_mpm_set_graceful_shutdown(cmd_parms *cmd, void *dummy,
317                                           const char *arg)
318 {
319     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
320     if (err != NULL) {
321         return err;
322     }
323     ap_graceful_shutdown_timeout = atoi(arg);
324     return NULL;
325 }
326
327 const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
328                                     const char *arg)
329 {
330     long value;
331     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
332     if (err != NULL) {
333         return err;
334     }
335
336     value = strtol(arg, NULL, 0);
337     if (value < 0 || errno == ERANGE)
338         return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ",
339                            arg, NULL);
340
341     ap_max_mem_free = (apr_uint32_t)value * 1024;
342
343     return NULL;
344 }
345
346 const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy,
347                                         const char *arg)
348 {
349     long value;
350     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
351     if (err != NULL) {
352         return err;
353     }
354
355     value = strtol(arg, NULL, 0);
356     if (value < 0 || errno == ERANGE)
357         return apr_pstrcat(cmd->pool, "Invalid ThreadStackSize value: ",
358                            arg, NULL);
359
360     ap_thread_stacksize = (apr_size_t)value;
361
362     return NULL;
363 }
364
365 AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
366 {
367     apr_status_t rv;
368
369     if (ap_run_mpm_query(query_code, result, &rv) == DECLINED) {
370         rv = APR_EGENERAL;
371     }
372
373     return rv;
374 }
375
376 AP_DECLARE(apr_status_t) ap_mpm_note_child_killed(int childnum)
377 {
378     return ap_run_mpm_note_child_killed(childnum);
379 }
380
381 AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton)
382 {
383     return ap_run_mpm_register_timed_callback(t, cbfn, baton);
384 }
385
386 AP_DECLARE(const char *)ap_show_mpm(void)
387 {
388     const char *name = ap_run_mpm_get_name();
389
390     if (!name) {
391         name = "";
392     }
393
394     return name;
395 }
396
397 AP_DECLARE(const char *)ap_check_mpm(void)
398 {
399     if (!_hooks.link_mpm || _hooks.link_mpm->nelts == 0)
400         return "No MPM loaded.";
401     else if (_hooks.link_mpm->nelts > 1)
402         return "More than one MPM loaded.";
403     else
404         return NULL;
405 }