WIP.
authorLinus Nordberg <linus@nordu.net>
Tue, 28 Sep 2010 20:27:04 +0000 (22:27 +0200)
committerLinus Nordberg <linus@nordu.net>
Tue, 28 Sep 2010 20:27:04 +0000 (22:27 +0200)
lib/Makefile
lib/attr.c
lib/debug.c
lib/debug.h
lib/err.c
lib/examples/Makefile
lib/examples/client.c
lib/libradsec-impl.h
lib/libradsec.h
lib/packet.c
lib/radsec.c

index bc35e88..8c6d5b4 100644 (file)
@@ -1,9 +1,12 @@
 CFLAGS = -Wall -g -DDEBUG
-OFILES = radsec.o err.o packet.o attr.o
 
-all: libradsec.a
+OFILES = attr.o \
+       debug.o \
+       err.o \
+       packet.o \
+       radsec.o
 
-base.o: base.c libradsec-base.h libradsec.h ../tlv11.h
+all: libradsec.a
 
 libradsec.a: $(OFILES)
        ar rc $@ $^
index bf5e105..4bd44f7 100644 (file)
@@ -2,27 +2,35 @@
 #include "libradsec.h"
 #include "libradsec-impl.h"
 
-fixme
-attr_create(fixme)
+int
+rs_attr_create(struct rs_connection *conn, struct rs_attr **attr, const char *type, const char *val)
 {
+  VALUE_PAIR *vp;
+  struct rs_attr *a;
 
-  printf ("creating value pairs\n");
-  /* User-Name.  */
-  vp = pairmake ("User-Name", USER_NAME, 0);
-  if (!vp) {
-    fr_perror ("pairmake");
-    return -1;
-  }
+  *attr = NULL;
+  a = (struct rs_attr *) malloc (sizeof(struct rs_attr));
+  if (!a)
+    return rs_conn_err_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
+  memset (a, 0, sizeof(struct rs_attr));
 
-  /* User-Password.  */
-  {
-    size_t pwlen =  sizeof(USER_PW);
-    strncpy (user_pw, USER_PW, sizeof(user_pw));
-    rad_pwencode(user_pw, &pwlen, SECRET, reqauth);
-  }
-  pairadd (&vp, pairmake ("User-Password", user_pw, 0));
-  pkt->vps = vp;
+  vp = pairmake (type, val, T_OP_EQ);
+  if (!vp)
+    {
+      rs_attr_destroy (a);
+      return rs_conn_err_push_fl (conn, RSE_FR, __FILE__, __LINE__,
+                                 "pairmake: %s", fr_strerror());
+    }
 
-  printf ("attributes:\n");
-  vp_printlist (stdout, vp);
+  a->vp = vp;
+  *attr = a;
+  return RSE_OK;
+}
+
+void
+rs_attr_destroy (struct rs_attr *attr)
+{
+  if (attr->vp)
+    pairfree (&attr->vp);
+  free (attr);
 }
index 2d4e242..34f4885 100644 (file)
@@ -1,4 +1,6 @@
+#include <stdio.h>
 #include <freeradius/libradius.h>
+#include "libradsec.h"
 #include "libradsec-impl.h"
 #include "debug.h"
 
@@ -69,3 +71,9 @@ rs_dump_packet (const struct rs_packet *pkt)
 {
   print_hex (pkt->rpkt);
 }
+
+void
+rs_dump_attr (const struct rs_attr *attr)
+{
+  vp_printlist (stderr, attr->vp);
+}
index 83c3650..a541555 100644 (file)
@@ -5,69 +5,5 @@
       if (i % 16 == 0) printf ("\n"); }        \
     printf ("\n"); }
 
-/* From freeradius-server/src/lib/radius.c */
-#include <freeradius/libradius.h>
-static void print_hex(RADIUS_PACKET *packet)
-{
-       int i;
-
-       if (!packet->data) return;
-
-       printf("  Code:\t\t%u\n", packet->data[0]);
-       printf("  Id:\t\t%u\n", packet->data[1]);
-       printf("  Length:\t%u\n", ((packet->data[2] << 8) |
-                                  (packet->data[3])));
-       printf("  Vector:\t");
-       for (i = 4; i < 20; i++) {
-               printf("%02x", packet->data[i]);
-       }
-       printf("\n");
-
-       if (packet->data_len > 20) {
-               int total;
-               const uint8_t *ptr;
-               printf("  Data:");
-
-               total = packet->data_len - 20;
-               ptr = packet->data + 20;
-
-               while (total > 0) {
-                       int attrlen;
-
-                       printf("\t\t");
-                       if (total < 2) { /* too short */
-                               printf("%02x\n", *ptr);
-                               break;
-                       }
-
-                       if (ptr[1] > total) { /* too long */
-                               for (i = 0; i < total; i++) {
-                                       printf("%02x ", ptr[i]);
-                               }
-                               break;
-                       }
-
-                       printf("%02x  %02x  ", ptr[0], ptr[1]);
-                       attrlen = ptr[1] - 2;
-                       ptr += 2;
-                       total -= 2;
-
-                       for (i = 0; i < attrlen; i++) {
-                               if ((i > 0) && ((i & 0x0f) == 0x00))
-                                       printf("\t\t\t");
-                               printf("%02x ", ptr[i]);
-                               if ((i & 0x0f) == 0x0f) printf("\n");
-                       }
-
-                       if ((attrlen & 0x0f) != 0x00) printf("\n");
-
-                       ptr += attrlen;
-                       total -= attrlen;
-               }
-       }
-       fflush(stdout);
-}
-
-/* Local Variables: */
-/* c-file-style: "stroustrup" */
-/* End: */
+void rs_dump_packet (const struct rs_packet *pkt);
+void rs_dump_attr (const struct rs_attr *attr);
index 66c5d94..9fcad0b 100644 (file)
--- a/lib/err.c
+++ b/lib/err.c
@@ -1,3 +1,4 @@
+#include <stdio.h>
 #include <assert.h>
 #include "libradsec.h"
 #include "libradsec-impl.h"
@@ -8,8 +9,8 @@ const char *_errtxt[] = {
   "NYI -- not yet implemented",        /* 2 RSE_NOSYS */
   "invalid handle"             /* 3 RSE_INVALID_CTX */
   "invalid connection"         /* 4 RSE_INVALID_CONN */
-  "ERR 5"                      /*  RSE_ */
-  "ERR 6"                      /*  RSE_ */
+  "connection type mismatch"   /* 5 RSE_CONN_TYPE_MISMATCH */
+  "FreeRadius error"           /* 6 RSE_FR */
   "ERR 7"                      /*  RSE_ */
   "ERR 8"                      /*  RSE_ */
   "ERR 9"                      /*  RSE_ */
@@ -28,27 +29,33 @@ const char *_errtxt[] = {
 };
 
 static struct rs_error *
-_err_new (unsigned int code, const char *msg)
+_err_new (unsigned int code, const char *file, int line, const char *fmt, va_list args)
 {
   struct rs_error *err;
 
-  err = malloc (sizeof (struct rs_error));
+  err = malloc (sizeof(struct rs_error));
   if (err)
     {
-      memset (err, 0, sizeof (struct rs_error));
+      int n;
+      memset (err, 0, sizeof(struct rs_error));
       err->code = code;
-      snprintf (err->buf, sizeof (err->buf), "%s: %s",
-               code < sizeof (_errtxt) / sizeof (*_errtxt) ?
-               _errtxt[code] : "invalid error index",
-               msg);
+      n = vsnprintf (err->buf, sizeof(err->buf), fmt, args);
+      if (n > 0)
+       {
+         char *sep = strrchr (file, '/');
+         if (sep)
+           file = sep + 1;
+         snprintf (err->buf + n, sizeof(err->buf) - n, " (%s: %d)", file,
+                   line);
+       }
     }
   return err;
 }
 
-int
-rs_ctx_err_push (struct rs_handle *ctx, int code, const char *msg)
+static int
+_ctx_err_vpush_fl (struct rs_handle *ctx, int code, const char *file, int line, const char *fmt, va_list args)
 {
-  struct rs_error *err = _err_new (code, msg);
+  struct rs_error *err = _err_new (code, file, line, fmt, args);
 
   if (err)
     ctx->err = err;
@@ -56,15 +63,45 @@ rs_ctx_err_push (struct rs_handle *ctx, int code, const char *msg)
 }
 
 int
-rs_conn_err_push (struct rs_connection *conn, int code, const char *msg)
+rs_ctx_err_push (struct rs_handle *ctx, int code, const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  _ctx_err_vpush_fl (ctx, code, NULL, 0, fmt, args);
+  va_end (args);
+  return code;
+}
+
+static int
+_conn_err_vpush_fl (struct rs_connection *conn, int code, const char *file, int line, const char *fmt, va_list args)
 {
-  struct rs_error *err = _err_new (code, msg);
+  struct rs_error *err = _err_new (code, file, line, fmt, args);
 
   if (err)
     conn->err = err;
   return code;
 }
 
+int
+rs_conn_err_push (struct rs_connection *conn, int code, const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  _conn_err_vpush_fl (conn, code, NULL, 0, fmt, args);
+  va_end (args);
+  return code;
+}
+
+int
+rs_conn_err_push_fl (struct rs_connection *conn, int code, const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  _conn_err_vpush_fl (conn, code, file, line, fmt, args);
+  va_end (args);
+  return code;
+}
+
 struct rs_error *
 rs_ctx_err_pop (struct rs_handle *ctx)
 {
@@ -99,23 +136,32 @@ rs_err_free (struct rs_error *err)
 }
 
 char *
-rs_err_msg (struct rs_error *err)
+rs_err_msg (struct rs_error *err, int dofree_flag)
 {
   char *msg;
 
+  if (!err)
+    return NULL;
   if (err->msg)
     msg = err->msg;
   else
     msg = strdup (err->buf);
 
-  rs_err_free (err);
+  if (dofree_flag)
+    rs_err_free (err);
   return msg;
 }
 
 int
-rs_err_code (struct rs_error *err)
+rs_err_code (struct rs_error *err, int dofree_flag)
 {
-  int code = err->code;
-  rs_err_free(err);
+  int code;
+
+  if (!err)
+    return -1;
+  code = err->code;
+
+  if (dofree_flag)
+    rs_err_free(err);
   return code;
 }
index e07a32b..ceb97f1 100644 (file)
@@ -1,12 +1,12 @@
 CFLAGS = -Wall -g
 
-all: blocking.o
+all: client
 
 blocking.o: blocking.c blocking.h ../libradsec-base.h ../libradsec.h
        $(CC) $(CFLAGS) -c -I .. $^
 
 client: client.c ../libradsec.a ../libradsec.h ../libradsec-impl.h
-       $(CC) $(CFLAGS) -o $@ -L /usr/lib/freeradius -lfreeradius-radius $^
+       $(CC) $(CFLAGS) -o $@ $< -L /usr/lib/freeradius -lfreeradius-radius -L .. -lradsec
 
 clean:
        -rm *.o
index 37601b6..eab4390 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include "../libradsec.h"
 #include "../debug.h"
 
 #define USER_NAME "bob"
 #define USER_PW "hemligt"
 
-int
+struct rs_error *
 rsx_client (const char *srvname, int srvport)
 {
-  struct rs_context *h;
-  struct rs_connecion *conn;
-  struct rs_packet *req, *resp;
+  struct rs_handle *h;
+  struct rs_connection *conn;
+  struct rs_peer *server;
+  struct rs_packet *req;
+  //struct rs_packet  *resp;
 
   if (rs_context_create (&h, "/usr/share/freeradius/dictionary"))
-    return rs_err_code (rs_ctx_err_code (h));
+    return NULL;
 
-  if (rs_conn_new (h, &conn))
-    return rs_err_code (rs_conn_err_code (conn));
-  if (rs_conn_add_server (conn, RS_CONN_TYPE_UDP, srvname, srvport, 10, 3, SECRET))
-    return rs_err_code (rs_conn_err_code (conn));
+  if (rs_conn_create (h, &conn))
+    return rs_conn_err_pop (conn);
+  if (rs_conn_add_server (conn, &server, RS_CONN_TYPE_UDP, srvname, srvport))
+    return rs_conn_err_pop (conn);
+  rs_server_set_timeout (server, 10);
+  rs_server_set_tries (server, 3);
+  rs_server_set_secret (server, SECRET);
 
   if (rs_packet_create_acc_request (conn, &req, USER_NAME, USER_PW))
-    return rs_err_code (rs_conn_err_code (conn));
+    return rs_conn_err_pop (conn);
 
-  if (rs_packet_send (req))
-    return rs_err_code (rs_conn_err_code (conn));
+  if (rs_packet_send (conn, req, NULL))
+    return rs_conn_err_pop (conn);
   req = NULL;
 
+#if 0
+  printf ("waiting for response\n");
   if (rs_packet_recv (conn, &resp))
-    return rs_err_code (rs_conn_err_code (conn));
+    return rs_conn_err_pop (conn);
+  printf ("got response\n");
+  rs_dump_packet (resp);
+#endif
 
   rs_conn_destroy (conn);
   rs_context_destroy (h);
+  return 0;
 }
 
 int
 main (int argc, char *argv[])
 {
-  exit (rsx_client ());
+  struct rs_error *err;
+
+  err = rsx_client (strsep (argv + 1, ":"), atoi (argv[1]));
+  if (!err)
+    return -1;
+  fprintf (stderr, "%s\n", rs_err_msg (err, 0));
+  return rs_err_code (err, 1);
 }
index e9ec644..170e90c 100644 (file)
@@ -15,6 +15,8 @@ enum rs_cred_type {
 };
 typedef unsigned int rs_cred_type_t;
 
+struct rs_packet;
+
 struct rs_credentials {
     enum rs_cred_type type;
     char *identity;
@@ -65,19 +67,22 @@ struct rs_handle {
 };
 
 struct rs_peer {
-    struct addrinfo addr;
+    struct rs_connection *conn;
+    struct addrinfo *addr;
     char *secret;
     int timeout;               /* client only */
     int tries;                 /* client only */
+    struct rs_peer *next;
 };
 
 struct rs_connection {
     struct rs_handle *ctx;
-    enum rs_conn_type conn_type;
+    enum rs_conn_type type;
     struct rs_credentials transport_credentials;
     struct rs_conn_callbacks callbacks;
+    struct rs_peer peers;
+    struct rs_peer *active_peer;
     struct rs_error *err;
-    struct rs_peer *peer;
 };
 
 struct rs_packet {
@@ -90,16 +95,18 @@ struct rs_attr {
     VALUE_PAIR *vp;
 };
 
+/* Internal functions.  */
+int rs_conn_open(struct rs_connection *conn);
 
 /* Convenience macros.  */
-#define rs_calloc(ctx, nmemb, size) \
-    (ctx->alloc_scheme.calloc ? ctx->alloc_scheme.calloc : calloc)(nmemb, size)
-#define rs_malloc(ctx, size) \
-    (ctx->alloc_scheme.malloc ? ctx->alloc_scheme.malloc : malloc)(size)
-#define rs_free(ctx, ptr) \
-    (ctx->alloc_scheme.free ? ctx->alloc_scheme.free : free)(ptr)
-#define rs_(ctx, realloc, ptr, size) \
-    (ctx->alloc_scheme.realloc ? ctx->alloc_scheme.realloc : realloc)(ptr, size)
+#define rs_calloc(h, nmemb, size) \
+    (h->alloc_scheme.calloc ? h->alloc_scheme.calloc : calloc)(nmemb, size)
+#define rs_malloc(h, size) \
+    (h->alloc_scheme.malloc ? h->alloc_scheme.malloc : malloc)(size)
+#define rs_free(h, ptr) \
+    (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)
 
 /* Local Variables: */
 /* c-file-style: "stroustrup" */
index 629e7e1..f956f45 100644 (file)
@@ -10,11 +10,14 @@ enum rs_err_code {
     RSE_NOSYS = 2,
     RSE_INVALID_CTX = 3,
     RSE_INVALID_CONN = 4,
-    RSE_SOME_ERROR = 21
+    RSE_CONN_TYPE_MISMATCH = 5,
+    RSE_FR = 6,
+    RSE_SOME_ERROR = 21,
 };
 
 enum rs_conn_type {
-    RS_CONN_TYPE_UDP = 0,
+    RS_CONN_TYPE_NONE = 0,
+    RS_CONN_TYPE_UDP,
     RS_CONN_TYPE_TCP,
     RS_CONN_TYPE_TLS,
     RS_CONN_TYPE_DTLS,
@@ -31,6 +34,7 @@ struct rs_packet;             /* radsec-impl.h */
 struct rs_conn;                        /* radsec-impl.h */
 struct rs_attr;                        /* radsec-impl.h */
 struct rs_error;               /* radsec-impl.h */
+struct rs_peer;                        /* radsec-impl.h */
 struct event_base;             /* <event.h> */
 
 /* Function prototypes.  */
@@ -39,37 +43,42 @@ void rs_context_destroy(struct rs_handle *ctx);
 int rs_context_set_alloc_scheme(struct rs_handle *ctx, struct rs_alloc_scheme *scheme);
 int rs_context_config_read(struct rs_handle *ctx, const char *config_file);
 
-int rs_conn_create(const struct rs_handle *ctx, struct rs_connection **conn);
-int rs_conn_add_server(struct rs_connection  *conn, rs_conn_type_t type, const char *host, int port, int timeout, int tries, const char *secret);
-int rs_conn_add_listener(struct rs_connection  *conn, rs_conn_type_t type, const char *host, int port, const char *secret);
+int rs_conn_create(struct rs_handle *ctx, struct rs_connection **conn);
+int rs_conn_add_server(struct rs_connection *conn, struct rs_peer **server, rs_conn_type_t type, const char *host, int port);
+int rs_conn_add_listener(struct rs_connection  *conn, rs_conn_type_t type, const char *host, int port);
 int rs_conn_destroy(struct rs_connection  *conn);
 int rs_conn_set_eventbase(struct rs_connection *conn, struct event_base *eb);
 int rs_conn_set_callbacks(struct rs_connection *conn, struct rs_conn_callbacks *cb);
-int rs_conn_set_server(struct rs_connection *conn, const char *name);
-int rs_conn_get_server(const struct rs_connection *conn, const char *name, size_t buflen); /* NAME <-- most recent server we spoke to */
+int rs_conn_select_server(struct rs_connection *conn, const char *name);
+int rs_conn_get_current_server(const struct rs_connection *conn, const char *name, size_t buflen);
+
+void rs_server_set_timeout(struct rs_peer *server, int timeout);
+void rs_server_set_tries(struct rs_peer *server, int tries);
+int rs_server_set_secret(struct rs_peer *server, const char *secret);
 
 int rs_packet_create_acc_request(struct rs_connection *conn, struct rs_packet **pkt, const char *user_name, const char *user_pw);
 //int rs_packet_create_acc_accept(cstruct rs_connection *conn, struct rs_packet **pkt);
 //int rs_packet_create_acc_reject(struct rs_connection *conn, struct rs_packet **pkt);
 //int rs_packet_create_acc_challenge(struct rs_connection *conn, struct rs_packet **pkt);
 void rs_packet_destroy(struct rs_packet *pkt);
-int rs_packet_add_attr(struct rs_packet *pkt, const struct rs_attr *attr);
+void rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr);
 //int rs_packet_add_new_attr(struct rs_packet *pkt, const char *attr_name, const char *attr_val);
 
 int rs_attr_create(struct rs_connection *conn, struct rs_attr **attr, const char *type, const char *val);
 void rs_attr_destroy(struct rs_attr *attr);
 
-int rs_packet_send(struct rs_conn *conn, const struct rs_packet *pkt, void *user_data);
-int rs_packet_receive(struct rs_conn *conn, struct rs_packet **pkt);
+int rs_packet_send(struct rs_connection *conn, const struct rs_packet *pkt, void *user_data);
+int rs_packet_recv(struct rs_connection *conn, struct rs_packet **pkt);
 
 
-int rs_ctx_err_push (struct rs_handle *ctx, int code, const char *msg);
-int rs_conn_err_push (struct rs_connection *conn, int code, const char *msg);
+int rs_ctx_err_push (struct rs_handle *ctx, int code, const char *fmt, ...);
+int rs_conn_err_push (struct rs_connection *conn, int code, const char *fmt, ...);
+int rs_conn_err_push_fl(struct rs_connection *conn, int code, const char *file, int line, const char *fmt, ...);
 struct rs_error *rs_ctx_err_pop (struct rs_handle *ctx);
 struct rs_error *rs_conn_err_pop (struct rs_connection *conn);
 void rs_err_free (struct rs_error *err);
-char *rs_err_msg (struct rs_error *err);
-int rs_err_code (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);
 
 /* Local Variables: */
 /* c-file-style: "stroustrup" */
index e734452..68adf2b 100644 (file)
@@ -1,8 +1,11 @@
 #include <string.h>
+#include <assert.h>
 #include <freeradius/libradius.h>
 #include "libradsec.h"
 #include "libradsec-impl.h"
-
+#if defined DEBUG
+#include "debug.h"
+#endif
 
 int
 _packet_create (struct rs_connection *conn, struct rs_packet **pkt_out,
@@ -45,33 +48,45 @@ rs_packet_create_acc_request (struct rs_connection *conn,
 
   if (rs_attr_create (conn, &attr, "User-Name", user_name))
     return -1;
-  if (rs_packet_add_attr (pkt, attr))
-    return -1;
+  rs_packet_add_attr (pkt, attr);
 
   if (rs_attr_create (conn, &attr, "User-Password", user_name))
     return -1;
-  if (rs_packet_add_attr (pkt, attr))
-    return -1;
+  /* FIXME: need this too? rad_pwencode(user_pw, &pwlen, SECRET, reqauth) */
+  rs_packet_add_attr (pkt, attr);
 
   return RSE_OK;
 }
 
 int
-rs_packet_send (struct rs_conn *conn, const struct rs_packet *pkt,
+rs_packet_send (struct rs_connection *conn, const struct rs_packet *pkt,
                void *user_data)
 {
-  rad_encode (pkt->rpkt, NULL, pkt->conn->secret);
+  assert (pkt->rpkt);
+
+  if (!conn->active_peer)
+    {
+      int err = rs_conn_open (conn);
+      if (err)
+       return err;
+      }
+  rad_encode (pkt->rpkt, NULL, conn->active_peer->secret);
 #if defined (DEBUG)
-  fprintf (stderr, "%s: about to send this to %"
-  print_hex (pkt);
+  fprintf (stderr, "%s: about to send this to %s", __func__, "fixme");
+  rs_dump_packet (pkt);
 #endif
 
-  
-
   return RSE_NOSYS;
 }
 
-int rs_packet_receive(struct rs_conn *conn, struct rs_packet **pkt)
+int rs_packet_receive(struct rs_connection *conn, struct rs_packet **pkt)
 {
   return RSE_NOSYS;
 }
+
+void
+rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr)
+{
+  pairadd (&pkt->rpkt->vps, attr->vp);
+  attr->pkt = pkt;
+}
index f645ee1..e0c881a 100644 (file)
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
 #include <libgen.h>
 
 #include <freeradius/libradius.h>
@@ -12,40 +13,49 @@ rs_context_create(struct rs_handle **ctx, const char *dict)
 {
   struct rs_handle *h;
 
-  *ctx = NULL;
-  h = (struct rs_handle *) malloc (sizeof (struct rs_handle));
+  if (ctx)
+    *ctx = NULL;
+  h = (struct rs_handle *) malloc (sizeof(struct rs_handle));
   if (h)
     {
-      char *buf;
+      char *buf1 = NULL, *buf2 = NULL;
       char *dir, *fn;
 
-      buf = malloc (strlen (dict) + 1);
-      if (!buf)
+      buf1 = malloc (strlen (dict) + 1);
+      buf2 = malloc (strlen (dict) + 1);
+      if (!buf1 || !buf2)
        {
          free (h);
+         if (buf1)
+           free (buf1);
+         if (buf2)
+           free (buf2);
          return RSE_NOMEM;
        }
-      strcpy (buf, dict);
-      dir = dirname (buf);
-      free (buf);
-      strcpy (buf, dict);
-      fn = basename (buf);
-      free (buf);
+      strcpy (buf1, dict);
+      dir = dirname (buf1);
+      strcpy (buf2, dict);
+      fn = basename (buf2);
       if (dict_init (dir, fn) < 0)
        {
          free (h);
          return RSE_SOME_ERROR;
        }
+      free (buf1);
+      free (buf2);
 #if defined (DEBUG)
       fr_log_fp = stderr;
       fr_debug_flag = 1;
 #endif
+
+      memset (h, 0, sizeof(struct rs_handle));
       fr_randinit (&h->fr_randctx, 0);
       fr_rand_seed (NULL, 0);
 
-      *ctx = h;
+      if (ctx)
+       *ctx = h;
     }
-  return (h ? RSE_OK : RSE_NOMEM);
+  return h ? RSE_OK : RSE_NOMEM;
 }
 
 void rs_context_destroy(struct rs_handle *ctx)
@@ -63,17 +73,73 @@ int rs_context_config_read(struct rs_handle *ctx, const char *config_file)
   return RSE_NOSYS;
 }
 
-int rs_conn_create(const struct rs_handle *ctx, struct rs_connection **conn)
+int rs_conn_create(struct rs_handle *ctx, struct rs_connection **conn)
 {
-  return RSE_NOSYS;
+  struct rs_connection *c;
+
+  c = (struct rs_connection *) malloc (sizeof(struct rs_connection));
+  if (c)
+    {
+      memset (c, 0, sizeof(struct rs_connection));
+      c->ctx = ctx;
+      c->peers.next = &c->peers;
+    }
+  if (conn)
+    *conn = c;
+  return c ? RSE_OK : rs_ctx_err_push (ctx, RSE_NOMEM, NULL);
 }
 
-int rs_conn_add_server(struct rs_connection  *conn, rs_conn_type_t type, const char *host, int port, int timeout, int tries, const char *secret)
+struct addrinfo *
+_resolv (const char *host, int port)
 {
-  return RSE_NOSYS;
+  return NULL;
 }
 
-int rs_conn_add_listener(struct rs_connection  *conn, rs_conn_type_t type, const char *host, int port, const char *secret)
+int rs_conn_add_server(struct rs_connection *conn, struct rs_peer **server, rs_conn_type_t type, const char *host, int port)
+{
+  struct rs_peer *srv;
+
+  if (conn->type == RS_CONN_TYPE_NONE)
+    conn->type = type;
+  else if (conn->type != type)
+    return rs_conn_err_push (conn, RSE_CONN_TYPE_MISMATCH, NULL);
+
+  srv = (struct rs_peer *) malloc (sizeof(struct rs_peer));
+  if (srv)
+    {
+      memset (srv, 0, sizeof(struct rs_peer));
+      srv->conn = conn;
+      srv->addr = _resolv (host, port);
+      srv->timeout = 10;
+      srv->tries = 3;
+      srv->next = conn->peers.next;
+      conn->peers.next = srv;
+    }
+  if (*server)
+    *server = srv;
+  return srv ? RSE_OK : rs_conn_err_push (conn, RSE_NOMEM, NULL);
+}
+
+void rs_server_set_timeout(struct rs_peer *server, int timeout)
+{
+  server->timeout = timeout;
+}
+void rs_server_set_tries(struct rs_peer *server, int tries)
+{
+  server->tries = tries;
+}
+int rs_server_set_secret(struct rs_peer *server, const char *secret)
+{
+  if (server->secret)
+    free (server->secret);
+  server->secret = (char *) malloc (strlen(secret) + 1);
+  if (!server->secret)
+    return rs_conn_err_push (server->conn, RSE_NOMEM, NULL);
+  strcpy (server->secret, secret);
+  return RSE_OK;
+}
+
+int rs_conn_add_listener(struct rs_connection *conn, rs_conn_type_t type, const char *host, int port)
 {
   return RSE_NOSYS;
 }
@@ -102,3 +168,9 @@ int rs_conn_get_server(const struct rs_connection *conn, const char *name, size_
 {
   return RSE_NOSYS;
 }
+
+int rs_conn_open(struct rs_connection *conn)
+{
+  return rs_conn_err_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
+                             "%s: NYI", __func__);
+}