Revamping for listeners.
authorLinus Nordberg <linus@nordberg.se>
Fri, 1 Mar 2013 13:34:21 +0000 (14:34 +0100)
committerLinus Nordberg <linus@nordberg.se>
Fri, 1 Mar 2013 13:34:21 +0000 (14:34 +0100)
Split rs_connection into rs_baseconn plus rs_connection and rs_listener.

Connections now has a state variable.

Connect buffer event and fd of _source_ connection, not that of
conn->active_peer. The connection object referred to by a peer is not
meant for using as a connection, only for reporting errors on.

Make sure things are sane even when not using a config file.

Bump library interface version to 1.0.0 since it's changed.

17 files changed:
lib/Makefile.am
lib/conn.c
lib/err.c
lib/err.h
lib/event.c
lib/examples/client-blocking.c
lib/include/radsec/radsec-impl.h
lib/include/radsec/radsec.h
lib/message.c
lib/peer.c
lib/peer.h
lib/radsec.sym
lib/send.c
lib/tcp.c
lib/tls.c
lib/udp.c
lib/util.c

index 06ea8d5..6d62c97 100644 (file)
@@ -3,19 +3,22 @@ ACLOCAL_AMFLAGS = -I m4
 
 # Shared library interface version, i.e. -version-info to Libtool,
 # expressed as three integers CURRENT:REVISION:AGE.
-
-# CURRENT is the version number of the current interface.  Increment
-#        CURRENT when the library interface changes.
-
+#
+# CURRENT is the version number of the current interface.
+# Increment CURRENT when the library interface changes.
+#
 # REVISION is the version number of the _implementation_ of the
-#          CURRENT interface.  Set REVISION to 0 when CURRENT changes,
-#          else increment.
-
+# CURRENT interface.
+# Set REVISION to 0 when CURRENT changes, else increment.
+#
 # AGE is the number of interfaces this library implements, i.e. how
-#     many versions before CURRENT that are supported.  Increment AGE
-#     when the library interface is _extended_.  Set AGE to 0 when the
-#     library interface is _changed_.
+# many versions before CURRENT that are supported.
+# Increment AGE when the library interface is _extended_.
+# Set AGE to 0 when the library interface is _changed_.
 
+VER_CUR = 1
+VER_REV = 0
+VER_AGE = 0
 
 SUBDIRS = radius radsecproxy . include examples
 
@@ -44,13 +47,19 @@ libradsec_la_SOURCES = \
        util.c
 
 if RS_ENABLE_TLS
-libradsec_la_SOURCES += tls.c
+  libradsec_la_SOURCES += tls.c
 else
-libradsec_la_SOURCES += md5.c
+  libradsec_la_SOURCES += md5.c
 endif
 
 EXTRA_DIST = HACKING LICENSE
 
-libradsec_la_LIBADD = radsecproxy/libradsec-radsecproxy.la radius/libradsec-radius.la
-libradsec_la_LDFLAGS = -version-info 0:0:0 -export-symbols radsec.sym
-libradsec_la_CFLAGS = $(AM_CFLAGS) -DHAVE_CONFIG_H -Werror # -DDEBUG -DDEBUG_LEVENT 
+libradsec_la_CFLAGS = \
+       $(AM_CFLAGS) -DHAVE_CONFIG_H \
+       -DDEBUG -DDEBUG_LEVENT
+libradsec_la_LDFLAGS = \
+       -version-info $(VER_CUR):$(VER_REV):$(VER_AGE) \
+       -export-symbols radsec.sym
+libradsec_la_LIBADD = \
+       radsecproxy/libradsec-radsecproxy.la \
+       radius/libradsec-radius.la
index d8c1569..95e65a4 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.
-   See LICENSE for licensing information.  */
+   See LICENSE for licensing information. */
 
 #if defined HAVE_CONFIG_H
 #include <config.h>
@@ -25,7 +25,7 @@ conn_close (struct rs_connection **connp)
   int r = 0;
   assert (connp);
   assert (*connp);
-  if ((*connp)->is_connected)
+  if ((*connp)->state == RS_CONN_STATE_CONNECTED)
     r = rs_conn_disconnect (*connp);
   if (r == RSE_OK)
     *connp = NULL;
@@ -53,7 +53,7 @@ conn_activate_timeout (struct rs_connection *conn)
   if (conn->base_.timeout.tv_sec || conn->base_.timeout.tv_usec)
     {
       rs_debug (("%s: activating timer: %d.%d\n", __func__,
-                conn->timeout.tv_sec, conn->timeout.tv_usec));
+                conn->base_.timeout.tv_sec, conn->base_.timeout.tv_usec));
       if (evtimer_add (conn->tev, &conn->base_.timeout))
        return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
                                    "evtimer_add: %d", errno);
@@ -64,7 +64,7 @@ conn_activate_timeout (struct rs_connection *conn)
 int
 conn_type_tls (const struct rs_connection *conn)
 {
-  assert (conn->active_peer);
+  assert (conn->base_.active_peer);
   return conn->base_.realm->type == RS_CONN_TYPE_TLS
     || conn->base_.realm->type == RS_CONN_TYPE_DTLS;
 }
@@ -72,9 +72,9 @@ conn_type_tls (const struct rs_connection *conn)
 int
 conn_cred_psk (const struct rs_connection *conn)
 {
-  assert (conn->active_peer);
-  return conn->active_peer->transport_cred &&
-    conn->active_peer->transport_cred->type == RS_CRED_TLS_PSK;
+  assert (conn->base_.active_peer);
+  return conn->base_.active_peer->transport_cred &&
+    conn->base_.active_peer->transport_cred->type == RS_CRED_TLS_PSK;
 }
 
 void
@@ -111,23 +111,21 @@ conn_configure (struct rs_context *ctx,
       struct rs_realm *r = rs_conf_find_realm (ctx, config);
       if (r)
        {
-         struct rs_peer *p;
-
          connbase->realm = r;
          connbase->peers = r->peers; /* FIXME: Copy instead?  */
+#if 0
          for (p = connbase->peers; p != NULL; p = p->next)
-           p->conn = TO_GENERIC_CONN(connbase);
+           p->connbase = connbase;
+#endif
          connbase->timeout.tv_sec = r->timeout;
          connbase->tryagain = r->retries;
        }
-      else
-       {
-         connbase->realm = rs_malloc (ctx, sizeof (struct rs_realm));
-         if (!connbase->realm)
-           return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__,
-                                      NULL);
-         memset (connbase->realm, 0, sizeof (struct rs_realm));
-       }
+    }
+  if (connbase->realm == NULL)
+    {
+      connbase->realm = rs_calloc (ctx, 1, sizeof (struct rs_realm));
+      if (connbase->realm == NULL)
+        return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
     }
   return RSE_OK;
 }
@@ -200,7 +198,7 @@ rs_conn_destroy (struct rs_connection *conn)
   /* NOTE: conn->realm is owned by context.  */
   /* NOTE: conn->peers is owned by context.  */
 
-  if (conn->is_connected)
+  if (conn->state == RS_CONN_STATE_CONNECTED)
     err = rs_conn_disconnect (conn);
 
 #if defined (RS_ENABLE_TLS)
@@ -284,7 +282,7 @@ struct event_base
 int rs_conn_get_fd (struct rs_connection *conn)
 {
   assert (conn);
-  assert (conn->active_peer);
+  assert (conn->base_.active_peer);
   return conn->base_.fd;
 }
 
index e0bcea9..413ab3e 100644 (file)
--- a/lib/err.c
+++ b/lib/err.c
@@ -1,5 +1,5 @@
 /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.
-   See LICENSE for licensing information.  */
+   See LICENSE for licensing information. */
 
 #if defined HAVE_CONFIG_H
 #include <config.h>
@@ -156,26 +156,41 @@ rs_err_ctx_push_fl (struct rs_context *ctx, int code, const char *file,
 }
 
 int
-err_conn_push_err (struct rs_connection *conn, struct rs_error *err)
+err_connbase_push_err (struct rs_conn_base *connbase, struct rs_error *err)
 {
 
-  if (conn->base_.err)
-    rs_err_free (conn->base_.err);
-  conn->base_.err = err;               /* FIXME: use a stack */
+  if (connbase->err)
+    rs_err_free (connbase->err);
+  connbase->err = err;         /* FIXME: use a stack */
 
   return err->code;
 }
 
 static int
-_conn_err_vpush_fl (struct rs_connection *conn, int code, const char *file,
-                   int line, const char *fmt, va_list args)
+_connbase_err_vpush_fl (struct rs_conn_base *connbase, int code,
+                        const char *file, int line, const char *fmt,
+                        va_list args)
 {
   struct rs_error *err = _err_vcreate (code, file, line, fmt, args);
 
   if (!err)
     return RSE_NOMEM;
 
-  return err_conn_push_err (conn, err);
+  return err_connbase_push_err (connbase, err);
+}
+
+int
+rs_err_connbase_push (struct rs_conn_base *connbase, int code,
+                      const char *fmt, ...)
+{
+  int r = 0;
+
+  va_list args;
+  va_start (args, fmt);
+  r = _connbase_err_vpush_fl (connbase, code, NULL, 0, fmt, args);
+  va_end (args);
+
+  return r;
 }
 
 int
@@ -185,7 +200,22 @@ rs_err_conn_push (struct rs_connection *conn, int code, const char *fmt, ...)
 
   va_list args;
   va_start (args, fmt);
-  r = _conn_err_vpush_fl (conn, code, NULL, 0, fmt, args);
+  r = _connbase_err_vpush_fl (TO_BASE_CONN (conn), code, NULL, 0, fmt, args);
+  va_end (args);
+
+  return r;
+}
+
+int
+rs_err_connbase_push_fl (struct rs_conn_base *connbase, int code,
+                         const char *file,
+                         int line, const char *fmt, ...)
+{
+  int r = 0;
+
+  va_list args;
+  va_start (args, fmt);
+  r = _connbase_err_vpush_fl (connbase, code, file, line, fmt, args);
   va_end (args);
 
   return r;
@@ -199,7 +229,7 @@ rs_err_conn_push_fl (struct rs_connection *conn, int code, const char *file,
 
   va_list args;
   va_start (args, fmt);
-  r = _conn_err_vpush_fl (conn, code, file, line, fmt, args);
+  r = _connbase_err_vpush_fl (TO_BASE_CONN (conn), code, file, line, fmt, args);
   va_end (args);
 
   return r;
index 6615ac8..de5851f 100644 (file)
--- a/lib/err.h
+++ b/lib/err.h
@@ -1,9 +1,10 @@
-/* Copyright 2011 NORDUnet A/S. All rights reserved.
-   See LICENSE for licensing information.  */
+/* Copyright 2011,2013 NORDUnet A/S. All rights reserved.
+   See LICENSE for licensing information. */
 
 struct rs_error *err_create (unsigned int code,
                             const char *file,
                             int line,
                             const char *fmt,
                             ...);
-int err_conn_push_err (struct rs_connection *conn, struct rs_error *err);
+int err_connbase_push_err (struct rs_conn_base *, struct rs_error *);
+int rs_err_connbase_push (struct rs_conn_base *, int, const char *, ...);
index f7b936a..c651e4b 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright 2011,2013 NORDUnet A/S. All rights reserved.
-   See LICENSE for licensing information.  */
+   See LICENSE for licensing information. */
 
 #if defined HAVE_CONFIG_H
 #include <config.h>
@@ -72,8 +72,8 @@ event_conn_timeout_cb (int fd, short event, void *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;
+                __func__, conn, conn->base_.fd, conn->base_.active_peer));
+      conn->state = RS_CONN_STATE_UNDEFINED;
       rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL);
       event_loopbreak (conn);
     }
@@ -90,7 +90,7 @@ event_retransmit_timeout_cb (int fd, short event, void *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));
+                __func__, conn, conn->base_.fd, conn->base_.active_peer));
       rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);
       event_loopbreak (conn);
     }
@@ -107,7 +107,7 @@ event_init_socket (struct rs_connection *conn, struct rs_peer *p)
       struct rs_error *err =
         rs_resolve (&p->addr_cache, p->realm->type, p->hostname, p->service);
       if (err != NULL)
-        return err_conn_push_err (conn, err);
+        return err_connbase_push_err (TO_BASE_CONN (conn), err);
     }
 
   conn->base_.fd = socket (p->addr_cache->ai_family, p->addr_cache->ai_socktype,
@@ -171,59 +171,67 @@ event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer)
 void
 event_do_connect (struct rs_connection *conn)
 {
-  struct rs_peer *p;
   int err, sockerr;
+  struct sockaddr *peer_addr;
+  size_t peer_addrlen;
 
   assert (conn);
-  assert (conn->active_peer);
-  p = conn->active_peer;
+  assert (conn->base_.active_peer);
+  assert (conn->base_.active_peer->addr_cache);
+  peer_addr = conn->base_.active_peer->addr_cache->ai_addr;
+  peer_addrlen = conn->base_.active_peer->addr_cache->ai_addrlen;
+
+  /* We don't connect listeners. */
+  assert (conn->base_.magic == RS_CONN_MAGIC_GENERIC);
 
 #if defined (DEBUG)
   {
     char host[80], serv[80];
 
-    getnameinfo (p->addr_cache->ai_addr,
-                p->addr_cache->ai_addrlen,
-                host, sizeof(host), serv, sizeof(serv),
+    getnameinfo (peer_addr, peer_addrlen,
+                host, sizeof(host),
+                 serv, sizeof(serv),
                 0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
     rs_debug (("%s: connecting to %s:%s\n", __func__, host, serv));
   }
 #endif
 
-  if (p->conn->base_.bev)              /* TCP */
+  if (conn->base_.bev)         /* TCP */
     {
       conn_activate_timeout (conn); /* Connect timeout.  */
-      err = bufferevent_socket_connect (p->conn->base_.bev,
-                                        p->addr_cache->ai_addr,
-                                       p->addr_cache->ai_addrlen);
+      err = bufferevent_socket_connect (conn->base_.bev,
+                                        peer_addr, peer_addrlen);
       if (err < 0)
-       rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
-                            "bufferevent_socket_connect: %s",
-                            evutil_gai_strerror (err));
+       rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
+                             "bufferevent_socket_connect: %s",
+                             evutil_gai_strerror (err));
       else
-       p->conn->is_connecting = 1;
+       conn->state = RS_CONN_STATE_CONNECTING;
     }
   else                         /* UDP */
     {
-      err = connect (p->conn->base_.fd,
-                     p->addr_cache->ai_addr,
-                     p->addr_cache->ai_addrlen);
+      err = connect (conn->base_.fd, peer_addr, peer_addrlen);
       if (err < 0)
        {
-         sockerr = evutil_socket_geterror (p->conn->fd);
-         rs_debug (("%s: %d: connect: %d (%s)\n", __func__, p->conn->fd,
+         sockerr = evutil_socket_geterror (conn->base_.fd);
+         rs_debug (("%s: %d: connect: %d (%s)\n", __func__,
+                     conn->base_.fd,
                     sockerr, evutil_socket_error_to_string (sockerr)));
-         rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__,
-                              "%d: connect: %d (%s)", p->conn->base_.fd, sockerr,
+         rs_err_conn_push_fl (conn, RSE_SOCKERR,
+                               __FILE__, __LINE__,
+                               "%d: connect: %d (%s)", conn->base_.fd,
+                               sockerr,
                               evutil_socket_error_to_string (sockerr));
        }
+      else
+       conn->state = RS_CONN_STATE_CONNECTING;
     }
 }
 
 int
 event_loopbreak (struct rs_connection *conn)
 {
-  int err = event_base_loopbreak (conn->base_.ctx->evb);
+  int err = event_base_loopbreak (TO_BASE_CONN(conn)->ctx->evb);
   if (err < 0)
     rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
                         "event_base_loopbreak: %s",
@@ -235,9 +243,9 @@ event_loopbreak (struct rs_connection *conn)
 void
 event_on_disconnect (struct rs_connection *conn)
 {
-  conn->is_connecting = 0;
-  conn->is_connected = 0;
-  rs_debug (("%s: %p disconnected\n", __func__, conn->active_peer));
+  conn->state = RS_CONN_STATE_UNDEFINED;
+  rs_debug (("%s: %p disconnected\n", __func__,
+             TO_BASE_CONN(conn)->active_peer));
   if (conn->callbacks.disconnected_cb)
     conn->callbacks.disconnected_cb (conn->base_.user_data);
 }
@@ -246,8 +254,8 @@ event_on_disconnect (struct rs_connection *conn)
 int
 event_on_connect (struct rs_connection *conn, struct rs_message *msg)
 {
-  assert (!conn->is_connecting);
-  assert (conn->active_peer);
+  assert (conn->state == RS_CONN_STATE_CONNECTING);
+  assert (conn->base_.active_peer);
 
 #if defined (RS_ENABLE_TLS)
   if (conn_type_tls(conn) && !conn_cred_psk(conn))
@@ -258,8 +266,8 @@ event_on_connect (struct rs_connection *conn, struct rs_message *msg)
       }
 #endif /* RS_ENABLE_TLS */
 
-  conn->is_connected = 1;
-  rs_debug (("%s: %p connected\n", __func__, conn->active_peer));
+  conn->state = RS_CONN_STATE_CONNECTED;
+  rs_debug (("%s: %p connected\n", __func__, TO_BASE_CONN(conn)->active_peer));
 
   if (conn->callbacks.connected_cb)
     conn->callbacks.connected_cb (conn->base_.user_data);
index 3ea4b51..d2ee9f4 100644 (file)
@@ -1,7 +1,11 @@
 /* RADIUS/RadSec client using libradsec in blocking mode. */
 
+/* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.
+   See LICENSE for licensing information. */
+
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <assert.h>
 #include <radsec/radsec.h>
 #include <radsec/request.h>
@@ -13,7 +17,7 @@
 #define USER_PW "password"
 
 struct rs_error *
-blocking_client (const char *config_fn, const char *configuration,
+blocking_client (const char *av1, const char *av2, const char *av3,
                  int use_request_object_flag)
 {
   struct rs_context *h = NULL;
@@ -22,6 +26,15 @@ blocking_client (const char *config_fn, const char *configuration,
   struct rs_message *req = NULL, *resp = NULL;
   struct rs_error *err = NULL;
   int r;
+#if defined (USE_CONFIG_FILE)
+  const char *config_fn= av1;
+  const char *configuration = av2;
+#else
+  const char *host = av1;
+  const char *service = av2;
+  const char *proto = av3;
+  struct rs_peer *server;
+#endif
 
   r = rs_context_create (&h);
   if (r)
@@ -31,15 +44,25 @@ blocking_client (const char *config_fn, const char *configuration,
     }
 
 #if !defined (USE_CONFIG_FILE)
+  /* Do it without a configuration file by setting all stuff "by
+   hand".  Doesn't work for TLS at the moment because we don't have an
+   API for setting the X509 cert file names and such. */
   {
-    struct rs_peer *server;
+    int conn_type = RS_CONN_TYPE_UDP;
 
     if (rs_conn_create (h, &conn, NULL))
       goto cleanup;
-    rs_conn_set_type (conn, RS_CONN_TYPE_UDP);
-    if (rs_peer_create (conn, &server))
+    if (proto)
+      {
+        if (!strncmp (proto, "udp", strlen ("udp")))
+          conn_type = RS_CONN_TYPE_UDP;
+        else if (!strncmp (proto, "tls", strlen ("tls")))
+          conn_type = RS_CONN_TYPE_TLS;
+      }
+    rs_conn_set_type (conn, conn_type);
+    if (rs_peer_create_for_conn (conn, &server))
       goto cleanup;
-    if (rs_peer_set_address (server, av1, av2))
+    if (rs_peer_set_address (server, host, service))
       goto cleanup;
     rs_peer_set_timeout (server, 1);
     rs_peer_set_retries (server, 3);
@@ -85,6 +108,10 @@ blocking_client (const char *config_fn, const char *configuration,
   err = rs_err_ctx_pop (h);
   if (err == RSE_OK)
     err = rs_err_conn_pop (conn);
+#if !defined (USE_CONFIG_FILE)
+  rs_peer_free_address (server);
+  rs_peer_free_secret (server);
+#endif
   if (resp)
     rs_message_destroy (resp);
   if (request)
@@ -118,7 +145,8 @@ main (int argc, char *argv[])
     }
   if (argc < 3)
     usage (argc, argv);
-  err = blocking_client (argv[1], argv[2], use_request_object_flag);
+  err = blocking_client (argv[1], argv[2], argc >= 3 ? argv[3] : NULL,
+                         use_request_object_flag);
   if (err)
     {
       fprintf (stderr, "error: %s: %d\n", rs_err_msg (err), rs_err_code (err, 0));
index fecf8f2..45ce7f6 100644 (file)
@@ -1,5 +1,5 @@
 /** @file libradsec-impl.h
-    @brief Libraray internal header file for libradsec.  */
+    @brief Libraray internal header file for libradsec. */
 
 /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.
    See LICENSE for licensing information. */
 #endif
 #include "compat.h"
 
-/* Constants.  */
+/**************/
+/* Constants. */
 #define RS_HEADER_LEN 4
+#define RS_CONN_MAGIC_BASE 0xAE004711u
+#define RS_CONN_MAGIC_GENERIC 0x843AEF47u
+#define RS_CONN_MAGIC_LISTENER 0xDCB04783u
 
-/* Data types.  */
+/***************/
+/* Data types. */
 enum rs_cred_type {
     RS_CRED_NONE = 0,
-    /* TLS pre-shared keys, RFC 4279.  */
+    /* TLS pre-shared keys, RFC 4279. */
     RS_CRED_TLS_PSK,
     /* RS_CRED_TLS_DH_PSK, */
     /* RS_CRED_TLS_RSA_PSK, */
@@ -34,6 +39,17 @@ enum rs_key_encoding {
 };
 typedef unsigned int rs_key_encoding_t;
 
+enum rs_peer_type {
+    RS_PEER_TYPE_CLIENT = 1,
+    RS_PEER_TYPE_SERVER = 2
+};
+
+enum rs_conn_subtype {
+    RS_CONN_OBJTYPE_BASE = 1,
+    RS_CONN_OBJTYPE_GENERIC,
+    RS_CONN_OBJTYPE_LISTENER,
+};
+
 #if defined (__cplusplus)
 extern "C" {
 #endif
@@ -50,19 +66,14 @@ struct rs_error {
     char buf[1024];
 };
 
-enum rs_peer_type {
-    RS_PEER_TYPE_CLIENT = 1,
-    RS_PEER_TYPE_SERVER = 2
-};
-
-/** Configuration object for a connection.  */
+/** Configuration object for a connection. */
 struct rs_peer {
     enum rs_peer_type type;
-    struct rs_connection *conn;
+    struct rs_conn_base *connbase; /**< For error handling. */
     struct rs_realm *realm;
     char *hostname;
     char *service;
-    char *secret;               /* RADIUS secret.  */
+    char *secret;               /* RADIUS secret. */
     struct evutil_addrinfo *addr_cache;
     char *cacertfile;
     char *cacertpath;
@@ -72,17 +83,18 @@ struct rs_peer {
     struct rs_peer *next;
 };
 
-/** Configuration object for a RADIUS realm.  */
+/** Configuration object for a RADIUS realm. */
 struct rs_realm {
     char *name;
     enum rs_conn_type type;
     int timeout;
     int retries;
+    struct rs_listener *listeners;
     struct rs_peer *peers;
     struct rs_realm *next;
 };
 
-/** Top configuration object.  */
+/** Top configuration object. */
 struct rs_config {
     struct rs_realm *realms;
     cfg_t *cfg;
@@ -93,47 +105,51 @@ struct rs_context {
     struct rs_config *config;
     struct rs_alloc_scheme alloc_scheme;
     struct rs_error *err;
-    struct event_base *evb;    /* Event base.  */
-};
-
-enum rs_conn_subtype {
-    RS_CONN_OBJTYPE_BASE = 1,
-    RS_CONN_OBJTYPE_GENERIC,
-    RS_CONN_OBJTYPE_LISTENER,
+    struct event_base *evb;    /* Event base. */
 };
-#define RS_CONN_MAGIC_BASE 0xAE004711u
-#define RS_CONN_MAGIC_GENERIC 0x843AEF47u
-#define RS_CONN_MAGIC_LISTENER 0xDCB04783u
 
 /** Base class for a connection. */
 struct rs_conn_base {
     uint32_t magic;             /* Must be one of RS_CONN_MAGIC_*. */
     struct rs_context *ctx;
-    struct rs_realm *realm;    /* Owned by ctx.  */
-    struct rs_peer *peers;      /*< Configured peers. */
+    struct rs_realm *realm;    /* Owned by ctx. */
+    /** For a listener, allowed client addr/port pairs.
+     For an outgoing connection, set of servers.
+     For an incoming connection, the peer (as the only entry). */
+    struct rs_peer *peers;      /**< Configured peers. */
+    struct rs_peer *active_peer; /**< The other end of the connection. */
     struct timeval timeout;
-    int tryagain;              /* For server failover.  */
+    int tryagain;              /* For server failover. */
     void *user_data;
     struct rs_error *err;
-    int fd;                    /* Socket.  */
-    /* TCP transport specifics.  */
-    struct bufferevent *bev;   /* Buffer event.  */
-    /* UDP transport specifics.  */
-    struct event *wev;         /* Write event (for UDP).  */
-    struct event *rev;         /* Read event (for UDP).  */
+    int fd;                    /* Socket. */
+    /* TCP transport specifics. */
+    struct bufferevent *bev;   /* Buffer event. */
+    /* UDP transport specifics. */
+    struct event *wev;         /* Write event (for UDP). */
+    struct event *rev;         /* Read event (for UDP). */
+};
+
+
+enum rs_conn_state {
+    RS_CONN_STATE_UNDEFINED = 0,
+    RS_CONN_STATE_CONNECTING,
+    RS_CONN_STATE_CONNECTED,
 };
 
 /** A "generic" connection. */
 struct rs_connection {
     struct rs_conn_base base_;
-    struct event *tev;         /* Timeout event.  */
+    struct event *tev;         /* Timeout event. */
     struct rs_conn_callbacks callbacks;
-    struct rs_peer *active_peer;
+    enum rs_conn_state state;
+#if 0
     char is_connecting;                /* FIXME: replace with a single state member */
     char is_connected;         /* FIXME: replace with a single state member */
-    struct rs_message *out_queue; /* Queue for outgoing UDP packets.  */
+#endif                          /* 0 */
+    struct rs_message *out_queue; /* Queue for outgoing UDP packets. */
 #if defined(RS_ENABLE_TLS)
-    /* TLS specifics.  */
+    /* TLS specifics. */
     SSL_CTX *tls_ctx;
     SSL *tls_ssl;
 #endif
@@ -145,6 +161,7 @@ struct rs_listener {
     struct rs_conn_base base_;
     struct evconnlistener *evlistener;
     struct rs_listener_callbacks callbacks;
+    struct rs_listener *next;
 };
 
 enum rs_message_flags {
@@ -159,16 +176,16 @@ struct rs_message {
     struct rs_connection *conn;
     unsigned int flags;
     uint8_t hdr[RS_HEADER_LEN];
-    struct radius_packet *rpkt;        /* FreeRADIUS object.  */
-    struct rs_message *next;   /* Used for UDP output queue.  */
+    struct radius_packet *rpkt;        /* FreeRADIUS object. */
+    struct rs_message *next;   /* Used for UDP output queue. */
 };
 
 #if defined (__cplusplus)
 }
 #endif
 
-/************************/
-/* Convenience macros.  */
+/***********************/
+/* Convenience macros. */
 
 /* Memory allocation. */
 #define rs_calloc(h, nmemb, size) ((h)->alloc_scheme.calloc != NULL \
@@ -192,6 +209,7 @@ struct rs_message {
 #define SUBTYPE_P(p, subtype, basemember) \
   ((void*) (((char*)(p)) - STRUCT_OFFSET(subtype, basemember)))
 #define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_))
+#define TO_BASE_CONN(c) (&((c)->base_))
 static struct rs_connection *TO_GENERIC_CONN (struct rs_conn_base *);
 static struct rs_listener *TO_LISTENER_CONN (struct rs_conn_base *);
 static INLINE struct rs_connection *TO_GENERIC_CONN (struct rs_conn_base *b)
index 021f677..cb98db7 100644 (file)
@@ -1,5 +1,5 @@
 /** \file radsec.h
-    \brief Public interface for libradsec.  */
+    \brief Public interface for libradsec. */
 
 /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.
    See LICENSE for licensing information. */
@@ -136,6 +136,7 @@ extern "C" {
 
 /* Data types.  */
 struct rs_context;             /* radsec-impl.h */
+struct rs_conn_base;            /* radsec-impl.h */
 struct rs_connection;          /* radsec-impl.h */
 struct rs_listener;             /* radsec-impl.h */
 struct rs_message;             /* radsec-impl.h */
@@ -175,8 +176,10 @@ struct rs_conn_callbacks {
 
 typedef void (*rs_listener_new_conn_cb) (struct rs_connection *conn,
                                          void *user_data);
+typedef void (*rs_listener_error_cb) (void *user_data);
 struct rs_listener_callbacks {
     rs_listener_new_conn_cb new_conn_cb;
+    rs_listener_error_cb error_cb;
 };
 
 typedef struct value_pair rs_avp;
@@ -327,11 +330,20 @@ int rs_conn_get_fd(struct rs_connection *conn);
 void rs_conn_set_timeout(struct rs_connection *conn, struct timeval *tv);
 
 /* Peer -- client and server.  */
-int rs_peer_create(struct rs_connection *conn, struct rs_peer **peer_out);
+/** Create a peer and add it to list of peers held by \a conn. */
+int rs_peer_create_for_conn (struct rs_connection *conn,
+                             struct rs_peer **peer_out);
+/** Create a peer and add it to list of peers held by \a listener. */
+int rs_peer_create_for_listener (struct rs_listener *listener,
+                                 struct rs_peer **peer_out);
+/** Set RADIUS secret for \a peer. Free resurces with \a rs_peer_free_secret. */
+int rs_peer_set_secret(struct rs_peer *peer, const char *secret);
+/** Free resources allocated by \a rs_peer_set_secret. */
+void rs_peer_free_secret (struct rs_peer *peer);
 int rs_peer_set_address(struct rs_peer *peer,
                        const char *hostname,
                        const char *service);
-int rs_peer_set_secret(struct rs_peer *peer, const char *secret);
+void rs_peer_free_address (struct rs_peer *peer);
 void rs_peer_set_timeout(struct rs_peer *peer, int timeout);
 void rs_peer_set_retries(struct rs_peer *peer, int retries);
 
@@ -427,6 +439,12 @@ int rs_err_conn_push_fl(struct rs_connection *conn,
                        int line,
                        const char *fmt,
                        ...);
+int rs_err_connbase_push_fl (struct rs_conn_base *connbase,
+                             int code,
+                             const char *file,
+                             int line,
+                             const char *fmt,
+                             ...);
 /** Pop the first error from the error FIFO associated with connection
     \a conn or NULL if there are no errors in the FIFO.  */
 struct rs_error *rs_err_conn_pop(struct rs_connection *conn);
index e010f94..47590ca 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.
-   See LICENSE for licensing information.  */
+   See LICENSE for licensing information. */
 
 #if defined HAVE_CONFIG_H
 #include <config.h>
@@ -28,21 +28,21 @@ message_verify_response (struct rs_connection *conn,
   int err;
 
   assert (conn);
-  assert (conn->active_peer);
-  assert (conn->active_peer->secret);
+  assert (conn->base_.active_peer);
+  assert (conn->base_.active_peer->secret);
   assert (response);
   assert (response->rpkt);
   assert (request);
   assert (request->rpkt);
 
-  response->rpkt->secret = conn->active_peer->secret;
-  response->rpkt->sizeof_secret = strlen (conn->active_peer->secret);
+  response->rpkt->secret = conn->base_.active_peer->secret;
+  response->rpkt->sizeof_secret = strlen (conn->base_.active_peer->secret);
 
   /* Verify header and message authenticator.  */
   err = nr_packet_verify (response->rpkt, request->rpkt);
   if (err)
     {
-      if (conn->is_connected)
+      if (conn->state == RS_CONN_STATE_CONNECTED)
        rs_conn_disconnect(conn);
       return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__,
                                  "nr_packet_verify");
@@ -52,7 +52,7 @@ message_verify_response (struct rs_connection *conn,
   err = nr_packet_decode (response->rpkt, request->rpkt);
   if (err)
     {
-      if (conn->is_connected)
+      if (conn->state == RS_CONN_STATE_CONNECTED)
        rs_conn_disconnect(conn);
       return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__,
                                  "nr_packet_decode");
@@ -71,11 +71,11 @@ message_do_send (struct rs_message *msg)
 
   assert (msg);
   assert (msg->conn);
-  assert (msg->conn->active_peer);
-  assert (msg->conn->active_peer->secret);
+  assert (msg->conn->base_.active_peer);
+  assert (msg->conn->base_.active_peer->secret);
   assert (msg->rpkt);
 
-  msg->rpkt->secret = msg->conn->active_peer->secret;
+  msg->rpkt->secret = msg->conn->base_.active_peer->secret;
   msg->rpkt->sizeof_secret = strlen (msg->rpkt->secret);
 
   /* Encode message.  */
@@ -92,8 +92,8 @@ message_do_send (struct rs_message *msg)
   {
     char host[80], serv[80];
 
-    getnameinfo (msg->conn->active_peer->addr_cache->ai_addr,
-                msg->conn->active_peer->addr_cache->ai_addrlen,
+    getnameinfo (msg->conn->base_.active_peer->addr_cache->ai_addr,
+                msg->conn->base_.active_peer->addr_cache->ai_addrlen,
                 host, sizeof(host), serv, sizeof(serv),
                 0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
     rs_debug (("%s: about to send this to %s:%s:\n", __func__, host, serv));
index 3e0069b..b6ec167 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.
-   See LICENSE for licensing information.  */
+   See LICENSE for licensing information. */
 
 #if defined HAVE_CONFIG_H
 #include <config.h>
@@ -20,12 +20,12 @@ 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->base_.peers; /* From the top.  */
+  if (conn->base_.active_peer)
+    conn->base_.active_peer = conn->base_.active_peer->next; /* Next.  */
+  if (!conn->base_.active_peer)
+    conn->base_.active_peer = conn->base_.peers; /* From the top.  */
 
-  return conn->active_peer;
+  return conn->base_.active_peer;
 }
 
 struct rs_peer *
@@ -33,10 +33,9 @@ peer_create (struct rs_context *ctx, struct rs_peer **rootp)
 {
   struct rs_peer *p;
 
-  p = (struct rs_peer *) rs_malloc (ctx, sizeof(*p));
+  p = (struct rs_peer *) rs_calloc (ctx, 1, sizeof(*p));
   if (p)
     {
-      memset (p, 0, sizeof(struct rs_peer));
       if (*rootp)
        {
          p->next = (*rootp)->next;
@@ -48,36 +47,49 @@ peer_create (struct rs_context *ctx, struct rs_peer **rootp)
   return p;
 }
 
-/* Public functions.  */
 int
-rs_peer_create (struct rs_connection *conn, struct rs_peer **peer_out)
+peer_create_for_connbase (struct rs_conn_base *connbase,
+                          struct rs_peer **peer_out)
 {
   struct rs_peer *peer;
 
-  peer = peer_create (conn->base_.ctx, &conn->base_.peers);
-  if (peer)
-    {
-      peer->conn = conn;
-      peer->realm->timeout = 2;        /* FIXME: Why?  */
-      peer->realm->retries = 2;        /* FIXME: Why?  */
-    }
-  else
-    return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
+  peer = peer_create (connbase->ctx, &connbase->peers);
+  if (peer == NULL)
+    return rs_err_connbase_push_fl (connbase, RSE_NOMEM, __FILE__, __LINE__,
+                                    NULL);
+  peer->connbase = connbase;
+  peer->realm = connbase->realm;
+
   if (*peer_out)
     *peer_out = peer;
   return RSE_OK;
 }
 
+/* Public functions.  */
+int
+rs_peer_create_for_conn (struct rs_connection *conn, struct rs_peer **peer_out)
+{
+  return peer_create_for_connbase (TO_BASE_CONN (conn), peer_out);
+}
+
 int
-rs_peer_set_address (struct rs_peer *peer, const char *hostname,
+rs_peer_create_for_listener (struct rs_listener *listener,
+                             struct rs_peer **peer_out)
+{
+  return peer_create_for_connbase (TO_BASE_CONN (listener), peer_out);
+}
+
+int
+rs_peer_set_address (struct rs_peer *peer,
+                     const char *hostname,
                      const char *service)
 {
   assert (peer);
-  assert (peer->conn);
-  assert (peer->conn->base_.ctx);
+  assert (peer->connbase);
+  assert (peer->connbase->ctx);
 
-  peer->hostname = rs_strdup (peer->conn->base_.ctx, hostname);
-  peer->service = rs_strdup (peer->conn->base_.ctx, service);
+  peer->hostname = rs_strdup (peer->connbase->ctx, hostname);
+  peer->service = rs_strdup (peer->connbase->ctx, service);
   if (peer->hostname == NULL || peer->service == NULL)
     return RSE_NOMEM;
 
@@ -85,12 +97,28 @@ rs_peer_set_address (struct rs_peer *peer, const char *hostname,
 }
 
 void
+rs_peer_free_address (struct rs_peer *peer)
+{
+  assert (peer);
+  assert (peer->connbase);
+  assert (peer->connbase->ctx);
+
+  if (peer->hostname)
+    rs_free (peer->connbase->ctx, peer->hostname);
+  peer->hostname = NULL;
+  if (peer->service)
+    rs_free (peer->connbase->ctx, peer->service);
+  peer->service = NULL;
+}
+
+void
 rs_peer_set_timeout (struct rs_peer *peer, int timeout)
 {
   assert (peer);
   assert (peer->realm);
   peer->realm->timeout = timeout;
 }
+
 void
 rs_peer_set_retries (struct rs_peer *peer, int retries)
 {
@@ -102,12 +130,26 @@ rs_peer_set_retries (struct rs_peer *peer, int retries)
 int
 rs_peer_set_secret (struct rs_peer *peer, const char *secret)
 {
-  if (peer->secret)
-    free (peer->secret);
-  peer->secret = (char *) malloc (strlen(secret) + 1);
+  assert (peer);
+  assert (peer->connbase);
+  assert (peer->connbase->ctx);
+
+  rs_peer_free_secret (peer);
+  peer->secret = rs_calloc (peer->connbase->ctx, 1, strlen(secret) + 1);
   if (!peer->secret)
-    return rs_err_conn_push (peer->conn, RSE_NOMEM, NULL);
+    return rs_err_connbase_push (peer->connbase, RSE_NOMEM, NULL);
   strcpy (peer->secret, secret);
   return RSE_OK;
 }
 
+void
+rs_peer_free_secret (struct rs_peer *peer)
+{
+  assert (peer);
+  assert (peer->connbase);
+  assert (peer->connbase->ctx);
+
+  if (peer->secret)
+    rs_free (peer->connbase->ctx, peer->secret);
+  peer->secret = NULL;
+}
index 4e976c5..95be0b0 100644 (file)
@@ -3,3 +3,4 @@
 
 struct rs_peer *peer_create (struct rs_context *ctx, struct rs_peer **rootp);
 struct rs_peer *peer_pick_peer (struct rs_connection *conn);
+int peer_create_for_connbase (struct rs_conn_base *, struct rs_peer **);
index 7e64560..6ad1361 100644 (file)
@@ -77,7 +77,10 @@ rs_message_create
 rs_message_create_authn_request
 rs_message_destroy
 rs_message_send
-rs_peer_create
+rs_peer_create_for_conn
+rs_peer_create_for_listener
+rs_peer_free_address
+rs_peer_free_secret
 rs_peer_set_address
 rs_peer_set_retries
 rs_peer_set_secret
index 6b76958..fab89a9 100644 (file)
@@ -24,12 +24,12 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)
   if (event_init_eventbase (conn))
     return -1;
 
-  if (!conn->active_peer)
+  if (!conn->base_.active_peer)
     peer_pick_peer (conn);
-  if (!conn->active_peer)
+  if (!conn->base_.active_peer)
     return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
 
-  if (event_init_socket (conn, conn->active_peer))
+  if (event_init_socket (conn, conn->base_.active_peer))
     return -1;
 
   if (conn->base_.realm->type == RS_CONN_TYPE_TCP
@@ -37,7 +37,7 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)
     {
       if (tcp_init_connect_timer (conn))
        return -1;
-      if (event_init_bufferevent (conn, conn->active_peer))
+      if (event_init_bufferevent (conn, conn->base_.active_peer))
        return -1;
     }
   else
@@ -48,9 +48,9 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)
        return -1;
     }
 
-  if (!conn->is_connected)
-    if (!conn->is_connecting)
-      event_do_connect (conn);
+  if (conn->state != RS_CONN_STATE_CONNECTED
+      && conn->state != RS_CONN_STATE_CONNECTING)
+    event_do_connect (conn);
 
   return RSE_OK;
 }
@@ -58,7 +58,8 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)
 static int
 _conn_is_open_p (struct rs_connection *conn)
 {
-  return conn->active_peer && conn->is_connected;
+  return conn->state == RS_CONN_STATE_CONNECTED
+    && conn->base_.active_peer != NULL;
 }
 
 /* User callback used when we're dispatching for user.  */
@@ -92,7 +93,7 @@ rs_message_send (struct rs_message *msg, void *user_data)
 
   assert (conn->base_.ctx);
   assert (conn->base_.ctx->evb);
-  assert (conn->active_peer);
+  assert (conn->base_.active_peer);
   assert (conn->base_.fd >= 0);
 
   conn->base_.user_data = user_data;
index b8d7906..f5673f5 100644 (file)
--- a/lib/tcp.c
+++ b/lib/tcp.c
@@ -109,7 +109,8 @@ _read_message (struct rs_message *msg)
       /* Find out what happens if there's data left in the buffer.  */
       {
        size_t rest = 0;
-       rest = evbuffer_get_length (bufferevent_get_input (msg->conn->bev));
+       rest =
+          evbuffer_get_length (bufferevent_get_input (msg->conn->base_.bev));
        if (rest)
          rs_debug (("%s: returning with %d octets left in buffer\n", __func__,
                     rest));
@@ -178,11 +179,10 @@ tcp_event_cb (struct bufferevent *bev, short events, void *user_data)
   assert (msg->conn);
   conn = msg->conn;
 #if defined (DEBUG)
-  assert (msg->conn->active_peer);
-  p = conn->active_peer;
+  assert (msg->conn->base_.active_peer);
+  p = conn->base_.active_peer;
 #endif
 
-  conn->is_connecting = 0;
   if (events & BEV_EVENT_CONNECTED)
     {
       if (conn->tev)
@@ -213,7 +213,7 @@ tcp_event_cb (struct bufferevent *bev, short events, void *user_data)
        }
       else
        {
-         rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr,
+         rs_debug (("%s: %d: %d (%s)\n", __func__, conn->base_.fd, sockerr,
                     evutil_socket_error_to_string (sockerr)));
          rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__,
                               "%d: %d (%s)", conn->base_.fd, sockerr,
index 979ee3c..b9fb3cf 100644 (file)
--- a/lib/tls.c
+++ b/lib/tls.c
@@ -26,14 +26,14 @@ _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm)
     {
       memset (c, 0, sizeof (struct tls));
       /* _conn_open() should've picked a peer by now. */
-      assert (conn->active_peer);
+      assert (conn->base_.active_peer);
       /* TODO: Make sure old radsecproxy code doesn't free these all
         of a sudden, or strdup them.  */
       c->name = realm->name;
-      c->cacertfile = conn->active_peer->cacertfile;
+      c->cacertfile = conn->base_.active_peer->cacertfile;
       c->cacertpath = NULL;    /* NYI */
-      c->certfile = conn->active_peer->certfile;
-      c->certkeyfile = conn->active_peer->certkeyfile;
+      c->certfile = conn->base_.active_peer->certfile;
+      c->certkeyfile = conn->base_.active_peer->certkeyfile;
       c->certkeypwd = NULL;    /* NYI */
       c->cacheexpiry = 0;      /* NYI */
       c->crlcheck = 0;         /* NYI */
@@ -60,7 +60,7 @@ psk_client_cb (SSL *ssl,
 
   conn = SSL_get_ex_data (ssl, 0);
   assert (conn != NULL);
-  cred = conn->active_peer->transport_cred;
+  cred = conn->base_.active_peer->transport_cred;
   assert (cred != NULL);
   /* NOTE: Ignoring identity hint from server.  */
 
@@ -126,7 +126,7 @@ rs_tls_init (struct rs_connection *conn)
   assert (conn->base_.ctx);
   ctx = conn->base_.ctx;
 
-  tlsconf = _get_tlsconf (conn, conn->active_peer->realm);
+  tlsconf = _get_tlsconf (conn, conn->base_.active_peer->realm);
   if (!tlsconf)
     return -1;
   ssl_ctx = tlsgetctx (RAD_TLS, tlsconf);
@@ -147,7 +147,7 @@ rs_tls_init (struct rs_connection *conn)
     }
 
 #if defined RS_ENABLE_TLS_PSK
-  if (conn->active_peer->transport_cred != NULL)
+  if (conn->base_.active_peer->transport_cred != NULL)
     {
       SSL_set_psk_client_callback (ssl, psk_client_cb);
       SSL_set_ex_data (ssl, 0, conn);
@@ -203,9 +203,9 @@ tls_verify_cert (struct rs_connection *conn)
   struct in6_addr addr;
   const char *hostname = NULL;
 
-  assert (conn->active_peer->conn == conn);
-  assert (conn->active_peer->hostname != NULL);
-  hostname = conn->active_peer->hostname;
+  assert (conn->base_.active_peer != NULL);
+  assert (conn->base_.active_peer->hostname != NULL);
+  hostname = conn->base_.active_peer->hostname;
 
   /* verifytlscert() performs basic verification as described by
      OpenSSL VERIFY(1), i.e. verification of the certificate chain.  */
index 71d7003..22a8375 100644 (file)
--- a/lib/udp.c
+++ b/lib/udp.c
@@ -129,7 +129,7 @@ _evcb (evutil_socket_t fd, short what, void *user_data)
       assert (msg);
       assert (msg->conn);
 
-      if (!msg->conn->is_connected)
+      if (msg->conn->state == RS_CONN_STATE_CONNECTING)
        event_on_connect (msg->conn, msg);
 
       if (msg->conn->out_queue)
index eceaec9..671fcde 100644 (file)
@@ -11,9 +11,10 @@ rs_strdup (struct rs_context *ctx, const char *s)
 {
   char *buf = rs_calloc (ctx, 1, strlen (s) + 1);
 
-  if (buf != NULL)
-    return strcpy (buf, s);
+  if (buf)
+    strcpy (buf, s);
+  else
+    rs_err_ctx_push (ctx, RSE_NOMEM, NULL);
 
-  rs_err_ctx_push (ctx, RSE_NOMEM, NULL);
-  return NULL;
+  return buf;
 }