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.16 2002/09/30 17:16:54 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, SIGHUP); |
116 |
sigaddset(&sigset, SIGINT); |
117 |
|
118 |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
119 |
} |
120 |
|
121 |
void unblock_main_signals() |
122 |
{ |
123 |
sigset_t sigset; |
124 |
|
125 |
sigemptyset(&sigset); |
126 |
sigaddset(&sigset, SIGALRM); |
127 |
sigaddset(&sigset, SIGUSR1); |
128 |
sigaddset(&sigset, SIGUSR2); |
129 |
sigaddset(&sigset, SIGTERM); |
130 |
sigaddset(&sigset, SIGHUP); |
131 |
sigaddset(&sigset, SIGINT); |
132 |
|
133 |
sigprocmask(SIG_UNBLOCK, &sigset, NULL); |
134 |
} |
135 |
|
136 |
void block_sigusr2() |
137 |
{ |
138 |
sigset_t sigset; |
139 |
|
140 |
sigemptyset(&sigset); |
141 |
sigaddset(&sigset, SIGUSR2); |
142 |
|
143 |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
144 |
} |
145 |
|
146 |
void unblock_sigusr2() |
147 |
{ |
148 |
sigset_t sigset; |
149 |
|
150 |
sigemptyset(&sigset); |
151 |
sigaddset(&sigset, SIGUSR2); |
152 |
|
153 |
sigprocmask(SIG_UNBLOCK, &sigset, NULL); |
154 |
} |
155 |
|
156 |
|
157 |
void sigsegv(int dummy) |
158 |
{ |
159 |
time(¤t_time); |
160 |
log_error_time(); |
161 |
fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir); |
162 |
fclose(stderr); |
163 |
chdir(tempdir); |
164 |
abort(); |
165 |
} |
166 |
|
167 |
void sigbus(int dummy) |
168 |
{ |
169 |
server_params *params = &global_server_params[0]; |
170 |
|
171 |
/* Note that in multithreaded cases the SIGBUS is catched |
172 |
* by the same thread that did the violation. So the following |
173 |
* code should be ok. |
174 |
*/ |
175 |
|
176 |
#ifdef ENABLE_SMP |
177 |
pthread_t tid = pthread_self(); |
178 |
int i; |
179 |
|
180 |
for (i = 0; i < global_server_params_size; i++) { |
181 |
if (pthread_equal(global_server_params[i].tid, tid)) { |
182 |
params = &global_server_params[i]; |
183 |
break; |
184 |
} |
185 |
} |
186 |
#endif |
187 |
|
188 |
if (params->handle_sigbus) { |
189 |
longjmp(params->env, dummy); |
190 |
} |
191 |
time(¤t_time); |
192 |
log_error_time(); |
193 |
fprintf(stderr, "caught SIGBUS, dumping core in %s\n", tempdir); |
194 |
fclose(stderr); |
195 |
chdir(tempdir); |
196 |
abort(); |
197 |
} |
198 |
|
199 |
#define SET_PTH_SIGFLAG( flag, val) \ |
200 |
global_server_params[0].flag = val |
201 |
|
202 |
#ifdef ENABLE_SMP |
203 |
# define _SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
204 |
{ pthread_t tid = pthread_self(); int i; int set = 0; \ |
205 |
for (i=0;i<global_server_params_size;i++) { \ |
206 |
if ( pthread_equal( global_server_params[i].tid, tid)) { \ |
207 |
global_server_params[i].flag = val; \ |
208 |
set = 1; \ |
209 |
break; \ |
210 |
} \ |
211 |
} |
212 |
|
213 |
# ifdef ENABLE_HIC |
214 |
# define SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
215 |
_SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
216 |
\ |
217 |
if (!set) { /* try hic threads */ \ |
218 |
for (i=0;i<global_hic_params_size;i++) { \ |
219 |
if ( pthread_equal( global_hic_params[i].tid, tid)) { \ |
220 |
global_hic_params[i].flag = val; \ |
221 |
break; \ |
222 |
} \ |
223 |
} \ |
224 |
} \ |
225 |
} |
226 |
# else |
227 |
|
228 |
# define SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
229 |
_SET_LOCAL_PTH_SIGFLAG( flag, val) } |
230 |
|
231 |
# endif |
232 |
|
233 |
#else |
234 |
# define SET_LOCAL_PTH_SIGFLAG SET_PTH_SIGFLAG |
235 |
#endif |
236 |
|
237 |
void sigterm(int dummy) |
238 |
{ |
239 |
SET_PTH_SIGFLAG(sigterm_flag, 1); |
240 |
} |
241 |
|
242 |
|
243 |
void sigterm_stage1_run() |
244 |
{ /* lame duck mode */ |
245 |
#ifdef ENABLE_SMP |
246 |
int i; |
247 |
#endif |
248 |
|
249 |
time(¤t_time); |
250 |
log_error_time(); |
251 |
fputs("caught SIGTERM, starting shutdown\n", stderr); |
252 |
|
253 |
#ifdef ENABLE_SMP |
254 |
{ |
255 |
int ret; |
256 |
/* remember that the first thread is actual the main process. |
257 |
*/ |
258 |
for (i = 1; i < global_server_params_size; i++) { |
259 |
/* terminate all threads */ |
260 |
if ((ret = pthread_cancel(global_server_params[i].tid)) != 0) { |
261 |
log_error_time(); |
262 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n", |
263 |
(int) global_server_params[i].tid, ret); |
264 |
exit(1); |
265 |
} |
266 |
} |
267 |
|
268 |
# ifdef ENABLE_HIC |
269 |
for (i = 0; i < global_hic_params_size; i++) { |
270 |
if ((ret = pthread_cancel(global_hic_params[i].tid)) != 0) { |
271 |
log_error_time(); |
272 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n", |
273 |
(int) global_hic_params[i].tid, ret); |
274 |
exit(1); |
275 |
} |
276 |
} |
277 |
# endif |
278 |
} |
279 |
#endif |
280 |
|
281 |
if (global_server_params[0].server_s[0].socket != -1) { |
282 |
FD_CLR(global_server_params[0].server_s[0].socket, |
283 |
&global_server_params[0].block_read_fdset); |
284 |
close(global_server_params[0].server_s[0].socket); |
285 |
} |
286 |
|
287 |
if (global_server_params[0].server_s[1].socket != -1) { |
288 |
FD_CLR(global_server_params[0].server_s[1].socket, |
289 |
&global_server_params[0].block_read_fdset); |
290 |
close(global_server_params[0].server_s[1].socket); |
291 |
} |
292 |
|
293 |
SET_PTH_SIGFLAG(sigterm_flag, 2); |
294 |
} |
295 |
|
296 |
|
297 |
void sigterm_stage2_run() |
298 |
{ /* lame duck mode */ |
299 |
int i; |
300 |
|
301 |
log_error_time(); |
302 |
fprintf(stderr, |
303 |
"exiting Hydra normally (uptime %d seconds)\n", |
304 |
(int) (current_time - start_time)); |
305 |
chdir(tempdir); |
306 |
clear_common_env(); |
307 |
dump_mime(); |
308 |
dump_passwd(); |
309 |
dump_virthost(); |
310 |
dump_directory_index(); |
311 |
dump_hic_modules(); |
312 |
|
313 |
for (i = 0; i < global_server_params_size; i++) { |
314 |
free_requests(&global_server_params[i]); |
315 |
} |
316 |
|
317 |
exit(0); |
318 |
} |
319 |
|
320 |
|
321 |
void sighup(int dummy) |
322 |
{ |
323 |
SET_PTH_SIGFLAG(sighup_flag, 1); |
324 |
} |
325 |
|
326 |
void sighup_run() |
327 |
{ |
328 |
int i; |
329 |
|
330 |
SET_PTH_SIGFLAG(sighup_flag, 0); |
331 |
|
332 |
time(¤t_time); |
333 |
log_error_time(); |
334 |
fputs("caught SIGHUP, restarting\n", stderr); |
335 |
|
336 |
#ifdef ENABLE_SMP |
337 |
/* Kill all threads! */ |
338 |
{ |
339 |
int ret; |
340 |
|
341 |
for (i = 1; i < global_server_params_size; i++) { |
342 |
if ((ret = pthread_cancel(global_server_params[i].tid)) != 0) { |
343 |
log_error_time(); |
344 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n", |
345 |
(int) global_server_params[i].tid, ret); |
346 |
exit(1); |
347 |
} |
348 |
} |
349 |
log_error_time(); |
350 |
fputs("Cancelled all the threads in the pool.\n", stderr); |
351 |
|
352 |
# ifdef ENABLE_HIC |
353 |
for (i = 0; i < global_hic_params_size; i++) { |
354 |
if ((ret = pthread_cancel(global_hic_params[i].tid)) != 0) { |
355 |
log_error_time(); |
356 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n", |
357 |
(int) global_hic_params[i].tid, ret); |
358 |
exit(1); |
359 |
} |
360 |
} |
361 |
|
362 |
log_error_time(); |
363 |
fputs("Cancelled all the HIC threads.\n", stderr); |
364 |
# endif |
365 |
|
366 |
} |
367 |
|
368 |
for (i = 0; i < global_server_params_size; i++) { |
369 |
free_requests(&global_server_params[i]); |
370 |
} |
371 |
|
372 |
#endif |
373 |
for (i = 0; i < global_server_params_size; i++) { |
374 |
FD_ZERO(&global_server_params[i].block_read_fdset); |
375 |
FD_ZERO(&global_server_params[i].block_write_fdset); |
376 |
} |
377 |
|
378 |
/* Philosophy change for 0.92: don't close and attempt reopen of logfiles, |
379 |
* since usual permission structure prevents such reopening. |
380 |
*/ |
381 |
|
382 |
/* clear_common_env(); NEVER DO THIS */ |
383 |
dump_mime(); |
384 |
dump_passwd(); |
385 |
dump_virthost(); |
386 |
dump_directory_index(); |
387 |
dump_hic_modules(); |
388 |
|
389 |
log_error_time(); |
390 |
fputs("re-reading configuration files\n", stderr); |
391 |
read_config_files(); |
392 |
|
393 |
/* We now need to dispatch the threads again */ |
394 |
#ifdef ENABLE_HIC |
395 |
hic_init(); |
396 |
#endif |
397 |
smp_reinit(); |
398 |
mmap_reinit(); |
399 |
|
400 |
log_error_time(); |
401 |
fputs("successful restart\n", stderr); |
402 |
|
403 |
} |
404 |
|
405 |
void sigint(int dummy) |
406 |
{ |
407 |
time(¤t_time); |
408 |
log_error_time(); |
409 |
fputs("caught SIGINT: shutting down\n", stderr); |
410 |
fclose(stderr); |
411 |
chdir(tempdir); |
412 |
exit(1); |
413 |
} |
414 |
|
415 |
void sigchld(int dummy) |
416 |
{ |
417 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 1); |
418 |
} |
419 |
|
420 |
void sigchld_run(void) |
421 |
{ |
422 |
int status; |
423 |
pid_t pid; |
424 |
|
425 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 0); |
426 |
|
427 |
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) |
428 |
if (verbose_cgi_logs) { |
429 |
time(¤t_time); |
430 |
log_error_time(); |
431 |
fprintf(stderr, "reaping child %d: status %d\n", (int) pid, |
432 |
status); |
433 |
} |
434 |
return; |
435 |
} |
436 |
|
437 |
void sigalrm(int dummy) |
438 |
{ |
439 |
SET_PTH_SIGFLAG(sigalrm_flag, 1); |
440 |
} |
441 |
|
442 |
void sigusr2(int dummy) |
443 |
{ |
444 |
return; |
445 |
} |
446 |
|
447 |
void sigusr1(int dummy) |
448 |
{ |
449 |
SET_PTH_SIGFLAG(sigusr1_flag, 1); |
450 |
} |
451 |
|
452 |
extern int ssl_params_refresh; |
453 |
extern int boa_ssl; |
454 |
|
455 |
void sigalrm_run(void) |
456 |
{ |
457 |
SET_PTH_SIGFLAG(sigalrm_flag, 0); |
458 |
|
459 |
#ifdef ENABLE_SSL |
460 |
if (boa_ssl) |
461 |
ssl_regenerate_params(); |
462 |
#endif |
463 |
|
464 |
if (boa_ssl && ssl_params_refresh) |
465 |
alarm(ssl_params_refresh); |
466 |
} |
467 |
|
468 |
void sigusr1_run(void) |
469 |
{ |
470 |
int i; |
471 |
|
472 |
SET_PTH_SIGFLAG(sigusr1_flag, 0); |
473 |
|
474 |
time(¤t_time); |
475 |
|
476 |
for (i = 0; i < global_server_params_size; i++) { |
477 |
log_error_time(); |
478 |
fprintf(stderr, "Thread %d: %ld requests, %ld errors\n", |
479 |
i + 1, global_server_params[i].status.requests, |
480 |
global_server_params[i].status.errors); |
481 |
} |
482 |
|
483 |
show_hash_stats(); |
484 |
|
485 |
} |