Convert to libevent.

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.
This commit is contained in:
Scott Lamb 2007-02-27 01:57:01 +00:00
parent 834290b00f
commit 38c25d62c2
9 changed files with 129 additions and 110 deletions

View file

@ -86,6 +86,9 @@ fi
dnl Checks for libraries. dnl Checks for libraries.
AC_CHECK_LIB(event, event_init,
[], [AC_MSG_ERROR(libevent is required)])
dnl Checks for header files. 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. dnl We do this in multiple stages, because unlike Linux all the other operating systems really suck and don't include their own dependencies.

View file

@ -70,6 +70,7 @@ connection_t *new_connection(void)
return NULL; return NULL;
gettimeofday(&c->start, NULL); gettimeofday(&c->start, NULL);
event_set(&c->ev, -1, 0, NULL, NULL);
return c; return c;
} }
@ -78,20 +79,14 @@ void free_connection(connection_t *c)
{ {
cp(); cp();
if(c->hostname) if(c) {
free(c->hostname); free(c->hostname);
if(c->inkey)
free(c->inkey); free(c->inkey);
if(c->outkey)
free(c->outkey); free(c->outkey);
if(c->mychallenge)
free(c->mychallenge); free(c->mychallenge);
if(c->hischallenge)
free(c->hischallenge); free(c->hischallenge);
event_del(&c->ev);
}
free(c); free(c);
} }

View file

@ -26,6 +26,8 @@
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <event.h>
#include "avl_tree.h" #include "avl_tree.h"
#define OPTION_INDIRECT 0x0001 #define OPTION_INDIRECT 0x0001
@ -60,6 +62,7 @@ typedef struct connection_t {
char *hostname; /* the hostname of its real ip */ char *hostname; /* the hostname of its real ip */
int protocol_version; /* used protocol */ int protocol_version; /* used protocol */
struct event ev; /* events on this metadata connection */
int socket; /* socket used for this connection */ int socket; /* socket used for this connection */
long int options; /* options for this connection */ long int options; /* options for this connection */
connection_status_t status; /* status info */ connection_status_t status; /* status info */

155
src/net.c
View file

@ -109,10 +109,10 @@ static void purge(void)
} }
/* /*
put all file descriptors in an fd_set array put all file descriptors into events
While we're at it, purge stuff that needs to be removed. 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; avl_node_t *node, *next;
connection_t *c; connection_t *c;
@ -120,9 +120,6 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
cp(); cp();
FD_ZERO(readset);
FD_ZERO(writeset);
for(node = connection_tree->head; node; node = next) { for(node = connection_tree->head; node; node = next) {
next = node->next; next = node->next;
c = node->data; c = node->data;
@ -132,28 +129,17 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
if(!connection_tree->head) if(!connection_tree->head)
purge(); purge();
} else { } else {
FD_SET(c->socket, readset); short events = EV_READ;
if(c->outbuflen > 0) if(c->outbuflen > 0)
FD_SET(c->socket, writeset); events |= EV_WRITE;
if(c->socket > max) event_del(&c->ev);
max = c->socket; event_set(&c->ev, c->socket, events,
handle_meta_connection_data, c);
if (event_add(&c->ev, NULL) < 0)
return -1;
} }
} }
return 0;
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;
} }
/* /*
@ -279,83 +265,59 @@ static void check_dead_connections(void)
} }
} }
/* void handle_meta_connection_data(int fd, short events, void *data)
check all connections to see if anything
happened on their sockets
*/
static void check_network_activity(fd_set * readset, fd_set * writeset)
{ {
connection_t *c; connection_t *c = data;
avl_node_t *node; int result;
int result, i;
socklen_t len = sizeof(result); socklen_t len = sizeof(result);
vpn_packet_t packet;
cp(); if (c->status.remove)
return;
/* check input from kernel */ if (events & EV_READ) {
if(FD_ISSET(device_fd, readset)) { if(c->status.connecting) {
if(read_packet(&packet)) c->status.connecting = false;
route(myself, &packet); getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
}
/* check meta connections */ if(!result)
for(node = connection_tree->head; node; node = node->next) { finish_connecting(c);
c = node->data; else {
ifdebug(CONNECTIONS) logger(LOG_DEBUG,
if(c->status.remove) _("Error while connecting to %s (%s): %s"),
continue; c->name, c->hostname, strerror(result));
closesocket(c->socket);
if(FD_ISSET(c->socket, readset)) { do_outgoing_connection(c);
if(c->status.connecting) { return;
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(!receive_meta(c)) {
terminate_connection(c, c->status.active);
continue;
} }
} }
if(FD_ISSET(c->socket, writeset)) { if (!receive_meta(c)) {
if(!flush_meta(c)) { terminate_connection(c, c->status.active);
terminate_connection(c, c->status.active); return;
continue;
}
} }
} }
for(i = 0; i < listen_sockets; i++) { if (events & EV_WRITE) {
if(FD_ISSET(listen_socket[i].udp, readset)) if(!flush_meta(c)) {
handle_incoming_vpn_data(listen_socket[i].udp); terminate_connection(c, c->status.active);
}
if(FD_ISSET(listen_socket[i].tcp, readset))
handle_new_meta_connection(listen_socket[i].tcp);
} }
} }
static void dummy(int a, short b, void *c)
{
}
/* /*
this is where it all happens... this is where it all happens...
*/ */
int main_loop(void) int main_loop(void)
{ {
fd_set readset, writeset;
struct timeval tv; struct timeval tv;
int r, maxfd; int r;
time_t last_ping_check, last_config_check, last_graph_dump; time_t last_ping_check, last_config_check, last_graph_dump;
tevent_t *event; tevent_t *event;
struct event timeout;
cp(); cp();
@ -374,23 +336,30 @@ int main_loop(void)
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
maxfd = build_fdset(&readset, &writeset); /* XXX: libevent transition: old timeout code in this loop */
timeout_set(&timeout, dummy, NULL);
r = select(maxfd + 1, &readset, &writeset, NULL, &tv); timeout_add(&timeout, &tv);
r = build_fdset();
if(r < 0) { if(r < 0) {
if(errno != EINTR && errno != EAGAIN) { logger(LOG_ERR, _("Error building fdset: %s"), strerror(errno));
logger(LOG_ERR, _("Error while waiting for input: %s"), cp_trace();
strerror(errno)); dump_connections();
cp_trace(); return 1;
dump_connections();
return 1;
}
continue;
} }
check_network_activity(&readset, &writeset); 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;
}
/* XXX: more libevent transition */
timeout_del(&timeout);
if(do_purge) { if(do_purge) {
purge(); purge();

View file

@ -24,6 +24,7 @@
#define __TINC_NET_H__ #define __TINC_NET_H__
#include <openssl/evp.h> #include <openssl/evp.h>
#include <event.h>
#include "ipv6.h" #include "ipv6.h"
@ -99,6 +100,8 @@ typedef struct packet_queue_t {
} packet_queue_t; } packet_queue_t;
typedef struct listen_socket_t { typedef struct listen_socket_t {
struct event ev_tcp;
struct event ev_udp;
int tcp; int tcp;
int udp; int udp;
sockaddr_t sa; sockaddr_t sa;
@ -133,10 +136,10 @@ extern EVP_CIPHER_CTX packet_ctx;
#include "node.h" #include "node.h"
extern void retry_outgoing(outgoing_t *); 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 finish_connecting(struct connection_t *);
extern void do_outgoing_connection(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_listen_socket(const sockaddr_t *);
extern int setup_vpn_in_socket(const sockaddr_t *); extern int setup_vpn_in_socket(const sockaddr_t *);
extern void send_packet(const struct node_t *, vpn_packet_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 void flush_queue(struct node_t *);
extern bool read_rsa_public_key(struct connection_t *); extern bool read_rsa_public_key(struct connection_t *);
extern void send_mtu_probe(struct node_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 #ifndef HAVE_MINGW
#define closesocket(s) close(s) #define closesocket(s) close(s)

View 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; vpn_packet_t pkt;
char *hostname; char *hostname;
@ -515,3 +515,11 @@ void handle_incoming_vpn_data(int sock)
receive_udppacket(n, &pkt); 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);
}

View file

@ -45,6 +45,7 @@
#include "xalloc.h" #include "xalloc.h"
char *myport; char *myport;
static struct event device_ev;
bool read_rsa_public_key(connection_t *c) bool read_rsa_public_key(connection_t *c)
{ {
@ -447,6 +448,14 @@ bool setup_myself(void)
if(!setup_device()) if(!setup_device())
return false; 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 */ /* Run tinc-up script to further initialize the tap interface */
asprintf(&envp[0], "NETNAME=%s", netname ? : ""); asprintf(&envp[0], "NETNAME=%s", netname ? : "");
asprintf(&envp[1], "DEVICE=%s", device ? : ""); asprintf(&envp[1], "DEVICE=%s", device ? : "");
@ -492,8 +501,33 @@ bool setup_myself(void)
listen_socket[listen_sockets].udp = listen_socket[listen_sockets].udp =
setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); 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; 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) { ifdebug(CONNECTIONS) {
hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);

View file

@ -384,7 +384,7 @@ void setup_outgoing_connection(outgoing_t *outgoing)
accept a new tcp connect and create a accept a new tcp connect and create a
new connection new connection
*/ */
bool handle_new_meta_connection(int sock) void handle_new_meta_connection(int sock, short events, void *data)
{ {
connection_t *c; connection_t *c;
sockaddr_t sa; sockaddr_t sa;
@ -398,7 +398,6 @@ bool handle_new_meta_connection(int sock)
if(fd < 0) { if(fd < 0) {
logger(LOG_ERR, _("Accepting a new connection failed: %s"), logger(LOG_ERR, _("Accepting a new connection failed: %s"),
strerror(errno)); strerror(errno));
return false;
} }
sockaddrunmap(&sa); sockaddrunmap(&sa);
@ -423,8 +422,6 @@ bool handle_new_meta_connection(int sock)
c->allow_request = ID; c->allow_request = ID;
send_id(c); send_id(c);
return true;
} }
void try_outgoing_connections(void) void try_outgoing_connections(void)

View file

@ -462,6 +462,11 @@ int main(int argc, char **argv)
if(!read_server_config()) if(!read_server_config())
return 1; return 1;
if(event_init() < 0) {
logger(LOG_ERR, _("Error initializing libevent!"));
return 1;
}
if(lzo_init() != LZO_E_OK) { if(lzo_init() != LZO_E_OK) {
logger(LOG_ERR, _("Error initializing LZO compressor!")); logger(LOG_ERR, _("Error initializing LZO compressor!"));
return 1; return 1;