1 /* $OpenBSD: signal.c,v 1.16 2013/04/29 00:28:23 okan Exp $ */ 2 3 /* 4 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 #ifdef HAVE_CONFIG_H 30 #include "config.h" 31 #endif 32 33 #ifdef WIN32 34 #define WIN32_LEAN_AND_MEAN 35 #include <winsock2.h> 36 #include <windows.h> 37 #undef WIN32_LEAN_AND_MEAN 38 #endif 39 #include <sys/types.h> 40 #ifdef HAVE_SYS_TIME_H 41 #include <sys/time.h> 42 #endif 43 #include <sys/queue.h> 44 #ifdef HAVE_SYS_SOCKET_H 45 #include <sys/socket.h> 46 #endif 47 #include <signal.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #ifdef HAVE_UNISTD_H 52 #include <unistd.h> 53 #endif 54 #include <errno.h> 55 #ifdef HAVE_FCNTL_H 56 #include <fcntl.h> 57 #endif 58 #include <assert.h> 59 60 #include "event.h" 61 #include "event-internal.h" 62 #include "evsignal.h" 63 #include "evutil.h" 64 #include "log.h" 65 66 struct event_base *evsignal_base = NULL; 67 68 static void evsignal_handler(int sig); 69 70 /* Callback for when the signal handler write a byte to our signaling socket */ 71 static void 72 evsignal_cb(int fd, short what, void *arg) 73 { 74 static char signals[1]; 75 #ifdef WIN32 76 SSIZE_T n; 77 #else 78 ssize_t n; 79 #endif 80 81 n = recv(fd, signals, sizeof(signals), 0); 82 if (n == -1) 83 event_err(1, "%s: read", __func__); 84 } 85 86 #ifdef HAVE_SETFD 87 #define FD_CLOSEONEXEC(x) do { \ 88 if (fcntl(x, F_SETFD, FD_CLOEXEC) == -1) \ 89 event_warn("fcntl(%d, F_SETFD)", x); \ 90 } while (0) 91 #else 92 #define FD_CLOSEONEXEC(x) 93 #endif 94 95 int 96 evsignal_init(struct event_base *base) 97 { 98 int i; 99 100 /* 101 * Our signal handler is going to write to one end of the socket 102 * pair to wake up our event loop. The event loop then scans for 103 * signals that got delivered. 104 */ 105 if (evutil_socketpair( 106 AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) { 107 #ifdef WIN32 108 /* Make this nonfatal on win32, where sometimes people 109 have localhost firewalled. */ 110 event_warn("%s: socketpair", __func__); 111 #else 112 event_err(1, "%s: socketpair", __func__); 113 #endif 114 return -1; 115 } 116 117 FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]); 118 FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]); 119 base->sig.sh_old = NULL; 120 base->sig.sh_old_max = 0; 121 base->sig.evsignal_caught = 0; 122 memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG); 123 /* initialize the queues for all events */ 124 for (i = 0; i < NSIG; ++i) 125 TAILQ_INIT(&base->sig.evsigevents[i]); 126 127 evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]); 128 129 event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], 130 EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal); 131 base->sig.ev_signal.ev_base = base; 132 base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL; 133 134 return 0; 135 } 136 137 /* Helper: set the signal handler for evsignal to handler in base, so that 138 * we can restore the original handler when we clear the current one. */ 139 int 140 _evsignal_set_handler(struct event_base *base, 141 int evsignal, void (*handler)(int)) 142 { 143 #ifdef HAVE_SIGACTION 144 struct sigaction sa; 145 #else 146 ev_sighandler_t sh; 147 #endif 148 struct evsignal_info *sig = &base->sig; 149 void *p; 150 151 /* 152 * resize saved signal handler array up to the highest signal number. 153 * a dynamic array is used to keep footprint on the low side. 154 */ 155 if (evsignal >= sig->sh_old_max) { 156 int new_max = evsignal + 1; 157 event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing", 158 __func__, evsignal, sig->sh_old_max)); 159 p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old)); 160 if (p == NULL) { 161 event_warn("realloc"); 162 return (-1); 163 } 164 165 memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old), 166 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old)); 167 168 sig->sh_old_max = new_max; 169 sig->sh_old = p; 170 } 171 172 /* allocate space for previous handler out of dynamic array */ 173 sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]); 174 if (sig->sh_old[evsignal] == NULL) { 175 event_warn("malloc"); 176 return (-1); 177 } 178 179 /* save previous handler and setup new handler */ 180 #ifdef HAVE_SIGACTION 181 memset(&sa, 0, sizeof(sa)); 182 sa.sa_handler = handler; 183 sa.sa_flags |= SA_RESTART; 184 sigfillset(&sa.sa_mask); 185 186 if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) { 187 event_warn("sigaction"); 188 free(sig->sh_old[evsignal]); 189 sig->sh_old[evsignal] = NULL; 190 return (-1); 191 } 192 #else 193 if ((sh = signal(evsignal, handler)) == SIG_ERR) { 194 event_warn("signal"); 195 free(sig->sh_old[evsignal]); 196 sig->sh_old[evsignal] = NULL; 197 return (-1); 198 } 199 *sig->sh_old[evsignal] = sh; 200 #endif 201 202 return (0); 203 } 204 205 int 206 evsignal_add(struct event *ev) 207 { 208 int evsignal; 209 struct event_base *base = ev->ev_base; 210 struct evsignal_info *sig = &ev->ev_base->sig; 211 212 if (ev->ev_events & (EV_READ|EV_WRITE)) 213 event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); 214 evsignal = EVENT_SIGNAL(ev); 215 assert(evsignal >= 0 && evsignal < NSIG); 216 if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) { 217 event_debug(("%s: %p: changing signal handler", __func__, ev)); 218 if (_evsignal_set_handler( 219 base, evsignal, evsignal_handler) == -1) 220 return (-1); 221 222 /* catch signals if they happen quickly */ 223 evsignal_base = base; 224 225 if (!sig->ev_signal_added) { 226 if (event_add(&sig->ev_signal, NULL)) 227 return (-1); 228 sig->ev_signal_added = 1; 229 } 230 } 231 232 /* multiple events may listen to the same signal */ 233 TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next); 234 235 return (0); 236 } 237 238 int 239 _evsignal_restore_handler(struct event_base *base, int evsignal) 240 { 241 int ret = 0; 242 struct evsignal_info *sig = &base->sig; 243 #ifdef HAVE_SIGACTION 244 struct sigaction *sh; 245 #else 246 ev_sighandler_t *sh; 247 #endif 248 249 /* restore previous handler */ 250 sh = sig->sh_old[evsignal]; 251 sig->sh_old[evsignal] = NULL; 252 #ifdef HAVE_SIGACTION 253 if (sigaction(evsignal, sh, NULL) == -1) { 254 event_warn("sigaction"); 255 ret = -1; 256 } 257 #else 258 if (signal(evsignal, *sh) == SIG_ERR) { 259 event_warn("signal"); 260 ret = -1; 261 } 262 #endif 263 free(sh); 264 265 return ret; 266 } 267 268 int 269 evsignal_del(struct event *ev) 270 { 271 struct event_base *base = ev->ev_base; 272 struct evsignal_info *sig = &base->sig; 273 int evsignal = EVENT_SIGNAL(ev); 274 275 assert(evsignal >= 0 && evsignal < NSIG); 276 277 /* multiple events may listen to the same signal */ 278 TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next); 279 280 if (!TAILQ_EMPTY(&sig->evsigevents[evsignal])) 281 return (0); 282 283 event_debug(("%s: %p: restoring signal handler", __func__, ev)); 284 285 return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev))); 286 } 287 288 static void 289 evsignal_handler(int sig) 290 { 291 int save_errno = errno; 292 293 if (evsignal_base == NULL) { 294 event_warn( 295 "%s: received signal %d, but have no base configured", 296 __func__, sig); 297 return; 298 } 299 300 evsignal_base->sig.evsigcaught[sig]++; 301 evsignal_base->sig.evsignal_caught = 1; 302 303 #ifndef HAVE_SIGACTION 304 signal(sig, evsignal_handler); 305 #endif 306 307 /* Wake up our notification mechanism */ 308 send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); 309 errno = save_errno; 310 } 311 312 void 313 evsignal_process(struct event_base *base) 314 { 315 struct evsignal_info *sig = &base->sig; 316 struct event *ev, *next_ev; 317 sig_atomic_t ncalls; 318 int i; 319 320 base->sig.evsignal_caught = 0; 321 for (i = 1; i < NSIG; ++i) { 322 ncalls = sig->evsigcaught[i]; 323 if (ncalls == 0) 324 continue; 325 sig->evsigcaught[i] -= ncalls; 326 327 for (ev = TAILQ_FIRST(&sig->evsigevents[i]); 328 ev != NULL; ev = next_ev) { 329 next_ev = TAILQ_NEXT(ev, ev_signal_next); 330 if (!(ev->ev_events & EV_PERSIST)) 331 event_del(ev); 332 event_active(ev, EV_SIGNAL, ncalls); 333 } 334 335 } 336 } 337 338 void 339 evsignal_dealloc(struct event_base *base) 340 { 341 int i = 0; 342 if (base->sig.ev_signal_added) { 343 event_del(&base->sig.ev_signal); 344 base->sig.ev_signal_added = 0; 345 } 346 for (i = 0; i < NSIG; ++i) { 347 if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL) 348 _evsignal_restore_handler(base, i); 349 } 350 351 if (base->sig.ev_signal_pair[0] != -1) { 352 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]); 353 base->sig.ev_signal_pair[0] = -1; 354 } 355 if (base->sig.ev_signal_pair[1] != -1) { 356 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]); 357 base->sig.ev_signal_pair[1] = -1; 358 } 359 base->sig.sh_old_max = 0; 360 361 /* per index frees are handled in evsignal_del() */ 362 if (base->sig.sh_old) { 363 free(base->sig.sh_old); 364 base->sig.sh_old = NULL; 365 } 366 } 367