Convert to libevent.
authorScott Lamb <slamb@slamb.org>
Tue, 27 Feb 2007 01:57:01 +0000 (01:57 +0000)
committerScott Lamb <slamb@slamb.org>
Tue, 27 Feb 2007 01:57:01 +0000 (01:57 +0000)
This is a quick initial conversion that doesn't yet show much advantage:
- We roll our own timeouts.
- We roll our own signal handling.
- We build up the meta connection fd events on each loop rather than
  on state changes.

configure.in
src/connection.c
src/connection.h
src/net.c
src/net.h
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/tincd.c

index 3cb6a4d..a29a88f 100644 (file)
@@ -86,6 +86,9 @@ fi
 
 dnl Checks for libraries.
 
+AC_CHECK_LIB(event, event_init,
+  [], [AC_MSG_ERROR(libevent is required)])
+
 dnl Checks for header files.
 dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.
 
index c4c9fd4..1f2f96c 100644 (file)
@@ -70,6 +70,7 @@ connection_t *new_connection(void)
                return NULL;
 
        gettimeofday(&c->start, NULL);
+       event_set(&c->ev, -1, 0, NULL, NULL);
 
        return c;
 }
@@ -78,20 +79,14 @@ void free_connection(connection_t *c)
 {
        cp();
 
-       if(c->hostname)
+       if(c) {
                free(c->hostname);
-
-       if(c->inkey)
                free(c->inkey);
-
-       if(c->outkey)
                free(c->outkey);
-
-       if(c->mychallenge)
                free(c->mychallenge);
-
-       if(c->hischallenge)
                free(c->hischallenge);
+               event_del(&c->ev);
+       }
 
        free(c);
 }
index 087d8f0..8d5537b 100644 (file)
@@ -26,6 +26,8 @@
 #include <openssl/rsa.h>
 #include <openssl/evp.h>
 
+#include <event.h>
+
 #include "avl_tree.h"
 
 #define OPTION_INDIRECT                0x0001
@@ -60,6 +62,7 @@ typedef struct connection_t {
        char *hostname;                         /* the hostname of its real ip */
        int protocol_version;           /* used protocol */
 
+       struct event ev;                        /* events on this metadata connection */
        int socket;                                     /* socket used for this connection */
        long int options;                       /* options for this connection */
        connection_status_t status;     /* status info */
index e9c7020..3a44ce6 100644 (file)
--- a/src/net.c
+++ b/src/net.c
@@ -109,10 +109,10 @@ static void purge(void)
 }
 
 /*
-  put all file descriptors in an fd_set array
-  While we're at it, purge stuff that needs to be removed.
+  put all file descriptors into events
+  While we're at it, purge stuf that needs to be removed.
 */
-static int build_fdset(fd_set *readset, fd_set *writeset)
+static int build_fdset(void)
 {
        avl_node_t *node, *next;
        connection_t *c;
@@ -120,9 +120,6 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
 
        cp();
 
-       FD_ZERO(readset);
-       FD_ZERO(writeset);
-
        for(node = connection_tree->head; node; node = next) {
                next = node->next;
                c = node->data;
@@ -132,28 +129,17 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
                        if(!connection_tree->head)
                                purge();
                } else {
-                       FD_SET(c->socket, readset);
+                       short events = EV_READ;
                        if(c->outbuflen > 0)
-                               FD_SET(c->socket, writeset);
-                       if(c->socket > max)
-                               max = c->socket;
+                               events |= EV_WRITE;
+                       event_del(&c->ev);
+                       event_set(&c->ev, c->socket, events,
+                                         handle_meta_connection_data, c);
+                       if (event_add(&c->ev, NULL) < 0)
+                               return -1;
                }
        }
-
-       for(i = 0; i < listen_sockets; i++) {
-               FD_SET(listen_socket[i].tcp, readset);
-               if(listen_socket[i].tcp > max)
-                       max = listen_socket[i].tcp;
-               FD_SET(listen_socket[i].udp, readset);
-               if(listen_socket[i].udp > max)
-                       max = listen_socket[i].udp;
-       }
-
-       FD_SET(device_fd, readset);
-       if(device_fd > max)
-               max = device_fd;
-       
-       return max;
+       return 0;
 }
 
 /*
@@ -279,83 +265,59 @@ static void check_dead_connections(void)
        }
 }
 
-/*
-  check all connections to see if anything
-  happened on their sockets
-*/
-static void check_network_activity(fd_set * readset, fd_set * writeset)
+void handle_meta_connection_data(int fd, short events, void *data)
 {
-       connection_t *c;
-       avl_node_t *node;
-       int result, i;
+       connection_t *c = data;
+       int result;
        socklen_t len = sizeof(result);
-       vpn_packet_t packet;
 
-       cp();
-
-       /* check input from kernel */
-       if(FD_ISSET(device_fd, readset)) {
-               if(read_packet(&packet))
-                       route(myself, &packet);
-       }
-
-       /* check meta connections */
-       for(node = connection_tree->head; node; node = node->next) {
-               c = node->data;
-
-               if(c->status.remove)
-                       continue;
-
-               if(FD_ISSET(c->socket, readset)) {
-                       if(c->status.connecting) {
-                               c->status.connecting = false;
-                               getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
-
-                               if(!result)
-                                       finish_connecting(c);
-                               else {
-                                       ifdebug(CONNECTIONS) logger(LOG_DEBUG,
-                                                          _("Error while connecting to %s (%s): %s"),
-                                                          c->name, c->hostname, strerror(result));
-                                       closesocket(c->socket);
-                                       do_outgoing_connection(c);
-                                       continue;
-                               }
-                       }
+       if (c->status.remove)
+               return;
 
-                       if(!receive_meta(c)) {
-                               terminate_connection(c, c->status.active);
-                               continue;
+       if (events & EV_READ) {
+               if(c->status.connecting) {
+                       c->status.connecting = false;
+                       getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
+
+                       if(!result)
+                               finish_connecting(c);
+                       else {
+                               ifdebug(CONNECTIONS) logger(LOG_DEBUG,
+                                                  _("Error while connecting to %s (%s): %s"),
+                                                  c->name, c->hostname, strerror(result));
+                               closesocket(c->socket);
+                               do_outgoing_connection(c);
+                               return;
                        }
                }
 
-               if(FD_ISSET(c->socket, writeset)) {
-                       if(!flush_meta(c)) {
-                               terminate_connection(c, c->status.active);
-                               continue;
-                       }
+               if (!receive_meta(c)) {
+                       terminate_connection(c, c->status.active);
+                       return;
                }
        }
 
-       for(i = 0; i < listen_sockets; i++) {
-               if(FD_ISSET(listen_socket[i].udp, readset))
-                       handle_incoming_vpn_data(listen_socket[i].udp);
-
-               if(FD_ISSET(listen_socket[i].tcp, readset))
-                       handle_new_meta_connection(listen_socket[i].tcp);
+       if (events & EV_WRITE) {
+               if(!flush_meta(c)) {
+                       terminate_connection(c, c->status.active);
+               }
        }
 }
 
+static void dummy(int a, short b, void *c)
+{
+}
+
 /*
   this is where it all happens...
 */
 int main_loop(void)
 {
-       fd_set readset, writeset;
        struct timeval tv;
-       int r, maxfd;
+       int r;
        time_t last_ping_check, last_config_check, last_graph_dump;
        tevent_t *event;
+       struct event timeout;
 
        cp();
 
@@ -374,23 +336,30 @@ int main_loop(void)
                tv.tv_sec = 1;
                tv.tv_usec = 0;
 
-               maxfd = build_fdset(&readset, &writeset);
-
-               r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
+               /* XXX: libevent transition: old timeout code in this loop */
+               timeout_set(&timeout, dummy, NULL);
+               timeout_add(&timeout, &tv);
 
+               r = build_fdset();
                if(r < 0) {
-                       if(errno != EINTR && errno != EAGAIN) {
-                               logger(LOG_ERR, _("Error while waiting for input: %s"),
-                                          strerror(errno));
-                               cp_trace();
-                               dump_connections();
-                               return 1;
-                       }
+                       logger(LOG_ERR, _("Error building fdset: %s"), strerror(errno));
+                       cp_trace();
+                       dump_connections();
+                       return 1;
+               }
 
-                       continue;
+               r = event_loop(EVLOOP_ONCE);
+               now = time(NULL);
+               if(r < 0) {
+                       logger(LOG_ERR, _("Error while waiting for input: %s"),
+                                  strerror(errno));
+                       cp_trace();
+                       dump_connections();
+                       return 1;
                }
 
-               check_network_activity(&readset, &writeset);
+               /* XXX: more libevent transition */
+               timeout_del(&timeout);
 
                if(do_purge) {
                        purge();
index d63c052..d66a1c7 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -24,6 +24,7 @@
 #define __TINC_NET_H__
 
 #include <openssl/evp.h>
+#include <event.h>
 
 #include "ipv6.h"
 
@@ -99,6 +100,8 @@ typedef struct packet_queue_t {
 } packet_queue_t;
 
 typedef struct listen_socket_t {
+       struct event ev_tcp;
+       struct event ev_udp;
        int tcp;
        int udp;
        sockaddr_t sa;
@@ -133,10 +136,10 @@ extern EVP_CIPHER_CTX packet_ctx;
 #include "node.h"
 
 extern void retry_outgoing(outgoing_t *);
-extern void handle_incoming_vpn_data(int);
+extern void handle_incoming_vpn_data(int, short, void *);
 extern void finish_connecting(struct connection_t *);
 extern void do_outgoing_connection(struct connection_t *);
-extern bool handle_new_meta_connection(int);
+extern void handle_new_meta_connection(int, short, void *);
 extern int setup_listen_socket(const sockaddr_t *);
 extern int setup_vpn_in_socket(const sockaddr_t *);
 extern void send_packet(const struct node_t *, vpn_packet_t *);
@@ -151,6 +154,8 @@ extern void terminate_connection(struct connection_t *, bool);
 extern void flush_queue(struct node_t *);
 extern bool read_rsa_public_key(struct connection_t *);
 extern void send_mtu_probe(struct node_t *);
+extern void handle_device_data(int, short, void *);
+extern void handle_meta_connection_data(int, short, void *);
 
 #ifndef HAVE_MINGW
 #define closesocket(s) close(s)
index 9e0ba2e..bb81081 100644 (file)
@@ -484,7 +484,7 @@ void flush_queue(node_t *n)
        }
 }
 
-void handle_incoming_vpn_data(int sock)
+void handle_incoming_vpn_data(int sock, short events, void *data)
 {
        vpn_packet_t pkt;
        char *hostname;
@@ -515,3 +515,11 @@ void handle_incoming_vpn_data(int sock)
 
        receive_udppacket(n, &pkt);
 }
+
+void handle_device_data(int sock, short events, void *data)
+{
+       vpn_packet_t packet;
+
+       if(read_packet(&packet))
+               route(myself, &packet);
+}
index 0c399bb..6596590 100644 (file)
@@ -45,6 +45,7 @@
 #include "xalloc.h"
 
 char *myport;
+static struct event device_ev;
 
 bool read_rsa_public_key(connection_t *c)
 {
@@ -447,6 +448,14 @@ bool setup_myself(void)
        if(!setup_device())
                return false;
 
+       event_set(&device_ev, device_fd, EV_READ|EV_PERSIST,
+                         handle_device_data, NULL);
+       if (event_add(&device_ev, NULL) < 0) {
+               logger(LOG_ERR, _("event_add failed: %s"), strerror(errno));
+               close_device();
+               return false;
+       }
+
        /* Run tinc-up script to further initialize the tap interface */
        asprintf(&envp[0], "NETNAME=%s", netname ? : "");
        asprintf(&envp[1], "DEVICE=%s", device ? : "");
@@ -492,8 +501,33 @@ bool setup_myself(void)
                listen_socket[listen_sockets].udp =
                        setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
 
-               if(listen_socket[listen_sockets].udp < 0)
+               if(listen_socket[listen_sockets].udp < 0) {
+                       close(listen_socket[listen_sockets].tcp);
+                       continue;
+               }
+
+               event_set(&listen_socket[listen_sockets].ev_tcp,
+                                 listen_socket[listen_sockets].tcp,
+                                 EV_READ|EV_PERSIST,
+                                 handle_new_meta_connection, NULL);
+               if(event_add(&listen_socket[listen_sockets].ev_tcp, NULL) < 0) {
+                       logger(LOG_WARNING, _("event_add failed: %s"), strerror(errno));
+                       close(listen_socket[listen_sockets].tcp);
+                       close(listen_socket[listen_sockets].udp);
                        continue;
+               }
+
+               event_set(&listen_socket[listen_sockets].ev_udp,
+                                 listen_socket[listen_sockets].udp,
+                                 EV_READ|EV_PERSIST,
+                                 handle_incoming_vpn_data, NULL);
+               if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
+                       logger(LOG_WARNING, _("event_add failed: %s"), strerror(errno));
+                       close(listen_socket[listen_sockets].tcp);
+                       close(listen_socket[listen_sockets].udp);
+                       event_del(&listen_socket[listen_sockets].ev_tcp);
+                       continue;
+               }
 
                ifdebug(CONNECTIONS) {
                        hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
index 1db1949..c727d7b 100644 (file)
@@ -384,7 +384,7 @@ void setup_outgoing_connection(outgoing_t *outgoing)
   accept a new tcp connect and create a
   new connection
 */
-bool handle_new_meta_connection(int sock)
+void handle_new_meta_connection(int sock, short events, void *data)
 {
        connection_t *c;
        sockaddr_t sa;
@@ -398,7 +398,6 @@ bool handle_new_meta_connection(int sock)
        if(fd < 0) {
                logger(LOG_ERR, _("Accepting a new connection failed: %s"),
                           strerror(errno));
-               return false;
        }
 
        sockaddrunmap(&sa);
@@ -423,8 +422,6 @@ bool handle_new_meta_connection(int sock)
 
        c->allow_request = ID;
        send_id(c);
-
-       return true;
 }
 
 void try_outgoing_connections(void)
index ed96762..3a35908 100644 (file)
@@ -462,6 +462,11 @@ int main(int argc, char **argv)
        if(!read_server_config())
                return 1;
 
+       if(event_init() < 0) {
+               logger(LOG_ERR, _("Error initializing libevent!"));
+               return 1;
+       }
+
        if(lzo_init() != LZO_E_OK) {
                logger(LOG_ERR, _("Error initializing LZO compressor!"));
                return 1;