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