Refactoring in preparation for handling more cases than client sending one packet.
[radsecproxy.git] / lib / packet.c
1 #include <string.h>
2 #include <assert.h>
3 #include <freeradius/libradius.h>
4 #include <event2/event.h>
5 #include <event2/bufferevent.h>
6 #include "libradsec.h"
7 #include "libradsec-impl.h"
8 #if defined DEBUG
9 #include "debug.h"
10 #endif
11
12 int
13 _packet_create (struct rs_connection *conn, struct rs_packet **pkt_out,
14                 int code)
15 {
16   struct rs_packet *p;
17   RADIUS_PACKET *rpkt;
18
19   *pkt_out = NULL;
20
21   rpkt = rad_alloc (1);
22   if (!rpkt)
23     return rs_conn_err_push (conn, RSE_NOMEM, __func__);
24   rpkt->id = -1;
25   rpkt->code = code;
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, PW_AUTHENTICATION_REQUEST))
50     return -1;
51   pkt = *pkt_out;
52
53   if (rs_attr_create (conn, &attr, "User-Name", user_name))
54     return -1;
55   rs_packet_add_attr (pkt, attr);
56
57   if (rs_attr_create (conn, &attr, "User-Password", user_pw))
58     return -1;
59   /* FIXME: need this too? rad_pwencode(user_pw, &pwlen, SECRET, reqauth) */
60   rs_packet_add_attr (pkt, attr);
61
62   return RSE_OK;
63 }
64
65 static void
66 _event_cb (struct bufferevent *bev, short events, void *ctx)
67 {
68   struct rs_packet *pkt = (struct rs_packet *) ctx;
69   struct rs_connection *conn;
70   struct rs_peer *p;
71
72   assert (pkt);
73   assert (pkt->conn);
74   assert (pkt->conn->active_peer);
75   conn = pkt->conn;
76   p = conn->active_peer;
77
78   p->is_connecting = 0;
79   if (events & BEV_EVENT_CONNECTED)
80     {
81       p->is_connected = 1;
82 #if defined (DEBUG)
83       fprintf (stderr, "%s: connected\n", __func__);
84 #endif
85       rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret);
86 #if defined (DEBUG)
87       fprintf (stderr, "%s: about to send this to %s:\n", __func__, "<fixme>");
88       rs_dump_packet (pkt);
89 #endif
90       if (bufferevent_write(bev, pkt->rpkt->data, pkt->rpkt->data_len))
91         rs_conn_err_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
92                              "bufferevent_write");
93       /* Packet will be freed in write callback.  */
94     }
95   else if (events & BEV_EVENT_ERROR)
96     rs_conn_err_push_fl (pkt->conn, RSE_CONNERR, __FILE__, __LINE__, NULL);
97 }
98
99 void
100 rs_packet_destroy(struct rs_packet *pkt)
101 {
102   rad_free (&pkt->rpkt);
103   rs_free (pkt->conn->ctx, pkt);
104 }
105
106 static void
107 _write_cb (struct bufferevent *bev, void *ctx)
108 {
109   struct rs_packet *pkt = (struct rs_packet *) ctx;
110
111   assert (pkt);
112   assert (pkt->conn);
113 #if defined (DEBUG)
114   fprintf (stderr, "%s: packet written, breaking event loop\n", __func__);
115 #endif
116   if (event_base_loopbreak (pkt->conn->evb) < 0)
117     abort ();                   /* FIXME */
118   rs_packet_destroy (pkt);
119 }
120
121 static int
122 _init_evb (struct rs_connection *conn)
123 {
124   if (!conn->evb)
125     {
126 #if defined (DEBUG)
127       event_enable_debug_mode ();
128 #endif
129       conn->evb = event_base_new ();
130       if (!conn->evb)
131         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
132                                     "event_base_new");
133     }
134   return RSE_OK;
135 }
136
137 static int
138 _init_socket (struct rs_connection *conn, struct rs_peer *p)
139 {
140   if (p->s < 0)
141     {
142       assert (p->addr);
143       p->s = socket (p->addr->ai_family, p->addr->ai_socktype,
144                      p->addr->ai_protocol);
145       if (p->s < 0)
146         return rs_conn_err_push_fl (conn, RSE_SOME_ERROR, __FILE__, __LINE__,
147                                     strerror (errno));
148     }
149   return RSE_OK;
150 }
151
152 static struct rs_peer *
153 _pick_peer (struct rs_connection *conn)
154 {
155   if (!conn->active_peer)
156     conn->active_peer = conn->peers;
157   return conn->active_peer;
158 }
159
160 static int
161 _init_bev (struct rs_connection *conn, struct rs_peer *peer,
162            struct rs_packet *pkt)
163 {
164   if (!conn->bev)
165     {
166       conn->bev = bufferevent_socket_new (conn->evb, peer->s, 0);
167       if (!conn->bev)
168         return rs_conn_err_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,
169                                     "bufferevent_socket_new");
170       bufferevent_setcb (conn->bev, NULL, _write_cb, _event_cb, pkt);
171     }
172   return RSE_OK;
173 }
174
175 static void
176 _do_connect (struct rs_peer *p)
177 {
178   if (bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
179                                   p->addr->ai_addrlen) < 0)
180     rs_conn_err_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
181                            "bufferevent_socket_connect");
182   else
183     p->is_connecting = 1;
184 }
185
186 static int
187 _conn_open(struct rs_connection *conn, struct rs_packet *pkt)
188 {
189   struct rs_peer *p;
190
191   if (_init_evb (conn))
192     return -1;
193
194   p = _pick_peer (conn);
195   if (!p)
196     return rs_conn_err_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL);
197
198   if (_init_socket (conn, p))
199     return -1;
200
201   if (_init_bev (conn, p, pkt))
202     return -1;
203
204   if (!p->is_connected)
205     if (!p->is_connecting)
206       _do_connect (p);
207
208   return RSE_OK;
209 }
210
211 int
212 rs_packet_send (struct rs_connection *conn, struct rs_packet *pkt, void *data)
213 {
214   assert (conn);
215   assert (pkt->rpkt);
216   if (_conn_open (conn, pkt))
217     return -1;
218   assert (conn->evb);
219   assert (conn->bev);
220   assert (conn->active_peer);
221   assert (conn->active_peer->s >= 0);
222   event_base_dispatch (conn->evb);
223 #if defined (DEBUG)
224   fprintf (stderr, "%s: event loop done\n", __func__);
225   assert (event_base_got_break(conn->evb));
226 #endif
227
228   return RSE_OK;
229 }
230
231 int rs_packet_receive(struct rs_connection *conn, struct rs_packet **pkt)
232 {
233   //struct bufferevent *bev;
234
235   //skalleper;
236   //bufferevent_enable(bev, EV_READ);
237   return 0;                     /* FIXME */
238 }
239
240
241 void
242 rs_packet_add_attr(struct rs_packet *pkt, struct rs_attr *attr)
243 {
244   pairadd (&pkt->rpkt->vps, attr->vp);
245   attr->pkt = pkt;
246 }
247