/* * request_list.c Hide the handling of the REQUEST list from * the main server. * * Version: $Id: request_list.c,v 1.19 2001/08/17 19:45:27 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2000 The FreeRADIUS server project * Copyright 2000 Alan DeKok */ static const char rcsid[] = "$Id: request_list.c,v 1.19 2001/08/17 19:45:27 aland Exp $"; #include "autoconf.h" #include "libradius.h" #include #include #include "radiusd.h" #include "rad_assert.h" #include "request_list.h" /* * We keep the incoming requests in an array, indexed by ID. * * Each array element contains a linked list of containers of * active requests, a count of the number of requests, and a time * at which the first request in the list must be serviced. */ typedef struct REQNODE { struct REQNODE *prev, *next; REQUEST *req; } REQNODE; typedef struct REQUESTINFO { REQNODE *first_request; REQNODE *last_request; int request_count; time_t last_cleaned_list; } REQUESTINFO; static REQUESTINFO request_list[256]; /* * Initialize the request list. */ int rl_init(void) { int i; /* * Initialize the request_list[] array. */ for (i = 0; i < 256; i++) { request_list[i].first_request = NULL; request_list[i].last_request = NULL; request_list[i].request_count = 0; request_list[i].last_cleaned_list = 0; } return 0; } /* * Delete a particular request. */ void rl_delete(REQUEST *request) { int id; REQNODE *prev, *next; prev = ((REQNODE *) request->container)->prev; next = ((REQNODE *) request->container)->next; id = request->packet->id; if (prev == NULL) { request_list[id].first_request = next; } else { prev->next = next; } if (next == NULL) { request_list[id].last_request = prev; } else { next->prev = prev; } free(request->container); request_free(&request); request_list[id].request_count--; } /* * Add a request to the request list. */ void rl_add(REQUEST *request) { int id = request->packet->id; rad_assert(request->container == NULL); request->container = rad_malloc(sizeof(REQNODE)); ((REQNODE *)request->container)->req = request; ((REQNODE *)request->container)->prev = NULL; ((REQNODE *)request->container)->next = NULL; if (!request_list[id].first_request) { rad_assert(request_list[id].request_count == 0); request_list[id].first_request = (REQNODE *)request->container; request_list[id].last_request = (REQNODE *)request->container; } else { rad_assert(request_list[id].request_count != 0); ((REQNODE *)request->container)->prev = request_list[id].last_request; request_list[id].last_request->next = (REQNODE *)request->container; request_list[id].last_request = (REQNODE *)request->container; } request_list[id].request_count++; } /* * Look up a particular request, using: * * Request ID, request code, source IP, source port, * * Note that we do NOT use the request vector to look up requests. * * We MUST NOT have two requests with identical (id/code/IP/port), and * different vectors. This is a serious error! */ REQUEST *rl_find(REQUEST *request) { REQNODE *curreq; for (curreq = request_list[request->packet->id].first_request; curreq != NULL ; curreq = ((REQNODE *)curreq->req->container)->next) { if ((curreq->req->packet->code == request->packet->code) && (curreq->req->packet->src_ipaddr == request->packet->src_ipaddr) && (curreq->req->packet->src_port == request->packet->src_port)) { return curreq->req; } } return NULL; } /* * Look up a particular request, using: * * Request ID, request code, source IP, source port, * * Note that we do NOT use the request vector to look up requests. * * We MUST NOT have two requests with identical (id/code/IP/port), and * different vectors. This is a serious error! */ REQUEST *rl_find_proxy(REQUEST *request) { REQNODE *curreq = NULL; int id; for (id = 0; (id < 256) && (curreq == NULL); id++) { for (curreq = request_list[id].first_request; curreq != NULL ; curreq = curreq->next) { if (curreq->req->proxy && (curreq->req->proxy->id == request->packet->id) && (curreq->req->proxy->dst_ipaddr == request->packet->src_ipaddr) && (curreq->req->proxy->dst_port == request->packet->src_port)) { return curreq->req; } } /* loop over all requests for this id. */ } /* loop over all id's... this is horribly inefficient */ return NULL; } /* * Walk over all requests, performing a callback for each request. */ int rl_walk(RL_WALK_FUNC walker, void *data) { int id, rcode; REQNODE *curreq, *next; /* * Walk over all 256 ID's. */ for (id = 0; id < 256; id++) { /* * Walk over the request list for each ID. */ for (curreq = request_list[id].first_request; curreq != NULL ; curreq = next) { /* * The callback MIGHT delete the current * request, so we CANNOT depend on curreq->next * to be there, when going to the next element * in the 'for' loop. */ next = curreq->next; rcode = walker(curreq->req, data); if (rcode != RL_WALK_CONTINUE) { return rcode; } } } return 0; } /* * Walk from one request to the next. */ REQUEST *rl_next(REQUEST *request) { int id, start_id; int count; /* * If we were passed a request, then go to the "next" one. */ if (request != NULL) { rad_assert(request->magic == REQUEST_MAGIC); /* * It has a "next", return it. */ if (((REQNODE *)request->container)->next != NULL) { return ((REQNODE *)request->container)->next->req; } else { /* * No "next", increment the ID, and look * at that one. */ start_id = request->packet->id + 1; start_id &= 0xff; count = 255; } } else { /* * No input request, start looking at ID 0. */ start_id = 0; count = 256; } /* * Check all ID's, wrapping around at 255. */ for (id = start_id; id < (start_id + count); id++) { /* * This ID has a request, return it. */ if (request_list[id & 0xff].first_request != NULL) { rad_assert(request_list[id&0xff].first_request->req != request); return request_list[id & 0xff].first_request->req; } } /* * No requests at all in the list. Nothing to do. */ DEBUG2("rl_next: returning NULL"); return NULL; } /* * Return the number of requests in the request list. */ int rl_num_requests(void) { int id; int request_count = 0; for (id = 0; id < 256; id++) { request_count += request_list[id].request_count; } return request_count; }