1 /* Copyright 2011 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 conn_close (&pkt->conn);
42 return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT,
43 "invalid packet length: %d",
46 memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN);
47 bufferevent_setwatermark (pkt->conn->bev, EV_READ,
48 pkt->rpkt->length - RS_HEADER_LEN, 0);
49 rs_debug (("%s: packet header read, total pkt len=%d\n",
50 __func__, pkt->rpkt->length));
54 rs_debug (("%s: buffer frozen while reading header\n", __func__));
56 else /* Error: libevent gave us less than the low watermark. */
58 conn_close (&pkt->conn);
59 return rs_err_conn_push_fl (pkt->conn, RSE_INTERNAL, __FILE__, __LINE__,
60 "got %d octets reading header", n);
66 /** Read a message, check that it's valid RADIUS and hand it off to
67 registered user callback.
69 The packet is read from the bufferevent associated with \a pkt and
70 the data is stored in \a pkt->rpkt.
72 Return 0 on success and !0 on failure. */
74 _read_packet (struct rs_packet *pkt)
79 rs_debug (("%s: trying to read %d octets of packet data\n", __func__,
80 pkt->rpkt->length - RS_HEADER_LEN));
82 n = bufferevent_read (pkt->conn->bev,
83 pkt->rpkt->data + RS_HEADER_LEN,
84 pkt->rpkt->length - RS_HEADER_LEN);
86 rs_debug (("%s: read %ld octets of packet data\n", __func__, n));
88 if (n == pkt->rpkt->length - RS_HEADER_LEN)
90 bufferevent_disable (pkt->conn->bev, EV_READ);
91 rs_debug (("%s: complete packet read\n", __func__));
92 pkt->flags &= ~RS_PACKET_HEADER_READ;
93 memset (pkt->hdr, 0, sizeof(*pkt->hdr));
95 /* Checks done by rad_packet_ok:
96 - lenghts (FIXME: checks really ok for tcp?)
98 - attribute lengths >= 2
99 - attribute sizes adding up correctly */
100 err = nr_packet_ok (pkt->rpkt);
103 conn_close (&pkt->conn);
104 return rs_err_conn_push_fl (pkt->conn, err, __FILE__, __LINE__,
109 /* Find out what happens if there's data left in the buffer. */
112 rest = evbuffer_get_length (bufferevent_get_input (pkt->conn->bev));
114 rs_debug (("%s: returning with %d octets left in buffer\n", __func__,
119 /* Hand over message to user. This changes ownership of pkt.
120 Don't touch it afterwards -- it might have been freed. */
121 if (pkt->conn->callbacks.received_cb)
122 pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data);
124 else if (n < 0) /* Buffer frozen. */
125 rs_debug (("%s: buffer frozen when reading packet\n", __func__));
126 else /* Short packet. */
127 rs_debug (("%s: waiting for another %d octets\n", __func__,
128 pkt->rpkt->length - RS_HEADER_LEN - n));
133 /* The read callback for TCP.
135 Read exactly one RADIUS message from BEV and store it in struct
136 rs_packet passed in USER_DATA.
138 Inform upper layer about successful reception of received RADIUS
139 message by invoking conn->callbacks.recevied_cb(), if !NULL. */
141 tcp_read_cb (struct bufferevent *bev, void *user_data)
143 struct rs_packet *pkt = (struct rs_packet *) user_data;
149 pkt->rpkt->sockfd = pkt->conn->fd;
150 pkt->rpkt->vps = NULL; /* FIXME: can this be done when initializing pkt? */
152 /* Read a message header if not already read, return if that
153 fails. Read a message and have it dispatched to the user
156 Room for improvement: Peek inside buffer (evbuffer_copyout()) to
157 avoid the extra copying. */
158 if ((pkt->flags & RS_PACKET_HEADER_READ) == 0)
159 if (_read_header (pkt))
165 tcp_event_cb (struct bufferevent *bev, short events, void *user_data)
167 struct rs_packet *pkt = (struct rs_packet *) user_data;
168 struct rs_connection *conn = NULL;
170 #if defined (RS_ENABLE_TLS)
171 unsigned long tlserr = 0;
174 struct rs_peer *p = NULL;
181 assert (pkt->conn->active_peer);
182 p = conn->active_peer;
185 conn->is_connecting = 0;
186 if (events & BEV_EVENT_CONNECTED)
189 evtimer_del (conn->tev); /* Cancel connect timer. */
190 if (event_on_connect (conn, pkt))
192 event_on_disconnect (conn);
193 event_loopbreak (conn);
196 else if (events & BEV_EVENT_EOF)
198 event_on_disconnect (conn);
200 else if (events & BEV_EVENT_TIMEOUT)
202 rs_debug (("%s: %p times out on %s\n", __func__, p,
203 (events & BEV_EVENT_READING) ? "read" : "write"));
204 rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);
206 else if (events & BEV_EVENT_ERROR)
208 sockerr = evutil_socket_geterror (conn->active_peer->fd);
209 if (sockerr == 0) /* FIXME: True that errno == 0 means closed? */
211 event_on_disconnect (conn);
212 rs_err_conn_push_fl (conn, RSE_DISCO, __FILE__, __LINE__, NULL);
216 rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr,
217 evutil_socket_error_to_string (sockerr)));
218 rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__,
219 "%d: %d (%s)", conn->fd, sockerr,
220 evutil_socket_error_to_string (sockerr));
222 #if defined (RS_ENABLE_TLS)
223 if (conn->tls_ssl) /* FIXME: correct check? */
225 for (tlserr = bufferevent_get_openssl_error (conn->bev);
227 tlserr = bufferevent_get_openssl_error (conn->bev))
229 rs_debug (("%s: openssl error: %s\n", __func__,
230 ERR_error_string (tlserr, NULL)));
231 rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
232 ERR_error_string (tlserr, NULL));
235 #endif /* RS_ENABLE_TLS */
236 event_loopbreak (conn);
240 if (events & BEV_EVENT_ERROR && events != BEV_EVENT_ERROR)
241 rs_debug (("%s: BEV_EVENT_ERROR and more: 0x%x\n", __func__, events));
246 tcp_write_cb (struct bufferevent *bev, void *ctx)
248 struct rs_packet *pkt = (struct rs_packet *) ctx;
253 if (pkt->conn->callbacks.sent_cb)
254 pkt->conn->callbacks.sent_cb (pkt->conn->user_data);
258 tcp_init_connect_timer (struct rs_connection *conn)
263 event_free (conn->tev);
264 conn->tev = evtimer_new (conn->evb, event_conn_timeout_cb, conn);
266 return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,