From: Linus Nordberg Date: Wed, 9 Mar 2011 09:18:06 +0000 (+0100) Subject: Add retransmission timer support (UDP). X-Git-Tag: libradsec-0.0.1~24^2~15 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=libradsec.git;a=commitdiff_plain;h=ce4d6dfe1728e5633a8f49fc4b16c36df0d23521 Add retransmission timer support (UDP). --- diff --git a/lib/conn.c b/lib/conn.c index 85cd7d5..3981f6a 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -282,3 +282,20 @@ rs_conn_set_timeout(struct rs_connection *conn, struct timeval *tv) assert (tv); conn->timeout = *tv; } + +int +conn_activate_timeout (struct rs_connection *conn) +{ + assert (conn); + assert (conn->tev); + assert (conn->evb); + if (conn->timeout.tv_sec || conn->timeout.tv_usec) + { + rs_debug (("%s: activating timer: %d.%d\n", __func__, + conn->timeout.tv_sec, conn->timeout.tv_usec)); + if (evtimer_add (conn->tev, &conn->timeout)) + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, + "evtimer_add: %d", errno); + } + return RSE_OK; +} diff --git a/lib/event.c b/lib/event.c index 55a7e6b..5afba98 100644 --- a/lib/event.c +++ b/lib/event.c @@ -21,6 +21,7 @@ #endif #include "event.h" #include "packet.h" +#include "conn.h" #include "debug.h" static void @@ -51,6 +52,41 @@ _evlog_cb (int severity, const char *msg) fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr? */ } +void +event_conn_timeout_cb (int fd, short event, void *data) +{ + struct rs_connection *conn = NULL; + + assert (data); + conn = (struct rs_connection *) data; + + if (event & EV_TIMEOUT) + { + rs_debug (("%s: connection timeout on %p (fd %d) connecting to %p\n", + __func__, conn, conn->fd, conn->active_peer)); + conn->is_connecting = 0; + rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL); + event_loopbreak (conn); + } +} + +void +event_retransmit_timeout_cb (int fd, short event, void *data) +{ + struct rs_connection *conn = NULL; + + assert (data); + conn = (struct rs_connection *) data; + + if (event & EV_TIMEOUT) + { + rs_debug (("%s: retransmission timeout on %p (fd %d) sending to %p\n", + __func__, conn, conn->fd, conn->active_peer)); + rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); + event_loopbreak (conn); + } +} + int event_init_socket (struct rs_connection *conn, struct rs_peer *p) { @@ -138,7 +174,7 @@ event_do_connect (struct rs_connection *conn) if (p->conn->bev) /* TCP */ { - tcp_set_connect_timeout (conn); + conn_activate_timeout (conn); /* Connect timeout. */ err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr, p->addr->ai_addrlen); if (err < 0) @@ -191,10 +227,10 @@ event_on_connect (struct rs_connection *conn, struct rs_packet *pkt) assert (!conn->is_connecting); conn->is_connected = 1; rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); - if (conn->tev) - evtimer_del (conn->tev); + if (conn->callbacks.connected_cb) conn->callbacks.connected_cb (conn->user_data); + if (pkt) packet_do_send (pkt); } @@ -202,6 +238,7 @@ event_on_connect (struct rs_connection *conn, struct rs_packet *pkt) int event_init_eventbase (struct rs_connection *conn) { + assert (conn); if (conn->evb) return RSE_OK; diff --git a/lib/event.h b/lib/event.h index e5ea90c..e042599 100644 --- a/lib/event.h +++ b/lib/event.h @@ -8,3 +8,5 @@ int event_init_eventbase (struct rs_connection *conn); int event_init_socket (struct rs_connection *conn, struct rs_peer *p); int event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer); void event_do_connect (struct rs_connection *conn); +void event_conn_timeout_cb (int fd, short event, void *data); +void event_retransmit_timeout_cb (int fd, short event, void *data); diff --git a/lib/packet.c b/lib/packet.c index 799234f..2611b46 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -88,7 +88,7 @@ packet_do_send (struct rs_packet *pkt) } #endif - if (pkt->conn->bev) + if (pkt->conn->bev) /* TCP. */ { int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, pkt->rpkt->data_len); @@ -97,13 +97,15 @@ packet_do_send (struct rs_packet *pkt) "bufferevent_write: %s", evutil_gai_strerror (err)); } - else + else /* UDP. */ { struct rs_packet **pp = &pkt->conn->out_queue; while (*pp && (*pp)->next) *pp = (*pp)->next; *pp = pkt; + + conn_activate_timeout (pkt->conn); /* Retransmission timer. */ } return RSE_OK; diff --git a/lib/peer.h b/lib/peer.h index f430bb2..a326325 100644 --- a/lib/peer.h +++ b/lib/peer.h @@ -1,4 +1,5 @@ /* Copyright 2011 NORDUnet A/S. All rights reserved. See the file COPYING for licensing information. */ +struct rs_peer *peer_create (struct rs_context *ctx, struct rs_peer **rootp); struct rs_peer *peer_pick_peer (struct rs_connection *conn); diff --git a/lib/radsec.c b/lib/radsec.c index ddd4edd..ec43b2f 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -20,6 +20,7 @@ #if defined (RS_ENABLE_TLS) #include #include "debug.h" +#include "err.h" #include "rsp_list.h" #include "../radsecproxy.h" #endif @@ -91,24 +92,44 @@ rs_context_create (struct rs_context **ctx, const char *dict) return err; } -struct rs_peer * -_rs_peer_create (struct rs_context *ctx, struct rs_peer **rootp) +struct rs_error * /* FIXME: Return int as all the others? */ +rs_resolv (struct evutil_addrinfo **addr, + rs_conn_type_t type, + const char *hostname, + const char *service) { - struct rs_peer *p; + int err; + struct evutil_addrinfo hints, *res = NULL; - p = (struct rs_peer *) rs_malloc (ctx, sizeof(*p)); - if (p) + memset (&hints, 0, sizeof(struct evutil_addrinfo)); + hints.ai_family = AF_INET; /* IPv4 only. TODO: Set AF_UNSPEC. */ + hints.ai_flags = AI_ADDRCONFIG; + switch (type) { - memset (p, 0, sizeof(struct rs_peer)); - if (*rootp) - { - p->next = (*rootp)->next; - (*rootp)->next = p; - } - else - *rootp = p; + case RS_CONN_TYPE_NONE: + return err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL); + case RS_CONN_TYPE_TCP: + /* Fall through. */ + case RS_CONN_TYPE_TLS: + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + break; + case RS_CONN_TYPE_UDP: + /* Fall through. */ + case RS_CONN_TYPE_DTLS: + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + break; + default: + return err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL); } - return p; + err = evutil_getaddrinfo (hostname, service, &hints, &res); + if (err) + return err_create (RSE_BADADDR, __FILE__, __LINE__, + "%s:%s: bad host name or service name (%s)", + hostname, service, evutil_gai_strerror(err)); + *addr = res; /* Simply use first result. */ + return NULL; } static void diff --git a/lib/send.c b/lib/send.c index f169ff9..0872471 100644 --- a/lib/send.c +++ b/lib/send.c @@ -35,6 +35,8 @@ _conn_open (struct rs_connection *conn, struct rs_packet *pkt) if (conn->realm->type == RS_CONN_TYPE_TCP || conn->realm->type == RS_CONN_TYPE_TLS) { + if (tcp_init_connect_timer (conn)) + return -1; if (event_init_bufferevent (conn, conn->active_peer)) return -1; } @@ -42,6 +44,8 @@ _conn_open (struct rs_connection *conn, struct rs_packet *pkt) { if (udp_init (conn, pkt)) return -1; + if (udp_init_retransmit_timer (conn)) + return -1; } if (!conn->is_connected) diff --git a/lib/tcp.c b/lib/tcp.c index 063e9b2..ce071cd 100644 --- a/lib/tcp.c +++ b/lib/tcp.c @@ -24,24 +24,6 @@ #include #endif -static void -_conn_timeout_cb (int fd, short event, void *data) -{ - struct rs_connection *conn; - - assert (data); - conn = (struct rs_connection *) data; - - if (event & EV_TIMEOUT) - { - rs_debug (("%s: connection timeout on %p (fd %d) connecting to %p\n", - __func__, conn, conn->fd, conn->active_peer)); - conn->is_connecting = 0; - rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL); - event_loopbreak (conn); - } -} - /* Read one RADIUS packet header. Return !0 on error. A return value of 0 means that we need more data. */ static int @@ -191,6 +173,8 @@ tcp_event_cb (struct bufferevent *bev, short events, void *user_data) conn->is_connecting = 0; if (events & BEV_EVENT_CONNECTED) { + if (conn->tev) + evtimer_del (conn->tev); /* Cancel connect timer. */ event_on_connect (conn, pkt); } else if (events & BEV_EVENT_EOF) @@ -255,13 +239,16 @@ tcp_write_cb (struct bufferevent *bev, void *ctx) } int -tcp_set_connect_timeout (struct rs_connection *conn) +tcp_init_connect_timer (struct rs_connection *conn) { - if (!conn->tev) - conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); + assert (conn); + + if (conn->tev) + event_free (conn->tev); + conn->tev = evtimer_new (conn->evb, event_conn_timeout_cb, conn); if (!conn->tev) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "evtimer_new"); - evtimer_add (conn->tev, &conn->timeout); + return RSE_OK; } diff --git a/lib/tcp.h b/lib/tcp.h index 8f519bb..fc2c4df 100644 --- a/lib/tcp.h +++ b/lib/tcp.h @@ -4,4 +4,4 @@ void tcp_event_cb (struct bufferevent *bev, short events, void *user_data); void tcp_read_cb (struct bufferevent *bev, void *user_data); void tcp_write_cb (struct bufferevent *bev, void *ctx); -int tcp_set_connect_timeout (struct rs_connection *conn); +int tcp_init_connect_timer (struct rs_connection *conn); diff --git a/lib/udp.c b/lib/udp.c index c602cbd..ac4e487 100644 --- a/lib/udp.c +++ b/lib/udp.c @@ -107,3 +107,18 @@ udp_init (struct rs_connection *conn, struct rs_packet *pkt) } return RSE_OK; } + +int +udp_init_retransmit_timer (struct rs_connection *conn) +{ + assert (conn); + + if (conn->tev) + event_free (conn->tev); + conn->tev = evtimer_new (conn->evb, event_retransmit_timeout_cb, conn); + if (!conn->tev) + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, + "evtimer_new"); + + return RSE_OK; +} diff --git a/lib/udp.h b/lib/udp.h index a2a7228..338e7c2 100644 --- a/lib/udp.h +++ b/lib/udp.h @@ -2,3 +2,4 @@ See the file COPYING for licensing information. */ int udp_init (struct rs_connection *conn, struct rs_packet *pkt); +int udp_init_retransmit_timer (struct rs_connection *conn);