1 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ 2 3 /* 4 * Copyright 2000-2002 Niels Provos <provos (at) 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, 1) == -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 return (-1); 190 } 191 #else 192 if ((sh = signal(evsignal, handler)) == SIG_ERR) { 193 event_warn("signal"); 194 free(sig->sh_old[evsignal]); 195 return (-1); 196 } 197 *sig->sh_old[evsignal] = sh; 198 #endif 199 200 return (0); 201 } 202 203 int 204 evsignal_add(struct event *ev) 205 { 206 int evsignal; 207 struct event_base *base = ev->ev_base; 208 struct evsignal_info *sig = &ev->ev_base->sig; 209 210 if (ev->ev_events & (EV_READ|EV_WRITE)) 211 event_errx(1, "%s: EV_SIGNAL incompatible use", __func__); 212 evsignal = EVENT_SIGNAL(ev); 213 assert(evsignal >= 0 && evsignal < NSIG); 214 if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) { 215 event_debug(("%s: %p: changing signal handler", __func__, ev)); 216 if (_evsignal_set_handler( 217 base, evsignal, evsignal_handler) == -1) 218 return (-1); 219 220 /* catch signals if they happen quickly */ 221 evsignal_base = base; 222 223 if (!sig->ev_signal_added) { 224 if (event_add(&sig->ev_signal, NULL)) 225 return (-1); 226 sig->ev_signal_added = 1; 227 } 228 } 229 230 /* multiple events may listen to the same signal */ 231 TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next); 232 233 return (0); 234 } 235 236 int 237 _evsignal_restore_handler(struct event_base *base, int evsignal) 238 { 239 int ret = 0; 240 struct evsignal_info *sig = &base->sig; 241 #ifdef HAVE_SIGACTION 242 struct sigaction *sh; 243 #else 244 ev_sighandler_t *sh; 245 #endif 246 247 /* restore previous handler */ 248 sh = sig->sh_old[evsignal]; 249 sig->sh_old[evsignal] = NULL; 250 #ifdef HAVE_SIGACTION 251 if (sigaction(evsignal, sh, NULL) == -1) { 252 event_warn("sigaction"); 253 ret = -1; 254 } 255 #else 256 if (signal(evsignal, *sh) == SIG_ERR) { 257 event_warn("signal"); 258 ret = -1; 259 } 260 #endif 261 free(sh); 262 263 return ret; 264 } 265 266 int 267 evsignal_del(struct event *ev) 268 { 269 struct event_base *base = ev->ev_base; 270 struct evsignal_info *sig = &base->sig; 271 int evsignal = EVENT_SIGNAL(ev); 272 273 assert(evsignal >= 0 && evsignal < NSIG); 274 275 /* multiple events may listen to the same signal */ 276 TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next); 277 278 if (!TAILQ_EMPTY(&sig->evsigevents[evsignal])) 279 return (0); 280 281 event_debug(("%s: %p: restoring signal handler", __func__, ev)); 282 283 return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev))); 284 } 285 286 static void 287 evsignal_handler(int sig) 288 { 289 int save_errno = errno; 290 291 if (evsignal_base == NULL) { 292 event_warn( 293 "%s: received signal %d, but have no base configured", 294 __func__, sig); 295 return; 296 } 297 298 evsignal_base->sig.evsigcaught[sig]++; 299 evsignal_base->sig.evsignal_caught = 1; 300 301 #ifndef HAVE_SIGACTION 302 signal(sig, evsignal_handler); 303 #endif 304 305 /* Wake up our notification mechanism */ 306 send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0); 307 errno = save_errno; 308 } 309 310 void 311 evsignal_process(struct event_base *base) 312 { 313 struct evsignal_info *sig = &base->sig; 314 struct event *ev, *next_ev; 315 sig_atomic_t ncalls; 316 int i; 317 318 base->sig.evsignal_caught = 0; 319 for (i = 1; i < NSIG; ++i) { 320 ncalls = sig->evsigcaught[i]; 321 if (ncalls == 0) 322 continue; 323 sig->evsigcaught[i] -= ncalls; 324 325 for (ev = TAILQ_FIRST(&sig->evsigevents[i]); 326 ev != NULL; ev = next_ev) { 327 next_ev = TAILQ_NEXT(ev, ev_signal_next); 328 if (!(ev->ev_events & EV_PERSIST)) 329 event_del(ev); 330 event_active(ev, EV_SIGNAL, ncalls); 331 } 332 333 } 334 } 335 336 void 337 evsignal_dealloc(struct event_base *base) 338 { 339 int i = 0; 340 if (base->sig.ev_signal_added) { 341 event_del(&base->sig.ev_signal); 342 base->sig.ev_signal_added = 0; 343 } 344 for (i = 0; i < NSIG; ++i) { 345 if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL) 346 _evsignal_restore_handler(base, i); 347 } 348 349 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]); 350 base->sig.ev_signal_pair[0] = -1; 351 EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]); 352 base->sig.ev_signal_pair[1] = -1; 353 base->sig.sh_old_max = 0; 354 355 /* per index frees are handled in evsignal_del() */ 356 free(base->sig.sh_old); 357 } 358