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 The FreeRADIUS server project
25 * The functions in this file must be called ONLY from radiusd.c,
26 * in the main server processing thread. These functions are NOT
30 static const char rcsid[] = "$Id$";
33 #include "libradius.h"
39 #include "rad_assert.h"
40 #include "request_list.h"
41 #include "radius_snmp.h"
45 * We keep the incoming requests in an array, indexed by ID.
47 * Each array element contains a linked list of containers of
48 * active requests, a count of the number of requests, and a time
49 * at which the first request in the list must be serviced.
52 typedef struct REQNODE {
53 struct REQNODE *prev, *next;
57 typedef struct REQUESTINFO {
58 REQNODE *first_request;
59 REQNODE *last_request;
61 time_t last_cleaned_list;
64 static REQUESTINFO request_list[256];
70 * It MAY make more sense here to key off of the packet ID, just
71 * like the request_list. Then again, saving another 8 lookups
72 * (on average) isn't much of a problem.
74 * The "request_cmp" function keys off of the packet ID first,
75 * so the first 8 layers of the tree will be the fanned-out
76 * tree for packet ID's.
78 static rbtree_t *request_tree;
81 static pthread_mutex_t proxy_mutex;
84 * This is easier than ifdef's throughout the code.
86 #define pthread_mutex_lock(_x)
87 #define pthread_mutex_unlock(_x)
89 static rbtree_t *proxy_tree;
92 * Compare two REQUEST data structures, based on a number
95 static int request_cmp(const void *one, const void *two)
97 const REQUEST *a = one;
98 const REQUEST *b = two;
101 * The following code looks unreasonable, but it's
102 * the only way to make the comparisons work.
104 if (a->packet->id < b->packet->id) return -1;
105 if (a->packet->id > b->packet->id) return +1;
107 if (a->packet->code < b->packet->code) return -1;
108 if (a->packet->code > b->packet->code) return +1;
110 if (a->packet->src_ipaddr < b->packet->src_ipaddr) return -1;
111 if (a->packet->src_ipaddr > b->packet->src_ipaddr) return +1;
113 if (a->packet->src_port < b->packet->src_port) return -1;
114 if (a->packet->src_port > b->packet->src_port) return +1;
116 if (a->packet->dst_ipaddr < b->packet->dst_ipaddr) return -1;
117 if (a->packet->dst_ipaddr > b->packet->dst_ipaddr) return +1;
119 if (a->packet->dst_port < b->packet->dst_port) return -1;
120 if (a->packet->dst_port > b->packet->dst_port) return +1;
123 * Everything's equal. Say so.
129 * Compare two REQUEST data structures, based on a number
130 * of criteria, for proxied packets.
132 static int proxy_cmp(const void *one, const void *two)
134 const REQUEST *a = one;
135 const REQUEST *b = two;
137 rad_assert(a->proxy != NULL);
138 rad_assert(b->proxy != NULL);
141 * The following code looks unreasonable, but it's
142 * the only way to make the comparisons work.
144 if (a->proxy->id < b->proxy->id) return -1;
145 if (a->proxy->id > b->proxy->id) return +1;
148 * Crap... we've got to check packet codes, too.
153 * FIXME: Add later, when we have multiple sockets
154 * for proxied requests.
156 if (a->proxy->src_ipaddr < b->proxy->src_ipaddr) return -1;
157 if (a->proxy->src_ipaddr > b->proxy->src_ipaddr) return +1;
159 if (a->proxy->src_port < b->proxy->src_port) return -1;
160 if (a->proxy->src_port > b->proxy->src_port) return +1;
163 if (a->proxy->dst_ipaddr < b->proxy->dst_ipaddr) return -1;
164 if (a->proxy->dst_ipaddr > b->proxy->dst_ipaddr) return +1;
166 if (a->proxy->dst_port < b->proxy->dst_port) return -1;
167 if (a->proxy->dst_port > b->proxy->dst_port) return +1;
170 * Everything's equal. Say so.
178 * Remember the next request at which we start walking
181 static REQUEST *last_request = NULL;
185 * Initialize the request list.
192 * Initialize the request_list[] array.
194 for (i = 0; i < 256; i++) {
195 request_list[i].first_request = NULL;
196 request_list[i].last_request = NULL;
197 request_list[i].request_count = 0;
198 request_list[i].last_cleaned_list = 0;
202 request_tree = rbtree_create(request_cmp, NULL, 0);
204 rad_assert("FAIL" == NULL);
207 proxy_tree = rbtree_create(proxy_cmp, NULL, 0);
209 rad_assert("FAIL" == NULL);
212 #ifndef HAVE_PTHREAD_H
214 * For now, always create the mutex.
216 * Later, we can only create it if there are multiple threads.
218 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
219 radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
230 * Delete a particular request.
232 void rl_delete(REQUEST *request)
235 REQNODE *prev, *next;
237 prev = ((REQNODE *) request->container)->prev;
238 next = ((REQNODE *) request->container)->next;
240 id = request->packet->id;
243 * Update the last request we touched.
245 * This is so the periodic "walk & clean list"
246 * function, below, doesn't walk over all requests
247 * all of the time. Rather, it tries to amortize
250 if (last_request == request) {
251 last_request = rl_next(last_request);
256 request_list[id].first_request = next;
262 request_list[id].last_request = prev;
267 free(request->container);
271 * Update the SNMP statistics.
273 * Note that we do NOT do this in rad_respond(),
274 * as that function is called from child threads.
275 * Instead, we update the stats when a request is
276 * deleted, because only the main server thread calls
279 if (mainconfig.do_snmp) {
280 switch (request->reply->code) {
281 case PW_AUTHENTICATION_ACK:
282 rad_snmp.auth.total_responses++;
283 rad_snmp.auth.total_access_accepts++;
286 case PW_AUTHENTICATION_REJECT:
287 rad_snmp.auth.total_responses++;
288 rad_snmp.auth.total_access_rejects++;
291 case PW_ACCESS_CHALLENGE:
292 rad_snmp.auth.total_responses++;
293 rad_snmp.auth.total_access_challenges++;
296 case PW_ACCOUNTING_RESPONSE:
297 rad_snmp.acct.total_responses++;
308 * Delete the request from the tree.
313 node = rbtree_find(request_tree, request);
314 rad_assert(node != NULL);
315 rbtree_delete(request_tree, node);
319 * Delete it from the proxy tree, too.
321 if (request->proxy) {
322 pthread_mutex_lock(&proxy_mutex);
323 node = rbtree_find(proxy_tree, request);
324 if (node) rbtree_delete(proxy_tree, node);
325 pthread_mutex_unlock(&proxy_mutex);
329 * For paranoia. Delete when the RBTREE code
332 DEBUG2(" Trees: %d %d\n",
333 rbtree_num_elements(request_tree),
334 rbtree_num_elements(proxy_tree));
339 request_free(&request);
340 request_list[id].request_count--;
345 * Add a request to the request list.
347 void rl_add(REQUEST *request)
349 int id = request->packet->id;
352 rad_assert(request->container == NULL);
354 request->container = rad_malloc(sizeof(REQNODE));
355 node = (REQNODE *) request->container;
361 if (!request_list[id].first_request) {
362 rad_assert(request_list[id].request_count == 0);
364 request_list[id].first_request = node;
365 request_list[id].last_request = node;
367 rad_assert(request_list[id].request_count != 0);
369 node->prev = request_list[id].last_request;
370 request_list[id].last_request->next = node;
371 request_list[id].last_request = node;
376 * Insert the request into the tree.
378 if (rbtree_insert(request_tree, request) == 0) {
379 rad_assert("FAIL" == NULL);
383 request_list[id].request_count++;
387 * Look up a particular request, using:
389 * Request ID, request code, source IP, source port,
391 * Note that we do NOT use the request vector to look up requests.
393 * We MUST NOT have two requests with identical (id/code/IP/port), and
394 * different vectors. This is a serious error!
396 REQUEST *rl_find(RADIUS_PACKET *packet)
401 myrequest.packet = packet;
403 return rbtree_finddata(request_tree, &myrequest);
407 for (curreq = request_list[packet->id].first_request;
409 curreq = ((REQNODE *)curreq->req->container)->next) {
411 * FIXME: Check destination IP and port, too?
413 * Can the same client send different packets
414 * from the same source IP/port to two different
415 * sockets on the server?
417 * YES: If the server has multiple IP's, and the
418 * NAS thinks it's doing load balancing to two
419 * different servers..
421 if ((curreq->req->packet->code == packet->code) &&
422 (curreq->req->packet->src_ipaddr == packet->src_ipaddr) &&
423 (curreq->req->packet->src_port == packet->src_port)) {
434 * Add an entry to the proxy tree.
436 void rl_add_proxy(REQUEST *request)
439 pthread_mutex_lock(&proxy_mutex);
442 * FIXME: Do magic to assign ID's, etc.
445 if (!rbtree_insert(proxy_tree, request)) {
446 rad_assert("FAILED" == 0);
449 pthread_mutex_unlock(&proxy_mutex);
459 * Look up a particular request, using:
461 * Request Id, request code, source IP, source port,
463 * Note that we do NOT use the request vector to look up requests.
465 * We MUST NOT have two requests with identical (id/code/IP/port), and
466 * different vectors. This is a serious error!
468 REQUEST *rl_find_proxy(RADIUS_PACKET *packet)
471 REQUEST myrequest, *maybe = NULL;
472 RADIUS_PACKET myproxy;
475 myrequest.proxy = &myproxy;
477 myproxy.id = packet->id;
480 * FIXME: Look for BOTH src/dst stuff.
482 myproxy.dst_ipaddr = packet->src_ipaddr;
483 myproxy.dst_port = packet->src_port;
485 pthread_mutex_lock(&proxy_mutex);
486 node = rbtree_find(proxy_tree, &myrequest);
488 maybe = rbtree_node2data(proxy_tree, node);
489 rbtree_delete(proxy_tree, node);
491 pthread_mutex_unlock(&proxy_mutex);
494 REQNODE *curreq = NULL;
498 * The Proxy RADIUS Id is completely independent
499 * of the original request Id. We've got to root through
500 * *all* requests, in order to find it.
502 * FIXME: Maybe we want to use the original packet Id
503 * as the Proxy-State?
505 for (id = 0; (id < 256) && (curreq == NULL); id++) {
506 for (curreq = request_list[id].first_request;
508 curreq = curreq->next) {
509 if (curreq->req->proxy &&
510 (curreq->req->proxy->id == packet->id) &&
511 (curreq->req->proxy->dst_ipaddr == packet->src_ipaddr) &&
512 (curreq->req->proxy->dst_port == packet->src_port)) {
515 } /* loop over all requests for this id. */
516 } /* loop over all id's... this is horribly inefficient */
522 * Walk over all requests, performing a callback for each request.
524 int rl_walk(RL_WALK_FUNC walker, void *data)
527 REQNODE *curreq, *next;
530 * Walk over all 256 ID's.
532 for (id = 0; id < 256; id++) {
535 * Walk over the request list for each ID.
537 for (curreq = request_list[id].first_request;
541 * The callback MIGHT delete the current
542 * request, so we CANNOT depend on curreq->next
543 * to be there, when going to the next element
548 rcode = walker(curreq->req, data);
549 if (rcode != RL_WALK_CONTINUE) {
559 * Walk from one request to the next.
561 REQUEST *rl_next(REQUEST *request)
567 * If we were passed a request, then go to the "next" one.
569 if (request != NULL) {
570 rad_assert(request->magic == REQUEST_MAGIC);
573 * It has a "next", return it.
575 if (((REQNODE *)request->container)->next != NULL) {
576 return ((REQNODE *)request->container)->next->req;
579 * No "next", increment the ID, and look
582 start_id = request->packet->id + 1;
588 * No input request, start looking at ID 0.
595 * Check all ID's, wrapping around at 255.
597 for (id = start_id; id < (start_id + count); id++) {
600 * This ID has a request, return it.
602 if (request_list[id & 0xff].first_request != NULL) {
603 rad_assert(request_list[id&0xff].first_request->req != request);
605 return request_list[id & 0xff].first_request->req;
610 * No requests at all in the list. Nothing to do.
612 DEBUG2("rl_next: returning NULL");
617 * Return the number of requests in the request list.
619 int rl_num_requests(void)
622 int request_count = 0;
624 for (id = 0; id < 256; id++) {
625 request_count += request_list[id].request_count;
628 return request_count;
631 typedef struct rl_walk_t {
638 * Refresh a request, by using proxy_retry_delay, cleanup_delay,
639 * max_request_time, etc.
641 * When walking over the request list, all of the per-request
642 * magic is done here.
644 static int refresh_request(REQUEST *request, void *data)
646 rl_walk_t *info = (rl_walk_t *) data;
648 child_pid_t child_pid;
650 rad_assert(request->magic == REQUEST_MAGIC);
653 * If the request is marked as a delayed reject, AND it's
654 * time to send the reject, then do so now.
656 if (request->finished &&
657 ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) != 0)) {
658 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
660 difference = info->now - request->timestamp;
661 if (difference >= (time_t) mainconfig.reject_delay) {
664 * Clear the 'delayed reject' bit, so that we
665 * don't do this again.
667 request->options &= ~RAD_REQUEST_OPTION_DELAYED_REJECT;
668 rad_send(request->reply, request->packet,
674 * If the request has finished processing, AND it's child has
675 * been cleaned up, AND it's time to clean up the request,
676 * OR, it's an accounting request. THEN, go delete it.
678 * If this is a request which had the "don't cache" option
679 * set, then delete it immediately, as it CANNOT have a
682 if (request->finished &&
683 ((request->timestamp + mainconfig.cleanup_delay <= info->now) ||
684 ((request->options & RAD_REQUEST_OPTION_DONT_CACHE) != 0))) {
685 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
688 * Request completed, delete it, and unlink it
689 * from the currently 'alive' list of requests.
691 DEBUG2("Cleaning up request %d ID %d with timestamp %08lx",
692 request->number, request->packet->id,
693 (unsigned long) request->timestamp);
696 * Delete the request.
699 return RL_WALK_CONTINUE;
703 * Maybe the child process handling the request has hung:
704 * kill it, and continue.
706 if ((request->timestamp + mainconfig.max_request_time) <= info->now) {
709 child_pid = request->child_pid;
710 number = request->number;
713 * There MUST be a RAD_PACKET reply.
715 rad_assert(request->reply != NULL);
718 * If we've tried to proxy the request, and
719 * the proxy server hasn't responded, then
720 * we send a REJECT back to the caller.
722 * For safety, we assert that there is no child
723 * handling the request. If the assertion fails,
724 * it means that we've sent a proxied request to
725 * the home server, and the child thread is still
726 * sitting on the request!
728 if (request->proxy && !request->proxy_reply) {
729 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
731 radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s:%d",
733 client_name(request->packet->src_ipaddr),
734 request->packet->src_port);
735 request_reject(request);
736 request->finished = TRUE;
737 return RL_WALK_CONTINUE;
740 if (mainconfig.kill_unresponsive_children) {
741 if (child_pid != NO_SUCH_CHILD_PID) {
743 * This request seems to have hung
746 #ifdef HAVE_PTHREAD_H
747 radlog(L_ERR, "Killing unresponsive thread for request %d",
749 pthread_cancel(child_pid);
751 } /* else no proxy reply, quietly fail */
754 * Maybe we haven't killed it. In that
755 * case, print a warning.
757 } else if ((child_pid != NO_SUCH_CHILD_PID) &&
758 ((request->options & RAD_REQUEST_OPTION_LOGGED_CHILD) == 0)) {
759 radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d",
760 (unsigned long)child_pid, number);
763 * Set the option that we've sent a log message,
764 * so that we don't send more than one message
767 request->options |= RAD_REQUEST_OPTION_LOGGED_CHILD;
771 * Send a reject message for the request, mark it
772 * finished, and forget about the child.
774 request_reject(request);
775 request->child_pid = NO_SUCH_CHILD_PID;
776 if (mainconfig.kill_unresponsive_children)
777 request->finished = TRUE;
778 return RL_WALK_CONTINUE;
779 } /* the request has been in the queue for too long */
782 * If the request is still being processed, then due to the
783 * above check, it's still within it's time limit. In that
784 * case, don't do anything.
786 if (request->child_pid != NO_SUCH_CHILD_PID) {
787 return RL_WALK_CONTINUE;
791 * The request is finished.
793 if (request->finished) goto setup_timeout;
796 * We're not proxying requests at all.
798 if (!mainconfig.proxy_requests) goto setup_timeout;
801 * We're proxying synchronously, so we don't retry it here.
802 * Some other code takes care of retrying the proxy requests.
804 if (mainconfig.proxy_synchronous) goto setup_timeout;
807 * The proxy retry delay is zero, meaning don't retry.
809 if (mainconfig.proxy_retry_delay == 0) goto setup_timeout;
812 * There is no proxied request for this packet, so there's
815 if (!request->proxy) goto setup_timeout;
818 * We've already seen the proxy reply, so we don't need
819 * to send another proxy request.
821 if (request->proxy_reply) goto setup_timeout;
824 * It's not yet time to re-send this proxied request.
826 if (request->proxy_next_try > info->now) goto setup_timeout;
829 * If the proxy retry count is zero, then
830 * we've sent the last try, and have NOT received
831 * a reply from the end server. In that case,
832 * we don't bother trying again, but just mark
833 * the request as finished, and go to the next one.
835 if (request->proxy_try_count == 0) {
836 rad_assert(request->child_pid == NO_SUCH_CHILD_PID);
837 request_reject(request);
838 realm_disable(request->proxy->dst_ipaddr,request->proxy->dst_port);
839 request->finished = TRUE;
844 * We're trying one more time, so count down
845 * the tries, and set the next try time.
847 request->proxy_try_count--;
848 request->proxy_next_try = info->now + mainconfig.proxy_retry_delay;
850 /* Fix up Acct-Delay-Time */
851 if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
852 VALUE_PAIR *delaypair;
853 delaypair = pairfind(request->proxy->vps, PW_ACCT_DELAY_TIME);
856 delaypair = paircreate(PW_ACCT_DELAY_TIME, PW_TYPE_INTEGER);
858 radlog(L_ERR|L_CONS, "no memory");
861 pairadd(&request->proxy->vps, delaypair);
863 delaypair->lvalue = info->now - request->proxy->timestamp;
865 /* Must recompile the valuepairs to wire format */
866 free(request->proxy->data);
867 request->proxy->data = NULL;
868 } /* proxy accounting request */
871 * Assert that we have NOT seen the proxy reply yet.
873 * If we HAVE seen it, then we SHOULD NOT be bugging the
876 rad_assert(request->proxy_reply == NULL);
879 * Send the proxy packet.
881 rad_send(request->proxy, NULL, request->proxysecret);
885 * Don't do more long-term checks, if we've got to wake
888 if (info->smallest == 0) {
889 return RL_WALK_CONTINUE;
893 * The request is finished. Wake up when it's time to
896 if (request->finished) {
897 difference = (request->timestamp + mainconfig.cleanup_delay) - info->now;
900 * If the request is marked up to be rejected later,
901 * then wake up later.
903 if ((request->options & RAD_REQUEST_OPTION_DELAYED_REJECT) != 0) {
904 if (difference >= (time_t) mainconfig.reject_delay) {
905 difference = (time_t) mainconfig.reject_delay;
909 } else if (request->proxy && !request->proxy_reply) {
911 * The request is NOT finished, but there is an
912 * outstanding proxy request, with no matching
915 * Wake up when it's time to re-send
918 * But in synchronous proxy, we don't retry but we update
919 * the next retry time as NAS has not resent the request
920 * in the given retry window.
922 if (mainconfig.proxy_synchronous) {
923 request->proxy_next_try = info->now + mainconfig.proxy_retry_delay;
925 difference = request->proxy_next_try - info->now;
928 * The request is NOT finished.
930 * Wake up when it's time to kill the errant
933 difference = (request->timestamp + mainconfig.max_request_time) - info->now;
937 * If the server is CPU starved, then we CAN miss a time
938 * for servicing requests. In which case the 'difference'
939 * value will be negative. select() doesn't like that,
942 if (difference < 0) {
947 * Update the 'smallest' time.
949 if ((info->smallest < 0) ||
950 (difference < info->smallest)) {
951 info->smallest = difference;
954 return RL_WALK_CONTINUE;
959 * Clean up the request list, every so often.
961 * This is done by walking through ALL of the list, and
962 * - marking any requests which are finished, and expired
963 * - killing any processes which are NOT finished after a delay
964 * - deleting any marked requests.
966 struct timeval *rl_clean_list(time_t now)
969 * Static variables, so that we don't do all of this work
970 * more than once per second.
972 * Note that we have 'tv' and 'last_tv'. 'last_tv' is
973 * pointed to by 'last_tv_ptr', and depending on the
974 * system implementation of select(), it MAY be modified.
976 * In that was, we want to use the ORIGINAL value, from
977 * 'tv', and wipe out the (possibly modified) last_tv.
979 static time_t last_cleaned_list = 0;
980 static struct timeval tv, *last_tv_ptr = NULL;
981 static struct timeval last_tv;
989 * If we've already set up the timeout or cleaned the
990 * request list this second, then don't do it again. We
991 * simply return the sleep delay from last time.
993 * Note that if we returned NULL last time, there was nothing
994 * to do. BUT we've been woken up since then, which can only
995 * happen if we received a packet. And if we've received a
996 * packet, then there's some work to do in the future.
998 * FIXME: We can probably use gettimeofday() for finer clock
999 * resolution, as the current method will cause it to sleep
1002 if ((last_tv_ptr != NULL) &&
1003 (last_cleaned_list == now) &&
1008 * If we're NOT walking the entire request list,
1009 * then we want to iteratively check the request
1012 * If there is NO previous request, go look for one.
1015 last_request = rl_next(last_request);
1018 * On average, there will be one request per
1019 * 'cleanup_delay' requests, which needs to be
1022 * And only do this servicing, if we have a request
1026 for (i = 0; i < mainconfig.cleanup_delay; i++) {
1030 * This function call MAY delete the
1031 * request pointed to by 'last_request'.
1033 next = rl_next(last_request);
1034 refresh_request(last_request, &info);
1035 last_request = next;
1038 * Nothing to do any more, exit.
1045 DEBUG2("Waking up in %d seconds...",
1046 (int) last_tv_ptr->tv_sec);
1049 last_cleaned_list = now;
1050 last_request = NULL;
1051 DEBUG2("--- Walking the entire request list ---");
1054 * Hmmm... this is Big Magic. We make it seem like
1055 * there's an additional second to wait, for a whole
1056 * host of reasons which I can't explain adequately,
1057 * but which cause the code to Just Work Right.
1061 rl_walk(refresh_request, &info);
1064 * We haven't found a time at which we need to wake up.
1065 * Return NULL, so that the select() call will sleep forever.
1067 if (info.smallest < 0) {
1069 * If we're not proxying, then there really isn't anything
1072 * If we ARE proxying, then we can safely sleep
1073 * forever if we're told to NEVER send proxy retries
1074 * ourselves, until the NAS kicks us again.
1076 * Otherwise, there are no outstanding requests, then
1077 * we can sleep forever. This happens when we get
1078 * woken up with a bad packet. It's discarded, so if
1079 * there are no live requests, we can safely sleep
1082 if ((!mainconfig.proxy_requests) ||
1083 mainconfig.proxy_synchronous ||
1084 (rl_num_requests() == 0)) {
1085 DEBUG2("Nothing to do. Sleeping until we see a request.");
1091 * We ARE proxying. In that case, we avoid a race condition
1092 * where a child thread handling a request proxies the
1093 * packet, and sets the retry delay. In that case, we're
1094 * supposed to wake up in N seconds, but we can't, as
1095 * we're sleeping forever.
1097 * Instead, we prevent the problem by waking up anyhow
1098 * at the 'proxy_retry_delay' time, even if there's
1099 * nothing to do. In the worst case, this will cause
1100 * the server to wake up every N seconds, to do a small
1101 * amount of unnecessary work.
1103 info.smallest = mainconfig.proxy_retry_delay;
1106 * Set the time (in seconds) for how long we're
1107 * supposed to sleep.
1109 tv.tv_sec = info.smallest;
1111 DEBUG2("Waking up in %d seconds...", (int) info.smallest);
1114 * Remember how long we should sleep for.
1117 last_tv_ptr = &last_tv;