Alphabetise radsec.sym.
[libradsec.git] / lib / event.c
1 /* Copyright 2011-2013 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 <string.h>
10 #include <errno.h>
11
12 #include <event2/event.h>
13 #include <event2/listener.h>
14 #include <event2/bufferevent.h>
15 #if defined (RS_ENABLE_TLS)
16 #include <event2/bufferevent_ssl.h>
17 #include <openssl/err.h>
18 #endif
19 #include <radsec/radsec.h>
20 #include <radsec/radsec-impl.h>
21 #include "tcp.h"
22 #include "udp.h"
23 #if defined (RS_ENABLE_TLS)
24 #include "tls.h"
25 #endif
26 #include "err.h"
27 #include "radsec.h"
28 #include "event.h"
29 #include "message.h"
30 #include "conn.h"
31 #include "listener.h"
32 #include "debug.h"
33
34 #if defined (DEBUG)
35 extern int _event_debug_mode_on;
36 #endif
37
38 static void
39 _evlog_cb (int severity, const char *msg)
40 {
41   const char *sevstr;
42   switch (severity)
43     {
44     case _EVENT_LOG_DEBUG:
45 #if !defined (DEBUG_LEVENT)
46       return;
47 #endif
48       sevstr = "debug";
49       break;
50     case _EVENT_LOG_MSG:
51       sevstr = "msg";
52       break;
53     case _EVENT_LOG_WARN:
54       sevstr = "warn";
55       break;
56     case _EVENT_LOG_ERR:
57       sevstr = "err";
58       break;
59     default:
60       sevstr = "???";
61       break;
62     }
63   fprintf (stderr, "libevent: [%s] %s\n", sevstr, msg); /* FIXME: stderr?  */
64 }
65
66 void
67 event_conn_timeout_cb (int fd, short event, void *data)
68 {
69   struct rs_connection *conn = NULL;
70
71   assert (data);
72   conn = (struct rs_connection *) data;
73
74   if (event & EV_TIMEOUT)
75     {
76       rs_debug (("%s: connection timeout on %p (fd %d) connecting to %p\n",
77                  __func__, conn, conn->base_.fd, conn->active_peer));
78       conn->state = RS_CONN_STATE_UNDEFINED;
79       rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL);
80       event_loopbreak (conn);
81     }
82 }
83
84 void
85 event_retransmit_timeout_cb (int fd, short event, void *data)
86 {
87   struct rs_connection *conn = NULL;
88
89   assert (data);
90   conn = (struct rs_connection *) data;
91
92   if (event & EV_TIMEOUT)
93     {
94       rs_debug (("%s: retransmission timeout on %p (fd %d) sending to %p\n",
95                  __func__, conn, conn->base_.fd, conn->active_peer));
96       rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);
97       event_loopbreak (conn);
98     }
99 }
100
101 /* FIXME: event_ is actually not such a great prefix given that we
102    link with libevent which exports 113 symbols prefixed 'event_'. */
103 int
104 event_init_socket (struct rs_conn_base *connbase, struct rs_peer *p)
105 {
106   if (connbase->fd != -1)
107     return RSE_OK;
108
109   assert (p);
110   assert (p->realm);
111
112   /* Resolve potential DNS name for peer. */
113   if (p->addr_cache == NULL)
114     {
115       struct rs_error *err =
116         rs_resolve (&p->addr_cache, p->realm->type, p->hostname, p->service);
117       if (err != NULL)
118         return err_connbase_push_err (connbase, err);
119     }
120
121   /* Create the socket and make it non-blocking. */
122   connbase->fd = socket (p->addr_cache->ai_family,
123                          p->addr_cache->ai_socktype,
124                          p->addr_cache->ai_protocol);
125   if (connbase->fd < 0)
126     return rs_err_connbase_push_fl (connbase, RSE_SOCKERR, __FILE__, __LINE__,
127                                     "socket: %d (%s)",
128                                     errno, strerror (errno));
129   if (evutil_make_socket_nonblocking (connbase->fd) < 0)
130     {
131       evutil_closesocket (connbase->fd);
132       connbase->fd = -1;
133       return rs_err_connbase_push_fl (connbase, RSE_SOCKERR, __FILE__, __LINE__,
134                                       "evutil_make_socket_nonblocking: %d (%s)",
135                                       errno, strerror (errno));
136     }
137
138   /* If we're inititalising the socket for a listener, bind to the
139      peer address. */
140   if (connbase->magic == RS_CONN_MAGIC_LISTENER)
141     {
142       assert (p->realm->type == connbase->transport);
143       if (p->realm->type == RS_CONN_TYPE_TLS
144           || p->realm->type == RS_CONN_TYPE_TCP)
145         {
146           struct rs_listener *listener = TO_LISTENER_CONN (connbase);
147           listener->evlistener =
148             evconnlistener_new_bind (listener->base_.ctx->evb,
149                                      listener_accept_cb_,
150                                      listener, LEV_OPT_REUSEABLE,
151                                      LISTENER_BACKLOG,
152                                      p->addr_cache->ai_addr,
153                                      p->addr_cache->ai_addrlen);
154           if (listener->evlistener == NULL)
155             return rs_err_connbase_push (connbase, RSE_EVENT,
156                                          "evconnlistener_new_bind: %d (%s)",
157                                          errno, strerror (errno));
158
159           evconnlistener_set_error_cb (listener->evlistener, listener_err_cb_);
160         }
161       else
162         {
163           return rs_err_connbase_push_fl (connbase, RSE_NOSYS,
164                                           __FILE__, __LINE__, NULL);
165         }
166     }
167
168   return RSE_OK;
169 }
170
171 int
172 event_init_bufferevent (struct rs_connection *conn)
173 {
174   struct rs_conn_base *connbase = NULL;
175   assert (conn);
176   connbase = TO_BASE_CONN(conn);
177
178   if (connbase->bev)
179     return RSE_OK;
180
181   if (connbase->transport == RS_CONN_TYPE_TCP)
182     {
183       connbase->bev = bufferevent_socket_new (connbase->ctx->evb,
184                                               connbase->fd, 0);
185       if (!connbase->bev)
186         return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
187                                     "bufferevent_socket_new");
188     }
189 #if defined (RS_ENABLE_TLS)
190   else if (connbase->transport == RS_CONN_TYPE_TLS)
191     {
192       enum bufferevent_ssl_state bev_ssl_state;
193
194       if (rs_tls_init (conn))
195         return -1;
196       bev_ssl_state = conn_originating_p (conn)
197         ? BUFFEREVENT_SSL_CONNECTING : BUFFEREVENT_SSL_ACCEPTING;
198
199       /* It would be convenient to pass BEV_OPT_CLOSE_ON_FREE in last
200          argument (options) but things seem to break when
201          be_openssl_ctrl() (in libevent) calls SSL_set_bio() after
202          BIO_new_socket() with flag=1. */
203       connbase->bev =
204         bufferevent_openssl_socket_new (connbase->ctx->evb, connbase->fd,
205                                         conn->tls_ssl, bev_ssl_state, 0);
206       if (!connbase->bev)
207         return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
208                                     "bufferevent_openssl_socket_new");
209     }
210 #endif  /* RS_ENABLE_TLS */
211   else
212     {
213       return rs_err_conn_push_fl (conn, RSE_INTERNAL, __FILE__, __LINE__,
214                                   "%s: unknown connection type: %d", __func__,
215                                   connbase->transport);
216     }
217
218   return RSE_OK;
219 }
220
221 void
222 event_do_connect (struct rs_connection *conn)
223 {
224   int err, sockerr;
225   struct sockaddr *peer_addr;
226   size_t peer_addrlen;
227
228   assert (conn);
229   assert (conn->active_peer);
230   assert (conn->active_peer->addr_cache);
231   peer_addr = conn->active_peer->addr_cache->ai_addr;
232   peer_addrlen = conn->active_peer->addr_cache->ai_addrlen;
233
234   /* We don't connect listeners. */
235   assert (conn->base_.magic == RS_CONN_MAGIC_GENERIC);
236
237 #if defined (DEBUG)
238   {
239     char host[80], serv[80];
240
241     getnameinfo (peer_addr, peer_addrlen,
242                  host, sizeof(host),
243                  serv, sizeof(serv),
244                  0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
245     rs_debug (("%s: connecting to %s:%s\n", __func__, host, serv));
246   }
247 #endif
248
249   if (conn->base_.bev)          /* TCP */
250     {
251       conn_activate_timeout (conn); /* Connect timeout.  */
252       err = bufferevent_socket_connect (conn->base_.bev,
253                                         peer_addr, peer_addrlen);
254       if (err < 0)
255         rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
256                              "bufferevent_socket_connect: %s",
257                              evutil_gai_strerror (err));
258       else
259         conn->state = RS_CONN_STATE_CONNECTING;
260     }
261   else                          /* UDP */
262     {
263       err = connect (conn->base_.fd, peer_addr, peer_addrlen);
264       if (err < 0)
265         {
266           sockerr = evutil_socket_geterror (conn->base_.fd);
267           rs_debug (("%s: %d: connect: %d (%s)\n", __func__,
268                      conn->base_.fd,
269                      sockerr, evutil_socket_error_to_string (sockerr)));
270           rs_err_conn_push (conn, RSE_SOCKERR,
271                             "%d: connect: %d (%s)", conn->base_.fd,
272                             sockerr, evutil_socket_error_to_string (sockerr));
273         }
274       else
275         conn->state = RS_CONN_STATE_CONNECTING;
276     }
277 }
278
279 int
280 event_loopbreak (struct rs_connection *conn)
281 {
282   int err = event_base_loopbreak (TO_BASE_CONN(conn)->ctx->evb);
283   if (err < 0)
284     rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
285                          "event_base_loopbreak: %s",
286                          evutil_gai_strerror (err)); /* FIXME: really gai_strerror? */
287   return err;
288 }
289
290
291 void
292 event_on_disconnect (struct rs_connection *conn)
293 {
294   conn->state = RS_CONN_STATE_UNDEFINED;
295   rs_debug (("%s: %p disconnected\n", __func__, conn->active_peer));
296   if (conn->callbacks.disconnected_cb)
297     conn->callbacks.disconnected_cb (conn->base_.user_data);
298 }
299
300 /** Internal connect event for originating connections. Returns 0 on
301     success and -1 on TLS certificate verification failure.  */
302 int
303 event_on_connect_orig (struct rs_connection *conn, struct rs_message *msg)
304 {
305   assert (conn->state == RS_CONN_STATE_CONNECTING);
306   assert (conn->active_peer);
307
308 #if defined (RS_ENABLE_TLS)
309   if (conn_type_tls_p (conn) && !conn_cred_psk (conn))
310     if (tls_verify_cert (conn) != RSE_OK)
311       {
312         rs_debug (("%s: server cert verification failed\n", __func__));
313         return -1;
314       }
315 #endif  /* RS_ENABLE_TLS */
316
317   conn->state = RS_CONN_STATE_CONNECTED;
318   rs_debug (("%s: %p connected\n", __func__, conn->active_peer));
319
320   if (conn->callbacks.connected_cb)
321     conn->callbacks.connected_cb (conn->base_.user_data);
322
323   if (msg)
324     message_do_send (msg);
325
326   return 0;
327 }
328
329 /** FIXME: DOC */
330 int
331 event_on_connect_term (struct rs_connection *conn, struct rs_message *msg)
332 {
333   /* TODO: verify client */
334   conn->state = RS_CONN_STATE_CONNECTED;
335   rs_debug (("%s: WARNING: not checking client cert!!!\n", __func__));
336   if (conn->callbacks.connected_cb)
337     conn->callbacks.connected_cb (conn->base_.user_data);
338   return 0;
339 }
340
341 int
342 event_init_eventbase (struct rs_conn_base *connbase)
343 {
344   assert (connbase);
345   assert (connbase->ctx);
346   if (connbase->ctx->evb)
347     return RSE_OK;
348
349 #if defined (DEBUG)
350   if (!_event_debug_mode_on)
351     event_enable_debug_mode ();
352 #endif
353   event_set_log_callback (_evlog_cb);
354   connbase->ctx->evb = event_base_new ();
355   if (!connbase->ctx->evb)
356     return rs_err_connbase_push_fl (connbase, RSE_EVENT, __FILE__, __LINE__,
357                                     "event_base_new");
358
359   return RSE_OK;
360 }