2 * request_list.c Hide the handling of the REQUEST list from
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.
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.
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
21 * Copyright 2000 The FreeRADIUS server project
22 * Copyright 2000 Alan DeKok <aland@ox.org>
25 static const char rcsid[] = "$Id$";
28 #include "libradius.h"
35 #include "request_list.h"
38 * We keep the incoming requests in an array, indexed by ID.
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.
45 typedef struct REQNODE {
46 struct REQNODE *prev, *next;
50 typedef struct REQUESTINFO {
51 REQNODE *first_request;
52 REQNODE *last_request;
54 time_t last_cleaned_list;
57 static REQUESTINFO request_list[256];
60 * Initialize the request list.
67 * Initialize the request_list[] array.
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;
80 * Delete a particular request.
82 void rl_delete(REQUEST *request)
87 prev = ((REQNODE *) request->container)->prev;
88 next = ((REQNODE *) request->container)->next;
90 id = request->packet->id;
93 request_list[id].first_request = next;
99 request_list[id].last_request = prev;
104 free(request->container);
105 request_free(&request);
106 request_list[id].request_count--;
110 * Add a request to the request list.
112 void rl_add(REQUEST *request)
114 int id = request->packet->id;
116 assert(request->container == NULL);
118 request->container = rad_malloc(sizeof(REQNODE));
119 ((REQNODE *)request->container)->req = request;
121 ((REQNODE *)request->container)->prev = NULL;
122 ((REQNODE *)request->container)->next = NULL;
124 if (!request_list[id].first_request) {
125 assert(request_list[id].request_count == 0);
127 request_list[id].first_request = (REQNODE *)request->container;
128 request_list[id].last_request = (REQNODE *)request->container;
130 assert(request_list[id].request_count != 0);
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;
137 request_list[id].request_count++;
141 * Look up a particular request, using:
143 * Request ID, request code, source IP, source port,
145 * Note that we do NOT use the request vector to look up requests.
147 * We MUST NOT have two requests with identical (id/code/IP/port), and
148 * different vectors. This is a serious error!
150 REQUEST *rl_find(REQUEST *request)
154 for (curreq = request_list[request->packet->id].first_request;
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)) {
171 * Look up a particular request, using:
173 * Request ID, request code, source IP, source port,
175 * Note that we do NOT use the request vector to look up requests.
177 * We MUST NOT have two requests with identical (id/code/IP/port), and
178 * different vectors. This is a serious error!
180 REQUEST *rl_find_proxy(REQUEST *request)
182 REQNODE *curreq = NULL;
185 for (id = 0; (id < 256) && (curreq == NULL); id++) {
186 for (curreq = request_list[id].first_request;
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)) {
196 } /* loop over all requests for this id. */
197 } /* loop over all id's... this is horribly inefficient */
205 * Walk over all requests, performing a callback for each request.
207 int rl_walk(RL_WALK_FUNC walker, void *data)
210 REQNODE *curreq, *next;
213 * Walk over all 256 ID's.
215 for (id = 0; id < 256; id++) {
218 * Walk over the request list for each ID.
220 for (curreq = request_list[id].first_request;
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
231 rcode = walker(curreq->req, data);
232 if (rcode != RL_WALK_CONTINUE) {
242 * Walk from one request to the next.
244 REQUEST *rl_next(REQUEST *request)
250 * If we were passed a request, then go to the "next" one.
252 if (request != NULL) {
253 assert(request->magic == REQUEST_MAGIC);
256 * It has a "next", return it.
258 if (((REQNODE *)request->container)->next != NULL) {
259 return ((REQNODE *)request->container)->next->req;
262 * No "next", increment the ID, and look
265 start_id = request->packet->id + 1;
271 * No input request, start looking at ID 0.
278 * Check all ID's, wrapping around at 255.
280 for (id = start_id; id < (start_id + count); id++) {
283 * This ID has a request, return it.
285 if (request_list[id & 0xff].first_request != NULL) {
286 assert(request_list[id&0xff].first_request->req != request);
288 return request_list[id & 0xff].first_request->req;
293 * No requests at all in the list. Nothing to do.
295 DEBUG2("rl_next: returning NULL");
300 * Return the number of requests in the request list.
302 int rl_num_requests(void)
305 int request_count = 0;
307 for (id = 0; id < 256; id++) {
308 request_count += request_list[id].request_count;
311 return request_count;