Add retransmission timer support (UDP).
authorLinus Nordberg <linus@nordu.net>
Wed, 9 Mar 2011 09:18:06 +0000 (10:18 +0100)
committerLinus Nordberg <linus@nordu.net>
Wed, 9 Mar 2011 09:18:06 +0000 (10:18 +0100)
lib/conn.c
lib/event.c
lib/event.h
lib/packet.c
lib/peer.h
lib/radsec.c
lib/send.c
lib/tcp.c
lib/tcp.h
lib/udp.c
lib/udp.h

index 85cd7d5..3981f6a 100644 (file)
@@ -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;
+}
index 55a7e6b..5afba98 100644 (file)
@@ -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;
 
index e5ea90c..e042599 100644 (file)
@@ -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);
index 799234f..2611b46 100644 (file)
@@ -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;
index f430bb2..a326325 100644 (file)
@@ -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);
index ddd4edd..ec43b2f 100644 (file)
@@ -20,6 +20,7 @@
 #if defined (RS_ENABLE_TLS)
 #include <regex.h>
 #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
index f169ff9..0872471 100644 (file)
@@ -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)
index 063e9b2..ce071cd 100644 (file)
--- a/lib/tcp.c
+++ b/lib/tcp.c
 #include <event2/buffer.h>
 #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;
 }
index 8f519bb..fc2c4df 100644 (file)
--- 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);
index c602cbd..ac4e487 100644 (file)
--- 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;
+}
index a2a7228..338e7c2 100644 (file)
--- 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);