Make request->number unsigned
[freeradius.git] / src / main / event.c
1 /*
2  * event.c      Server event handling
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2007  The FreeRADIUS server project
21  * Copyright 2007  Alan DeKok <aland@deployingradius.com>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29 #include <freeradius-devel/event.h>
30 #include <freeradius-devel/detail.h>
31
32 #include <freeradius-devel/rad_assert.h>
33
34 #include <signal.h>
35 #include <fcntl.h>
36
37 #ifdef HAVE_SYS_WAIT_H
38 #       include <sys/wait.h>
39 #endif
40
41 #define USEC (1000000)
42
43 extern pid_t radius_pid;
44 extern int dont_fork;
45 extern int check_config;
46 extern char *debug_condition;
47
48 /*
49  *      Ridiculous amounts of local state.
50  */
51 static fr_event_list_t  *el = NULL;
52 static fr_packet_list_t *pl = NULL;
53 static int                      request_num_counter = 0;
54 static struct timeval           now;
55 time_t                          fr_start_time;
56 static int                      have_children;
57 static int                      just_started = TRUE;
58
59 #ifndef __MINGW32__
60 #ifdef HAVE_PTHREAD_H
61 #define WITH_SELF_PIPE (1)
62 #endif
63 #endif
64
65 #ifdef WITH_SELF_PIPE
66 static int self_pipe[2];
67 #endif
68
69 #ifdef HAVE_PTHREAD_H
70 #ifdef WITH_PROXY
71 static pthread_mutex_t  proxy_mutex;
72 #endif
73
74 #define PTHREAD_MUTEX_LOCK if (have_children) pthread_mutex_lock
75 #define PTHREAD_MUTEX_UNLOCK if (have_children) pthread_mutex_unlock
76
77 static pthread_t NO_SUCH_CHILD_PID;
78 #else
79 /*
80  *      This is easier than ifdef's throughout the code.
81  */
82 #define PTHREAD_MUTEX_LOCK(_x)
83 #define PTHREAD_MUTEX_UNLOCK(_x)
84 int thread_pool_addrequest(REQUEST *request, RAD_REQUEST_FUNP fun)
85 {
86         radius_handle_request(request, fun);
87         return 1;
88 }
89 #endif
90
91 #define INSERT_EVENT(_function, _ctx) if (!fr_event_insert(el, _function, _ctx, &((_ctx)->when), &((_ctx)->ev))) { _rad_panic(__FILE__, __LINE__, "Failed to insert event"); }
92
93 #ifdef WITH_PROXY
94 static fr_packet_list_t *proxy_list = NULL;
95
96 /*
97  *      We keep the proxy FD's here.  The RADIUS Id's are marked
98  *      "allocated" per Id, via a bit per proxy FD.
99  */
100 static int              proxy_all_used = FALSE;
101 static int              proxy_fds[32];
102 static rad_listen_t     *proxy_listeners[32];
103 static void check_for_zombie_home_server(REQUEST *request);
104 #else
105 #define remove_from_proxy_hash(foo)
106 #endif
107
108 static void request_post_handler(REQUEST *request);
109 static void wait_a_bit(void *ctx);
110 static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd, void *ctx);
111 #ifdef WITH_DETAIL
112 static void event_poll_detail(void *ctx);
113 #endif
114
115 static void NEVER_RETURNS _rad_panic(const char *file, unsigned int line,
116                                     const char *msg)
117 {
118         radlog(L_ERR, "[%s:%d] %s", file, line, msg);
119         _exit(1);
120 }
121
122 #define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
123
124
125 static void tv_add(struct timeval *tv, int usec_delay)
126 {
127         if (usec_delay > USEC) {
128                 tv->tv_sec += usec_delay / USEC;
129                 usec_delay %= USEC;
130         }
131         tv->tv_usec += usec_delay;
132
133         if (tv->tv_usec > USEC) {
134                 tv->tv_sec += tv->tv_usec / USEC;
135                 tv->tv_usec %= USEC;
136         }
137 }
138
139 static void remove_from_request_hash(REQUEST *request)
140 {
141         if (!request->in_request_hash) return;
142
143         fr_packet_list_yank(pl, request->packet);
144         request->in_request_hash = FALSE;
145
146         request_stats_final(request);
147 }
148
149
150 #ifdef WITH_PROXY
151 static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply)
152 {
153         RADIUS_PACKET **proxy_p;
154         REQUEST *request;
155
156         PTHREAD_MUTEX_LOCK(&proxy_mutex);
157         proxy_p = fr_packet_list_find_byreply(proxy_list, reply);
158
159         if (!proxy_p) {
160                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
161                 return NULL;
162         }
163
164         request = fr_packet2myptr(REQUEST, proxy, proxy_p);
165
166         if (!request) {
167                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
168                 return NULL;
169         }
170
171         request->num_proxied_responses++;
172
173         /*
174          *      Catch the most common case of everything working
175          *      correctly.
176          */
177         if (request->num_proxied_requests == request->num_proxied_responses) {
178                 fr_packet_list_yank(proxy_list, request->proxy);
179                 fr_packet_list_id_free(proxy_list, request->proxy);
180                 request->in_proxy_hash = FALSE;
181         }
182
183         /*
184          *      On the FIRST reply, decrement the count of outstanding
185          *      requests.  Note that this is NOT the count of sent
186          *      packets, but whether or not the home server has
187          *      responded at all.
188          */
189         if (!request->proxy_reply &&
190             request->home_server &&
191             request->home_server->currently_outstanding) {
192                 request->home_server->currently_outstanding--;
193         }
194
195         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
196
197         return request;
198 }
199
200
201 static void remove_from_proxy_hash(REQUEST *request)
202 {
203         /*
204          *      Check this without grabbing the mutex because it's a
205          *      lot faster that way.
206          */
207         if (!request->in_proxy_hash) return;
208
209         /*
210          *      The "not in hash" flag is definitive.  However, if the
211          *      flag says that it IS in the hash, there might still be
212          *      a race condition where it isn't.
213          */
214         PTHREAD_MUTEX_LOCK(&proxy_mutex);
215
216         if (!request->in_proxy_hash) {
217                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
218                 return;
219         }
220
221         fr_packet_list_yank(proxy_list, request->proxy);
222         fr_packet_list_id_free(proxy_list, request->proxy);
223
224         /*
225          *      The home server hasn't replied, but we've given up on
226          *      this request.  Don't count this request against the
227          *      home server.
228          */
229         if (!request->proxy_reply &&
230             request->home_server &&
231             request->home_server->currently_outstanding) {
232                 request->home_server->currently_outstanding--;
233         }
234
235         /*
236          *      Got from YES in hash, to NO, not in hash while we hold
237          *      the mutex.  This guarantees that when another thread
238          *      grans the mutex, the "not in hash" flag is correct.
239          */
240         request->in_proxy_hash = FALSE;
241
242         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
243 }
244
245 static void ev_request_free(REQUEST **prequest)
246 {
247         REQUEST *request;
248         
249         if (!prequest || !*prequest) return;
250
251         request = *prequest;
252
253 #ifdef WITH_COA
254         if (request->coa) {
255                 /*
256                  *      Divorce the child from the parent first,
257                  *      then clean up the child.
258                  */
259                 request->coa->parent = NULL;
260                 ev_request_free(&request->coa);
261         }
262
263         /*
264          *      Divorce the parent from the child, and leave the
265          *      parent still alive.
266          */
267         if (request->parent && (request->parent->coa == request)) {
268                 request->parent->coa = NULL;
269         }
270 #endif
271
272         if (request->ev) fr_event_delete(el, &request->ev);
273         if (request->in_proxy_hash) remove_from_proxy_hash(request);
274         if (request->in_request_hash) remove_from_request_hash(request);
275
276         request_free(prequest);
277 }
278
279 static int proxy_id_alloc(REQUEST *request, RADIUS_PACKET *packet)
280 {
281         int i, proxy, found;
282         rad_listen_t *proxy_listener;
283
284         if (fr_packet_list_id_alloc(proxy_list, packet)) return 1;
285
286         if (proxy_all_used) return 0;
287
288         /*
289          *      Allocate a new proxy fd.  This function adds
290          *      it to the tail of the list of listeners.  With
291          *      some care, this can be thread-safe.
292          */
293         proxy_listener = proxy_new_listener(&packet->src_ipaddr, FALSE);
294         if (!proxy_listener) {
295                 radlog(L_PROXY, "Failed to create a new socket for proxying requests.");
296                 return 0;
297         }
298         
299         /*
300          *      Cache it locally.
301          */
302         found = -1;
303         proxy = proxy_listener->fd;
304         for (i = 0; i < 32; i++) {
305                 /*
306                  *      Found a free entry.  Save the socket,
307                  *      and remember where we saved it.
308                  */
309                 if (proxy_fds[(proxy + i) & 0x1f] == -1) {
310                         found = (proxy + i) & 0x1f;
311                         proxy_fds[found] = proxy;
312                         proxy_listeners[found] = proxy_listener;
313                         break;
314                 }
315         }
316         if (found < 0) {
317                 proxy_all_used = TRUE;
318                 listen_free(&proxy_listener);
319                 radlog(L_ERR, "Failed creating new proxy socket: server is too busy and home servers appear to be down");
320                 return 0;
321         }
322
323         
324         if (!fr_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
325                         RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
326                 return 0;
327                 
328         }
329         
330         if (!fr_packet_list_id_alloc(proxy_list, packet)) {
331                         RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
332                 return 0;
333         }
334         
335         /*
336          *      Signal the main thread to add the new FD to the list
337          *      of listening FD's.
338          */
339         radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
340         return 1;
341 }
342
343
344 static int insert_into_proxy_hash(REQUEST *request, int retransmit)
345 {
346         int i, proxy;
347         char buf[128];
348
349         rad_assert(request->proxy != NULL);
350         rad_assert(proxy_list != NULL);
351
352         PTHREAD_MUTEX_LOCK(&proxy_mutex);
353
354         /*
355          *      Keep track of maximum outstanding requests to a
356          *      particular home server.  'max_outstanding' is
357          *      enforced in home_server_ldb(), in realms.c.
358          */
359         if (request->home_server) {
360                 request->home_server->currently_outstanding++;
361         }
362
363         if (retransmit) {
364                 RADIUS_PACKET packet;
365
366                 packet = *request->proxy;
367
368                 if (!proxy_id_alloc(request, &packet)) {
369                         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
370                         return 0;
371                 }
372
373                 /*
374                  *      Yank the request, free the old Id, and
375                  *      remember the new Id.
376                  */
377                 fr_packet_list_yank(proxy_list, request->proxy);
378                 fr_packet_list_id_free(proxy_list, request->proxy);
379                 *request->proxy = packet;
380
381         } else if (!proxy_id_alloc(request, request->proxy)) {
382                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
383                 return 0;
384         }
385
386         rad_assert(request->proxy->sockfd >= 0);
387
388         /*
389          *      FIXME: Hack until we get rid of rad_listen_t, and put
390          *      the information into the packet_list.
391          */
392         proxy = -1;
393         for (i = 0; i < 32; i++) {
394                 if (proxy_fds[i] == request->proxy->sockfd) {
395                         proxy = i;
396                         break;
397                 }
398         }
399
400         if (proxy < 0) {
401                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
402                 RDEBUG2("ERROR: All sockets are full.");
403                 return 0;
404         }
405
406         rad_assert(proxy_fds[proxy] != -1);
407         rad_assert(proxy_listeners[proxy] != NULL);
408         request->proxy_listener = proxy_listeners[proxy];
409
410         if (!fr_packet_list_insert(proxy_list, &request->proxy)) {
411                 fr_packet_list_id_free(proxy_list, request->proxy);
412                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
413                 RDEBUG2("ERROR: Failed to insert entry into proxy list");
414                 return 0;
415         }
416
417         request->in_proxy_hash = TRUE;
418
419         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
420
421         RDEBUG3(" proxy: allocating destination %s port %d - Id %d",
422                inet_ntop(request->proxy->dst_ipaddr.af,
423                          &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
424                request->proxy->dst_port,
425                request->proxy->id);
426
427         return 1;
428 }
429
430
431 /*
432  *      Called as BOTH an event, and in-line from other functions.
433  */
434 static void wait_for_proxy_id_to_expire(void *ctx)
435 {
436         REQUEST *request = ctx;
437
438         rad_assert(request->magic == REQUEST_MAGIC);
439         rad_assert(request->proxy != NULL);
440
441         if (!fr_event_now(el, &now)) gettimeofday(&now, NULL);
442         request->when = request->proxy_when;
443
444 #ifdef WITH_COA
445         if (((request->proxy->code == PW_COA_REQUEST) ||
446              (request->proxy->code == PW_DISCONNECT_REQUEST)) &&
447             (request->packet->code != request->proxy->code)) {
448                 request->when.tv_sec += request->home_server->coa_mrd;
449         } else
450 #endif
451         request->when.tv_sec += request->home_server->response_window;
452
453         if ((request->num_proxied_requests == request->num_proxied_responses) ||
454             timercmp(&now, &request->when, >)) {
455                 if (request->packet) {
456                         RDEBUG2("Cleaning up request %u ID %d with timestamp +%d",
457                                request->number, request->packet->id,
458                                (unsigned int) (request->timestamp - fr_start_time));
459                 } else {
460                         RDEBUG2("Cleaning up request %u with timestamp +%d",
461                                request->number,
462                                (unsigned int) (request->timestamp - fr_start_time));
463                 }
464
465                 ev_request_free(&request);
466                 return;
467         }
468
469         INSERT_EVENT(wait_for_proxy_id_to_expire, request);
470 }
471 #endif
472
473 #ifdef HAVE_PTHREAD_H
474 static void wait_for_child_to_die(void *ctx)
475 {
476         REQUEST *request = ctx;
477
478         rad_assert(request->magic == REQUEST_MAGIC);
479
480         /*
481          *      If it's still queued (waiting for a thread to pick it
482          *      up) OR, it's running AND there's still a child thread
483          *      handling it, THEN delay some more.
484          */
485         if ((request->child_state == REQUEST_QUEUED) ||
486             ((request->child_state == REQUEST_RUNNING) &&
487              (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0))) {
488
489                 /*
490                  *      Cap delay at five minutes.
491                  */
492                 if (request->delay < (USEC * 60 * 5)) {
493                         request->delay += (request->delay >> 1);
494                         radlog(L_INFO, "WARNING: Child is hung for request %u in component %s module %s.",
495                                request->number, request->component, request->module);
496                 } else {
497                         RDEBUG2("Child is still stuck for request %u",
498                                 request->number);
499                 }
500                 tv_add(&request->when, request->delay);
501
502                 INSERT_EVENT(wait_for_child_to_die, request);
503                 return;
504         }
505
506         RDEBUG2("Child is finally responsive for request %u", request->number);
507         remove_from_request_hash(request);
508
509 #ifdef WITH_PROXY
510         if (request->proxy) {
511                 wait_for_proxy_id_to_expire(request);
512                 return;
513         }
514 #endif
515
516         ev_request_free(&request);
517 }
518 #endif
519
520 static void cleanup_delay(void *ctx)
521 {
522         REQUEST *request = ctx;
523
524         rad_assert(request->magic == REQUEST_MAGIC);
525         rad_assert((request->child_state == REQUEST_CLEANUP_DELAY) ||
526                    (request->child_state == REQUEST_DONE));
527
528         remove_from_request_hash(request);
529
530 #ifdef WITH_PROXY
531         if (request->proxy && request->in_proxy_hash) {
532                 wait_for_proxy_id_to_expire(request);
533                 return;
534         }
535 #endif
536
537         RDEBUG2("Cleaning up request %u ID %d with timestamp +%d",
538                request->number, request->packet->id,
539                (unsigned int) (request->timestamp - fr_start_time));
540
541         ev_request_free(&request);
542 }
543
544
545 /*
546  *      In daemon mode, AND this request has debug flags set.
547  */
548 #define DEBUG_PACKET if (!debug_flag && request->options && request->radlog) debug_packet
549
550 static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, int direction)
551 {
552         VALUE_PAIR *vp;
553         char buffer[1024];
554         const char *received, *from;
555         const fr_ipaddr_t *ip;
556         int port;
557
558         if (!packet) return;
559
560         rad_assert(request->radlog != NULL);
561
562         if (direction == 0) {
563                 received = "Received";
564                 from = "from";  /* what else? */
565                 ip = &packet->src_ipaddr;
566                 port = packet->src_port;
567
568         } else {
569                 received = "Sending";
570                 from = "to";    /* hah! */
571                 ip = &packet->dst_ipaddr;
572                 port = packet->dst_port;
573         }
574         
575         /*
576          *      Client-specific debugging re-prints the input
577          *      packet into the client log.
578          *
579          *      This really belongs in a utility library
580          */
581         if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
582                 RDEBUG("%s %s packet %s host %s port %d, id=%d, length=%d",
583                        received, fr_packet_codes[packet->code], from,
584                        inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
585                        port, packet->id, packet->data_len);
586         } else {
587                 RDEBUG("%s packet %s host %s port %d code=%d, id=%d, length=%d",
588                        received, from,
589                        inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
590                        port,
591                        packet->code, packet->id, packet->data_len);
592         }
593
594         for (vp = packet->vps; vp != NULL; vp = vp->next) {
595                 vp_prints(buffer, sizeof(buffer), vp);
596                 request->radlog(L_DBG, 0, request, "\t%s", buffer);
597         }
598 }
599
600 static void reject_delay(void *ctx)
601 {
602         REQUEST *request = ctx;
603
604         rad_assert(request->magic == REQUEST_MAGIC);
605         rad_assert(request->child_state == REQUEST_REJECT_DELAY);
606
607         RDEBUG2("Sending delayed reject for request %u", request->number);
608
609         DEBUG_PACKET(request, request->reply, 1);
610
611         request->listener->send(request->listener, request);
612
613         request->when.tv_sec += request->root->cleanup_delay;
614         request->child_state = REQUEST_CLEANUP_DELAY;
615
616         INSERT_EVENT(cleanup_delay, request);
617 }
618
619
620 #ifdef WITH_PROXY
621 void revive_home_server(void *ctx)
622 {
623         home_server *home = ctx;
624         char buffer[128];
625
626         home->state = HOME_STATE_ALIVE;
627         home->currently_outstanding = 0;
628         home->revive_time = now;
629
630         /*
631          *      Delete any outstanding events.
632          */
633         if (home->ev) fr_event_delete(el, &home->ev);
634
635         radlog(L_PROXY, "Marking home server %s port %d alive again... we have no idea if it really is alive or not.",
636                inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
637                          buffer, sizeof(buffer)),
638                home->port);
639
640 }
641
642
643 static void no_response_to_ping(void *ctx)
644 {
645         REQUEST *request = ctx;
646         home_server *home;
647         char buffer[128];
648
649         rad_assert(request->home_server != NULL);
650
651         home = request->home_server;
652         home->num_received_pings = 0;
653
654         radlog(L_ERR, "No response to status check %d for home server %s port %d",
655                request->number,
656                inet_ntop(request->proxy->dst_ipaddr.af,
657                          &request->proxy->dst_ipaddr.ipaddr,
658                          buffer, sizeof(buffer)),
659                request->proxy->dst_port);
660
661         check_for_zombie_home_server(request);
662
663         wait_for_proxy_id_to_expire(request);
664 }
665
666
667 static void received_response_to_ping(REQUEST *request)
668 {
669         home_server *home;
670         char buffer[128];
671
672         rad_assert(request->home_server != NULL);
673
674         home = request->home_server;
675         home->num_received_pings++;
676
677         radlog(L_PROXY, "Received response to status check %d (%d in current sequence)",
678                request->number, home->num_received_pings);
679
680         /*
681          *      Remove the request from any hashes
682          */
683         fr_event_delete(el, &request->ev);
684         remove_from_proxy_hash(request);
685         rad_assert(request->in_request_hash == FALSE);
686
687         /*
688          *      The control socket may have marked the home server as
689          *      alive.  OR, it may have suddenly started responding to
690          *      requests again.  If so, don't re-do the "make alive"
691          *      work.
692          */
693         if (home->state == HOME_STATE_ALIVE) return;
694
695         /*
696          *      We haven't received enough ping responses to mark it
697          *      "alive".  Wait a bit.
698          */
699         if (home->num_received_pings < home->num_pings_to_alive) {
700                 return;
701         }
702
703         home->state = HOME_STATE_ALIVE;
704         home->currently_outstanding = 0;
705         home->revive_time = now;
706
707         if (!fr_event_delete(el, &home->ev)) {
708                 RDEBUG2("Hmm... no event for home server.  Oh well.");
709         }
710
711         radlog(L_PROXY, "Marking home server %s port %d alive",
712                inet_ntop(request->proxy->dst_ipaddr.af,
713                          &request->proxy->dst_ipaddr.ipaddr,
714                          buffer, sizeof(buffer)),
715                request->proxy->dst_port);
716 }
717
718
719 /*
720  *      Called from start of zombie period, OR after control socket
721  *      marks the home server dead.
722  */
723 static void ping_home_server(void *ctx)
724 {
725         uint32_t jitter;
726         home_server *home = ctx;
727         REQUEST *request;
728         VALUE_PAIR *vp;
729
730         if ((home->state == HOME_STATE_ALIVE) ||
731             (home->ping_check == HOME_PING_CHECK_NONE) ||
732             (home->ev != NULL)) {
733                 return;
734         }
735
736         request = request_alloc();
737         request->number = request_num_counter++;
738
739         request->proxy = rad_alloc(1);
740         rad_assert(request->proxy != NULL);
741
742         fr_event_now(el, &request->when);
743         home->when = request->when;
744
745         if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
746                 request->proxy->code = PW_STATUS_SERVER;
747
748                 radius_pairmake(request, &request->proxy->vps,
749                                 "Message-Authenticator", "0x00", T_OP_SET);
750
751         } else if (home->type == HOME_TYPE_AUTH) {
752                 request->proxy->code = PW_AUTHENTICATION_REQUEST;
753
754                 radius_pairmake(request, &request->proxy->vps,
755                                 "User-Name", home->ping_user_name, T_OP_SET);
756                 radius_pairmake(request, &request->proxy->vps,
757                                 "User-Password", home->ping_user_password, T_OP_SET);
758                 radius_pairmake(request, &request->proxy->vps,
759                                 "Service-Type", "Authenticate-Only", T_OP_SET);
760                 radius_pairmake(request, &request->proxy->vps,
761                                 "Message-Authenticator", "0x00", T_OP_SET);
762
763         } else {
764 #ifdef WITH_ACCOUNTING
765                 request->proxy->code = PW_ACCOUNTING_REQUEST;
766                 
767                 radius_pairmake(request, &request->proxy->vps,
768                                 "User-Name", home->ping_user_name, T_OP_SET);
769                 radius_pairmake(request, &request->proxy->vps,
770                                 "Acct-Status-Type", "Stop", T_OP_SET);
771                 radius_pairmake(request, &request->proxy->vps,
772                                 "Acct-Session-Id", "00000000", T_OP_SET);
773                 vp = radius_pairmake(request, &request->proxy->vps,
774                                      "Event-Timestamp", "0", T_OP_SET);
775                 vp->vp_date = now.tv_sec;
776 #else
777                 rad_assert("Internal sanity check failed");
778 #endif
779         }
780
781         radius_pairmake(request, &request->proxy->vps,
782                         "NAS-Identifier", "Status Check. Are you alive?",
783                         T_OP_SET);
784
785         request->proxy->dst_ipaddr = home->ipaddr;
786         request->proxy->dst_port = home->port;
787         request->home_server = home;
788
789         rad_assert(request->proxy_listener == NULL);
790
791         if (!insert_into_proxy_hash(request, FALSE)) {
792                 RDEBUG2("ERROR: Failed inserting status check %d into proxy hash.  Discarding it.",
793                        request->number);
794                 ev_request_free(&request);
795                 return;
796         }
797         rad_assert(request->proxy_listener != NULL);
798         request->proxy_listener->send(request->proxy_listener,
799                                       request);
800
801         request->next_callback = NULL;
802         request->child_state = REQUEST_PROXIED;
803         gettimeofday(&request->when, NULL);
804         home->when = request->when;
805         request->when.tv_sec += home->ping_timeout;;
806
807         INSERT_EVENT(no_response_to_ping, request);
808
809         /*
810          *      Add +/- 2s of jitter, as suggested in RFC 3539
811          *      and in the Issues and Fixes draft.
812          */
813         home->when.tv_sec += home->ping_interval - 2;
814
815         jitter = fr_rand();
816         jitter ^= (jitter >> 10);
817         jitter &= ((1 << 23) - 1); /* 22 bits of 1 */
818
819         tv_add(&home->when, jitter);
820
821         INSERT_EVENT(ping_home_server, home);
822 }
823
824
825 void mark_home_server_dead(home_server *home, struct timeval *when)
826 {
827         int previous_state = home->state;
828         char buffer[128];
829
830         radlog(L_PROXY, "Marking home server %s port %d as dead.",
831                inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
832                          buffer, sizeof(buffer)),
833                home->port);
834
835         home->state = HOME_STATE_IS_DEAD;
836         home->num_received_pings = 0;
837
838         if (home->ping_check != HOME_PING_CHECK_NONE) {
839                 /*
840                  *      If the control socket marks us dead, start
841                  *      pinging.  Otherwise, we already started
842                  *      pinging when it was marked "zombie".
843                  */
844                 if (previous_state == HOME_STATE_ALIVE) {
845                         ping_home_server(home);
846                 }
847
848         } else {
849                 /*
850                  *      Revive it after a fixed period of time.  This
851                  *      is very, very, bad.
852                  */
853                 home->when = *when;
854                 home->when.tv_sec += home->revive_interval;
855
856                 INSERT_EVENT(revive_home_server, home);
857         }
858 }
859
860 static void check_for_zombie_home_server(REQUEST *request)
861 {
862         home_server *home;
863         struct timeval when;
864
865         home = request->home_server;
866
867         if (home->state != HOME_STATE_ZOMBIE) return;
868
869         when = home->zombie_period_start;
870         when.tv_sec += home->zombie_period;
871
872         fr_event_now(el, &now);
873         if (timercmp(&now, &when, <)) {
874                 return;
875         }
876
877         mark_home_server_dead(home, &request->when);
878 }
879
880 static int proxy_to_virtual_server(REQUEST *request);
881
882 static int virtual_server_handler(UNUSED REQUEST *request)
883 {
884         proxy_to_virtual_server(request);
885         return 0;
886 }
887
888 static void proxy_fallback_handler(REQUEST *request)
889 {
890         /*
891          *      A proper time is required for wait_a_bit.
892          */
893         request->delay = USEC / 10;
894         gettimeofday(&now, NULL);
895         request->next_when = now;
896         tv_add(&request->next_when, request->delay);
897         request->next_callback = wait_a_bit;
898
899         /*
900          *      Re-queue the request.
901          */
902         request->child_state = REQUEST_QUEUED;
903         
904         rad_assert(request->proxy != NULL);
905         if (!thread_pool_addrequest(request, virtual_server_handler)) {
906                 request->child_state = REQUEST_DONE;
907         }
908
909 #ifdef HAVE_PTHREAD_H
910         /*
911          *      MAY free the request if we're over max_request_time,
912          *      AND we're not in threaded mode!
913          *
914          *      Note that we call this ONLY if we're threaded, as
915          *      if we're NOT threaded, request_post_handler() calls
916          *      wait_a_bit(), which means that "request" may not
917          *      exist any more...
918          */
919         if (have_children) wait_a_bit(request);
920 #endif
921 }
922
923
924 static int setup_post_proxy_fail(REQUEST *request)
925 {
926         DICT_VALUE *dval = NULL;
927         VALUE_PAIR *vp;
928
929         request->child_state = REQUEST_RUNNING;
930
931         if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
932                 dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Authentication");
933
934         } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
935                 dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Accounting");
936
937 #ifdef WITH_COA
938                 /*
939                  *      See no_response_to_coa_request
940                  */
941         } else if (((request->packet->code >> 8) & 0xff) == PW_COA_REQUEST) {
942                 request->packet->code &= 0xff; /* restore it */
943
944                 if (request->proxy->code == PW_COA_REQUEST) {
945                         dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-CoA");
946
947                 } else if (request->proxy->code == PW_DISCONNECT_REQUEST) {
948                         dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail-Disconnect");
949                 } else {
950                         return 0;
951                 }
952
953 #endif
954         } else {
955                 return 0;
956         }
957
958         if (!dval) dval = dict_valbyname(PW_POST_PROXY_TYPE, "Fail");
959
960         if (!dval) {
961                 pairdelete(&request->config_items, PW_POST_PROXY_TYPE);
962                 return 0;
963         }
964
965         vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
966         if (!vp) vp = radius_paircreate(request, &request->config_items,
967                                         PW_POST_PROXY_TYPE, PW_TYPE_INTEGER);
968         vp->vp_integer = dval->value;
969
970         rad_assert(request->proxy_reply == NULL);
971
972         return 1;
973 }
974
975
976 static int null_handler(UNUSED REQUEST *request)
977 {
978         return 0;
979 }
980
981 static void post_proxy_fail_handler(REQUEST *request)
982 {
983         /*
984          *      A proper time is required for wait_a_bit.
985          */
986         request->delay = USEC / 10;
987         gettimeofday(&now, NULL);
988
989         /*
990          *      Not set up to run Post-Proxy-Type = Fail.
991          *
992          *      Mark the request as still running, and figure out what
993          *      to do next.
994          */
995         if (!setup_post_proxy_fail(request)) {
996                 request_post_handler(request);
997
998         } else {
999                 /*
1000                  *      Re-queue the request.
1001                  */
1002                 request->child_state = REQUEST_QUEUED;
1003
1004                 /*
1005                  *      There is a post-proxy-type of fail.  We run
1006                  *      the request through the pre/post proxy
1007                  *      handlers, just like it was a real proxied
1008                  *      request.  However, we set the per-request
1009                  *      handler to NULL, as we don't want to do
1010                  *      anything else.
1011                  *
1012                  *      Note that when we're not threaded, this will
1013                  *      process the request even if it's greater than
1014                  *      max_request_time.  That's not fatal.
1015                  */
1016                 request->priority = 0;
1017                 rad_assert(request->proxy != NULL);
1018                 thread_pool_addrequest(request, null_handler);
1019         }
1020
1021         /*
1022          *      MAY free the request if we're over max_request_time,
1023          *      AND we're not in threaded mode!
1024          *
1025          *      Note that we call this ONLY if we're threaded, as
1026          *      if we're NOT threaded, request_post_handler() calls
1027          *      wait_a_bit(), which means that "request" may not
1028          *      exist any more...
1029          */
1030         if (have_children) wait_a_bit(request);
1031 }
1032
1033
1034 /* maybe check this against wait_for_proxy_id_to_expire? */
1035 static void no_response_to_proxied_request(void *ctx)
1036 {
1037         REQUEST *request = ctx;
1038         home_server *home;
1039         char buffer[128];
1040
1041         rad_assert(request->magic == REQUEST_MAGIC);
1042         rad_assert(request->child_state == REQUEST_PROXIED);
1043
1044         /*
1045          *      If we've failed over to an internal home server,
1046          *      replace the callback with the correct one.  This
1047          *      is due to locking issues with child threads...
1048          */
1049         if (request->home_server->server) {
1050                 wait_a_bit(request);
1051                 return;
1052         }
1053
1054         check_for_zombie_home_server(request);
1055
1056         home = request->home_server;
1057
1058         /*
1059          *      The default as of 2.1.7 is to allow requests to
1060          *      fail-over to a backup home server when this one does
1061          *      not respond.  The old behavior can be configured as
1062          *      well.
1063          */
1064         if (home->no_response_fail) {
1065                 radlog(L_ERR, "Rejecting request %u (proxy Id %d) due to lack of any response from home server %s port %d",
1066                        request->number, request->proxy->id,
1067                        inet_ntop(request->proxy->dst_ipaddr.af,
1068                                  &request->proxy->dst_ipaddr.ipaddr,
1069                                  buffer, sizeof(buffer)),
1070                        request->proxy->dst_port);
1071
1072                 post_proxy_fail_handler(request);
1073         } else {
1074                 rad_assert(request->ev == NULL);
1075                 request->child_state = REQUEST_RUNNING;
1076                 wait_a_bit(request);
1077         }
1078
1079         /*
1080          *      Don't touch request due to race conditions
1081          */
1082         if (home->state == HOME_STATE_IS_DEAD) {
1083                 rad_assert(home->ev != NULL); /* or it will never wake up */
1084                 return;
1085         }
1086
1087         /*
1088          *      Enable the zombie period when we notice that the home
1089          *      server hasn't responded.  We do NOT back-date the start
1090          *      of the zombie period.
1091          */
1092         if (home->state == HOME_STATE_ALIVE) {
1093                 home->state = HOME_STATE_ZOMBIE;
1094                 home->zombie_period_start = now;        
1095                 fr_event_delete(el, &home->ev);
1096                 home->currently_outstanding = 0;
1097                 home->num_received_pings = 0;
1098
1099                 radlog(L_PROXY, "Marking home server %s port %d as zombie (it looks like it is dead).",
1100                        inet_ntop(home->ipaddr.af, &home->ipaddr.ipaddr,
1101                                  buffer, sizeof(buffer)),
1102                        home->port);
1103
1104                 /*
1105                  *      Start pinging the home server.
1106                  */
1107                 ping_home_server(home);
1108         }
1109 }
1110 #endif
1111
1112 static void wait_a_bit(void *ctx)
1113 {
1114         struct timeval when;
1115         REQUEST *request = ctx;
1116         fr_event_callback_t callback = NULL;
1117
1118         rad_assert(request->magic == REQUEST_MAGIC);
1119
1120 #ifdef WITH_COA
1121         /*
1122          *      The CoA request is a new (internally generated)
1123          *      request, created in a child thread.  We therefore need
1124          *      some way to tie its events back into the main event
1125          *      handler.
1126          */
1127         if (request->coa && !request->coa->proxy_reply &&
1128             request->coa->next_callback) {
1129                 request->coa->when = request->coa->next_when;
1130                 INSERT_EVENT(request->coa->next_callback, request->coa);
1131                 request->coa->next_callback = NULL;
1132                 request->coa->parent = NULL;
1133                 request->coa = NULL;
1134         }
1135 #endif
1136
1137         switch (request->child_state) {
1138         case REQUEST_QUEUED:
1139         case REQUEST_RUNNING:
1140                 when = request->received;
1141                 when.tv_sec += request->root->max_request_time;
1142
1143                 /*
1144                  *      Normally called from the event loop with the
1145                  *      proper event loop time.  Otherwise, called from
1146                  *      post proxy fail handler, which sets "now", and
1147                  *      this call won't re-set it, because we're not
1148                  *      in the event loop.
1149                  */
1150                 fr_event_now(el, &now);
1151
1152                 /*
1153                  *      Request still has more time.  Continue
1154                  *      waiting.
1155                  */
1156                 if (timercmp(&now, &when, <) ||
1157                     ((request->listener->type == RAD_LISTEN_DETAIL) &&
1158                      (request->child_state == REQUEST_QUEUED))) {
1159                         if (request->delay < (USEC / 10)) {
1160                                 request->delay = USEC / 10;
1161                         }
1162                         request->delay += request->delay >> 1;
1163
1164 #ifdef WITH_DETAIL
1165                         /*
1166                          *      Cap wait at some sane value for detail
1167                          *      files.
1168                          */
1169                         if ((request->listener->type == RAD_LISTEN_DETAIL) &&
1170                             (request->delay > (request->root->max_request_time * USEC))) {
1171                                 request->delay = request->root->max_request_time * USEC;
1172                         }
1173 #endif
1174
1175                         request->when = now;
1176                         tv_add(&request->when, request->delay);
1177                         callback = wait_a_bit;
1178                         break;
1179                 }
1180
1181 #if defined(HAVE_PTHREAD_H) || defined(WITH_PROXY)
1182                 /*
1183                  *      A child thread MAY still be running on the
1184                  *      request.  Ask the thread to stop working on
1185                  *      the request.
1186                  */
1187                 if (have_children &&
1188                     (pthread_equal(request->child_pid, NO_SUCH_CHILD_PID) == 0)) {
1189                         request->master_state = REQUEST_STOP_PROCESSING;
1190
1191                         radlog(L_ERR, "WARNING: Unresponsive child for request %u, in module %s component %s",
1192                                request->number,
1193                                request->module ? request->module : "<server core>",
1194                                request->component ? request->component : "<server core>");
1195                         
1196                         request->delay = USEC / 4;
1197                         tv_add(&request->when, request->delay);
1198                         callback = wait_for_child_to_die;
1199                         break;
1200                 }
1201 #endif
1202
1203                 /*
1204                  *      Else no child thread is processing the
1205                  *      request.  We probably should have just marked
1206                  *      the request as 'done' elsewhere, like in the
1207                  *      post-proxy-fail handler.  But doing that would
1208                  *      involve checking for max_request_time in
1209                  *      multiple places, so this may be simplest.
1210                  */
1211                 request->child_state = REQUEST_DONE;
1212                 /* FALL-THROUGH */
1213
1214                 /*
1215                  *      Mark the request as no longer running,
1216                  *      and clean it up.
1217                  */
1218         case REQUEST_DONE:
1219 #ifdef HAVE_PTHREAD_H
1220                 request->child_pid = NO_SUCH_CHILD_PID;
1221 #endif
1222
1223 #ifdef WTH_COA
1224                 /*
1225                  *      This is a CoA request.  It's been divorced
1226                  *      from everything else, so we clean it up now.
1227                  */
1228                 if (!request->in_request_hash &&
1229                     request->proxy &&
1230                     (request->packet->code != request->proxy->code) &&
1231                     ((request->proxy->code == PW_COA_REQUEST) ||
1232                      (request->proxy->code == PW_DISCONNECT_REQUEST))) {
1233                         /*
1234                          *      FIXME: Do CoA MIBs
1235                          */
1236                         ev_request_free(&request);
1237                         return;
1238                 }
1239 #endif
1240                 request_stats_final(request);
1241                 cleanup_delay(request);
1242                 return;
1243
1244         case REQUEST_REJECT_DELAY:
1245         case REQUEST_CLEANUP_DELAY:
1246 #ifdef HAVE_PTHREAD_H
1247                 request->child_pid = NO_SUCH_CHILD_PID;
1248 #endif
1249                 request_stats_final(request);
1250
1251         case REQUEST_PROXIED:
1252                 rad_assert(request->next_callback != NULL);
1253                 rad_assert(request->next_callback != wait_a_bit);
1254
1255                 request->when = request->next_when;
1256                 callback = request->next_callback;
1257                 request->next_callback = NULL;
1258                 break;
1259
1260         default:
1261                 rad_panic("Internal sanity check failure");
1262                 return;
1263         }
1264
1265         /*
1266          *      Something major went wrong.  Discard the request, and
1267          *      keep running.
1268          *
1269          *      FIXME: No idea why this happens or how to fix it...
1270          *      It seems to happen *only* when requests are proxied,
1271          *      and where the home server doesn't respond.  So it looks
1272          *      like a race condition above, but it happens in debug
1273          *      mode, with no threads...
1274          */
1275         if (!callback) {
1276                 RDEBUG("WARNING: Internal sanity check failed in event handler for request %u: Discarding the request!", request->number);
1277                 ev_request_free(&request);
1278                 return;
1279         }
1280
1281         INSERT_EVENT(callback, request);
1282 }
1283
1284 #ifdef WITH_COA
1285 static void no_response_to_coa_request(void *ctx)
1286 {
1287         REQUEST *request = ctx;
1288         char buffer[128];
1289
1290         rad_assert(request->magic == REQUEST_MAGIC);
1291         rad_assert(request->child_state == REQUEST_PROXIED);
1292         rad_assert(request->home_server != NULL);
1293         rad_assert(!request->in_request_hash);
1294
1295         radlog(L_ERR, "No response to CoA request sent to %s",
1296                inet_ntop(request->proxy->dst_ipaddr.af,
1297                          &request->proxy->dst_ipaddr.ipaddr,
1298                          buffer, sizeof(buffer)));
1299
1300         /*
1301          *      Hack.
1302          */
1303         request->packet->code |= (PW_COA_REQUEST << 8);
1304         post_proxy_fail_handler(request);
1305 }
1306
1307
1308 static int update_event_timestamp(RADIUS_PACKET *packet, time_t when)
1309 {
1310         VALUE_PAIR *vp;
1311
1312         vp = pairfind(packet->vps, PW_EVENT_TIMESTAMP);
1313         if (!vp) return 0;
1314
1315         vp->vp_date = when;
1316
1317         if (packet->data) {
1318                 free(packet->data);
1319                 packet->data = NULL;
1320                 packet->data_len = 0;
1321         }
1322
1323         return 1;               /* time stamp updated */
1324 }
1325
1326
1327 /*
1328  *      Called when we haven't received a response to a CoA request.
1329  */
1330 static void retransmit_coa_request(void *ctx)
1331 {
1332         int delay, frac;
1333         struct timeval mrd;
1334         REQUEST *request = ctx;
1335
1336         rad_assert(request->magic == REQUEST_MAGIC);
1337         rad_assert(request->child_state == REQUEST_PROXIED);
1338         rad_assert(request->home_server != NULL);
1339         rad_assert(!request->in_request_hash);
1340         rad_assert(request->parent == NULL);
1341         
1342         fr_event_now(el, &now);
1343
1344         /*
1345          *      Cap count at MRC, if it is non-zero.
1346          */
1347         if (request->home_server->coa_mrc &&
1348             (request->num_coa_requests >= request->home_server->coa_mrc)) {
1349                 no_response_to_coa_request(request);
1350                 return;
1351         }
1352
1353         /*
1354          *      RFC 5080 Section 2.2.1
1355          *
1356          *      RT = 2*RTprev + RAND*RTprev
1357          *         = 1.9 * RTprev + rand(0,.2) * RTprev
1358          *         = 1.9 * RTprev + rand(0,1) * (RTprev / 5)
1359          */
1360         delay = fr_rand();
1361         delay ^= (delay >> 16);
1362         delay &= 0xffff;
1363         frac = request->delay / 5;
1364         delay = ((frac >> 16) * delay) + (((frac & 0xffff) * delay) >> 16);
1365
1366         delay += (2 * request->delay) - (request->delay / 10);
1367
1368         /*
1369          *      Cap delay at MRT, if MRT is non-zero.
1370          */
1371         if (request->home_server->coa_mrt &&
1372             (delay > (request->home_server->coa_mrt * USEC))) {
1373                 int mrt_usec = request->home_server->coa_mrt * USEC;
1374
1375                 /*
1376                  *      delay = MRT + RAND * MRT
1377                  *            = 0.9 MRT + rand(0,.2)  * MRT
1378                  */
1379                 delay = fr_rand();
1380                 delay ^= (delay >> 15);
1381                 delay &= 0x1ffff;
1382                 delay = ((mrt_usec >> 16) * delay) + (((mrt_usec & 0xffff) * delay) >> 16);
1383                 delay += mrt_usec - (mrt_usec / 10);
1384         }
1385
1386         request->delay = delay;
1387         request->when = now;
1388         tv_add(&request->when, request->delay);
1389         mrd = request->proxy_when;
1390         mrd.tv_sec += request->home_server->coa_mrd;
1391
1392         /*
1393          *      Cap duration at MRD.
1394          */
1395         if (timercmp(&mrd, &request->when, <)) {
1396                 request->when = mrd;
1397                 INSERT_EVENT(no_response_to_coa_request, request);
1398
1399         } else {
1400                 INSERT_EVENT(retransmit_coa_request, request);
1401         }
1402         
1403         if (update_event_timestamp(request->proxy, now.tv_sec)) {
1404                 if (!insert_into_proxy_hash(request, TRUE)) {
1405                         DEBUG("ERROR: Failed re-inserting CoA request into proxy hash.");
1406                         return;
1407                 }
1408
1409                 request->num_proxied_requests = 0;
1410                 request->num_proxied_responses = 0;
1411         }
1412
1413         request->num_proxied_requests++;
1414         request->num_coa_requests++; /* is NOT reset by code 3 lines above! */
1415
1416         request->proxy_listener->send(request->proxy_listener,
1417                                       request);
1418 }
1419
1420
1421 /*
1422  *      The original request is either DONE, or in CLEANUP_DELAY.
1423  */
1424 static int originated_coa_request(REQUEST *request)
1425 {
1426         int delay, rcode, pre_proxy_type = 0;
1427         VALUE_PAIR *vp;
1428         REQUEST *coa;
1429         fr_ipaddr_t ipaddr;
1430         char buffer[256];
1431
1432         rad_assert(request->proxy == NULL);
1433         rad_assert(!request->in_proxy_hash);
1434         rad_assert(request->proxy_reply == NULL);
1435
1436         /*
1437          *      Check whether we want to originate one, or cancel one.
1438          */
1439         vp = pairfind(request->config_items, PW_SEND_COA_REQUEST);
1440         if (!vp && request->coa) {
1441                 vp = pairfind(request->coa->proxy->vps, PW_SEND_COA_REQUEST);
1442         }
1443
1444         if (vp) {
1445                 if (vp->vp_integer == 0) {
1446                         ev_request_free(&request->coa);
1447                         return 1;       /* success */
1448                 }
1449         }
1450
1451         if (!request->coa) request_alloc_coa(request);
1452         if (!request->coa) return 0;
1453
1454         coa = request->coa;
1455
1456         /*
1457          *      src_ipaddr will be set up in proxy_encode.
1458          */
1459         memset(&ipaddr, 0, sizeof(ipaddr));
1460         vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS);
1461         if (vp) {
1462                 ipaddr.af = AF_INET;
1463                 ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
1464
1465         } else if ((vp = pairfind(coa->proxy->vps,
1466                                   PW_PACKET_DST_IPV6_ADDRESS)) != NULL) {
1467                 ipaddr.af = AF_INET6;
1468                 ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
1469                 
1470         } else if ((vp = pairfind(coa->proxy->vps,
1471                                   PW_HOME_SERVER_POOL)) != NULL) {
1472                 coa->home_pool = home_pool_byname(vp->vp_strvalue,
1473                                                   HOME_TYPE_COA);
1474                 if (!coa->home_pool) {
1475                         RDEBUG2("WARNING: No such home_server_pool %s",
1476                                vp->vp_strvalue);
1477         fail:
1478                         ev_request_free(&request->coa);
1479                         return 0;
1480                 }
1481
1482                 /*
1483                  *      Prefer
1484                  */
1485         } else if (request->client->coa_pool) {
1486                 coa->home_pool = request->client->coa_pool;
1487
1488         } else if (request->client->coa_server) {
1489                 coa->home_server = request->client->coa_server;
1490
1491         } else {
1492                 /*
1493                  *      If all else fails, send it to the client that
1494                  *      originated this request.
1495                  */
1496                 memcpy(&ipaddr, &request->packet->src_ipaddr, sizeof(ipaddr));
1497         }
1498
1499         /*
1500          *      Use the pool, if it exists.
1501          */
1502         if (coa->home_pool) {
1503                 coa->home_server = home_server_ldb(NULL, coa->home_pool, coa);
1504                 if (!coa->home_server) {
1505                         RDEBUG("WARNING: No live home server for home_server_pool %s", vp->vp_strvalue);
1506                         goto fail;
1507                 }
1508
1509         } else if (!coa->home_server) {
1510                 int port = PW_COA_UDP_PORT;
1511
1512                 vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT);
1513                 if (vp) port = vp->vp_integer;
1514
1515                 coa->home_server = home_server_find(&ipaddr, port);
1516                 if (!coa->home_server) {
1517                         RDEBUG2("WARNING: Unknown destination %s:%d for CoA request.",
1518                                inet_ntop(ipaddr.af, &ipaddr.ipaddr,
1519                                          buffer, sizeof(buffer)), port);
1520                         goto fail;
1521                 }
1522         }
1523
1524         vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE);
1525         if (vp) {
1526                 switch (vp->vp_integer) {
1527                 case PW_COA_REQUEST:
1528                 case PW_DISCONNECT_REQUEST:
1529                         coa->proxy->code = vp->vp_integer;
1530                         break;
1531                         
1532                 default:
1533                         DEBUG("Cannot set CoA Packet-Type to code %d",
1534                               vp->vp_integer);
1535                         goto fail;
1536                 }
1537         }
1538
1539         if (!coa->proxy->code) coa->proxy->code = PW_COA_REQUEST;
1540
1541         /*
1542          *      The rest of the server code assumes that
1543          *      request->packet && request->reply exist.  Copy them
1544          *      from the original request.
1545          */
1546         rad_assert(coa->packet != NULL);
1547         rad_assert(coa->packet->vps == NULL);
1548         memcpy(coa->packet, request->packet, sizeof(*request->packet));
1549         coa->packet->vps = paircopy(request->packet->vps);
1550         coa->packet->data = NULL;
1551         rad_assert(coa->reply != NULL);
1552         rad_assert(coa->reply->vps == NULL);
1553         memcpy(coa->reply, request->reply, sizeof(*request->reply));
1554         coa->reply->vps = paircopy(request->reply->vps);
1555         coa->reply->data = NULL;
1556         coa->config_items = paircopy(request->config_items);
1557
1558         /*
1559          *      Call the pre-proxy routines.
1560          */
1561         vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
1562         if (vp) {
1563                 RDEBUG2("  Found Pre-Proxy-Type %s", vp->vp_strvalue);
1564                 pre_proxy_type = vp->vp_integer;
1565         }
1566
1567         if (coa->home_pool && coa->home_pool->virtual_server) {
1568                 const char *old_server = coa->server;
1569                 
1570                 coa->server = coa->home_pool->virtual_server;
1571                 RDEBUG2(" server %s {", coa->server);
1572                 rcode = module_pre_proxy(pre_proxy_type, coa);
1573                 RDEBUG2(" }");
1574                 coa->server = old_server;
1575         } else {
1576                 rcode = module_pre_proxy(pre_proxy_type, coa);
1577         }
1578         switch (rcode) {
1579         default:
1580                 goto fail;
1581
1582         /*
1583          *      Only send the CoA packet if the pre-proxy code succeeded.
1584          */
1585         case RLM_MODULE_NOOP:
1586         case RLM_MODULE_OK:
1587         case RLM_MODULE_UPDATED:
1588                 break;
1589         }
1590
1591         /*
1592          *      Source IP / port is set when the proxy socket
1593          *      is chosen.
1594          */
1595         coa->proxy->dst_ipaddr = coa->home_server->ipaddr;
1596         coa->proxy->dst_port = coa->home_server->port;
1597
1598         if (!insert_into_proxy_hash(coa, FALSE)) {
1599                 DEBUG("ERROR: Failed inserting CoA request into proxy hash.");
1600                 goto fail;
1601         }
1602
1603         /*
1604          *      We CANNOT divorce the CoA request from the parent
1605          *      request.  This function is running in a child thread,
1606          *      and we need access to the main event loop in order to
1607          *      to add the timers for the CoA packet.  See
1608          *      wait_a_bit().
1609          */
1610
1611         /*
1612          *      Forget about the original request completely at this
1613          *      point.
1614          */
1615         request = coa;
1616
1617         gettimeofday(&request->proxy_when, NULL);       
1618         request->received = request->next_when = request->proxy_when;
1619         rad_assert(request->proxy_reply == NULL);
1620
1621         /*
1622          *      Implement re-transmit algorithm as per RFC 5080
1623          *      Section 2.2.1.
1624          *
1625          *      We want IRT + RAND*IRT
1626          *      or 0.9 IRT + rand(0,.2) IRT
1627          *
1628          *      2^20 ~ USEC, and we want 2.
1629          *      rand(0,0.2) USEC ~ (rand(0,2^21) / 10)
1630          */
1631         delay = (fr_rand() & ((1 << 22) - 1)) / 10;
1632         request->delay = delay * request->home_server->coa_irt;
1633         delay = request->home_server->coa_irt * USEC;
1634         delay -= delay / 10;
1635         delay += request->delay;
1636      
1637         request->delay = delay;
1638         tv_add(&request->next_when, delay);
1639         request->next_callback = retransmit_coa_request;
1640         
1641         /*
1642          *      Note that we set proxied BEFORE sending the packet.
1643          *
1644          *      Once we send it, the request is tainted, as
1645          *      another thread may have picked it up.  Don't
1646          *      touch it!
1647          */
1648         request->num_proxied_requests = 1;
1649         request->num_proxied_responses = 0;
1650         request->child_pid = NO_SUCH_CHILD_PID;
1651
1652         update_event_timestamp(request->proxy, request->proxy_when.tv_sec);
1653
1654         request->child_state = REQUEST_PROXIED;
1655
1656         DEBUG_PACKET(request, request->proxy, 1);
1657
1658         request->proxy_listener->send(request->proxy_listener,
1659                                       request);
1660         return 1;
1661 }
1662 #endif  /* WITH_COA */
1663
1664 #ifdef WITH_PROXY
1665 static int process_proxy_reply(REQUEST *request)
1666 {
1667         int rcode;
1668         int post_proxy_type = 0;
1669         VALUE_PAIR *vp;
1670         
1671         /*
1672          *      Delete any reply we had accumulated until now.
1673          */
1674         pairfree(&request->reply->vps);
1675         
1676         /*
1677          *      Run the packet through the post-proxy stage,
1678          *      BEFORE playing games with the attributes.
1679          */
1680         vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
1681         if (vp) {
1682                 RDEBUG2("  Found Post-Proxy-Type %s", vp->vp_strvalue);
1683                 post_proxy_type = vp->vp_integer;
1684         }
1685         
1686         if (request->home_pool && request->home_pool->virtual_server) {
1687                 const char *old_server = request->server;
1688                 
1689                 request->server = request->home_pool->virtual_server;
1690                 RDEBUG2(" server %s {", request->server);
1691                 rcode = module_post_proxy(post_proxy_type, request);
1692                 RDEBUG2(" }");
1693                 request->server = old_server;
1694         } else {
1695                 rcode = module_post_proxy(post_proxy_type, request);
1696         }
1697
1698 #ifdef WITH_COA
1699         if (request->packet->code == request->proxy->code)
1700           /*
1701            *    Don't run the next bit if we originated a CoA
1702            *    packet, after receiving an Access-Request or
1703            *    Accounting-Request.
1704            */
1705 #endif
1706         
1707         /*
1708          *      There may NOT be a proxy reply, as we may be
1709          *      running Post-Proxy-Type = Fail.
1710          */
1711         if (request->proxy_reply) {
1712                 /*
1713                  *      Delete the Proxy-State Attributes from
1714                  *      the reply.  These include Proxy-State
1715                  *      attributes from us and remote server.
1716                  */
1717                 pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
1718                 
1719                 /*
1720                  *      Add the attributes left in the proxy
1721                  *      reply to the reply list.
1722                  */
1723                 pairadd(&request->reply->vps, request->proxy_reply->vps);
1724                 request->proxy_reply->vps = NULL;
1725                 
1726                 /*
1727                  *      Free proxy request pairs.
1728                  */
1729                 pairfree(&request->proxy->vps);
1730         }
1731         
1732         switch (rcode) {
1733         default:  /* Don't do anything */
1734                 break;
1735         case RLM_MODULE_FAIL:
1736                 /* FIXME: debug print stuff */
1737                 request->child_state = REQUEST_DONE;
1738                 return 0;
1739                 
1740         case RLM_MODULE_HANDLED:
1741                 /* FIXME: debug print stuff */
1742                 request->child_state = REQUEST_DONE;
1743                 return 0;
1744         }
1745
1746         return 1;
1747 }
1748 #endif
1749
1750 static int request_pre_handler(REQUEST *request)
1751 {
1752         int rcode;
1753
1754         rad_assert(request->magic == REQUEST_MAGIC);
1755         rad_assert(request->packet != NULL);
1756
1757         request->child_state = REQUEST_RUNNING;
1758
1759         /*
1760          *      Don't decode the packet if it's an internal "fake"
1761          *      request.  Instead, just return so that the caller can
1762          *      process it.
1763          */
1764         if (request->packet->dst_port == 0) {
1765                 request->username = pairfind(request->packet->vps,
1766                                              PW_USER_NAME);
1767                 request->password = pairfind(request->packet->vps,
1768                                              PW_USER_PASSWORD);
1769                 return 1;
1770         }
1771
1772 #ifdef WITH_PROXY
1773         /*
1774          *      Put the decoded packet into it's proper place.
1775          */
1776         if (request->proxy_reply != NULL) {
1777                 rcode = request->proxy_listener->decode(request->proxy_listener,
1778                                                         request);
1779                 DEBUG_PACKET(request, request->proxy_reply, 0);
1780         } else
1781 #endif
1782         if (request->packet->vps == NULL) {
1783                 rcode = request->listener->decode(request->listener, request);
1784                 
1785                 if (debug_condition) {
1786                         int result = FALSE;
1787                         const char *my_debug = debug_condition;
1788
1789                         /*
1790                          *      Ignore parse errors.
1791                          */
1792                         radius_evaluate_condition(request, RLM_MODULE_OK, 0,
1793                                                   &my_debug, 1,
1794                                                   &result);
1795                         if (result) {
1796                                 request->options = 2;
1797                                 request->radlog = radlog_request;
1798                         }
1799                 }
1800                 
1801                 DEBUG_PACKET(request, request->packet, 0);
1802         } else {
1803                 rcode = 0;
1804         }
1805
1806         if (rcode < 0) {
1807                 RDEBUG("%s Dropping packet without response.", fr_strerror());
1808                 request->reply->offset = -2; /* bad authenticator */
1809                 request->child_state = REQUEST_DONE;
1810                 return 0;
1811         }
1812
1813         if (!request->username) {
1814                 request->username = pairfind(request->packet->vps,
1815                                              PW_USER_NAME);
1816         }
1817
1818 #ifdef WITH_PROXY
1819         if (request->proxy) {
1820                 return process_proxy_reply(request);
1821 #endif
1822         }
1823
1824         return 1;
1825 }
1826
1827
1828 #ifdef WITH_PROXY
1829 /*
1830  *      Do state handling when we proxy a request.
1831  */
1832 static int proxy_request(REQUEST *request)
1833 {
1834         struct timeval when;
1835         char buffer[128];
1836
1837 #ifdef WITH_COA
1838         if (request->coa) {
1839                 RDEBUG("WARNING: Cannot proxy and originate CoA packets at the same time.  Cancelling CoA request");
1840                 ev_request_free(&request->coa);
1841         }
1842 #endif
1843
1844         if (request->home_server->server) {
1845                 RDEBUG("ERROR: Cannot perform real proxying to a virtual server.");
1846                 return 0;
1847         }
1848
1849         if (!insert_into_proxy_hash(request, FALSE)) {
1850                 RDEBUG("ERROR: Failed inserting request into proxy hash.");
1851                 return 0;
1852         }
1853
1854         request->proxy_listener->encode(request->proxy_listener, request);
1855
1856         when = request->received;
1857         when.tv_sec += request->root->max_request_time;
1858
1859         gettimeofday(&request->proxy_when, NULL);
1860
1861         request->next_when = request->proxy_when;
1862         request->next_when.tv_sec += request->home_server->response_window;
1863
1864         rad_assert(request->home_server->response_window > 0);
1865
1866         if (timercmp(&when, &request->next_when, <)) {
1867                 request->next_when = when;
1868         }
1869         request->next_callback = no_response_to_proxied_request;
1870
1871         RDEBUG2("Proxying request %u to home server %s port %d",
1872                request->number,
1873                inet_ntop(request->proxy->dst_ipaddr.af,
1874                          &request->proxy->dst_ipaddr.ipaddr,
1875                          buffer, sizeof(buffer)),
1876                request->proxy->dst_port);
1877
1878         /*
1879          *      Note that we set proxied BEFORE sending the packet.
1880          *
1881          *      Once we send it, the request is tainted, as
1882          *      another thread may have picked it up.  Don't
1883          *      touch it!
1884          */
1885         request->num_proxied_requests = 1;
1886         request->num_proxied_responses = 0;
1887 #ifdef HAVE_PTHREAD_H
1888         request->child_pid = NO_SUCH_CHILD_PID;
1889 #endif
1890         request->child_state = REQUEST_PROXIED;
1891
1892         DEBUG_PACKET(request, request->proxy, 1);
1893
1894         request->proxy_listener->send(request->proxy_listener,
1895                                       request);
1896         return 1;
1897 }
1898
1899
1900 /*
1901  *      "Proxy" the request by sending it to a new virtual server.
1902  */
1903 static int proxy_to_virtual_server(REQUEST *request)
1904 {
1905         REQUEST *fake;
1906         RAD_REQUEST_FUNP fun;
1907
1908         if (!request->home_server || !request->home_server->server) return 0;
1909
1910         if (request->parent) {
1911                 RDEBUG2("WARNING: Cancelling proxy request to virtual server %s as this request was itself proxied.", request->home_server->server);
1912                 return 0;
1913         }
1914
1915         fake = request_alloc_fake(request);
1916         if (!fake) {
1917                 RDEBUG2("WARNING: Out of memory");
1918                 return 0;
1919         }
1920
1921         fake->packet->vps = paircopy(request->proxy->vps);
1922         fake->server = request->home_server->server;
1923
1924         if (request->proxy->code == PW_AUTHENTICATION_REQUEST) {
1925                 fun = rad_authenticate;
1926
1927 #ifdef WITH_ACCOUNTING
1928         } else if (request->proxy->code == PW_ACCOUNTING_REQUEST) {
1929                 fun = rad_accounting;
1930 #endif
1931
1932         } else {
1933                 RDEBUG2("Unknown packet type %d", request->proxy->code);
1934                 ev_request_free(&fake);
1935                 return 0;
1936         }
1937
1938         RDEBUG2(">>> Sending proxied request internally to virtual server.");
1939         radius_handle_request(fake, fun);
1940         RDEBUG2("<<< Received proxied response code %d from internal virtual server.", fake->reply->code);
1941
1942         if (fake->reply->code != 0) {
1943                 request->proxy_reply = fake->reply;
1944                 fake->reply = NULL;
1945         } else {
1946                 /*
1947                  *      There was no response
1948                  */
1949                 setup_post_proxy_fail(request);
1950         }
1951
1952         ev_request_free(&fake);
1953
1954         process_proxy_reply(request);
1955
1956         /*
1957          *      Process it through the normal section again, but ONLY
1958          *      if we received a proxy reply..
1959          */
1960         if (request->proxy_reply) {
1961                 if (request->server) RDEBUG("server %s {",
1962                                             request->server != NULL ?
1963                                             request->server : ""); 
1964                 fun(request);
1965                 
1966                 if (request->server) RDEBUG("} # server %s",
1967                                             request->server != NULL ?
1968                                             request->server : "");
1969         }
1970
1971         return 2;               /* success, but NOT '1' !*/
1972 }
1973
1974 /*
1975  *      Return 1 if we did proxy it, or the proxy attempt failed
1976  *      completely.  Either way, the caller doesn't touch the request
1977  *      any more if we return 1.
1978  */
1979 static int successfully_proxied_request(REQUEST *request)
1980 {
1981         int rcode;
1982         int pre_proxy_type = 0;
1983         VALUE_PAIR *realmpair;
1984         VALUE_PAIR *strippedname;
1985         VALUE_PAIR *vp;
1986         char *realmname = NULL;
1987         home_server *home;
1988         REALM *realm = NULL;
1989         home_pool_t *pool;
1990
1991         /*
1992          *      If it was already proxied, do nothing.
1993          *
1994          *      FIXME: This should really be a serious error.
1995          */
1996         if (request->in_proxy_hash ||
1997             (request->proxy_reply && (request->proxy_reply->code != 0))) {
1998                 return 0;
1999         }
2000
2001         realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM);
2002         if (!realmpair || (realmpair->length == 0)) {
2003                 int pool_type;
2004
2005                 vp = pairfind(request->config_items, PW_HOME_SERVER_POOL);
2006                 if (!vp) return 0;
2007
2008                 switch (request->packet->code) {
2009                 case PW_AUTHENTICATION_REQUEST:
2010                         pool_type = HOME_TYPE_AUTH;
2011                         break;
2012
2013 #ifdef WITH_ACCOUNTING
2014                 case PW_ACCOUNTING_REQUEST:
2015                         pool_type = HOME_TYPE_ACCT;
2016                         break;
2017 #endif
2018
2019 #ifdef WITH_COA
2020                 case PW_COA_REQUEST:
2021                 case PW_DISCONNECT_REQUEST:
2022                         pool_type = HOME_TYPE_COA;
2023                         break;
2024 #endif
2025
2026                 default:
2027                         return 0;
2028                 }
2029
2030                 pool = home_pool_byname(vp->vp_strvalue, pool_type);
2031                 if (!pool) {
2032                         RDEBUG2("ERROR: Cannot proxy to unknown pool %s",
2033                                 vp->vp_strvalue);
2034                         return 0;
2035                 }
2036
2037                 realmname = NULL; /* no realms */
2038                 realm = NULL;
2039                 goto found_pool;
2040         }
2041
2042         realmname = (char *) realmpair->vp_strvalue;
2043
2044         realm = realm_find2(realmname);
2045         if (!realm) {
2046                 RDEBUG2("ERROR: Cannot proxy to unknown realm %s", realmname);
2047                 return 0;
2048         }
2049
2050         /*
2051          *      Figure out which pool to use.
2052          */
2053         if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
2054                 pool = realm->auth_pool;
2055
2056 #ifdef WITH_ACCOUNTING
2057         } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
2058                 pool = realm->acct_pool;
2059 #endif
2060
2061 #ifdef WITH_COA
2062         } else if ((request->packet->code == PW_COA_REQUEST) ||
2063                    (request->packet->code == PW_DISCONNECT_REQUEST)) {
2064                 pool = realm->acct_pool;
2065 #endif
2066
2067         } else {
2068                 rad_panic("Internal sanity check failed");
2069         }
2070
2071         if (!pool) {
2072                 RDEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
2073                        realmname);
2074                 return 0;
2075         }
2076
2077 found_pool:
2078         home = home_server_ldb(realmname, pool, request);
2079         if (!home) {
2080                 RDEBUG2("ERROR: Failed to find live home server for realm %s",
2081                        realmname);
2082                 return -1;
2083         }
2084         request->home_pool = pool;
2085
2086 #ifdef WITH_COA
2087         /*
2088          *      Once we've decided to proxy a request, we cannot send
2089          *      a CoA packet.  So we free up any CoA packet here.
2090          */
2091         ev_request_free(&request->coa);
2092 #endif
2093         /*
2094          *      Remember that we sent the request to a Realm.
2095          */
2096         if (realmname) pairadd(&request->packet->vps,
2097                                pairmake("Realm", realmname, T_OP_EQ));
2098
2099         /*
2100          *      Strip the name, if told to.
2101          *
2102          *      Doing it here catches the case of proxied tunneled
2103          *      requests.
2104          */
2105         if (realm && (realm->striprealm == TRUE) &&
2106            (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) {
2107                 /*
2108                  *      If there's a Stripped-User-Name attribute in
2109                  *      the request, then use THAT as the User-Name
2110                  *      for the proxied request, instead of the
2111                  *      original name.
2112                  *
2113                  *      This is done by making a copy of the
2114                  *      Stripped-User-Name attribute, turning it into
2115                  *      a User-Name attribute, deleting the
2116                  *      Stripped-User-Name and User-Name attributes
2117                  *      from the vps list, and making the new
2118                  *      User-Name the head of the vps list.
2119                  */
2120                 vp = pairfind(request->proxy->vps, PW_USER_NAME);
2121                 if (!vp) {
2122                         vp = radius_paircreate(request, NULL,
2123                                                PW_USER_NAME, PW_TYPE_STRING);
2124                         rad_assert(vp != NULL); /* handled by above function */
2125                         /* Insert at the START of the list */
2126                         vp->next = request->proxy->vps;
2127                         request->proxy->vps = vp;
2128                 }
2129                 memcpy(vp->vp_strvalue, strippedname->vp_strvalue,
2130                        sizeof(vp->vp_strvalue));
2131                 vp->length = strippedname->length;
2132
2133                 /*
2134                  *      Do NOT delete Stripped-User-Name.
2135                  */
2136         }
2137
2138         /*
2139          *      If there is no PW_CHAP_CHALLENGE attribute but
2140          *      there is a PW_CHAP_PASSWORD we need to add it
2141          *      since we can't use the request authenticator
2142          *      anymore - we changed it.
2143          */
2144         if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
2145             pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
2146             pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) {
2147                 vp = radius_paircreate(request, &request->proxy->vps,
2148                                        PW_CHAP_CHALLENGE, PW_TYPE_OCTETS);
2149                 vp->length = AUTH_VECTOR_LEN;
2150                 memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN);
2151         }
2152
2153         /*
2154          *      The RFC's say we have to do this, but FreeRADIUS
2155          *      doesn't need it.
2156          */
2157         vp = radius_paircreate(request, &request->proxy->vps,
2158                                PW_PROXY_STATE, PW_TYPE_OCTETS);
2159         snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), "%d",
2160                  request->packet->id);
2161         vp->length = strlen(vp->vp_strvalue);
2162
2163         /*
2164          *      Should be done BEFORE inserting into proxy hash, as
2165          *      pre-proxy may use this information, or change it.
2166          */
2167         request->proxy->code = request->packet->code;
2168
2169         /*
2170          *      Call the pre-proxy routines.
2171          */
2172         vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
2173         if (vp) {
2174                 RDEBUG2("  Found Pre-Proxy-Type %s", vp->vp_strvalue);
2175                 pre_proxy_type = vp->vp_integer;
2176         }
2177
2178         rad_assert(request->home_pool != NULL);
2179
2180         if (request->home_pool->virtual_server) {
2181                 const char *old_server = request->server;
2182                 
2183                 request->server = request->home_pool->virtual_server;
2184                 RDEBUG2(" server %s {", request->server);
2185                 rcode = module_pre_proxy(pre_proxy_type, request);
2186                 RDEBUG2(" }");
2187                         request->server = old_server;
2188         } else {
2189                 rcode = module_pre_proxy(pre_proxy_type, request);
2190         }
2191         switch (rcode) {
2192         case RLM_MODULE_FAIL:
2193         case RLM_MODULE_INVALID:
2194         case RLM_MODULE_NOTFOUND:
2195         case RLM_MODULE_USERLOCK:
2196         default:
2197                 /* FIXME: debug print failed stuff */
2198                 return -1;
2199
2200         case RLM_MODULE_REJECT:
2201         case RLM_MODULE_HANDLED:
2202                 return 0;
2203
2204         /*
2205          *      Only proxy the packet if the pre-proxy code succeeded.
2206          */
2207         case RLM_MODULE_NOOP:
2208         case RLM_MODULE_OK:
2209         case RLM_MODULE_UPDATED:
2210                 break;
2211         }
2212
2213         /*
2214          *      If it's a fake request, don't send the proxy
2215          *      packet.  The outer tunnel session will take
2216          *      care of doing that.
2217          */
2218         if (request->packet->dst_port == 0) {
2219                 request->home_server = NULL;
2220                 return 1;
2221         }
2222
2223         if (request->home_server->server) {
2224                 return proxy_to_virtual_server(request);
2225         }
2226
2227         if (!proxy_request(request)) {
2228                 RDEBUG("ERROR: Failed to proxy request %u", request->number);
2229                 return -1;
2230         }
2231         
2232         return 1;
2233 }
2234 #endif
2235
2236 static void request_post_handler(REQUEST *request)
2237 {
2238         int child_state = -1;
2239         struct timeval when;
2240         VALUE_PAIR *vp;
2241
2242         if ((request->master_state == REQUEST_STOP_PROCESSING) ||
2243             (request->parent &&
2244              (request->parent->master_state == REQUEST_STOP_PROCESSING))) {
2245                 RDEBUG2("request %u was cancelled.", request->number);
2246 #ifdef HAVE_PTHREAD_H
2247                 request->child_pid = NO_SUCH_CHILD_PID;
2248 #endif
2249                 child_state = REQUEST_DONE;
2250                 goto cleanup;
2251         }
2252
2253         if (request->child_state != REQUEST_RUNNING) {
2254                 rad_panic("Internal sanity check failed");
2255         }
2256
2257 #ifdef WITH_COA
2258         /*
2259          *      If it's not in the request hash, it's a CoA request.
2260          *      We hope.
2261          */
2262         if (!request->in_request_hash &&
2263             request->proxy &&
2264             ((request->proxy->code == PW_COA_REQUEST) ||
2265              (request->proxy->code == PW_DISCONNECT_REQUEST))) {
2266                 request->next_callback = NULL;
2267                 child_state = REQUEST_DONE;
2268                 goto cleanup;
2269         }
2270 #endif
2271
2272         /*
2273          *      Catch Auth-Type := Reject BEFORE proxying the packet.
2274          */
2275         if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
2276             (request->reply->code == 0) &&
2277             ((vp = pairfind(request->config_items, PW_AUTH_TYPE)) != NULL) &&
2278             (vp->vp_integer == PW_AUTHTYPE_REJECT)) {
2279                 request->reply->code = PW_AUTHENTICATION_REJECT;
2280         }
2281
2282 #ifdef WITH_PROXY
2283         if (request->root->proxy_requests &&
2284             !request->in_proxy_hash &&
2285             (request->reply->code == 0) &&
2286             (request->packet->dst_port != 0) &&
2287             (request->packet->code != PW_STATUS_SERVER)) {
2288                 int rcode = successfully_proxied_request(request);
2289
2290                 if (rcode == 1) return; /* request is invalid */
2291
2292                 /*
2293                  *      Failed proxying it (dead home servers, etc.)
2294                  *      Run it through Post-Proxy-Type = Fail, and
2295                  *      respond to the request.
2296                  *
2297                  *      Note that we're in a child thread here, so we
2298                  *      do NOT re-schedule the request.  Instead, we
2299                  *      do what we would have done, which is run the
2300                  *      pre-handler, a NULL request handler, and then
2301                  *      the post handler.
2302                  */
2303                 if ((rcode < 0) && setup_post_proxy_fail(request)) {
2304                         request_pre_handler(request);
2305                 }
2306
2307                 /*
2308                  *      Else we weren't supposed to proxy it,
2309                  *      OR we proxied it internally to a virutal server.
2310                  */
2311         }
2312
2313 #ifdef WITH_COA
2314         else if (request->proxy && request->coa) {
2315                 RDEBUG("WARNING: Cannot proxy and originate CoA packets at the same time.  Cancelling CoA request");
2316                 ev_request_free(&request->coa);
2317         }
2318 #endif
2319 #endif
2320
2321         /*
2322          *      Fake requests don't get encoded or signed.  The caller
2323          *      also requires the reply VP's, so we don't free them
2324          *      here!
2325          */
2326         if (request->packet->dst_port == 0) {
2327                 /* FIXME: RDEBUG going to the next request */
2328 #ifdef HAVE_PTHREAD_H
2329                 request->child_pid = NO_SUCH_CHILD_PID;
2330 #endif
2331                 request->child_state = REQUEST_DONE;
2332                 return;
2333         }
2334
2335 #ifdef WITH_PROXY
2336         /*
2337          *      Copy Proxy-State from the request to the reply.
2338          */
2339         vp = paircopy2(request->packet->vps, PW_PROXY_STATE);
2340         if (vp) pairadd(&request->reply->vps, vp);
2341 #endif
2342
2343         /*
2344          *      Access-Requests get delayed or cached.
2345          */
2346         switch (request->packet->code) {
2347         case PW_AUTHENTICATION_REQUEST:
2348                 gettimeofday(&request->next_when, NULL);
2349
2350                 if (request->reply->code == 0) {
2351                         /*
2352                          *      Check if the lack of response is intentional.
2353                          */
2354                         vp = pairfind(request->config_items,
2355                                       PW_RESPONSE_PACKET_TYPE);
2356                         if (!vp) {
2357                                 RDEBUG2("There was no response configured: rejecting request %u",
2358                                        request->number);
2359                                 request->reply->code = PW_AUTHENTICATION_REJECT;
2360
2361                         } else if (vp->vp_integer == 256) {
2362                                 RDEBUG2("Not responding to request %u",
2363                                        request->number);
2364
2365                                 /*
2366                                  *      Force cleanup after a long
2367                                  *      time, so that we don't
2368                                  *      re-process the packet.
2369                                  */
2370                                 request->next_when.tv_sec += request->root->max_request_time;
2371                                 request->next_callback = cleanup_delay;
2372                                 child_state = REQUEST_CLEANUP_DELAY;
2373                                 break;
2374                         } else {
2375                                 request->reply->code = vp->vp_integer;
2376
2377                         }
2378                 }
2379
2380                 /*
2381                  *      Run rejected packets through
2382                  *
2383                  *      Post-Auth-Type = Reject
2384                  */
2385                 if (request->reply->code == PW_AUTHENTICATION_REJECT) {
2386                         pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
2387                         vp = radius_pairmake(request, &request->config_items,
2388                                              "Post-Auth-Type", "Reject",
2389                                              T_OP_SET);
2390                         if (vp) rad_postauth(request);
2391
2392                         /*
2393                          *      If configured, delay Access-Reject packets.
2394                          *
2395                          *      If request->root->reject_delay = 0, we discover
2396                          *      that we have to send the packet now.
2397                          */
2398                         when = request->received;
2399                         when.tv_sec += request->root->reject_delay;
2400
2401                         if (timercmp(&when, &request->next_when, >)) {
2402                                 RDEBUG2("Delaying reject of request %u for %d seconds",
2403                                        request->number,
2404                                        request->root->reject_delay);
2405                                 request->next_when = when;
2406                                 request->next_callback = reject_delay;
2407 #ifdef HAVE_PTHREAD_H
2408                                 request->child_pid = NO_SUCH_CHILD_PID;
2409 #endif
2410                                 request->child_state = REQUEST_REJECT_DELAY;
2411                                 return;
2412                         }
2413                 }
2414
2415 #ifdef WITH_COA
2416         case PW_COA_REQUEST:
2417         case PW_DISCONNECT_REQUEST:
2418 #endif
2419                 request->next_when.tv_sec += request->root->cleanup_delay;
2420                 request->next_callback = cleanup_delay;
2421                 child_state = REQUEST_CLEANUP_DELAY;
2422                 break;
2423
2424         case PW_ACCOUNTING_REQUEST:
2425                 request->next_callback = NULL; /* just to be safe */
2426                 child_state = REQUEST_DONE;
2427                 break;
2428
2429                 /*
2430                  *      FIXME: Status-Server should probably not be
2431                  *      handled here...
2432                  */
2433         case PW_STATUS_SERVER:
2434                 request->next_callback = NULL;
2435                 child_state = REQUEST_DONE;
2436                 break;
2437
2438         default:
2439                 /*
2440                  *      DHCP, VMPS, etc.
2441                  */
2442                 request->next_callback = NULL;
2443                 child_state = REQUEST_DONE;
2444                 break;
2445         }
2446
2447         /*
2448          *      Suppress "no reply" packets here, unless we're reading
2449          *      from the "detail" file.  In that case, we've got to
2450          *      tell the detail file handler that the request is dead,
2451          *      and it should re-send it.
2452          *      If configured, encode, sign, and send.
2453          */
2454         if ((request->reply->code != 0) ||
2455             (request->listener->type == RAD_LISTEN_DETAIL)) {
2456                 DEBUG_PACKET(request, request->reply, 1);
2457                 request->listener->send(request->listener, request);
2458         }
2459
2460 #ifdef WITH_COA
2461         /*
2462          *      Now that we've completely processed the request,
2463          *      see if we need to originate a CoA request.  But ONLY
2464          *      if it wasn't proxied.
2465          */
2466         if (!request->proxy &&
2467             (request->coa ||
2468              (pairfind(request->config_items, PW_SEND_COA_REQUEST) != NULL))) {
2469                 if (!originated_coa_request(request)) {
2470                         RDEBUG2("Do CoA Fail handler here");
2471                 }
2472                 /* request->coa is stil set, so we can update events */
2473         }
2474 #endif
2475
2476  cleanup:
2477         /*
2478          *      Clean up.  These are no longer needed.
2479          */
2480         pairfree(&request->config_items);
2481
2482         pairfree(&request->packet->vps);
2483         request->username = NULL;
2484         request->password = NULL;
2485
2486         pairfree(&request->reply->vps);
2487
2488 #ifdef WITH_PROXY
2489         if (request->proxy) {
2490                 pairfree(&request->proxy->vps);
2491
2492                 if (request->proxy_reply) {
2493                         pairfree(&request->proxy_reply->vps);
2494                 }
2495
2496 #if 0
2497                 /*
2498                  *      We're not tracking responses from the home
2499                  *      server, we can therefore free this memory in
2500                  *      the child thread.
2501                  */
2502                 if (!request->in_proxy_hash) {
2503                         rad_free(&request->proxy);
2504                         rad_free(&request->proxy_reply);
2505                         request->home_server = NULL;
2506                 }
2507 #endif
2508         }
2509 #endif
2510
2511         RDEBUG2("Finished request %u.", request->number);
2512         rad_assert(child_state >= 0);
2513         request->child_state = child_state;
2514
2515         /*
2516          *      Single threaded mode: update timers now.
2517          */
2518         if (!have_children) wait_a_bit(request);
2519 }
2520
2521
2522 static void received_retransmit(REQUEST *request, const RADCLIENT *client)
2523 {
2524 #ifdef WITH_PROXY
2525         char buffer[128];
2526 #endif
2527
2528         RAD_STATS_TYPE_INC(request->listener, total_dup_requests);
2529         RAD_STATS_CLIENT_INC(request->listener, client, total_dup_requests);
2530         
2531         switch (request->child_state) {
2532         case REQUEST_QUEUED:
2533         case REQUEST_RUNNING:
2534 #ifdef WITH_PROXY
2535         discard:
2536 #endif
2537                 radlog(L_ERR, "Discarding duplicate request from "
2538                        "client %s port %d - ID: %d due to unfinished request %u",
2539                        client->shortname,
2540                        request->packet->src_port,request->packet->id,
2541                        request->number);
2542                 break;
2543
2544 #ifdef WITH_PROXY
2545         case REQUEST_PROXIED:
2546                 /*
2547                  *      We're not supposed to have duplicate
2548                  *      accounting packets.  The other states handle
2549                  *      duplicates fine (discard, or send duplicate
2550                  *      reply).  But we do NOT want to retransmit an
2551                  *      accounting request here, because that would
2552                  *      involve updating the Acct-Delay-Time, and
2553                  *      therefore changing the packet Id, etc.
2554                  *
2555                  *      Instead, we just discard the packet.  We may
2556                  *      eventually respond, or the client will send a
2557                  *      new accounting packet.            
2558                  *
2559                  *      The same comments go for Status-Server, and
2560                  *      other packet types.
2561                  *
2562                  *      FIXME: coa: when we proxy CoA && Disconnect
2563                  *      packets, this logic has to be fixed.
2564                  */
2565                 if (request->packet->code != PW_AUTHENTICATION_REQUEST) {
2566                         goto discard;
2567                 }
2568
2569                 check_for_zombie_home_server(request);
2570
2571                 /*
2572                  *      If we've just discovered that the home server is
2573                  *      dead, send the packet to another one.
2574                  */
2575                 if ((request->packet->dst_port != 0) &&
2576                     (request->home_server->state == HOME_STATE_IS_DEAD)) {
2577                         home_server *home;
2578
2579                         remove_from_proxy_hash(request);
2580
2581                         home = home_server_ldb(NULL, request->home_pool, request);
2582                         if (!home) {
2583                                 RDEBUG2("Failed to find live home server for request %u", request->number);
2584                         no_home_servers:
2585                                 /*
2586                                  *      Do post-request processing,
2587                                  *      and any insertion of necessary
2588                                  *      events.
2589                                  */
2590                                 post_proxy_fail_handler(request);
2591                                 return;
2592                         }
2593
2594                         request->proxy->code = request->packet->code;
2595
2596                         /*
2597                          *      Free the old packet, to force re-encoding
2598                          */
2599                         free(request->proxy->data);
2600                         request->proxy->data = NULL;
2601                         request->proxy->data_len = 0;
2602
2603                         /*
2604                          *      This request failed over to a virtual
2605                          *      server.  Push it back onto the queue
2606                          *      to be processed.
2607                          */
2608                         if (request->home_server->server) {
2609                                 proxy_fallback_handler(request);
2610                                 return;
2611                         }
2612
2613                         /*
2614                          *      Try to proxy the request.
2615                          */
2616                         if (!proxy_request(request)) {
2617                                 RDEBUG("ERROR: Failed to re-proxy request %u", request->number);
2618                                 goto no_home_servers;
2619                         }
2620
2621                         /*
2622                          *      This code executes in the main server
2623                          *      thread, so there's no need for locking.
2624                          */
2625                         rad_assert(request->next_callback != NULL);
2626                         INSERT_EVENT(request->next_callback, request);
2627                         request->next_callback = NULL;
2628                         return;
2629                 } /* else the home server is still alive */
2630
2631                 RDEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
2632                        inet_ntop(request->proxy->dst_ipaddr.af,
2633                                  &request->proxy->dst_ipaddr.ipaddr,
2634                                  buffer, sizeof(buffer)),
2635                        request->proxy->dst_port,
2636                        request->proxy->id);
2637                 request->num_proxied_requests++;
2638
2639                 DEBUG_PACKET(request, request->proxy, 1);
2640                 request->proxy_listener->send(request->proxy_listener,
2641                                               request);
2642                 break;
2643 #endif
2644
2645         case REQUEST_REJECT_DELAY:
2646                 RDEBUG2("Waiting to send Access-Reject "
2647                        "to client %s port %d - ID: %d",
2648                        client->shortname,
2649                        request->packet->src_port, request->packet->id);
2650                 break;
2651
2652         case REQUEST_CLEANUP_DELAY:
2653         case REQUEST_DONE:
2654                 if (request->reply->code == 0) {
2655                         RDEBUG2("Ignoring retransmit from client %s port %d "
2656                                 "- ID: %d, no reply was configured",
2657                                 client->shortname,
2658                                 request->packet->src_port, request->packet->id);
2659                         return;
2660                 }
2661
2662                 /*
2663                  *      FIXME: This sends duplicate replies to
2664                  *      accounting requests, even if Acct-Delay-Time
2665                  *      or Event-Timestamp is in the packet.  In those
2666                  *      cases, the Id should be changed, and the packet
2667                  *      re-calculated.
2668                  */
2669                 RDEBUG2("Sending duplicate reply "
2670                        "to client %s port %d - ID: %d",
2671                        client->shortname,
2672                        request->packet->src_port, request->packet->id);
2673                 DEBUG_PACKET(request, request->reply, 1);
2674                 request->listener->send(request->listener, request);
2675                 break;
2676         }
2677 }
2678
2679
2680 static void received_conflicting_request(REQUEST *request,
2681                                          const RADCLIENT *client)
2682 {
2683         radlog(L_ERR, "Received conflicting packet from "
2684                "client %s port %d - ID: %d due to unfinished request %u.  Giving up on old request.",
2685                client->shortname,
2686                request->packet->src_port, request->packet->id,
2687                request->number);
2688
2689         /*
2690          *      Nuke it from the request hash, so we can receive new
2691          *      packets.
2692          */
2693         remove_from_request_hash(request);
2694
2695         switch (request->child_state) {
2696 #ifdef HAVE_PTHREAD_H
2697                 /*
2698                  *      It's queued or running.  Tell it to stop, and
2699                  *      wait for it to do so.
2700                  */
2701         case REQUEST_QUEUED:
2702         case REQUEST_RUNNING:
2703                 request->master_state = REQUEST_STOP_PROCESSING;
2704                 request->delay += request->delay >> 1;
2705
2706                 tv_add(&request->when, request->delay);
2707
2708                 INSERT_EVENT(wait_for_child_to_die, request);
2709                 return;
2710 #endif
2711
2712                 /*
2713                  *      Catch race conditions.  It may have switched
2714                  *      from running to done while this code is being
2715                  *      executed.
2716                  */
2717         case REQUEST_REJECT_DELAY:
2718         case REQUEST_CLEANUP_DELAY:
2719         case REQUEST_DONE:
2720                 break;
2721
2722                 /*
2723                  *      It's in some other state, and therefore also
2724                  *      in the event queue.  At some point, the
2725                  *      child will notice, and we can then delete it.
2726                  */
2727         case REQUEST_PROXIED:
2728         default:
2729                 rad_assert(request->ev != NULL);
2730                 break;
2731         }
2732 }
2733
2734
2735 static int can_handle_new_request(RADIUS_PACKET *packet,
2736                                   RADCLIENT *client,
2737                                   struct main_config_t *root)
2738 {
2739         /*
2740          *      Count the total number of requests, to see if
2741          *      there are too many.  If so, return with an
2742          *      error.
2743          */
2744         if (root->max_requests) {
2745                 int request_count = fr_packet_list_num_elements(pl);
2746
2747                 /*
2748                  *      This is a new request.  Let's see if
2749                  *      it makes us go over our configured
2750                  *      bounds.
2751                  */
2752                 if (request_count > root->max_requests) {
2753                         radlog(L_ERR, "Dropping request (%d is too many): "
2754                                "from client %s port %d - ID: %d", request_count,
2755                                client->shortname,
2756                                packet->src_port, packet->id);
2757                         radlog(L_INFO, "WARNING: Please check the configuration file.\n"
2758                                "\tThe value for 'max_requests' is probably set too low.\n");
2759                         return 0;
2760                 } /* else there were a small number of requests */
2761         } /* else there was no configured limit for requests */
2762
2763         /*
2764          *      FIXME: Add per-client checks.  If one client is sending
2765          *      too many packets, start discarding them.
2766          *
2767          *      We increment the counters here, and decrement them
2768          *      when the response is sent... somewhere in this file.
2769          */
2770
2771         /*
2772          *      FUTURE: Add checks for system load.  If the system is
2773          *      busy, start dropping requests...
2774          *
2775          *      We can probably keep some statistics ourselves...  if
2776          *      there are more requests coming in than we can handle,
2777          *      start dropping some.
2778          */
2779
2780         return 1;
2781 }
2782
2783
2784 int received_request(rad_listen_t *listener,
2785                      RADIUS_PACKET *packet, REQUEST **prequest,
2786                      RADCLIENT *client)
2787 {
2788         RADIUS_PACKET **packet_p;
2789         REQUEST *request = NULL;
2790         struct main_config_t *root = &mainconfig;
2791
2792         packet_p = fr_packet_list_find(pl, packet);
2793         if (packet_p) {
2794                 request = fr_packet2myptr(REQUEST, packet, packet_p);
2795                 rad_assert(request->in_request_hash);
2796
2797                 if ((request->packet->data_len == packet->data_len) &&
2798                     (memcmp(request->packet->vector, packet->vector,
2799                             sizeof(packet->vector)) == 0)) {
2800                         received_retransmit(request, client);
2801                         return 0;
2802                 }
2803
2804                 /*
2805                  *      The new request is different from the old one,
2806                  *      but maybe the old is finished.  If so, delete
2807                  *      the old one.
2808                  */
2809                 switch (request->child_state) {
2810                         struct timeval when;
2811
2812                 default:
2813                         /*
2814                          *      Special hacks for race conditions.
2815                          *      The reply is encoded, and therefore
2816                          *      likely sent.  We received a *new*
2817                          *      packet from the client, likely before
2818                          *      the next line or two of code which
2819                          *      updated the child state.  In this
2820                          *      case, just accept the new request.
2821                          */
2822                         if ((request->reply->code != 0) &&
2823                             request->reply->data) {
2824                                 radlog(L_INFO, "WARNING: Allowing fast client %s port %d - ID: %d for recent request %u.",
2825                                        client->shortname,
2826                                        packet->src_port, packet->id,
2827                                        request->number);
2828                                 remove_from_request_hash(request);
2829                                 request = NULL;
2830                                 break;
2831                         }
2832
2833                         gettimeofday(&when, NULL);
2834                         when.tv_sec -= 1;
2835
2836                         /*
2837                          *      If the cached request was received
2838                          *      within the last second, then we
2839                          *      discard the NEW request instead of the
2840                          *      old one.  This will happen ONLY when
2841                          *      the client is severely broken, and is
2842                          *      sending conflicting packets very
2843                          *      quickly.
2844                          */
2845                         if (timercmp(&when, &request->received, <)) {
2846                                 radlog(L_ERR, "Discarding conflicting packet from "
2847                                        "client %s port %d - ID: %d due to recent request %u.",
2848                                        client->shortname,
2849                                        packet->src_port, packet->id,
2850                                        request->number);
2851                                 return 0;
2852                         }
2853
2854                         received_conflicting_request(request, client);
2855                         request = NULL;
2856                         break;
2857
2858                 case REQUEST_REJECT_DELAY:
2859                 case REQUEST_CLEANUP_DELAY:
2860                         request->child_state = REQUEST_DONE;
2861                 case REQUEST_DONE:
2862                         cleanup_delay(request);
2863                         request = NULL;
2864                         break;
2865                 }
2866         }
2867
2868         /*
2869          *      We may want to quench the new request.
2870          */
2871         if ((listener->type != RAD_LISTEN_DETAIL) &&
2872             !can_handle_new_request(packet, client, root)) {
2873                 return 0;
2874         }
2875
2876         /*
2877          *      Create and initialize the new request.
2878          */
2879         request = request_alloc(); /* never fails */
2880
2881         if ((request->reply = rad_alloc(0)) == NULL) {
2882                 radlog(L_ERR, "No memory");
2883                 exit(1);
2884         }
2885
2886         request->listener = listener;
2887         request->client = client;
2888         request->packet = packet;
2889         request->packet->timestamp = request->timestamp;
2890         request->number = request_num_counter++;
2891         request->priority = listener->type;
2892 #ifdef HAVE_PTHREAD_H
2893         request->child_pid = NO_SUCH_CHILD_PID;
2894 #endif
2895
2896         /*
2897          *      Status-Server packets go to the head of the queue.
2898          */
2899         if (request->packet->code == PW_STATUS_SERVER) request->priority = 0;
2900
2901         /*
2902          *      Set virtual server identity
2903          */
2904         if (client->server) {
2905                 request->server = client->server;
2906         } else if (listener->server) {
2907                 request->server = listener->server;
2908         } else {
2909                 request->server = NULL;
2910         }
2911
2912         /*
2913          *      Remember the request in the list.
2914          */
2915         if (!fr_packet_list_insert(pl, &request->packet)) {
2916                 radlog(L_ERR, "Failed to insert request %u in the list of live requests: discarding", request->number);
2917                 ev_request_free(&request);
2918                 return 0;
2919         }
2920
2921         request->in_request_hash = TRUE;
2922         request->root = root;
2923         root->refcount++;
2924
2925         /*
2926          *      The request passes many of our sanity checks.
2927          *      From here on in, if anything goes wrong, we
2928          *      send a reject message, instead of dropping the
2929          *      packet.
2930          */
2931
2932         /*
2933          *      Build the reply template from the request.
2934          */
2935
2936         request->reply->sockfd = request->packet->sockfd;
2937         request->reply->dst_ipaddr = request->packet->src_ipaddr;
2938         request->reply->src_ipaddr = request->packet->dst_ipaddr;
2939         request->reply->dst_port = request->packet->src_port;
2940         request->reply->src_port = request->packet->dst_port;
2941         request->reply->id = request->packet->id;
2942         request->reply->code = 0; /* UNKNOWN code */
2943         memcpy(request->reply->vector, request->packet->vector,
2944                sizeof(request->reply->vector));
2945         request->reply->vps = NULL;
2946         request->reply->data = NULL;
2947         request->reply->data_len = 0;
2948
2949         request->master_state = REQUEST_ACTIVE;
2950         request->child_state = REQUEST_QUEUED;
2951         request->next_callback = NULL;
2952
2953         gettimeofday(&request->received, NULL);
2954         request->timestamp = request->received.tv_sec;
2955         request->when = request->received;
2956
2957         request->delay = USEC;
2958
2959         tv_add(&request->when, request->delay);
2960
2961         INSERT_EVENT(wait_a_bit, request);
2962
2963         *prequest = request;
2964         return 1;
2965 }
2966
2967
2968 #ifdef WITH_PROXY
2969 REQUEST *received_proxy_response(RADIUS_PACKET *packet)
2970 {
2971         char            buffer[128];
2972         REQUEST         *request;
2973
2974         /*
2975          *      Also removes from the proxy hash if responses == requests
2976          */
2977         request = lookup_in_proxy_hash(packet);
2978
2979         if (!request) {
2980                 radlog(L_PROXY, "No outstanding request was found for reply from host %s port %d - ID %d",
2981                        inet_ntop(packet->src_ipaddr.af,
2982                                  &packet->src_ipaddr.ipaddr,
2983                                  buffer, sizeof(buffer)),
2984                        packet->src_port, packet->id);
2985                 return NULL;
2986         }
2987
2988         /*
2989          *      We haven't replied to the NAS, but we have seen an
2990          *      earlier reply from the home server.  Ignore this packet,
2991          *      as we're likely still processing the previous reply.
2992          */
2993         if (request->proxy_reply) {
2994                 if (memcmp(request->proxy_reply->vector,
2995                            packet->vector,
2996                            sizeof(request->proxy_reply->vector)) == 0) {
2997                         RDEBUG2("Discarding duplicate reply from host %s port %d  - ID: %d for request %u",
2998                                inet_ntop(packet->src_ipaddr.af,
2999                                          &packet->src_ipaddr.ipaddr,
3000                                          buffer, sizeof(buffer)),
3001                                packet->src_port, packet->id,
3002                                request->number);
3003                 } else {
3004                         /*
3005                          *      ? The home server gave us a new proxy
3006                          *      reply which doesn't match the old
3007                          *      one.  Delete it.
3008                          */
3009                         RDEBUG2("Ignoring conflicting proxy reply");
3010                 }
3011                 
3012                 /* assert that there's an event queued for request? */
3013                 return NULL;
3014         }
3015
3016         /*
3017          *      Verify the packet before doing ANYTHING with it.  This
3018          *      means we're doing more MD5 checks in the server core.
3019          *      However, we can fix that by moving to multiple threads
3020          *      listening on sockets.
3021          *
3022          *      We do this AFTER looking the request up in the hash,
3023          *      and AFTER vhecking if we saw a previous request.  This
3024          *      helps minimize the DoS effect of people attacking us
3025          *      with spoofed packets.
3026          */
3027         if (rad_verify(packet, request->proxy,
3028                        request->home_server->secret) != 0) {
3029                 DEBUG("Ignoring spoofed proxy reply.  Signature is invalid");
3030                 return NULL;
3031         }
3032
3033         gettimeofday(&now, NULL);
3034
3035         /*
3036          *      Maybe move this earlier in the decision process?
3037          *      Having it here means that late or duplicate proxy
3038          *      replies no longer get the home server marked as
3039          *      "alive".  This might be good for stability, though.
3040          *
3041          *      FIXME: Do we really want to do this whenever we
3042          *      receive a packet?  Setting this here means that we
3043          *      mark it alive on *any* packet, even if it's lost all
3044          *      of the *other* packets in the last 10s.
3045          */
3046         if (request->proxy->code != PW_STATUS_SERVER) {
3047                 request->home_server->state = HOME_STATE_ALIVE;
3048         }
3049         
3050 #ifdef WITH_COA
3051         /*
3052          *      When originating CoA, the "proxy" reply is the reply
3053          *      to the CoA request that we originated.  At this point,
3054          *      the original request is finished, and it has a reply.
3055          *
3056          *      However, if we haven't separated the two requests, do
3057          *      so now.  This is done so that cleaning up the original
3058          *      request won't cause the CoA request to be free'd.  See
3059          *      util.c, request_free()
3060          */
3061         if (request->parent && (request->parent->coa == request)) {
3062                 request->parent->coa = NULL;
3063                 request->parent = NULL;
3064
3065                 /*
3066                  *      The proxied packet was different from the
3067                  *      original packet, AND the proxied packet was
3068                  *      a CoA: allow it.
3069                  */
3070         } else if ((request->packet->code != request->proxy->code) &&
3071                    ((request->proxy->code == PW_COA_REQUEST) ||
3072                     (request->proxy->code == PW_DISCONNECT_REQUEST))) {
3073           /*
3074            *    It's already divorced: do nothing.
3075            */
3076           
3077         } else
3078                 /*
3079                  *      Skip the next set of checks, as the original
3080                  *      reply is cached.  We want to be able to still
3081                  *      process the CoA reply, AND to reference the
3082                  *      original request/reply.
3083                  *
3084                  *      This is getting to be really quite a bit of a
3085                  *      hack.
3086                  */
3087 #endif
3088
3089         /*
3090          *      If there's a reply to the NAS, ignore everything
3091          *      related to proxy responses
3092          */
3093         if (request->reply && request->reply->code != 0) {
3094                 RDEBUG2("Ignoring proxy reply that arrived after we sent a reply to the NAS");
3095                 return NULL;
3096         }
3097         
3098 #ifdef WITH_STATS
3099         /*
3100          *      The average includes our time to receive packets and
3101          *      look them up in the hashes, which should be the same
3102          *      for all packets.
3103          *
3104          *      We update the response time only for the FIRST packet
3105          *      we receive.
3106          */
3107         if (request->home_server->ema.window > 0) {
3108                 radius_stats_ema(&request->home_server->ema,
3109                                  &now, &request->proxy_when);
3110         }
3111 #endif
3112
3113         switch (request->child_state) {
3114         case REQUEST_QUEUED:
3115         case REQUEST_RUNNING:
3116                 radlog(L_ERR, "Internal sanity check failed for child state");
3117                 /* FALL-THROUGH */
3118
3119         case REQUEST_REJECT_DELAY:
3120         case REQUEST_CLEANUP_DELAY:
3121         case REQUEST_DONE:
3122                 radlog(L_ERR, "Reply from home server %s port %d  - ID: %d arrived too late for request %u. Try increasing 'retry_delay' or 'max_request_time'",
3123                        inet_ntop(packet->src_ipaddr.af,
3124                                  &packet->src_ipaddr.ipaddr,
3125                                  buffer, sizeof(buffer)),
3126                        packet->src_port, packet->id,
3127                        request->number);
3128                 /* assert that there's an event queued for request? */
3129                 return NULL;
3130
3131         case REQUEST_PROXIED:
3132                 break;
3133         }
3134
3135         request->proxy_reply = packet;
3136
3137 #if 0
3138         /*
3139          *      Perform RTT calculations, as per RFC 2988 (for TCP).
3140          *      Note that we only do so on the first response.
3141          */
3142         if ((request->num_proxied_responses == 1)
3143                 int rtt;
3144                 home_server *home = request->home_server;
3145
3146                 rtt = now.tv_sec - request->proxy_when.tv_sec;
3147                 rtt *= USEC;
3148                 rtt += now.tv_usec;
3149                 rtt -= request->proxy_when.tv_usec;
3150
3151                 if (!home->has_rtt) {
3152                         home->has_rtt = TRUE;
3153
3154                         home->srtt = rtt;
3155                         home->rttvar = rtt / 2;
3156
3157                 } else {
3158                         home->rttvar -= home->rttvar >> 2;
3159                         home->rttvar += (home->srtt - rtt);
3160                         home->srtt -= home->srtt >> 3;
3161                         home->srtt += rtt >> 3;
3162                 }
3163
3164                 home->rto = home->srtt;
3165                 if (home->rttvar > (USEC / 4)) {
3166                         home->rto += home->rttvar * 4;
3167                 } else {
3168                         home->rto += USEC;
3169                 }
3170         }
3171 #endif
3172
3173         /*
3174          *      There's no incoming request, so it's a proxied packet
3175          *      we originated.
3176          */
3177         if (!request->packet) {
3178                 received_response_to_ping(request);
3179                 request->proxy_reply = NULL; /* caller will free it */
3180                 ev_request_free(&request);
3181                 return NULL;
3182         }
3183
3184         request->child_state = REQUEST_QUEUED;
3185         request->when = now;
3186         request->delay = USEC;
3187         request->priority = RAD_LISTEN_PROXY;
3188         tv_add(&request->when, request->delay);
3189
3190         /*
3191          *      Wait a bit will take care of max_request_time
3192          */
3193         INSERT_EVENT(wait_a_bit, request);
3194
3195         return request;
3196 }
3197 #endif
3198
3199 void event_new_fd(rad_listen_t *this)
3200 {
3201         char buffer[1024];
3202
3203         if (this->status == RAD_LISTEN_STATUS_KNOWN) return;
3204         
3205         this->print(this, buffer, sizeof(buffer));
3206         
3207         if (this->status == RAD_LISTEN_STATUS_INIT) {
3208                 if (just_started) {
3209                         DEBUG("Listening on %s", buffer);
3210                 } else {
3211                         radlog(L_INFO, " ... adding new socket %s", buffer);
3212                 }
3213                 if (!fr_event_fd_insert(el, 0, this->fd,
3214                                         event_socket_handler, this)) {
3215                         radlog(L_ERR, "Failed remembering handle for proxy socket!");
3216                         exit(1);
3217                 }
3218                 
3219                 this->status = RAD_LISTEN_STATUS_KNOWN;
3220                 return;
3221         }
3222         
3223         if (this->status == RAD_LISTEN_STATUS_CLOSED) {
3224                 radlog(L_INFO, " ... closing socket %s", buffer);
3225                 
3226                 fr_event_fd_delete(el, 0, this->fd);
3227                 this->status = RAD_LISTEN_STATUS_FINISH;
3228                 
3229                 /*
3230                  *      Close the fd AFTER fixing up the requests and
3231                  *      listeners, so that they don't send/recv on the
3232                  *      wrong socket (if someone manages to open
3233                  *      another one).
3234                  */
3235                 close(this->fd);
3236                 this->fd = -1;
3237         }
3238 }
3239
3240 static void handle_signal_self(int flag)
3241 {
3242         if ((flag & (RADIUS_SIGNAL_SELF_EXIT | RADIUS_SIGNAL_SELF_TERM)) != 0) {
3243                 if ((flag & RADIUS_SIGNAL_SELF_EXIT) != 0) {
3244                         fr_event_loop_exit(el, 1);
3245                 } else {
3246                         fr_event_loop_exit(el, 2);
3247                 }
3248
3249                 return;
3250         } /* else exit/term flags weren't set */
3251
3252         /*
3253          *      Tell the even loop to stop processing.
3254          */
3255         if ((flag & RADIUS_SIGNAL_SELF_HUP) != 0) {
3256                 time_t when;
3257                 static time_t last_hup = 0;
3258
3259                 when = time(NULL);
3260                 if ((int) (when - last_hup) < 5) {
3261                         radlog(L_INFO, "Ignoring HUP (less than 5s since last one)");
3262                         return;
3263                 }
3264
3265                 radlog(L_INFO, "Received HUP signal.");
3266
3267                 last_hup = when;
3268
3269                 fr_event_loop_exit(el, 0x80);
3270         }
3271
3272 #ifdef WITH_DETAIL
3273         if ((flag & RADIUS_SIGNAL_SELF_DETAIL) != 0) {
3274                 rad_listen_t *this;
3275                 
3276                 /*
3277                  *      FIXME: O(N) loops suck.
3278                  */
3279                 for (this = mainconfig.listen;
3280                      this != NULL;
3281                      this = this->next) {
3282                         if (this->type != RAD_LISTEN_DETAIL) continue;
3283
3284                         /*
3285                          *      This one didn't send the signal, skip
3286                          *      it.
3287                          */
3288                         if (!this->decode(this, NULL)) continue;
3289
3290                         /*
3291                          *      Go service the interrupt.
3292                          */
3293                         event_poll_detail(this);
3294                 }
3295         }
3296 #endif
3297
3298         if ((flag & RADIUS_SIGNAL_SELF_NEW_FD) != 0) {
3299                 rad_listen_t *this;
3300                 
3301                 for (this = mainconfig.listen;
3302                      this != NULL;
3303                      this = this->next) {
3304                         event_new_fd(this);
3305                 }
3306         }
3307 }
3308
3309 #ifndef WITH_SELF_PIPE
3310 void radius_signal_self(int flag)
3311 {
3312         handle_signal_self(flag);
3313 }
3314 #else
3315 /*
3316  *      Inform ourselves that we received a signal.
3317  */
3318 void radius_signal_self(int flag)
3319 {
3320         ssize_t rcode;
3321         uint8_t buffer[16];
3322
3323         /*
3324          *      The read MUST be non-blocking for this to work.
3325          */
3326         rcode = read(self_pipe[0], buffer, sizeof(buffer));
3327         if (rcode > 0) {
3328                 ssize_t i;
3329
3330                 for (i = 0; i < rcode; i++) {
3331                         buffer[0] |= buffer[i];
3332                 }
3333         } else {
3334                 buffer[0] = 0;
3335         }
3336
3337         buffer[0] |= flag;
3338
3339         write(self_pipe[1], buffer, 1);
3340 }
3341
3342
3343 static void event_signal_handler(UNUSED fr_event_list_t *xel,
3344                                  UNUSED int fd, UNUSED void *ctx)
3345 {
3346         ssize_t i, rcode;
3347         uint8_t buffer[32];
3348
3349         rcode = read(self_pipe[0], buffer, sizeof(buffer));
3350         if (rcode <= 0) return;
3351
3352         /*
3353          *      Merge pending signals.
3354          */
3355         for (i = 0; i < rcode; i++) {
3356                 buffer[0] |= buffer[i];
3357         }
3358
3359         handle_signal_self(buffer[0]);
3360 }
3361 #endif
3362
3363
3364 static void event_socket_handler(fr_event_list_t *xel, UNUSED int fd,
3365                                  void *ctx)
3366 {
3367         rad_listen_t *listener = ctx;
3368         RAD_REQUEST_FUNP fun;
3369         REQUEST *request;
3370
3371         rad_assert(xel == el);
3372
3373         xel = xel;
3374
3375         if (listener->fd < 0) rad_panic("Socket was closed on us!");
3376         
3377         if (!listener->recv(listener, &fun, &request)) return;
3378
3379         if (!thread_pool_addrequest(request, fun)) {
3380                 request->child_state = REQUEST_DONE;
3381         }
3382 }
3383
3384
3385 /*
3386  *      This function is called periodically to see if this detail
3387  *      file is available for reading.
3388  */
3389 static void event_poll_detail(void *ctx)
3390 {
3391         int rcode, delay;
3392         RAD_REQUEST_FUNP fun;
3393         REQUEST *request;
3394         rad_listen_t *this = ctx;
3395         struct timeval when;
3396         listen_detail_t *detail = this->data;
3397
3398         rad_assert(this->type == RAD_LISTEN_DETAIL);
3399
3400         /*
3401          *      Try to read something.
3402          *
3403          *      FIXME: This does poll AND receive.
3404          */
3405         rcode = this->recv(this, &fun, &request);
3406         if (rcode != 0) {
3407                 rad_assert(fun != NULL);
3408                 rad_assert(request != NULL);
3409                 
3410                 if (!thread_pool_addrequest(request, fun)) {
3411                         request->child_state = REQUEST_DONE;
3412                 }
3413         }
3414
3415         if (!fr_event_now(el, &now)) gettimeofday(&now, NULL);
3416         when = now;
3417
3418         /*
3419          *      Backdoor API to get the delay until the next poll
3420          *      time.
3421          */
3422         delay = this->encode(this, NULL);
3423         tv_add(&when, delay);
3424
3425         if (!fr_event_insert(el, event_poll_detail, this,
3426                              &when, &detail->ev)) {
3427                 radlog(L_ERR, "Failed creating handler");
3428                 exit(1);
3429         }
3430 }
3431
3432
3433 static void event_status(struct timeval *wake)
3434 {
3435 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
3436         int argval;
3437 #endif
3438
3439         if (debug_flag == 0) {
3440                 if (just_started) {
3441                         radlog(L_INFO, "Ready to process requests.");
3442                         just_started = FALSE;
3443                 }
3444                 return;
3445         }
3446
3447         if (!wake) {
3448                 radlog(L_INFO, "Ready to process requests.");
3449
3450         } else if ((wake->tv_sec != 0) ||
3451                    (wake->tv_usec >= 100000)) {
3452                 DEBUG("Waking up in %d.%01u seconds.",
3453                       (int) wake->tv_sec, (unsigned int) wake->tv_usec / 100000);
3454         }
3455
3456
3457         /*
3458          *      FIXME: Put this somewhere else, where it isn't called
3459          *      all of the time...
3460          */
3461
3462 #if !defined(HAVE_PTHREAD_H) && defined(WNOHANG)
3463         /*
3464          *      If there are no child threads, then there may
3465          *      be child processes.  In that case, wait for
3466          *      their exit status, and throw that exit status
3467          *      away.  This helps get rid of zxombie children.
3468          */
3469         while (waitpid(-1, &argval, WNOHANG) > 0) {
3470                 /* do nothing */
3471         }
3472 #endif
3473
3474 }
3475
3476 /*
3477  *      Externally-visibly functions.
3478  */
3479 int radius_event_init(CONF_SECTION *cs, int spawn_flag)
3480 {
3481         rad_listen_t *this, *head = NULL;
3482
3483         if (el) return 0;
3484
3485         time(&fr_start_time);
3486
3487         el = fr_event_list_create(event_status);
3488         if (!el) return 0;
3489
3490         pl = fr_packet_list_create(0);
3491         if (!pl) return 0;      /* leak el */
3492
3493         request_num_counter = 0;
3494
3495 #ifdef WITH_PROXY
3496         if (mainconfig.proxy_requests) {
3497                 /*
3498                  *      Create the tree for managing proxied requests and
3499                  *      responses.
3500                  */
3501                 proxy_list = fr_packet_list_create(1);
3502                 if (!proxy_list) return 0;
3503
3504 #ifdef HAVE_PTHREAD_H
3505                 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
3506                         radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
3507                                strerror(errno));
3508                         exit(1);
3509                 }
3510 #endif
3511         }
3512 #endif
3513
3514 #ifdef HAVE_PTHREAD_H
3515 #ifndef __MINGW32__
3516         NO_SUCH_CHILD_PID = (pthread_t ) (0);
3517 #else
3518         NO_SUCH_CHILD_PID = pthread_self(); /* not a child thread */
3519 #endif
3520         /*
3521          *      Initialize the threads ONLY if we're spawning, AND
3522          *      we're running normally.
3523          */
3524         if (spawn_flag && !check_config &&
3525             (thread_pool_init(cs, &spawn_flag) < 0)) {
3526                 exit(1);
3527         }
3528 #endif
3529
3530         /*
3531          *      Move all of the thread calls to this file?
3532          *
3533          *      It may be best for the mutexes to be in this file...
3534          */
3535         have_children = spawn_flag;
3536
3537         if (check_config) {
3538                 DEBUG("%s: #### Skipping IP addresses and Ports ####",
3539                        mainconfig.name);
3540                 return 1;
3541         }
3542
3543 #ifdef WITH_SELF_PIPE
3544         /*
3545          *      Child threads need a pipe to signal us, as do the
3546          *      signal handlers.
3547          */
3548         if (pipe(self_pipe) < 0) {
3549                 radlog(L_ERR, "radiusd: Error opening internal pipe: %s",
3550                        strerror(errno));
3551                 exit(1);
3552         }
3553         if (fcntl(self_pipe[0], F_SETFL, O_NONBLOCK | FD_CLOEXEC) < 0) {
3554                 radlog(L_ERR, "radiusd: Error setting internal flags: %s",
3555                        strerror(errno));
3556                 exit(1);
3557         }
3558         if (fcntl(self_pipe[1], F_SETFL, O_NONBLOCK | FD_CLOEXEC) < 0) {
3559                 radlog(L_ERR, "radiusd: Error setting internal flags: %s",
3560                        strerror(errno));
3561                 exit(1);
3562         }
3563
3564         if (!fr_event_fd_insert(el, 0, self_pipe[0],
3565                                   event_signal_handler, el)) {
3566                 radlog(L_ERR, "Failed creating handler for signals");
3567                 exit(1);
3568         }
3569 #endif  /* WITH_SELF_PIPE */
3570
3571 #ifdef WITH_PROXY
3572         /*
3573          *      Mark the proxy Fd's as unused.
3574          */
3575         {
3576                 int i;
3577
3578                 for (i = 0; i < 32; i++) proxy_fds[i] = -1;
3579         }
3580 #endif
3581
3582        DEBUG("%s: #### Opening IP addresses and Ports ####",
3583                mainconfig.name);
3584
3585        /*
3586         *       The server temporarily switches to an unprivileged
3587         *       user very early in the bootstrapping process.
3588         *       However, some sockets MAY require privileged access
3589         *       (bind to device, or to port < 1024, or to raw
3590         *       sockets).  Those sockets need to call suid up/down
3591         *       themselves around the functions that need a privileged
3592         *       uid.
3593         */
3594         if (listen_init(cs, &head) < 0) {
3595                 _exit(1);
3596         }
3597         
3598         /*
3599          *      At this point, no one has any business *ever* going
3600          *      back to root uid.
3601          */
3602         fr_suid_down_permanent();
3603
3604         /*
3605          *      Add all of the sockets to the event loop.
3606          */
3607         for (this = head;
3608              this != NULL;
3609              this = this->next) {
3610                 char buffer[256];
3611
3612                 this->print(this, buffer, sizeof(buffer));
3613
3614                 switch (this->type) {
3615 #ifdef WITH_DETAIL
3616                 case RAD_LISTEN_DETAIL:
3617                         DEBUG("Listening on %s", buffer);
3618
3619                         /*
3620                          *      Detail files are always known, and aren't
3621                          *      put into the socket event loop.
3622                          */
3623                         this->status = RAD_LISTEN_STATUS_KNOWN;
3624
3625                         /*
3626                          *      Set up the first poll interval.
3627                          */
3628                         event_poll_detail(this);
3629                         break;
3630 #endif
3631
3632 #ifdef WITH_PROXY
3633                 case RAD_LISTEN_PROXY:
3634                         rad_assert(proxy_fds[this->fd & 0x1f] == -1);
3635                         rad_assert(proxy_listeners[this->fd & 0x1f] == NULL);
3636                         
3637                         proxy_fds[this->fd & 0x1f] = this->fd;
3638                         proxy_listeners[this->fd & 0x1f] = this;
3639                         if (!fr_packet_list_socket_add(proxy_list,
3640                                                          this->fd)) {
3641                                 rad_assert(0 == 1);
3642                         }
3643                         /* FALL-THROUGH */
3644 #endif
3645
3646                 default:
3647                         break;
3648                 }
3649
3650                 event_new_fd(this);
3651         }
3652
3653         mainconfig.listen = head;
3654
3655         return 1;
3656 }
3657
3658
3659 static int request_hash_cb(UNUSED void *ctx, void *data)
3660 {
3661         REQUEST *request = fr_packet2myptr(REQUEST, packet, data);
3662
3663 #ifdef WITH_PROXY
3664         rad_assert(request->in_proxy_hash == FALSE);
3665 #endif
3666
3667         ev_request_free(&request);
3668
3669         return 0;
3670 }
3671
3672
3673 #ifdef WITH_PROXY
3674 static int proxy_hash_cb(UNUSED void *ctx, void *data)
3675 {
3676         REQUEST *request = fr_packet2myptr(REQUEST, proxy, data);
3677
3678         ev_request_free(&request);
3679
3680         return 0;
3681 }
3682 #endif
3683
3684 void radius_event_free(void)
3685 {
3686         /*
3687          *      FIXME: Stop all threads, or at least check that
3688          *      they're all waiting on the semaphore, and the queues
3689          *      are empty.
3690          */
3691
3692 #ifdef WITH_PROXY
3693         /*
3694          *      There are requests in the proxy hash that aren't
3695          *      referenced from anywhere else.  Remove them first.
3696          */
3697         if (proxy_list) {
3698                 fr_packet_list_walk(proxy_list, NULL, proxy_hash_cb);
3699                 fr_packet_list_free(proxy_list);
3700                 proxy_list = NULL;
3701         }
3702 #endif
3703
3704         fr_packet_list_walk(pl, NULL, request_hash_cb);
3705
3706         fr_packet_list_free(pl);
3707         pl = NULL;
3708
3709         fr_event_list_free(el);
3710 }
3711
3712 int radius_event_process(void)
3713 {
3714         if (!el) return 0;
3715
3716         return fr_event_loop(el);
3717 }
3718
3719 void radius_handle_request(REQUEST *request, RAD_REQUEST_FUNP fun)
3720 {
3721         request->options = RAD_REQUEST_OPTION_DEBUG2;
3722
3723         if (request_pre_handler(request)) {
3724                 rad_assert(fun != NULL);
3725                 rad_assert(request != NULL);
3726                 
3727                 if (request->server) RDEBUG("server %s {",
3728                                             request->server != NULL ?
3729                                             request->server : ""); 
3730                 fun(request);
3731
3732                 if (request->server) RDEBUG("} # server %s",
3733                                              request->server != NULL ?
3734                                             request->server : "");
3735
3736                 request_post_handler(request);
3737         }
3738
3739         DEBUG2("Going to the next request");
3740         return;
3741 }