]> granicus.if.org Git - apache/blob - server/mpm_common.c
remove TPF support
[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 #if AP_ENABLE_EXCEPTION_HOOK
60 APR_HOOK_STRUCT(
61     APR_HOOK_LINK(fatal_exception)
62     APR_HOOK_LINK(monitor)
63     APR_HOOK_LINK(drop_privileges)
64     APR_HOOK_LINK(mpm)
65     APR_HOOK_LINK(mpm_query)
66     APR_HOOK_LINK(mpm_get_child_pid)
67     APR_HOOK_LINK(mpm_note_child_killed)
68     APR_HOOK_LINK(mpm_register_timed_callback)
69     APR_HOOK_LINK(mpm_get_name)
70 )
71 AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
72                           (ap_exception_info_t *ei), (ei), OK, DECLINED)
73 #else
74 APR_HOOK_STRUCT(
75     APR_HOOK_LINK(monitor)
76     APR_HOOK_LINK(drop_privileges)
77     APR_HOOK_LINK(mpm)
78     APR_HOOK_LINK(mpm_query)
79     APR_HOOK_LINK(mpm_get_child_pid)
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), (p), 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(apr_status_t, mpm_query,
94                             (int query_code, int *result),
95                             (query_code, result), APR_ENOTIMPL)
96 AP_IMPLEMENT_HOOK_RUN_FIRST(pid_t, mpm_get_child_pid,
97                             (int childnum),
98                             (childnum), 0)
99 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_note_child_killed,
100                             (int childnum),
101                             (childnum), APR_ENOTIMPL)
102 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback,
103                             (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton),
104                             (t, cbfn, baton), APR_ENOTIMPL)
105 AP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
106                             (void),
107                             (), NULL)
108
109 /* number of calls to wait_or_timeout between writable probes */
110 #ifndef INTERVAL_OF_WRITABLE_PROBES
111 #define INTERVAL_OF_WRITABLE_PROBES 10
112 #endif
113 static int wait_or_timeout_counter;
114
115 void ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode, apr_proc_t *ret,
116                         apr_pool_t *p)
117 {
118     apr_status_t rv;
119
120     ++wait_or_timeout_counter;
121     if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
122         wait_or_timeout_counter = 0;
123         ap_run_monitor(p);
124     }
125
126     rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
127     if (APR_STATUS_IS_EINTR(rv)) {
128         ret->pid = -1;
129         return;
130     }
131
132     if (APR_STATUS_IS_CHILD_DONE(rv)) {
133         return;
134     }
135
136     apr_sleep(1000000);
137     ret->pid = -1;
138     return;
139 }
140
141 #if defined(TCP_NODELAY) && !defined(MPE)
142 void ap_sock_disable_nagle(apr_socket_t *s)
143 {
144     /* The Nagle algorithm says that we should delay sending partial
145      * packets in hopes of getting more data.  We don't want to do
146      * this; we are not telnet.  There are bad interactions between
147      * persistent connections and Nagle's algorithm that have very severe
148      * performance penalties.  (Failing to disable Nagle is not much of a
149      * problem with simple HTTP.)
150      *
151      * In spite of these problems, failure here is not a shooting offense.
152      */
153     apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
154
155     if (status != APR_SUCCESS) {
156         ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf,
157                      "apr_socket_opt_set: (TCP_NODELAY)");
158     }
159 }
160 #endif
161
162 #ifdef HAVE_GETPWNAM
163 AP_DECLARE(uid_t) ap_uname2id(const char *name)
164 {
165     struct passwd *ent;
166
167     if (name[0] == '#')
168         return (atoi(&name[1]));
169
170     if (!(ent = getpwnam(name))) {
171         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
172                      "%s: bad user name %s", ap_server_argv0, name);
173         exit(1);
174     }
175
176     return (ent->pw_uid);
177 }
178 #endif
179
180 #ifdef HAVE_GETGRNAM
181 AP_DECLARE(gid_t) ap_gname2id(const char *name)
182 {
183     struct group *ent;
184
185     if (name[0] == '#')
186         return (atoi(&name[1]));
187
188     if (!(ent = getgrnam(name))) {
189         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
190                      "%s: bad group name %s", ap_server_argv0, name);
191         exit(1);
192     }
193
194     return (ent->gr_gid);
195 }
196 #endif
197
198 #ifndef HAVE_INITGROUPS
199 int initgroups(const char *name, gid_t basegid)
200 {
201 #if defined(QNX) || defined(MPE) || defined(_OSD_POSIX) || defined(__TANDEM) || defined(WIN32) || defined(NETWARE)
202 /* QNX and MPE do not appear to support supplementary groups. */
203     return 0;
204 #else /* ndef QNX */
205     gid_t groups[NGROUPS_MAX];
206     struct group *g;
207     int index = 0;
208
209     setgrent();
210
211     groups[index++] = basegid;
212
213     while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) {
214         if (g->gr_gid != basegid) {
215             char **names;
216
217             for (names = g->gr_mem; *names != NULL; ++names) {
218                 if (!strcmp(*names, name))
219                     groups[index++] = g->gr_gid;
220             }
221         }
222     }
223
224     endgrent();
225
226     return setgroups(index, groups);
227 #endif /* def QNX */
228 }
229 #endif /* def NEED_INITGROUPS */
230
231 /* standard mpm configuration handling */
232 const char *ap_pid_fname = NULL;
233
234 const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy,
235                                const char *arg)
236 {
237     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
238     if (err != NULL) {
239         return err;
240     }
241
242     if (cmd->server->is_virtual) {
243         return "PidFile directive not allowed in <VirtualHost>";
244     }
245
246     ap_pid_fname = arg;
247     return NULL;
248 }
249
250 const char * ap_mpm_set_scoreboard(cmd_parms *cmd, void *dummy,
251                                    const char *arg)
252 {
253     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
254     if (err != NULL) {
255         return err;
256     }
257
258     ap_scoreboard_fname = arg;
259     return NULL;
260 }
261
262 const char *ap_lock_fname = NULL;
263
264 const char *ap_mpm_set_lockfile(cmd_parms *cmd, void *dummy,
265                                 const char *arg)
266 {
267     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
268     if (err != NULL) {
269         return err;
270     }
271
272     ap_lock_fname = arg;
273     return NULL;
274 }
275
276 int ap_max_requests_per_child = 0;
277
278 const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy,
279                                     const char *arg)
280 {
281     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
282     if (err != NULL) {
283         return err;
284     }
285
286     ap_max_requests_per_child = atoi(arg);
287
288     return NULL;
289 }
290
291 char ap_coredump_dir[MAX_STRING_LEN];
292 int ap_coredumpdir_configured;
293
294 const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
295                                    const char *arg)
296 {
297     apr_status_t rv;
298     apr_finfo_t finfo;
299     const char *fname;
300     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
301     if (err != NULL) {
302         return err;
303     }
304
305     fname = ap_server_root_relative(cmd->pool, arg);
306     if (!fname) {
307         return apr_pstrcat(cmd->pool, "Invalid CoreDumpDirectory path ",
308                            arg, NULL);
309     }
310     if ((rv = apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool)) != APR_SUCCESS) {
311         return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
312                            " does not exist", NULL);
313     }
314     if (finfo.filetype != APR_DIR) {
315         return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
316                            " is not a directory", NULL);
317     }
318     apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
319     ap_coredumpdir_configured = 1;
320     return NULL;
321 }
322
323 int ap_graceful_shutdown_timeout = 0;
324
325 const char * ap_mpm_set_graceful_shutdown(cmd_parms *cmd, void *dummy,
326                                           const char *arg)
327 {
328     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
329     if (err != NULL) {
330         return err;
331     }
332     ap_graceful_shutdown_timeout = atoi(arg);
333     return NULL;
334 }
335
336 apr_lockmech_e ap_accept_lock_mech = APR_LOCK_DEFAULT;
337
338 const char *ap_mpm_set_accept_lock_mech(cmd_parms *cmd,
339                                         void *dummy,
340                                         const char *arg)
341 {
342     apr_status_t rv;
343     const char *lockfile;
344     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
345     if (err != NULL) {
346         return err;
347     }
348
349     rv = ap_parse_mutex(arg, cmd->server->process->pool,
350                         &ap_accept_lock_mech, &lockfile);
351
352     if ((rv == APR_ENOTIMPL) || (rv == APR_ENOLOCK)) {
353         return apr_pstrcat(cmd->pool, "Invalid AcceptMutex argument ", arg,
354                            " (" AP_AVAILABLE_MUTEXES_STRING ")", NULL);
355     } else if (rv == APR_BADARG) {
356             return apr_pstrcat(cmd->pool, "Invalid AcceptMutex filepath ",
357                                arg, NULL);
358     }
359
360     if (lockfile && !ap_lock_fname)
361         ap_lock_fname = lockfile;
362     return NULL;
363 }
364
365 apr_uint32_t ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
366
367 const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
368                                     const char *arg)
369 {
370     long value;
371     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
372     if (err != NULL) {
373         return err;
374     }
375
376     value = strtol(arg, NULL, 0);
377     if (value < 0 || errno == ERANGE)
378         return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ",
379                            arg, NULL);
380
381     ap_max_mem_free = (apr_uint32_t)value * 1024;
382
383     return NULL;
384 }
385
386 apr_size_t ap_thread_stacksize = 0; /* use system default */
387
388 const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy,
389                                         const char *arg)
390 {
391     long value;
392     const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
393     if (err != NULL) {
394         return err;
395     }
396
397     value = strtol(arg, NULL, 0);
398     if (value < 0 || errno == ERANGE)
399         return apr_pstrcat(cmd->pool, "Invalid ThreadStackSize value: ",
400                            arg, NULL);
401
402     ap_thread_stacksize = (apr_size_t)value;
403
404     return NULL;
405 }
406
407 AP_DECLARE(int) ap_mpm_run(apr_pool_t *pconf, apr_pool_t *plog, server_rec *server_conf)
408 {
409     return ap_run_mpm(pconf, plog, server_conf);
410 }
411
412 AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
413 {
414     return ap_run_mpm_query(query_code, result);
415 }
416
417 AP_DECLARE(pid_t) ap_mpm_get_child_pid(int childnum)
418 {
419     return ap_run_mpm_get_child_pid(childnum);
420 }
421
422 AP_DECLARE(apr_status_t) ap_mpm_note_child_killed(int childnum)
423 {
424     return ap_run_mpm_note_child_killed(childnum);
425 }
426
427 AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton)
428 {
429     return ap_run_mpm_register_timed_callback(t, cbfn, baton);
430 }
431
432 AP_DECLARE(const char *)ap_show_mpm(void)
433 {
434     const char *name = ap_run_mpm_get_name();
435
436     if (!name) {
437         name = "";
438     }
439
440     return name;
441 }