c49eaa97a0d3872a7e2b286d9270401574a6c34c
[radsecproxy.git] / lib / send.c
1 /* Copyright 2011 NORDUnet A/S. All rights reserved.
2    See the file COPYING for licensing information.  */
3
4 #if defined HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include <assert.h>
9 #include <event2/event.h>
10 #include <event2/bufferevent.h>
11 #include <radsec/radsec.h>
12 #include <radsec/radsec-impl.h>
13 #include "debug.h"
14 #include "packet.h"
15 #include "event.h"
16 #include "peer.h"
17 #include "tcp.h"
18 #include "udp.h"
19
20 static int
21 _conn_open (struct rs_connection *conn, struct rs_packet *pkt)
22 {
23   if (event_init_eventbase (conn))
24     return -1;
25
26   if (!conn->active_peer)
27     peer_pick_peer (conn);
28   if (!conn->active_peer)
29     return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
30
31   if (event_init_socket (conn, conn->active_peer))
32     return -1;
33
34   if (conn->realm->type == RS_CONN_TYPE_TCP
35       || conn->realm->type == RS_CONN_TYPE_TLS)
36     {
37       if (event_init_bufferevent (conn, conn->active_peer))
38         return -1;
39     }
40   else
41     {
42       if (udp_init (conn, pkt))
43         return -1;
44     }
45
46   if (!conn->is_connected)
47     if (!conn->is_connecting)
48       event_do_connect (conn);
49
50   return RSE_OK;
51 }
52
53 static int
54 _conn_is_open_p (struct rs_connection *conn)
55 {
56   return conn->active_peer && conn->is_connected;
57 }
58
59 /* User callback used when we're dispatching for user.  */
60 static void
61 _wcb (void *user_data)
62 {
63   struct rs_packet *pkt = (struct rs_packet *) user_data;
64   assert (pkt);
65   pkt->written_flag = 1;
66   if (pkt->conn->bev)
67     bufferevent_disable (pkt->conn->bev, EV_WRITE|EV_READ);
68   else
69     event_del (pkt->conn->wev);
70 }
71
72 int
73 rs_packet_send (struct rs_packet *pkt, void *user_data)
74 {
75   struct rs_connection *conn = NULL;
76   int err = 0;
77
78   assert (pkt);
79   assert (pkt->conn);
80   conn = pkt->conn;
81
82   if (_conn_is_open_p (conn))
83     packet_do_send (pkt);
84   else
85     if (_conn_open (conn, pkt))
86       return -1;
87
88   assert (conn->evb);
89   assert (conn->active_peer);
90   assert (conn->fd >= 0);
91
92   conn->user_data = user_data;
93
94   if (conn->bev)                /* TCP */
95     {
96       bufferevent_setcb (conn->bev, NULL, tcp_write_cb, tcp_event_cb, pkt);
97       bufferevent_enable (conn->bev, EV_WRITE);
98     }
99   else                  /* UDP */
100     {
101       err = event_add (conn->wev, NULL);
102       if (err < 0)
103         return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
104                                     "event_add: %s",
105                                     evutil_gai_strerror (err));
106     }
107
108   /* Do dispatch, unless the user wants to do it herself.  */
109   if (!conn->user_dispatch_flag)
110     {
111       conn->callbacks.sent_cb = _wcb;
112       conn->user_data = pkt;
113       rs_debug (("%s: entering event loop\n", __func__));
114       err = event_base_dispatch (conn->evb);
115       if (err < 0)
116         return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
117                                     "event_base_dispatch: %s",
118                                     evutil_gai_strerror (err));
119       rs_debug (("%s: event loop done\n", __func__));
120       conn->callbacks.sent_cb = NULL;
121       conn->user_data = NULL;
122
123       if (!pkt->written_flag)
124         return -1;
125     }
126
127   return RSE_OK;
128 }