summaryrefslogtreecommitdiff
path: root/include/mpm_common.h
blob: 334624ee065a84721f2da7a804defd10c9f15882 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* The purpose of this file is to store the code that MOST mpm's will need
 * this does not mean a function only goes into this file if every MPM needs
 * it.  It means that if a function is needed by more than one MPM, and
 * future maintenance would be served by making the code common, then the
 * function belongs here.
 *
 * This is going in src/main because it is not platform specific, it is
 * specific to multi-process servers, but NOT to Unix.  Which is why it
 * does not belong in src/os/unix
 */

/**
 * @file  mpm_common.h
 * @brief Multi-Processing Modules functions
 *
 * @defgroup APACHE_MPM Multi-Processing Modules
 * @ingroup  APACHE
 * @{
 */

#ifndef APACHE_MPM_COMMON_H
#define APACHE_MPM_COMMON_H

#include "ap_config.h"
#include "ap_mpm.h"
#include "scoreboard.h"

#if APR_HAVE_NETINET_TCP_H
#include <netinet/tcp.h>    /* for TCP_NODELAY */
#endif

#include "apr_proc_mutex.h"

#ifdef __cplusplus
extern "C" {
#endif

/* The maximum length of the queue of pending connections, as defined
 * by listen(2).  Under some systems, it should be increased if you
 * are experiencing a heavy TCP SYN flood attack.
 *
 * It defaults to 511 instead of 512 because some systems store it
 * as an 8-bit datatype; 512 truncated to 8-bits is 0, while 511 is
 * 255 when truncated.
 */
#ifndef DEFAULT_LISTENBACKLOG
#define DEFAULT_LISTENBACKLOG 511
#endif

/* Signal used to gracefully restart */
#define AP_SIG_GRACEFUL SIGUSR1

/* Signal used to gracefully restart (without SIG prefix) */
#define AP_SIG_GRACEFUL_SHORT USR1

/* Signal used to gracefully restart (as a quoted string) */
#define AP_SIG_GRACEFUL_STRING "SIGUSR1"

/* Signal used to gracefully stop */
#define AP_SIG_GRACEFUL_STOP SIGWINCH

/* Signal used to gracefully stop (without SIG prefix) */
#define AP_SIG_GRACEFUL_STOP_SHORT WINCH

/* Signal used to gracefully stop (as a quoted string) */
#define AP_SIG_GRACEFUL_STOP_STRING "SIGWINCH"

/**
 * Callback function used for ap_reclaim_child_processes() and
 * ap_relieve_child_processes().  The callback function will be
 * called for each terminated child process.
 */
typedef void ap_reclaim_callback_fn_t(int childnum, pid_t pid,
                                      ap_generation_t gen);

#if (!defined(WIN32) && !defined(NETWARE)) || defined(DOXYGEN)
/**
 * Make sure all child processes that have been spawned by the parent process
 * have died.  This includes process registered as "other_children".
 *
 * @param terminate Either 1 or 0.  If 1, send the child processes SIGTERM
 *        each time through the loop.  If 0, give the process time to die
 *        on its own before signalling it.
 * @param mpm_callback Callback invoked for each dead child process
 *
 * @note The MPM child processes which are reclaimed are those listed
 * in the scoreboard as well as those currently registered via
 * ap_register_extra_mpm_process().
 */
AP_DECLARE(void) ap_reclaim_child_processes(int terminate,
                                            ap_reclaim_callback_fn_t *mpm_callback);

/**
 * Catch any child processes that have been spawned by the parent process
 * which have exited. This includes processes registered as "other_children".
 *
 * @param mpm_callback Callback invoked for each dead child process

 * @note The MPM child processes which are relieved are those listed
 * in the scoreboard as well as those currently registered via
 * ap_register_extra_mpm_process().
 */
AP_DECLARE(void) ap_relieve_child_processes(ap_reclaim_callback_fn_t *mpm_callback);

/**
 * Tell ap_reclaim_child_processes() and ap_relieve_child_processes() about
 * an MPM child process which has no entry in the scoreboard.
 * @param pid The process id of an MPM child process which should be
 * reclaimed when ap_reclaim_child_processes() is called.
 * @param gen The generation of this MPM child process.
 *
 * @note If an extra MPM child process terminates prior to calling
 * ap_reclaim_child_processes(), remove it from the list of such processes
 * by calling ap_unregister_extra_mpm_process().
 */
AP_DECLARE(void) ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen);

/**
 * Unregister an MPM child process which was previously registered by a
 * call to ap_register_extra_mpm_process().
 * @param pid The process id of an MPM child process which no longer needs to
 * be reclaimed.
 * @param old_gen Set to the server generation of the process, if found.
 * @return 1 if the process was found and removed, 0 otherwise
 */
AP_DECLARE(int) ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *old_gen);

/**
 * Safely signal an MPM child process, if the process is in the
 * current process group.  Otherwise fail.
 * @param pid the process id of a child process to signal
 * @param sig the signal number to send
 * @return APR_SUCCESS if signal is sent, otherwise an error as per kill(3);
 * APR_EINVAL is returned if passed either an invalid (< 1) pid, or if
 * the pid is not in the current process group
 */
AP_DECLARE(apr_status_t) ap_mpm_safe_kill(pid_t pid, int sig);

/**
 * Log why a child died to the error log, if the child died without the
 * parent signalling it.
 * @param pid The child that has died
 * @param why The return code of the child process
 * @param status The status returned from ap_wait_or_timeout
 * @return 0 on success, APEXIT_CHILDFATAL if MPM should terminate
 */
AP_DECLARE(int) ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, int status);

AP_DECLARE(apr_status_t) ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf);
AP_DECLARE(apr_status_t) ap_fatal_signal_child_setup(server_rec *s);

#endif /* (!WIN32 && !NETWARE) || DOXYGEN */

/**
 * Pool cleanup for end-generation hook implementation
 * (core httpd function)
 */
apr_status_t ap_mpm_end_gen_helper(void *unused);

/**
 * Run the monitor hook (once every ten calls), determine if any child
 * process has died and, if none died, sleep one second.
 * @param status The return code if a process has died
 * @param exitcode The returned exit status of the child, if a child process
 *                 dies, or the signal that caused the child to die.
 * @param ret The process id of the process that died
 * @param p The pool to allocate out of
 * @param s The server_rec to pass
 */
AP_DECLARE(void) ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode,
                                    apr_proc_t *ret, apr_pool_t *p, 
                                    server_rec *s);

#if defined(TCP_NODELAY)
/**
 * Turn off the nagle algorithm for the specified socket.  The nagle algorithm
 * says that we should delay sending partial packets in the hopes of getting
 * more data.  There are bad interactions between persistent connections and
 * Nagle's algorithm that have severe performance penalties.
 * @param s The socket to disable nagle for.
 */
void ap_sock_disable_nagle(apr_socket_t *s);
#else
#define ap_sock_disable_nagle(s)        /* NOOP */
#endif

#ifdef HAVE_GETPWNAM
/**
 * Convert a username to a numeric ID
 * @param name The name to convert
 * @return The user id corresponding to a name
 * @fn uid_t ap_uname2id(const char *name)
 */
AP_DECLARE(uid_t) ap_uname2id(const char *name);
#endif

#ifdef HAVE_GETGRNAM
/**
 * Convert a group name to a numeric ID
 * @param name The name to convert
 * @return The group id corresponding to a name
 * @fn gid_t ap_gname2id(const char *name)
 */
AP_DECLARE(gid_t) ap_gname2id(const char *name);
#endif

#ifndef HAVE_INITGROUPS
/**
 * The initgroups() function initializes the group access list by reading the
 * group database /etc/group and using all groups of which user is a member.
 * The additional group basegid is also added to the list.
 * @param name The user name - must be non-NULL
 * @param basegid The basegid to add
 * @return returns 0 on success
 * @fn int initgroups(const char *name, gid_t basegid)
 */
int initgroups(const char *name, gid_t basegid);
#endif

#if (!defined(WIN32) && !defined(NETWARE)) || defined(DOXYGEN)

typedef struct ap_pod_t ap_pod_t;

struct ap_pod_t {
    apr_file_t *pod_in;
    apr_file_t *pod_out;
    apr_pool_t *p;
};

/**
 * Open the pipe-of-death.  The pipe of death is used to tell all child
 * processes that it is time to die gracefully.
 * @param p The pool to use for allocating the pipe
 * @param pod the pipe-of-death that is created.
 */
AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod);

/**
 * Check the pipe to determine if the process has been signalled to die.
 */
AP_DECLARE(apr_status_t) ap_mpm_pod_check(ap_pod_t *pod);

/**
 * Close the pipe-of-death
 *
 * @param pod the pipe-of-death to close.
 */
AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod);

/**
 * Write data to the pipe-of-death, signalling that one child process
 * should die.
 * @param pod the pipe-of-death to write to.
 */
AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod);

/**
 * Write data to the pipe-of-death, signalling that all child process
 * should die.
 * @param pod The pipe-of-death to write to.
 * @param num The number of child processes to kill
 */
AP_DECLARE(void) ap_mpm_pod_killpg(ap_pod_t *pod, int num);

#define AP_MPM_PODX_RESTART_CHAR '$'
#define AP_MPM_PODX_GRACEFUL_CHAR '!'

typedef enum { AP_MPM_PODX_NORESTART, AP_MPM_PODX_RESTART, AP_MPM_PODX_GRACEFUL } ap_podx_restart_t;

/**
 * Open the extended pipe-of-death.
 * @param p The pool to use for allocating the pipe
 * @param pod The pipe-of-death that is created.
 */
AP_DECLARE(apr_status_t) ap_mpm_podx_open(apr_pool_t *p, ap_pod_t **pod);

/**
 * Check the extended pipe to determine if the process has been signalled to die.
 */
AP_DECLARE(int) ap_mpm_podx_check(ap_pod_t *pod);

/**
 * Close the pipe-of-death
 *
 * @param pod The pipe-of-death to close.
 */
AP_DECLARE(apr_status_t) ap_mpm_podx_close(ap_pod_t *pod);

/**
 * Write data to the extended pipe-of-death, signalling that one child process
 * should die.
 * @param pod the pipe-of-death to write to.
 * @param graceful restart-type
 */
AP_DECLARE(apr_status_t) ap_mpm_podx_signal(ap_pod_t *pod,
                                            ap_podx_restart_t graceful);

/**
 * Write data to the extended pipe-of-death, signalling that all child process
 * should die.
 * @param pod The pipe-of-death to write to.
 * @param num The number of child processes to kill
 * @param graceful restart-type
 */
AP_DECLARE(void) ap_mpm_podx_killpg(ap_pod_t *pod, int num,
                                    ap_podx_restart_t graceful);

#endif /* (!WIN32 && !NETWARE) || DOXYGEN */

/**
 * Check that exactly one MPM is loaded
 * Returns NULL if yes, error string if not.
 */
AP_DECLARE(const char *) ap_check_mpm(void);

/*
 * These data members are common to all mpms. Each new mpm
 * should either use the appropriate ap_mpm_set_* function
 * in their command table or create their own for custom or
 * OS specific needs. These should work for most.
 */

/**
 * The maximum number of requests each child thread or
 * process handles before dying off
 */
AP_DECLARE_DATA extern int ap_max_requests_per_child;
const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy,
                                    const char *arg);

/**
 * The filename used to store the process id.
 */
AP_DECLARE_DATA extern const char *ap_pid_fname;
const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy,
                               const char *arg);
void ap_mpm_dump_pidfile(apr_pool_t *p, apr_file_t *out);

/*
 * The directory that the server changes directory to dump core.
 */
AP_DECLARE_DATA extern char ap_coredump_dir[MAX_STRING_LEN];
AP_DECLARE_DATA extern int ap_coredumpdir_configured;
const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
                                   const char *arg);

/**
 * Set the timeout period for a graceful shutdown.
 */
AP_DECLARE_DATA extern int ap_graceful_shutdown_timeout;
AP_DECLARE(const char *)ap_mpm_set_graceful_shutdown(cmd_parms *cmd, void *dummy,
                                         const char *arg);
#define AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND \
AP_INIT_TAKE1("GracefulShutdownTimeout", ap_mpm_set_graceful_shutdown, NULL, \
              RSRC_CONF, "Maximum time in seconds to wait for child "        \
              "processes to complete transactions during shutdown")


int ap_signal_server(int *, apr_pool_t *);
void ap_mpm_rewrite_args(process_rec *);

AP_DECLARE_DATA extern apr_uint32_t ap_max_mem_free;
extern const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
                                           const char *arg);

AP_DECLARE_DATA extern apr_size_t ap_thread_stacksize;
extern const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy,
                                               const char *arg);

/* core's implementation of child_status hook */
extern void ap_core_child_status(server_rec *s, pid_t pid, ap_generation_t gen,
                                 int slot, mpm_child_status status);

#if defined(AP_ENABLE_EXCEPTION_HOOK) && AP_ENABLE_EXCEPTION_HOOK
extern const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy,
                                             const char *arg);
#endif

/**
 * This hook allows modules to be called at intervals by some MPMs
 * in the parent process.  IOW, this is not portable to all platforms
 * or MPMs.
 * @param p The pconf pool
 * @param s The main server
 * @return OK or DECLINED (errors are ignored)
 * @ingroup hooks
 */
AP_DECLARE_HOOK(int,monitor,(apr_pool_t *p, server_rec *s))

/* register modules that undertake to manage system security */
AP_DECLARE(int) ap_sys_privileges_handlers(int inc);
AP_DECLARE_HOOK(int, drop_privileges, (apr_pool_t * pchild, server_rec * s))

/**
 * implement the ap_mpm_query() function
 * The MPM should return OK+APR_ENOTIMPL for any unimplemented query codes;
 * modules which intercede for specific query codes should DECLINE for others.
 * @ingroup hooks
 */
AP_DECLARE_HOOK(int, mpm_query, (int query_code, int *result, apr_status_t *rv))

/**
 * register the specified callback
 * @ingroup hooks
 */
AP_DECLARE_HOOK(apr_status_t, mpm_register_timed_callback,
                (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton))

/**
 * register the specified callback
 * @ingroup hooks
 */
AP_DECLARE_HOOK(apr_status_t, mpm_register_poll_callback,
                (apr_pool_t *p, const apr_array_header_t *pds,
                 ap_mpm_callback_fn_t *cbfn, void *baton))

/* register the specified callback, with timeout 
 * @ingroup hooks
 *
 */
AP_DECLARE_HOOK(apr_status_t, mpm_register_poll_callback_timeout,
                (apr_pool_t *p, const apr_array_header_t *pds,
                ap_mpm_callback_fn_t *cbfn, ap_mpm_callback_fn_t *tofn,
                void *baton, apr_time_t timeout))

/** Resume the suspended connection 
 * @ingroup hooks
 */
AP_DECLARE_HOOK(apr_status_t, mpm_resume_suspended, (conn_rec*))

/**
 * Get MPM name (e.g., "prefork" or "event")
 * @ingroup hooks
 */
AP_DECLARE_HOOK(const char *,mpm_get_name,(void))

/**
 * Hook called to determine whether we should stay within the write completion
 * phase.
 * @param c The current connection
 * @return OK if write completion should continue, DECLINED if write completion
 * should end gracefully, or a positive error if we should begin to linger.
 * @ingroup hooks
 */
AP_DECLARE_HOOK(int, output_pending, (conn_rec *c))

/**
 * Hook called to determine whether any data is pending in the input filters.
 * @param c The current connection
 * @return OK if we can read without blocking, DECLINED if a read would block.
 * @ingroup hooks
 */
AP_DECLARE_HOOK(int, input_pending, (conn_rec *c))

/**
 * Notification that connection handling is suspending (disassociating from the
 * current thread)
 * @param c The current connection
 * @param r The current request, or NULL if there is no active request
 * @ingroup hooks
 * @see ap_hook_resume_connection
 * @note This hook is not implemented by MPMs like Prefork and Worker which 
 * handle all processing of a particular connection on the same thread.
 * @note This hook will be called on the thread that was previously
 * processing the connection.
 * @note This hook is not called at the end of connection processing.  This
 * hook only notifies a module when processing of an active connection is
 * suspended.
 * @note Resumption and subsequent suspension of a connection solely to perform
 * I/O by the MPM, with no execution of non-MPM code, may not necessarily result
 * in a call to this hook.
 * @ingroup hooks
 */
AP_DECLARE_HOOK(void, suspend_connection,
                (conn_rec *c, request_rec *r))

/**
 * Notification that connection handling is resuming (associating with a thread)
 * @param c The current connection
 * @param r The current request, or NULL if there is no active request
 * @ingroup hooks
 * @see ap_hook_suspend_connection
 * @note This hook is not implemented by MPMs like Prefork and Worker which 
 * handle all processing of a particular connection on the same thread.
 * @note This hook will be called on the thread that will resume processing
 * the connection.
 * @note This hook is not called at the beginning of connection processing.
 * This hook only notifies a module when processing resumes for a
 * previously-suspended connection.
 * @note Resumption and subsequent suspension of a connection solely to perform
 * I/O by the MPM, with no execution of non-MPM code, may not necessarily result
 * in a call to this hook.
 * @ingroup hooks
 */
AP_DECLARE_HOOK(void, resume_connection,
                (conn_rec *c, request_rec *r))

/**
 * Notification that the child is stopping. No new requests
 * or other tasks to be started.
 * If graceful, already started requests/tasks should be
 * processed normally.
 * @param pchild The child pool
 * @param graceful != 0 iff this is a graceful shutdown.
 */
AP_DECLARE_HOOK(void, child_stopping,
                (apr_pool_t *pchild, int graceful))

/**
 * Notification that the child has stopped processing
 * requests completely. Any running threads should be
 * shut down now.
 * Ideally, when this hook completes, no more threads
 * are running in the child process.
 * Note that de-allocation of global resources should
 * be run via memory pool destroy callback after this.
 * @param pchild The child pool
 * @param graceful != 0 iff this is a graceful shutdown.
 */
AP_DECLARE_HOOK(void, child_stopped,
                (apr_pool_t *pchild, int graceful))

/* mutex type string for accept mutex, if any; MPMs should use the
 * same mutex type for ease of configuration
 */
#define AP_ACCEPT_MUTEX_TYPE "mpm-accept"

/* internal pre-config logic for MPM-related settings, callable only from
 * core's pre-config hook
 */
void mpm_common_pre_config(apr_pool_t *pconf);

#ifdef __cplusplus
}
#endif

#endif /* !APACHE_MPM_COMMON_H */
/** @} */