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.25 2006-03-09 18:11:07 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 |
|
47 |
/* |
48 |
* Name: init_signals |
49 |
* Description: Sets up signal handlers for all our friends. |
50 |
*/ |
51 |
|
52 |
void init_signals(void) |
53 |
{ |
54 |
struct sigaction sa; |
55 |
|
56 |
sa.sa_flags = 0; |
57 |
|
58 |
sigemptyset(&sa.sa_mask); |
59 |
sigaddset(&sa.sa_mask, SIGSEGV); |
60 |
sigaddset(&sa.sa_mask, SIGBUS); |
61 |
sigaddset(&sa.sa_mask, SIGTERM); |
62 |
sigaddset(&sa.sa_mask, SIGHUP); |
63 |
sigaddset(&sa.sa_mask, SIGINT); |
64 |
sigaddset(&sa.sa_mask, SIGPIPE); |
65 |
sigaddset(&sa.sa_mask, SIGCHLD); |
66 |
sigaddset(&sa.sa_mask, SIGALRM); |
67 |
sigaddset(&sa.sa_mask, SIGUSR1); |
68 |
sigaddset(&sa.sa_mask, SIGUSR2); |
69 |
|
70 |
sa.sa_handler = sigsegv; |
71 |
sigaction(SIGSEGV, &sa, NULL); |
72 |
|
73 |
sa.sa_handler = sigbus; |
74 |
sigaction(SIGBUS, &sa, NULL); |
75 |
|
76 |
sa.sa_handler = SIG_IGN; |
77 |
sigaction(SIGPIPE, &sa, NULL); |
78 |
|
79 |
sa.sa_handler = sigchld; |
80 |
sigaction(SIGCHLD, &sa, NULL); |
81 |
|
82 |
sa.sa_handler = sigterm; |
83 |
sigaction(SIGTERM, &sa, NULL); |
84 |
|
85 |
sa.sa_handler = sighup; |
86 |
sigaction(SIGHUP, &sa, NULL); |
87 |
|
88 |
sa.sa_handler = sigint; |
89 |
sigaction(SIGINT, &sa, NULL); |
90 |
|
91 |
sa.sa_handler = sigalrm; |
92 |
sigaction(SIGALRM, &sa, NULL); |
93 |
|
94 |
sa.sa_handler = sigusr1; |
95 |
sigaction(SIGUSR1, &sa, NULL); |
96 |
|
97 |
} |
98 |
|
99 |
/* Blocks all signals that should be handled by |
100 |
* the main thread, so that other threads are |
101 |
* not annoyed. |
102 |
*/ |
103 |
void block_main_signals() |
104 |
{ |
105 |
sigset_t sigset; |
106 |
|
107 |
sigemptyset(&sigset); |
108 |
sigaddset(&sigset, SIGALRM); |
109 |
sigaddset(&sigset, SIGUSR1); |
110 |
sigaddset(&sigset, SIGUSR2); |
111 |
sigaddset(&sigset, SIGTERM); |
112 |
sigaddset(&sigset, SIGINT); |
113 |
|
114 |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
115 |
} |
116 |
|
117 |
void unblock_main_signals() |
118 |
{ |
119 |
sigset_t sigset; |
120 |
|
121 |
sigemptyset(&sigset); |
122 |
sigaddset(&sigset, SIGALRM); |
123 |
sigaddset(&sigset, SIGUSR1); |
124 |
sigaddset(&sigset, SIGUSR2); |
125 |
sigaddset(&sigset, SIGTERM); |
126 |
sigaddset(&sigset, SIGHUP); |
127 |
sigaddset(&sigset, SIGINT); |
128 |
|
129 |
sigprocmask(SIG_UNBLOCK, &sigset, NULL); |
130 |
} |
131 |
|
132 |
void block_sigusr2() |
133 |
{ |
134 |
sigset_t sigset; |
135 |
|
136 |
sigemptyset(&sigset); |
137 |
sigaddset(&sigset, SIGUSR2); |
138 |
|
139 |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
140 |
} |
141 |
|
142 |
void unblock_sigusr2() |
143 |
{ |
144 |
sigset_t sigset; |
145 |
|
146 |
sigemptyset(&sigset); |
147 |
sigaddset(&sigset, SIGUSR2); |
148 |
|
149 |
sigprocmask(SIG_UNBLOCK, &sigset, NULL); |
150 |
} |
151 |
|
152 |
|
153 |
void sigsegv(int dummy) |
154 |
{ |
155 |
time(¤t_time); |
156 |
log_error_time(); |
157 |
fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir); |
158 |
fclose(stderr); |
159 |
chdir(tempdir); |
160 |
abort(); |
161 |
} |
162 |
|
163 |
void sigbus(int dummy) |
164 |
{ |
165 |
server_params *params = &global_server_params[0]; |
166 |
|
167 |
/* Note that in multithreaded cases the SIGBUS is catched |
168 |
* by the same thread that did the violation. So the following |
169 |
* code should be ok. |
170 |
*/ |
171 |
|
172 |
#ifdef ENABLE_SMP |
173 |
pthread_t tid = pthread_self(); |
174 |
int i; |
175 |
|
176 |
for (i = 0; i < global_server_params_size; i++) { |
177 |
if (pthread_equal(global_server_params[i].tid, tid)) { |
178 |
params = &global_server_params[i]; |
179 |
break; |
180 |
} |
181 |
} |
182 |
#endif |
183 |
|
184 |
if (params->handle_sigbus) { |
185 |
longjmp(params->env, dummy); |
186 |
} |
187 |
time(¤t_time); |
188 |
log_error_time(); |
189 |
fprintf(stderr, "caught SIGBUS, dumping core in %s\n", tempdir); |
190 |
fclose(stderr); |
191 |
chdir(tempdir); |
192 |
abort(); |
193 |
} |
194 |
|
195 |
#define SET_PTH_SIGFLAG( flag, val) \ |
196 |
global_server_params[0].flag = val |
197 |
|
198 |
#ifdef ENABLE_SMP |
199 |
# define _SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
200 |
{ pthread_t tid = pthread_self(); int i; int set = 0; \ |
201 |
for (i=0;i<global_server_params_size;i++) { \ |
202 |
if ( pthread_equal( global_server_params[i].tid, tid)) { \ |
203 |
global_server_params[i].flag = val; \ |
204 |
set = 1; \ |
205 |
break; \ |
206 |
} \ |
207 |
} |
208 |
|
209 |
# define SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
210 |
_SET_LOCAL_PTH_SIGFLAG( flag, val) } |
211 |
|
212 |
#else |
213 |
# define SET_LOCAL_PTH_SIGFLAG SET_PTH_SIGFLAG |
214 |
#endif |
215 |
|
216 |
void sigterm(int dummy) |
217 |
{ |
218 |
SET_PTH_SIGFLAG(sigterm_flag, 1); |
219 |
} |
220 |
|
221 |
|
222 |
void sigterm_stage1_run() |
223 |
{ /* lame duck mode */ |
224 |
#ifdef ENABLE_SMP |
225 |
int i; |
226 |
#endif |
227 |
|
228 |
time(¤t_time); |
229 |
log_error_time(); |
230 |
fputs("caught SIGTERM, starting shutdown\n", stderr); |
231 |
|
232 |
#ifdef ENABLE_SMP |
233 |
{ |
234 |
int ret; |
235 |
/* remember that the first thread is actual the main process. |
236 |
*/ |
237 |
for (i = 1; i < global_server_params_size; i++) { |
238 |
/* terminate all threads */ |
239 |
if ((ret = pthread_cancel(global_server_params[i].tid)) != 0) { |
240 |
log_error_time(); |
241 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n", |
242 |
(int) global_server_params[i].tid, ret); |
243 |
exit(1); |
244 |
} |
245 |
} |
246 |
} |
247 |
#endif |
248 |
|
249 |
if (global_server_params[0].server_s[0].socket != -1) { |
250 |
close(global_server_params[0].server_s[0].socket); |
251 |
} |
252 |
|
253 |
if (global_server_params[0].server_s[1].socket != -1) { |
254 |
close(global_server_params[0].server_s[1].socket); |
255 |
} |
256 |
|
257 |
SET_PTH_SIGFLAG(sigterm_flag, 2); |
258 |
} |
259 |
|
260 |
|
261 |
void sigterm_stage2_run() |
262 |
{ /* lame duck mode */ |
263 |
int i; |
264 |
|
265 |
log_error_time(); |
266 |
fprintf(stderr, |
267 |
"exiting Hydra normally (uptime %d seconds)\n", |
268 |
(int) (current_time - start_time)); |
269 |
chdir(tempdir); |
270 |
clear_common_env(); |
271 |
dump_mime(); |
272 |
dump_passwd(); |
273 |
dump_virthost(); |
274 |
dump_directory_index(); |
275 |
dump_cgi_action_modules(); |
276 |
|
277 |
for (i = 0; i < global_server_params_size; i++) { |
278 |
free_requests(&global_server_params[i]); |
279 |
} |
280 |
|
281 |
exit(0); |
282 |
} |
283 |
|
284 |
|
285 |
void sighup(int dummy) |
286 |
{ |
287 |
SET_LOCAL_PTH_SIGFLAG(sighup_flag, 1); |
288 |
} |
289 |
|
290 |
void sighup_run() |
291 |
{ |
292 |
int i; |
293 |
|
294 |
/* In sighup case, the father frees all memory, and |
295 |
* the childen terminate. |
296 |
*/ |
297 |
|
298 |
SET_LOCAL_PTH_SIGFLAG(sighup_flag, 0); |
299 |
|
300 |
|
301 |
#ifdef ENABLE_SMP |
302 |
/* Kill all threads! */ |
303 |
if (pthread_self() == father_id) { |
304 |
int ret; |
305 |
|
306 |
time(¤t_time); |
307 |
log_error_time(); |
308 |
fputs("caught SIGHUP, restarting\n", stderr); |
309 |
|
310 |
for (i = 1; i < global_server_params_size; i++) { |
311 |
if ((ret = pthread_kill(global_server_params[i].tid, SIGHUP)) != 0) { |
312 |
log_error_time(); |
313 |
fprintf(stderr, "Could not kill thread: %d. errno = %d.\n", |
314 |
(int) global_server_params[i].tid, ret); |
315 |
} else |
316 |
if ((ret=pthread_join( global_server_params[i].tid, NULL)) != 0) { |
317 |
log_error_time(); |
318 |
fprintf(stderr, "Could not join thread: %d. errno = %d.\n", |
319 |
(int) global_server_params[i].tid, ret); |
320 |
} |
321 |
} |
322 |
log_error_time(); |
323 |
fputs("Terminated all the threads in the pool.\n", stderr); |
324 |
|
325 |
for (i = 0; i < global_server_params_size; i++) { |
326 |
free_requests(&global_server_params[i]); |
327 |
} |
328 |
|
329 |
#endif |
330 |
for (i = 0; i < global_server_params_size; i++) { |
331 |
BOA_FD_ZERO(&global_server_params[i].block_read_fdset); |
332 |
BOA_FD_ZERO(&global_server_params[i].block_write_fdset); |
333 |
} |
334 |
|
335 |
/* Philosophy change for 0.92: don't close and attempt reopen of logfiles, |
336 |
* since usual permission structure prevents such reopening. |
337 |
*/ |
338 |
|
339 |
/* clear_common_env(); NEVER DO THIS */ |
340 |
dump_mime(); |
341 |
dump_passwd(); |
342 |
dump_virthost(); |
343 |
dump_directory_index(); |
344 |
dump_cgi_action_modules(); |
345 |
|
346 |
log_error_time(); |
347 |
fputs("re-reading configuration files\n", stderr); |
348 |
read_config_files(); |
349 |
|
350 |
/* We now need to dispatch the threads again */ |
351 |
smp_reinit(); |
352 |
ssl_reinit(); |
353 |
mmap_reinit(); |
354 |
|
355 |
log_error_time(); |
356 |
fputs("successful restart\n", stderr); |
357 |
|
358 |
#ifdef ENABLE_SMP |
359 |
} else { /* a normal thread -- not father */ |
360 |
pthread_exit(NULL); |
361 |
} |
362 |
#endif |
363 |
|
364 |
} |
365 |
|
366 |
void sigint(int dummy) |
367 |
{ |
368 |
time(¤t_time); |
369 |
log_error_time(); |
370 |
fputs("caught SIGINT: shutting down\n", stderr); |
371 |
fclose(stderr); |
372 |
chdir(tempdir); |
373 |
exit(1); |
374 |
} |
375 |
|
376 |
void sigchld(int dummy) |
377 |
{ |
378 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 1); |
379 |
} |
380 |
|
381 |
void sigchld_run(void) |
382 |
{ |
383 |
int status; |
384 |
pid_t pid; |
385 |
|
386 |
SET_LOCAL_PTH_SIGFLAG(sigchld_flag, 0); |
387 |
|
388 |
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) |
389 |
if (verbose_cgi_logs) { |
390 |
time(¤t_time); |
391 |
log_error_time(); |
392 |
fprintf(stderr, "reaping child %d: status %d\n", (int) pid, |
393 |
status); |
394 |
} |
395 |
return; |
396 |
} |
397 |
|
398 |
void sigalrm(int dummy) |
399 |
{ |
400 |
SET_PTH_SIGFLAG(sigalrm_flag, 1); |
401 |
} |
402 |
|
403 |
void sigusr2(int dummy) |
404 |
{ |
405 |
return; |
406 |
} |
407 |
|
408 |
void sigusr1(int dummy) |
409 |
{ |
410 |
SET_PTH_SIGFLAG(sigusr1_flag, 1); |
411 |
} |
412 |
|
413 |
#ifdef ENABLE_SMP |
414 |
extern pthread_mutex_t mmap_lock; |
415 |
#endif |
416 |
|
417 |
void sigalrm_run(void) |
418 |
{ |
419 |
SET_PTH_SIGFLAG(sigalrm_flag, 0); |
420 |
|
421 |
#ifdef ENABLE_SSL |
422 |
if (boa_ssl) |
423 |
ssl_regenerate_params(); |
424 |
#endif |
425 |
|
426 |
log_error_time(); |
427 |
fprintf(stderr, "Cleaning up file caches.\n"); |
428 |
#ifdef ENABLE_SMP |
429 |
pthread_mutex_lock(&mmap_lock); |
430 |
#endif |
431 |
/* Clear all unused entries in the mmap list */ |
432 |
cleanup_mmap_list(1); |
433 |
#ifdef ENABLE_SMP |
434 |
pthread_mutex_unlock(&mmap_lock); |
435 |
#endif |
436 |
|
437 |
if (maintenance_interval) |
438 |
alarm(maintenance_interval); |
439 |
|
440 |
} |
441 |
|
442 |
void sigusr1_run(void) |
443 |
{ |
444 |
int i; |
445 |
|
446 |
SET_PTH_SIGFLAG(sigusr1_flag, 0); |
447 |
|
448 |
time(¤t_time); |
449 |
|
450 |
for (i = 0; i < global_server_params_size; i++) { |
451 |
log_error_time(); |
452 |
fprintf(stderr, "Thread %d: %ld requests, %ld errors\n", |
453 |
i + 1, global_server_params[i].status.requests, |
454 |
global_server_params[i].status.errors); |
455 |
} |
456 |
|
457 |
/* Only print the running connections if we have set a connection |
458 |
* limit. That is because we do not count connections when we |
459 |
* have no connection limits. |
460 |
*/ |
461 |
if (max_connections != INT_MAX) { |
462 |
log_error_time(); |
463 |
fprintf(stderr, "Running connections: %ld\n", |
464 |
get_total_global_connections(0)); |
465 |
} |
466 |
|
467 |
#ifdef ENABLE_SSL |
468 |
if ( max_ssl_connections != INT_MAX) { |
469 |
log_error_time(); |
470 |
fprintf(stderr, "Running SSL connections: %ld\n", |
471 |
get_total_global_connections(1)); |
472 |
} |
473 |
#endif |
474 |
|
475 |
show_hash_stats(); |
476 |
|
477 |
} |