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.19 2002/10/09 08:49:46 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 |
FD_CLR(global_server_params[0].server_s[0].socket, |
282 |
&global_server_params[0].block_read_fdset); |
283 |
close(global_server_params[0].server_s[0].socket); |
284 |
} |
285 |
|
286 |
if (global_server_params[0].server_s[1].socket != -1) { |
287 |
FD_CLR(global_server_params[0].server_s[1].socket, |
288 |
&global_server_params[0].block_read_fdset); |
289 |
close(global_server_params[0].server_s[1].socket); |
290 |
} |
291 |
|
292 |
SET_PTH_SIGFLAG(sigterm_flag, 2); |
293 |
} |
294 |
|
295 |
|
296 |
void sigterm_stage2_run() |
297 |
{ /* lame duck mode */ |
298 |
int i; |
299 |
|
300 |
log_error_time(); |
301 |
fprintf(stderr, |
302 |
"exiting Hydra normally (uptime %d seconds)\n", |
303 |
(int) (current_time - start_time)); |
304 |
chdir(tempdir); |
305 |
clear_common_env(); |
306 |
dump_mime(); |
307 |
dump_passwd(); |
308 |
dump_virthost(); |
309 |
dump_directory_index(); |
310 |
dump_hic_modules(); |
311 |
|
312 |
for (i = 0; i < global_server_params_size; i++) { |
313 |
free_requests(&global_server_params[i]); |
314 |
} |
315 |
|
316 |
exit(0); |
317 |
} |
318 |
|
319 |
|
320 |
void sighup(int dummy) |
321 |
{ |
322 |
SET_LOCAL_PTH_SIGFLAG(sighup_flag, 1); |
323 |
} |
324 |
|
325 |
void sighup_run() |
326 |
{ |
327 |
int i; |
328 |
|
329 |
/* In sighup case, the father frees all memory, and |
330 |
* the childen terminate. |
331 |
*/ |
332 |
|
333 |
SET_LOCAL_PTH_SIGFLAG(sighup_flag, 0); |
334 |
|
335 |
|
336 |
#ifdef ENABLE_SMP |
337 |
/* Kill all threads! */ |
338 |
if (pthread_self() == father_id) { |
339 |
int ret; |
340 |
|
341 |
time(¤t_time); |
342 |
log_error_time(); |
343 |
fputs("caught SIGHUP, restarting\n", stderr); |
344 |
|
345 |
for (i = 1; i < global_server_params_size; i++) { |
346 |
if ((ret = pthread_kill(global_server_params[i].tid, SIGHUP)) != 0) { |
347 |
log_error_time(); |
348 |
fprintf(stderr, "Could not kill thread: %d. errno = %d.\n", |
349 |
(int) global_server_params[i].tid, ret); |
350 |
} else |
351 |
if ((ret=pthread_join( global_server_params[i].tid, NULL)) != 0) { |
352 |
log_error_time(); |
353 |
fprintf(stderr, "Could not join thread: %d. errno = %d.\n", |
354 |
(int) global_hic_params[i].tid, ret); |
355 |
} |
356 |
} |
357 |
log_error_time(); |
358 |
fputs("Terminated all the threads in the pool.\n", stderr); |
359 |
|
360 |
# ifdef ENABLE_HIC |
361 |
for (i = 0; i < global_hic_params_size; i++) { |
362 |
if ((ret = pthread_kill(global_hic_params[i].tid, SIGHUP)) != 0) { |
363 |
log_error_time(); |
364 |
fprintf(stderr, "Could not kill thread: %d. errno = %d.\n", |
365 |
(int) global_hic_params[i].tid, ret); |
366 |
} else |
367 |
/* wait too see it die */ |
368 |
if ((ret=pthread_join( global_hic_params[i].tid, NULL)) != 0) { |
369 |
log_error_time(); |
370 |
fprintf(stderr, "Could not join thread: %d. errno = %d.\n", |
371 |
(int) global_hic_params[i].tid, ret); |
372 |
} |
373 |
} |
374 |
|
375 |
log_error_time(); |
376 |
fputs("Terminated all the HIC threads.\n", stderr); |
377 |
# endif |
378 |
|
379 |
for (i = 0; i < global_server_params_size; i++) { |
380 |
free_requests(&global_server_params[i]); |
381 |
} |
382 |
|
383 |
#endif |
384 |
for (i = 0; i < global_server_params_size; i++) { |
385 |
FD_ZERO(&global_server_params[i].block_read_fdset); |
386 |
FD_ZERO(&global_server_params[i].block_write_fdset); |
387 |
} |
388 |
|
389 |
/* Philosophy change for 0.92: don't close and attempt reopen of logfiles, |
390 |
* since usual permission structure prevents such reopening. |
391 |
*/ |
392 |
|
393 |
/* clear_common_env(); NEVER DO THIS */ |
394 |
dump_mime(); |
395 |
dump_passwd(); |
396 |
dump_virthost(); |
397 |
dump_directory_index(); |
398 |
dump_hic_modules(); |
399 |
|
400 |
log_error_time(); |
401 |
fputs("re-reading configuration files\n", stderr); |
402 |
read_config_files(); |
403 |
|
404 |
/* We now need to dispatch the threads again */ |
405 |
#ifdef ENABLE_HIC |
406 |
hic_init(); |
407 |
#endif |
408 |
smp_reinit(); |
409 |
ssl_reinit(); |
410 |
mmap_reinit(); |
411 |
|
412 |
log_error_time(); |
413 |
fputs("successful restart\n", stderr); |
414 |
|
415 |
} else { /* a normal thread -- not father */ |
416 |
pthread_exit(NULL); |
417 |
} |
418 |
|
419 |
} |
420 |
|
421 |
void sigint(int dummy) |
422 |
{ |
423 |
time(¤t_time); |
424 |
log_error_time(); |
425 |
fputs("caught SIGINT: shutting down\n", stderr); |
426 |
fclose(stderr); |
427 |
chdir(tempdir); |
428 |
exit(1); |
429 |
} |
430 |
|
431 |
void sigchld(int dummy) |
432 |
{ |
433 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 1); |
434 |
} |
435 |
|
436 |
void sigchld_run(void) |
437 |
{ |
438 |
int status; |
439 |
pid_t pid; |
440 |
|
441 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 0); |
442 |
|
443 |
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) |
444 |
if (verbose_cgi_logs) { |
445 |
time(¤t_time); |
446 |
log_error_time(); |
447 |
fprintf(stderr, "reaping child %d: status %d\n", (int) pid, |
448 |
status); |
449 |
} |
450 |
return; |
451 |
} |
452 |
|
453 |
void sigalrm(int dummy) |
454 |
{ |
455 |
SET_PTH_SIGFLAG(sigalrm_flag, 1); |
456 |
} |
457 |
|
458 |
void sigusr2(int dummy) |
459 |
{ |
460 |
return; |
461 |
} |
462 |
|
463 |
void sigusr1(int dummy) |
464 |
{ |
465 |
SET_PTH_SIGFLAG(sigusr1_flag, 1); |
466 |
} |
467 |
|
468 |
extern int ssl_params_refresh; |
469 |
extern int boa_ssl; |
470 |
|
471 |
void sigalrm_run(void) |
472 |
{ |
473 |
SET_PTH_SIGFLAG(sigalrm_flag, 0); |
474 |
|
475 |
#ifdef ENABLE_SSL |
476 |
if (boa_ssl) |
477 |
ssl_regenerate_params(); |
478 |
#endif |
479 |
|
480 |
if (boa_ssl && ssl_params_refresh) |
481 |
alarm(ssl_params_refresh); |
482 |
} |
483 |
|
484 |
void sigusr1_run(void) |
485 |
{ |
486 |
int i; |
487 |
|
488 |
SET_PTH_SIGFLAG(sigusr1_flag, 0); |
489 |
|
490 |
time(¤t_time); |
491 |
|
492 |
for (i = 0; i < global_server_params_size; i++) { |
493 |
log_error_time(); |
494 |
fprintf(stderr, "Thread %d: %ld requests, %ld errors\n", |
495 |
i + 1, global_server_params[i].status.requests, |
496 |
global_server_params[i].status.errors); |
497 |
} |
498 |
|
499 |
show_hash_stats(); |
500 |
|
501 |
} |