Add stricter checks for netnames.
[tinc] / src / event.c
index 0e4e2bd..59b96e3 100644 (file)
@@ -35,7 +35,7 @@ static const long READ_EVENTS = FD_READ | FD_ACCEPT | FD_CLOSE;
 static const long WRITE_EVENTS = FD_WRITE | FD_CONNECT;
 static DWORD event_count = 0;
 #endif
-static volatile bool running;
+static bool running;
 
 static int io_compare(const io_t *a, const io_t *b) {
 #ifndef HAVE_MINGW
@@ -72,9 +72,11 @@ void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
 
        io->fd = fd;
 #ifdef HAVE_MINGW
-       io->event = WSACreateEvent();
-       if (io->event == WSA_INVALID_EVENT)
-               abort();
+       if (io->fd != -1) {
+               io->event = WSACreateEvent();
+               if (io->event == WSA_INVALID_EVENT)
+                       abort();
+       }
        event_count++;
 #endif
        io->cb = cb;
@@ -87,10 +89,19 @@ void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
                abort();
 }
 
+#ifdef HAVE_MINGW
+void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event) {
+       io->event = event;
+       io_add(io, cb, data, -1, 0);
+}
+#endif
+
 void io_set(io_t *io, int flags) {
        if (flags == io->flags)
                return;
        io->flags = flags;
+       if (io->fd == -1)
+               return;
 
 #ifndef HAVE_MINGW
        if(flags & IO_READ)
@@ -119,7 +130,7 @@ void io_del(io_t *io) {
 
        io_set(io, 0);
 #ifdef HAVE_MINGW
-       if (WSACloseEvent(io->event) == FALSE)
+       if (io->fd != -1 && WSACloseEvent(io->event) == FALSE)
                abort();
        event_count--;
 #endif
@@ -245,10 +256,10 @@ bool event_loop(void) {
        fd_set writable;
 
        while(running) {
-               memcpy(&readable, &readfds, sizeof readable);
-               memcpy(&writable, &writefds, sizeof writable);
                struct timeval diff;
                struct timeval *tv = get_time_remaining(&diff);
+               memcpy(&readable, &readfds, sizeof readable);
+               memcpy(&writable, &writefds, sizeof writable);
 
                int fds = 0;
 
@@ -274,6 +285,16 @@ bool event_loop(void) {
                                io->cb(io->data, IO_WRITE);
                        else if(FD_ISSET(io->fd, &readable))
                                io->cb(io->data, IO_READ);
+                       else
+                               continue;
+
+                       /*
+                          There are scenarios in which the callback will remove another io_t from the tree
+                          (e.g. closing a double connection). Since splay_each does not support that, we
+                          need to exit the loop now. That's okay, since any remaining events will get picked
+                          up by the next select() call.
+                        */
+                       break;
                }
        }
 #else
@@ -283,9 +304,7 @@ bool event_loop(void) {
                DWORD timeout_ms = tv ? (tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1) : WSA_INFINITE;
 
                if (!event_count) {
-                       LeaveCriticalSection(&mutex);
                        Sleep(timeout_ms);
-                       EnterCriticalSection(&mutex);
                        continue;
                }
 
@@ -317,9 +336,7 @@ bool event_loop(void) {
                        event_index++;
                }
 
-               LeaveCriticalSection(&mutex);
                DWORD result = WSAWaitForMultipleEvents(event_count, events, FALSE, timeout_ms, FALSE);
-               EnterCriticalSection(&mutex);
 
                WSAEVENT event;
                if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + event_count)
@@ -334,25 +351,23 @@ bool event_loop(void) {
                if (!io)
                        abort();
 
-               WSANETWORKEVENTS network_events;
-               if (WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0)
-                       return false;
-               if (network_events.lNetworkEvents & WRITE_EVENTS)
-                       io->cb(io->data, IO_WRITE);
-               if (network_events.lNetworkEvents & READ_EVENTS)
-                       io->cb(io->data, IO_READ);
+               if (io->fd == -1) {
+                       io->cb(io->data, 0);
+               } else {
+                       WSANETWORKEVENTS network_events;
+                       if (WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0)
+                               return false;
+                       if (network_events.lNetworkEvents & WRITE_EVENTS)
+                               io->cb(io->data, IO_WRITE);
+                       if (network_events.lNetworkEvents & READ_EVENTS)
+                               io->cb(io->data, IO_READ);
+               }
        }
 #endif
 
        return true;
 }
 
-void event_flush_output(void) {
-       for splay_each(io_t, io, &io_tree)
-               if(io->flags & IO_WRITE)
-                       io->cb(io->data, IO_WRITE);
-}
-
 void event_exit(void) {
        running = false;
 }