1 /* Copyright 2011-2013 NORDUnet A/S. All rights reserved.
2 See LICENSE for licensing information. */
4 #if defined HAVE_CONFIG_H
9 #include <event2/event.h>
10 #include <event2/bufferevent.h>
11 #if defined (RS_ENABLE_TLS)
12 #include <event2/bufferevent_ssl.h>
13 #include <openssl/err.h>
15 #include <radius/client.h>
16 #include <radsec/radsec.h>
17 #include <radsec/radsec-impl.h>
25 #include <event2/buffer.h>
28 /** Read one RADIUS packet header. Return !0 on error. */
30 _read_header (struct rs_packet *pkt)
34 n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN);
35 if (n == RS_HEADER_LEN)
37 pkt->flags |= RS_PACKET_HEADER_READ;
38 pkt->rpkt->length = (pkt->hdr[2] << 8) + pkt->hdr[3];
39 if (pkt->rpkt->length < 20 || pkt->rpkt->length > RS_MAX_PACKET_LEN)
41 rs_debug (("%s: invalid packet length: %d\n",
42 __func__, pkt->rpkt->length));
43 rs_conn_disconnect (pkt->conn);
44 return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT,
45 "invalid packet length: %d",
48 memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN);
49 bufferevent_setwatermark (pkt->conn->bev, EV_READ,
50 pkt->rpkt->length - RS_HEADER_LEN, 0);
51 rs_debug (("%s: packet header read, total pkt len=%d\n",
52 __func__, pkt->rpkt->length));
56 rs_debug (("%s: buffer frozen while reading header\n", __func__));
58 else /* Error: libevent gave us less than the low watermark. */
60 rs_debug (("%s: got: %d octets reading header\n", __func__, n));
61 rs_conn_disconnect (pkg->conn);
62 return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__,
63 "got %d octets reading header", n);
69 /** Read a message, check that it's valid RADIUS and hand it off to
70 registered user callback.
72 The packet is read from the bufferevent associated with \a pkt and
73 the data is stored in \a pkt->rpkt.
75 Return 0 on success and !0 on failure. */
77 _read_packet (struct rs_packet *pkt)
82 rs_debug (("%s: trying to read %d octets of packet data\n", __func__,
83 pkt->rpkt->length - RS_HEADER_LEN));
85 n = bufferevent_read (pkt->conn->bev,
86 pkt->rpkt->data + RS_HEADER_LEN,
87 pkt->rpkt->length - RS_HEADER_LEN);
89 rs_debug (("%s: read %ld octets of packet data\n", __func__, n));
91 if (n == pkt->rpkt->length - RS_HEADER_LEN)
93 bufferevent_disable (pkt->conn->bev, EV_READ);
94 rs_debug (("%s: complete packet read\n", __func__));
95 pkt->flags &= ~RS_PACKET_HEADER_READ;
96 memset (pkt->hdr, 0, sizeof(*pkt->hdr));
98 /* Checks done by rad_packet_ok:
99 - lenghts (FIXME: checks really ok for tcp?)
101 - attribute lengths >= 2
102 - attribute sizes adding up correctly */
103 err = nr_packet_ok (pkt->rpkt);
106 rs_debug (("%s: %d: invalid packet\n", __func__, -err));
107 rs_conn_disconnect (pkt->conn);
108 return rs_err_conn_push_fl (pkt->conn, -err, __FILE__, __LINE__,
113 /* Find out what happens if there's data left in the buffer. */
116 rest = evbuffer_get_length (bufferevent_get_input (pkt->conn->bev));
118 rs_debug (("%s: returning with %d octets left in buffer\n", __func__,
123 /* Hand over message to user. This changes ownership of pkt.
124 Don't touch it afterwards -- it might have been freed. */
125 if (pkt->conn->callbacks.received_cb)
126 pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data);
128 else if (n < 0) /* Buffer frozen. */
129 rs_debug (("%s: buffer frozen when reading packet\n", __func__));
130 else /* Short packet. */
131 rs_debug (("%s: waiting for another %d octets\n", __func__,
132 pkt->rpkt->length - RS_HEADER_LEN - n));
137 /* The read callback for TCP.
139 Read exactly one RADIUS message from BEV and store it in struct
140 rs_packet passed in USER_DATA.
142 Inform upper layer about successful reception of received RADIUS
143 message by invoking conn->callbacks.recevied_cb(), if !NULL. */
145 tcp_read_cb (struct bufferevent *bev, void *user_data)
147 struct rs_packet *pkt = (struct rs_packet *) user_data;
153 pkt->rpkt->sockfd = pkt->conn->fd;
154 pkt->rpkt->vps = NULL; /* FIXME: can this be done when initializing pkt? */
156 /* Read a message header if not already read, return if that
157 fails. Read a message and have it dispatched to the user
160 Room for improvement: Peek inside buffer (evbuffer_copyout()) to
161 avoid the extra copying. */
162 if ((pkt->flags & RS_PACKET_HEADER_READ) == 0)
163 if (_read_header (pkt))
169 tcp_event_cb (struct bufferevent *bev, short events, void *user_data)
171 struct rs_packet *pkt = (struct rs_packet *) user_data;
172 struct rs_connection *conn = NULL;
174 #if defined (RS_ENABLE_TLS)
175 unsigned long tlserr = 0;
178 struct rs_peer *p = NULL;
185 assert (pkt->conn->active_peer);
186 p = conn->active_peer;
189 conn->is_connecting = 0;
190 if (events & BEV_EVENT_CONNECTED)
193 evtimer_del (conn->tev); /* Cancel connect timer. */
194 if (event_on_connect (conn, pkt))
196 event_on_disconnect (conn);
197 event_loopbreak (conn);
200 else if (events & BEV_EVENT_EOF)
202 event_on_disconnect (conn);
204 else if (events & BEV_EVENT_TIMEOUT)
206 rs_debug (("%s: %p times out on %s\n", __func__, p,
207 (events & BEV_EVENT_READING) ? "read" : "write"));
208 rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);
210 else if (events & BEV_EVENT_ERROR)
212 sockerr = evutil_socket_geterror (conn->active_peer->fd);
213 if (sockerr == 0) /* FIXME: True that errno == 0 means closed? */
215 event_on_disconnect (conn);
216 rs_err_conn_push_fl (conn, RSE_DISCO, __FILE__, __LINE__, NULL);
220 rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr,
221 evutil_socket_error_to_string (sockerr)));
222 rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__,
223 "%d: %d (%s)", conn->fd, sockerr,
224 evutil_socket_error_to_string (sockerr));
226 #if defined (RS_ENABLE_TLS)
227 if (conn->tls_ssl) /* FIXME: correct check? */
229 for (tlserr = bufferevent_get_openssl_error (conn->bev);
231 tlserr = bufferevent_get_openssl_error (conn->bev))
233 rs_debug (("%s: openssl error: %s\n", __func__,
234 ERR_error_string (tlserr, NULL)));
235 rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
236 ERR_error_string (tlserr, NULL));
239 #endif /* RS_ENABLE_TLS */
240 event_loopbreak (conn);
244 if (events & BEV_EVENT_ERROR && events != BEV_EVENT_ERROR)
245 rs_debug (("%s: BEV_EVENT_ERROR and more: 0x%x\n", __func__, events));
250 tcp_write_cb (struct bufferevent *bev, void *ctx)
252 struct rs_packet *pkt = (struct rs_packet *) ctx;
257 if (pkt->conn->callbacks.sent_cb)
258 pkt->conn->callbacks.sent_cb (pkt->conn->user_data);
262 tcp_init_connect_timer (struct rs_connection *conn)
267 event_free (conn->tev);
268 conn->tev = evtimer_new (conn->evb, event_conn_timeout_cb, conn);
270 return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,