From b10a02e5f3a7dd184ada869015e438e63bca52bf Mon Sep 17 00:00:00 2001
From: Linus Nordberg <linus@nordu.net>
Date: Wed, 29 Sep 2010 15:52:39 +0200
Subject: WIP -- connecting and sending a packet using libevent.

---
 lib/err.c             |  4 +--
 lib/examples/Makefile |  2 +-
 lib/examples/client.c | 12 ++-----
 lib/libradsec-impl.h  |  1 +
 lib/libradsec.h       |  6 ++--
 lib/packet.c          | 88 ++++++++++++++++++++++++++++++++++++++++++++-------
 lib/radsec.c          | 22 +++++++++++++
 7 files changed, 108 insertions(+), 27 deletions(-)

(limited to 'lib')

diff --git a/lib/err.c b/lib/err.c
index b0f05c6..74edeb0 100644
--- a/lib/err.c
+++ b/lib/err.c
@@ -13,8 +13,8 @@ const char *_errtxt[] = {
   "FreeRadius error"		/* 6 RSE_FR */
   "bad hostname or port"	/* 7 RSE_BADADDR */
   "no peer configured"		/* 8 RSE_NOPEER */
-  "ERR 9"			/*  RSE_ */
-  "ERR 10"			/*  RSE_ */
+  "libevent error"		/* 9 RSE_EVENT */
+  "connection error"		/* 10 RSE_CONNERR */
   "ERR 11"			/*  RSE_ */
   "ERR 12"			/*  RSE_ */
   "ERR 13"			/*  RSE_ */
diff --git a/lib/examples/Makefile b/lib/examples/Makefile
index a9876da..f9f2ee1 100644
--- a/lib/examples/Makefile
+++ b/lib/examples/Makefile
@@ -6,7 +6,7 @@ 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 -L .. -lradsec -L /usr/local/lib -levent
+	$(CC) $(CFLAGS) -o $@ $< -L /usr/lib/freeradius -lfreeradius-radius -L .. -lradsec -L /usr/local/lib -levent_core
 
 clean:
 	-rm *.o client
diff --git a/lib/examples/client.c b/lib/examples/client.c
index a6b7999..2304e49 100644
--- a/lib/examples/client.c
+++ b/lib/examples/client.c
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <event2/event.h>
 #include "../libradsec.h"
 #include "../debug.h"
 
@@ -18,14 +19,13 @@ rsx_client (const char *srvname, int srvport)
   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 NULL;
 
   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))
+  if (rs_conn_add_server (conn, &server, RS_CONN_TYPE_TCP, srvname, srvport))
     return rs_conn_err_pop (conn);
   rs_server_set_timeout (server, 10);
   rs_server_set_tries (server, 3);
@@ -38,14 +38,6 @@ rsx_client (const char *srvname, int srvport)
     return rs_conn_err_pop (conn);
   req = NULL;
 
-#if 0
-  printf ("waiting for response\n");
-  if (rs_packet_recv (conn, &resp))
-    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;
diff --git a/lib/libradsec-impl.h b/lib/libradsec-impl.h
index 939cdd9..e51c54c 100644
--- a/lib/libradsec-impl.h
+++ b/lib/libradsec-impl.h
@@ -79,6 +79,7 @@ struct rs_peer {
 
 struct rs_connection {
     struct rs_handle *ctx;
+    struct event_base *evb;
     enum rs_conn_type type;
     struct rs_credentials transport_credentials;
     struct rs_conn_callbacks callbacks;
diff --git a/lib/libradsec.h b/lib/libradsec.h
index 255c0f5..2ccafe2 100644
--- a/lib/libradsec.h
+++ b/lib/libradsec.h
@@ -14,6 +14,8 @@ enum rs_err_code {
     RSE_FR = 6,
     RSE_BADADDR = 7,
     RSE_NOPEER = 8,
+    RSE_EVENT = 9,
+    RSE_CONNERR = 10,
     RSE_SOME_ERROR = 21,
 };
 
@@ -48,7 +50,7 @@ int rs_context_config_read(struct rs_handle *ctx, const char *config_file);
 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 *hostname, int port);
 int rs_conn_add_listener(struct rs_connection  *conn, rs_conn_type_t type, const char *hostname, int port);
-void rs_conn_destroy(struct rs_connection  *conn);
+void 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_select_server(struct rs_connection *conn, const char *name);
@@ -69,7 +71,7 @@ void rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr);
 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_connection *conn, const struct rs_packet *pkt, void *user_data);
+int rs_packet_send(struct rs_connection *conn, struct rs_packet *pkt, void *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 *fmt, ...);
diff --git a/lib/packet.c b/lib/packet.c
index eefb5eb..652c495 100644
--- a/lib/packet.c
+++ b/lib/packet.c
@@ -1,6 +1,8 @@
 #include <string.h>
 #include <assert.h>
 #include <freeradius/libradius.h>
+#include <event2/event.h>
+#include <event2/bufferevent.h>
 #include "libradsec.h"
 #include "libradsec-impl.h"
 #if defined DEBUG
@@ -29,6 +31,7 @@ _packet_create (struct rs_connection *conn, struct rs_packet **pkt_out,
       return rs_conn_err_push (conn, RSE_NOMEM, __func__);
     }
   memset (p, 0, sizeof (struct rs_packet));
+  p->conn = conn;
   p->rpkt = rpkt;
 
   *pkt_out = p;
@@ -59,26 +62,87 @@ rs_packet_create_acc_request (struct rs_connection *conn,
   return RSE_OK;
 }
 
+static void
+_event_cb (struct bufferevent *bev, short events, void *ctx)
+{
+  struct rs_packet *pkt = (struct rs_packet *) ctx;
+
+  assert (pkt);
+  assert (pkt->conn);
+  if (events & BEV_EVENT_CONNECTED)
+    {
+#if defined (DEBUG)
+      fprintf (stderr, "%s: connected\n", __func__);
+#endif
+      rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret);
+#if defined (DEBUG)
+      fprintf (stderr, "%s: about to send this to %s:\n", __func__, "<fixme>");
+      rs_dump_packet (pkt);
+#endif
+      if (bufferevent_write(bev, pkt->rpkt->data, pkt->rpkt->data_len))
+	rs_conn_err_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
+			     "bufferevent_write");
+      /* Packet will be freed in write callback.  */
+    }
+  else if (events & BEV_EVENT_ERROR)
+    rs_conn_err_push_fl (pkt->conn, RSE_CONNERR, __FILE__, __LINE__, NULL);
+}
+
+void
+rs_packet_destroy(struct rs_packet *pkt)
+{
+  rad_free (&pkt->rpkt);
+  rs_free (pkt->conn->ctx, pkt);
+}
+
+static void
+_write_cb (struct bufferevent *bev, void *ctx)
+{
+  struct rs_packet *pkt = (struct rs_packet *) ctx;
+
+  assert (pkt);
+  assert (pkt->conn);
+#if defined (DEBUG)
+  fprintf (stderr, "%s: packet written, breaking event loop\n", __func__);
+#endif
+  if (event_base_loopbreak (pkt->conn->evb) < 0)
+    abort ();			/* FIXME */
+  rs_packet_destroy (pkt);
+}
+
 int
-rs_packet_send (struct rs_connection *conn, const struct rs_packet *pkt,
-		void *user_data)
+rs_packet_send (struct rs_connection *conn, struct rs_packet *pkt, void *data)
 {
+  struct bufferevent *bev;
+  struct rs_peer *p;
+
   assert (pkt->rpkt);
 
-  if (!conn->active_peer)
+  if (rs_conn_open (conn))
+    return -1;
+  p = conn->active_peer;
+  assert (p);
+
+  assert (conn->active_peer->s >= 0);
+  bev = bufferevent_socket_new (conn->evb, conn->active_peer->s, 0);
+  if (!bev)
+    return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
+				"bufferevent_socket_new");
+  if (bufferevent_socket_connect (bev, p->addr->ai_addr, p->addr->ai_addrlen) < 0)
     {
-      int err = rs_conn_open (conn);
-      if (err)
-	return err;
-      }
-  rad_encode (pkt->rpkt, NULL, conn->active_peer->secret);
+      bufferevent_free (bev);
+      return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
+				  "bufferevent_socket_connect");
+    }
+
+  bufferevent_setcb (bev, NULL, _write_cb, _event_cb, pkt);
+  event_base_dispatch (conn->evb);
 #if defined (DEBUG)
-  fprintf (stderr, "%s: about to send this to %s:\n", __func__, "<fixme>");
-  rs_dump_packet (pkt);
+  fprintf (stderr, "%s: event loop done\n", __func__);
+  assert (event_base_got_break(conn->evb));
 #endif
 
-  return rs_conn_err_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__,
-			      "%s: NYI", __func__);
+  return RSE_OK;
 }
 
 int rs_packet_receive(struct rs_connection *conn, struct rs_packet **pkt)
diff --git a/lib/radsec.c b/lib/radsec.c
index 97f62e6..82576e1 100644
--- a/lib/radsec.c
+++ b/lib/radsec.c
@@ -5,6 +5,7 @@
 #include <libgen.h>
 
 #include <freeradius/libradius.h>
+#include <event2/event.h>
 #include <event2/util.h>
 #include "libradsec.h"
 #include "libradsec-impl.h"
@@ -202,6 +203,9 @@ rs_conn_destroy(struct rs_connection *conn)
       if (p->secret)
 	rs_free (conn->ctx, p->secret);
     }
+
+  if (conn->evb)
+    event_base_free (conn->evb);
 }
 
 int rs_conn_set_eventbase(struct rs_connection *conn, struct event_base *eb)
@@ -245,6 +249,7 @@ rs_conn_open(struct rs_connection *conn)
   if (s < 0)
     return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
 				strerror (errno));
+#if 0		       /* let librevent do this in rs_packet_send() */
   if (connect (s, p->addr->ai_addr, p->addr->ai_addrlen))
     {
       /* TODO: handle nonblocking sockets (EINTR, EAGAIN).  */
@@ -252,6 +257,23 @@ rs_conn_open(struct rs_connection *conn)
       return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
 				  strerror (errno));
     }
+#endif
+
+  if (!conn->evb)
+    {
+#if defined (DEBUG)
+      event_enable_debug_mode ();
+#endif
+      conn->evb = event_base_new ();
+    }
+
+  if (!conn->evb)
+    {
+      EVUTIL_CLOSESOCKET (s);
+      return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
+				  "event_base_new");
+    }
+
   p->s = s;
   conn->active_peer = p;
   return RSE_OK;
-- 
cgit v1.1