diff options
author | Linus Nordberg <linus@nordberg.se> | 2011-02-24 22:25:22 +0100 |
---|---|---|
committer | Linus Nordberg <linus@nordberg.se> | 2011-02-24 22:25:22 +0100 |
commit | 0befcd00af0a034bc4ec4e3466d2b37b3c658cc9 (patch) | |
tree | 742871b724df82485ce01adc37391161f487d778 /lib/packet.c | |
parent | 8ebd28762a9398ac39d6bd15d69495048ec0a1a4 (diff) |
Config file changes and small API changes.
'timeout' and 'tries' move from 'server' stanza to top. 'tries' is
now 'retries'.
Moving around in internal data structs, making struct peer strictly config.
Bug fixes in configuration code.
Adding some more cleanup code, freeing allocated memory (still not done!).
Diffstat (limited to 'lib/packet.c')
-rw-r--r-- | lib/packet.c | 166 |
1 files changed, 105 insertions, 61 deletions
diff --git a/lib/packet.c b/lib/packet.c index 9c6edf2..c8f4af1 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -6,6 +6,8 @@ #include <stdlib.h> #include <string.h> +#include <errno.h> +#include <sys/time.h> #include <assert.h> #include <freeradius/libradius.h> #include <event2/event.h> @@ -63,14 +65,14 @@ _do_send (struct rs_packet *pkt) if (err < 0) return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, "bufferevent_write: %s", - evutil_gai_strerror(err)); + evutil_gai_strerror (err)); return RSE_OK; } static void _on_connect (struct rs_connection *conn) { - conn->active_peer->is_connected = 1; + conn->is_connected = 1; rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); if (conn->callbacks.connected_cb) conn->callbacks.connected_cb (conn->user_data); @@ -79,7 +81,8 @@ _on_connect (struct rs_connection *conn) static void _on_disconnect (struct rs_connection *conn) { - conn->active_peer->is_connected = 0; + 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); @@ -89,11 +92,11 @@ static void _event_cb (struct bufferevent *bev, short events, void *ctx) { struct rs_packet *pkt = (struct rs_packet *)ctx; - struct rs_connection *conn; - struct rs_peer *p; - int sockerr; + struct rs_connection *conn = NULL; + struct rs_peer *p = NULL; + int sockerr = 0; #if defined (RS_ENABLE_TLS) - unsigned long tlserr; + unsigned long tlserr = 0; #endif assert (pkt); @@ -102,7 +105,7 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) conn = pkt->conn; p = conn->active_peer; - p->is_connecting = 0; + conn->is_connecting = 0; if (events & BEV_EVENT_CONNECTED) { _on_connect (conn); @@ -113,6 +116,12 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) { _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_IOTIMEOUT, __FILE__, __LINE__, NULL); + } else if (events & BEV_EVENT_ERROR) { sockerr = evutil_socket_geterror (conn->active_peer->fd); @@ -124,11 +133,12 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) { rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__, "%d: socket error %d (%s)", - conn->active_peer->fd, + conn->fd, sockerr, evutil_socket_error_to_string (sockerr)); - rs_debug (("%s: socket error on fd %d: %d\n", __func__, - conn->active_peer->fd, + 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) @@ -146,6 +156,11 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) } #endif /* RS_ENABLE_TLS */ } + +#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 @@ -308,7 +323,7 @@ _read_cb (struct bufferevent *bev, void *ctx) assert (pkt->conn); assert (pkt->rpkt); - pkt->rpkt->sockfd = pkt->conn->active_peer->fd; + pkt->rpkt->sockfd = pkt->conn->fd; pkt->rpkt->vps = NULL; if (!pkt->hdr_read_flag) @@ -348,35 +363,37 @@ _evlog_cb (int severity, const char *msg) static int _init_evb (struct rs_connection *conn) { - if (!conn->evb) - { + if (conn->evb) + return RSE_OK; + #if defined (DEBUG) - event_enable_debug_mode (); + 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"); - } + 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 (p->fd != -1) + if (conn->fd != -1) return RSE_OK; assert (p->addr); - p->fd = socket (p->addr->ai_family, p->addr->ai_socktype, - p->addr->ai_protocol); - if (p->fd < 0) + 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_SOME_ERROR, __FILE__, __LINE__, strerror (errno)); - if (evutil_make_socket_nonblocking (p->fd) < 0) + if (evutil_make_socket_nonblocking (conn->fd) < 0) { - evutil_closesocket (p->fd); + evutil_closesocket (conn->fd); + conn->fd = -1; return rs_err_conn_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__, strerror (errno)); } @@ -386,8 +403,13 @@ _init_socket (struct rs_connection *conn, struct rs_peer *p) 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; + conn->active_peer = conn->peers; /* From the top. */ + return conn->active_peer; } @@ -397,15 +419,20 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer) if (conn->bev) return RSE_OK; - switch (conn->type) + switch (conn->realm->type) { 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, peer->fd, 0); + 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: if (rs_tls_init (conn)) @@ -414,62 +441,79 @@ _init_bev (struct rs_connection *conn, struct rs_peer *peer) 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, peer->fd, conn->tls_ssl, + 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"); - break; + case RS_CONN_TYPE_DTLS: return rs_err_conn_push_fl (conn, RSE_NOSYS, __FILE__, __LINE__, "%s: NYI", __func__); #endif /* RS_ENABLE_TLS */ + default: return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__, "%s: unknown connection type: %d", __func__, - conn->type); + conn->realm->type); } return RSE_OK; } static void -_do_connect (struct rs_peer *p) +_do_connect (struct rs_connection *conn) { + struct rs_peer *p; int err; + 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 + 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)); + evutil_gai_strerror (err)); else - p->is_connecting = 1; + p->conn->is_connecting = 1; } static int _conn_open(struct rs_connection *conn, struct rs_packet *pkt) { - struct rs_peer *p; - if (_init_evb (conn)) return -1; - p = _pick_peer (conn); - if (!p) + 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, p)) + if (_init_socket (conn, conn->active_peer)) return -1; - if (_init_bev (conn, p)) + if (_init_bev (conn, conn->active_peer)) return -1; - if (!p->is_connected) - if (!p->is_connecting) - _do_connect (p); + if (!conn->is_connected) + if (!conn->is_connecting) + _do_connect (conn); return RSE_OK; } @@ -477,7 +521,7 @@ _conn_open(struct rs_connection *conn, struct rs_packet *pkt) static int _conn_is_open_p (struct rs_connection *conn) { - return conn->active_peer && conn->active_peer->is_connected; + return conn->active_peer && conn->is_connected; } /* Public functions. */ @@ -553,14 +597,14 @@ _wcb (void *user_data) if (err < 0) rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, "event_base_loopbreak: %s", - evutil_gai_strerror(err)); + evutil_gai_strerror (err)); } int rs_packet_send (struct rs_packet *pkt, void *user_data) { struct rs_connection *conn = NULL; - int err = RSE_OK; + int err = 0; assert (pkt); assert (pkt->conn); @@ -575,7 +619,7 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) assert (conn->evb); assert (conn->bev); assert (conn->active_peer); - assert (conn->active_peer->fd >= 0); + assert (conn->fd >= 0); conn->user_data = user_data; bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt); @@ -590,7 +634,7 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) if (err < 0) return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, "event_base_dispatch: %s", - evutil_gai_strerror(err)); + evutil_gai_strerror (err)); rs_debug (("%s: event loop done\n", __func__)); conn->callbacks.sent_cb = NULL; conn->user_data = NULL; @@ -613,7 +657,7 @@ _rcb (struct rs_packet *packet, void *user_data) if (err < 0) rs_err_conn_push_fl (packet->conn, RSE_EVENT, __FILE__, __LINE__, "event_base_loopbreak: %s", - evutil_gai_strerror(err)); + evutil_gai_strerror (err)); } /* Special function used in libradsec blocking dispatching mode, @@ -636,10 +680,11 @@ rs_conn_receive_packet (struct rs_connection *conn, struct rs_packet *request, struct rs_packet **pkt_out) { - int err = RSE_OK; + 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)) @@ -648,36 +693,35 @@ rs_conn_receive_packet (struct rs_connection *conn, pkt->conn = conn; pkt->original = request; - if (_conn_open (conn, pkt)) - return -1; assert (conn->evb); assert (conn->bev); assert (conn->active_peer); - assert (conn->active_peer->fd >= 0); + assert (conn->fd >= 0); - /* Install read and event callbacks with libevent. */ + /* Install callbacks with libevent. */ bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0); bufferevent_enable (conn->bev, EV_READ); bufferevent_setcb (conn->bev, _read_cb, NULL, _event_cb, pkt); - /* Install read callback with ourselves, for signaling successful - reception of message. */ + /* Install read callback with ourselves, for breaking event + loop upon reception of a valid packet. */ conn->callbacks.received_cb = _rcb; /* 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)); + evutil_gai_strerror (err)); rs_debug (("%s: event loop done\n", __func__)); - conn->callbacks.received_cb = NULL; + if (!event_base_got_break (conn->evb)) return -1; #if defined (DEBUG) - rs_dump_packet (pkt); + rs_dump_packet (pkt); #endif pkt->original = NULL; /* FIXME: Why? */ |