Enable tls psk
[radsecproxy.git] / udp.c
1 /* Copyright 2011 NORDUnet A/S. All rights reserved.
2    See LICENSE for licensing information. */
3
4 #if defined HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include <assert.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <event2/event.h>
12 #include <radius/client.h>
13 #include <radsec/radsec.h>
14 #include <radsec/radsec-impl.h>
15 #include "debug.h"
16 #include "event.h"
17 #include "compat.h"
18 #include "udp.h"
19
20 /* Send one packet, the first in queue.  */
21 static int
22 _send (struct rs_connection *conn, int fd)
23 {
24   ssize_t r = 0;
25   struct rs_packet *pkt = conn->out_queue;
26
27   assert (pkt->rpkt);
28   assert (pkt->rpkt->data);
29
30   /* Send.  */
31   r = compat_send (fd, pkt->rpkt->data, pkt->rpkt->length, 0);
32   if (r == -1)
33     {
34       int sockerr = evutil_socket_geterror (pkt->conn->fd);
35       if (sockerr != EAGAIN)
36         return rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__,
37                                     "%d: send: %d (%s)", fd, sockerr,
38                                     evutil_socket_error_to_string (sockerr));
39     }
40
41   assert (r == pkt->rpkt->length);
42   /* Unlink the packet.  */
43   conn->out_queue = pkt->next;
44
45   /* If there are more packets in queue, add the write event again.  */
46   if (pkt->conn->out_queue)
47     {
48       r = event_add (pkt->conn->wev, NULL);
49       if (r < 0)
50         return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
51                                     "event_add: %s", evutil_gai_strerror (r));
52       rs_debug (("%s: re-adding the write event\n", __func__));
53     }
54
55   return RSE_OK;
56 }
57
58 /* Callback for conn->wev and conn->rev.  FIXME: Rename.
59
60    USER_DATA contains connection for EV_READ and a packet for
61    EV_WRITE.  This is because we don't have a connect/establish entry
62    point at the user level -- send implies connect so when we're
63    connected we need the packet to send.  */
64 static void
65 _evcb (evutil_socket_t fd, short what, void *user_data)
66 {
67   int err;
68   struct rs_packet *pkt = (struct rs_packet *) user_data;
69
70   rs_debug (("%s: fd=%d what =", __func__, fd));
71   if (what & EV_TIMEOUT) rs_debug ((" TIMEOUT -- shouldn't happen!"));
72   if (what & EV_READ) rs_debug ((" READ"));
73   if (what & EV_WRITE) rs_debug ((" WRITE"));
74   rs_debug (("\n"));
75
76   assert (pkt);
77   assert (pkt->conn);
78   if (what & EV_READ)
79     {
80       /* Read a single UDP packet and stick it in USER_DATA.  */
81       /* TODO: Verify that unsolicited packets are dropped.  */
82       ssize_t r = 0;
83
84       assert (pkt->rpkt->data);
85
86       r = compat_recv (fd, pkt->rpkt->data, RS_MAX_PACKET_LEN, MSG_TRUNC);
87       if (r == -1)
88         {
89           int sockerr = evutil_socket_geterror (pkt->conn->fd);
90           if (sockerr == EAGAIN)
91             {
92               /* FIXME: Really shouldn't happen since we've been told
93                  that fd is readable!  */
94               rs_debug (("%s: EAGAIN reading UDP packet -- wot?\n"));
95               goto err_out;
96             }
97
98           /* Hard error.  */
99           rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__,
100                                "%d: recv: %d (%s)", fd, sockerr,
101                                evutil_socket_error_to_string (sockerr));
102           event_del (pkt->conn->tev);
103           goto err_out;
104         }
105       event_del (pkt->conn->tev);
106       if (r < 20 || r > RS_MAX_PACKET_LEN)      /* Short or long packet.  */
107         {
108           rs_err_conn_push (pkt->conn, RSE_INVALID_PKT,
109                             "invalid packet length: %d", r);
110           goto err_out;
111         }
112       pkt->rpkt->length = (pkt->rpkt->data[2] << 8) + pkt->rpkt->data[3];
113       err = nr_packet_ok (pkt->rpkt);
114       if (err)
115         {
116           rs_err_conn_push_fl (pkt->conn, -err, __FILE__, __LINE__,
117                                "invalid packet");
118           goto err_out;
119         }
120       /* Hand over message to user.  This changes ownership of pkt.
121          Don't touch it afterwards -- it might have been freed.  */
122       if (pkt->conn->callbacks.received_cb)
123         pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data);
124       else
125         rs_debug (("%s: no received-callback -- dropping packet\n", __func__));
126     }
127   else if (what & EV_WRITE)
128     {
129       if (!pkt->conn->is_connected)
130         event_on_connect (pkt->conn, pkt);
131
132       if (pkt->conn->out_queue)
133         if (_send (pkt->conn, fd) == RSE_OK)
134           if (pkt->conn->callbacks.sent_cb)
135             pkt->conn->callbacks.sent_cb (pkt->conn->user_data);
136     }
137   return;
138
139  err_out:
140   rs_conn_disconnect (pkt->conn);
141 }
142
143 int
144 udp_init (struct rs_connection *conn, struct rs_packet *pkt)
145 {
146   assert (!conn->bev);
147
148   conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, NULL);
149   conn->wev = event_new (conn->evb, conn->fd, EV_WRITE, _evcb, NULL);
150   if (!conn->rev || !conn->wev)
151     {
152       if (conn->rev)
153         {
154           event_free (conn->rev);
155           conn->rev = NULL;
156         }
157       /* ENOMEM _or_ EINVAL but EINVAL only if we use EV_SIGNAL, at
158          least for now (libevent-2.0.5).  */
159       return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
160     }
161   return RSE_OK;
162 }
163
164 int
165 udp_init_retransmit_timer (struct rs_connection *conn)
166 {
167   assert (conn);
168
169   if (conn->tev)
170     event_free (conn->tev);
171   conn->tev = evtimer_new (conn->evb, event_retransmit_timeout_cb, conn);
172   if (!conn->tev)
173     return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
174                                 "evtimer_new");
175
176   return RSE_OK;
177 }