1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
/* Copyright 2011,2013 NORDUnet A/S. All rights reserved.
See LICENSE for licensing information. */
#if defined HAVE_CONFIG_H
#include <config.h>
#endif
#include <assert.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <radsec/radsec.h>
#include <radsec/radsec-impl.h>
#include "debug.h"
#include "packet.h"
#include "event.h"
#include "peer.h"
#include "conn.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 (tcp_init_connect_timer (conn))
return -1;
if (event_init_bufferevent (conn, conn->active_peer))
return -1;
}
else
{
if (udp_init (conn, pkt))
return -1;
if (udp_init_retransmit_timer (conn))
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->flags |= RS_PACKET_SENT;
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 */
{
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__,
"event_add: %s",
evutil_gai_strerror (err));
}
/* Do dispatch, unless the user wants to do it herself. */
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 (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->flags & RS_PACKET_SENT) == 0)
{
assert (rs_err_conn_peek_code (conn));
return rs_err_conn_peek_code (conn);
}
}
return RSE_OK;
}
|