WIP
[libradsec.git] / lib / packet.c
1 /* See the file COPYING for licensing information.  */
2
3 #include <string.h>
4 #include <assert.h>
5 #include <freeradius/libradius.h>
6 #include <event2/event.h>
7 #include <event2/bufferevent.h>
8 #include <radsec/libradsec.h>
9 #include <radsec/libradsec-impl.h>
10 #if defined DEBUG
11 #include "debug.h"
12 #endif
13
14 static int
15 _packet_create (struct rs_connection *conn, struct rs_packet **pkt_out)
16 {
17   struct rs_packet *p;
18   RADIUS_PACKET *rpkt;
19
20   *pkt_out = NULL;
21
22   rpkt = rad_alloc (1);
23   if (!rpkt)
24     return rs_conn_err_push (conn, RSE_NOMEM, __func__);
25   rpkt->id = -1;
26
27   p = (struct rs_packet *) malloc (sizeof (struct rs_packet));
28   if (!p)
29     {
30       rad_free (&rpkt);
31       return rs_conn_err_push (conn, RSE_NOMEM, __func__);
32     }
33   memset (p, 0, sizeof (struct rs_packet));
34   p->conn = conn;
35   p->rpkt = rpkt;
36
37   *pkt_out = p;
38   return RSE_OK;
39 }
40
41 int
42 rs_packet_create_acc_request (struct rs_connection *conn,
43                               struct rs_packet **pkt_out,
44                               const char *user_name, const char *user_pw)
45 {
46   struct rs_packet *pkt;
47   struct rs_attr *attr;
48
49   if (_packet_create (conn, pkt_out))
50     return -1;
51   pkt = *pkt_out;
52   pkt->rpkt->code = PW_AUTHENTICATION_REQUEST;
53
54   if (rs_attr_create (conn, &attr, "User-Name", user_name))
55     return -1;
56   rs_packet_add_attr (pkt, attr);
57
58   if (rs_attr_create (conn, &attr, "User-Password", user_pw))
59     return -1;
60   /* FIXME: need this too? rad_pwencode(user_pw, &pwlen, SECRET, reqauth) */
61   rs_packet_add_attr (pkt, attr);
62
63   return RSE_OK;
64 }
65
66 static void
67 _event_cb (struct bufferevent *bev, short events, void *ctx)
68 {
69   struct rs_packet *pkt = (struct rs_packet *) ctx;
70   struct rs_connection *conn;
71   struct rs_peer *p;
72
73   assert (pkt);
74   assert (pkt->conn);
75   assert (pkt->conn->active_peer);
76   conn = pkt->conn;
77   p = conn->active_peer;
78
79   p->is_connecting = 0;
80   if (events & BEV_EVENT_CONNECTED)
81     {
82       p->is_connected = 1;
83 #if defined (DEBUG)
84       fprintf (stderr, "%s: connected\n", __func__);
85 #endif
86       rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret);
87       assert (pkt->rpkt);
88 #if defined (DEBUG)
89       fprintf (stderr, "%s: about to send this to %s:\n", __func__, "<fixme>");
90       rs_dump_packet (pkt);
91 #endif
92       if (bufferevent_write(bev, pkt->rpkt->data, pkt->rpkt->data_len))
93         rs_conn_err_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
94                              "bufferevent_write");
95       /* Packet will be freed in write callback.  */
96     }
97   else if (events & BEV_EVENT_ERROR)
98     rs_conn_err_push_fl (pkt->conn, RSE_CONNERR, __FILE__, __LINE__, NULL);
99 }
100
101 void
102 rs_packet_destroy(struct rs_packet *pkt)
103 {
104   rad_free (&pkt->rpkt);
105   rs_free (pkt->conn->ctx, pkt);
106 }
107
108 static void
109 _write_cb (struct bufferevent *bev, void *ctx)
110 {
111   struct rs_packet *pkt = (struct rs_packet *) ctx;
112
113   assert (pkt);
114   assert (pkt->conn);
115 #if defined (DEBUG)
116   fprintf (stderr, "%s: packet written, breaking event loop\n", __func__);
117 #endif
118   if (event_base_loopbreak (pkt->conn->evb) < 0)
119     abort ();                   /* FIXME */
120   rs_packet_destroy (pkt);
121 }
122
123 static void
124 _read_cb (struct bufferevent *bev, void *ctx)
125 {
126   struct rs_packet *pkt = (struct rs_packet *) ctx;
127   size_t n;
128
129   assert (pkt);
130   assert (pkt->conn);
131   if (!pkt->hdr_read_flag)
132     {
133       n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN);
134       if (n == RS_HEADER_LEN)
135         {
136           pkt->hdr_read_flag = 1;
137           pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3];
138           if (pkt->rpkt->data_len < 20 /* || len > 4096 */)
139             abort ();  /* TODO: Read and discard.  */
140           pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len);
141           if (!pkt->rpkt->data)
142             {
143               rs_conn_err_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__,
144                                    NULL);
145               abort (); /* FIXME: recovering takes reading of packet */
146             }
147           memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN);
148           bufferevent_setwatermark (pkt->conn->bev, EV_READ,
149                                     pkt->rpkt->data_len - RS_HEADER_LEN, 0);
150 #if defined (DEBUG)
151           fprintf (stderr, "%s: packet header read, total pkt len=%d\n",
152                    __func__, pkt->rpkt->data_len);
153 #endif
154         }
155       else if (n < 0)
156         return;                 /* Buffer frozen.  */
157       else
158         assert (!"short header");
159     }
160
161   printf ("%s: trying to read %d octets of packet data\n", __func__, pkt->rpkt->data_len - RS_HEADER_LEN);
162   n = bufferevent_read (pkt->conn->bev, pkt->rpkt->data + RS_HEADER_LEN, pkt->rpkt->data_len - RS_HEADER_LEN);
163   printf ("%s: read %d octets of packet data\n", __func__, n);
164   if (n == pkt->rpkt->data_len - RS_HEADER_LEN)
165     {
166       bufferevent_disable (pkt->conn->bev, EV_READ);
167       pkt->hdr_read_flag = 0;
168       memset (pkt->hdr, 0, sizeof(*pkt->hdr));
169 #if defined (DEBUG)
170       fprintf (stderr, "%s: complete packet read\n", __func__);
171 #endif
172       rad_decode (pkt->rpkt, NULL, pkt->conn->active_peer->secret);
173       if (event_base_loopbreak (pkt->conn->evb) < 0)
174         abort ();               /* FIXME */
175     }
176   else if (n < 0)
177     return;                     /* Buffer frozen.  */
178   else
179     assert (!"short packet");
180 }
181
182 static int
183 _init_evb (struct rs_connection *conn)
184 {
185   if (!conn->evb)
186     {
187 #if defined (DEBUG)
188       event_enable_debug_mode ();
189 #endif
190       conn->evb = event_base_new ();
191       if (!conn->evb)
192         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
193                                     "event_base_new");
194     }
195   return RSE_OK;
196 }
197
198 static int
199 _init_socket (struct rs_connection *conn, struct rs_peer *p)
200 {
201   if (p->s < 0)
202     {
203       assert (p->addr);
204       p->s = socket (p->addr->ai_family, p->addr->ai_socktype,
205                      p->addr->ai_protocol);
206       if (p->s < 0)
207         return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
208                                     strerror (errno));
209     }
210   return RSE_OK;
211 }
212
213 static struct rs_peer *
214 _pick_peer (struct rs_connection *conn)
215 {
216   if (!conn->active_peer)
217     conn->active_peer = conn->peers;
218   return conn->active_peer;
219 }
220
221 static int
222 _init_bev (struct rs_connection *conn, struct rs_peer *peer)
223 {
224   if (!conn->bev)
225     {
226       conn->bev = bufferevent_socket_new (conn->evb, peer->s, 0);
227       if (!conn->bev)
228         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
229                                     "bufferevent_socket_new");
230     }
231   return RSE_OK;
232 }
233
234 static void
235 _do_connect (struct rs_peer *p)
236 {
237   if (bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
238                                   p->addr->ai_addrlen) < 0)
239     rs_conn_err_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
240                            "bufferevent_socket_connect");
241   else
242     p->is_connecting = 1;
243 }
244
245 static int
246 _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
247 {
248   struct rs_peer *p;
249
250   if (_init_evb (conn))
251     return -1;
252
253   p = _pick_peer (conn);
254   if (!p)
255     return rs_conn_err_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
256
257   if (_init_socket (conn, p))
258     return -1;
259
260   if (_init_bev (conn, p))
261     return -1;
262   bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
263
264   if (!p->is_connected)
265     if (!p->is_connecting)
266       _do_connect (p);
267
268   return RSE_OK;
269 }
270
271 int
272 rs_packet_send (struct rs_packet *pkt, void *data)
273 {
274   struct rs_connection *conn;
275   assert (pkt);
276   assert (pkt->conn);
277   assert (pkt->rpkt);
278   conn = pkt->conn;
279
280   if (_conn_open (conn, pkt))
281     return -1;
282   assert (conn->evb);
283   assert (conn->bev);
284   assert (conn->active_peer);
285   assert (conn->active_peer->s >= 0);
286
287   event_base_dispatch (conn->evb);
288
289 #if defined (DEBUG)
290   fprintf (stderr, "%s: event loop done\n", __func__);
291   assert (event_base_got_break(conn->evb));
292 #endif
293
294   return RSE_OK;
295 }
296
297 int
298 rs_conn_receive_packet (struct rs_connection *conn, struct rs_packet **pkt_out)
299 {
300   struct rs_packet *pkt;
301
302   assert (conn);
303
304   if (_packet_create (conn, pkt_out))
305     return -1;
306   pkt = *pkt_out;
307   pkt->conn = conn;
308
309   if (_conn_open (conn, pkt))
310     return -1;
311   assert (conn->evb);
312   assert (conn->bev);
313   assert (conn->active_peer);
314   assert (conn->active_peer->s >= 0);
315
316   bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0);
317   bufferevent_enable (conn->bev, EV_READ);
318   event_base_dispatch (conn->evb);
319 #if defined (DEBUG)
320   fprintf (stderr, "%s: event loop done", __func__);
321   if (event_base_got_break(conn->evb))
322     {
323       fprintf (stderr, ", got this:\n");
324       rs_dump_packet (pkt);
325     }
326   else
327     fprintf (stderr, ", no reply\n");
328 #endif
329
330   return RSE_OK;
331 }
332
333 void
334 rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr)
335 {
336   pairadd (&pkt->rpkt->vps, attr->vp);
337   attr->pkt = pkt;
338 }
339
340 struct radius_packet *
341 rs_packet_frpkt(struct rs_packet *pkt)
342 {
343   assert (pkt);
344   return pkt->rpkt;
345 }