Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * Copyright (C) 2005-2006 Voice Sistem S.R.L |
4 | | * |
5 | | * This file is part of opensips, a free SIP server. |
6 | | * |
7 | | * opensips is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version |
11 | | * |
12 | | * opensips is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | * |
21 | | */ |
22 | | |
23 | | #include <sys/types.h> |
24 | | #include <sys/wait.h> |
25 | | #include <signal.h> |
26 | | |
27 | | #include "dprint.h" |
28 | | #include "daemonize.h" |
29 | | #include "pt.h" |
30 | | #include "status_report.h" |
31 | | #include "shutdown.h" |
32 | | #include "signals.h" |
33 | | |
34 | | /* last signal received */ |
35 | | static int sig_flag = 0; |
36 | | |
37 | | /* the initial SIGSEGV handler, provided by the OS */ |
38 | | static struct sigaction sa_sys_segv; |
39 | | static char sa_sys_is_valid; |
40 | | |
41 | | /** |
42 | | * Signal handler for the server. |
43 | | */ |
44 | | void handle_sigs(void) |
45 | 0 | { |
46 | 0 | pid_t chld; |
47 | 0 | int chld_status,overall_status=0; |
48 | 0 | int i; |
49 | 0 | int do_exit; |
50 | |
|
51 | 0 | switch(sig_flag){ |
52 | 0 | case 0: break; /* do nothing*/ |
53 | 0 | case SIGPIPE: |
54 | | /* SIGPIPE might be rarely received on use of |
55 | | exec module; simply ignore it |
56 | | */ |
57 | 0 | case SIGUSR1: |
58 | 0 | case SIGUSR2: |
59 | 0 | case SIGHUP: |
60 | | /* ignoring it*/ |
61 | 0 | break; |
62 | 0 | case SIGINT: |
63 | 0 | case SIGTERM: |
64 | | /* we end the program in all these cases */ |
65 | 0 | if (sig_flag==SIGINT) |
66 | 0 | LM_DBG("SIGINT received, program terminates\n"); |
67 | 0 | else |
68 | 0 | LM_DBG("SIGTERM received, program terminates\n"); |
69 | |
|
70 | 0 | shutdown_opensips( 0/*status*/ ); |
71 | 0 | break; |
72 | | |
73 | 0 | case SIGCHLD: |
74 | 0 | do_exit = 0; |
75 | 0 | while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) { |
76 | | /* is it a process we know about? */ |
77 | 0 | if ( (i=get_process_ID_by_PID( chld )) == -1 ) { |
78 | 0 | LM_DBG("unknown child process %d ended. Ignoring\n",chld); |
79 | 0 | continue; |
80 | 0 | } |
81 | 0 | if (pt[i].flags & OSS_PROC_SELFEXIT) { |
82 | 0 | LM_NOTICE("process %d/%d did selfexit with " |
83 | 0 | "status %d\n", i, chld, WTERMSIG(chld_status)); |
84 | 0 | reset_process_slot(i); |
85 | 0 | continue; |
86 | 0 | } |
87 | 0 | do_exit = 1; |
88 | | /* process the signal */ |
89 | 0 | overall_status |= chld_status; |
90 | 0 | LM_DBG("OpenSIPS exit status = %d\n",overall_status); |
91 | |
|
92 | 0 | if (WIFEXITED(chld_status)) |
93 | 0 | LM_INFO("child process %d exited normally," |
94 | 0 | " status=%d\n", chld, |
95 | 0 | WEXITSTATUS(chld_status)); |
96 | 0 | else if (WIFSIGNALED(chld_status)) { |
97 | 0 | LM_INFO("child process %d exited by a signal" |
98 | 0 | " %d\n", chld, WTERMSIG(chld_status)); |
99 | 0 | #ifdef WCOREDUMP |
100 | 0 | LM_INFO("core was %sgenerated\n", |
101 | 0 | WCOREDUMP(chld_status) ? "" : "not " ); |
102 | 0 | #endif |
103 | 0 | }else if (WIFSTOPPED(chld_status)) |
104 | 0 | LM_INFO("child process %d stopped by a" |
105 | 0 | " signal %d\n", chld, |
106 | 0 | WSTOPSIG(chld_status)); |
107 | | |
108 | | /* mark the child process as terminated / not running */ |
109 | 0 | pt[i].pid = -1; |
110 | 0 | } |
111 | 0 | if (!do_exit) |
112 | 0 | break; |
113 | 0 | LM_INFO("terminating due to SIGCHLD\n"); |
114 | | /* exit */ |
115 | 0 | shutdown_opensips( overall_status ); |
116 | 0 | break; |
117 | | |
118 | 0 | default: |
119 | 0 | LM_CRIT("unhandled signal %d\n", sig_flag); |
120 | 0 | } |
121 | 0 | sig_flag=0; |
122 | 0 | } |
123 | | |
124 | | static inline int restore_segv_handler(void) |
125 | 0 | { |
126 | 0 | LM_DBG("restoring SIGSEGV handler...\n"); |
127 | |
|
128 | 0 | if (!sa_sys_is_valid) |
129 | 0 | return 1; |
130 | | |
131 | 0 | if (sigaction(SIGSEGV, &sa_sys_segv, NULL) < 0) { |
132 | 0 | LM_ERR("failed to restore system SIGSEGV handler\n"); |
133 | 0 | return -1; |
134 | 0 | } |
135 | | |
136 | 0 | LM_DBG("successfully restored system SIGSEGV handler\n"); |
137 | |
|
138 | 0 | return 0; |
139 | 0 | } |
140 | | |
141 | | |
142 | | /** |
143 | | * Exit regulary on a specific signal. |
144 | | * This is good for profiling which only works if exited regularly |
145 | | * and not by default signal handlers |
146 | | * \param signo The signal that should be handled |
147 | | */ |
148 | | static void sig_usr(int signo) |
149 | 0 | { |
150 | 0 | int status; |
151 | 0 | pid_t pid; |
152 | 0 | UNUSED(pid); |
153 | |
|
154 | 0 | if (is_main){ |
155 | 0 | if (signo == SIGSEGV) { |
156 | 0 | LM_CRIT("segfault in attendant (starter) process!\n"); |
157 | 0 | if (restore_segv_handler() != 0) |
158 | 0 | exit(-1); |
159 | 0 | return; |
160 | 0 | } |
161 | | |
162 | 0 | if (sig_flag == 0) |
163 | 0 | sig_flag = signo; |
164 | 0 | else /* previous sig. not processed yet, ignoring? */ |
165 | 0 | return; |
166 | 0 | }else{ |
167 | | /* process the important signals */ |
168 | 0 | switch(signo){ |
169 | 0 | case SIGPIPE: |
170 | 0 | case SIGINT: |
171 | 0 | case SIGUSR1: |
172 | 0 | case SIGUSR2: |
173 | 0 | case SIGHUP: |
174 | | /* ignored*/ |
175 | 0 | break; |
176 | 0 | case SIGTERM: |
177 | | /* ignore any SIGTERM if not in shutdown sequance (this |
178 | | * is marked by the attendent process) */ |
179 | 0 | if (sr_get_core_status()!=STATE_TERMINATING) |
180 | 0 | return; |
181 | | /* if some shutdown already in progress, ignore this one */ |
182 | 0 | if (sig_flag==0) sig_flag=signo; |
183 | 0 | else return; |
184 | | /* do the termination */ |
185 | 0 | LM_INFO("signal %d received\n", signo); |
186 | | /* print memory stats for non-main too */ |
187 | | #ifdef PKG_MALLOC |
188 | | LM_GEN1(memdump, "Memory status (pkg):\n"); |
189 | | pkg_status(); |
190 | | #endif |
191 | 0 | exit(0); |
192 | 0 | break; |
193 | 0 | case SIGCHLD: |
194 | 0 | while ( (pid = waitpid(-1, &status, WNOHANG))>0 ); |
195 | 0 | break; |
196 | 0 | case SIGSEGV: |
197 | | /* looks like we ate some spicy SIP */ |
198 | 0 | LM_CRIT("segfault in process pid: %d, id: %d\n", |
199 | 0 | pt[process_no].pid, process_no); |
200 | 0 | pt[process_no].flags |= OSS_PROC_DOING_DUMP; |
201 | 0 | if (restore_segv_handler() != 0) |
202 | 0 | exit(-1); |
203 | 0 | pkg_status(); |
204 | 0 | } |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | |
209 | | /** |
210 | | * Install the signal handlers. |
211 | | * \return 0 on success, -1 on error |
212 | | */ |
213 | | int install_sigs(void) |
214 | 0 | { |
215 | 0 | struct sigaction act; |
216 | |
|
217 | 0 | memset(&act, 0, sizeof act); |
218 | |
|
219 | 0 | act.sa_handler = sig_usr; |
220 | 0 | if (sigaction(SIGSEGV, &act, &sa_sys_segv) < 0) { |
221 | 0 | LM_INFO("failed to install custom SIGSEGV handler -- corefiles must " |
222 | 0 | "now be written within %d sec to avoid truncation!\n", |
223 | 0 | GRACEFUL_SHUTDOWN_TIMEOUT); |
224 | 0 | } else { |
225 | 0 | LM_DBG("override SIGSEGV handler: success\n"); |
226 | 0 | sa_sys_is_valid = 1; |
227 | 0 | } |
228 | |
|
229 | 0 | if (signal(SIGINT, sig_usr) == SIG_ERR ) { |
230 | 0 | LM_ERR("no SIGINT signal handler can be installed\n"); |
231 | 0 | goto error; |
232 | 0 | } |
233 | | /* if we debug and write to a pipe, we want to exit nicely too */ |
234 | 0 | if (signal(SIGPIPE, sig_usr) == SIG_ERR ) { |
235 | 0 | LM_ERR("no SIGINT signal handler can be installed\n"); |
236 | 0 | goto error; |
237 | 0 | } |
238 | | |
239 | 0 | if (signal(SIGUSR1, sig_usr) == SIG_ERR ) { |
240 | 0 | LM_ERR("no SIGUSR1 signal handler can be installed\n"); |
241 | 0 | goto error; |
242 | 0 | } |
243 | 0 | if (signal(SIGCHLD , sig_usr) == SIG_ERR ) { |
244 | 0 | LM_ERR("no SIGCHLD signal handler can be installed\n"); |
245 | 0 | goto error; |
246 | 0 | } |
247 | 0 | if (signal(SIGTERM , sig_usr) == SIG_ERR ) { |
248 | 0 | LM_ERR("no SIGTERM signal handler can be installed\n"); |
249 | 0 | goto error; |
250 | 0 | } |
251 | 0 | if (signal(SIGHUP , sig_usr) == SIG_ERR ) { |
252 | 0 | LM_ERR("no SIGHUP signal handler can be installed\n"); |
253 | 0 | goto error; |
254 | 0 | } |
255 | 0 | if (signal(SIGUSR2 , sig_usr) == SIG_ERR ) { |
256 | 0 | LM_ERR("no SIGUSR2 signal handler can be installed\n"); |
257 | 0 | goto error; |
258 | 0 | } |
259 | 0 | return 0; |
260 | 0 | error: |
261 | 0 | return -1; |
262 | 0 | } |