Code "cleanups." I confess that I sometimes went beyond the TODO
[freeradius.git] / src / main / request_list.c
1 /*
2  * request_list.c       Hide the handling of the REQUEST list from
3  *                      the main server.
4  *
5  * Version:     $Id$
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * Copyright 2000  The FreeRADIUS server project
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  */
24
25 static const char rcsid[] = "$Id$";
26
27 #include "autoconf.h"
28 #include "libradius.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33
34 #include "radiusd.h"
35 #include "request_list.h"
36
37 /*
38  *  We keep the incoming requests in an array, indexed by ID.
39  *
40  *  Each array element contains a linked list of containers of 
41  *  active requests, a count of the number of requests, and a time 
42  *  at which the first request in the list must be serviced.
43  */
44
45 typedef struct REQNODE {
46         struct REQNODE *prev, *next;
47         REQUEST *req;
48 } REQNODE;
49
50 typedef struct REQUESTINFO {
51         REQNODE *first_request;
52         REQNODE *last_request;
53         int request_count;
54         time_t last_cleaned_list;
55 } REQUESTINFO;
56
57 static REQUESTINFO      request_list[256];
58
59 /*
60  *      Initialize the request list.
61  */
62 int rl_init(void)
63 {
64         int i;
65
66         /*
67          *      Initialize the request_list[] array.
68          */
69         for (i = 0; i < 256; i++) {
70                 request_list[i].first_request = NULL;
71                 request_list[i].last_request = NULL;
72                 request_list[i].request_count = 0;
73                 request_list[i].last_cleaned_list = 0;
74         }
75         
76         return 0;
77 }
78
79 /*
80  *      Delete a particular request.
81  */
82 void rl_delete(REQUEST *request)
83 {
84         int id;
85         REQNODE *prev, *next;
86
87         prev = ((REQNODE *) request->container)->prev;
88         next = ((REQNODE *) request->container)->next;
89         
90         id = request->packet->id;
91
92         if (prev == NULL) {
93                 request_list[id].first_request = next;
94         } else {
95                 prev->next = next;
96         }
97
98         if (next == NULL) {
99                 request_list[id].last_request = prev;
100         } else {
101                 next->prev = prev;
102         }
103         
104         free(request->container);
105         request_free(&request);
106         request_list[id].request_count--;
107 }
108
109 /*
110  *      Add a request to the request list.
111  */
112 void rl_add(REQUEST *request)
113 {
114         int id = request->packet->id;
115
116         assert(request->container == NULL);
117
118         request->container = rad_malloc(sizeof(REQNODE));
119         ((REQNODE *)request->container)->req = request;
120
121         ((REQNODE *)request->container)->prev = NULL;
122         ((REQNODE *)request->container)->next = NULL;
123
124         if (!request_list[id].first_request) {
125                 assert(request_list[id].request_count == 0);
126
127                 request_list[id].first_request = (REQNODE *)request->container;
128                 request_list[id].last_request = (REQNODE *)request->container;
129         } else {
130                 assert(request_list[id].request_count != 0);
131
132                 ((REQNODE *)request->container)->prev = request_list[id].last_request;
133                 request_list[id].last_request->next = (REQNODE *)request->container;
134                 request_list[id].last_request = (REQNODE *)request->container;
135         }
136
137         request_list[id].request_count++;
138 }
139
140 /*
141  *      Look up a particular request, using:
142  *
143  *      Request ID, request code, source IP, source port, 
144  *
145  *      Note that we do NOT use the request vector to look up requests.
146  *
147  *      We MUST NOT have two requests with identical (id/code/IP/port), and
148  *      different vectors.  This is a serious error!
149  */
150 REQUEST *rl_find(REQUEST *request)
151 {
152         REQNODE *curreq;
153
154         for (curreq = request_list[request->packet->id].first_request;
155                         curreq != NULL ;
156                         curreq = ((REQNODE *)curreq->req->container)->next) {
157                 if ((curreq->req->packet->code == request->packet->code) &&
158                                 (curreq->req->packet->src_ipaddr == request->packet->src_ipaddr) &&
159                                 (curreq->req->packet->src_port == request->packet->src_port)) {
160                         break;
161                 }
162         }
163
164         if (curreq == NULL)
165                 return(NULL);
166
167         return curreq->req;
168 }
169
170 /*
171  *      Look up a particular request, using:
172  *
173  *      Request ID, request code, source IP, source port, 
174  *
175  *      Note that we do NOT use the request vector to look up requests.
176  *
177  *      We MUST NOT have two requests with identical (id/code/IP/port), and
178  *      different vectors.  This is a serious error!
179  */
180 REQUEST *rl_find_proxy(REQUEST *request)
181 {
182         REQNODE *curreq = NULL;
183         int id;
184         
185         for (id = 0; (id < 256) && (curreq == NULL); id++) {
186                 for (curreq = request_list[id].first_request;
187                                 curreq != NULL ;
188                                 curreq = curreq->next) {
189                         if (curreq->req->proxy &&
190                                         (curreq->req->proxy->id == request->packet->id) &&
191                                         (curreq->req->proxy->dst_ipaddr == request->packet->src_ipaddr) &&
192                                         (curreq->req->proxy->dst_port == request->packet->src_port)) {
193                                 
194                                 break;
195                         }
196                 } /* loop over all requests for this id. */
197         } /* loop over all id's... this is horribly inefficient */
198
199         if (curreq == NULL)
200                 return(NULL);
201
202         return curreq->req;
203 }
204 /*
205  *      Walk over all requests, performing a callback for each request.
206  */
207 int rl_walk(RL_WALK_FUNC walker, void *data)
208 {
209         int id, rcode;
210         REQNODE *curreq, *next;
211
212         /*
213          *      Walk over all 256 ID's.
214          */
215         for (id = 0; id < 256; id++) {
216
217                 /*
218                  *      Walk over the request list for each ID.
219                  */
220                 for (curreq = request_list[id].first_request;
221                                 curreq != NULL ;
222                                 curreq = next) {
223                         /*
224                          *      The callback MIGHT delete the current
225                          *      request, so we CANNOT depend on curreq->next
226                          *      to be there, when going to the next element
227                          *      in the 'for' loop.
228                          */
229                         next = curreq->next;
230
231                         rcode = walker(curreq->req, data);
232                         if (rcode != RL_WALK_CONTINUE) {
233                                 return rcode;
234                         }
235                 }
236         }
237
238         return 0;
239 }
240
241 /*
242  *      Walk from one request to the next.
243  */
244 REQUEST *rl_next(REQUEST *request)
245 {
246         int id, start_id;
247         int count;
248
249         /*
250          *      If we were passed a request, then go to the "next" one.
251          */
252         if (request != NULL) {
253                 assert(request->magic == REQUEST_MAGIC);
254
255                 /*
256                  *      It has a "next", return it.
257                  */
258                 if (((REQNODE *)request->container)->next != NULL) {
259                         return ((REQNODE *)request->container)->next->req;
260                 } else {
261                         /*
262                          *      No "next", increment the ID, and look
263                          *      at that one.
264                          */
265                         start_id = request->packet->id + 1;
266                         start_id &= 0xff;
267                         count = 255;
268                 }
269         } else {
270                 /*
271                  *      No input request, start looking at ID 0.
272                  */
273                 start_id = 0;
274                 count = 256;
275         }
276
277         /*
278          *      Check all ID's, wrapping around at 255.
279          */
280         for (id = start_id; id < (start_id + count); id++) {
281
282                 /*
283                  *      This ID has a request, return it.
284                  */
285                 if (request_list[id & 0xff].first_request != NULL) {
286                         assert(request_list[id&0xff].first_request->req != request);
287
288                         return request_list[id & 0xff].first_request->req;
289                 }
290         }
291
292         /*
293          *      No requests at all in the list. Nothing to do.
294          */
295         DEBUG2("rl_next:  returning NULL");
296         return NULL;
297 }
298
299 /*
300  *      Return the number of requests in the request list.
301  */
302 int rl_num_requests(void)
303 {
304         int id;
305         int request_count = 0;
306
307         for (id = 0; id < 256; id++) {
308                 request_count += request_list[id].request_count;
309         }
310         
311         return request_count;
312 }