From b10a02e5f3a7dd184ada869015e438e63bca52bf Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 29 Sep 2010 15:52:39 +0200 Subject: [PATCH 1/1] 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(-) 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 #include #include +#include #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 #include #include +#include +#include #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__, ""); + 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__, ""); - 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 #include +#include #include #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; -- 2.1.4