Merge branch 'winevents-clean' of https://github.com/dechamps/tinc into 1.1
[tinc] / src / net_socket.c
index 939aa9c..3b6399b 100644 (file)
@@ -401,19 +401,38 @@ static void handle_meta_io(void *data, int flags) {
        connection_t *c = data;
 
        if(c->status.connecting) {
-               c->status.connecting = false;
-
-               int result;
-               socklen_t len = sizeof result;
-               getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);
-
-               if(!result)
-                       finish_connecting(c);
-               else {
-                       logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(result));
-                       terminate_connection(c, false);
+               /*
+                  The event loop does not protect against spurious events. Verify that we are actually connected
+                  by issuing an empty send() call.
+
+                  Note that the behavior of send() on potentially unconnected sockets differ between platforms:
+                  +------------+-----------+-------------+-----------+
+                  |   Event    |   POSIX   |    Linux    |  Windows  |
+                  +------------+-----------+-------------+-----------+
+                  | Spurious   | ENOTCONN  | EWOULDBLOCK | ENOTCONN  |
+                  | Failed     | ENOTCONN  | (cause)     | ENOTCONN  |
+                  | Successful | (success) | (success)   | (success) |
+                  +------------+-----------+-------------+-----------+
+               */
+               if (send(c->socket, NULL, 0, 0) != 0) {
+                       if (sockwouldblock(sockerrno))
+                               return;
+                       int socket_error;
+                       if (!socknotconn(sockerrno))
+                               socket_error = sockerrno;
+                       else {
+                               int len = sizeof socket_error;
+                               getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&socket_error, &len);
+                       }
+                       if (socket_error) {
+                               logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Error while connecting to %s (%s): %s", c->name, c->hostname, sockstrerror(socket_error));
+                               terminate_connection(c, false);
+                       }
                        return;
                }
+
+               c->status.connecting = false;
+               finish_connecting(c);
        }
 
        if(flags & IO_WRITE)