Config file changes and small API changes.
authorLinus Nordberg <linus@nordberg.se>
Thu, 24 Feb 2011 21:25:22 +0000 (22:25 +0100)
committerLinus Nordberg <linus@nordberg.se>
Thu, 24 Feb 2011 21:25:22 +0000 (22:25 +0100)
'timeout' and 'tries' move from 'server' stanza to top.  'tries' is
now 'retries'.
Moving around in internal data structs, making struct peer strictly config.
Bug fixes in configuration code.
Adding some more cleanup code, freeing allocated memory (still not done!).

lib/Makefile.am
lib/conf.c
lib/conn.c
lib/err.c
lib/include/radsec/radsec-impl.h
lib/include/radsec/radsec.h
lib/packet.c
lib/radsec.c

index a76de88..d43198b 100644 (file)
@@ -31,4 +31,4 @@ libradsec_la_SOURCES += \
 endif
 
 libradsec_la_LDFLAGS = -version-info 0:0:0
-libradsec_la_CFLAGS = $(AM_CFLAGS) #-DDEBUG -DDEBUG_LEVENT 
+libradsec_la_CFLAGS = $(AM_CFLAGS) #-DDEBUG -DDEBUG_LEVENT -Werror
index 8519922..5c1c51b 100644 (file)
@@ -8,11 +8,14 @@
 #include <string.h>
 #include <radsec/radsec.h>
 #include <radsec/radsec-impl.h>
+#include "debug.h"
 
 #if 0
-  # example of client config
+  # client config options
   config NAME {
       type = "UDP"|"TCP"|"TLS"|"DTLS"
+      timeout = INT
+      retries = INT
       cacertfile = STRING
       #cacertpath = STRING
       certfile = STRING
@@ -21,8 +24,6 @@
           hostname = STRING
          service = STRING
          secret = STRING
-         timeout = INT         /* optional */
-         tries = INT           /* optional */
       }
   }
 #endif
 int
 rs_context_read_config(struct rs_context *ctx, const char *config_file)
 {
-#warning "Missing some error handling in rs_context_read_config()"
+
+  /* FIXME: Missing some error handling in rs_context_read_config().  */
+
   cfg_opt_t server_opts[] =
     {
       CFG_STR ("hostname", NULL, CFGF_NONE),
       CFG_STR ("service", "radius", CFGF_NONE),
       CFG_STR ("secret", NULL, CFGF_NONE),
-      CFG_INT ("timeout", 3, CFGF_NONE),
-      CFG_INT ("tries", 1, CFGF_NONE),
       CFG_END ()
     };
   cfg_opt_t config_opts[] =
     {
       CFG_STR ("type", "UDP", CFGF_NONE),
+      CFG_INT ("timeout", 2, CFGF_NONE),
+      CFG_INT ("retries", 2, CFGF_NONE),
       CFG_STR ("cacertfile", NULL, CFGF_NONE),
       /*CFG_STR ("cacertpath", NULL, CFGF_NONE),*/
       CFG_STR ("certfile", NULL, CFGF_NONE),
@@ -70,8 +73,13 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file)
       if (!r)
        return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
       memset (r, 0, sizeof(*r));
-      r->next = ctx->realms->next;
-      ctx->realms->next = r;
+      if (ctx->realms)
+       {
+         r->next = ctx->realms->next;
+         ctx->realms->next = r;
+       }
+      else
+         ctx->realms = r;
       cfg_config = cfg_getnsec (cfg, "config", i);
       r->name = strdup (cfg_title (cfg_config));
 
@@ -87,6 +95,8 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file)
       else
        return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__,
                                   "invalid connection type: %s", typestr);
+      r->timeout = cfg_getint (cfg_config, "timeout");
+      r->retries = cfg_getint (cfg_config, "retries");
 
       r->cacertfile = cfg_getstr (cfg_config, "cacertfile");
       /*r->cacertpath = cfg_getstr (cfg_config, "cacertpath");*/
@@ -106,8 +116,6 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file)
          _rs_resolv (&p->addr, r->type, cfg_getstr (cfg_server, "hostname"),
                      cfg_getstr (cfg_server, "service"));
          p->secret = strdup (cfg_getstr (cfg_server, "secret"));
-         p->timeout = cfg_getint (cfg_server, "timeout");
-         p->tries = cfg_getint (cfg_server, "tries");
        }
     }
   return RSE_OK;
@@ -118,7 +126,7 @@ rs_conf_find_realm(struct rs_context *ctx, const char *name)
 {
   struct rs_realm *r;
 
-  for (r = ctx->realms->next; r != ctx->realms; r = r->next)
+  for (r = ctx->realms; r; r = r->next)
     if (!strcmp (r->name, name))
        return r;
   return NULL;
index 717eba6..784c316 100644 (file)
@@ -18,37 +18,50 @@ rs_conn_create (struct rs_context *ctx, struct rs_connection **conn,
   struct rs_connection *c;
 
   c = (struct rs_connection *) malloc (sizeof(struct rs_connection));
-  if (c)
+  if (!c)
+    return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
+
+  memset (c, 0, sizeof(struct rs_connection));
+  c->ctx = ctx;
+  c->fd = -1;
+  if (config)
     {
-      memset (c, 0, sizeof(struct rs_connection));
-      c->ctx = ctx;
-      if (config)
+      struct rs_realm *r = rs_conf_find_realm (ctx, config);
+      if (r)
+       {
+         struct rs_peer *p;
+
+         c->realm = r;
+         c->peers = r->peers;  /* FIXME: Copy instead?  */
+         for (p = c->peers; p; p = p->next)
+           p->conn = c;
+         c->tryagain = r->retries;
+       }
+      else
        {
-         struct rs_realm *r = rs_conf_find_realm (ctx, config);
-         if (r)
-           {
-             struct rs_peer *p;
-
-             c->type = r->type;
-             c->peers = r->peers; /* FIXME: Copy instead?  */
-             for (p = c->peers; p; p = p->next)
-               p->conn = c;
-           }
+         c->realm = rs_malloc (ctx, sizeof (struct rs_realm));
+         if (!c->realm)
+           return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__,
+                                      NULL);
+         memset (c->realm, 0, sizeof (struct rs_realm));
        }
     }
+
   if (conn)
     *conn = c;
-  return c ? RSE_OK : rs_err_ctx_push (ctx, RSE_NOMEM, NULL);
+  return RSE_OK;
 }
 
 void
 rs_conn_set_type (struct rs_connection *conn, rs_conn_type_t type)
 {
-  conn->type = type;
+  assert (conn);
+  assert (conn->realm);
+  conn->realm->type = type;
 }
 
 
-struct rs_error *
+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)
 {
@@ -74,6 +87,8 @@ _rs_resolv (struct evutil_addrinfo **addr, rs_conn_type_t type,
       hints.ai_socktype = SOCK_DGRAM;
       hints.ai_protocol = IPPROTO_UDP;
       break;
+    default:
+      return _rs_err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL);
     }
   err = evutil_getaddrinfo (hostname, service, &hints, &res);
   if (err)
@@ -100,8 +115,8 @@ rs_conn_disconnect (struct rs_connection *conn)
 
   assert (conn);
 
-  err = evutil_closesocket (conn->active_peer->fd);
-  conn->active_peer->fd = -1;
+  err = evutil_closesocket (conn->fd);
+  conn->fd = -1;
   return err;
 }
 
@@ -113,13 +128,15 @@ rs_conn_destroy (struct rs_connection *conn)
 
   assert (conn);
 
-  if (conn->active_peer->is_connected)
+  if (conn->is_connected)
     {
       err = rs_conn_disconnect (conn);
       if (err)
        return err;
     }
 
+  /* NOTE: conn->realm is owned by context.  */
+
   for (p = conn->peers; p; p = p->next)
     {
       if (p->addr)
@@ -128,6 +145,8 @@ rs_conn_destroy (struct rs_connection *conn)
        rs_free (conn->ctx, p->secret);
     }
 
+  if (conn->tev)
+    event_free (conn->tev);
   if (conn->evb)
     event_base_free (conn->evb);
 
@@ -183,5 +202,5 @@ int rs_conn_fd (struct rs_connection *conn)
 {
   assert (conn);
   assert (conn->active_peer);
-  return conn->active_peer->fd;
+  return conn->fd;
 }
index a7ddeb9..1ad76a6 100644 (file)
--- a/lib/err.c
+++ b/lib/err.c
@@ -27,7 +27,7 @@ static const char *_errtxt[] = {
   "internal error",            /* 13 RSE_INTERNAL */
   "SSL error",                 /* 14 RSE_SSLERR */
   "invalid packet",            /* 15 RSE_INVALID_PKT */
-  "ERR 16",                    /*  RSE_ */
+  "I/O timeout",               /* 16 RSE_IOTIMEOUT */
   "ERR 17",                    /*  RSE_ */
   "ERR 18",                    /*  RSE_ */
   "ERR 19",                    /*  RSE_ */
@@ -177,6 +177,15 @@ rs_err_conn_pop (struct rs_connection *conn)
   return err;
 }
 
+int
+rs_err_conn_peek_code (struct rs_connection *conn)
+{
+  if (conn && conn->err)
+    return conn->err->code;
+  else
+    return RSE_OK;
+}
+
 void
 rs_err_free (struct rs_error *err)
 {
index 14801ab..b5dafef 100644 (file)
@@ -23,8 +23,6 @@ typedef unsigned int rs_cred_type_t;
 extern "C" {
 #endif
 
-struct rs_packet;
-
 struct rs_credentials {
     enum rs_cred_type type;
     char *identity;
@@ -37,22 +35,19 @@ struct rs_error {
     char buf[1024];
 };
 
-struct rs_peer {
+struct rs_peer {               /* Config object for a connection.  */
     struct rs_connection *conn;
     struct rs_realm *realm;
     struct evutil_addrinfo *addr;
-    int fd;                    /* Socket.  */
-    char is_connecting;                /* FIXME: replace with a single state member */
-    char is_connected;         /* FIXME: replace with a single state member */
     char *secret;
-    int timeout;               /* client only */
-    int tries;                 /* client only */
     struct rs_peer *next;
 };
 
-struct rs_realm {
+struct rs_realm {            /* Config object for a RADIUS realm.  */
     char *name;
     enum rs_conn_type type;
+    int timeout;
+    int retries;
     char *cacertfile;
     char *cacertpath;
     char *certfile;
@@ -70,15 +65,20 @@ struct rs_context {
 
 struct rs_connection {
     struct rs_context *ctx;
-    struct event_base *evb;
-    struct bufferevent *bev;
-    enum rs_conn_type type;
+    struct rs_realm *realm;    /* Owned by ctx.  */
+    struct event_base *evb;    /* Event base.  */
+    struct bufferevent *bev;   /* Buffer event.  */
+    struct event *tev;         /* Timeout event.  */
     struct rs_credentials transport_credentials;
     struct rs_conn_callbacks callbacks;
     void *user_data;
     struct rs_peer *peers;
     struct rs_peer *active_peer;
     struct rs_error *err;
+    char is_connecting;                /* FIXME: replace with a single state member */
+    char is_connected;         /* FIXME: replace with a single state member */
+    int fd;                    /* Socket.  */
+    int tryagain;
     int nextid;
     int user_dispatch_flag : 1;        /* User does the dispatching.  */
 #if defined(RS_ENABLE_TLS)
@@ -125,6 +125,8 @@ int _rs_err_conn_push_err(struct rs_connection *conn,
     (h->alloc_scheme.free ? h->alloc_scheme.free : free)(ptr)
 #define rs_realloc(h, realloc, ptr, size) \
     (h->alloc_scheme.realloc ? h->alloc_scheme.realloc : realloc)(ptr, size)
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
 
 /* Local Variables: */
 /* c-file-style: "stroustrup" */
index d609118..c929111 100644 (file)
@@ -21,6 +21,7 @@ enum rs_err_code {
     RSE_INTERNAL = 13,
     RSE_SSLERR = 14,           /* OpenSSL error.  */
     RSE_INVALID_PKT = 15,
+    RSE_IOTIMEOUT = 16,
     RSE_SOME_ERROR = 21,  /* Unspecified error.  Shouldn't happen.  */
 };
 
@@ -115,7 +116,7 @@ int rs_server_set_address(struct rs_peer *server, const char *hostname,
                          const char *service);
 int rs_server_set_secret(struct rs_peer *server, const char *secret);
 void rs_server_set_timeout(struct rs_peer *server, int timeout);
-void rs_server_set_tries(struct rs_peer *server, int tries);
+void rs_server_set_retries(struct rs_peer *server, int retries);
 
 /* Packet.  */
 int rs_packet_create(struct rs_connection *conn, struct rs_packet **pkt_out);
@@ -149,6 +150,7 @@ int rs_err_conn_push(struct rs_connection *conn, int code, const char *fmt,
 int rs_err_conn_push_fl(struct rs_connection *conn, int code,
                        const char *file, int line, const char *fmt, ...);
 struct rs_error *rs_err_conn_pop(struct rs_connection *conn);
+int rs_err_conn_peek_code (struct rs_connection *conn);
 void rs_err_free(struct rs_error *err);
 char *rs_err_msg(struct rs_error *err, int dofree_flag);
 int rs_err_code(struct rs_error *err, int dofree_flag);
index 9c6edf2..c8f4af1 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
+#include <sys/time.h>
 #include <assert.h>
 #include <freeradius/libradius.h>
 #include <event2/event.h>
@@ -63,14 +65,14 @@ _do_send (struct rs_packet *pkt)
   if (err < 0)
     return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
                                "bufferevent_write: %s",
-                               evutil_gai_strerror(err));
+                               evutil_gai_strerror (err));
   return RSE_OK;
 }
 
 static void
 _on_connect (struct rs_connection *conn)
 {
-  conn->active_peer->is_connected = 1;
+  conn->is_connected = 1;
   rs_debug (("%s: %p connected\n", __func__, conn->active_peer));
   if (conn->callbacks.connected_cb)
     conn->callbacks.connected_cb (conn->user_data);
@@ -79,7 +81,8 @@ _on_connect (struct rs_connection *conn)
 static void
 _on_disconnect (struct rs_connection *conn)
 {
-  conn->active_peer->is_connected = 0;
+  conn->is_connecting = 0;
+  conn->is_connected = 0;
   rs_debug (("%s: %p disconnected\n", __func__, conn->active_peer));
   if (conn->callbacks.disconnected_cb)
     conn->callbacks.disconnected_cb (conn->user_data);
@@ -89,11 +92,11 @@ static void
 _event_cb (struct bufferevent *bev, short events, void *ctx)
 {
   struct rs_packet *pkt = (struct rs_packet *)ctx;
-  struct rs_connection *conn;
-  struct rs_peer *p;
-  int sockerr;
+  struct rs_connection *conn = NULL;
+  struct rs_peer *p = NULL;
+  int sockerr = 0;
 #if defined (RS_ENABLE_TLS)
-  unsigned long tlserr;
+  unsigned long tlserr = 0;
 #endif
 
   assert (pkt);
@@ -102,7 +105,7 @@ _event_cb (struct bufferevent *bev, short events, void *ctx)
   conn = pkt->conn;
   p = conn->active_peer;
 
-  p->is_connecting = 0;
+  conn->is_connecting = 0;
   if (events & BEV_EVENT_CONNECTED)
     {
       _on_connect (conn);
@@ -113,6 +116,12 @@ _event_cb (struct bufferevent *bev, short events, void *ctx)
     {
       _on_disconnect (conn);
     }
+  else if (events & BEV_EVENT_TIMEOUT)
+    {
+      rs_debug (("%s: %p times out on %s\n", __func__, p,
+                (events & BEV_EVENT_READING) ? "read" : "write"));
+      rs_err_conn_push_fl (pkt->conn, RSE_IOTIMEOUT, __FILE__, __LINE__, NULL);
+    }
   else if (events & BEV_EVENT_ERROR)
     {
       sockerr = evutil_socket_geterror (conn->active_peer->fd);
@@ -124,11 +133,12 @@ _event_cb (struct bufferevent *bev, short events, void *ctx)
        {
          rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__,
                               "%d: socket error %d (%s)",
-                              conn->active_peer->fd,
+                              conn->fd,
                               sockerr,
                               evutil_socket_error_to_string (sockerr));
-         rs_debug (("%s: socket error on fd %d: %d\n", __func__,
-                    conn->active_peer->fd,
+         rs_debug (("%s: socket error on fd %d: %s (%d)\n", __func__,
+                    conn->fd,
+                    evutil_socket_error_to_string (sockerr),
                     sockerr));
        }
 #if defined (RS_ENABLE_TLS)
@@ -146,6 +156,11 @@ _event_cb (struct bufferevent *bev, short events, void *ctx)
        }
 #endif /* RS_ENABLE_TLS */
     }
+
+#if defined (DEBUG)
+  if (events & BEV_EVENT_ERROR && events != BEV_EVENT_ERROR)
+    rs_debug (("%s: BEV_EVENT_ERROR and more: 0x%x\n", __func__, events));
+#endif
 }
 
 static void
@@ -308,7 +323,7 @@ _read_cb (struct bufferevent *bev, void *ctx)
   assert (pkt->conn);
   assert (pkt->rpkt);
 
-  pkt->rpkt->sockfd = pkt->conn->active_peer->fd;
+  pkt->rpkt->sockfd = pkt->conn->fd;
   pkt->rpkt->vps = NULL;
 
   if (!pkt->hdr_read_flag)
@@ -348,35 +363,37 @@ _evlog_cb (int severity, const char *msg)
 static int
 _init_evb (struct rs_connection *conn)
 {
-  if (!conn->evb)
-    {
+  if (conn->evb)
+    return RSE_OK;
+
 #if defined (DEBUG)
-      event_enable_debug_mode ();
+  event_enable_debug_mode ();
 #endif
-      event_set_log_callback (_evlog_cb);
-      conn->evb = event_base_new ();
-      if (!conn->evb)
-       return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
-                                   "event_base_new");
-    }
+  event_set_log_callback (_evlog_cb);
+  conn->evb = event_base_new ();
+  if (!conn->evb)
+    return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
+                               "event_base_new");
+
   return RSE_OK;
 }
 
 static int
 _init_socket (struct rs_connection *conn, struct rs_peer *p)
 {
-  if (p->fd != -1)
+  if (conn->fd != -1)
     return RSE_OK;
 
   assert (p->addr);
-  p->fd = socket (p->addr->ai_family, p->addr->ai_socktype,
-                 p->addr->ai_protocol);
-  if (p->fd < 0)
+  conn->fd = socket (p->addr->ai_family, p->addr->ai_socktype,
+                    p->addr->ai_protocol);
+  if (conn->fd < 0)
     return rs_err_conn_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
                                strerror (errno));
-  if (evutil_make_socket_nonblocking (p->fd) < 0)
+  if (evutil_make_socket_nonblocking (conn->fd) < 0)
     {
-      evutil_closesocket (p->fd);
+      evutil_closesocket (conn->fd);
+      conn->fd = -1;
       return rs_err_conn_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
                                  strerror (errno));
     }
@@ -386,8 +403,13 @@ _init_socket (struct rs_connection *conn, struct rs_peer *p)
 static struct rs_peer *
 _pick_peer (struct rs_connection *conn)
 {
+  assert (conn);
+
+  if (conn->active_peer)
+    conn->active_peer = conn->active_peer->next; /* Next.  */
   if (!conn->active_peer)
-    conn->active_peer = conn->peers;
+    conn->active_peer = conn->peers; /* From the top.  */
+
   return conn->active_peer;
 }
 
@@ -397,15 +419,20 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer)
   if (conn->bev)
     return RSE_OK;
 
-  switch (conn->type)
+  switch (conn->realm->type)
     {
     case RS_CONN_TYPE_UDP:
+      /* Fall through.  */
+      /* NOTE: We know this is wrong for several reasons, most notably
+        because libevent doesn't work as expected with UDP.  The
+        timeout handling is wrong too.  */
     case RS_CONN_TYPE_TCP:
-      conn->bev = bufferevent_socket_new (conn->evb, peer->fd, 0);
+      conn->bev = bufferevent_socket_new (conn->evb, conn->fd, 0);
       if (!conn->bev)
        return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
                                    "bufferevent_socket_new");
       break;
+
 #if defined (RS_ENABLE_TLS)
     case RS_CONN_TYPE_TLS:
       if (rs_tls_init (conn))
@@ -414,62 +441,79 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer)
         seem to break when be_openssl_ctrl() (in libevent) calls
         SSL_set_bio() after BIO_new_socket() with flag=1.  */
       conn->bev =
-       bufferevent_openssl_socket_new (conn->evb, peer->fd, conn->tls_ssl,
+       bufferevent_openssl_socket_new (conn->evb, conn->fd, conn->tls_ssl,
                                        BUFFEREVENT_SSL_CONNECTING, 0);
       if (!conn->bev)
        return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
                                    "bufferevent_openssl_socket_new");
-
       break;
+
     case RS_CONN_TYPE_DTLS:
       return rs_err_conn_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
                                  "%s: NYI", __func__);
 #endif /* RS_ENABLE_TLS */
+
     default:
       return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__,
                                  "%s: unknown connection type: %d", __func__,
-                                 conn->type);
+                                 conn->realm->type);
     }
 
   return RSE_OK;
 }
 
 static void
-_do_connect (struct rs_peer *p)
+_do_connect (struct rs_connection *conn)
 {
+  struct rs_peer *p;
   int err;
 
+  assert (conn);
+  assert (conn->active_peer);
+  p = conn->active_peer;
+
+#if defined (DEBUG)
+  {
+    char host[80], serv[80];
+
+    getnameinfo (p->addr->ai_addr,
+                p->addr->ai_addrlen,
+                host, sizeof(host), serv, sizeof(serv),
+                0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
+    rs_debug (("%s: connecting to %s:%s\n", __func__, host, serv));
+  }
+#endif
+
   err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
                                    p->addr->ai_addrlen);
   if (err < 0)
     rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
                         "bufferevent_socket_connect: %s",
-                        evutil_gai_strerror(err));
+                        evutil_gai_strerror (err));
   else
-    p->is_connecting = 1;
+    p->conn->is_connecting = 1;
 }
 
 static int
 _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
 {
-  struct rs_peer *p;
-
   if (_init_evb (conn))
     return -1;
 
-  p = _pick_peer (conn);
-  if (!p)
+  if (!conn->active_peer)
+    _pick_peer (conn);
+  if (!conn->active_peer)
     return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
 
-  if (_init_socket (conn, p))
+  if (_init_socket (conn, conn->active_peer))
     return -1;
 
-  if (_init_bev (conn, p))
+  if (_init_bev (conn, conn->active_peer))
     return -1;
 
-  if (!p->is_connected)
-    if (!p->is_connecting)
-      _do_connect (p);
+  if (!conn->is_connected)
+    if (!conn->is_connecting)
+      _do_connect (conn);
 
   return RSE_OK;
 }
@@ -477,7 +521,7 @@ _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
 static int
 _conn_is_open_p (struct rs_connection *conn)
 {
-  return conn->active_peer && conn->active_peer->is_connected;
+  return conn->active_peer && conn->is_connected;
 }
 
 /* Public functions.  */
@@ -553,14 +597,14 @@ _wcb (void *user_data)
   if (err < 0)
     rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
                         "event_base_loopbreak: %s",
-                        evutil_gai_strerror(err));
+                        evutil_gai_strerror (err));
 }
 
 int
 rs_packet_send (struct rs_packet *pkt, void *user_data)
 {
   struct rs_connection *conn = NULL;
-  int err = RSE_OK;
+  int err = 0;
 
   assert (pkt);
   assert (pkt->conn);
@@ -575,7 +619,7 @@ rs_packet_send (struct rs_packet *pkt, void *user_data)
   assert (conn->evb);
   assert (conn->bev);
   assert (conn->active_peer);
-  assert (conn->active_peer->fd >= 0);
+  assert (conn->fd >= 0);
 
   conn->user_data = user_data;
   bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt);
@@ -590,7 +634,7 @@ rs_packet_send (struct rs_packet *pkt, void *user_data)
       if (err < 0)
        return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
                                    "event_base_dispatch: %s",
-                                   evutil_gai_strerror(err));
+                                   evutil_gai_strerror (err));
       rs_debug (("%s: event loop done\n", __func__));
       conn->callbacks.sent_cb = NULL;
       conn->user_data = NULL;
@@ -613,7 +657,7 @@ _rcb (struct rs_packet *packet, void *user_data)
   if (err < 0)
     rs_err_conn_push_fl (packet->conn, RSE_EVENT, __FILE__, __LINE__,
                         "event_base_loopbreak: %s",
-                        evutil_gai_strerror(err));
+                        evutil_gai_strerror (err));
 }
 
 /* Special function used in libradsec blocking dispatching mode,
@@ -636,10 +680,11 @@ rs_conn_receive_packet (struct rs_connection *conn,
                        struct rs_packet *request,
                        struct rs_packet **pkt_out)
 {
-  int err = RSE_OK;
+  int err = 0;
   struct rs_packet *pkt = NULL;
 
   assert (conn);
+  assert (conn->realm);
   assert (!conn->user_dispatch_flag); /* Dispatching mode only.  */
 
   if (rs_packet_create (conn, pkt_out))
@@ -648,36 +693,35 @@ rs_conn_receive_packet (struct rs_connection *conn,
   pkt->conn = conn;
   pkt->original = request;
 
-  if (_conn_open (conn, pkt))
-    return -1;
   assert (conn->evb);
   assert (conn->bev);
   assert (conn->active_peer);
-  assert (conn->active_peer->fd >= 0);
+  assert (conn->fd >= 0);
 
-  /* Install read and event callbacks with libevent.  */
+  /* Install callbacks with libevent.  */
   bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0);
   bufferevent_enable (conn->bev, EV_READ);
   bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt);
 
-  /* Install read callback with ourselves, for signaling successful
-     reception of message.  */
+  /* Install read callback with ourselves, for breaking event
+     loop upon reception of a valid packet.  */
   conn->callbacks.received_cb = _rcb;
 
   /* Dispatch.  */
   rs_debug (("%s: entering event loop\n", __func__));
   err = event_base_dispatch (conn->evb);
+  conn->callbacks.received_cb = NULL;
   if (err < 0)
     return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
                                "event_base_dispatch: %s",
-                               evutil_gai_strerror(err));
+                               evutil_gai_strerror (err));
   rs_debug (("%s: event loop done\n", __func__));
-  conn->callbacks.received_cb = NULL;
+
   if (!event_base_got_break (conn->evb))
     return -1;
 
 #if defined (DEBUG)
-  rs_dump_packet (pkt);
+      rs_dump_packet (pkt);
 #endif
 
   pkt->original = NULL;                /* FIXME: Why?  */
index 16a554f..c821566 100644 (file)
@@ -18,6 +18,7 @@
 #include <radsec/radsec-impl.h>
 #if defined (RS_ENABLE_TLS)
 #include <regex.h>
+#include "debug.h"
 #include "rsp_list.h"
 #include "../radsecproxy.h"
 #endif
@@ -69,14 +70,6 @@ rs_context_create(struct rs_context **ctx, const char *dict)
   debug_init ("libradsec");    /* radsecproxy compat, FIXME: remove */
 
   memset (h, 0, sizeof(struct rs_context));
-  h->realms = malloc (sizeof (struct rs_realm));
-  if (!h->realms)
-    {
-      err = RSE_NOMEM;
-      goto err_out;
-    }
-  memset (h->realms, 0, sizeof (struct rs_realm));
-  h->realms->next = h->realms;
   fr_randinit (&h->fr_randctx, 0);
   fr_rand_seed (NULL, 0);
 
@@ -95,19 +88,6 @@ rs_context_create(struct rs_context **ctx, const char *dict)
   return err;
 }
 
-void rs_context_destroy(struct rs_context *ctx)
-{
-  free (ctx);
-}
-
-int rs_context_set_alloc_scheme(struct rs_context *ctx,
-                               struct rs_alloc_scheme *scheme)
-{
-  return rs_err_ctx_push_fl (ctx, RSE_NOSYS, __FILE__, __LINE__,
-                            "%s: NYI", __func__);
-}
-
-
 struct rs_peer *
 _rs_peer_create (struct rs_context *ctx, struct rs_peer **rootp)
 {
@@ -117,15 +97,59 @@ _rs_peer_create (struct rs_context *ctx, struct rs_peer **rootp)
   if (p)
     {
       memset (p, 0, sizeof(struct rs_peer));
-      p->fd = -1;
       if (*rootp)
-       (*rootp)->next = p;
+       {
+         p->next = (*rootp)->next;
+         (*rootp)->next = p;
+       }
       else
        *rootp = p;
     }
   return p;
 }
 
+static void
+_rs_peer_destroy (struct rs_peer *p)
+{
+  assert (p);
+  assert (p->conn);
+  assert (p->conn->ctx);
+  /* NOTE: The peer object doesn't own its connection (conn).  */
+  if (p->addr)
+    {
+      evutil_freeaddrinfo (p->addr);
+      p->addr = NULL;
+    }
+  rs_free (p->conn->ctx, p);
+}
+
+void rs_context_destroy(struct rs_context *ctx)
+{
+  struct rs_realm *r = NULL;
+  struct rs_peer *p = NULL;
+
+  for (r = ctx->realms; r; )
+    {
+      struct rs_realm *tmp = r;
+      for (p = r->peers; p; )
+       {
+         struct rs_peer *tmp = p;
+         p = p->next;
+         _rs_peer_destroy (tmp);
+       }
+      r = r->next;
+      rs_free (ctx, tmp);
+    }
+  rs_free (ctx, ctx);
+}
+
+int rs_context_set_alloc_scheme(struct rs_context *ctx,
+                               struct rs_alloc_scheme *scheme)
+{
+  return rs_err_ctx_push_fl (ctx, RSE_NOSYS, __FILE__, __LINE__,
+                            "%s: NYI", __func__);
+}
+
 int
 rs_server_create (struct rs_connection *conn, struct rs_peer **server)
 {
@@ -135,8 +159,8 @@ rs_server_create (struct rs_connection *conn, struct rs_peer **server)
   if (srv)
     {
       srv->conn = conn;
-      srv->timeout = 1;
-      srv->tries = 3;
+      srv->realm->timeout = 2;
+      srv->realm->retries = 2;
     }
   else
     return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
@@ -151,7 +175,10 @@ rs_server_set_address (struct rs_peer *server, const char *hostname,
 {
   struct rs_error *err;
 
-  err = _rs_resolv (&server->addr, server->conn->type, hostname, service);
+  assert (server);
+  assert (server->realm);
+
+  err = _rs_resolv (&server->addr, server->realm->type, hostname, service);
   if (err)
     return _rs_err_conn_push_err (server->conn, err);
   return RSE_OK;
@@ -160,12 +187,16 @@ rs_server_set_address (struct rs_peer *server, const char *hostname,
 void
 rs_server_set_timeout (struct rs_peer *server, int timeout)
 {
-  server->timeout = timeout;
+  assert (server);
+  assert (server->realm);
+  server->realm->timeout = timeout;
 }
 void
-rs_server_set_tries (struct rs_peer *server, int tries)
+rs_server_set_retries (struct rs_peer *server, int retries)
 {
-  server->tries = tries;
+  assert (server);
+  assert (server->realm);
+  server->realm->retries = retries;
 }
 
 int