1 |
/* |
2 |
* Hydra, an http server |
3 |
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com> |
4 |
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org> |
5 |
* Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org> |
6 |
* Some changes Copyright (C) 1997 Alain Magloire <alain.magloire@rcsm.ee.mcgill.ca> |
7 |
* Portions Copyright (C) 2002 Nikos Mavroyanopoulos <nmav@gnutls.org> |
8 |
* |
9 |
* This program is free software; you can redistribute it and/or modify |
10 |
* it under the terms of the GNU General Public License as published by |
11 |
* the Free Software Foundation; either version 1, or (at your option) |
12 |
* any later version. |
13 |
* |
14 |
* This program is distributed in the hope that it will be useful, |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
* GNU General Public License for more details. |
18 |
* |
19 |
* You should have received a copy of the GNU General Public License |
20 |
* along with this program; if not, write to the Free Software |
21 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 |
* |
23 |
*/ |
24 |
|
25 |
/* $Id: signals.c,v 1.23.2.4 2003/01/19 10:45:43 nmav Exp $*/ |
26 |
|
27 |
#include "boa.h" |
28 |
#ifdef HAVE_SYS_WAIT_H |
29 |
#include <sys/wait.h> /* wait */ |
30 |
#endif |
31 |
#include <signal.h> /* signal */ |
32 |
#include "ssl.h" |
33 |
|
34 |
#ifdef ENABLE_SMP |
35 |
extern pthread_t father_id; |
36 |
#endif |
37 |
|
38 |
void sigsegv(int); |
39 |
void sigbus(int); |
40 |
void sigterm(int); |
41 |
void sighup(int); |
42 |
void sigint(int); |
43 |
void sigchld(int); |
44 |
void sigalrm(int); |
45 |
void sigusr1(int); |
46 |
void sigusr2(int); /* needed in HIC thread */ |
47 |
|
48 |
/* |
49 |
* Name: init_signals |
50 |
* Description: Sets up signal handlers for all our friends. |
51 |
*/ |
52 |
|
53 |
void init_signals(void) |
54 |
{ |
55 |
struct sigaction sa; |
56 |
|
57 |
sa.sa_flags = 0; |
58 |
|
59 |
sigemptyset(&sa.sa_mask); |
60 |
sigaddset(&sa.sa_mask, SIGSEGV); |
61 |
sigaddset(&sa.sa_mask, SIGBUS); |
62 |
sigaddset(&sa.sa_mask, SIGTERM); |
63 |
sigaddset(&sa.sa_mask, SIGHUP); |
64 |
sigaddset(&sa.sa_mask, SIGINT); |
65 |
sigaddset(&sa.sa_mask, SIGPIPE); |
66 |
sigaddset(&sa.sa_mask, SIGCHLD); |
67 |
sigaddset(&sa.sa_mask, SIGALRM); |
68 |
sigaddset(&sa.sa_mask, SIGUSR1); |
69 |
sigaddset(&sa.sa_mask, SIGUSR2); |
70 |
|
71 |
sa.sa_handler = sigsegv; |
72 |
sigaction(SIGSEGV, &sa, NULL); |
73 |
|
74 |
sa.sa_handler = sigbus; |
75 |
sigaction(SIGBUS, &sa, NULL); |
76 |
|
77 |
sa.sa_handler = SIG_IGN; |
78 |
sigaction(SIGPIPE, &sa, NULL); |
79 |
|
80 |
sa.sa_handler = sigchld; |
81 |
sigaction(SIGCHLD, &sa, NULL); |
82 |
|
83 |
sa.sa_handler = sigterm; |
84 |
sigaction(SIGTERM, &sa, NULL); |
85 |
|
86 |
sa.sa_handler = sighup; |
87 |
sigaction(SIGHUP, &sa, NULL); |
88 |
|
89 |
sa.sa_handler = sigint; |
90 |
sigaction(SIGINT, &sa, NULL); |
91 |
|
92 |
sa.sa_handler = sigalrm; |
93 |
sigaction(SIGALRM, &sa, NULL); |
94 |
|
95 |
sa.sa_handler = sigusr1; |
96 |
sigaction(SIGUSR1, &sa, NULL); |
97 |
|
98 |
sa.sa_handler = sigusr2; |
99 |
sigaction(SIGUSR2, &sa, NULL); |
100 |
} |
101 |
|
102 |
/* Blocks all signals that should be handled by |
103 |
* the main thread, so that other threads are |
104 |
* not annoyed. |
105 |
*/ |
106 |
void block_main_signals() |
107 |
{ |
108 |
sigset_t sigset; |
109 |
|
110 |
sigemptyset(&sigset); |
111 |
sigaddset(&sigset, SIGALRM); |
112 |
sigaddset(&sigset, SIGUSR1); |
113 |
sigaddset(&sigset, SIGUSR2); |
114 |
sigaddset(&sigset, SIGTERM); |
115 |
sigaddset(&sigset, SIGINT); |
116 |
|
117 |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
118 |
} |
119 |
|
120 |
void unblock_main_signals() |
121 |
{ |
122 |
sigset_t sigset; |
123 |
|
124 |
sigemptyset(&sigset); |
125 |
sigaddset(&sigset, SIGALRM); |
126 |
sigaddset(&sigset, SIGUSR1); |
127 |
sigaddset(&sigset, SIGUSR2); |
128 |
sigaddset(&sigset, SIGTERM); |
129 |
sigaddset(&sigset, SIGHUP); |
130 |
sigaddset(&sigset, SIGINT); |
131 |
|
132 |
sigprocmask(SIG_UNBLOCK, &sigset, NULL); |
133 |
} |
134 |
|
135 |
void block_sigusr2() |
136 |
{ |
137 |
sigset_t sigset; |
138 |
|
139 |
sigemptyset(&sigset); |
140 |
sigaddset(&sigset, SIGUSR2); |
141 |
|
142 |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
143 |
} |
144 |
|
145 |
void unblock_sigusr2() |
146 |
{ |
147 |
sigset_t sigset; |
148 |
|
149 |
sigemptyset(&sigset); |
150 |
sigaddset(&sigset, SIGUSR2); |
151 |
|
152 |
sigprocmask(SIG_UNBLOCK, &sigset, NULL); |
153 |
} |
154 |
|
155 |
|
156 |
void sigsegv(int dummy) |
157 |
{ |
158 |
time(¤t_time); |
159 |
log_error_time(); |
160 |
fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir); |
161 |
fclose(stderr); |
162 |
chdir(tempdir); |
163 |
abort(); |
164 |
} |
165 |
|
166 |
void sigbus(int dummy) |
167 |
{ |
168 |
server_params *params = &global_server_params[0]; |
169 |
|
170 |
/* Note that in multithreaded cases the SIGBUS is catched |
171 |
* by the same thread that did the violation. So the following |
172 |
* code should be ok. |
173 |
*/ |
174 |
|
175 |
#ifdef ENABLE_SMP |
176 |
pthread_t tid = pthread_self(); |
177 |
int i; |
178 |
|
179 |
for (i = 0; i < global_server_params_size; i++) { |
180 |
if (pthread_equal(global_server_params[i].tid, tid)) { |
181 |
params = &global_server_params[i]; |
182 |
break; |
183 |
} |
184 |
} |
185 |
#endif |
186 |
|
187 |
if (params->handle_sigbus) { |
188 |
longjmp(params->env, dummy); |
189 |
} |
190 |
time(¤t_time); |
191 |
log_error_time(); |
192 |
fprintf(stderr, "caught SIGBUS, dumping core in %s\n", tempdir); |
193 |
fclose(stderr); |
194 |
chdir(tempdir); |
195 |
abort(); |
196 |
} |
197 |
|
198 |
#define SET_PTH_SIGFLAG( flag, val) \ |
199 |
global_server_params[0].flag = val |
200 |
|
201 |
#ifdef ENABLE_SMP |
202 |
# define _SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
203 |
{ pthread_t tid = pthread_self(); int i; int set = 0; \ |
204 |
for (i=0;i<global_server_params_size;i++) { \ |
205 |
if ( pthread_equal( global_server_params[i].tid, tid)) { \ |
206 |
global_server_params[i].flag = val; \ |
207 |
set = 1; \ |
208 |
break; \ |
209 |
} \ |
210 |
} |
211 |
|
212 |
# ifdef ENABLE_HIC |
213 |
# define SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
214 |
_SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
215 |
\ |
216 |
if (!set) { /* try hic threads */ \ |
217 |
for (i=0;i<global_hic_params_size;i++) { \ |
218 |
if ( pthread_equal( global_hic_params[i].tid, tid)) { \ |
219 |
global_hic_params[i].flag = val; \ |
220 |
break; \ |
221 |
} \ |
222 |
} \ |
223 |
} \ |
224 |
} |
225 |
# else |
226 |
|
227 |
# define SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
228 |
_SET_LOCAL_PTH_SIGFLAG( flag, val) } |
229 |
|
230 |
# endif |
231 |
|
232 |
#else |
233 |
# define SET_LOCAL_PTH_SIGFLAG SET_PTH_SIGFLAG |
234 |
#endif |
235 |
|
236 |
void sigterm(int dummy) |
237 |
{ |
238 |
SET_PTH_SIGFLAG(sigterm_flag, 1); |
239 |
} |
240 |
|
241 |
|
242 |
void sigterm_stage1_run() |
243 |
{ /* lame duck mode */ |
244 |
#ifdef ENABLE_SMP |
245 |
int i; |
246 |
#endif |
247 |
|
248 |
time(¤t_time); |
249 |
log_error_time(); |
250 |
fputs("caught SIGTERM, starting shutdown\n", stderr); |
251 |
|
252 |
#ifdef ENABLE_SMP |
253 |
{ |
254 |
int ret; |
255 |
/* remember that the first thread is actual the main process. |
256 |
*/ |
257 |
for (i = 1; i < global_server_params_size; i++) { |
258 |
/* terminate all threads */ |
259 |
if ((ret = pthread_cancel(global_server_params[i].tid)) != 0) { |
260 |
log_error_time(); |
261 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n", |
262 |
(int) global_server_params[i].tid, ret); |
263 |
exit(1); |
264 |
} |
265 |
} |
266 |
|
267 |
# ifdef ENABLE_HIC |
268 |
for (i = 0; i < global_hic_params_size; i++) { |
269 |
if ((ret = pthread_cancel(global_hic_params[i].tid)) != 0) { |
270 |
log_error_time(); |
271 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n", |
272 |
(int) global_hic_params[i].tid, ret); |
273 |
exit(1); |
274 |
} |
275 |
} |
276 |
# endif |
277 |
} |
278 |
#endif |
279 |
|
280 |
if (global_server_params[0].server_s[0].socket != -1) { |
281 |
close(global_server_params[0].server_s[0].socket); |
282 |
} |
283 |
|
284 |
if (global_server_params[0].server_s[1].socket != -1) { |
285 |
close(global_server_params[0].server_s[1].socket); |
286 |
} |
287 |
|
288 |
SET_PTH_SIGFLAG(sigterm_flag, 2); |
289 |
} |
290 |
|
291 |
|
292 |
void sigterm_stage2_run() |
293 |
{ /* lame duck mode */ |
294 |
int i; |
295 |
|
296 |
log_error_time(); |
297 |
fprintf(stderr, |
298 |
"exiting Hydra normally (uptime %d seconds)\n", |
299 |
(int) (current_time - start_time)); |
300 |
chdir(tempdir); |
301 |
clear_common_env(); |
302 |
dump_mime(); |
303 |
dump_passwd(); |
304 |
dump_virthost(); |
305 |
dump_directory_index(); |
306 |
dump_hic_modules(); |
307 |
|
308 |
for (i = 0; i < global_server_params_size; i++) { |
309 |
free_requests(&global_server_params[i]); |
310 |
} |
311 |
|
312 |
exit(0); |
313 |
} |
314 |
|
315 |
|
316 |
void sighup(int dummy) |
317 |
{ |
318 |
SET_LOCAL_PTH_SIGFLAG(sighup_flag, 1); |
319 |
} |
320 |
|
321 |
void sighup_run() |
322 |
{ |
323 |
int i; |
324 |
|
325 |
/* In sighup case, the father frees all memory, and |
326 |
* the childen terminate. |
327 |
*/ |
328 |
|
329 |
SET_LOCAL_PTH_SIGFLAG(sighup_flag, 0); |
330 |
|
331 |
|
332 |
#ifdef ENABLE_SMP |
333 |
/* Kill all threads! */ |
334 |
if (pthread_self() == father_id) { |
335 |
int ret; |
336 |
|
337 |
time(¤t_time); |
338 |
log_error_time(); |
339 |
fputs("caught SIGHUP, restarting\n", stderr); |
340 |
|
341 |
for (i = 1; i < global_server_params_size; i++) { |
342 |
if ((ret = pthread_kill(global_server_params[i].tid, SIGHUP)) != 0) { |
343 |
log_error_time(); |
344 |
fprintf(stderr, "Could not kill thread: %d. errno = %d.\n", |
345 |
(int) global_server_params[i].tid, ret); |
346 |
} else |
347 |
if ((ret=pthread_join( global_server_params[i].tid, NULL)) != 0) { |
348 |
log_error_time(); |
349 |
fprintf(stderr, "Could not join thread: %d. errno = %d.\n", |
350 |
(int) global_server_params[i].tid, ret); |
351 |
} |
352 |
} |
353 |
log_error_time(); |
354 |
fputs("Terminated all the threads in the pool.\n", stderr); |
355 |
|
356 |
# ifdef ENABLE_HIC |
357 |
for (i = 0; i < global_hic_params_size; i++) { |
358 |
if ((ret = pthread_kill(global_hic_params[i].tid, SIGHUP)) != 0) { |
359 |
log_error_time(); |
360 |
fprintf(stderr, "Could not kill thread: %d. errno = %d.\n", |
361 |
(int) global_hic_params[i].tid, ret); |
362 |
} else |
363 |
/* wait too see it die */ |
364 |
if ((ret=pthread_join( global_hic_params[i].tid, NULL)) != 0) { |
365 |
log_error_time(); |
366 |
fprintf(stderr, "Could not join thread: %d. errno = %d.\n", |
367 |
(int) global_hic_params[i].tid, ret); |
368 |
} |
369 |
} |
370 |
|
371 |
log_error_time(); |
372 |
fputs("Terminated all the HIC threads.\n", stderr); |
373 |
# endif |
374 |
|
375 |
for (i = 0; i < global_server_params_size; i++) { |
376 |
free_requests(&global_server_params[i]); |
377 |
} |
378 |
|
379 |
#endif |
380 |
for (i = 0; i < global_server_params_size; i++) { |
381 |
BOA_FD_ZERO(&global_server_params[i].block_read_fdset); |
382 |
BOA_FD_ZERO(&global_server_params[i].block_write_fdset); |
383 |
} |
384 |
|
385 |
/* Philosophy change for 0.92: don't close and attempt reopen of logfiles, |
386 |
* since usual permission structure prevents such reopening. |
387 |
*/ |
388 |
|
389 |
/* clear_common_env(); NEVER DO THIS */ |
390 |
dump_mime(); |
391 |
dump_passwd(); |
392 |
dump_virthost(); |
393 |
dump_directory_index(); |
394 |
dump_hic_modules(); |
395 |
|
396 |
log_error_time(); |
397 |
fputs("re-reading configuration files\n", stderr); |
398 |
read_config_files(); |
399 |
|
400 |
/* We now need to dispatch the threads again */ |
401 |
#ifdef ENABLE_HIC |
402 |
hic_init(); |
403 |
#endif |
404 |
smp_reinit(); |
405 |
ssl_reinit(); |
406 |
mmap_reinit(); |
407 |
|
408 |
log_error_time(); |
409 |
fputs("successful restart\n", stderr); |
410 |
|
411 |
} else { /* a normal thread -- not father */ |
412 |
pthread_exit(NULL); |
413 |
} |
414 |
|
415 |
} |
416 |
|
417 |
void sigint(int dummy) |
418 |
{ |
419 |
time(¤t_time); |
420 |
log_error_time(); |
421 |
fputs("caught SIGINT: shutting down\n", stderr); |
422 |
fclose(stderr); |
423 |
chdir(tempdir); |
424 |
exit(1); |
425 |
} |
426 |
|
427 |
void sigchld(int dummy) |
428 |
{ |
429 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 1); |
430 |
} |
431 |
|
432 |
void sigchld_run(void) |
433 |
{ |
434 |
int status; |
435 |
pid_t pid; |
436 |
|
437 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 0); |
438 |
|
439 |
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) |
440 |
if (verbose_cgi_logs) { |
441 |
time(¤t_time); |
442 |
log_error_time(); |
443 |
fprintf(stderr, "reaping child %d: status %d\n", (int) pid, |
444 |
status); |
445 |
} |
446 |
return; |
447 |
} |
448 |
|
449 |
void sigalrm(int dummy) |
450 |
{ |
451 |
SET_PTH_SIGFLAG(sigalrm_flag, 1); |
452 |
} |
453 |
|
454 |
void sigusr2(int dummy) |
455 |
{ |
456 |
return; |
457 |
} |
458 |
|
459 |
void sigusr1(int dummy) |
460 |
{ |
461 |
SET_PTH_SIGFLAG(sigusr1_flag, 1); |
462 |
} |
463 |
|
464 |
#ifdef ENABLE_SMP |
465 |
extern pthread_mutex_t mmap_lock; |
466 |
#endif |
467 |
|
468 |
void sigalrm_run(void) |
469 |
{ |
470 |
SET_PTH_SIGFLAG(sigalrm_flag, 0); |
471 |
|
472 |
#ifdef ENABLE_SSL |
473 |
if (boa_ssl) |
474 |
ssl_regenerate_params(); |
475 |
#endif |
476 |
|
477 |
log_error_time(); |
478 |
fprintf(stderr, "Cleaning up file caches.\n"); |
479 |
#ifdef ENABLE_SMP |
480 |
pthread_mutex_lock(&mmap_lock); |
481 |
#endif |
482 |
/* Clear all unused entries in the mmap list */ |
483 |
cleanup_mmap_list(1); |
484 |
#ifdef ENABLE_SMP |
485 |
pthread_mutex_unlock(&mmap_lock); |
486 |
#endif |
487 |
|
488 |
if (maintenance_interval) |
489 |
alarm(maintenance_interval); |
490 |
|
491 |
} |
492 |
|
493 |
void sigusr1_run(void) |
494 |
{ |
495 |
int i; |
496 |
|
497 |
SET_PTH_SIGFLAG(sigusr1_flag, 0); |
498 |
|
499 |
time(¤t_time); |
500 |
|
501 |
for (i = 0; i < global_server_params_size; i++) { |
502 |
log_error_time(); |
503 |
fprintf(stderr, "Thread %d: %ld requests, %ld errors\n", |
504 |
i + 1, global_server_params[i].status.requests, |
505 |
global_server_params[i].status.errors); |
506 |
} |
507 |
|
508 |
/* Only print the running connections if we have set a connection |
509 |
* limit. That is because we do not count connections when we |
510 |
* have no connection limits. |
511 |
*/ |
512 |
if (max_connections != INT_MAX) { |
513 |
log_error_time(); |
514 |
fprintf(stderr, "Running connections: %ld\n", |
515 |
get_total_global_connections(0)); |
516 |
} |
517 |
|
518 |
#ifdef ENABLE_SSL |
519 |
if ( max_ssl_connections != INT_MAX) { |
520 |
log_error_time(); |
521 |
fprintf(stderr, "Running SSL connections: %ld\n", |
522 |
get_total_global_connections(1)); |
523 |
} |
524 |
#endif |
525 |
|
526 |
show_hash_stats(); |
527 |
|
528 |
} |