WIP
[radsecproxy.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 "libradsec.h"
9 #include "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           uint16_t len = (pkt->hdr[2] << 8) + pkt->hdr[3];
137           uint8_t *buf = rs_malloc (pkt->conn->ctx, len);
138
139           pkt->hdr_read_flag = 1;
140           if (!buf)
141             {
142               rs_conn_err_push_fl (pkt->conn, RSE_NOMEM, __FILE__,
143                                    __LINE__, NULL);
144               abort (); /* FIXME: recovering takes reading of packet */
145             }
146           pkt->rpkt->data = buf;
147           pkt->rpkt->data_len = len;
148           bufferevent_setwatermark (pkt->conn->bev, EV_READ,
149                                     len - RS_HEADER_LEN, 0);
150 #if defined (DEBUG)
151           fprintf (stderr, "%s: packet header read, pkt len=%d\n", __func__,
152                    len);
153 #endif
154         }
155       else if (n < 0)
156         return; /* Buffer frozen, i suppose.  Let's hope it thaws.  */
157       else
158         {
159           assert (n < RS_HEADER_LEN);
160           return;               /* Need more to complete header.  */
161           }
162     }
163
164   printf ("%s: trying to read %d octets of packet data\n", __func__, pkt->rpkt->data_len - RS_HEADER_LEN;
165   n = bufferevent_read (pkt->conn->bev, pkt->rpkt->data,
166                         pkt->rpkt->data_len - RS_HEADER_LEN);
167   printf ("%s: read %d octets of packet data\n", __func__, n);
168   if (n == pkt->rpkt->data_len - RS_HEADER_LEN)
169     {
170       bufferevent_disable (pkt->conn->bev, EV_READ);
171       pkt->hdr_read_flag = 0;
172       memset (pkt->hdr, 0, sizeof(*pkt->hdr));
173 #if defined (DEBUG)
174       fprintf (stderr, "%s: complete packet read\n", __func__);
175 #endif
176       if (event_base_loopbreak (pkt->conn->evb) < 0)
177         abort ();               /* FIXME */
178     }
179 }
180
181 static int
182 _init_evb (struct rs_connection *conn)
183 {
184   if (!conn->evb)
185     {
186 #if defined (DEBUG)
187       event_enable_debug_mode ();
188 #endif
189       conn->evb = event_base_new ();
190       if (!conn->evb)
191         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
192                                     "event_base_new");
193     }
194   return RSE_OK;
195 }
196
197 static int
198 _init_socket (struct rs_connection *conn, struct rs_peer *p)
199 {
200   if (p->s < 0)
201     {
202       assert (p->addr);
203       p->s = socket (p->addr->ai_family, p->addr->ai_socktype,
204                      p->addr->ai_protocol);
205       if (p->s < 0)
206         return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
207                                     strerror (errno));
208     }
209   return RSE_OK;
210 }
211
212 static struct rs_peer *
213 _pick_peer (struct rs_connection *conn)
214 {
215   if (!conn->active_peer)
216     conn->active_peer = conn->peers;
217   return conn->active_peer;
218 }
219
220 static int
221 _init_bev (struct rs_connection *conn, struct rs_peer *peer)
222 {
223   if (!conn->bev)
224     {
225       conn->bev = bufferevent_socket_new (conn->evb, peer->s, 0);
226       if (!conn->bev)
227         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
228                                     "bufferevent_socket_new");
229     }
230   return RSE_OK;
231 }
232
233 static void
234 _do_connect (struct rs_peer *p)
235 {
236   if (bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
237                                   p->addr->ai_addrlen) < 0)
238     rs_conn_err_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
239                            "bufferevent_socket_connect");
240   else
241     p->is_connecting = 1;
242 }
243
244 static int
245 _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
246 {
247   struct rs_peer *p;
248
249   if (_init_evb (conn))
250     return -1;
251
252   p = _pick_peer (conn);
253   if (!p)
254     return rs_conn_err_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
255
256   if (_init_socket (conn, p))
257     return -1;
258
259   if (_init_bev (conn, p))
260     return -1;
261   bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
262
263   if (!p->is_connected)
264     if (!p->is_connecting)
265       _do_connect (p);
266
267   return RSE_OK;
268 }
269
270 int
271 rs_packet_send (struct rs_connection *conn, struct rs_packet *pkt, void *data)
272 {
273   assert (conn);
274   assert (pkt->rpkt);
275
276   if (_conn_open (conn, pkt))
277     return -1;
278   assert (conn->evb);
279   assert (conn->bev);
280   assert (conn->active_peer);
281   assert (conn->active_peer->s >= 0);
282
283   event_base_dispatch (conn->evb);
284
285 #if defined (DEBUG)
286   fprintf (stderr, "%s: event loop done\n", __func__);
287   assert (event_base_got_break(conn->evb));
288 #endif
289
290   return RSE_OK;
291 }
292
293 int
294 rs_packet_receive(struct rs_connection *conn, struct rs_packet **pkt_out)
295 {
296   struct rs_packet *pkt;
297
298   assert (conn);
299
300   if (_packet_create (conn, pkt_out))
301     return -1;
302   pkt = *pkt_out;
303   pkt->conn = conn;
304
305   if (_conn_open (conn, pkt))
306     return -1;
307   assert (conn->evb);
308   assert (conn->bev);
309   assert (conn->active_peer);
310   assert (conn->active_peer->s >= 0);
311
312   bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0);
313   bufferevent_enable (conn->bev, EV_READ);
314   event_base_dispatch (conn->evb);
315 #if defined (DEBUG)
316   fprintf (stderr, "%s: event loop done\n", __func__);
317   assert (event_base_got_break(conn->evb));
318 #endif
319
320 #if defined (DEBUG)
321   fprintf (stderr, "%s: got this:\n", __func__);
322   rs_dump_packet (pkt);
323 #endif
324
325   return RSE_OK;
326 }
327
328 void
329 rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr)
330 {
331   pairadd (&pkt->rpkt->vps, attr->vp);
332   attr->pkt = pkt;
333 }