From 714fa685ee2f704a9d1945a7b0b1fa73bfe6ff55 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 3 Mar 2011 11:50:35 +0100 Subject: Correct an error string. --- lib/packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packet.c b/lib/packet.c index 9527012..ea1a07f 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -452,7 +452,7 @@ _set_timeout (struct rs_connection *conn) conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); if (!conn->tev) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "event_new"); + "evtimer_new"); tv.tv_sec = conn->realm->timeout; tv.tv_usec = 0; evtimer_add (conn->tev, &tv); -- cgit v1.1 From b01fafad7778040ec98619653328deecc1ef1ab1 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 3 Mar 2011 14:02:40 +0100 Subject: Correct an error code. --- lib/packet.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/packet.c b/lib/packet.c index ea1a07f..2ef7e45 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -46,9 +46,11 @@ _do_send (struct rs_packet *pkt) assert (pkt->rpkt); assert (!pkt->original); + /* Add Message-Authenticator, RFC 2869. */ + /* FIXME: Make Message-Authenticator optional? */ vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); if (!vp) - return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, + return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "paircreate: %s", fr_strerror ()); pairadd (&pkt->rpkt->vps, vp); -- cgit v1.1 From 41a69151d5a375f524e2227f87979ff758bf2a62 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 3 Mar 2011 16:05:48 +0100 Subject: _init_evb: Don't crash on socket errors. --- lib/compat.c | 8 ++++++++ lib/compat.h | 1 + lib/packet.c | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 lib/compat.c create mode 100644 lib/compat.h diff --git a/lib/compat.c b/lib/compat.c new file mode 100644 index 0000000..731c071 --- /dev/null +++ b/lib/compat.c @@ -0,0 +1,8 @@ +#include +#include + +ssize_t +compat_send (int sockfd, const void *buf, size_t len, int flags) +{ + compat_send (int sockfd, const void *buf, size_t len, int flags); +} diff --git a/lib/compat.h b/lib/compat.h new file mode 100644 index 0000000..202d6dd --- /dev/null +++ b/lib/compat.h @@ -0,0 +1 @@ +ssize_t compat_send (int sockfd, const void *buf, size_t len, int flags); diff --git a/lib/packet.c b/lib/packet.c index 2ef7e45..d025027 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -404,13 +404,15 @@ _init_socket (struct rs_connection *conn, struct rs_peer *p) p->addr->ai_protocol); if (conn->fd < 0) return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, - strerror (errno)); + "socket: %d (%s)", + errno, strerror (errno)); if (evutil_make_socket_nonblocking (conn->fd) < 0) { evutil_closesocket (conn->fd); conn->fd = -1; return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, - strerror (errno)); + "evutil_make_socket_nonblocking: %d (%s)", + errno, strerror (errno)); } return RSE_OK; } -- cgit v1.1 From b884a7a9c4b846f8e9f571f50cd9c5d9518e6ca2 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 4 Mar 2011 12:51:42 +0100 Subject: Do free the config object. --- lib/conf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/conf.c b/lib/conf.c index 5c1c51b..adbda25 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -118,6 +118,7 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) p->secret = strdup (cfg_getstr (cfg_server, "secret")); } } + cfg_free (cfg); return RSE_OK; } -- cgit v1.1 From 69b4b2fa50c7789ae16c2b417c8c291ed780770d Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 4 Mar 2011 13:00:42 +0100 Subject: Do _copy_ the strings from the config object. --- lib/conf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/conf.c b/lib/conf.c index adbda25..ff225ce 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -98,10 +98,10 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) 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");*/ - r->certfile = cfg_getstr (cfg_config, "certfile"); - r->certkeyfile = cfg_getstr (cfg_config, "certkeyfile"); + r->cacertfile = strdup (cfg_getstr (cfg_config, "cacertfile")); + /*r->cacertpath = strdup (cfg_getstr (cfg_config, "cacertpath"));*/ + r->certfile = strdup (cfg_getstr (cfg_config, "certfile")); + r->certkeyfile = strdup (cfg_getstr (cfg_config, "certkeyfile")); /* Add peers, one per server stanza. */ for (j = 0; j < cfg_size (cfg_config, "server"); j++) -- cgit v1.1 From c1de57efcaa05f4127a73f99c9f366149dc4b98f Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 4 Mar 2011 13:27:57 +0100 Subject: Revert 578e3551 -- double free in second invocation of dict_free(). --- lib/radsec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/radsec.c b/lib/radsec.c index 6cc9fe4..f8bd246 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -142,7 +142,6 @@ void rs_context_destroy(struct rs_context *ctx) r = r->next; rs_free (ctx, tmp); } - dict_free (); rs_free (ctx, ctx); } -- cgit v1.1 From f87be530d67823a5d82367468e33d58b201ebee1 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 14:30:14 +0100 Subject: Don't free config object until we destroy the context. --- lib/conf.c | 28 ++++++++++++++++++---------- lib/include/radsec/radsec-impl.h | 2 ++ lib/radsec.c | 5 +++++ 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/conf.c b/lib/conf.c index ff225ce..c8b2a46 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -31,9 +31,12 @@ int rs_context_read_config(struct rs_context *ctx, const char *config_file) { - /* FIXME: Missing some error handling in rs_context_read_config(). */ + cfg_t *cfg, *cfg_config, *cfg_server; + int i, j; + const char *s; + cfg_opt_t server_opts[] = { CFG_STR ("hostname", NULL, CFGF_NONE), @@ -58,8 +61,6 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) CFG_SEC ("config", config_opts, CFGF_TITLE | CFGF_MULTI), CFG_END () }; - cfg_t *cfg, *cfg_config, *cfg_server; - int i, j; cfg = cfg_init (opts, CFGF_NONE); if (cfg_parse (cfg, config_file) == CFG_PARSE_ERROR) @@ -81,7 +82,11 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) else ctx->realms = r; cfg_config = cfg_getnsec (cfg, "config", i); - r->name = strdup (cfg_title (cfg_config)); + s = cfg_title (cfg_config); + if (s == NULL) + return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__, + "missing config name"); + r->name = strdup (s); typestr = cfg_getstr (cfg_config, "type"); if (!strcmp (typestr, "UDP")) @@ -98,10 +103,10 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) r->timeout = cfg_getint (cfg_config, "timeout"); r->retries = cfg_getint (cfg_config, "retries"); - r->cacertfile = strdup (cfg_getstr (cfg_config, "cacertfile")); - /*r->cacertpath = strdup (cfg_getstr (cfg_config, "cacertpath"));*/ - r->certfile = strdup (cfg_getstr (cfg_config, "certfile")); - r->certkeyfile = strdup (cfg_getstr (cfg_config, "certkeyfile")); + r->cacertfile = cfg_getstr (cfg_config, "cacertfile"); + /*r->cacertpath = cfg_getstr (cfg_config, "cacertpath");*/ + r->certfile = cfg_getstr (cfg_config, "certfile"); + r->certkeyfile = cfg_getstr (cfg_config, "certkeyfile"); /* Add peers, one per server stanza. */ for (j = 0; j < cfg_size (cfg_config, "server"); j++) @@ -115,10 +120,13 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) cfg_server = cfg_getnsec (cfg_config, "server", j); _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->secret = cfg_getstr (cfg_server, "secret"); } } - cfg_free (cfg); + + /* Save config object in context, for freeing in + rs_context_destroy(). */ + ctx->cfg = cfg; return RSE_OK; } diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index 932e5d2..963c821 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -5,6 +5,7 @@ #include #include +#include #if defined(RS_ENABLE_TLS) #include #endif @@ -61,6 +62,7 @@ struct rs_context { struct rs_alloc_scheme alloc_scheme; struct rs_error *err; fr_randctx fr_randctx; + cfg_t *cfg; }; struct rs_connection { diff --git a/lib/radsec.c b/lib/radsec.c index f8bd246..afb871e 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -142,6 +142,11 @@ void rs_context_destroy(struct rs_context *ctx) r = r->next; rs_free (ctx, tmp); } + + if (ctx->cfg) + cfg_free (ctx->cfg); + ctx->cfg = NULL; + rs_free (ctx, ctx); } -- cgit v1.1 From fda0bfd44f940688f85fe3a99a0c8cd91611452f Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 14:44:27 +0100 Subject: Cosmetic changes. --- lib/packet.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/packet.c b/lib/packet.c index d025027..9874dee 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -330,9 +330,9 @@ _read_packet (struct rs_packet *pkt) Inform upper layer about successful reception of valid RADIUS message by invoking conn->callbacks.recevied_cb(), if !NULL. */ static void -_read_cb (struct bufferevent *bev, void *ctx) +_read_cb (struct bufferevent *bev, void *user_data) { - struct rs_packet *pkt = (struct rs_packet *) ctx; + struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); assert (pkt->conn); @@ -765,21 +765,21 @@ rs_conn_receive_packet (struct rs_connection *conn, } void -rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr) +rs_packet_add_attr (struct rs_packet *pkt, struct rs_attr *attr) { pairadd (&pkt->rpkt->vps, attr->vp); attr->pkt = pkt; } struct radius_packet * -rs_packet_frpkt(struct rs_packet *pkt) +rs_packet_frpkt (struct rs_packet *pkt) { assert (pkt); return pkt->rpkt; } void -rs_packet_destroy(struct rs_packet *pkt) +rs_packet_destroy (struct rs_packet *pkt) { if (pkt) { -- cgit v1.1 From 7636505962a348d9564e53922834dc6df1274653 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 14:46:57 +0100 Subject: UDP w/o bufferevents, part 1. Sending, no retransmitting and no receiving. --- lib/Makefile.am | 3 +- lib/compat.c | 3 +- lib/conn.c | 14 +- lib/examples/client-udp.conf | 6 +- lib/include/radsec/radsec-impl.h | 13 +- lib/packet.c | 277 +++++++++++++++++++++++++++++---------- lib/radsec.c | 3 +- 7 files changed, 233 insertions(+), 86 deletions(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index 311d3cc..69c1c27 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -10,6 +10,7 @@ lib_LTLIBRARIES = libradsec.la libradsec_la_SOURCES = \ attr.c \ + compat.c \ conf.c \ conn.c \ debug.c \ @@ -32,4 +33,4 @@ libradsec_la_SOURCES += \ endif libradsec_la_LDFLAGS = -version-info 0:0:0 -libradsec_la_CFLAGS = $(AM_CFLAGS) #-DDEBUG -DDEBUG_LEVENT -Werror +libradsec_la_CFLAGS = $(AM_CFLAGS) -DDEBUG -DDEBUG_LEVENT -Werror # -ansi diff --git a/lib/compat.c b/lib/compat.c index 731c071..b00bea1 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -1,8 +1,9 @@ #include #include +#include "compat.h" ssize_t compat_send (int sockfd, const void *buf, size_t len, int flags) { - compat_send (int sockfd, const void *buf, size_t len, int flags); + return send (sockfd, buf, len, flags); } diff --git a/lib/conn.c b/lib/conn.c index 904596b..48d2fe5 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -126,25 +127,22 @@ rs_conn_destroy (struct rs_connection *conn) assert (conn); - if (conn->is_connected) - { - err = rs_conn_disconnect (conn); - if (err) - return err; - } - /* NOTE: conn->realm is owned by context. */ /* NOTE: conn->peers is owned by context. */ + if (conn->is_connected) + err = rs_conn_disconnect (conn); if (conn->tev) event_free (conn->tev); + if (conn->bev) + bufferevent_free (conn->bev); if (conn->evb) event_base_free (conn->evb); /* TODO: free tls_ctx */ /* TODO: free tls_ssl */ - return 0; + return err; } int diff --git a/lib/examples/client-udp.conf b/lib/examples/client-udp.conf index a83fb26..8578e8b 100644 --- a/lib/examples/client-udp.conf +++ b/lib/examples/client-udp.conf @@ -1,10 +1,10 @@ config blocking-udp { type = "UDP" + timeout = 2 + retries = 2 server { - hostname = "localhost" + hostname = "127.0.0.1" service = "1820" secret = "sikrit" - timeout = 1 /* optional */ - tries = 10 /* optional */ } } diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index 963c821..f8904ac 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -69,7 +69,6 @@ struct rs_connection { struct rs_context *ctx; 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; @@ -80,10 +79,17 @@ struct rs_connection { 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 tryagain; /* For server failover. */ + int nextid; /* Next RADIUS packet identifier. */ int user_dispatch_flag : 1; /* User does the dispatching. */ + /* 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). */ + struct rs_packet *out_queue; /* Queue for outgoing UDP packets. */ #if defined(RS_ENABLE_TLS) + /* TLS specifics. */ SSL_CTX *tls_ctx; SSL *tls_ssl; #endif @@ -97,6 +103,7 @@ struct rs_packet { struct rs_packet *original; char valid_flag; char written_flag; + struct rs_packet *next; /* Used for UDP output queue. */ }; struct rs_attr { diff --git a/lib/packet.c b/lib/packet.c index 9874dee..afe2725 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -8,17 +8,19 @@ #include #include #include +#include #include #include #include #include #include #include -#include "tls.h" +#include "compat.h" #include "debug.h" #if defined (RS_ENABLE_TLS) #include #include +#include "tls.h" #endif #if defined (DEBUG) #include @@ -27,6 +29,18 @@ #endif static int +_close_conn (struct rs_connection **connp) +{ + int r; + assert (connp); + assert (*connp); + r = rs_conn_destroy (*connp); + if (!r) + *connp = NULL; + return r; +} + +static int _loopbreak (struct rs_connection *conn) { int err = event_base_loopbreak (conn->evb); @@ -37,11 +51,12 @@ _loopbreak (struct rs_connection *conn) return err; } +/* Badly named helper function for preparing a RADIUS message and + queue it. FIXME: Rename. */ static int _do_send (struct rs_packet *pkt) { - int err; - VALUE_PAIR *vp; + VALUE_PAIR *vp = NULL; assert (pkt->rpkt); assert (!pkt->original); @@ -73,23 +88,39 @@ _do_send (struct rs_packet *pkt) } #endif - err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, - pkt->rpkt->data_len); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "bufferevent_write: %s", - evutil_gai_strerror (err)); + if (pkt->conn->bev) + { + int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, + pkt->rpkt->data_len); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "bufferevent_write: %s", + evutil_gai_strerror (err)); + } + else + { + struct rs_packet **pp = &pkt->conn->out_queue; + + while (*pp && (*pp)->next) + *pp = (*pp)->next; + *pp = pkt; + } + return RSE_OK; } static void -_on_connect (struct rs_connection *conn) +_on_connect (struct rs_connection *conn, struct rs_packet *pkt) { + assert (!conn->is_connecting); conn->is_connected = 1; rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); - evtimer_del (conn->tev); + if (conn->tev) + evtimer_del (conn->tev); if (conn->callbacks.connected_cb) conn->callbacks.connected_cb (conn->user_data); + if (pkt) + _do_send (pkt); } static void @@ -103,9 +134,9 @@ _on_disconnect (struct rs_connection *conn) } static void -_event_cb (struct bufferevent *bev, short events, void *ctx) +_event_cb (struct bufferevent *bev, short events, void *user_data) { - struct rs_packet *pkt = (struct rs_packet *)ctx; + struct rs_packet *pkt = (struct rs_packet *) user_data; struct rs_connection *conn = NULL; struct rs_peer *p = NULL; int sockerr = 0; @@ -122,9 +153,7 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) conn->is_connecting = 0; if (events & BEV_EVENT_CONNECTED) { - _on_connect (conn); - if (_do_send (pkt)) - rs_debug (("%s: error sending\n", __func__)); + _on_connect (conn, pkt); } else if (events & BEV_EVENT_EOF) { @@ -145,15 +174,11 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) } else { + rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr, + evutil_socket_error_to_string (sockerr))); rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: socket error %d (%s)", - conn->fd, - sockerr, + "%d: %d (%s)", conn->fd, sockerr, evutil_socket_error_to_string (sockerr)); - 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) if (conn->tls_ssl) /* FIXME: correct check? */ @@ -204,7 +229,7 @@ _read_header (struct rs_packet *pkt) pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3]; if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT, "invalid packet length: %d", pkt->rpkt->data_len); @@ -212,7 +237,7 @@ _read_header (struct rs_packet *pkt) pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len); if (!pkt->rpkt->data) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, NULL); } @@ -228,7 +253,7 @@ _read_header (struct rs_packet *pkt) } else /* Error: libevent gave us less than the low watermark. */ { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__, "got %d octets reading header", n); } @@ -264,7 +289,7 @@ _read_packet (struct rs_packet *pkt) - attribute sizes adding up correctly */ if (!rad_packet_ok (pkt->rpkt, 0) != 0) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "invalid packet: %s", fr_strerror ()); } @@ -280,7 +305,7 @@ _read_packet (struct rs_packet *pkt) if (rad_verify (pkt->rpkt, pkt->original->rpkt, pkt->conn->active_peer->secret)) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_verify: %s", fr_strerror ()); } @@ -289,7 +314,7 @@ _read_packet (struct rs_packet *pkt) if (rad_decode (pkt->rpkt, pkt->original->rpkt, pkt->conn->active_peer->secret)) { - bufferevent_free (pkt->conn->bev); /* Close connection. */ + _close_conn (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_decode: %s", fr_strerror ()); } @@ -376,7 +401,7 @@ _evlog_cb (int severity, const char *msg) } static int -_init_evb (struct rs_connection *conn) +_init_eventbase (struct rs_connection *conn) { if (conn->evb) return RSE_OK; @@ -465,27 +490,21 @@ _set_timeout (struct rs_connection *conn) } static int -_init_bev (struct rs_connection *conn, struct rs_peer *peer) +_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer) { if (conn->bev) return RSE_OK; - switch (conn->realm->type) + if (conn->realm->type == RS_CONN_TYPE_TCP) { - 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, 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: + else if (conn->realm->type == RS_CONN_TYPE_TLS) + { if (rs_tls_init (conn)) return -1; /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things @@ -497,13 +516,10 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer) 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__, NULL); + } #endif /* RS_ENABLE_TLS */ - - default: + else + { return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__, "%s: unknown connection type: %d", __func__, conn->realm->type); @@ -512,11 +528,81 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer) return RSE_OK; } +/* Callback for conn->wev and conn->rev. FIXME: Rename. */ +static void +_evcb (evutil_socket_t fd, short what, void *user_data) +{ + //rs_debug (("%s: fd=%d what=0x%x\n", __func__, fd, what)); + if (what & EV_TIMEOUT) + { + struct rs_connection *conn = (struct rs_connection *) user_data; + assert (conn); + conn->is_connecting = 0; + rs_debug (("%s: UDP timeout NYI", __func__)); + } + else if (what & EV_READ) + { + struct rs_connection *conn = (struct rs_connection *) user_data; + assert (conn); + /* read a single UDP packet and stick it in a new struct + rs_packet */ + + rs_debug (("%s: UDP read NYI", __func__)); + } + else if (what & EV_WRITE) + { + struct rs_packet *pkt = (struct rs_packet *) user_data; + assert (pkt); + /* Socket ready for writing, possibly as a result of a + successful connect. */ + if (!pkt->conn->is_connected) + _on_connect (pkt->conn, pkt); + if (pkt->conn->out_queue) + { + /* Send one packet, the first. */ + ssize_t r = 0; + struct rs_packet *p = pkt->conn->out_queue; + + assert (p->rpkt); + assert (p->rpkt->data); + r = compat_send (fd, p->rpkt->data, p->rpkt->data_len, 0); + if (r == -1) + { + int sockerr = evutil_socket_geterror (p->conn->fd); + if (sockerr != EAGAIN) + rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: send: %d (%s)", fd, sockerr, + evutil_socket_error_to_string (sockerr)); + return; /* Don't unlink packet. */ + } + pkt->conn->out_queue = p->next; + } + } +} + +static int +_init_udp (struct rs_connection *conn, struct rs_packet *pkt) +{ + assert (!conn->bev); + + conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn); + conn->wev = event_new (conn->evb, conn->fd, EV_WRITE|EV_PERSIST, _evcb, pkt); + if (!conn->rev || !conn->wev) + { + if (conn->rev) + event_free (conn->rev); + /* ENOMEM _or_ EINVAL but EINVAL only if we use EV_SIGNAL, at + least for now (libevent-2.0.5). */ + return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); + } + return RSE_OK; +} + static void _do_connect (struct rs_connection *conn) { struct rs_peer *p; - int err; + int err, sockerr; assert (conn); assert (conn->active_peer); @@ -534,21 +620,37 @@ _do_connect (struct rs_connection *conn) } #endif - _set_timeout (conn); - 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)); - else - p->conn->is_connecting = 1; + if (p->conn->bev) /* TCP */ + { + _set_timeout (conn); + 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)); + else + p->conn->is_connecting = 1; + } + else /* UDP */ + { + err = connect (p->conn->fd, p->addr->ai_addr, p->addr->ai_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_error_to_string (sockerr))); + rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: connect: %d (%s)", p->conn->fd, sockerr, + evutil_socket_error_to_string (sockerr)); + } + } } static int -_conn_open(struct rs_connection *conn, struct rs_packet *pkt) +_conn_open (struct rs_connection *conn, struct rs_packet *pkt) { - if (_init_evb (conn)) + if (_init_eventbase (conn)) return -1; if (!conn->active_peer) @@ -559,8 +661,17 @@ _conn_open(struct rs_connection *conn, struct rs_packet *pkt) if (_init_socket (conn, conn->active_peer)) return -1; - if (_init_bev (conn, conn->active_peer)) - return -1; + if (conn->realm->type == RS_CONN_TYPE_TCP + || conn->realm->type == RS_CONN_TYPE_TLS) + { + if (_init_bufferevent (conn, conn->active_peer)) + return -1; + } + else + { + if (_init_udp (conn, pkt)) + return -1; + } if (!conn->is_connected) if (!conn->is_connecting) @@ -640,7 +751,10 @@ _wcb (void *user_data) struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); pkt->written_flag = 1; - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + if (pkt->conn->bev) + bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + else + event_del (pkt->conn->wev); } int @@ -660,13 +774,24 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) return -1; assert (conn->evb); - assert (conn->bev); assert (conn->active_peer); assert (conn->fd >= 0); conn->user_data = user_data; - bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_WRITE); + + if (conn->bev) /* TCP */ + { + bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt); + bufferevent_enable (conn->bev, EV_WRITE); + } + else /* UDP */ + { + err = event_add (conn->wev, NULL); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", + evutil_gai_strerror (err)); + } /* Do dispatch, unless the user wants to do it herself. */ if (!conn->user_dispatch_flag) @@ -696,7 +821,10 @@ _rcb (struct rs_packet *packet, void *user_data) struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); pkt->valid_flag = 1; - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + if (pkt->conn->bev) + bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + else + event_del (pkt->conn->rev); } /* Special function used in libradsec blocking dispatching mode, @@ -737,11 +865,22 @@ rs_conn_receive_packet (struct rs_connection *conn, assert (conn->active_peer); assert (conn->fd >= 0); - bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); - bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_READ); conn->callbacks.received_cb = _rcb; conn->user_data = pkt; + if (conn->bev) + { + bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); + bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt); + bufferevent_enable (conn->bev, EV_READ); + } + else + { + err = event_add (conn->rev, NULL); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", + evutil_gai_strerror (err)); + } /* Dispatch. */ rs_debug (("%s: entering event loop\n", __func__)); diff --git a/lib/radsec.c b/lib/radsec.c index afb871e..f191e73 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -125,7 +125,8 @@ _rs_peer_destroy (struct rs_peer *p) rs_free (p->conn->ctx, p); } -void rs_context_destroy(struct rs_context *ctx) +void +rs_context_destroy (struct rs_context *ctx) { struct rs_realm *r = NULL; struct rs_peer *p = NULL; -- cgit v1.1 From 5c60297a1eaab7b10d6f584ba329493a41b812d0 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 15:53:58 +0100 Subject: Restructure code, moving most code out of packet.c Also, move copyright notice out of COPYING and into every file. --- lib/COPYING | 2 - lib/Makefile.am | 6 +- lib/attr.c | 3 +- lib/compat.c | 7 + lib/compat.h | 3 + lib/conf.c | 3 +- lib/conn.c | 93 ++++++- lib/debug.c | 3 +- lib/debug.h | 3 +- lib/err.c | 3 +- lib/event.c | 252 ++++++++++++++++++ lib/event.h | 11 + lib/packet.c | 782 +------------------------------------------------------- lib/packet.h | 4 + lib/peer.c | 19 +- lib/peer.h | 4 + lib/radsec.c | 5 +- lib/radsec.h | 9 + lib/request.c | 3 +- lib/send.c | 128 ++++++++++ lib/tcp.c | 276 ++++++++++++++++++++ lib/tcp.h | 6 + lib/tls.c | 3 +- lib/tls.h | 3 +- lib/udp.c | 85 ++++++ lib/udp.h | 4 + 26 files changed, 931 insertions(+), 789 deletions(-) create mode 100644 lib/event.c create mode 100644 lib/event.h create mode 100644 lib/packet.h create mode 100644 lib/peer.h create mode 100644 lib/radsec.h create mode 100644 lib/send.c create mode 100644 lib/tcp.c create mode 100644 lib/tcp.h create mode 100644 lib/udp.c create mode 100644 lib/udp.h diff --git a/lib/COPYING b/lib/COPYING index 0a1858c..7256aa4 100644 --- a/lib/COPYING +++ b/lib/COPYING @@ -1,5 +1,3 @@ -Copyright 2010, 2011 NORDUnet A/S. All rights reserved. - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/lib/Makefile.am b/lib/Makefile.am index 69c1c27..fdaf1ec 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -15,10 +15,14 @@ libradsec_la_SOURCES = \ conn.c \ debug.c \ err.c \ + event.c \ packet.c \ peer.c \ radsec.c \ - request.c + request.c \ + send.c \ + tcp.c \ + udp.c libradsec_la_SOURCES += \ rsp_debug.c \ diff --git a/lib/attr.c b/lib/attr.c index 29384d5..23efa6e 100644 --- a/lib/attr.c +++ b/lib/attr.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include diff --git a/lib/compat.c b/lib/compat.c index b00bea1..fa075a1 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -1,3 +1,10 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +#if defined HAVE_CONFIG_H +#include +#endif + #include #include #include "compat.h" diff --git a/lib/compat.h b/lib/compat.h index 202d6dd..50ae22e 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -1 +1,4 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + ssize_t compat_send (int sockfd, const void *buf, size_t len, int flags); diff --git a/lib/conf.c b/lib/conf.c index c8b2a46..1d394ba 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include diff --git a/lib/conn.c b/lib/conn.c index 48d2fe5..14693ae 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include @@ -11,6 +12,8 @@ #include #include #include +#include "event.h" +#include "tcp.h" int rs_conn_create (struct rs_context *ctx, struct rs_connection **conn, @@ -193,3 +196,91 @@ int rs_conn_fd (struct rs_connection *conn) assert (conn->active_peer); return conn->fd; } + +static void +_rcb (struct rs_packet *packet, void *user_data) +{ + struct rs_packet *pkt = (struct rs_packet *) user_data; + assert (pkt); + pkt->valid_flag = 1; + if (pkt->conn->bev) + bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + else + event_del (pkt->conn->rev); +} + +/* Special function used in libradsec blocking dispatching mode, + i.e. with socket set to block on read/write and with no libradsec + callbacks registered. + + For any other use of libradsec, a the received_cb callback should + be registered in the callbacks member of struct rs_connection. + + On successful reception, verification and decoding of a RADIUS + message, PKT_OUT will upon return point at a pointer to a struct + rs_packet containing the message. + + If anything goes wrong or if the read times out (TODO: explain), + PKT_OUT will point at the NULL pointer and one or more errors are + pushed on the connection (available through rs_err_conn_pop()). */ + +int +rs_conn_receive_packet (struct rs_connection *conn, + struct rs_packet *request, + struct rs_packet **pkt_out) +{ + 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)) + return -1; + pkt = *pkt_out; + pkt->conn = conn; + pkt->original = request; + + assert (conn->evb); + assert (conn->bev); + assert (conn->active_peer); + assert (conn->fd >= 0); + + conn->callbacks.received_cb = _rcb; + conn->user_data = pkt; + if (conn->bev) + { + bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); + bufferevent_setcb (conn->bev, tcp_read_cb, NULL, tcp_event_cb, pkt); + bufferevent_enable (conn->bev, EV_READ); + } + else + { + err = event_add (conn->rev, NULL); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", + evutil_gai_strerror (err)); + } + + /* 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)); + rs_debug (("%s: event loop done\n", __func__)); + + if (!pkt->valid_flag) + return -1; + +#if defined (DEBUG) + rs_dump_packet (pkt); +#endif + + pkt->original = NULL; /* FIXME: Why? */ + return RSE_OK; +} diff --git a/lib/debug.c b/lib/debug.c index 4544f3c..59f25c1 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include diff --git a/lib/debug.h b/lib/debug.h index 4a899b2..a8d8632 100644 --- a/lib/debug.h +++ b/lib/debug.h @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #define hd(p, l) { int i; \ for (i = 1; i <= l; i++) { \ diff --git a/lib/err.c b/lib/err.c index 1e1dfaf..55fc5de 100644 --- a/lib/err.c +++ b/lib/err.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include diff --git a/lib/event.c b/lib/event.c new file mode 100644 index 0000000..97a08c8 --- /dev/null +++ b/lib/event.c @@ -0,0 +1,252 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +#if defined HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined (RS_ENABLE_TLS) +#include +#include +#endif +#include +#include +#if defined (RS_ENABLE_TLS) +#include "tls.h" +#endif +#include "udp.h" +#include "event.h" +#include "packet.h" +#include "debug.h" + +static void +_evlog_cb (int severity, const char *msg) +{ + const char *sevstr; + switch (severity) + { + case _EVENT_LOG_DEBUG: +#if !defined (DEBUG_LEVENT) + return; +#endif + sevstr = "debug"; + break; + case _EVENT_LOG_MSG: + sevstr = "msg"; + break; + case _EVENT_LOG_WARN: + sevstr = "warn"; + break; + case _EVENT_LOG_ERR: + sevstr = "err"; + break; + default: + sevstr = "???"; + break; + } + fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr? */ +} + +int +event_init_socket (struct rs_connection *conn, struct rs_peer *p) +{ + if (conn->fd != -1) + return RSE_OK; + + assert (p->addr); + 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_SOCKERR, __FILE__, __LINE__, + "socket: %d (%s)", + errno, strerror (errno)); + if (evutil_make_socket_nonblocking (conn->fd) < 0) + { + evutil_closesocket (conn->fd); + conn->fd = -1; + return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, + "evutil_make_socket_nonblocking: %d (%s)", + errno, strerror (errno)); + } + return RSE_OK; +} + +static void +_conn_timeout_cb (int fd, short event, void *data) +{ + struct rs_connection *conn; + + assert (data); + conn = (struct rs_connection *) 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; + rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); + event_loopbreak (conn); + } +} + +int +event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer) +{ + if (conn->bev) + return RSE_OK; + + if (conn->realm->type == RS_CONN_TYPE_TCP) + { + 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"); + } +#if defined (RS_ENABLE_TLS) + else if (conn->realm->type == RS_CONN_TYPE_TLS) + { + if (rs_tls_init (conn)) + return -1; + /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things + 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, 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"); + } +#endif /* RS_ENABLE_TLS */ + else + { + return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__, + "%s: unknown connection type: %d", __func__, + conn->realm->type); + } + + return RSE_OK; +} + +void +event_do_connect (struct rs_connection *conn) +{ + struct rs_peer *p; + int err, sockerr; + + 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 + + if (p->conn->bev) /* TCP */ + { + event_set_timeout (conn); + 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)); + else + p->conn->is_connecting = 1; + } + else /* UDP */ + { + err = connect (p->conn->fd, p->addr->ai_addr, p->addr->ai_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_error_to_string (sockerr))); + rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: connect: %d (%s)", p->conn->fd, sockerr, + evutil_socket_error_to_string (sockerr)); + } + } +} + +int +event_loopbreak (struct rs_connection *conn) +{ + int err = event_base_loopbreak (conn->evb); + if (err < 0) + rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, + "event_base_loopbreak: %s", + evutil_gai_strerror (err)); + return err; +} + + +int +event_set_timeout (struct rs_connection *conn) +{ + struct timeval tv; + + if (!conn->tev) + conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); + if (!conn->tev) + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, + "evtimer_new"); + tv.tv_sec = conn->realm->timeout; + tv.tv_usec = 0; + evtimer_add (conn->tev, &tv); + + return RSE_OK; +} + +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)); + if (conn->callbacks.disconnected_cb) + conn->callbacks.disconnected_cb (conn->user_data); +} + +void +event_on_connect (struct rs_connection *conn, struct rs_packet *pkt) +{ + assert (!conn->is_connecting); + conn->is_connected = 1; + rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); + if (conn->tev) + evtimer_del (conn->tev); + if (conn->callbacks.connected_cb) + conn->callbacks.connected_cb (conn->user_data); + if (pkt) + packet_do_send (pkt); +} + +int +event_init_eventbase (struct rs_connection *conn) +{ + if (conn->evb) + return RSE_OK; + +#if defined (DEBUG) + 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"); + + return RSE_OK; +} diff --git a/lib/event.h b/lib/event.h new file mode 100644 index 0000000..5395f58 --- /dev/null +++ b/lib/event.h @@ -0,0 +1,11 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +int event_set_timeout (struct rs_connection *conn); +void event_on_disconnect (struct rs_connection *conn); +void event_on_connect (struct rs_connection *conn, struct rs_packet *pkt); +int event_loopbreak (struct rs_connection *conn); +int event_init_eventbase (struct rs_connection *conn); +int event_init_socket (struct rs_connection *conn, struct rs_peer *p); +int event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer); +void event_do_connect (struct rs_connection *conn); diff --git a/lib/packet.c b/lib/packet.c index afe2725..6ba9fd3 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -1,60 +1,27 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include #endif -#include -#include -#include -#include -#include #include -#include -#include #include #include #include -#include "compat.h" #include "debug.h" -#if defined (RS_ENABLE_TLS) -#include -#include -#include "tls.h" -#endif +#include "packet.h" + #if defined (DEBUG) #include #include #include #endif -static int -_close_conn (struct rs_connection **connp) -{ - int r; - assert (connp); - assert (*connp); - r = rs_conn_destroy (*connp); - if (!r) - *connp = NULL; - return r; -} - -static int -_loopbreak (struct rs_connection *conn) -{ - int err = event_base_loopbreak (conn->evb); - if (err < 0) - rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "event_base_loopbreak: %s", - evutil_gai_strerror (err)); - return err; -} - /* Badly named helper function for preparing a RADIUS message and queue it. FIXME: Rename. */ -static int -_do_send (struct rs_packet *pkt) +int +packet_do_send (struct rs_packet *pkt) { VALUE_PAIR *vp = NULL; @@ -109,583 +76,6 @@ _do_send (struct rs_packet *pkt) return RSE_OK; } -static void -_on_connect (struct rs_connection *conn, struct rs_packet *pkt) -{ - assert (!conn->is_connecting); - conn->is_connected = 1; - rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); - if (conn->tev) - evtimer_del (conn->tev); - if (conn->callbacks.connected_cb) - conn->callbacks.connected_cb (conn->user_data); - if (pkt) - _do_send (pkt); -} - -static void -_on_disconnect (struct rs_connection *conn) -{ - 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); -} - -static void -_event_cb (struct bufferevent *bev, short events, void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - struct rs_connection *conn = NULL; - struct rs_peer *p = NULL; - int sockerr = 0; -#if defined (RS_ENABLE_TLS) - unsigned long tlserr = 0; -#endif - - assert (pkt); - assert (pkt->conn); - assert (pkt->conn->active_peer); - conn = pkt->conn; - p = conn->active_peer; - - conn->is_connecting = 0; - if (events & BEV_EVENT_CONNECTED) - { - _on_connect (conn, pkt); - } - else if (events & BEV_EVENT_EOF) - { - _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_TIMEOUT_IO, __FILE__, __LINE__, NULL); - } - else if (events & BEV_EVENT_ERROR) - { - sockerr = evutil_socket_geterror (conn->active_peer->fd); - if (sockerr == 0) /* FIXME: True that errno == 0 means closed? */ - { - _on_disconnect (conn); - } - else - { - rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr, - evutil_socket_error_to_string (sockerr))); - rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: %d (%s)", conn->fd, sockerr, - evutil_socket_error_to_string (sockerr)); - } -#if defined (RS_ENABLE_TLS) - if (conn->tls_ssl) /* FIXME: correct check? */ - { - for (tlserr = bufferevent_get_openssl_error (conn->bev); - tlserr; - tlserr = bufferevent_get_openssl_error (conn->bev)) - { - rs_debug (("%s: openssl error: %s\n", __func__, - ERR_error_string (tlserr, NULL))); - rs_err_conn_push_fl (pkt->conn, RSE_SSLERR, __FILE__, __LINE__, - ERR_error_string (tlserr, NULL)); - } - } -#endif /* RS_ENABLE_TLS */ - _loopbreak (conn); - } - -#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 -_write_cb (struct bufferevent *bev, void *ctx) -{ - struct rs_packet *pkt = (struct rs_packet *) ctx; - - assert (pkt); - assert (pkt->conn); - - if (pkt->conn->callbacks.sent_cb) - pkt->conn->callbacks.sent_cb (pkt->conn->user_data); -} - -/* Read one RADIUS packet header. Return !0 on error. A return value - of 0 means that we need more data. */ -static int -_read_header (struct rs_packet *pkt) -{ - size_t n = 0; - - n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN); - if (n == RS_HEADER_LEN) - { - pkt->hdr_read_flag = 1; - pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3]; - if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096) - { - _close_conn (&pkt->conn); - return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT, - "invalid packet length: %d", - pkt->rpkt->data_len); - } - pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len); - if (!pkt->rpkt->data) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, - NULL); - } - memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN); - bufferevent_setwatermark (pkt->conn->bev, EV_READ, - pkt->rpkt->data_len - RS_HEADER_LEN, 0); - rs_debug (("%s: packet header read, total pkt len=%d\n", - __func__, pkt->rpkt->data_len)); - } - else if (n < 0) - { - rs_debug (("%s: buffer frozen while reading header\n", __func__)); - } - else /* Error: libevent gave us less than the low watermark. */ - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__, - "got %d octets reading header", n); - } - - return 0; -} - -static int -_read_packet (struct rs_packet *pkt) -{ - size_t n = 0; - - rs_debug (("%s: trying to read %d octets of packet data\n", __func__, - pkt->rpkt->data_len - RS_HEADER_LEN)); - - n = bufferevent_read (pkt->conn->bev, - pkt->rpkt->data + RS_HEADER_LEN, - pkt->rpkt->data_len - RS_HEADER_LEN); - - rs_debug (("%s: read %ld octets of packet data\n", __func__, n)); - - if (n == pkt->rpkt->data_len - RS_HEADER_LEN) - { - bufferevent_disable (pkt->conn->bev, EV_READ); - rs_debug (("%s: complete packet read\n", __func__)); - pkt->hdr_read_flag = 0; - memset (pkt->hdr, 0, sizeof(*pkt->hdr)); - - /* Checks done by rad_packet_ok: - - lenghts (FIXME: checks really ok for tcp?) - - invalid code field - - attribute lengths >= 2 - - attribute sizes adding up correctly */ - if (!rad_packet_ok (pkt->rpkt, 0) != 0) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "invalid packet: %s", fr_strerror ()); - } - - /* TODO: Verify that reception of an unsolicited response packet - results in connection being closed. */ - - /* If we have a request to match this response against, verify - and decode the response. */ - if (pkt->original) - { - /* Verify header and message authenticator. */ - if (rad_verify (pkt->rpkt, pkt->original->rpkt, - pkt->conn->active_peer->secret)) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "rad_verify: %s", fr_strerror ()); - } - - /* Decode and decrypt. */ - if (rad_decode (pkt->rpkt, pkt->original->rpkt, - pkt->conn->active_peer->secret)) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "rad_decode: %s", fr_strerror ()); - } - } - -#if defined (DEBUG) - /* Find out what happens if there's data left in the buffer. */ - { - size_t rest = 0; - rest = evbuffer_get_length (bufferevent_get_input (pkt->conn->bev)); - if (rest) - rs_debug (("%s: returning with %d octets left in buffer\n", __func__, - rest)); - } -#endif - - /* Hand over message to user, changes ownership of pkt. Don't - touch it afterwards -- it might have been freed. */ - if (pkt->conn->callbacks.received_cb) - pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data); - } - else if (n < 0) /* Buffer frozen. */ - rs_debug (("%s: buffer frozen when reading packet\n", __func__)); - else /* Short packet. */ - rs_debug (("%s: waiting for another %d octets\n", __func__, - pkt->rpkt->data_len - RS_HEADER_LEN - n)); - - return 0; -} - -/* Read callback for TCP. - - Read exactly one RADIUS message from BEV and store it in struct - rs_packet passed in CTX (hereby called 'pkt'). - - Verify the received packet against pkt->original, if !NULL. - - Inform upper layer about successful reception of valid RADIUS - message by invoking conn->callbacks.recevied_cb(), if !NULL. */ -static void -_read_cb (struct bufferevent *bev, void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - - assert (pkt); - assert (pkt->conn); - assert (pkt->rpkt); - - pkt->rpkt->sockfd = pkt->conn->fd; - pkt->rpkt->vps = NULL; - - if (!pkt->hdr_read_flag) - if (_read_header (pkt)) - return; - _read_packet (pkt); -} - -static void -_evlog_cb (int severity, const char *msg) -{ - const char *sevstr; - switch (severity) - { - case _EVENT_LOG_DEBUG: -#if !defined (DEBUG_LEVENT) - return; -#endif - sevstr = "debug"; - break; - case _EVENT_LOG_MSG: - sevstr = "msg"; - break; - case _EVENT_LOG_WARN: - sevstr = "warn"; - break; - case _EVENT_LOG_ERR: - sevstr = "err"; - break; - default: - sevstr = "???"; - break; - } - fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr? */ -} - -static int -_init_eventbase (struct rs_connection *conn) -{ - if (conn->evb) - return RSE_OK; - -#if defined (DEBUG) - 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"); - - return RSE_OK; -} - -static int -_init_socket (struct rs_connection *conn, struct rs_peer *p) -{ - if (conn->fd != -1) - return RSE_OK; - - assert (p->addr); - 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_SOCKERR, __FILE__, __LINE__, - "socket: %d (%s)", - errno, strerror (errno)); - if (evutil_make_socket_nonblocking (conn->fd) < 0) - { - evutil_closesocket (conn->fd); - conn->fd = -1; - return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__, - "evutil_make_socket_nonblocking: %d (%s)", - errno, strerror (errno)); - } - return RSE_OK; -} - -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; /* From the top. */ - - return conn->active_peer; -} - -static void -_conn_timeout_cb (int fd, short event, void *data) -{ - struct rs_connection *conn; - - assert (data); - conn = (struct rs_connection *) 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; - rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); - _loopbreak (conn); - } -} -static int -_set_timeout (struct rs_connection *conn) -{ - struct timeval tv; - - if (!conn->tev) - conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); - if (!conn->tev) - return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "evtimer_new"); - tv.tv_sec = conn->realm->timeout; - tv.tv_usec = 0; - evtimer_add (conn->tev, &tv); - - return RSE_OK; -} - -static int -_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer) -{ - if (conn->bev) - return RSE_OK; - - if (conn->realm->type == RS_CONN_TYPE_TCP) - { - 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"); - } -#if defined (RS_ENABLE_TLS) - else if (conn->realm->type == RS_CONN_TYPE_TLS) - { - if (rs_tls_init (conn)) - return -1; - /* Would be convenient to pass BEV_OPT_CLOSE_ON_FREE but things - 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, 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"); - } -#endif /* RS_ENABLE_TLS */ - else - { - return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__, - "%s: unknown connection type: %d", __func__, - conn->realm->type); - } - - return RSE_OK; -} - -/* Callback for conn->wev and conn->rev. FIXME: Rename. */ -static void -_evcb (evutil_socket_t fd, short what, void *user_data) -{ - //rs_debug (("%s: fd=%d what=0x%x\n", __func__, fd, what)); - if (what & EV_TIMEOUT) - { - struct rs_connection *conn = (struct rs_connection *) user_data; - assert (conn); - conn->is_connecting = 0; - rs_debug (("%s: UDP timeout NYI", __func__)); - } - else if (what & EV_READ) - { - struct rs_connection *conn = (struct rs_connection *) user_data; - assert (conn); - /* read a single UDP packet and stick it in a new struct - rs_packet */ - - rs_debug (("%s: UDP read NYI", __func__)); - } - else if (what & EV_WRITE) - { - struct rs_packet *pkt = (struct rs_packet *) user_data; - assert (pkt); - /* Socket ready for writing, possibly as a result of a - successful connect. */ - if (!pkt->conn->is_connected) - _on_connect (pkt->conn, pkt); - if (pkt->conn->out_queue) - { - /* Send one packet, the first. */ - ssize_t r = 0; - struct rs_packet *p = pkt->conn->out_queue; - - assert (p->rpkt); - assert (p->rpkt->data); - r = compat_send (fd, p->rpkt->data, p->rpkt->data_len, 0); - if (r == -1) - { - int sockerr = evutil_socket_geterror (p->conn->fd); - if (sockerr != EAGAIN) - rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: send: %d (%s)", fd, sockerr, - evutil_socket_error_to_string (sockerr)); - return; /* Don't unlink packet. */ - } - pkt->conn->out_queue = p->next; - } - } -} - -static int -_init_udp (struct rs_connection *conn, struct rs_packet *pkt) -{ - assert (!conn->bev); - - conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn); - conn->wev = event_new (conn->evb, conn->fd, EV_WRITE|EV_PERSIST, _evcb, pkt); - if (!conn->rev || !conn->wev) - { - if (conn->rev) - event_free (conn->rev); - /* ENOMEM _or_ EINVAL but EINVAL only if we use EV_SIGNAL, at - least for now (libevent-2.0.5). */ - return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); - } - return RSE_OK; -} - -static void -_do_connect (struct rs_connection *conn) -{ - struct rs_peer *p; - int err, sockerr; - - 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 - - if (p->conn->bev) /* TCP */ - { - _set_timeout (conn); - 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)); - else - p->conn->is_connecting = 1; - } - else /* UDP */ - { - err = connect (p->conn->fd, p->addr->ai_addr, p->addr->ai_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_error_to_string (sockerr))); - rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: connect: %d (%s)", p->conn->fd, sockerr, - evutil_socket_error_to_string (sockerr)); - } - } -} - -static int -_conn_open (struct rs_connection *conn, struct rs_packet *pkt) -{ - if (_init_eventbase (conn)) - return -1; - - 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, conn->active_peer)) - return -1; - - if (conn->realm->type == RS_CONN_TYPE_TCP - || conn->realm->type == RS_CONN_TYPE_TLS) - { - if (_init_bufferevent (conn, conn->active_peer)) - return -1; - } - else - { - if (_init_udp (conn, pkt)) - return -1; - } - - if (!conn->is_connected) - if (!conn->is_connecting) - _do_connect (conn); - - return RSE_OK; -} - -static int -_conn_is_open_p (struct rs_connection *conn) -{ - return conn->active_peer && conn->is_connected; -} - /* Public functions. */ int rs_packet_create (struct rs_connection *conn, struct rs_packet **pkt_out) @@ -744,165 +134,6 @@ rs_packet_create_authn_request (struct rs_connection *conn, return RSE_OK; } -/* User callback used when we're dispatching for user. */ -static void -_wcb (void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - assert (pkt); - pkt->written_flag = 1; - if (pkt->conn->bev) - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); - else - event_del (pkt->conn->wev); -} - -int -rs_packet_send (struct rs_packet *pkt, void *user_data) -{ - struct rs_connection *conn = NULL; - int err = 0; - - assert (pkt); - assert (pkt->conn); - conn = pkt->conn; - - if (_conn_is_open_p (conn)) - _do_send (pkt); - else - if (_conn_open (conn, pkt)) - return -1; - - assert (conn->evb); - assert (conn->active_peer); - assert (conn->fd >= 0); - - conn->user_data = user_data; - - if (conn->bev) /* TCP */ - { - bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_WRITE); - } - else /* UDP */ - { - err = event_add (conn->wev, NULL); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_add: %s", - evutil_gai_strerror (err)); - } - - /* Do dispatch, unless the user wants to do it herself. */ - if (!conn->user_dispatch_flag) - { - conn->callbacks.sent_cb = _wcb; - conn->user_data = pkt; - rs_debug (("%s: entering event loop\n", __func__)); - err = event_base_dispatch (conn->evb); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_base_dispatch: %s", - evutil_gai_strerror (err)); - rs_debug (("%s: event loop done\n", __func__)); - conn->callbacks.sent_cb = NULL; - conn->user_data = NULL; - - if (!pkt->written_flag) - return -1; - } - - return RSE_OK; -} - -static void -_rcb (struct rs_packet *packet, void *user_data) -{ - struct rs_packet *pkt = (struct rs_packet *) user_data; - assert (pkt); - pkt->valid_flag = 1; - if (pkt->conn->bev) - bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); - else - event_del (pkt->conn->rev); -} - -/* Special function used in libradsec blocking dispatching mode, - i.e. with socket set to block on read/write and with no libradsec - callbacks registered. - - For any other use of libradsec, a the received_cb callback should - be registered in the callbacks member of struct rs_connection. - - On successful reception, verification and decoding of a RADIUS - message, PKT_OUT will upon return point at a pointer to a struct - rs_packet containing the message. - - If anything goes wrong or if the read times out (TODO: explain), - PKT_OUT will point at the NULL pointer and one or more errors are - pushed on the connection (available through rs_err_conn_pop()). */ - -int -rs_conn_receive_packet (struct rs_connection *conn, - struct rs_packet *request, - struct rs_packet **pkt_out) -{ - 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)) - return -1; - pkt = *pkt_out; - pkt->conn = conn; - pkt->original = request; - - assert (conn->evb); - assert (conn->bev); - assert (conn->active_peer); - assert (conn->fd >= 0); - - conn->callbacks.received_cb = _rcb; - conn->user_data = pkt; - if (conn->bev) - { - bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); - bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt); - bufferevent_enable (conn->bev, EV_READ); - } - else - { - err = event_add (conn->rev, NULL); - if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_add: %s", - evutil_gai_strerror (err)); - } - - /* 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)); - rs_debug (("%s: event loop done\n", __func__)); - - if (!pkt->valid_flag) - return -1; - -#if defined (DEBUG) - rs_dump_packet (pkt); -#endif - - pkt->original = NULL; /* FIXME: Why? */ - return RSE_OK; -} - void rs_packet_add_attr (struct rs_packet *pkt, struct rs_attr *attr) { @@ -927,3 +158,4 @@ rs_packet_destroy (struct rs_packet *pkt) rs_free (pkt->conn->ctx, pkt); } } + diff --git a/lib/packet.h b/lib/packet.h new file mode 100644 index 0000000..7053329 --- /dev/null +++ b/lib/packet.h @@ -0,0 +1,4 @@ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +int packet_do_send (struct rs_packet *pkt); diff --git a/lib/peer.c b/lib/peer.c index 4fbb54f..0a1d2ec 100644 --- a/lib/peer.c +++ b/lib/peer.c @@ -1,4 +1,6 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + #if defined HAVE_CONFIG_H #include #endif @@ -6,7 +8,22 @@ #include #include #include +#include "peer.h" + +struct rs_peer * +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; /* From the top. */ + + return conn->active_peer; +} +/* Public functions. */ int rs_peer_create (struct rs_connection *conn, struct rs_peer **peer_out) { diff --git a/lib/peer.h b/lib/peer.h new file mode 100644 index 0000000..f430bb2 --- /dev/null +++ b/lib/peer.h @@ -0,0 +1,4 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +struct rs_peer *peer_pick_peer (struct rs_connection *conn); diff --git a/lib/radsec.c b/lib/radsec.c index f191e73..6eb7c39 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include @@ -24,6 +25,8 @@ #endif #include "rsp_debug.h" + +/* Public functions. */ int rs_context_create(struct rs_context **ctx, const char *dict) { diff --git a/lib/radsec.h b/lib/radsec.h new file mode 100644 index 0000000..c88be66 --- /dev/null +++ b/lib/radsec.h @@ -0,0 +1,9 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +/* RFC 5080 2.2.1. Retransmission Behavior */ +#define IRT 2 +#define MRC 5 +#define MRT 16 +#define MRD 30 + diff --git a/lib/request.c b/lib/request.c index 9aa29cb..1d0b4ac 100644 --- a/lib/request.c +++ b/lib/request.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include diff --git a/lib/send.c b/lib/send.c new file mode 100644 index 0000000..c49eaa9 --- /dev/null +++ b/lib/send.c @@ -0,0 +1,128 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +#if defined HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include "debug.h" +#include "packet.h" +#include "event.h" +#include "peer.h" +#include "tcp.h" +#include "udp.h" + +static int +_conn_open (struct rs_connection *conn, struct rs_packet *pkt) +{ + if (event_init_eventbase (conn)) + return -1; + + if (!conn->active_peer) + peer_pick_peer (conn); + if (!conn->active_peer) + return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL); + + if (event_init_socket (conn, conn->active_peer)) + return -1; + + if (conn->realm->type == RS_CONN_TYPE_TCP + || conn->realm->type == RS_CONN_TYPE_TLS) + { + if (event_init_bufferevent (conn, conn->active_peer)) + return -1; + } + else + { + if (udp_init (conn, pkt)) + return -1; + } + + if (!conn->is_connected) + if (!conn->is_connecting) + event_do_connect (conn); + + return RSE_OK; +} + +static int +_conn_is_open_p (struct rs_connection *conn) +{ + return conn->active_peer && conn->is_connected; +} + +/* User callback used when we're dispatching for user. */ +static void +_wcb (void *user_data) +{ + struct rs_packet *pkt = (struct rs_packet *) user_data; + assert (pkt); + pkt->written_flag = 1; + if (pkt->conn->bev) + bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); + else + event_del (pkt->conn->wev); +} + +int +rs_packet_send (struct rs_packet *pkt, void *user_data) +{ + struct rs_connection *conn = NULL; + int err = 0; + + assert (pkt); + assert (pkt->conn); + conn = pkt->conn; + + if (_conn_is_open_p (conn)) + packet_do_send (pkt); + else + if (_conn_open (conn, pkt)) + return -1; + + assert (conn->evb); + assert (conn->active_peer); + assert (conn->fd >= 0); + + conn->user_data = user_data; + + if (conn->bev) /* TCP */ + { + bufferevent_setcb (conn->bev, NULL, tcp_write_cb, tcp_event_cb, pkt); + bufferevent_enable (conn->bev, EV_WRITE); + } + else /* UDP */ + { + err = event_add (conn->wev, NULL); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", + evutil_gai_strerror (err)); + } + + /* Do dispatch, unless the user wants to do it herself. */ + if (!conn->user_dispatch_flag) + { + conn->callbacks.sent_cb = _wcb; + conn->user_data = pkt; + rs_debug (("%s: entering event loop\n", __func__)); + err = event_base_dispatch (conn->evb); + if (err < 0) + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_base_dispatch: %s", + evutil_gai_strerror (err)); + rs_debug (("%s: event loop done\n", __func__)); + conn->callbacks.sent_cb = NULL; + conn->user_data = NULL; + + if (!pkt->written_flag) + return -1; + } + + return RSE_OK; +} diff --git a/lib/tcp.c b/lib/tcp.c new file mode 100644 index 0000000..2e641f6 --- /dev/null +++ b/lib/tcp.c @@ -0,0 +1,276 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +#if defined HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#if defined (RS_ENABLE_TLS) +#include +#include +#endif +#include +#include +#include "tcp.h" +#include "packet.h" +#include "debug.h" +#include "event.h" + +#if defined (DEBUG) +#include +#endif + +static int +_close_conn (struct rs_connection **connp) +{ + int r; + assert (connp); + assert (*connp); + r = rs_conn_destroy (*connp); + if (!r) + *connp = NULL; + return r; +} + +/* Read one RADIUS packet header. Return !0 on error. A return value + of 0 means that we need more data. */ +static int +_read_header (struct rs_packet *pkt) +{ + size_t n = 0; + + n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN); + if (n == RS_HEADER_LEN) + { + pkt->hdr_read_flag = 1; + pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3]; + if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096) + { + _close_conn (&pkt->conn); + return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT, + "invalid packet length: %d", + pkt->rpkt->data_len); + } + pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len); + if (!pkt->rpkt->data) + { + _close_conn (&pkt->conn); + return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, + NULL); + } + memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN); + bufferevent_setwatermark (pkt->conn->bev, EV_READ, + pkt->rpkt->data_len - RS_HEADER_LEN, 0); + rs_debug (("%s: packet header read, total pkt len=%d\n", + __func__, pkt->rpkt->data_len)); + } + else if (n < 0) + { + rs_debug (("%s: buffer frozen while reading header\n", __func__)); + } + else /* Error: libevent gave us less than the low watermark. */ + { + _close_conn (&pkt->conn); + return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__, + "got %d octets reading header", n); + } + + return 0; +} + +static int +_read_packet (struct rs_packet *pkt) +{ + size_t n = 0; + + rs_debug (("%s: trying to read %d octets of packet data\n", __func__, + pkt->rpkt->data_len - RS_HEADER_LEN)); + + n = bufferevent_read (pkt->conn->bev, + pkt->rpkt->data + RS_HEADER_LEN, + pkt->rpkt->data_len - RS_HEADER_LEN); + + rs_debug (("%s: read %ld octets of packet data\n", __func__, n)); + + if (n == pkt->rpkt->data_len - RS_HEADER_LEN) + { + bufferevent_disable (pkt->conn->bev, EV_READ); + rs_debug (("%s: complete packet read\n", __func__)); + pkt->hdr_read_flag = 0; + memset (pkt->hdr, 0, sizeof(*pkt->hdr)); + + /* Checks done by rad_packet_ok: + - lenghts (FIXME: checks really ok for tcp?) + - invalid code field + - attribute lengths >= 2 + - attribute sizes adding up correctly */ + if (!rad_packet_ok (pkt->rpkt, 0) != 0) + { + _close_conn (&pkt->conn); + return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, + "invalid packet: %s", fr_strerror ()); + } + + /* TODO: Verify that reception of an unsolicited response packet + results in connection being closed. */ + + /* If we have a request to match this response against, verify + and decode the response. */ + if (pkt->original) + { + /* Verify header and message authenticator. */ + if (rad_verify (pkt->rpkt, pkt->original->rpkt, + pkt->conn->active_peer->secret)) + { + _close_conn (&pkt->conn); + return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, + "rad_verify: %s", fr_strerror ()); + } + + /* Decode and decrypt. */ + if (rad_decode (pkt->rpkt, pkt->original->rpkt, + pkt->conn->active_peer->secret)) + { + _close_conn (&pkt->conn); + return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, + "rad_decode: %s", fr_strerror ()); + } + } + +#if defined (DEBUG) + /* Find out what happens if there's data left in the buffer. */ + { + size_t rest = 0; + rest = evbuffer_get_length (bufferevent_get_input (pkt->conn->bev)); + if (rest) + rs_debug (("%s: returning with %d octets left in buffer\n", __func__, + rest)); + } +#endif + + /* Hand over message to user, changes ownership of pkt. Don't + touch it afterwards -- it might have been freed. */ + if (pkt->conn->callbacks.received_cb) + pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data); + } + else if (n < 0) /* Buffer frozen. */ + rs_debug (("%s: buffer frozen when reading packet\n", __func__)); + else /* Short packet. */ + rs_debug (("%s: waiting for another %d octets\n", __func__, + pkt->rpkt->data_len - RS_HEADER_LEN - n)); + + return 0; +} + +/* Read callback for TCP. + + Read exactly one RADIUS message from BEV and store it in struct + rs_packet passed in CTX (hereby called 'pkt'). + + Verify the received packet against pkt->original, if !NULL. + + Inform upper layer about successful reception of valid RADIUS + message by invoking conn->callbacks.recevied_cb(), if !NULL. */ +void +tcp_read_cb (struct bufferevent *bev, void *user_data) +{ + struct rs_packet *pkt = (struct rs_packet *) user_data; + + assert (pkt); + assert (pkt->conn); + assert (pkt->rpkt); + + pkt->rpkt->sockfd = pkt->conn->fd; + pkt->rpkt->vps = NULL; + + if (!pkt->hdr_read_flag) + if (_read_header (pkt)) + return; + _read_packet (pkt); +} + +void +tcp_event_cb (struct bufferevent *bev, short events, void *user_data) +{ + struct rs_packet *pkt = (struct rs_packet *) user_data; + struct rs_connection *conn = NULL; + struct rs_peer *p = NULL; + int sockerr = 0; +#if defined (RS_ENABLE_TLS) + unsigned long tlserr = 0; +#endif + + assert (pkt); + assert (pkt->conn); + assert (pkt->conn->active_peer); + conn = pkt->conn; + p = conn->active_peer; + + conn->is_connecting = 0; + if (events & BEV_EVENT_CONNECTED) + { + event_on_connect (conn, pkt); + } + else if (events & BEV_EVENT_EOF) + { + event_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_TIMEOUT_IO, __FILE__, __LINE__, NULL); + } + else if (events & BEV_EVENT_ERROR) + { + sockerr = evutil_socket_geterror (conn->active_peer->fd); + if (sockerr == 0) /* FIXME: True that errno == 0 means closed? */ + { + event_on_disconnect (conn); + } + else + { + rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr, + evutil_socket_error_to_string (sockerr))); + rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: %d (%s)", conn->fd, sockerr, + evutil_socket_error_to_string (sockerr)); + } +#if defined (RS_ENABLE_TLS) + if (conn->tls_ssl) /* FIXME: correct check? */ + { + for (tlserr = bufferevent_get_openssl_error (conn->bev); + tlserr; + tlserr = bufferevent_get_openssl_error (conn->bev)) + { + rs_debug (("%s: openssl error: %s\n", __func__, + ERR_error_string (tlserr, NULL))); + rs_err_conn_push_fl (pkt->conn, RSE_SSLERR, __FILE__, __LINE__, + ERR_error_string (tlserr, NULL)); + } + } +#endif /* RS_ENABLE_TLS */ + event_loopbreak (conn); + } + +#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 +} + +void +tcp_write_cb (struct bufferevent *bev, void *ctx) +{ + struct rs_packet *pkt = (struct rs_packet *) ctx; + + assert (pkt); + assert (pkt->conn); + + if (pkt->conn->callbacks.sent_cb) + pkt->conn->callbacks.sent_cb (pkt->conn->user_data); +} + diff --git a/lib/tcp.h b/lib/tcp.h new file mode 100644 index 0000000..eae3e7b --- /dev/null +++ b/lib/tcp.h @@ -0,0 +1,6 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +void tcp_event_cb (struct bufferevent *bev, short events, void *user_data); +void tcp_read_cb (struct bufferevent *bev, void *user_data); +void tcp_write_cb (struct bufferevent *bev, void *ctx); diff --git a/lib/tls.c b/lib/tls.c index f57c027..6fcf5a0 100644 --- a/lib/tls.c +++ b/lib/tls.c @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined HAVE_CONFIG_H #include diff --git a/lib/tls.h b/lib/tls.h index 5dcbc47..d457cfd 100644 --- a/lib/tls.h +++ b/lib/tls.h @@ -1,4 +1,5 @@ -/* See the file COPYING for licensing information. */ +/* Copyright 2010 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ #if defined (__cplusplus) extern "C" { diff --git a/lib/udp.c b/lib/udp.c new file mode 100644 index 0000000..3573033 --- /dev/null +++ b/lib/udp.c @@ -0,0 +1,85 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +#if defined HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include "debug.h" +#include "event.h" +#include "compat.h" +#include "udp.h" + +/* Callback for conn->wev and conn->rev. FIXME: Rename. */ +static void +_evcb (evutil_socket_t fd, short what, void *user_data) +{ + //rs_debug (("%s: fd=%d what=0x%x\n", __func__, fd, what)); + if (what & EV_TIMEOUT) + { + struct rs_connection *conn = (struct rs_connection *) user_data; + assert (conn); + conn->is_connecting = 0; + rs_debug (("%s: UDP timeout NYI", __func__)); + } + else if (what & EV_READ) + { + struct rs_connection *conn = (struct rs_connection *) user_data; + assert (conn); + /* read a single UDP packet and stick it in a new struct + rs_packet */ + + rs_debug (("%s: UDP read NYI", __func__)); + } + else if (what & EV_WRITE) + { + struct rs_packet *pkt = (struct rs_packet *) user_data; + assert (pkt); + /* Socket ready for writing, possibly as a result of a + successful connect. */ + if (!pkt->conn->is_connected) + event_on_connect (pkt->conn, pkt); + if (pkt->conn->out_queue) + { + /* Send one packet, the first. */ + ssize_t r = 0; + struct rs_packet *p = pkt->conn->out_queue; + + assert (p->rpkt); + assert (p->rpkt->data); + r = compat_send (fd, p->rpkt->data, p->rpkt->data_len, 0); + if (r == -1) + { + int sockerr = evutil_socket_geterror (p->conn->fd); + if (sockerr != EAGAIN) + rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: send: %d (%s)", fd, sockerr, + evutil_socket_error_to_string (sockerr)); + return; /* Don't unlink packet. */ + } + pkt->conn->out_queue = p->next; + } + } +} + +int +udp_init (struct rs_connection *conn, struct rs_packet *pkt) +{ + assert (!conn->bev); + + conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn); + conn->wev = event_new (conn->evb, conn->fd, EV_WRITE|EV_PERSIST, _evcb, pkt); + if (!conn->rev || !conn->wev) + { + if (conn->rev) + event_free (conn->rev); + /* ENOMEM _or_ EINVAL but EINVAL only if we use EV_SIGNAL, at + least for now (libevent-2.0.5). */ + return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); + } + return RSE_OK; +} diff --git a/lib/udp.h b/lib/udp.h new file mode 100644 index 0000000..a2a7228 --- /dev/null +++ b/lib/udp.h @@ -0,0 +1,4 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +int udp_init (struct rs_connection *conn, struct rs_packet *pkt); -- cgit v1.1 From e5207cd80b8a522be84e3f66479663e559309ee7 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 16:44:43 +0100 Subject: Replace asserts with EINVAL checks. --- lib/request.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/request.c b/lib/request.c index 1d0b4ac..0d98544 100644 --- a/lib/request.c +++ b/lib/request.c @@ -95,19 +95,13 @@ _rs_req_packet_sent(void *user_data) int rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) { - int err; - struct rs_connection *conn; - - assert (request); - assert (request->conn); - assert (request->req_msg); - conn = request->conn; + int err = 0; + struct rs_connection *conn = NULL; if (!request || !request->conn || !request->req_msg || !resp_msg) return rs_err_conn_push_fl (conn, RSE_INVAL, __FILE__, __LINE__, NULL); - + conn = request->conn; request->saved_cb = conn->callbacks; - conn->callbacks.connected_cb = _rs_req_connected; conn->callbacks.disconnected_cb = _rs_req_disconnected; conn->callbacks.received_cb = _rs_req_packet_received; -- cgit v1.1 From 43d0740f143ba737a1fc5ace3a323ffa8b09e7ae Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 17:04:54 +0100 Subject: request: Save callers user_data and do invoke callers callbacks. --- lib/include/radsec/request-impl.h | 1 + lib/request.c | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/include/radsec/request-impl.h b/lib/include/radsec/request-impl.h index 4f50d44..19aef66 100644 --- a/lib/include/radsec/request-impl.h +++ b/lib/include/radsec/request-impl.h @@ -11,6 +11,7 @@ struct rs_request struct rs_packet *req_msg; struct rs_packet *resp_msg; struct rs_conn_callbacks saved_cb; + void *saved_user_data; }; #if defined (__cplusplus) diff --git a/lib/request.c b/lib/request.c index 0d98544..9c4b58f 100644 --- a/lib/request.c +++ b/lib/request.c @@ -62,34 +62,50 @@ rs_request_destroy (struct rs_request *request) #if 0 static void -_timer_cb(evutil_socket_t fd, short what, void *arg) +_timer_cb (evutil_socket_t fd, short what, void *arg) { } #endif static void -_rs_req_connected(void *user_data) +_rs_req_connected (void *user_data) { - //struct rs_request *request = (struct rs_request *)user_data; + struct rs_request *request = (struct rs_request *) user_data; + assert (request); + assert (request->conn); + if (request->saved_cb.connected_cb) + request->saved_cb.connected_cb (request->saved_user_data); } static void -_rs_req_disconnected(void *user_data) +_rs_req_disconnected (void *user_data) { - //struct rs_request *request = (struct rs_request *)user_data; + struct rs_request *request = (struct rs_request *) user_data; + assert (request); + assert (request->conn); + if (request->saved_cb.disconnected_cb) + request->saved_cb.disconnected_cb (request->saved_user_data); } static void -_rs_req_packet_received(struct rs_packet *msg, void *user_data) +_rs_req_packet_received (struct rs_packet *msg, void *user_data) { - //struct rs_request *request = (struct rs_request *)user_data; + struct rs_request *request = (struct rs_request *) user_data; + assert (request); + assert (request->conn); + if (request->saved_cb.received_cb) + request->saved_cb.received_cb (msg, request->saved_user_data); } static void -_rs_req_packet_sent(void *user_data) +_rs_req_packet_sent (void *user_data) { - //struct rs_request *request = (struct rs_request *)user_data; + struct rs_request *request = (struct rs_request *) user_data; + assert (request); + assert (request->conn); + if (request->saved_cb.sent_cb) + request->saved_cb.sent_cb (request->saved_user_data); } int @@ -101,6 +117,10 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) if (!request || !request->conn || !request->req_msg || !resp_msg) return rs_err_conn_push_fl (conn, RSE_INVAL, __FILE__, __LINE__, NULL); conn = request->conn; + + request->saved_user_data = conn->user_data; + conn->user_data = request; + request->saved_cb = conn->callbacks; conn->callbacks.connected_cb = _rs_req_connected; conn->callbacks.disconnected_cb = _rs_req_disconnected; @@ -116,6 +136,7 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) goto cleanup; cleanup: + conn->user_data = request->saved_user_data; conn->callbacks = request->saved_cb; return err; } -- cgit v1.1 From f082f0d0617d12854a5fd0dc683d357144e36c5c Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 6 Mar 2011 17:08:41 +0100 Subject: Move event_set_timeout --> tcp_set_connect_timeout. --- lib/event.c | 40 +++------------------------------------- lib/event.h | 1 - lib/tcp.c | 34 ++++++++++++++++++++++++++++++++++ lib/tcp.h | 1 + 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/event.c b/lib/event.c index 97a08c8..55a7e6b 100644 --- a/lib/event.c +++ b/lib/event.c @@ -14,10 +14,11 @@ #endif #include #include +#include "tcp.h" +#include "udp.h" #if defined (RS_ENABLE_TLS) #include "tls.h" #endif -#include "udp.h" #include "event.h" #include "packet.h" #include "debug.h" @@ -74,24 +75,6 @@ event_init_socket (struct rs_connection *conn, struct rs_peer *p) return RSE_OK; } -static void -_conn_timeout_cb (int fd, short event, void *data) -{ - struct rs_connection *conn; - - assert (data); - conn = (struct rs_connection *) 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; - rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); - event_loopbreak (conn); - } -} - int event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer) { @@ -155,7 +138,7 @@ event_do_connect (struct rs_connection *conn) if (p->conn->bev) /* TCP */ { - event_set_timeout (conn); + tcp_set_connect_timeout (conn); err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr, p->addr->ai_addrlen); if (err < 0) @@ -192,23 +175,6 @@ event_loopbreak (struct rs_connection *conn) } -int -event_set_timeout (struct rs_connection *conn) -{ - struct timeval tv; - - if (!conn->tev) - conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); - if (!conn->tev) - return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, - "evtimer_new"); - tv.tv_sec = conn->realm->timeout; - tv.tv_usec = 0; - evtimer_add (conn->tev, &tv); - - return RSE_OK; -} - void event_on_disconnect (struct rs_connection *conn) { diff --git a/lib/event.h b/lib/event.h index 5395f58..e5ea90c 100644 --- a/lib/event.h +++ b/lib/event.h @@ -1,7 +1,6 @@ /* Copyright 2011 NORDUnet A/S. All rights reserved. See the file COPYING for licensing information. */ -int event_set_timeout (struct rs_connection *conn); void event_on_disconnect (struct rs_connection *conn); void event_on_connect (struct rs_connection *conn, struct rs_packet *pkt); int event_loopbreak (struct rs_connection *conn); diff --git a/lib/tcp.c b/lib/tcp.c index 2e641f6..acee94b 100644 --- a/lib/tcp.c +++ b/lib/tcp.c @@ -23,6 +23,24 @@ #include #endif +static void +_conn_timeout_cb (int fd, short event, void *data) +{ + struct rs_connection *conn; + + assert (data); + conn = (struct rs_connection *) 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; + rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); + event_loopbreak (conn); + } +} + static int _close_conn (struct rs_connection **connp) { @@ -274,3 +292,19 @@ tcp_write_cb (struct bufferevent *bev, void *ctx) pkt->conn->callbacks.sent_cb (pkt->conn->user_data); } +int +tcp_set_connect_timeout (struct rs_connection *conn) +{ + struct timeval tv; + + if (!conn->tev) + conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); + if (!conn->tev) + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, + "evtimer_new"); + tv.tv_sec = conn->realm->timeout; + tv.tv_usec = 0; + evtimer_add (conn->tev, &tv); + + return RSE_OK; +} diff --git a/lib/tcp.h b/lib/tcp.h index eae3e7b..8f519bb 100644 --- a/lib/tcp.h +++ b/lib/tcp.h @@ -4,3 +4,4 @@ void tcp_event_cb (struct bufferevent *bev, short events, void *user_data); void tcp_read_cb (struct bufferevent *bev, void *user_data); void tcp_write_cb (struct bufferevent *bev, void *ctx); +int tcp_set_connect_timeout (struct rs_connection *conn); -- cgit v1.1 From 725bec6f03436f9aedb3ffc7196049ab0f32f218 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 7 Mar 2011 09:38:01 +0100 Subject: Remove lib/radsec.h. 1. Two radsec.h is icky. 2. Its contents fit nicely in send.c. --- lib/radsec.h | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 lib/radsec.h diff --git a/lib/radsec.h b/lib/radsec.h deleted file mode 100644 index c88be66..0000000 --- a/lib/radsec.h +++ /dev/null @@ -1,9 +0,0 @@ -/* Copyright 2011 NORDUnet A/S. All rights reserved. - See the file COPYING for licensing information. */ - -/* RFC 5080 2.2.1. Retransmission Behavior */ -#define IRT 2 -#define MRC 5 -#define MRT 16 -#define MRD 30 - -- cgit v1.1 From 41af6cd03dac4eb905d0d3de574d2e4f3f9600eb Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 7 Mar 2011 09:53:40 +0100 Subject: Formatting changes. --- lib/radsec.c | 8 +++++--- lib/request.c | 4 ++-- lib/send.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/radsec.c b/lib/radsec.c index 6eb7c39..dd182c6 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -28,7 +28,7 @@ /* Public functions. */ int -rs_context_create(struct rs_context **ctx, const char *dict) +rs_context_create (struct rs_context **ctx, const char *dict) { int err = RSE_OK; struct rs_context *h; @@ -154,8 +154,10 @@ rs_context_destroy (struct rs_context *ctx) rs_free (ctx, ctx); } -int rs_context_set_alloc_scheme(struct rs_context *ctx, - struct rs_alloc_scheme *scheme) +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__, NULL); } + diff --git a/lib/request.c b/lib/request.c index 9c4b58f..80a0a81 100644 --- a/lib/request.c +++ b/lib/request.c @@ -127,11 +127,11 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) conn->callbacks.received_cb = _rs_req_packet_received; conn->callbacks.sent_cb = _rs_req_packet_sent; - err = rs_packet_send(request->req_msg, request); + err = rs_packet_send (request->req_msg, request); if (err) goto cleanup; - err = rs_conn_receive_packet(request->conn, request->req_msg, resp_msg); + err = rs_conn_receive_packet (request->conn, request->req_msg, resp_msg); if (err) goto cleanup; diff --git a/lib/send.c b/lib/send.c index c49eaa9..871d657 100644 --- a/lib/send.c +++ b/lib/send.c @@ -96,7 +96,7 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) bufferevent_setcb (conn->bev, NULL, tcp_write_cb, tcp_event_cb, pkt); bufferevent_enable (conn->bev, EV_WRITE); } - else /* UDP */ + else /* UDP */ { err = event_add (conn->wev, NULL); if (err < 0) -- cgit v1.1 From cbcaa6a7c8f8a6704f6b4a68f260020957214a07 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 7 Mar 2011 15:23:40 +0100 Subject: Move verification of response packets up to a level where it makes sense. Replace the user_dispatch_flag on connections with conn_user_dispatch_p(). Remove the 'original' member from packet and instead have an upper layer verify. Rename packet valid_flag --> received_flag to reflect that we don't verify. Move _close_conn() --> conn_close(). Move packet flags into a single unsigned int, for portability. (_read_packet): Don't verify packet. (rs_conn_receive_packet): Don't touch PKT_OUT if there isn't a packet. (rs_conn_receive_packet): Verify packet using packet_verify_response(). --- lib/conn.c | 73 ++++++++++++++++++++++++++++------------ lib/include/radsec/radsec-impl.h | 14 ++++---- lib/packet.c | 39 +++++++++++++++++++-- lib/packet.h | 3 ++ lib/send.c | 17 +++++++--- lib/tcp.c | 69 +++++++++---------------------------- 6 files changed, 125 insertions(+), 90 deletions(-) diff --git a/lib/conn.c b/lib/conn.c index 14693ae..028302c 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -12,10 +12,35 @@ #include #include #include +#include "conn.h" #include "event.h" +#include "packet.h" #include "tcp.h" int +conn_close (struct rs_connection **connp) +{ + int r; + assert (connp); + assert (*connp); + r = rs_conn_destroy (*connp); + if (!r) + *connp = NULL; + return r; +} + +int +conn_user_dispatch_p (const struct rs_connection *conn) +{ + assert (conn); + + return (conn->callbacks.connected_cb || + conn->callbacks.disconnected_cb || + conn->callbacks.received_cb || + conn->callbacks.sent_cb); +} + +int rs_conn_create (struct rs_context *ctx, struct rs_connection **conn, const char *config) { @@ -158,7 +183,6 @@ void rs_conn_set_callbacks (struct rs_connection *conn, struct rs_conn_callbacks *cb) { assert (conn); - conn->user_dispatch_flag = 1; memcpy (&conn->callbacks, cb, sizeof (conn->callbacks)); } @@ -166,7 +190,6 @@ void rs_conn_del_callbacks (struct rs_connection *conn) { assert (conn); - conn->user_dispatch_flag = 0; memset (&conn->callbacks, 0, sizeof (conn->callbacks)); } @@ -202,7 +225,9 @@ _rcb (struct rs_packet *packet, void *user_data) { struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); - pkt->valid_flag = 1; + assert (pkt->conn); + + pkt->flags |= rs_packet_received_flag; if (pkt->conn->bev) bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); else @@ -216,17 +241,18 @@ _rcb (struct rs_packet *packet, void *user_data) For any other use of libradsec, a the received_cb callback should be registered in the callbacks member of struct rs_connection. - On successful reception, verification and decoding of a RADIUS - message, PKT_OUT will upon return point at a pointer to a struct - rs_packet containing the message. + On successful reception of a RADIUS message it will be verified + against REQ_MSG, if !NULL. - If anything goes wrong or if the read times out (TODO: explain), - PKT_OUT will point at the NULL pointer and one or more errors are - pushed on the connection (available through rs_err_conn_pop()). */ + If PKT_OUT is !NULL it will upon return point at a pointer to a + struct rs_packet containing the message. + If anything goes wrong or if the read times out (TODO: explain), + PKT_OUT will not be changed and one or more errors are pushed on + the connection (available through rs_err_conn_pop()). */ int rs_conn_receive_packet (struct rs_connection *conn, - struct rs_packet *request, + struct rs_packet *req_msg, struct rs_packet **pkt_out) { int err = 0; @@ -234,13 +260,11 @@ rs_conn_receive_packet (struct rs_connection *conn, assert (conn); assert (conn->realm); - assert (!conn->user_dispatch_flag); /* Dispatching mode only. */ + assert (!conn_user_dispatch_p (conn)); /* Dispatching mode only. */ - if (rs_packet_create (conn, pkt_out)) + if (rs_packet_create (conn, &pkt)) return -1; - pkt = *pkt_out; pkt->conn = conn; - pkt->original = request; assert (conn->evb); assert (conn->bev); @@ -249,6 +273,8 @@ rs_conn_receive_packet (struct rs_connection *conn, conn->callbacks.received_cb = _rcb; conn->user_data = pkt; + pkt->flags &= ~rs_packet_received_flag; + if (conn->bev) { bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); @@ -264,7 +290,7 @@ rs_conn_receive_packet (struct rs_connection *conn, evutil_gai_strerror (err)); } - /* Dispatch. */ + rs_debug (("%s: entering event loop\n", __func__)); err = event_base_dispatch (conn->evb); conn->callbacks.received_cb = NULL; @@ -274,13 +300,16 @@ rs_conn_receive_packet (struct rs_connection *conn, evutil_gai_strerror (err)); rs_debug (("%s: event loop done\n", __func__)); - if (!pkt->valid_flag) - return -1; - -#if defined (DEBUG) - rs_dump_packet (pkt); -#endif + if ((pkt->flags & rs_packet_received_flag) == 0 + || (req_msg + && packet_verify_response (pkt->conn, pkt, req_msg) != RSE_OK)) + { + assert (rs_err_conn_peek_code (pkt->conn)); + return -1; + } - pkt->original = NULL; /* FIXME: Why? */ + if (pkt_out) + *pkt_out = pkt; return RSE_OK; } + diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index f8904ac..e790ccf 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -81,7 +81,6 @@ struct rs_connection { int fd; /* Socket. */ int tryagain; /* For server failover. */ int nextid; /* Next RADIUS packet identifier. */ - int user_dispatch_flag : 1; /* User does the dispatching. */ /* TCP transport specifics. */ struct bufferevent *bev; /* Buffer event. */ /* UDP transport specifics. */ @@ -95,14 +94,17 @@ struct rs_connection { #endif }; +enum rs_packet_flags { + rs_packet_hdr_read_flag, + rs_packet_received_flag, + rs_packet_sent_flag, +}; + struct rs_packet { struct rs_connection *conn; - char hdr_read_flag; - uint8_t hdr[4]; + unsigned int flags; + uint8_t hdr[RS_HEADER_LEN]; RADIUS_PACKET *rpkt; - struct rs_packet *original; - char valid_flag; - char written_flag; struct rs_packet *next; /* Used for UDP output queue. */ }; diff --git a/lib/packet.c b/lib/packet.c index 6ba9fd3..799234f 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -9,6 +9,7 @@ #include #include #include +#include "conn.h" #include "debug.h" #include "packet.h" @@ -18,15 +19,47 @@ #include #endif -/* Badly named helper function for preparing a RADIUS message and - queue it. FIXME: Rename. */ +int +packet_verify_response (struct rs_connection *conn, + struct rs_packet *response, + struct rs_packet *request) +{ + assert (conn); + assert (conn->active_peer); + assert (conn->active_peer->secret); + assert (response); + assert (response->rpkt); + assert (request); + assert (request->rpkt); + + /* Verify header and message authenticator. */ + if (rad_verify (response->rpkt, request->rpkt, conn->active_peer->secret)) + { + conn_close (&conn); + return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__, + "rad_verify: %s", fr_strerror ()); + } + + /* Decode and decrypt. */ + if (rad_decode (response->rpkt, request->rpkt, conn->active_peer->secret)) + { + conn_close (&conn); + return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__, + "rad_decode: %s", fr_strerror ()); + } + + return RSE_OK; +} + + +/* Badly named function for preparing a RADIUS message and queue it. + FIXME: Rename. */ int packet_do_send (struct rs_packet *pkt) { VALUE_PAIR *vp = NULL; assert (pkt->rpkt); - assert (!pkt->original); /* Add Message-Authenticator, RFC 2869. */ /* FIXME: Make Message-Authenticator optional? */ diff --git a/lib/packet.h b/lib/packet.h index 7053329..edff9de 100644 --- a/lib/packet.h +++ b/lib/packet.h @@ -2,3 +2,6 @@ See the file COPYING for licensing information. */ int packet_do_send (struct rs_packet *pkt); +int packet_verify_response (struct rs_connection *conn, + struct rs_packet *response, + struct rs_packet *request); diff --git a/lib/send.c b/lib/send.c index 871d657..cc7fd71 100644 --- a/lib/send.c +++ b/lib/send.c @@ -14,9 +14,16 @@ #include "packet.h" #include "event.h" #include "peer.h" +#include "conn.h" #include "tcp.h" #include "udp.h" +/* RFC 5080 2.2.1. Retransmission Behavior */ +#define IRT 2 +#define MRC 5 +#define MRT 16 +#define MRD 30 + static int _conn_open (struct rs_connection *conn, struct rs_packet *pkt) { @@ -62,7 +69,7 @@ _wcb (void *user_data) { struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); - pkt->written_flag = 1; + pkt->flags |= rs_packet_sent_flag; if (pkt->conn->bev) bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ); else @@ -100,27 +107,27 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) { err = event_add (conn->wev, NULL); if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "event_add: %s", evutil_gai_strerror (err)); } /* Do dispatch, unless the user wants to do it herself. */ - if (!conn->user_dispatch_flag) + if (!conn_user_dispatch_p (conn)) { conn->callbacks.sent_cb = _wcb; conn->user_data = pkt; rs_debug (("%s: entering event loop\n", __func__)); err = event_base_dispatch (conn->evb); if (err < 0) - return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "event_base_dispatch: %s", evutil_gai_strerror (err)); rs_debug (("%s: event loop done\n", __func__)); conn->callbacks.sent_cb = NULL; conn->user_data = NULL; - if (!pkt->written_flag) + if ((pkt->flags & rs_packet_sent_flag) == 0) return -1; } diff --git a/lib/tcp.c b/lib/tcp.c index acee94b..1801d62 100644 --- a/lib/tcp.c +++ b/lib/tcp.c @@ -16,6 +16,7 @@ #include #include "tcp.h" #include "packet.h" +#include "conn.h" #include "debug.h" #include "event.h" @@ -41,18 +42,6 @@ _conn_timeout_cb (int fd, short event, void *data) } } -static int -_close_conn (struct rs_connection **connp) -{ - int r; - assert (connp); - assert (*connp); - r = rs_conn_destroy (*connp); - if (!r) - *connp = NULL; - return r; -} - /* Read one RADIUS packet header. Return !0 on error. A return value of 0 means that we need more data. */ static int @@ -63,11 +52,11 @@ _read_header (struct rs_packet *pkt) n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN); if (n == RS_HEADER_LEN) { - pkt->hdr_read_flag = 1; + pkt->flags |= rs_packet_hdr_read_flag; pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3]; if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096) { - _close_conn (&pkt->conn); + conn_close (&pkt->conn); return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT, "invalid packet length: %d", pkt->rpkt->data_len); @@ -75,7 +64,7 @@ _read_header (struct rs_packet *pkt) pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len); if (!pkt->rpkt->data) { - _close_conn (&pkt->conn); + conn_close (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, NULL); } @@ -91,7 +80,7 @@ _read_header (struct rs_packet *pkt) } else /* Error: libevent gave us less than the low watermark. */ { - _close_conn (&pkt->conn); + conn_close (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__, "got %d octets reading header", n); } @@ -117,7 +106,7 @@ _read_packet (struct rs_packet *pkt) { bufferevent_disable (pkt->conn->bev, EV_READ); rs_debug (("%s: complete packet read\n", __func__)); - pkt->hdr_read_flag = 0; + pkt->flags &= ~rs_packet_hdr_read_flag; memset (pkt->hdr, 0, sizeof(*pkt->hdr)); /* Checks done by rad_packet_ok: @@ -125,39 +114,13 @@ _read_packet (struct rs_packet *pkt) - invalid code field - attribute lengths >= 2 - attribute sizes adding up correctly */ - if (!rad_packet_ok (pkt->rpkt, 0) != 0) + if (!rad_packet_ok (pkt->rpkt, 0)) { - _close_conn (&pkt->conn); + conn_close (&pkt->conn); return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "invalid packet: %s", fr_strerror ()); } - /* TODO: Verify that reception of an unsolicited response packet - results in connection being closed. */ - - /* If we have a request to match this response against, verify - and decode the response. */ - if (pkt->original) - { - /* Verify header and message authenticator. */ - if (rad_verify (pkt->rpkt, pkt->original->rpkt, - pkt->conn->active_peer->secret)) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "rad_verify: %s", fr_strerror ()); - } - - /* Decode and decrypt. */ - if (rad_decode (pkt->rpkt, pkt->original->rpkt, - pkt->conn->active_peer->secret)) - { - _close_conn (&pkt->conn); - return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, - "rad_decode: %s", fr_strerror ()); - } - } - #if defined (DEBUG) /* Find out what happens if there's data left in the buffer. */ { @@ -169,8 +132,8 @@ _read_packet (struct rs_packet *pkt) } #endif - /* Hand over message to user, changes ownership of pkt. Don't - touch it afterwards -- it might have been freed. */ + /* Hand over message to user. This changes ownership of pkt. + Don't touch it afterwards -- it might have been freed. */ if (pkt->conn->callbacks.received_cb) pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data); } @@ -183,14 +146,12 @@ _read_packet (struct rs_packet *pkt) return 0; } -/* Read callback for TCP. +/* The read callback for TCP. Read exactly one RADIUS message from BEV and store it in struct - rs_packet passed in CTX (hereby called 'pkt'). - - Verify the received packet against pkt->original, if !NULL. + rs_packet passed in USER_DATA. - Inform upper layer about successful reception of valid RADIUS + Inform upper layer about successful reception of received RADIUS message by invoking conn->callbacks.recevied_cb(), if !NULL. */ void tcp_read_cb (struct bufferevent *bev, void *user_data) @@ -204,9 +165,9 @@ tcp_read_cb (struct bufferevent *bev, void *user_data) pkt->rpkt->sockfd = pkt->conn->fd; pkt->rpkt->vps = NULL; - if (!pkt->hdr_read_flag) + if ((pkt->flags & rs_packet_hdr_read_flag) == 0) if (_read_header (pkt)) - return; + return; /* Error. */ _read_packet (pkt); } -- cgit v1.1 From a379adb7d6cf86ebf2c60451fab1df588060de23 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 7 Mar 2011 15:25:33 +0100 Subject: Requests are now high level, i.e. not for user doing the dispatching. --- lib/request.c | 67 +++++++---------------------------------------------------- 1 file changed, 7 insertions(+), 60 deletions(-) diff --git a/lib/request.c b/lib/request.c index 80a0a81..8cb8b7e 100644 --- a/lib/request.c +++ b/lib/request.c @@ -12,6 +12,7 @@ #include #include #include +#include "conn.h" int rs_request_create (struct rs_connection *conn, struct rs_request **req_out) @@ -68,75 +69,21 @@ _timer_cb (evutil_socket_t fd, short what, void *arg) } #endif -static void -_rs_req_connected (void *user_data) -{ - struct rs_request *request = (struct rs_request *) user_data; - assert (request); - assert (request->conn); - if (request->saved_cb.connected_cb) - request->saved_cb.connected_cb (request->saved_user_data); -} - -static void -_rs_req_disconnected (void *user_data) -{ - struct rs_request *request = (struct rs_request *) user_data; - assert (request); - assert (request->conn); - if (request->saved_cb.disconnected_cb) - request->saved_cb.disconnected_cb (request->saved_user_data); -} - -static void -_rs_req_packet_received (struct rs_packet *msg, void *user_data) -{ - struct rs_request *request = (struct rs_request *) user_data; - assert (request); - assert (request->conn); - if (request->saved_cb.received_cb) - request->saved_cb.received_cb (msg, request->saved_user_data); -} - -static void -_rs_req_packet_sent (void *user_data) -{ - struct rs_request *request = (struct rs_request *) user_data; - assert (request); - assert (request->conn); - if (request->saved_cb.sent_cb) - request->saved_cb.sent_cb (request->saved_user_data); -} - int rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) { - int err = 0; struct rs_connection *conn = NULL; if (!request || !request->conn || !request->req_msg || !resp_msg) return rs_err_conn_push_fl (conn, RSE_INVAL, __FILE__, __LINE__, NULL); conn = request->conn; + assert (!conn_user_dispatch_p (conn)); /* This function is high level. */ - request->saved_user_data = conn->user_data; - conn->user_data = request; - - request->saved_cb = conn->callbacks; - conn->callbacks.connected_cb = _rs_req_connected; - conn->callbacks.disconnected_cb = _rs_req_disconnected; - conn->callbacks.received_cb = _rs_req_packet_received; - conn->callbacks.sent_cb = _rs_req_packet_sent; - - err = rs_packet_send (request->req_msg, request); - if (err) - goto cleanup; + if (rs_packet_send (request->req_msg, request)) + return -1; - err = rs_conn_receive_packet (request->conn, request->req_msg, resp_msg); - if (err) - goto cleanup; + if (rs_conn_receive_packet (request->conn, request->req_msg, resp_msg)) + return -1; -cleanup: - conn->user_data = request->saved_user_data; - conn->callbacks = request->saved_cb; - return err; + return RSE_OK; } -- cgit v1.1 From 962869fcd2decd993171aa82c00b9e0b3517f995 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 7 Mar 2011 15:26:12 +0100 Subject: examples/client-blocking.c: Clean up and improve error handling. --- lib/examples/client-blocking.c | 68 +++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index 27f87ca..31fd6d1 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -8,6 +8,7 @@ #include #include #include +#include "debug.h" /* For rs_dump_packet(). */ #define SECRET "sikrit" #define USER_NAME "molgan" @@ -16,9 +17,10 @@ struct rs_error * blocking_client (const char *av1, const char *av2, int use_request_object_flag) { - struct rs_context *h; - struct rs_connection *conn; - struct rs_packet *req, *resp = NULL; + struct rs_context *h = NULL; + struct rs_connection *conn = NULL; + struct rs_request *request = NULL; + struct rs_packet *req = NULL, *resp = NULL; if (rs_context_create (&h, "/usr/share/freeradius/dictionary")) return NULL; @@ -28,67 +30,59 @@ blocking_client (const char *av1, const char *av2, int use_request_object_flag) struct rs_peer *server; if (rs_conn_create (h, &conn, NULL)) - return rs_err_conn_pop (conn); + goto cleanup; rs_conn_set_type (conn, RS_CONN_TYPE_UDP); if (rs_peer_create (conn, &server)) - return rs_err_conn_pop (conn); + goto cleanup; if (rs_peer_set_address (server, av1, av2)) - return rs_err_conn_pop (conn); + goto cleanup; rs_peer_set_timeout (server, 1); rs_peer_set_retries (server, 3); if (rs_peer_set_secret (server, SECRET)) - return rs_err_conn_pop (conn); + goto cleanup; } #else if (rs_context_read_config (h, av1)) - return rs_err_ctx_pop (h); + goto cleanup; if (rs_conn_create (h, &conn, av2)) - return rs_err_conn_pop (conn); + goto cleanup; #endif /* USE_CONFIG_FILE */ if (use_request_object_flag) { - struct rs_request *request; - if (rs_request_create_authn (conn, &request, USER_NAME, USER_PW)) - return rs_err_conn_pop (conn); + goto cleanup; if (rs_request_send (request, &resp)) - return rs_err_conn_pop (conn); - rs_request_destroy (request); + goto cleanup; } else { if (rs_packet_create_authn_request (conn, &req, USER_NAME, USER_PW)) - return rs_err_conn_pop (conn); - + goto cleanup; if (rs_packet_send (req, NULL)) - { - rs_packet_destroy (req); - return rs_err_conn_pop (conn); - } + goto cleanup; if (rs_conn_receive_packet (conn, req, &resp)) - { - rs_packet_destroy (req); - return rs_err_conn_pop (conn); - } - rs_packet_destroy (req); + goto cleanup; } if (resp) - { - RADIUS_PACKET *fr_pkt = NULL; - VALUE_PAIR *fr_vp = NULL; + rs_dump_packet (resp); + else + fprintf (stderr, "%s: no response\n", __func__); - fr_pkt = rs_packet_frpkt (resp); - fr_vp = fr_pkt->vps; /* FIXME: Is there an accessor? */ - if (fr_vp) - vp_printlist(stdout, fr_vp); - rs_packet_destroy (resp); - } + cleanup: + if (resp) + rs_packet_destroy (resp); + if (req) + rs_packet_destroy (req); + if (conn) + rs_conn_destroy (conn); + if (request) + rs_request_destroy (request); + if (h) + rs_context_destroy (h); - rs_conn_destroy (conn); - rs_context_destroy (h); - return NULL; + return rs_err_conn_pop (conn); } int -- cgit v1.1 From 1073de4a6139cf1b78ed82bc93e26be385cb76b1 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 Mar 2011 13:20:20 +0100 Subject: Don't return -1 to user but rather an error code. NOTE: Changes rs_conn_receive_packet() and rs_packet_send() only. --- lib/conn.c | 2 +- lib/send.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/conn.c b/lib/conn.c index 028302c..feed856 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -305,7 +305,7 @@ rs_conn_receive_packet (struct rs_connection *conn, && packet_verify_response (pkt->conn, pkt, req_msg) != RSE_OK)) { assert (rs_err_conn_peek_code (pkt->conn)); - return -1; + return rs_err_conn_peek_code (conn); } if (pkt_out) diff --git a/lib/send.c b/lib/send.c index cc7fd71..af25144 100644 --- a/lib/send.c +++ b/lib/send.c @@ -128,7 +128,10 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) conn->user_data = NULL; if ((pkt->flags & rs_packet_sent_flag) == 0) - return -1; + { + assert (rs_err_conn_peek_code (conn)); + return rs_err_conn_peek_code (conn); + } } return RSE_OK; -- cgit v1.1 From 657eec7ee5a276521eb456bf648878935e794b6e Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 Mar 2011 13:32:10 +0100 Subject: Clean up struct rs_error somewhat. More to be done here! --- lib/err.c | 19 +++++-------------- lib/examples/client-blocking.c | 2 +- lib/include/radsec/radsec-impl.h | 1 - 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/lib/err.c b/lib/err.c index 55fc5de..e2112c3 100644 --- a/lib/err.c +++ b/lib/err.c @@ -178,7 +178,9 @@ rs_err_conn_pop (struct rs_connection *conn) int rs_err_conn_peek_code (struct rs_connection *conn) { - if (conn && conn->err) + if (!conn) + return -1; /* FIXME: RSE_INVALID_CONN */ + if (conn->err) return conn->err->code; else return RSE_OK; @@ -188,26 +190,15 @@ void rs_err_free (struct rs_error *err) { assert (err); - if (err->msg) - free (err->msg); free (err); } char * -rs_err_msg (struct rs_error *err, int dofree_flag) +rs_err_msg (struct rs_error *err) { - char *msg; - if (!err) return NULL; - if (err->msg) - msg = err->msg; - else - msg = strdup (err->buf); - - if (dofree_flag) - rs_err_free (err); - return msg; + return err->buf; } int diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index 31fd6d1..ef361e5 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -100,7 +100,7 @@ main (int argc, char *argv[]) err = blocking_client (argv[1], argv[2], use_request_object_flag); if (err) { - fprintf (stderr, "%s\n", rs_err_msg (err, 0)); + fprintf (stderr, "%s\n", rs_err_msg (err)); return rs_err_code (err, 1); } return 0; diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index e790ccf..a924fc9 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -32,7 +32,6 @@ struct rs_credentials { struct rs_error { int code; - char *msg; char buf[1024]; }; -- cgit v1.1 From d464ebb9235fe78e6588e95d4d3333d5ee95ca48 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 Mar 2011 13:37:46 +0100 Subject: Timeout implemented in request objects, supported by TCP. TODO: UDP. --- lib/conn.c | 8 +++++ lib/err.c | 1 + lib/include/radsec/radsec-impl.h | 1 + lib/include/radsec/radsec.h | 9 +++-- lib/request.c | 72 ++++++++++++++++++++++++++++++++++------ lib/send.c | 6 ---- lib/tcp.c | 9 ++--- 7 files changed, 80 insertions(+), 26 deletions(-) diff --git a/lib/conn.c b/lib/conn.c index feed856..0786de2 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -64,6 +64,7 @@ rs_conn_create (struct rs_context *ctx, struct rs_connection **conn, c->peers = r->peers; /* FIXME: Copy instead? */ for (p = c->peers; p; p = p->next) p->conn = c; + c->timeout.tv_sec = r->timeout; c->tryagain = r->retries; } else @@ -313,3 +314,10 @@ rs_conn_receive_packet (struct rs_connection *conn, return RSE_OK; } +void +rs_conn_set_timeout(struct rs_connection *conn, struct timeval *tv) +{ + assert (conn); + assert (tv); + conn->timeout = *tv; +} diff --git a/lib/err.c b/lib/err.c index e2112c3..1f2cbc0 100644 --- a/lib/err.c +++ b/lib/err.c @@ -31,6 +31,7 @@ static const char *_errtxt[] = { "connect timeout", /* 16 RSE_TIMEOUT_CONN */ "invalid argument", /* 17 RSE_INVAL */ "I/O timeout", /* 18 RSE_TIMEOUT_IO */ + "timeout", /* 19 RSE_TIMEOUT */ }; #define ERRTXT_SIZE (sizeof(_errtxt) / sizeof(*_errtxt)) diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index a924fc9..49f9a35 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -75,6 +75,7 @@ struct rs_connection { struct rs_peer *peers; struct rs_peer *active_peer; struct rs_error *err; + struct timeval timeout; char is_connecting; /* FIXME: replace with a single state member */ char is_connected; /* FIXME: replace with a single state member */ int fd; /* Socket. */ diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index fcd391d..5f8f4db 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -3,6 +3,7 @@ /* See the file COPYING for licensing information. */ #include +#include enum rs_err_code { RSE_OK = 0, @@ -21,9 +22,10 @@ enum rs_err_code { RSE_INTERNAL = 13, RSE_SSLERR = 14, /* OpenSSL error. */ RSE_INVALID_PKT = 15, - RSE_TIMEOUT_CONN = 16, - RSE_INVAL = 17, - RSE_TIMEOUT_IO = 18, + RSE_TIMEOUT_CONN = 16, /* Connection timeout. */ + RSE_INVAL = 17, /* Invalid argument. */ + RSE_TIMEOUT_IO = 18, /* I/O timeout. */ + RSE_TIMEOUT = 19, /* High level timeout. */ }; enum rs_conn_type { @@ -111,6 +113,7 @@ int rs_conn_receive_packet(struct rs_connection *conn, struct rs_packet *request, struct rs_packet **pkt_out); int rs_conn_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); diff --git a/lib/request.c b/lib/request.c index 8cb8b7e..b0a8eef 100644 --- a/lib/request.c +++ b/lib/request.c @@ -5,14 +5,26 @@ #include #endif -#include +#include +#include #include +#include #include #include #include #include #include +#include +#include "debug.h" #include "conn.h" +#include "tcp.h" + +/* RFC 5080 2.2.1. Retransmission Behavior. */ +#define IRT 2 +#define MRC 5 +#define MRT 16 +#define MRD 30 +#define RAND 100 /* Rand factor, milliseconds. */ int rs_request_create (struct rs_connection *conn, struct rs_request **req_out) @@ -61,29 +73,69 @@ rs_request_destroy (struct rs_request *request) rs_free (request->conn->ctx, request); } -#if 0 static void -_timer_cb (evutil_socket_t fd, short what, void *arg) - +_rand_rt (struct timeval *res, uint32_t rtprev, uint32_t factor) { + uint32_t ms = rtprev * (fr_rand () % factor); + res->tv_sec = rtprev + ms / 1000; + res->tv_usec = (ms % 1000) * 1000; } -#endif int rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) { + int r = 0; struct rs_connection *conn = NULL; + int count = 0; + struct timeval rt = {0,0}; + struct timeval end = {0,0}; + struct timeval now = {0,0}; + struct timeval tmp_tv = {0,0}; + struct timeval mrt_tv = {MRT,0}; if (!request || !request->conn || !request->req_msg || !resp_msg) return rs_err_conn_push_fl (conn, RSE_INVAL, __FILE__, __LINE__, NULL); conn = request->conn; assert (!conn_user_dispatch_p (conn)); /* This function is high level. */ - if (rs_packet_send (request->req_msg, request)) - return -1; + gettimeofday (&end, NULL); + end.tv_sec += MRD; + _rand_rt (&rt, IRT, RAND); + while (1) + { + rs_conn_set_timeout (conn, &rt); + r = rs_packet_send (request->req_msg, NULL); + if (r == RSE_OK) + { + r = rs_conn_receive_packet (request->conn, + request->req_msg, + resp_msg); + if (r == RSE_OK) + break; /* Success. */ - if (rs_conn_receive_packet (request->conn, request->req_msg, resp_msg)) - return -1; + /* Timing out on receiving data or reconnecting a broken TCP + connection is ok. */ + if (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO) + break; /* Error. */ + } + else if (r != RSE_TIMEOUT_CONN) /* Timeout on TCP connect is ok. */ + break; /* Error. */ - return RSE_OK; + gettimeofday (&now, NULL); + if (++count > MRC || timercmp (&now, &end, >)) + { + r = RSE_TIMEOUT; + break; /* Timeout. */ + } + + /* rt = 2 * rt + _rand_rt (rt, RAND); */ + timeradd (&rt, &rt, &rt); /* rt = 2 * rt */ + _rand_rt (&tmp_tv, IRT, RAND); + timeradd (&rt, &tmp_tv, &rt); + if (timercmp (&rt, &mrt_tv, >)) + _rand_rt (&rt, MRT, RAND); + } + + rs_debug (("%s: returning %d\n", __func__, r)); + return r; } diff --git a/lib/send.c b/lib/send.c index af25144..f169ff9 100644 --- a/lib/send.c +++ b/lib/send.c @@ -18,12 +18,6 @@ #include "tcp.h" #include "udp.h" -/* RFC 5080 2.2.1. Retransmission Behavior */ -#define IRT 2 -#define MRC 5 -#define MRT 16 -#define MRD 30 - static int _conn_open (struct rs_connection *conn, struct rs_packet *pkt) { diff --git a/lib/tcp.c b/lib/tcp.c index 1801d62..c315143 100644 --- a/lib/tcp.c +++ b/lib/tcp.c @@ -37,7 +37,7 @@ _conn_timeout_cb (int fd, short event, void *data) rs_debug (("%s: connection timeout on %p (fd %d) connecting to %p\n", __func__, conn, conn->fd, conn->active_peer)); conn->is_connecting = 0; - rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); + rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL); event_loopbreak (conn); } } @@ -256,16 +256,11 @@ tcp_write_cb (struct bufferevent *bev, void *ctx) int tcp_set_connect_timeout (struct rs_connection *conn) { - struct timeval tv; - if (!conn->tev) conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); if (!conn->tev) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "evtimer_new"); - tv.tv_sec = conn->realm->timeout; - tv.tv_usec = 0; - evtimer_add (conn->tev, &tv); - + evtimer_add (conn->tev, &conn->timeout); return RSE_OK; } -- cgit v1.1 From 76c95bfc9033167fa692172360000df853b2a094 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 Mar 2011 14:24:30 +0100 Subject: examples/client-blocking: pull out the error before freeing conn. --- lib/examples/client-blocking.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index ef361e5..15152b6 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -21,6 +21,7 @@ blocking_client (const char *av1, const char *av2, int use_request_object_flag) struct rs_connection *conn = NULL; struct rs_request *request = NULL; struct rs_packet *req = NULL, *resp = NULL; + struct rs_error *err = NULL; if (rs_context_create (&h, "/usr/share/freeradius/dictionary")) return NULL; @@ -71,6 +72,7 @@ blocking_client (const char *av1, const char *av2, int use_request_object_flag) fprintf (stderr, "%s: no response\n", __func__); cleanup: + err = rs_err_conn_pop (conn); if (resp) rs_packet_destroy (resp); if (req) @@ -82,7 +84,7 @@ blocking_client (const char *av1, const char *av2, int use_request_object_flag) if (h) rs_context_destroy (h); - return rs_err_conn_pop (conn); + return err; } int -- cgit v1.1 From 6f3ae93eb1a5c4e352b42a9fae9b6f544a2e341a Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 Mar 2011 14:27:59 +0100 Subject: Update rs_err_msg() prototype. Also, rename enum rs_err_code to not collide with the function named the same. --- lib/include/radsec/radsec.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index 5f8f4db..f620fed 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -5,7 +5,7 @@ #include #include -enum rs_err_code { +enum rs_error_code { RSE_OK = 0, RSE_NOMEM = 1, RSE_NOSYS = 2, @@ -167,7 +167,7 @@ int rs_err_conn_push_fl(struct rs_connection *conn, 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); +char *rs_err_msg(struct rs_error *err); int rs_err_code(struct rs_error *err, int dofree_flag); #if defined (__cplusplus) -- cgit v1.1 From eff368434eafc492c8b4f8a455e2cb53a101708b Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 Mar 2011 14:29:09 +0100 Subject: Zap a double free. --- lib/radsec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/radsec.c b/lib/radsec.c index dd182c6..ddd4edd 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -117,14 +117,14 @@ _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). */ + + /* NOTE: The peer object doesn't own conn, nor realm. */ + /* NOTE: secret is owned by config */ if (p->addr) { evutil_freeaddrinfo (p->addr); p->addr = NULL; } - if (p->secret) - rs_free (p->conn->ctx, p->secret); rs_free (p->conn->ctx, p); } -- cgit v1.1 From b10f559880ab49a83558a63a7f5cd1d96e9ece53 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Tue, 8 Mar 2011 14:29:39 +0100 Subject: Add (disabled) linkage to libefence. --- lib/examples/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/examples/Makefile.am b/lib/examples/Makefile.am index 49d3409..ee0787b 100644 --- a/lib/examples/Makefile.am +++ b/lib/examples/Makefile.am @@ -4,5 +4,5 @@ AM_CFLAGS = -Wall -g bin_PROGRAMS = client client_SOURCES = client-blocking.c -client_LDADD = ../libradsec.la +client_LDADD = ../libradsec.la #-lefence client_CFLAGS = $(AM_CFLAGS) -DUSE_CONFIG_FILE -- cgit v1.1 From 7385db38d82b26736ba56bc7aec4c79acc420824 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 10:10:04 +0100 Subject: Don't make UDP write event persistant. rs_packet_send() adds the event again when there's a packet to send and the write callback does the same if it doesn't drain the queue. --- lib/udp.c | 68 ++++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/lib/udp.c b/lib/udp.c index 3573033..c602cbd 100644 --- a/lib/udp.c +++ b/lib/udp.c @@ -14,6 +14,44 @@ #include "compat.h" #include "udp.h" +/* Send one packet, the first in queue. */ +static void +_send (struct rs_connection *conn, int fd) +{ + ssize_t r = 0; + struct rs_packet *pkt = conn->out_queue; + + assert (pkt->rpkt); + assert (pkt->rpkt->data); + + /* Send. */ + r = compat_send (fd, pkt->rpkt->data, pkt->rpkt->data_len, 0); + if (r == -1) + { + int sockerr = evutil_socket_geterror (pkt->conn->fd); + if (sockerr != EAGAIN) + rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: send: %d (%s)", fd, sockerr, + evutil_socket_error_to_string (sockerr)); + return; /* Don't unlink packet. */ + } + + /* Unlink the packet. */ + conn->out_queue = pkt->next; + + /* If there are more packets in queue, add the write event again. */ + if (pkt->conn->out_queue) + { + r = event_add (pkt->conn->wev, NULL); + if (r < 0) + { + rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", evutil_gai_strerror (r)); + return; + } + } +} + /* Callback for conn->wev and conn->rev. FIXME: Rename. */ static void _evcb (evutil_socket_t fd, short what, void *user_data) @@ -33,36 +71,22 @@ _evcb (evutil_socket_t fd, short what, void *user_data) /* read a single UDP packet and stick it in a new struct rs_packet */ + /* TODO: Verify that reception of an unsolicited response packet + results in connection being closed. */ rs_debug (("%s: UDP read NYI", __func__)); + + /* TODO: delete retransmit timer */ } else if (what & EV_WRITE) { struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); - /* Socket ready for writing, possibly as a result of a - successful connect. */ + if (!pkt->conn->is_connected) event_on_connect (pkt->conn, pkt); - if (pkt->conn->out_queue) - { - /* Send one packet, the first. */ - ssize_t r = 0; - struct rs_packet *p = pkt->conn->out_queue; - assert (p->rpkt); - assert (p->rpkt->data); - r = compat_send (fd, p->rpkt->data, p->rpkt->data_len, 0); - if (r == -1) - { - int sockerr = evutil_socket_geterror (p->conn->fd); - if (sockerr != EAGAIN) - rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: send: %d (%s)", fd, sockerr, - evutil_socket_error_to_string (sockerr)); - return; /* Don't unlink packet. */ - } - pkt->conn->out_queue = p->next; - } + if (pkt->conn->out_queue) + _send (pkt->conn, fd); } } @@ -72,7 +96,7 @@ udp_init (struct rs_connection *conn, struct rs_packet *pkt) assert (!conn->bev); conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn); - conn->wev = event_new (conn->evb, conn->fd, EV_WRITE|EV_PERSIST, _evcb, pkt); + conn->wev = event_new (conn->evb, conn->fd, EV_WRITE, _evcb, pkt); if (!conn->rev || !conn->wev) { if (conn->rev) -- cgit v1.1 From fac0219dad91c574417f78ec674aa0dd10949e15 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 10:14:20 +0100 Subject: Rename and move around a few helper functions. --- lib/conf.c | 7 ++-- lib/conn.c | 41 +--------------------- lib/err.c | 75 ++++++++++++++++++++++++++++------------ lib/include/radsec/radsec-impl.h | 15 +++----- lib/peer.c | 31 ++++++++++++++--- 5 files changed, 88 insertions(+), 81 deletions(-) diff --git a/lib/conf.c b/lib/conf.c index 1d394ba..7e27f0b 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -9,6 +9,7 @@ #include #include #include +#include "peer.h" #include "debug.h" #if 0 @@ -112,15 +113,15 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) /* Add peers, one per server stanza. */ for (j = 0; j < cfg_size (cfg_config, "server"); j++) { - struct rs_peer *p = _rs_peer_create (ctx, &r->peers); + struct rs_peer *p = peer_create (ctx, &r->peers); if (!p) return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL); p->realm = r; cfg_server = cfg_getnsec (cfg_config, "server", j); - _rs_resolv (&p->addr, r->type, cfg_getstr (cfg_server, "hostname"), - cfg_getstr (cfg_server, "service")); + rs_resolv (&p->addr, r->type, cfg_getstr (cfg_server, "hostname"), + cfg_getstr (cfg_server, "service")); p->secret = cfg_getstr (cfg_server, "secret"); } } diff --git a/lib/conn.c b/lib/conn.c index 0786de2..85cd7d5 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -7,11 +7,11 @@ #include #include -#include #include #include #include #include +#include "debug.h" #include "conn.h" #include "event.h" #include "packet.h" @@ -90,45 +90,6 @@ rs_conn_set_type (struct rs_connection *conn, rs_conn_type_t type) conn->realm->type = type; } - -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) -{ - int err; - struct evutil_addrinfo hints, *res = NULL; - - memset (&hints, 0, sizeof(struct evutil_addrinfo)); - hints.ai_family = AF_INET; /* IPv4 only. TODO: Set AF_UNSPEC. */ - hints.ai_flags = AI_ADDRCONFIG; - switch (type) - { - case RS_CONN_TYPE_NONE: - return _rs_err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL); - case RS_CONN_TYPE_TCP: - /* Fall through. */ - case RS_CONN_TYPE_TLS: - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - break; - case RS_CONN_TYPE_UDP: - /* Fall through. */ - case RS_CONN_TYPE_DTLS: - 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) - return _rs_err_create (RSE_BADADDR, __FILE__, __LINE__, - "%s:%s: bad host name or service name (%s)", - hostname, service, evutil_gai_strerror(err)); - *addr = res; /* Simply use first result. */ - return NULL; -} - int rs_conn_add_listener (struct rs_connection *conn, rs_conn_type_t type, const char *hostname, int port) diff --git a/lib/err.c b/lib/err.c index 1f2cbc0..eecebb1 100644 --- a/lib/err.c +++ b/lib/err.c @@ -39,7 +39,7 @@ static struct rs_error * _err_vcreate (unsigned int code, const char *file, int line, const char *fmt, va_list args) { - struct rs_error *err; + struct rs_error *err = NULL; err = malloc (sizeof(struct rs_error)); if (err) @@ -69,15 +69,19 @@ _err_vcreate (unsigned int code, const char *file, int line, const char *fmt, } struct rs_error * -_rs_err_create (unsigned int code, const char *file, int line, const char *fmt, - ...) +err_create (unsigned int code, + const char *file, + int line, + const char *fmt, + ...) { - struct rs_error *err; + struct rs_error *err = NULL; va_list args; va_start (args, fmt); err = _err_vcreate (code, file, line, fmt, args); va_end (args); + return err; } @@ -87,36 +91,52 @@ _ctx_err_vpush_fl (struct rs_context *ctx, int code, const char *file, { struct rs_error *err = _err_vcreate (code, file, line, fmt, args); - if (err) - ctx->err = err; - return code; + if (!err) + return RSE_NOMEM; + + /* TODO: Implement a stack. */ + if (ctx->err) + rs_err_free (ctx->err); + ctx->err = err; + + return err->code; } int rs_err_ctx_push (struct rs_context *ctx, int code, const char *fmt, ...) { + int r = 0; va_list args; + va_start (args, fmt); - _ctx_err_vpush_fl (ctx, code, NULL, 0, fmt, args); + r = _ctx_err_vpush_fl (ctx, code, NULL, 0, fmt, args); va_end (args); - return code; + + return r; } int rs_err_ctx_push_fl (struct rs_context *ctx, int code, const char *file, int line, const char *fmt, ...) { + int r = 0; va_list args; + va_start (args, fmt); - _ctx_err_vpush_fl (ctx, code, file, line, fmt, args); + r = _ctx_err_vpush_fl (ctx, code, file, line, fmt, args); va_end (args); - return code; + + return r; } int -_rs_err_conn_push_err (struct rs_connection *conn, struct rs_error *err) +err_conn_push_err (struct rs_connection *conn, struct rs_error *err) { + + if (conn->err) + rs_err_free (conn->err); conn->err = err; /* FIXME: use a stack */ + return err->code; } @@ -126,30 +146,37 @@ _conn_err_vpush_fl (struct rs_connection *conn, int code, const char *file, { struct rs_error *err = _err_vcreate (code, file, line, fmt, args); - if (err) - _rs_err_conn_push_err (conn, err); - return code; + if (!err) + return RSE_NOMEM; + + return err_conn_push_err (conn, err); } int rs_err_conn_push (struct rs_connection *conn, int code, const char *fmt, ...) { + int r = 0; + va_list args; va_start (args, fmt); - _conn_err_vpush_fl (conn, code, NULL, 0, fmt, args); + r = _conn_err_vpush_fl (conn, code, NULL, 0, fmt, args); va_end (args); - return code; + + return r; } int rs_err_conn_push_fl (struct rs_connection *conn, int code, const char *file, int line, const char *fmt, ...) { + int r = 0; + va_list args; va_start (args, fmt); - _conn_err_vpush_fl (conn, code, file, line, fmt, args); + r = _conn_err_vpush_fl (conn, code, file, line, fmt, args); va_end (args); - return code; + + return r; } struct rs_error * @@ -161,6 +188,7 @@ rs_err_ctx_pop (struct rs_context *ctx) return NULL; /* FIXME: RSE_INVALID_CTX. */ err = ctx->err; ctx->err = NULL; + return err; } @@ -173,6 +201,7 @@ rs_err_conn_pop (struct rs_connection *conn) return NULL; /* FIXME: RSE_INVALID_CONN */ err = conn->err; conn->err = NULL; + return err; } @@ -183,8 +212,8 @@ rs_err_conn_peek_code (struct rs_connection *conn) return -1; /* FIXME: RSE_INVALID_CONN */ if (conn->err) return conn->err->code; - else - return RSE_OK; + + return RSE_OK; } void @@ -199,6 +228,7 @@ rs_err_msg (struct rs_error *err) { if (!err) return NULL; + return err->buf; } @@ -212,6 +242,7 @@ rs_err_code (struct rs_error *err, int dofree_flag) code = err->code; if (dofree_flag) - rs_err_free(err); + rs_err_free (err); + return code; } diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index 49f9a35..9bcd208 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -113,18 +113,11 @@ struct rs_attr { VALUE_PAIR *vp; }; -/* Nonpublic functions. */ -struct rs_error *_rs_resolv(struct evutil_addrinfo **addr, - rs_conn_type_t type, const char *hostname, +/* Nonpublic functions (in radsec.c -- FIXME: move?). */ +struct rs_error *rs_resolv (struct evutil_addrinfo **addr, + rs_conn_type_t type, + const char *hostname, const char *service); -struct rs_peer *_rs_peer_create(struct rs_context *ctx, - struct rs_peer **rootp); -struct rs_error *_rs_err_create(unsigned int code, const char *file, - int line, const char *fmt, ...); -int _rs_err_conn_push_err(struct rs_connection *conn, - struct rs_error *err); - - #if defined (__cplusplus) } #endif diff --git a/lib/peer.c b/lib/peer.c index 0a1d2ec..bcd5c97 100644 --- a/lib/peer.c +++ b/lib/peer.c @@ -8,6 +8,7 @@ #include #include #include +#include "err.h" #include "peer.h" struct rs_peer * @@ -23,18 +24,38 @@ peer_pick_peer (struct rs_connection *conn) return conn->active_peer; } +struct rs_peer * +peer_create (struct rs_context *ctx, struct rs_peer **rootp) +{ + struct rs_peer *p; + + p = (struct rs_peer *) rs_malloc (ctx, sizeof(*p)); + if (p) + { + memset (p, 0, sizeof(struct rs_peer)); + if (*rootp) + { + p->next = (*rootp)->next; + (*rootp)->next = p; + } + else + *rootp = p; + } + return p; +} + /* Public functions. */ int rs_peer_create (struct rs_connection *conn, struct rs_peer **peer_out) { struct rs_peer *peer; - peer = _rs_peer_create (conn->ctx, &conn->peers); + peer = peer_create (conn->ctx, &conn->peers); if (peer) { peer->conn = conn; - peer->realm->timeout = 2; - peer->realm->retries = 2; + 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); @@ -52,9 +73,9 @@ rs_peer_set_address (struct rs_peer *peer, const char *hostname, assert (peer); assert (peer->realm); - err = _rs_resolv (&peer->addr, peer->realm->type, hostname, service); + err = rs_resolv (&peer->addr, peer->realm->type, hostname, service); if (err) - return _rs_err_conn_push_err (peer->conn, err); + return err_conn_push_err (peer->conn, err); return RSE_OK; } -- cgit v1.1 From c4e2bd206bb9248843a8a4d9a945c5e49a188474 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 10:16:27 +0100 Subject: Add RSE_DISCO. --- lib/err.c | 1 + lib/include/radsec/radsec.h | 1 + lib/tcp.c | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/err.c b/lib/err.c index eecebb1..4a90019 100644 --- a/lib/err.c +++ b/lib/err.c @@ -32,6 +32,7 @@ static const char *_errtxt[] = { "invalid argument", /* 17 RSE_INVAL */ "I/O timeout", /* 18 RSE_TIMEOUT_IO */ "timeout", /* 19 RSE_TIMEOUT */ + "peer disconnected", /* 20 RSE_DISCO */ }; #define ERRTXT_SIZE (sizeof(_errtxt) / sizeof(*_errtxt)) diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index f620fed..971fc17 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -26,6 +26,7 @@ enum rs_error_code { RSE_INVAL = 17, /* Invalid argument. */ RSE_TIMEOUT_IO = 18, /* I/O timeout. */ RSE_TIMEOUT = 19, /* High level timeout. */ + RSE_DISCO = 20, }; enum rs_conn_type { diff --git a/lib/tcp.c b/lib/tcp.c index c315143..063e9b2 100644 --- a/lib/tcp.c +++ b/lib/tcp.c @@ -209,6 +209,7 @@ tcp_event_cb (struct bufferevent *bev, short events, void *user_data) if (sockerr == 0) /* FIXME: True that errno == 0 means closed? */ { event_on_disconnect (conn); + rs_err_conn_push_fl (pkt->conn, RSE_DISCO, __FILE__, __LINE__, NULL); } else { -- cgit v1.1 From ce4d6dfe1728e5633a8f49fc4b16c36df0d23521 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 10:18:06 +0100 Subject: Add retransmission timer support (UDP). --- lib/conn.c | 17 +++++++++++++++++ lib/event.c | 43 ++++++++++++++++++++++++++++++++++++++++--- lib/event.h | 2 ++ lib/packet.c | 6 ++++-- lib/peer.h | 1 + lib/radsec.c | 49 +++++++++++++++++++++++++++++++++++-------------- lib/send.c | 4 ++++ lib/tcp.c | 31 +++++++++---------------------- lib/tcp.h | 2 +- lib/udp.c | 15 +++++++++++++++ lib/udp.h | 1 + 11 files changed, 129 insertions(+), 42 deletions(-) diff --git a/lib/conn.c b/lib/conn.c index 85cd7d5..3981f6a 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -282,3 +282,20 @@ rs_conn_set_timeout(struct rs_connection *conn, struct timeval *tv) assert (tv); conn->timeout = *tv; } + +int +conn_activate_timeout (struct rs_connection *conn) +{ + assert (conn); + assert (conn->tev); + assert (conn->evb); + if (conn->timeout.tv_sec || conn->timeout.tv_usec) + { + rs_debug (("%s: activating timer: %d.%d\n", __func__, + conn->timeout.tv_sec, conn->timeout.tv_usec)); + if (evtimer_add (conn->tev, &conn->timeout)) + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, + "evtimer_add: %d", errno); + } + return RSE_OK; +} diff --git a/lib/event.c b/lib/event.c index 55a7e6b..5afba98 100644 --- a/lib/event.c +++ b/lib/event.c @@ -21,6 +21,7 @@ #endif #include "event.h" #include "packet.h" +#include "conn.h" #include "debug.h" static void @@ -51,6 +52,41 @@ _evlog_cb (int severity, const char *msg) fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr? */ } +void +event_conn_timeout_cb (int fd, short event, void *data) +{ + struct rs_connection *conn = NULL; + + assert (data); + conn = (struct rs_connection *) 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; + rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL); + event_loopbreak (conn); + } +} + +void +event_retransmit_timeout_cb (int fd, short event, void *data) +{ + struct rs_connection *conn = NULL; + + assert (data); + conn = (struct rs_connection *) 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)); + rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL); + event_loopbreak (conn); + } +} + int event_init_socket (struct rs_connection *conn, struct rs_peer *p) { @@ -138,7 +174,7 @@ event_do_connect (struct rs_connection *conn) if (p->conn->bev) /* TCP */ { - tcp_set_connect_timeout (conn); + conn_activate_timeout (conn); /* Connect timeout. */ err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr, p->addr->ai_addrlen); if (err < 0) @@ -191,10 +227,10 @@ event_on_connect (struct rs_connection *conn, struct rs_packet *pkt) assert (!conn->is_connecting); conn->is_connected = 1; rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); - if (conn->tev) - evtimer_del (conn->tev); + if (conn->callbacks.connected_cb) conn->callbacks.connected_cb (conn->user_data); + if (pkt) packet_do_send (pkt); } @@ -202,6 +238,7 @@ event_on_connect (struct rs_connection *conn, struct rs_packet *pkt) int event_init_eventbase (struct rs_connection *conn) { + assert (conn); if (conn->evb) return RSE_OK; diff --git a/lib/event.h b/lib/event.h index e5ea90c..e042599 100644 --- a/lib/event.h +++ b/lib/event.h @@ -8,3 +8,5 @@ int event_init_eventbase (struct rs_connection *conn); int event_init_socket (struct rs_connection *conn, struct rs_peer *p); int event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer); void event_do_connect (struct rs_connection *conn); +void event_conn_timeout_cb (int fd, short event, void *data); +void event_retransmit_timeout_cb (int fd, short event, void *data); diff --git a/lib/packet.c b/lib/packet.c index 799234f..2611b46 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -88,7 +88,7 @@ packet_do_send (struct rs_packet *pkt) } #endif - if (pkt->conn->bev) + if (pkt->conn->bev) /* TCP. */ { int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, pkt->rpkt->data_len); @@ -97,13 +97,15 @@ packet_do_send (struct rs_packet *pkt) "bufferevent_write: %s", evutil_gai_strerror (err)); } - else + else /* UDP. */ { struct rs_packet **pp = &pkt->conn->out_queue; while (*pp && (*pp)->next) *pp = (*pp)->next; *pp = pkt; + + conn_activate_timeout (pkt->conn); /* Retransmission timer. */ } return RSE_OK; diff --git a/lib/peer.h b/lib/peer.h index f430bb2..a326325 100644 --- a/lib/peer.h +++ b/lib/peer.h @@ -1,4 +1,5 @@ /* Copyright 2011 NORDUnet A/S. All rights reserved. See the file COPYING for licensing information. */ +struct rs_peer *peer_create (struct rs_context *ctx, struct rs_peer **rootp); struct rs_peer *peer_pick_peer (struct rs_connection *conn); diff --git a/lib/radsec.c b/lib/radsec.c index ddd4edd..ec43b2f 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -20,6 +20,7 @@ #if defined (RS_ENABLE_TLS) #include #include "debug.h" +#include "err.h" #include "rsp_list.h" #include "../radsecproxy.h" #endif @@ -91,24 +92,44 @@ rs_context_create (struct rs_context **ctx, const char *dict) return err; } -struct rs_peer * -_rs_peer_create (struct rs_context *ctx, struct rs_peer **rootp) +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) { - struct rs_peer *p; + int err; + struct evutil_addrinfo hints, *res = NULL; - p = (struct rs_peer *) rs_malloc (ctx, sizeof(*p)); - if (p) + memset (&hints, 0, sizeof(struct evutil_addrinfo)); + hints.ai_family = AF_INET; /* IPv4 only. TODO: Set AF_UNSPEC. */ + hints.ai_flags = AI_ADDRCONFIG; + switch (type) { - memset (p, 0, sizeof(struct rs_peer)); - if (*rootp) - { - p->next = (*rootp)->next; - (*rootp)->next = p; - } - else - *rootp = p; + case RS_CONN_TYPE_NONE: + return err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL); + case RS_CONN_TYPE_TCP: + /* Fall through. */ + case RS_CONN_TYPE_TLS: + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + break; + case RS_CONN_TYPE_UDP: + /* Fall through. */ + case RS_CONN_TYPE_DTLS: + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + break; + default: + return err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL); } - return p; + err = evutil_getaddrinfo (hostname, service, &hints, &res); + if (err) + return err_create (RSE_BADADDR, __FILE__, __LINE__, + "%s:%s: bad host name or service name (%s)", + hostname, service, evutil_gai_strerror(err)); + *addr = res; /* Simply use first result. */ + return NULL; } static void diff --git a/lib/send.c b/lib/send.c index f169ff9..0872471 100644 --- a/lib/send.c +++ b/lib/send.c @@ -35,6 +35,8 @@ _conn_open (struct rs_connection *conn, struct rs_packet *pkt) if (conn->realm->type == RS_CONN_TYPE_TCP || conn->realm->type == RS_CONN_TYPE_TLS) { + if (tcp_init_connect_timer (conn)) + return -1; if (event_init_bufferevent (conn, conn->active_peer)) return -1; } @@ -42,6 +44,8 @@ _conn_open (struct rs_connection *conn, struct rs_packet *pkt) { if (udp_init (conn, pkt)) return -1; + if (udp_init_retransmit_timer (conn)) + return -1; } if (!conn->is_connected) diff --git a/lib/tcp.c b/lib/tcp.c index 063e9b2..ce071cd 100644 --- a/lib/tcp.c +++ b/lib/tcp.c @@ -24,24 +24,6 @@ #include #endif -static void -_conn_timeout_cb (int fd, short event, void *data) -{ - struct rs_connection *conn; - - assert (data); - conn = (struct rs_connection *) 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; - rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL); - event_loopbreak (conn); - } -} - /* Read one RADIUS packet header. Return !0 on error. A return value of 0 means that we need more data. */ static int @@ -191,6 +173,8 @@ tcp_event_cb (struct bufferevent *bev, short events, void *user_data) conn->is_connecting = 0; if (events & BEV_EVENT_CONNECTED) { + if (conn->tev) + evtimer_del (conn->tev); /* Cancel connect timer. */ event_on_connect (conn, pkt); } else if (events & BEV_EVENT_EOF) @@ -255,13 +239,16 @@ tcp_write_cb (struct bufferevent *bev, void *ctx) } int -tcp_set_connect_timeout (struct rs_connection *conn) +tcp_init_connect_timer (struct rs_connection *conn) { - if (!conn->tev) - conn->tev = evtimer_new (conn->evb, _conn_timeout_cb, conn); + assert (conn); + + if (conn->tev) + event_free (conn->tev); + conn->tev = evtimer_new (conn->evb, event_conn_timeout_cb, conn); if (!conn->tev) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "evtimer_new"); - evtimer_add (conn->tev, &conn->timeout); + return RSE_OK; } diff --git a/lib/tcp.h b/lib/tcp.h index 8f519bb..fc2c4df 100644 --- a/lib/tcp.h +++ b/lib/tcp.h @@ -4,4 +4,4 @@ void tcp_event_cb (struct bufferevent *bev, short events, void *user_data); void tcp_read_cb (struct bufferevent *bev, void *user_data); void tcp_write_cb (struct bufferevent *bev, void *ctx); -int tcp_set_connect_timeout (struct rs_connection *conn); +int tcp_init_connect_timer (struct rs_connection *conn); diff --git a/lib/udp.c b/lib/udp.c index c602cbd..ac4e487 100644 --- a/lib/udp.c +++ b/lib/udp.c @@ -107,3 +107,18 @@ udp_init (struct rs_connection *conn, struct rs_packet *pkt) } return RSE_OK; } + +int +udp_init_retransmit_timer (struct rs_connection *conn) +{ + assert (conn); + + if (conn->tev) + event_free (conn->tev); + conn->tev = evtimer_new (conn->evb, event_retransmit_timeout_cb, conn); + if (!conn->tev) + return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, + "evtimer_new"); + + return RSE_OK; +} diff --git a/lib/udp.h b/lib/udp.h index a2a7228..338e7c2 100644 --- a/lib/udp.h +++ b/lib/udp.h @@ -2,3 +2,4 @@ See the file COPYING for licensing information. */ int udp_init (struct rs_connection *conn, struct rs_packet *pkt); +int udp_init_retransmit_timer (struct rs_connection *conn); -- cgit v1.1 From 8967b5275fa61ddba7031b5b82750031e4f8bb4b Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 10:24:22 +0100 Subject: Use retransmisison timer in request object. --- lib/request.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/request.c b/lib/request.c index b0a8eef..f354382 100644 --- a/lib/request.c +++ b/lib/request.c @@ -18,6 +18,7 @@ #include "debug.h" #include "conn.h" #include "tcp.h" +#include "udp.h" /* RFC 5080 2.2.1. Retransmission Behavior. */ #define IRT 2 @@ -91,7 +92,7 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) struct timeval end = {0,0}; struct timeval now = {0,0}; struct timeval tmp_tv = {0,0}; - struct timeval mrt_tv = {MRT,0}; + const struct timeval mrt_tv = {MRT,0}; if (!request || !request->conn || !request->req_msg || !resp_msg) return rs_err_conn_push_fl (conn, RSE_INVAL, __FILE__, __LINE__, NULL); @@ -104,6 +105,7 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) while (1) { rs_conn_set_timeout (conn, &rt); + r = rs_packet_send (request->req_msg, NULL); if (r == RSE_OK) { @@ -113,13 +115,11 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) if (r == RSE_OK) break; /* Success. */ - /* Timing out on receiving data or reconnecting a broken TCP - connection is ok. */ if (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO) break; /* Error. */ } - else if (r != RSE_TIMEOUT_CONN) /* Timeout on TCP connect is ok. */ - break; /* Error. */ + else if (r != RSE_TIMEOUT_CONN && r != RSE_TIMEOUT_IO) + break; /* Error. */ gettimeofday (&now, NULL); if (++count > MRC || timercmp (&now, &end, >)) @@ -128,14 +128,17 @@ rs_request_send (struct rs_request *request, struct rs_packet **resp_msg) break; /* Timeout. */ } - /* rt = 2 * rt + _rand_rt (rt, RAND); */ - timeradd (&rt, &rt, &rt); /* rt = 2 * rt */ + /* rt = 2 * rt + rand_rt (rt, RAND); */ + timeradd (&rt, &rt, &rt); _rand_rt (&tmp_tv, IRT, RAND); timeradd (&rt, &tmp_tv, &rt); if (timercmp (&rt, &mrt_tv, >)) _rand_rt (&rt, MRT, RAND); } + timerclear (&rt); + rs_conn_set_timeout (conn, &rt); + rs_debug (("%s: returning %d\n", __func__, r)); return r; } -- cgit v1.1 From 7bd18eed0316ca7cae8c416b1853842c7c375355 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 12:48:00 +0100 Subject: Add missing header files. --- lib/conn.h | 6 ++++++ lib/err.h | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 lib/conn.h create mode 100644 lib/err.h diff --git a/lib/conn.h b/lib/conn.h new file mode 100644 index 0000000..18d2da3 --- /dev/null +++ b/lib/conn.h @@ -0,0 +1,6 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING for licensing information. */ + +int conn_user_dispatch_p (const struct rs_connection *conn); +int conn_close (struct rs_connection **connp); +int conn_activate_timeout (struct rs_connection *conn); diff --git a/lib/err.h b/lib/err.h new file mode 100644 index 0000000..5e1c9c9 --- /dev/null +++ b/lib/err.h @@ -0,0 +1,9 @@ +/* Copyright 2011 NORDUnet A/S. All rights reserved. + See the file COPYING 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); -- cgit v1.1 From f9bc41973f176e8bb4fb3f27b2a7f24247a56d28 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 13:12:20 +0100 Subject: Remove superfluous assignment. This is done in rs_packet_create(). --- lib/conn.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/conn.c b/lib/conn.c index 3981f6a..8d369ab 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -226,7 +226,6 @@ rs_conn_receive_packet (struct rs_connection *conn, if (rs_packet_create (conn, &pkt)) return -1; - pkt->conn = conn; assert (conn->evb); assert (conn->bev); -- cgit v1.1 From e92bfb068a357645de21a920362fe82ab6ec669f Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 19:49:54 +0100 Subject: Formatting changes. --- lib/attr.c | 5 ++++- lib/packet.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/attr.c b/lib/attr.c index 23efa6e..2face5f 100644 --- a/lib/attr.c +++ b/lib/attr.c @@ -10,7 +10,10 @@ #include int -rs_attr_create(struct rs_connection *conn, struct rs_attr **attr, const char *type, const char *val) +rs_attr_create(struct rs_connection *conn, + struct rs_attr **attr, + const char *type, + const char *val) { VALUE_PAIR *vp; struct rs_attr *a; diff --git a/lib/packet.c b/lib/packet.c index 2611b46..e79268b 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -88,6 +88,7 @@ packet_do_send (struct rs_packet *pkt) } #endif + /* Put message in output buffer. */ if (pkt->conn->bev) /* TCP. */ { int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, -- cgit v1.1 From 11cf984f611e835c394deede450af9fd69434e30 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 19:51:59 +0100 Subject: Don't add Message-Authenticator more than once. Retransmiting the packet showed that we added another Message-Authenticator attribute every time we sent it. --- lib/packet.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/packet.c b/lib/packet.c index e79268b..7b5ae2d 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -59,19 +59,25 @@ packet_do_send (struct rs_packet *pkt) { VALUE_PAIR *vp = NULL; + assert (pkt); + assert (pkt->conn); + assert (pkt->conn->active_peer); + assert (pkt->conn->active_peer->secret); assert (pkt->rpkt); - /* Add Message-Authenticator, RFC 2869. */ + /* Add a Message-Authenticator, RFC 2869, if not already present. */ /* FIXME: Make Message-Authenticator optional? */ vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); if (!vp) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "paircreate: %s", fr_strerror ()); - pairadd (&pkt->rpkt->vps, vp); + pairreplace (&pkt->rpkt->vps, vp); + /* Encode message. */ if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_encode: %s", fr_strerror ()); + /* Sign message. */ if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_sign: %s", fr_strerror ()); -- cgit v1.1 From 0a7d803b9aa40512cf0f0c574d397ccba3ff1d13 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 23:09:26 +0100 Subject: Get UDP working. For UDP, activate retransmit timer before receiving rather than sending makes the event loop break nicely after sending a message (which is important for blocking mode). Not quite sure that this is really accurate wrt to retransmission timing though but it should do for now. For UDP, set the user_data member for the read callback in rs_conn_receive_packet -- the one from udp_init() doesn't do much good now. For UDP, implement receiving message. Add compat_recv(). --- lib/compat.c | 6 ++++ lib/compat.h | 1 + lib/conn.c | 14 +++++--- lib/packet.c | 2 -- lib/udp.c | 114 +++++++++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 100 insertions(+), 37 deletions(-) diff --git a/lib/compat.c b/lib/compat.c index fa075a1..ccc6388 100644 --- a/lib/compat.c +++ b/lib/compat.c @@ -14,3 +14,9 @@ compat_send (int sockfd, const void *buf, size_t len, int flags) { return send (sockfd, buf, len, flags); } + +ssize_t +compat_recv (int sockfd, void *buf, size_t len, int flags) +{ + return recv (sockfd, buf, len, flags); +} diff --git a/lib/compat.h b/lib/compat.h index 50ae22e..125f651 100644 --- a/lib/compat.h +++ b/lib/compat.h @@ -2,3 +2,4 @@ See the file COPYING for licensing information. */ ssize_t compat_send (int sockfd, const void *buf, size_t len, int flags); +ssize_t compat_recv (int sockfd, void *buf, size_t len, int flags); diff --git a/lib/conn.c b/lib/conn.c index 8d369ab..5382888 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -228,29 +228,33 @@ rs_conn_receive_packet (struct rs_connection *conn, return -1; assert (conn->evb); - assert (conn->bev); - assert (conn->active_peer); assert (conn->fd >= 0); conn->callbacks.received_cb = _rcb; conn->user_data = pkt; pkt->flags &= ~rs_packet_received_flag; - if (conn->bev) + if (conn->bev) /* TCP. */ { bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); bufferevent_setcb (conn->bev, tcp_read_cb, NULL, tcp_event_cb, pkt); bufferevent_enable (conn->bev, EV_READ); } - else + else /* UDP. */ { + /* Put fresh packet in user_data for the callback and enable the + read event. */ + event_assign (conn->rev, conn->evb, event_get_fd (conn->rev), + EV_READ, event_get_callback (conn->rev), pkt); err = event_add (conn->rev, NULL); if (err < 0) return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, "event_add: %s", evutil_gai_strerror (err)); - } + /* Activae retransmission timer. */ + conn_activate_timeout (pkt->conn); + } rs_debug (("%s: entering event loop\n", __func__)); err = event_base_dispatch (conn->evb); diff --git a/lib/packet.c b/lib/packet.c index 7b5ae2d..48fb55e 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -111,8 +111,6 @@ packet_do_send (struct rs_packet *pkt) while (*pp && (*pp)->next) *pp = (*pp)->next; *pp = pkt; - - conn_activate_timeout (pkt->conn); /* Retransmission timer. */ } return RSE_OK; diff --git a/lib/udp.c b/lib/udp.c index ac4e487..19968b3 100644 --- a/lib/udp.c +++ b/lib/udp.c @@ -6,6 +6,8 @@ #endif #include +#include +#include #include #include #include @@ -15,7 +17,7 @@ #include "udp.h" /* Send one packet, the first in queue. */ -static void +static int _send (struct rs_connection *conn, int fd) { ssize_t r = 0; @@ -30,12 +32,12 @@ _send (struct rs_connection *conn, int fd) { int sockerr = evutil_socket_geterror (pkt->conn->fd); if (sockerr != EAGAIN) - rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, - "%d: send: %d (%s)", fd, sockerr, - evutil_socket_error_to_string (sockerr)); - return; /* Don't unlink packet. */ + return rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: send: %d (%s)", fd, sockerr, + evutil_socket_error_to_string (sockerr)); } + assert (r == pkt->rpkt->data_len); /* Unlink the packet. */ conn->out_queue = pkt->next; @@ -44,38 +46,83 @@ _send (struct rs_connection *conn, int fd) { r = event_add (pkt->conn->wev, NULL); if (r < 0) - { - rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "event_add: %s", evutil_gai_strerror (r)); - return; - } + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "event_add: %s", evutil_gai_strerror (r)); + rs_debug (("%s: re-adding the write event\n", __func__)); } + + return RSE_OK; } -/* Callback for conn->wev and conn->rev. FIXME: Rename. */ +/* Callback for conn->wev and conn->rev. FIXME: Rename. + + USER_DATA contains connection for EV_READ and a packet for + EV_WRITE. This is because we don't have a connect/establish entry + point at the user level -- send implies connect so when we're + connected we need the packet to send. */ static void _evcb (evutil_socket_t fd, short what, void *user_data) { - //rs_debug (("%s: fd=%d what=0x%x\n", __func__, fd, what)); - if (what & EV_TIMEOUT) - { - struct rs_connection *conn = (struct rs_connection *) user_data; - assert (conn); - conn->is_connecting = 0; - rs_debug (("%s: UDP timeout NYI", __func__)); - } - else if (what & EV_READ) + rs_debug (("%s: fd=%d what =", __func__, fd)); + if (what & EV_TIMEOUT) rs_debug ((" TIMEOUT")); + if (what & EV_READ) rs_debug ((" READ")); + if (what & EV_WRITE) rs_debug ((" WRITE")); + rs_debug (("\n")); + + if (what & EV_READ) { - struct rs_connection *conn = (struct rs_connection *) user_data; - assert (conn); - /* read a single UDP packet and stick it in a new struct - rs_packet */ + /* Read a single UDP packet and stick it in USER_DATA. */ + /* TODO: Verify that unsolicited packets are dropped. */ + struct rs_packet *pkt = (struct rs_packet *) user_data; + ssize_t r = 0; - /* TODO: Verify that reception of an unsolicited response packet - results in connection being closed. */ - rs_debug (("%s: UDP read NYI", __func__)); + assert (pkt); + assert (pkt->conn); - /* TODO: delete retransmit timer */ + pkt->rpkt->data = rs_malloc (pkt->conn->ctx, 4096); + if (pkt->rpkt->data == NULL) + { + rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, NULL); + return; + } + r = compat_recv (fd, pkt->rpkt->data, 4096, MSG_TRUNC); + if (r == -1) + { + int sockerr = evutil_socket_geterror (pkt->conn->fd); + if (sockerr == EAGAIN) + { + /* FIXME: Really shouldn't happen since we've been told + that fd is readable! */ + rs_debug (("%s: EAGAIN reading UDP packet -- wot?")); + return; + } + + /* Hard error. */ + rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, + "%d: recv: %d (%s)", fd, sockerr, + evutil_socket_error_to_string (sockerr)); + event_del (pkt->conn->tev); + return; + } + event_del (pkt->conn->tev); + if (r < 20 || r > 4096) /* Short or long packet. */ + { + rs_err_conn_push (pkt->conn, RSE_INVALID_PKT, + "invalid packet length: %d", + pkt->rpkt->data_len); + return; + } + pkt->rpkt->data_len = (pkt->rpkt->data[2] << 8) + pkt->rpkt->data[3]; + if (!rad_packet_ok (pkt->rpkt, 0)) + { + rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, + "invalid packet: %s", fr_strerror ()); + return; + } + /* Hand over message to user. This changes ownership of pkt. + Don't touch it afterwards -- it might have been freed. */ + if (pkt->conn->callbacks.received_cb) + pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data); } else if (what & EV_WRITE) { @@ -86,8 +133,15 @@ _evcb (evutil_socket_t fd, short what, void *user_data) event_on_connect (pkt->conn, pkt); if (pkt->conn->out_queue) - _send (pkt->conn, fd); + if (_send (pkt->conn, fd) == RSE_OK) + if (pkt->conn->callbacks.sent_cb) + pkt->conn->callbacks.sent_cb (pkt->conn->user_data); } + +#if defined (DEBUG) + if (what & EV_TIMEOUT) + rs_debug (("%s: timeout on UDP event, shouldn't happen\n", __func__)); +#endif } int @@ -95,7 +149,7 @@ udp_init (struct rs_connection *conn, struct rs_packet *pkt) { assert (!conn->bev); - conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn); + conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, NULL); conn->wev = event_new (conn->evb, conn->fd, EV_WRITE, _evcb, pkt); if (!conn->rev || !conn->wev) { -- cgit v1.1 From 192dd27b23f9d982a47cad3a4eb88c2fcb3ff3e0 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 9 Mar 2011 23:10:08 +0100 Subject: Change default configuration to do RadSec rather than UDP. --- lib/conf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/conf.c b/lib/conf.c index 7e27f0b..14bc3ef 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -42,15 +42,15 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) cfg_opt_t server_opts[] = { CFG_STR ("hostname", NULL, CFGF_NONE), - CFG_STR ("service", "radius", CFGF_NONE), - CFG_STR ("secret", NULL, CFGF_NONE), + CFG_STR ("service", "2083", CFGF_NONE), + CFG_STR ("secret", "radsec", 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_INT ("timeout", 2, CFGF_NONE), /* FIXME: Remove? */ + CFG_INT ("retries", 2, CFGF_NONE), /* FIXME: Remove? */ CFG_STR ("cacertfile", NULL, CFGF_NONE), /*CFG_STR ("cacertpath", NULL, CFGF_NONE),*/ CFG_STR ("certfile", NULL, CFGF_NONE), -- cgit v1.1 From 9ee2245ee1e0f7efedff61891a57a4a9b014542f Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 10 Mar 2011 00:16:59 +0100 Subject: Disable DEBUG. --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index fdaf1ec..7eb0f08 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -37,4 +37,4 @@ libradsec_la_SOURCES += \ endif libradsec_la_LDFLAGS = -version-info 0:0:0 -libradsec_la_CFLAGS = $(AM_CFLAGS) -DDEBUG -DDEBUG_LEVENT -Werror # -ansi +libradsec_la_CFLAGS = $(AM_CFLAGS) -Werror #-DDEBUG -DDEBUG_LEVENT # -ansi -- cgit v1.1 From a48992622d54c6d5dbf5abe3022cfe5b06167261 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 10 Mar 2011 00:20:25 +0100 Subject: Don't miscompile without --enable-tls. Include err.h and debug.h even w/o RS_ENABLE_TLS. --- lib/radsec.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/radsec.c b/lib/radsec.c index ec43b2f..2ae515d 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -17,15 +17,14 @@ #include #include #include +#include "err.h" +#include "debug.h" +#include "rsp_debug.h" #if defined (RS_ENABLE_TLS) #include -#include "debug.h" -#include "err.h" #include "rsp_list.h" #include "../radsecproxy.h" #endif -#include "rsp_debug.h" - /* Public functions. */ int -- cgit v1.1 From 1a1e09bd5def4fae2a499294535b37805f79fde8 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 10 Mar 2011 08:08:32 +0100 Subject: [UDP] Don't crash on second packet. [UDP] Set the user_data member for the write callback in rs_packet_send() -- the one from udp_init() doesn't do much good at this point. --- lib/send.c | 2 ++ lib/udp.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/send.c b/lib/send.c index 0872471..a8ad1d5 100644 --- a/lib/send.c +++ b/lib/send.c @@ -103,6 +103,8 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) } else /* UDP */ { + event_assign (conn->wev, conn->evb, event_get_fd (conn->wev), + EV_WRITE, event_get_callback (conn->wev), pkt); err = event_add (conn->wev, NULL); if (err < 0) return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, diff --git a/lib/udp.c b/lib/udp.c index 19968b3..911616d 100644 --- a/lib/udp.c +++ b/lib/udp.c @@ -128,6 +128,7 @@ _evcb (evutil_socket_t fd, short what, void *user_data) { struct rs_packet *pkt = (struct rs_packet *) user_data; assert (pkt); + assert (pkt->conn); if (!pkt->conn->is_connected) event_on_connect (pkt->conn, pkt); @@ -150,7 +151,7 @@ udp_init (struct rs_connection *conn, struct rs_packet *pkt) assert (!conn->bev); conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, NULL); - conn->wev = event_new (conn->evb, conn->fd, EV_WRITE, _evcb, pkt); + conn->wev = event_new (conn->evb, conn->fd, EV_WRITE, _evcb, NULL); if (!conn->rev || !conn->wev) { if (conn->rev) -- cgit v1.1 From 6d5c276000a65e35dae2f672913c767e696cb56a Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 10 Mar 2011 10:56:08 +0100 Subject: Remove -Werror since we still have some warnings in radsecproxy. --- lib/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index 7eb0f08..d4d9b78 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -37,4 +37,4 @@ libradsec_la_SOURCES += \ endif libradsec_la_LDFLAGS = -version-info 0:0:0 -libradsec_la_CFLAGS = $(AM_CFLAGS) -Werror #-DDEBUG -DDEBUG_LEVENT # -ansi +libradsec_la_CFLAGS = $(AM_CFLAGS) #-DDEBUG -DDEBUG_LEVENT #-Werror -- cgit v1.1 From 73d7353cb7a244d08fdd8b6d14e01db4b00824b7 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 11 Mar 2011 13:18:44 +0100 Subject: Handle an ENOMEM case in conf.c. --- lib/conf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/conf.c b/lib/conf.c index 14bc3ef..0f00fd8 100644 --- a/lib/conf.c +++ b/lib/conf.c @@ -89,6 +89,8 @@ rs_context_read_config(struct rs_context *ctx, const char *config_file) return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__, "missing config name"); r->name = strdup (s); + if (!r->name) + return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL); typestr = cfg_getstr (cfg_config, "type"); if (!strcmp (typestr, "UDP")) -- cgit v1.1 From 2913a6b0f4fc5d097843d8c80786b8c313fb9d30 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 11 Mar 2011 13:19:01 +0100 Subject: Do free the connection object. --- lib/conn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/conn.c b/lib/conn.c index 5382888..f737820 100644 --- a/lib/conn.c +++ b/lib/conn.c @@ -132,6 +132,8 @@ rs_conn_destroy (struct rs_connection *conn) /* TODO: free tls_ctx */ /* TODO: free tls_ssl */ + rs_free (conn->ctx, conn); + return err; } -- cgit v1.1 From c19e71100032927bf5d88ef700a5034dc3f08565 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 11 Mar 2011 13:19:39 +0100 Subject: Free the realm name which is strdup'd when config is read. --- lib/radsec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/radsec.c b/lib/radsec.c index 2ae515d..0957365 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -163,6 +163,7 @@ rs_context_destroy (struct rs_context *ctx) p = p->next; _rs_peer_destroy (tmp); } + rs_free (ctx, r->name); r = r->next; rs_free (ctx, tmp); } -- cgit v1.1 From efce8db03af505f76c0c579f2439757bd6998dc9 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sat, 12 Mar 2011 01:03:43 +0100 Subject: Fix crash bug in _rs_peer_destroy(). Don't expect a peer to always have a connection. --- lib/radsec.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/radsec.c b/lib/radsec.c index 0957365..a05a22b 100644 --- a/lib/radsec.c +++ b/lib/radsec.c @@ -131,23 +131,6 @@ rs_resolv (struct evutil_addrinfo **addr, return NULL; } -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 conn, nor realm. */ - /* NOTE: secret is owned by config */ - if (p->addr) - { - evutil_freeaddrinfo (p->addr); - p->addr = NULL; - } - rs_free (p->conn->ctx, p); -} - void rs_context_destroy (struct rs_context *ctx) { @@ -160,8 +143,10 @@ rs_context_destroy (struct rs_context *ctx) for (p = r->peers; p; ) { struct rs_peer *tmp = p; + if (p->addr) + evutil_freeaddrinfo (p->addr); p = p->next; - _rs_peer_destroy (tmp); + rs_free (ctx, tmp); } rs_free (ctx, r->name); r = r->next; -- cgit v1.1