Simplify signal handling.
[tinc] / src / event.c
1 /*
2     event.c -- I/O, timeout and signal event handling
3     Copyright (C) 2012-2021 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21 #include "event.h"
22 #include "utils.h"
23
24 struct timeval now;
25
26 #ifndef HAVE_MINGW
27 static fd_set readfds;
28 static fd_set writefds;
29 #else
30 static const long READ_EVENTS = FD_READ | FD_ACCEPT | FD_CLOSE;
31 static const long WRITE_EVENTS = FD_WRITE | FD_CONNECT;
32 static DWORD event_count = 0;
33 #endif
34 static bool running;
35
36 static int io_compare(const io_t *a, const io_t *b) {
37 #ifndef HAVE_MINGW
38         return a->fd - b->fd;
39 #else
40
41         if(a->event < b->event) {
42                 return -1;
43         }
44
45         if(a->event > b->event) {
46                 return 1;
47         }
48
49         return 0;
50 #endif
51 }
52
53 static int timeout_compare(const timeout_t *a, const timeout_t *b) {
54         struct timeval diff;
55         timersub(&a->tv, &b->tv, &diff);
56
57         if(diff.tv_sec < 0) {
58                 return -1;
59         }
60
61         if(diff.tv_sec > 0) {
62                 return 1;
63         }
64
65         if(diff.tv_usec < 0) {
66                 return -1;
67         }
68
69         if(diff.tv_usec > 0) {
70                 return 1;
71         }
72
73         if(a < b) {
74                 return -1;
75         }
76
77         if(a > b) {
78                 return 1;
79         }
80
81         return 0;
82 }
83
84 static splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare};
85 static splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare};
86
87 void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
88         if(io->cb) {
89                 return;
90         }
91
92         io->fd = fd;
93 #ifdef HAVE_MINGW
94
95         if(io->fd != -1) {
96                 io->event = WSACreateEvent();
97
98                 if(io->event == WSA_INVALID_EVENT) {
99                         abort();
100                 }
101         }
102
103         event_count++;
104 #endif
105         io->cb = cb;
106         io->data = data;
107         io->node.data = io;
108
109         io_set(io, flags);
110
111         if(!splay_insert_node(&io_tree, &io->node)) {
112                 abort();
113         }
114 }
115
116 #ifdef HAVE_MINGW
117 void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event) {
118         io->event = event;
119         io_add(io, cb, data, -1, 0);
120 }
121 #endif
122
123 void io_set(io_t *io, int flags) {
124         if(flags == io->flags) {
125                 return;
126         }
127
128         io->flags = flags;
129
130         if(io->fd == -1) {
131                 return;
132         }
133
134 #ifndef HAVE_MINGW
135
136         if(flags & IO_READ) {
137                 FD_SET(io->fd, &readfds);
138         } else {
139                 FD_CLR(io->fd, &readfds);
140         }
141
142         if(flags & IO_WRITE) {
143                 FD_SET(io->fd, &writefds);
144         } else {
145                 FD_CLR(io->fd, &writefds);
146         }
147
148 #else
149         long events = 0;
150
151         if(flags & IO_WRITE) {
152                 events |= WRITE_EVENTS;
153         }
154
155         if(flags & IO_READ) {
156                 events |= READ_EVENTS;
157         }
158
159         if(WSAEventSelect(io->fd, io->event, events) != 0) {
160                 abort();
161         }
162
163 #endif
164 }
165
166 void io_del(io_t *io) {
167         if(!io->cb) {
168                 return;
169         }
170
171         io_set(io, 0);
172 #ifdef HAVE_MINGW
173
174         if(io->fd != -1 && WSACloseEvent(io->event) == FALSE) {
175                 abort();
176         }
177
178         event_count--;
179 #endif
180
181         splay_unlink_node(&io_tree, &io->node);
182         io->cb = NULL;
183 }
184
185 void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
186         timeout->cb = cb;
187         timeout->data = data;
188         timeout->node.data = timeout;
189
190         timeout_set(timeout, tv);
191 }
192
193 void timeout_set(timeout_t *timeout, struct timeval *tv) {
194         if(timerisset(&timeout->tv)) {
195                 splay_unlink_node(&timeout_tree, &timeout->node);
196         }
197
198         if(!now.tv_sec) {
199                 gettimeofday(&now, NULL);
200         }
201
202         timeradd(&now, tv, &timeout->tv);
203
204         if(!splay_insert_node(&timeout_tree, &timeout->node)) {
205                 abort();
206         }
207 }
208
209 void timeout_del(timeout_t *timeout) {
210         if(!timeout->cb) {
211                 return;
212         }
213
214         splay_unlink_node(&timeout_tree, &timeout->node);
215         timeout->cb = 0;
216         timeout->tv = (struct timeval) {
217                 0, 0
218         };
219 }
220
221 #ifndef HAVE_MINGW
222
223 // From Matz's Ruby
224 #ifndef NSIG
225 # define NSIG (_SIGMAX + 1)      /* For QNX */
226 #endif
227
228
229 static io_t signalio;
230 static int pipefd[2] = {-1, -1};
231 static signal_t *signal_handle[NSIG + 1] = {};
232
233 static void signal_handler(int signum) {
234         unsigned char num = signum;
235         write(pipefd[1], &num, 1);
236 }
237
238 static void signalio_handler(void *data, int flags) {
239         (void)data;
240         (void)flags;
241         unsigned char signum;
242
243         if(read(pipefd[0], &signum, 1) != 1) {
244                 return;
245         }
246
247         signal_t *sig = signal_handle[signum];
248
249         if(sig) {
250                 sig->cb(sig->data);
251         }
252 }
253
254 static void pipe_init(void) {
255         if(!pipe(pipefd)) {
256                 io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ);
257         }
258 }
259
260 void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) {
261         if(sig->cb) {
262                 return;
263         }
264
265         sig->signum = signum;
266         sig->cb = cb;
267         sig->data = data;
268
269         if(pipefd[0] == -1) {
270                 pipe_init();
271         }
272
273         signal(signum, signal_handler);
274
275         signal_handle[signum] = sig;
276 }
277
278 void signal_del(signal_t *sig) {
279         if(!sig->cb) {
280                 return;
281         }
282
283         signal(sig->signum, SIG_DFL);
284
285         signal_handle[sig->signum] = NULL;
286         sig->cb = NULL;
287 }
288 #endif
289
290 static struct timeval *get_time_remaining(struct timeval *diff) {
291         gettimeofday(&now, NULL);
292         struct timeval *tv = NULL;
293
294         while(timeout_tree.head) {
295                 timeout_t *timeout = timeout_tree.head->data;
296                 timersub(&timeout->tv, &now, diff);
297
298                 if(diff->tv_sec < 0) {
299                         timeout->cb(timeout->data);
300
301                         if(timercmp(&timeout->tv, &now, <)) {
302                                 timeout_del(timeout);
303                         }
304                 } else {
305                         tv = diff;
306                         break;
307                 }
308         }
309
310         return tv;
311 }
312
313 bool event_loop(void) {
314         running = true;
315
316 #ifndef HAVE_MINGW
317         fd_set readable;
318         fd_set writable;
319
320         while(running) {
321                 struct timeval diff;
322                 struct timeval *tv = get_time_remaining(&diff);
323                 memcpy(&readable, &readfds, sizeof(readable));
324                 memcpy(&writable, &writefds, sizeof(writable));
325
326                 int fds = 0;
327
328                 if(io_tree.tail) {
329                         io_t *last = io_tree.tail->data;
330                         fds = last->fd + 1;
331                 }
332
333                 int n = select(fds, &readable, &writable, NULL, tv);
334
335                 if(n < 0) {
336                         if(sockwouldblock(sockerrno)) {
337                                 continue;
338                         } else {
339                                 return false;
340                         }
341                 }
342
343                 if(!n) {
344                         continue;
345                 }
346
347                 unsigned int curgen = io_tree.generation;
348
349                 for splay_each(io_t, io, &io_tree) {
350                         if(FD_ISSET(io->fd, &writable)) {
351                                 io->cb(io->data, IO_WRITE);
352                         } else if(FD_ISSET(io->fd, &readable)) {
353                                 io->cb(io->data, IO_READ);
354                         } else {
355                                 continue;
356                         }
357
358                         /*
359                            There are scenarios in which the callback will remove another io_t from the tree
360                            (e.g. closing a double connection). Since splay_each does not support that, we
361                            need to exit the loop if that happens. That's okay, since any remaining events will
362                            get picked up by the next select() call.
363                          */
364                         if(curgen != io_tree.generation) {
365                                 break;
366                         }
367                 }
368         }
369
370 #else
371
372         while(running) {
373                 struct timeval diff;
374                 struct timeval *tv = get_time_remaining(&diff);
375                 DWORD timeout_ms = tv ? (DWORD)(tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1) : WSA_INFINITE;
376
377                 if(!event_count) {
378                         Sleep(timeout_ms);
379                         continue;
380                 }
381
382                 /*
383                    For some reason, Microsoft decided to make the FD_WRITE event edge-triggered instead of level-triggered,
384                    which is the opposite of what select() does. In practice, that means that if a FD_WRITE event triggers,
385                    it will never trigger again until a send() returns EWOULDBLOCK. Since the semantics of this event loop
386                    is that write events are level-triggered (i.e. they continue firing until the socket is full), we need
387                    to emulate these semantics by making sure we fire each IO_WRITE that is still writeable.
388
389                    Note that technically FD_CLOSE has the same problem, but it's okay because user code does not rely on
390                    this event being fired again if ignored.
391                 */
392                 unsigned int curgen = io_tree.generation;
393
394                 for splay_each(io_t, io, &io_tree) {
395                         if(io->flags & IO_WRITE && send(io->fd, NULL, 0, 0) == 0) {
396                                 io->cb(io->data, IO_WRITE);
397
398                                 if(curgen != io_tree.generation) {
399                                         break;
400                                 }
401                         }
402                 }
403
404                 if(event_count > WSA_MAXIMUM_WAIT_EVENTS) {
405                         WSASetLastError(WSA_INVALID_PARAMETER);
406                         return(false);
407                 }
408
409                 WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS];
410                 io_t *io_map[WSA_MAXIMUM_WAIT_EVENTS];
411                 DWORD event_index = 0;
412
413                 for splay_each(io_t, io, &io_tree) {
414                         events[event_index] = io->event;
415                         io_map[event_index] = io;
416                         event_index++;
417                 }
418
419                 /*
420                  * If the generation number changes due to event addition
421                  * or removal by a callback we restart the loop.
422                  */
423                 curgen = io_tree.generation;
424
425                 for(DWORD event_offset = 0; event_offset < event_count;) {
426                         DWORD result = WSAWaitForMultipleEvents(event_count - event_offset, &events[event_offset], FALSE, timeout_ms, FALSE);
427
428                         if(result == WSA_WAIT_TIMEOUT) {
429                                 break;
430                         }
431
432                         if(result < WSA_WAIT_EVENT_0 || result >= WSA_WAIT_EVENT_0 + event_count - event_offset) {
433                                 return false;
434                         }
435
436                         /* Look up io in the map by index. */
437                         event_index = result - WSA_WAIT_EVENT_0 + event_offset;
438                         io_t *io = io_map[event_index];
439
440                         if(io->fd == -1) {
441                                 io->cb(io->data, 0);
442
443                                 if(curgen != io_tree.generation) {
444                                         break;
445                                 }
446                         } else {
447                                 WSANETWORKEVENTS network_events;
448
449                                 if(WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0) {
450                                         return(false);
451                                 }
452
453                                 if(network_events.lNetworkEvents & READ_EVENTS) {
454                                         io->cb(io->data, IO_READ);
455
456                                         if(curgen != io_tree.generation) {
457                                                 break;
458                                         }
459                                 }
460
461                                 /*
462                                     The fd might be available for write too. However, if we already fired the read callback, that
463                                     callback might have deleted the io (e.g. through terminate_connection()), so we can't fire the
464                                     write callback here. Instead, we loop back and let the writable io loop above handle it.
465                                  */
466                         }
467
468                         /* Continue checking the rest of the events. */
469                         event_offset = event_index + 1;
470
471                         /* Just poll the next time through. */
472                         timeout_ms = 0;
473                 }
474         }
475
476 #endif
477
478         return true;
479 }
480
481 void event_exit(void) {
482         running = false;
483 }