Coverage Report

Created: 2025-08-29 06:53

/src/opensips/signals.c
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
}