c602cbdb4d8c4fc90201d7c1e45d5d8544139923
[radsecproxy.git] / lib / udp.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 <radsec/radsec.h>
11 #include <radsec/radsec-impl.h>
12 #include "debug.h"
13 #include "event.h"
14 #include "compat.h"
15 #include "udp.h"
16
17 /* Send one packet, the first in queue.  */
18 static void
19 _send (struct rs_connection *conn, int fd)
20 {
21   ssize_t r = 0;
22   struct rs_packet *pkt = conn->out_queue;
23
24   assert (pkt->rpkt);
25   assert (pkt->rpkt->data);
26
27   /* Send.  */
28   r = compat_send (fd, pkt->rpkt->data, pkt->rpkt->data_len, 0);
29   if (r == -1)
30     {
31       int sockerr = evutil_socket_geterror (pkt->conn->fd);
32       if (sockerr != EAGAIN)
33         rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__,
34                              "%d: send: %d (%s)", fd, sockerr,
35                              evutil_socket_error_to_string (sockerr));
36       return;           /* Don't unlink packet. */
37     }
38
39   /* Unlink the packet.  */
40   conn->out_queue = pkt->next;
41
42   /* If there are more packets in queue, add the write event again.  */
43   if (pkt->conn->out_queue)
44     {
45       r = event_add (pkt->conn->wev, NULL);
46       if (r < 0)
47         {
48           rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
49                                "event_add: %s", evutil_gai_strerror (r));
50           return;
51         }
52     }
53 }
54
55 /* Callback for conn->wev and conn->rev.  FIXME: Rename.  */
56 static void
57 _evcb (evutil_socket_t fd, short what, void *user_data)
58 {
59   //rs_debug (("%s: fd=%d what=0x%x\n", __func__, fd, what));
60   if (what & EV_TIMEOUT)
61     {
62       struct rs_connection *conn = (struct rs_connection *) user_data;
63       assert (conn);
64       conn->is_connecting = 0;
65       rs_debug (("%s: UDP timeout NYI", __func__));
66     }
67   else if (what & EV_READ)
68     {
69       struct rs_connection *conn = (struct rs_connection *) user_data;
70       assert (conn);
71       /* read a single UDP packet and stick it in a new struct
72          rs_packet */
73
74       /* TODO: Verify that reception of an unsolicited response packet
75          results in connection being closed.  */
76       rs_debug (("%s: UDP read NYI", __func__));
77
78       /* TODO: delete retransmit timer */
79     }
80   else if (what & EV_WRITE)
81     {
82       struct rs_packet *pkt = (struct rs_packet *) user_data;
83       assert (pkt);
84
85       if (!pkt->conn->is_connected)
86         event_on_connect (pkt->conn, pkt);
87
88       if (pkt->conn->out_queue)
89         _send (pkt->conn, fd);
90     }
91 }
92
93 int
94 udp_init (struct rs_connection *conn, struct rs_packet *pkt)
95 {
96   assert (!conn->bev);
97
98   conn->rev = event_new (conn->evb, conn->fd, EV_READ|EV_PERSIST, _evcb, conn);
99   conn->wev = event_new (conn->evb, conn->fd, EV_WRITE, _evcb, pkt);
100   if (!conn->rev || !conn->wev)
101     {
102       if (conn->rev)
103         event_free (conn->rev);
104       /* ENOMEM _or_ EINVAL but EINVAL only if we use EV_SIGNAL, at
105          least for now (libevent-2.0.5).  */
106       return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
107     }
108   return RSE_OK;
109 }