summaryrefslogtreecommitdiff
path: root/lib/packet.c
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordberg.se>2011-02-24 22:25:22 +0100
committerLinus Nordberg <linus@nordberg.se>2011-02-24 22:25:22 +0100
commit0befcd00af0a034bc4ec4e3466d2b37b3c658cc9 (patch)
tree742871b724df82485ce01adc37391161f487d778 /lib/packet.c
parent8ebd28762a9398ac39d6bd15d69495048ec0a1a4 (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.c166
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? */