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 2003-2004 The FreeRADIUS server project
23 static const char rcsid[] = "$Id$";
25 #include <freeradius-devel/autoconf.h>
31 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/rad_assert.h>
33 #include <freeradius-devel/request_list.h>
34 #include <freeradius-devel/radius_snmp.h>
36 struct request_list_t {
37 lrad_hash_table_t *ht;
41 typedef struct request_entry_t {
42 struct request_entry_t *next;
48 static pthread_mutex_t proxy_mutex;
51 * This is easier than ifdef's throughout the code.
53 #define pthread_mutex_lock(_x)
54 #define pthread_mutex_unlock(_x)
58 * We keep track of packets we're proxying, keyed by
59 * source socket, and destination ip/port, and Id.
61 static rbtree_t *proxy_tree;
64 * We keep track of free/used Id's, by destination ip/port.
66 * We need a different tree than above, because this one is NOT
67 * keyed by Id. Instead, we use this one to allocate Id's.
69 static rbtree_t *proxy_id_tree;
72 * We keep the proxy FD's here. The RADIUS Id's are marked
73 * "allocated" per Id, via a bit per proxy FD.
75 static int proxy_fds[32];
76 static rad_listen_t *proxy_listeners[32];
79 * We can use 256 RADIUS Id's per dst ipaddr/port, per server
80 * socket. So, to allocate them, we key off of dst ipaddr/port,
81 * and then search the RADIUS Id's, looking for an unused socket.
83 * We do NOT key off of socket fd's, here, either. Instead,
84 * we look for a free Id from a sockfd, any sockfd.
86 typedef struct proxy_id_t {
87 lrad_ipaddr_t dst_ipaddr;
91 * FIXME: Allocate more proxy sockets when this gets full.
94 uint32_t mask; /* of FD's we know about. */
95 uint32_t id[1]; /* really id[256] */
100 * Find a matching entry in the proxy ID tree.
102 static int proxy_id_cmp(const void *one, const void *two)
105 const proxy_id_t *a = one;
106 const proxy_id_t *b = two;
109 * The following comparisons look weird, but it's
110 * the only way to make the comparisons work.
112 if (a->dst_port < b->dst_port) return -1;
113 if (a->dst_port > b->dst_port) return +1;
115 if (a->dst_ipaddr.af < b->dst_ipaddr.af) return -1;
116 if (a->dst_ipaddr.af > b->dst_ipaddr.af) return +1;
118 switch (a->dst_ipaddr.af) {
120 rcode = memcmp(&a->dst_ipaddr.ipaddr.ip4addr,
121 &b->dst_ipaddr.ipaddr.ip4addr,
122 sizeof(a->dst_ipaddr.ipaddr.ip4addr));
125 rcode = memcmp(&a->dst_ipaddr.ipaddr.ip6addr,
126 &b->dst_ipaddr.ipaddr.ip6addr,
127 sizeof(a->dst_ipaddr.ipaddr.ip6addr));
130 return -1; /* FIXME: die! */
134 * We could optimize this away, but the compiler should
135 * do that work for us, and this coding style helps us
136 * remember what to do if we add more checks later.
138 if (rcode != 0) return rcode;
141 * Everything's equal. Say so.
147 static void packet_hash(RADIUS_PACKET *packet)
151 hash = lrad_hash(&packet->src_port, sizeof(packet->src_port));
154 * We shouldn't have to hash af, sockfd, code, or dst_port,
155 * as they're the same for one request_list_t
158 hash = lrad_hash_update(&packet->src_ipaddr.af,
159 sizeof(packet->src_ipaddr.af), hash);
161 hash = lrad_hash_update(&packet->code, sizeof(packet->code), hash);
162 hash = lrad_hash_update(&packet->sockfd, sizeof(packet->sockfd), hash);
163 hash = lrad_hash_update(&packet->dst_port,
164 sizeof(packet->dst_port), hash);
168 * The caller ensures that src & dst AF are the same.
170 * We use dst IP in the hash, as the sockfd may be listening
171 * on "*", with udpfromto, to get multiple dst IP's.
173 switch (packet->src_ipaddr.af) {
175 hash = lrad_hash_update(&packet->src_ipaddr.ipaddr.ip4addr,
176 sizeof(packet->src_ipaddr.ipaddr.ip4addr),
178 hash = lrad_hash_update(&packet->dst_ipaddr.ipaddr.ip4addr,
179 sizeof(packet->dst_ipaddr.ipaddr.ip4addr),
183 hash = lrad_hash_update(&packet->src_ipaddr.ipaddr.ip6addr,
184 sizeof(packet->src_ipaddr.ipaddr.ip6addr),
186 hash = lrad_hash_update(&packet->dst_ipaddr.ipaddr.ip6addr,
187 sizeof(packet->dst_ipaddr.ipaddr.ip6addr),
196 * Put the packet Id into the high byte of the hash,
197 * to minimize the number of possible collisions.
199 * The hash table indexing is done via the low bits,
200 * so we shouldn't use those.
202 rad_assert((packet->id >= 0) && (packet->id < 256));
203 packet->hash = packet->id << 24;
204 packet->hash |= hash >> 8;
208 static int packet_cmp(const RADIUS_PACKET *a, const RADIUS_PACKET *b)
211 if (a->id != b->id) return 0;
213 if (a->src_port != b->src_port) return 0;
215 switch (a->dst_ipaddr.af) {
217 if (memcmp(&a->dst_ipaddr.ipaddr.ip4addr,
218 &b->dst_ipaddr.ipaddr.ip4addr,
219 sizeof(a->dst_ipaddr.ipaddr.ip4addr)) != 0)
221 if (memcmp(&a->src_ipaddr.ipaddr.ip4addr,
222 &b->src_ipaddr.ipaddr.ip4addr,
223 sizeof(a->src_ipaddr.ipaddr.ip4addr)) != 0)
227 if (memcmp(&a->dst_ipaddr.ipaddr.ip6addr,
228 &b->dst_ipaddr.ipaddr.ip6addr,
229 sizeof(a->dst_ipaddr.ipaddr.ip6addr)) != 0)
231 if (memcmp(&a->src_ipaddr.ipaddr.ip6addr,
232 &b->src_ipaddr.ipaddr.ip6addr,
233 sizeof(a->src_ipaddr.ipaddr.ip6addr)) != 0)
242 * These next comparisons should reall be assertions.
244 if (a->src_ipaddr.af != b->src_ipaddr.af) return 0;
246 if (a->dst_ipaddr.af != b->dst_ipaddr.af) return 0;
248 if (a->sockfd != b->sockfd) return 0;
250 if (a->code != b->code) return 0;
252 if (a->dst_port != b->dst_port) return 0;
255 * Everything's equal. Say so.
261 * Compare two REQUEST data structures, based on a number
262 * of criteria, for proxied packets.
264 static int proxy_cmp(const void *one, const void *two)
267 const REQUEST *a = one;
268 const REQUEST *b = two;
270 rad_assert(a->magic == REQUEST_MAGIC);
271 rad_assert(b->magic == REQUEST_MAGIC);
273 rad_assert(a->proxy != NULL);
274 rad_assert(b->proxy != NULL);
277 * The following code looks unreasonable, but it's
278 * the only way to make the comparisons work.
280 if (a->proxy->sockfd < b->proxy->sockfd) return -1;
281 if (a->proxy->sockfd > b->proxy->sockfd) return +1;
283 if (a->proxy->id < b->proxy->id) return -1;
284 if (a->proxy->id > b->proxy->id) return +1;
287 * We've got to check packet codes, too. But
288 * this should be done later, by someone else...
290 if (a->proxy->dst_ipaddr.af < b->proxy->dst_ipaddr.af) return -1;
291 if (a->proxy->dst_ipaddr.af > b->proxy->dst_ipaddr.af) return +1;
293 if (a->proxy->dst_port < b->proxy->dst_port) return -1;
294 if (a->proxy->dst_port > b->proxy->dst_port) return +1;
296 switch (a->proxy->dst_ipaddr.af) {
298 rcode = memcmp(&a->proxy->dst_ipaddr.ipaddr.ip4addr,
299 &b->proxy->dst_ipaddr.ipaddr.ip4addr,
300 sizeof(a->proxy->dst_ipaddr.ipaddr.ip4addr));
303 rcode = memcmp(&a->proxy->dst_ipaddr.ipaddr.ip6addr,
304 &b->proxy->dst_ipaddr.ipaddr.ip6addr,
305 sizeof(a->proxy->dst_ipaddr.ipaddr.ip6addr));
308 return -1; /* FIXME: die! */
311 if (rcode != 0) return rcode;
314 * FIXME: Check the Proxy-State attribute, too.
315 * This will help cut down on duplicates.
319 * Everything's equal. Say so.
326 * Initialize the request list.
328 request_list_t *rl_init(void)
330 request_list_t *rl = rad_malloc(sizeof(*rl));
333 * Initialize the request_list[] array.
335 memset(rl, 0, sizeof(*rl));
337 rl->ht = lrad_hash_table_create(10, NULL, 0);
339 rad_assert("FAIL" == NULL);
341 lrad_hash_table_set_data_size(rl->ht, sizeof(request_entry_t));
346 int rl_init_proxy(void)
349 * Hacks, so that multiple users can call rl_init,
350 * and it won't get excited.
352 * FIXME: Move proxy stuff to another struct entirely.
354 if (proxy_tree) return 0;
357 * Create the tree for managing proxied requests and
360 proxy_tree = rbtree_create(proxy_cmp, NULL, 1);
362 rad_assert("FAIL" == NULL);
366 * Create the tree for allocating proxy ID's.
368 proxy_id_tree = rbtree_create(proxy_id_cmp, NULL, 0);
369 if (!proxy_id_tree) {
370 rad_assert("FAIL" == NULL);
373 #ifdef HAVE_PTHREAD_H
375 * For now, always create the mutex.
377 * Later, we can only create it if there are multiple threads.
379 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
380 radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
387 * The Id allocation table is done by bits, so we have
388 * 32 bits per Id. These bits indicate which entry
389 * in the proxy_fds array is used for that Id.
391 * This design allows 256*32 = 8k requests to be
392 * outstanding to a home server, before something goes
397 rad_listen_t *listener;
400 * Mark the Fd's as unused.
402 for (i = 0; i < 32; i++) proxy_fds[i] = -1;
404 for (listener = mainconfig.listen;
406 listener = listener->next) {
407 if (listener->type == RAD_LISTEN_PROXY) {
408 proxy_fds[listener->fd & 0x1f] = listener->fd;
409 proxy_listeners[listener->fd & 0x1f] = listener;
418 static int rl_free_entry(void *ctx, void *data)
420 request_entry_t *next, *entry = data;
423 ctx = ctx; /* -Wunused */
425 for (entry = data; entry != NULL; entry = next) {
428 #ifdef HAVE_PTHREAD_H
430 * If someone is processing this request, kill
431 * them, and mark the request as not being used.
433 if (request->child_pid != NO_SUCH_CHILD_PID) {
434 pthread_kill(request->child_pid, SIGKILL);
435 request->child_pid = NO_SUCH_CHILD_PID;
438 request_free(&request);
439 if (entry != data) free(entry);
447 * Delete everything in the request list.
449 * This should be called only when debugging the server...
451 void rl_deinit(request_list_t *rl)
456 rbtree_free(proxy_tree);
459 rbtree_free(proxy_id_tree);
460 proxy_id_tree = NULL;
464 * Delete everything in the table, too.
466 lrad_hash_table_walk(rl->ht, rl_free_entry, NULL);
468 lrad_hash_table_free(rl->ht);
472 * Just to ensure no one is using the memory.
474 memset(rl, 0, sizeof(*rl));
479 * Delete a request from the proxy trees.
481 static void rl_delete_proxy(REQUEST *request, rbnode_t *node)
483 proxy_id_t myid, *entry;
485 rad_assert(node != NULL);
487 rbtree_delete(proxy_tree, node);
489 myid.dst_ipaddr = request->proxy->dst_ipaddr;
490 myid.dst_port = request->proxy->dst_port;
493 * Find the Id in the array of allocated Id's,
496 entry = rbtree_finddata(proxy_id_tree, &myid);
501 DEBUG3(" proxy: de-allocating destination %s port %d - Id %d",
502 inet_ntop(entry->dst_ipaddr.af,
503 &entry->dst_ipaddr.ipaddr, buf, sizeof(buf)),
508 * Find the proxy socket associated with this
509 * Id. We loop over all 32 proxy fd's, but we
510 * partially index by proxy fd's, which means
511 * that we almost always break out of the loop
514 for (i = 0; i < 32; i++) {
517 offset = (request->proxy->sockfd + i) & 0x1f;
519 if (proxy_fds[offset] == request->proxy->sockfd) {
521 entry->id[request->proxy->id] &= ~(1 << offset);
524 } /* else die horribly? */
529 * Hmm... not sure what to do here.
531 DEBUG3(" proxy: FAILED TO FIND destination %s port %d - Id %d",
532 inet_ntop(myid.dst_ipaddr.af,
533 &myid.dst_ipaddr.ipaddr, buf, sizeof(buf)),
541 * Yank a request from the tree, without free'ing it.
543 void rl_yank(request_list_t *rl, REQUEST *request)
545 request_entry_t *entry;
549 * Update the SNMP statistics.
551 * Note that we do NOT do this in rad_respond(),
552 * as that function is called from child threads.
553 * Instead, we update the stats when a request is
554 * deleted, because only the main server thread calls
557 if (mainconfig.do_snmp) {
558 switch (request->reply->code) {
559 case PW_AUTHENTICATION_ACK:
560 rad_snmp.auth.total_responses++;
561 rad_snmp.auth.total_access_accepts++;
564 case PW_AUTHENTICATION_REJECT:
565 rad_snmp.auth.total_responses++;
566 rad_snmp.auth.total_access_rejects++;
569 case PW_ACCESS_CHALLENGE:
570 rad_snmp.auth.total_responses++;
571 rad_snmp.auth.total_access_challenges++;
574 case PW_ACCOUNTING_RESPONSE:
575 rad_snmp.acct.total_responses++;
585 * Delete the request from the list.
587 entry = lrad_hash_table_finddata(rl->ht, request->packet->hash);
590 * The entry managed by the hash table is being deleted.
592 if (entry->request == request) {
594 request_entry_t *next = entry->next;
595 entry->next = next->next;
596 entry->request = next->request;
599 rad_assert(rl->collisions > 0);
602 lrad_hash_table_delete(rl->ht, request->packet->hash);
605 } else { /* a secondary entry is being deleted */
606 request_entry_t *this, *next, **last;
609 for (this = entry->next; this != NULL; this = next) {
612 if (this->request != request) {
620 rad_assert(rl->collisions > 0);
628 * If there's a proxied packet, and we're still
629 * waiting for a reply, then delete the packet
630 * from the list of outstanding proxied requests.
632 if (request->proxy &&
633 (request->proxy_outstanding > 0)) {
635 pthread_mutex_lock(&proxy_mutex);
636 node = rbtree_find(proxy_tree, request);
637 rl_delete_proxy(request, node);
638 pthread_mutex_unlock(&proxy_mutex);
644 * Delete a request from the tree.
646 void rl_delete(request_list_t *rl, REQUEST *request)
648 rl_yank(rl, request);
649 request_free(&request);
654 * Add a request to the request list.
656 int rl_add(request_list_t *rl, REQUEST *request)
658 request_entry_t *entry, myentry;
660 entry = lrad_hash_table_finddata(rl->ht, request->packet->hash);
663 myentry.request = request;
664 return lrad_hash_table_insert(rl->ht, request->packet->hash,
669 * Collision: insert it into a linked list (yuck)
671 entry->next = rad_malloc(sizeof(*entry));
672 entry->next->next = NULL;
673 entry->next->request = request;
675 DEBUG3(" FYI: hash collision...");
683 * Look up a particular request, using:
685 * Request ID, request code, source IP, source port,
687 * Note that we do NOT use the request vector to look up requests.
689 * We MUST NOT have two requests with identical (id/code/IP/port), and
690 * different vectors. This is a serious error!
692 REQUEST *rl_find(request_list_t *rl, RADIUS_PACKET *packet)
694 request_entry_t *entry;
698 entry = lrad_hash_table_finddata(rl->ht, packet->hash);
699 if (!entry) return NULL;
702 * Call a packet comparison function?
704 while (entry && !packet_cmp(packet, entry->request->packet)) {
708 if (!entry) return NULL;
710 return entry->request;
714 * Add an entry to the proxy tree.
716 * This is the ONLY function in this source file which may be called
717 * from a child thread. It therefore needs mutexes...
719 int rl_add_proxy(REQUEST *request)
723 proxy_id_t myid, *entry;
726 myid.dst_ipaddr = request->proxy->dst_ipaddr;
727 myid.dst_port = request->proxy->dst_port;
730 * Proxied requests get sent out the proxy FD ONLY.
732 * FIXME: Once we allocate multiple proxy FD's, move this
733 * code to below, so we can have more than 256 requests
736 request->proxy_outstanding = 1;
738 pthread_mutex_lock(&proxy_mutex);
743 entry = rbtree_finddata(proxy_id_tree, &myid);
744 if (!entry) { /* allocate it */
745 entry = rad_malloc(sizeof(*entry) + sizeof(entry->id) * 255);
747 entry->dst_ipaddr = request->proxy->dst_ipaddr;
748 entry->dst_port = request->proxy->dst_port;
751 DEBUG3(" proxy: creating destination %s port %d",
752 inet_ntop(entry->dst_ipaddr.af,
753 &entry->dst_ipaddr.ipaddr, buf, sizeof(buf)),
757 * Insert the new home server entry into
760 * FIXME: We don't (currently) delete the
761 * entries, so this is technically a
764 if (rbtree_insert(proxy_id_tree, entry) == 0) {
765 pthread_mutex_unlock(&proxy_mutex);
766 DEBUG2("ERROR: Failed to insert entry into proxy Id tree");
772 * Clear out bits in the array which DO have
773 * proxy Fd's associated with them. We do this
774 * by getting the mask of bits which have proxy
777 for (i = 0; i < 32; i++) {
778 if (proxy_fds[i] != -1) {
782 rad_assert(mask != 0);
785 * Set bits here indicate that the Fd is in use.
792 * Set the bits which are unused (and therefore
793 * allocated). The clear bits indicate that the Id
794 * for that FD is unused.
796 for (i = 0; i < 256; i++) {
799 } /* else the entry already existed in the proxy Id tree */
803 * Try to find a free Id.
806 for (i = 0; i < 256; i++) {
808 * Some bits are still zero..
810 if (entry->id[(i + entry->index) & 0xff] != (uint32_t) ~0) {
811 found = (i + entry->index) & 0xff;
816 * Hmm... do we want to re-use Id's, when we
817 * haven't seen all of the responses?
822 * No free Id, try to get a new FD.
825 rad_listen_t *proxy_listener;
828 * First, see if there were FD's recently allocated,
829 * which we don't know about.
832 for (i = 0; i < 32; i++) {
833 if (proxy_fds[i] < 0) continue;
839 * There ARE more FD's than we know about.
840 * Update the masks for Id's, and re-try.
842 if (entry->mask != mask) {
844 * New mask always has more bits than
845 * the old one, but never fewer bits.
847 rad_assert((entry->mask & mask) == entry->mask);
850 * Clear the bits we already know about,
851 * and then or in those bits into the
859 * Clear the bits in the Id's for the new
862 for (i = 0; i < 256; i++) {
863 entry->id[i] &= mask;
867 * And try again to allocate an Id.
870 } /* else no new Fd's were allocated. */
873 * If all Fd's are allocated, die.
876 pthread_mutex_unlock(&proxy_mutex);
877 radlog(L_ERR|L_CONS, "ERROR: More than 8000 proxied requests outstanding for destination %s port %d",
878 inet_ntop(entry->dst_ipaddr.af,
879 &entry->dst_ipaddr.ipaddr,
886 * Allocate a new proxy Fd. This function adds it
887 * into the list of listeners.
889 proxy_listener = proxy_new_listener();
890 if (!proxy_listener) {
891 pthread_mutex_unlock(&proxy_mutex);
892 DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
900 proxy = proxy_listener->fd;
901 for (i = 0; i < 32; i++) {
903 * Found a free entry. Save the socket,
904 * and remember where we saved it.
906 if (proxy_fds[(proxy + i) & 0x1f] == -1) {
907 proxy_fds[(proxy + i) & 0x1f] = proxy;
908 found = (proxy + i) & 0x1f;
912 rad_assert(found >= 0); /* i.e. the mask had free bits. */
919 * Clear the relevant bits in the mask.
921 for (i = 0; i < 256; i++) {
922 entry->id[i] &= mask;
926 * Pick a random Id to start from, as we've
927 * just guaranteed that it's free.
929 found = lrad_rand() & 0xff;
933 * Mark next (hopefully unused) entry.
935 entry->index = (found + 1) & 0xff;
938 * We now have to find WHICH proxy fd to use.
941 for (i = 0; i < 32; i++) {
943 * FIXME: pick a random socket to use?
945 if ((entry->id[found] & (1 << i)) == 0) {
952 * There was no bit clear, which we had just checked above...
954 rad_assert(proxy != -1);
957 * Mark the Id as allocated, for thei Fd.
959 entry->id[found] |= (1 << proxy);
960 request->proxy->id = found;
962 rad_assert(proxy_fds[proxy] != -1);
963 request->proxy->sockfd = proxy_fds[proxy];
964 request->proxy_listener = proxy_listeners[proxy];
966 DEBUG3(" proxy: allocating destination %s port %d - Id %d",
967 inet_ntop(entry->dst_ipaddr.af,
968 &entry->dst_ipaddr.ipaddr, buf, sizeof(buf)),
972 if (!rbtree_insert(proxy_tree, request)) {
973 pthread_mutex_unlock(&proxy_mutex);
974 DEBUG2("ERROR: Failed to insert entry into proxy tree");
978 pthread_mutex_unlock(&proxy_mutex);
985 * Look up a particular request, using:
987 * Request Id, request code, source IP, source port,
989 * Note that we do NOT use the request vector to look up requests.
991 * We MUST NOT have two requests with identical (id/code/IP/port), and
992 * different vectors. This is a serious error!
994 REQUEST *rl_find_proxy(RADIUS_PACKET *packet)
997 REQUEST myrequest, *maybe = NULL;
998 RADIUS_PACKET myproxy;
1001 * If we use the socket FD as an indicator,
1002 * then that implicitely contains information
1003 * as to our src ipaddr/port, so we don't need
1004 * to use that in the comparisons.
1006 myproxy.sockfd = packet->sockfd;
1007 myproxy.id = packet->id;
1008 myproxy.dst_ipaddr = packet->src_ipaddr;
1009 myproxy.dst_port = packet->src_port;
1012 myrequest.magic = REQUEST_MAGIC;
1014 myrequest.proxy = &myproxy;
1016 pthread_mutex_lock(&proxy_mutex);
1017 node = rbtree_find(proxy_tree, &myrequest);
1020 maybe = rbtree_node2data(proxy_tree, node);
1021 rad_assert(maybe->proxy_outstanding > 0);
1022 maybe->proxy_outstanding--;
1025 * Received all of the replies we expect.
1026 * delete it from both trees.
1028 if (maybe->proxy_outstanding == 0) {
1029 rl_delete_proxy(&myrequest, node);
1032 pthread_mutex_unlock(&proxy_mutex);
1039 * Return the number of requests in the request list.
1041 int rl_num_requests(request_list_t *rl)
1043 return lrad_hash_table_num_elements(rl->ht) + rl->collisions;
1048 * See also radiusd.c
1050 #define SLEEP_FOREVER (65536)
1051 typedef struct rl_walk_t {
1059 * Refresh a request, by using cleanup_delay, max_request_time, etc.
1061 * When walking over the request list, all of the per-request
1062 * magic is done here.
1064 static int refresh_request(void *ctx, void *data)
1067 rl_walk_t *info = (rl_walk_t *) ctx;
1068 child_pid_t child_pid;
1069 request_list_t *rl = info->rl;
1070 request_entry_t *entry = data;
1071 request_entry_t *next = entry->next;
1072 REQUEST *request = entry->request;
1074 if (next) refresh_request(ctx, next);
1076 rad_assert(request->magic == REQUEST_MAGIC);
1078 time_passed = (int) (info->now - request->timestamp);
1081 * If the request is marked as a delayed reject, AND it's
1082 * time to send the reject, then do so now.
1084 if (request->finished &&
1085 ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) != 0)) {
1086 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
1087 if (time_passed < mainconfig.reject_delay) {
1093 * Clear the 'delayed reject' bit, so that we
1094 * don't do this again, and fall through to
1095 * setting cleanup delay.
1097 request->listener->send(request->listener, request);
1098 request->options &= ~RAD_REQUEST_OPTION_DELAYED_REJECT;
1101 * FIXME: Beware interaction with cleanup_delay,
1102 * where we might send a reject, and immediately
1103 * there-after clean it up!
1108 * If the request is finished, AND more than cleanup_delay
1109 * seconds have passed since it was received, clean it up.
1111 * OR, if this is a request which had the "don't cache"
1112 * option set, then delete it immediately, as it CANNOT
1115 if ((request->finished &&
1116 (time_passed >= mainconfig.cleanup_delay)) ||
1117 ((request->options & RAD_REQUEST_OPTION_DONT_CACHE) != 0)) {
1118 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
1121 * Request completed, delete it, and unlink it
1122 * from the currently 'alive' list of requests.
1125 DEBUG2("Cleaning up request %d ID %d with timestamp %08lx",
1126 request->number, request->packet->id,
1127 (unsigned long) request->timestamp);
1130 * Delete the request.
1132 rl_delete(rl, request);
1137 * If more than max_request_time has passed since
1138 * we received the request, kill it.
1140 if (time_passed >= mainconfig.max_request_time) {
1143 child_pid = request->child_pid;
1144 number = request->number;
1147 * There MUST be a RAD_PACKET reply.
1149 rad_assert(request->reply != NULL);
1152 * If we've tried to proxy the request, and
1153 * the proxy server hasn't responded, then
1154 * we send a REJECT back to the caller.
1156 * For safety, we assert that there is no child
1157 * handling the request. If the assertion fails,
1158 * it means that we've sent a proxied request to
1159 * the home server, and the child thread is still
1160 * sitting on the request!
1162 if (request->proxy && !request->proxy_reply) {
1163 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
1165 radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",
1167 client_name_old(&request->packet->src_ipaddr),
1168 request->packet->src_port);
1169 request_reject(request, REQUEST_FAIL_HOME_SERVER);
1170 request->finished = TRUE;
1174 if (mainconfig.kill_unresponsive_children) {
1175 if (child_pid != NO_SUCH_CHILD_PID) {
1177 * This request seems to have hung
1180 #ifdef HAVE_PTHREAD_H
1181 radlog(L_ERR, "Killing unresponsive thread for request %d",
1183 pthread_cancel(child_pid);
1185 } /* else no proxy reply, quietly fail */
1188 * Maybe we haven't killed it. In that
1189 * case, print a warning.
1191 } else if ((child_pid != NO_SUCH_CHILD_PID) &&
1192 ((request->options & RAD_REQUEST_OPTION_LOGGED_CHILD) == 0)) {
1193 radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d",
1194 (unsigned long)child_pid, number);
1197 * Set the option that we've sent a log message,
1198 * so that we don't send more than one message
1201 request->options |= RAD_REQUEST_OPTION_LOGGED_CHILD;
1205 * Send a reject message for the request, mark it
1206 * finished, and forget about the child.
1208 request_reject(request, REQUEST_FAIL_SERVER_TIMEOUT);
1210 request->child_pid = NO_SUCH_CHILD_PID;
1212 if (mainconfig.kill_unresponsive_children)
1213 request->finished = TRUE;
1215 } /* else the request is still allowed to be in the queue */
1218 * If the request is finished, set the cleanup delay.
1220 if (request->finished) {
1221 time_passed = mainconfig.cleanup_delay - time_passed;
1226 * Set reject delay, if appropriate.
1228 if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
1229 (mainconfig.reject_delay > 0)) {
1231 time_passed = mainconfig.reject_delay - time_passed;
1234 * This catches a corner case, apparently.
1236 if ((request->reply->code == PW_AUTHENTICATION_REJECT) &&
1237 (time_passed == 0)) goto reject_packet;
1238 if (time_passed == 0) time_passed = 1;
1243 * Accounting requests are always proxied
1244 * asynchronously, authentication requests are
1245 * always proxied synchronously.
1247 if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
1248 (request->proxy && !request->proxy_reply) &&
1249 (info->now != request->proxy_start_time)) {
1251 * We've tried to send it, but the home server
1254 if (request->proxy_try_count == 0) {
1255 request_reject(request, REQUEST_FAIL_HOME_SERVER2);
1256 rad_assert(request->proxy->dst_ipaddr.af == AF_INET);
1257 request->finished = TRUE;
1258 goto cleanup; /* delete the request & continue */
1262 * Figure out how long we have to wait before
1263 * sending a re-transmit.
1265 time_passed = (info->now - request->proxy_start_time) % mainconfig.proxy_retry_delay;
1266 if (time_passed == 0) {
1268 vp = pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME);
1270 vp = paircreate(PW_ACCT_DELAY_TIME,
1273 radlog(L_ERR|L_CONS, "no memory");
1276 pairadd(&request->proxy->vps, vp);
1277 vp->lvalue = info->now - request->proxy_start_time;
1279 vp->lvalue += mainconfig.proxy_retry_delay;
1283 * This function takes care of re-transmits.
1285 request->proxy_listener->send(request->proxy_listener, request);
1286 request->proxy_try_count--;
1288 time_passed = mainconfig.proxy_retry_delay - time_passed;
1293 * The request is still alive, wake up when it's
1296 time_passed = mainconfig.max_request_time - time_passed;
1299 if (time_passed < info->sleep_time) {
1300 info->sleep_time = time_passed;
1308 * Clean up the request list, every so often.
1310 * This is done by walking through ALL of the list, and
1311 * - marking any requests which are finished, and expired
1312 * - killing any processes which are NOT finished after a delay
1313 * - deleting any marked requests.
1315 * Returns the number of millisends to sleep, before processing
1318 int rl_clean_list(request_list_t *rl, time_t now)
1323 info.sleep_time = SLEEP_FOREVER;
1326 lrad_hash_table_walk(rl->ht, refresh_request, &info);
1328 if (info.sleep_time < 0) info.sleep_time = 0;
1330 return info.sleep_time;