1275970Scy/*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
2275970Scy
3275970Scy/*
4275970Scy * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
5275970Scy * Copyright 2007-2012 Niels Provos and Nick Mathewson
6275970Scy *
7275970Scy * Redistribution and use in source and binary forms, with or without
8275970Scy * modification, are permitted provided that the following conditions
9275970Scy * are met:
10275970Scy * 1. Redistributions of source code must retain the above copyright
11275970Scy *    notice, this list of conditions and the following disclaimer.
12275970Scy * 2. Redistributions in binary form must reproduce the above copyright
13275970Scy *    notice, this list of conditions and the following disclaimer in the
14275970Scy *    documentation and/or other materials provided with the distribution.
15275970Scy * 3. The name of the author may not be used to endorse or promote products
16275970Scy *    derived from this software without specific prior written permission.
17275970Scy *
18275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28275970Scy */
29275970Scy#include "event2/event-config.h"
30275970Scy#include "evconfig-private.h"
31275970Scy
32275970Scy#ifdef _WIN32
33275970Scy#define WIN32_LEAN_AND_MEAN
34275970Scy#include <winsock2.h>
35275970Scy#include <windows.h>
36275970Scy#undef WIN32_LEAN_AND_MEAN
37275970Scy#endif
38275970Scy#include <sys/types.h>
39275970Scy#ifdef EVENT__HAVE_SYS_TIME_H
40275970Scy#include <sys/time.h>
41275970Scy#endif
42275970Scy#include <sys/queue.h>
43275970Scy#ifdef EVENT__HAVE_SYS_SOCKET_H
44275970Scy#include <sys/socket.h>
45275970Scy#endif
46275970Scy#include <signal.h>
47275970Scy#include <stdio.h>
48275970Scy#include <stdlib.h>
49275970Scy#include <string.h>
50275970Scy#ifdef EVENT__HAVE_UNISTD_H
51275970Scy#include <unistd.h>
52275970Scy#endif
53275970Scy#include <errno.h>
54275970Scy#ifdef EVENT__HAVE_FCNTL_H
55275970Scy#include <fcntl.h>
56275970Scy#endif
57275970Scy
58275970Scy#include "event2/event.h"
59275970Scy#include "event2/event_struct.h"
60275970Scy#include "event-internal.h"
61275970Scy#include "event2/util.h"
62275970Scy#include "evsignal-internal.h"
63275970Scy#include "log-internal.h"
64275970Scy#include "evmap-internal.h"
65275970Scy#include "evthread-internal.h"
66275970Scy
67275970Scy/*
68275970Scy  signal.c
69275970Scy
70275970Scy  This is the signal-handling implementation we use for backends that don't
71275970Scy  have a better way to do signal handling.  It uses sigaction() or signal()
72275970Scy  to set a signal handler, and a socket pair to tell the event base when
73275970Scy
74275970Scy  Note that I said "the event base" : only one event base can be set up to use
75275970Scy  this at a time.  For historical reasons and backward compatibility, if you
76275970Scy  add an event for a signal to event_base A, then add an event for a signal
77275970Scy  (any signal!) to event_base B, event_base B will get informed about the
78275970Scy  signal, but event_base A won't.
79275970Scy
80275970Scy  It would be neat to change this behavior in some future version of Libevent.
81275970Scy  kqueue already does something far more sensible.  We can make all backends
82275970Scy  on Linux do a reasonable thing using signalfd.
83275970Scy*/
84275970Scy
85275970Scy#ifndef _WIN32
86275970Scy/* Windows wants us to call our signal handlers as __cdecl.  Nobody else
87275970Scy * expects you to do anything crazy like this. */
88275970Scy#define __cdecl
89275970Scy#endif
90275970Scy
91275970Scystatic int evsig_add(struct event_base *, evutil_socket_t, short, short, void *);
92275970Scystatic int evsig_del(struct event_base *, evutil_socket_t, short, short, void *);
93275970Scy
94275970Scystatic const struct eventop evsigops = {
95275970Scy	"signal",
96275970Scy	NULL,
97275970Scy	evsig_add,
98275970Scy	evsig_del,
99275970Scy	NULL,
100275970Scy	NULL,
101275970Scy	0, 0, 0
102275970Scy};
103275970Scy
104275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT
105275970Scy/* Lock for evsig_base and evsig_base_n_signals_added fields. */
106275970Scystatic void *evsig_base_lock = NULL;
107275970Scy#endif
108275970Scy/* The event base that's currently getting informed about signals. */
109275970Scystatic struct event_base *evsig_base = NULL;
110275970Scy/* A copy of evsig_base->sigev_n_signals_added. */
111275970Scystatic int evsig_base_n_signals_added = 0;
112275970Scystatic evutil_socket_t evsig_base_fd = -1;
113275970Scy
114275970Scystatic void __cdecl evsig_handler(int sig);
115275970Scy
116275970Scy#define EVSIGBASE_LOCK() EVLOCK_LOCK(evsig_base_lock, 0)
117275970Scy#define EVSIGBASE_UNLOCK() EVLOCK_UNLOCK(evsig_base_lock, 0)
118275970Scy
119275970Scyvoid
120275970Scyevsig_set_base_(struct event_base *base)
121275970Scy{
122275970Scy	EVSIGBASE_LOCK();
123275970Scy	evsig_base = base;
124275970Scy	evsig_base_n_signals_added = base->sig.ev_n_signals_added;
125275970Scy	evsig_base_fd = base->sig.ev_signal_pair[1];
126275970Scy	EVSIGBASE_UNLOCK();
127275970Scy}
128275970Scy
129275970Scy/* Callback for when the signal handler write a byte to our signaling socket */
130275970Scystatic void
131275970Scyevsig_cb(evutil_socket_t fd, short what, void *arg)
132275970Scy{
133275970Scy	static char signals[1024];
134275970Scy	ev_ssize_t n;
135275970Scy	int i;
136275970Scy	int ncaught[NSIG];
137275970Scy	struct event_base *base;
138275970Scy
139275970Scy	base = arg;
140275970Scy
141275970Scy	memset(&ncaught, 0, sizeof(ncaught));
142275970Scy
143275970Scy	while (1) {
144275970Scy#ifdef _WIN32
145275970Scy		n = recv(fd, signals, sizeof(signals), 0);
146275970Scy#else
147275970Scy		n = read(fd, signals, sizeof(signals));
148275970Scy#endif
149275970Scy		if (n == -1) {
150275970Scy			int err = evutil_socket_geterror(fd);
151275970Scy			if (! EVUTIL_ERR_RW_RETRIABLE(err))
152275970Scy				event_sock_err(1, fd, "%s: recv", __func__);
153275970Scy			break;
154275970Scy		} else if (n == 0) {
155275970Scy			/* XXX warn? */
156275970Scy			break;
157275970Scy		}
158275970Scy		for (i = 0; i < n; ++i) {
159275970Scy			ev_uint8_t sig = signals[i];
160275970Scy			if (sig < NSIG)
161275970Scy				ncaught[sig]++;
162275970Scy		}
163275970Scy	}
164275970Scy
165275970Scy	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
166275970Scy	for (i = 0; i < NSIG; ++i) {
167275970Scy		if (ncaught[i])
168275970Scy			evmap_signal_active_(base, i, ncaught[i]);
169275970Scy	}
170275970Scy	EVBASE_RELEASE_LOCK(base, th_base_lock);
171275970Scy}
172275970Scy
173275970Scyint
174275970Scyevsig_init_(struct event_base *base)
175275970Scy{
176275970Scy	/*
177275970Scy	 * Our signal handler is going to write to one end of the socket
178275970Scy	 * pair to wake up our event loop.  The event loop then scans for
179275970Scy	 * signals that got delivered.
180275970Scy	 */
181275970Scy	if (evutil_make_internal_pipe_(base->sig.ev_signal_pair) == -1) {
182275970Scy#ifdef _WIN32
183275970Scy		/* Make this nonfatal on win32, where sometimes people
184275970Scy		   have localhost firewalled. */
185275970Scy		event_sock_warn(-1, "%s: socketpair", __func__);
186275970Scy#else
187275970Scy		event_sock_err(1, -1, "%s: socketpair", __func__);
188275970Scy#endif
189275970Scy		return -1;
190275970Scy	}
191275970Scy
192275970Scy	if (base->sig.sh_old) {
193275970Scy		mm_free(base->sig.sh_old);
194275970Scy	}
195275970Scy	base->sig.sh_old = NULL;
196275970Scy	base->sig.sh_old_max = 0;
197275970Scy
198275970Scy	event_assign(&base->sig.ev_signal, base, base->sig.ev_signal_pair[0],
199275970Scy		EV_READ | EV_PERSIST, evsig_cb, base);
200275970Scy
201275970Scy	base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
202275970Scy	event_priority_set(&base->sig.ev_signal, 0);
203275970Scy
204275970Scy	base->evsigsel = &evsigops;
205275970Scy
206275970Scy	return 0;
207275970Scy}
208275970Scy
209275970Scy/* Helper: set the signal handler for evsignal to handler in base, so that
210275970Scy * we can restore the original handler when we clear the current one. */
211275970Scyint
212275970Scyevsig_set_handler_(struct event_base *base,
213275970Scy    int evsignal, void (__cdecl *handler)(int))
214275970Scy{
215275970Scy#ifdef EVENT__HAVE_SIGACTION
216275970Scy	struct sigaction sa;
217275970Scy#else
218275970Scy	ev_sighandler_t sh;
219275970Scy#endif
220275970Scy	struct evsig_info *sig = &base->sig;
221275970Scy	void *p;
222275970Scy
223275970Scy	/*
224275970Scy	 * resize saved signal handler array up to the highest signal number.
225275970Scy	 * a dynamic array is used to keep footprint on the low side.
226275970Scy	 */
227275970Scy	if (evsignal >= sig->sh_old_max) {
228275970Scy		int new_max = evsignal + 1;
229275970Scy		event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
230275970Scy			    __func__, evsignal, sig->sh_old_max));
231275970Scy		p = mm_realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
232275970Scy		if (p == NULL) {
233275970Scy			event_warn("realloc");
234275970Scy			return (-1);
235275970Scy		}
236275970Scy
237275970Scy		memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
238275970Scy		    0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
239275970Scy
240275970Scy		sig->sh_old_max = new_max;
241275970Scy		sig->sh_old = p;
242275970Scy	}
243275970Scy
244275970Scy	/* allocate space for previous handler out of dynamic array */
245275970Scy	sig->sh_old[evsignal] = mm_malloc(sizeof *sig->sh_old[evsignal]);
246275970Scy	if (sig->sh_old[evsignal] == NULL) {
247275970Scy		event_warn("malloc");
248275970Scy		return (-1);
249275970Scy	}
250275970Scy
251275970Scy	/* save previous handler and setup new handler */
252275970Scy#ifdef EVENT__HAVE_SIGACTION
253275970Scy	memset(&sa, 0, sizeof(sa));
254275970Scy	sa.sa_handler = handler;
255275970Scy	sa.sa_flags |= SA_RESTART;
256275970Scy	sigfillset(&sa.sa_mask);
257275970Scy
258275970Scy	if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
259275970Scy		event_warn("sigaction");
260275970Scy		mm_free(sig->sh_old[evsignal]);
261275970Scy		sig->sh_old[evsignal] = NULL;
262275970Scy		return (-1);
263275970Scy	}
264275970Scy#else
265275970Scy	if ((sh = signal(evsignal, handler)) == SIG_ERR) {
266275970Scy		event_warn("signal");
267275970Scy		mm_free(sig->sh_old[evsignal]);
268275970Scy		sig->sh_old[evsignal] = NULL;
269275970Scy		return (-1);
270275970Scy	}
271275970Scy	*sig->sh_old[evsignal] = sh;
272275970Scy#endif
273275970Scy
274275970Scy	return (0);
275275970Scy}
276275970Scy
277275970Scystatic int
278275970Scyevsig_add(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
279275970Scy{
280275970Scy	struct evsig_info *sig = &base->sig;
281275970Scy	(void)p;
282275970Scy
283275970Scy	EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
284275970Scy
285275970Scy	/* catch signals if they happen quickly */
286275970Scy	EVSIGBASE_LOCK();
287275970Scy	if (evsig_base != base && evsig_base_n_signals_added) {
288275970Scy		event_warnx("Added a signal to event base %p with signals "
289275970Scy		    "already added to event_base %p.  Only one can have "
290275970Scy		    "signals at a time with the %s backend.  The base with "
291275970Scy		    "the most recently added signal or the most recent "
292275970Scy		    "event_base_loop() call gets preference; do "
293275970Scy		    "not rely on this behavior in future Libevent versions.",
294275970Scy		    base, evsig_base, base->evsel->name);
295275970Scy	}
296275970Scy	evsig_base = base;
297275970Scy	evsig_base_n_signals_added = ++sig->ev_n_signals_added;
298275970Scy	evsig_base_fd = base->sig.ev_signal_pair[1];
299275970Scy	EVSIGBASE_UNLOCK();
300275970Scy
301275970Scy	event_debug(("%s: %d: changing signal handler", __func__, (int)evsignal));
302275970Scy	if (evsig_set_handler_(base, (int)evsignal, evsig_handler) == -1) {
303275970Scy		goto err;
304275970Scy	}
305275970Scy
306275970Scy
307275970Scy	if (!sig->ev_signal_added) {
308275970Scy		if (event_add_nolock_(&sig->ev_signal, NULL, 0))
309275970Scy			goto err;
310275970Scy		sig->ev_signal_added = 1;
311275970Scy	}
312275970Scy
313275970Scy	return (0);
314275970Scy
315275970Scyerr:
316275970Scy	EVSIGBASE_LOCK();
317275970Scy	--evsig_base_n_signals_added;
318275970Scy	--sig->ev_n_signals_added;
319275970Scy	EVSIGBASE_UNLOCK();
320275970Scy	return (-1);
321275970Scy}
322275970Scy
323275970Scyint
324275970Scyevsig_restore_handler_(struct event_base *base, int evsignal)
325275970Scy{
326275970Scy	int ret = 0;
327275970Scy	struct evsig_info *sig = &base->sig;
328275970Scy#ifdef EVENT__HAVE_SIGACTION
329275970Scy	struct sigaction *sh;
330275970Scy#else
331275970Scy	ev_sighandler_t *sh;
332275970Scy#endif
333275970Scy
334275970Scy	if (evsignal >= sig->sh_old_max) {
335275970Scy		/* Can't actually restore. */
336275970Scy		/* XXXX.*/
337275970Scy		return 0;
338275970Scy	}
339275970Scy
340275970Scy	/* restore previous handler */
341275970Scy	sh = sig->sh_old[evsignal];
342275970Scy	sig->sh_old[evsignal] = NULL;
343275970Scy#ifdef EVENT__HAVE_SIGACTION
344275970Scy	if (sigaction(evsignal, sh, NULL) == -1) {
345275970Scy		event_warn("sigaction");
346275970Scy		ret = -1;
347275970Scy	}
348275970Scy#else
349275970Scy	if (signal(evsignal, *sh) == SIG_ERR) {
350275970Scy		event_warn("signal");
351275970Scy		ret = -1;
352275970Scy	}
353275970Scy#endif
354275970Scy
355275970Scy	mm_free(sh);
356275970Scy
357275970Scy	return ret;
358275970Scy}
359275970Scy
360275970Scystatic int
361275970Scyevsig_del(struct event_base *base, evutil_socket_t evsignal, short old, short events, void *p)
362275970Scy{
363275970Scy	EVUTIL_ASSERT(evsignal >= 0 && evsignal < NSIG);
364275970Scy
365275970Scy	event_debug(("%s: "EV_SOCK_FMT": restoring signal handler",
366275970Scy		__func__, EV_SOCK_ARG(evsignal)));
367275970Scy
368275970Scy	EVSIGBASE_LOCK();
369275970Scy	--evsig_base_n_signals_added;
370275970Scy	--base->sig.ev_n_signals_added;
371275970Scy	EVSIGBASE_UNLOCK();
372275970Scy
373275970Scy	return (evsig_restore_handler_(base, (int)evsignal));
374275970Scy}
375275970Scy
376275970Scystatic void __cdecl
377275970Scyevsig_handler(int sig)
378275970Scy{
379275970Scy	int save_errno = errno;
380275970Scy#ifdef _WIN32
381275970Scy	int socket_errno = EVUTIL_SOCKET_ERROR();
382275970Scy#endif
383275970Scy	ev_uint8_t msg;
384275970Scy
385275970Scy	if (evsig_base == NULL) {
386275970Scy		event_warnx(
387275970Scy			"%s: received signal %d, but have no base configured",
388275970Scy			__func__, sig);
389275970Scy		return;
390275970Scy	}
391275970Scy
392275970Scy#ifndef EVENT__HAVE_SIGACTION
393275970Scy	signal(sig, evsig_handler);
394275970Scy#endif
395275970Scy
396275970Scy	/* Wake up our notification mechanism */
397275970Scy	msg = sig;
398275970Scy#ifdef _WIN32
399275970Scy	send(evsig_base_fd, (char*)&msg, 1, 0);
400275970Scy#else
401275970Scy	{
402275970Scy		int r = write(evsig_base_fd, (char*)&msg, 1);
403275970Scy		(void)r; /* Suppress 'unused return value' and 'unused var' */
404275970Scy	}
405275970Scy#endif
406275970Scy	errno = save_errno;
407275970Scy#ifdef _WIN32
408275970Scy	EVUTIL_SET_SOCKET_ERROR(socket_errno);
409275970Scy#endif
410275970Scy}
411275970Scy
412275970Scyvoid
413275970Scyevsig_dealloc_(struct event_base *base)
414275970Scy{
415275970Scy	int i = 0;
416275970Scy	if (base->sig.ev_signal_added) {
417275970Scy		event_del(&base->sig.ev_signal);
418275970Scy		base->sig.ev_signal_added = 0;
419275970Scy	}
420275970Scy	/* debug event is created in evsig_init_/event_assign even when
421275970Scy	 * ev_signal_added == 0, so unassign is required */
422275970Scy	event_debug_unassign(&base->sig.ev_signal);
423275970Scy
424275970Scy	for (i = 0; i < NSIG; ++i) {
425275970Scy		if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
426275970Scy			evsig_restore_handler_(base, i);
427275970Scy	}
428275970Scy	EVSIGBASE_LOCK();
429275970Scy	if (base == evsig_base) {
430275970Scy		evsig_base = NULL;
431275970Scy		evsig_base_n_signals_added = 0;
432275970Scy		evsig_base_fd = -1;
433275970Scy	}
434275970Scy	EVSIGBASE_UNLOCK();
435275970Scy
436275970Scy	if (base->sig.ev_signal_pair[0] != -1) {
437275970Scy		evutil_closesocket(base->sig.ev_signal_pair[0]);
438275970Scy		base->sig.ev_signal_pair[0] = -1;
439275970Scy	}
440275970Scy	if (base->sig.ev_signal_pair[1] != -1) {
441275970Scy		evutil_closesocket(base->sig.ev_signal_pair[1]);
442275970Scy		base->sig.ev_signal_pair[1] = -1;
443275970Scy	}
444275970Scy	base->sig.sh_old_max = 0;
445275970Scy
446275970Scy	/* per index frees are handled in evsig_del() */
447275970Scy	if (base->sig.sh_old) {
448275970Scy		mm_free(base->sig.sh_old);
449275970Scy		base->sig.sh_old = NULL;
450275970Scy	}
451275970Scy}
452275970Scy
453275970Scystatic void
454275970Scyevsig_free_globals_locks(void)
455275970Scy{
456275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT
457275970Scy	if (evsig_base_lock != NULL) {
458275970Scy		EVTHREAD_FREE_LOCK(evsig_base_lock, 0);
459275970Scy		evsig_base_lock = NULL;
460275970Scy	}
461275970Scy#endif
462275970Scy	return;
463275970Scy}
464275970Scy
465275970Scyvoid
466275970Scyevsig_free_globals_(void)
467275970Scy{
468275970Scy	evsig_free_globals_locks();
469275970Scy}
470275970Scy
471275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT
472275970Scyint
473275970Scyevsig_global_setup_locks_(const int enable_locks)
474275970Scy{
475275970Scy	EVTHREAD_SETUP_GLOBAL_LOCK(evsig_base_lock, 0);
476275970Scy	return 0;
477275970Scy}
478275970Scy
479275970Scy#endif
480