50ddc9268f0f18e62be8180d78589b577e52748c
[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
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/modules.h>
30 #include <freeradius-devel/event.h>
31 #include <freeradius-devel/radius_snmp.h>
32
33 #include <freeradius-devel/rad_assert.h>
34
35 #ifdef HAVE_SIGNAL_H
36 #include <signal.h>
37 #endif
38
39 #define USEC (1000000)
40
41 /*
42  *      Ridiculous amounts of local state.
43  */
44 static lrad_event_list_t        *el = NULL;
45 static lrad_packet_list_t       *pl = NULL;
46 static int                      request_num_counter = 0;
47 static struct timeval           now;
48 static time_t                   start_time;
49 static int                      have_children;
50
51 #ifdef HAVE_PTHREAD_H
52 static pthread_mutex_t  proxy_mutex;
53
54 #define PTHREAD_MUTEX_LOCK if (have_children) pthread_mutex_lock
55 #define PTHREAD_MUTEX_UNLOCK if (have_children) pthread_mutex_unlock
56 #else
57 /*
58  *      This is easier than ifdef's throughout the code.
59  */
60 #define PTHREAD_MUTEX_LOCK(_x)
61 #define PTHREAD_MUTEX_UNLOCK(_x)
62 #endif
63
64 static lrad_packet_list_t *proxy_list = NULL;
65
66 /*
67  *      We keep the proxy FD's here.  The RADIUS Id's are marked
68  *      "allocated" per Id, via a bit per proxy FD.
69  */
70 static int              proxy_fds[32];
71 static rad_listen_t     *proxy_listeners[32];
72
73
74 static void _rad_panic(const char *file, unsigned int line, const char *msg)
75 {
76         radlog(L_ERR, "]%s:%d] %s", file, line, msg);
77         _exit(1);
78 }
79
80 #define rad_panic(x) _rad_panic(__FILE__, __LINE__, x)
81
82
83 /*
84  *      FIXME FIXME: Do SNMP, but smarter...  have an array[code].foo,
85  *      so we increment counters by just using code as an offset.  The
86  *      array should be the union of the server && client SNMP
87  *      variables, which should simplify it a lot.
88  */
89
90 static void tv_add(struct timeval *tv, int usec_delay)
91 {
92         if (usec_delay > USEC) {
93                 tv->tv_sec += usec_delay / USEC;
94                 usec_delay %= USEC;
95         }
96         tv->tv_usec += usec_delay;
97
98         if (tv->tv_usec > USEC) {
99                 tv->tv_usec -= USEC;
100                 tv->tv_sec++;
101         }
102 }
103
104
105 static void remove_from_request_hash(REQUEST *request)
106 {
107 #ifdef WITH_SNMP
108         /*
109          *      Update the SNMP statistics.
110          *
111          *      Note that we do NOT do this in a child thread.
112          *      Instead, we update the stats when a request is
113          *      deleted, because only the main server thread calls
114          *      this function...
115          */
116         if (mainconfig.do_snmp) {
117                 switch (request->reply->code) {
118                 case PW_AUTHENTICATION_ACK:
119                   rad_snmp.auth.total_responses++;
120                   rad_snmp.auth.total_access_accepts++;
121                   break;
122
123                 case PW_AUTHENTICATION_REJECT:
124                   rad_snmp.auth.total_responses++;
125                   rad_snmp.auth.total_access_rejects++;
126                   break;
127
128                 case PW_ACCESS_CHALLENGE:
129                   rad_snmp.auth.total_responses++;
130                   rad_snmp.auth.total_access_challenges++;
131                   break;
132
133                 case PW_ACCOUNTING_RESPONSE:
134                   rad_snmp.acct.total_responses++;
135                   break;
136
137                 default:
138                         break;
139                 }
140         }
141 #endif
142
143         if (!request->in_request_hash) return;
144
145         lrad_packet_list_yank(pl, request->packet);
146         request->in_request_hash = FALSE;
147 }
148
149
150 static REQUEST *lookup_in_proxy_hash(RADIUS_PACKET *reply)
151 {
152         RADIUS_PACKET **proxy_p;
153         REQUEST *request;
154
155         PTHREAD_MUTEX_LOCK(&proxy_mutex);
156         proxy_p = lrad_packet_list_find_byreply(proxy_list, reply);
157
158         if (!proxy_p) {
159                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
160                 return NULL;
161         }
162
163         request = lrad_packet2myptr(REQUEST, proxy, proxy_p);
164                 
165         if (!request) {
166                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
167                 return NULL;
168         }
169
170         request->num_proxied_responses++;
171
172         /*
173          *      Catch the most common case of everything working
174          *      correctly.
175          */
176         if (request->num_proxied_requests == request->num_proxied_responses) {
177                 /*
178                  *      FIXME: remove from the event list, too?
179                  */
180                 lrad_packet_list_yank(proxy_list, request->proxy);
181                 lrad_packet_list_id_free(proxy_list, request->proxy);
182                 request->in_proxy_hash = FALSE;
183         }
184
185         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
186
187         return request;
188 }
189
190
191 static void remove_from_proxy_hash(REQUEST *request)
192 {
193         if (!request->in_proxy_hash) return;
194
195         PTHREAD_MUTEX_LOCK(&proxy_mutex);
196         request->home_server->currently_outstanding--;
197         lrad_packet_list_yank(proxy_list, request->proxy);
198         lrad_packet_list_id_free(proxy_list, request->proxy);
199         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
200
201         request->in_proxy_hash = FALSE;
202 }
203
204
205 static int insert_into_proxy_hash(REQUEST *request)
206 {
207         int i, proxy;
208         char buf[128];
209
210         rad_assert(request->proxy != NULL);
211         rad_assert(proxy_list != NULL);
212
213         request->proxy->sockfd = -1;
214
215         PTHREAD_MUTEX_LOCK(&proxy_mutex);
216
217         request->home_server->currently_outstanding++;
218
219         if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
220                 int found;
221                 rad_listen_t *proxy_listener;
222
223                 /*
224                  *      Allocate a new proxy fd.  This function adds it
225                  *      into the list of listeners.
226                  */
227                 proxy_listener = proxy_new_listener();
228                 if (!proxy_listener) {
229                         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
230                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
231                         return 0;
232                 }
233
234                 /*
235                  *      Cache it locally.
236                  */
237                 found = -1;
238                 proxy = proxy_listener->fd;
239                 for (i = 0; i < 32; i++) {
240                         DEBUG2("PROXY %d %d", i, proxy_fds[(proxy + i) & 0x1f]);
241
242                         /*
243                          *      Found a free entry.  Save the socket,
244                          *      and remember where we saved it.
245                          */
246                         if (proxy_fds[(proxy + i) & 0x1f] == -1) {
247                                 found = (proxy + i) & 0x1f;
248                                 proxy_fds[found] = proxy;
249                                 proxy_listeners[found] = proxy_listener;
250                                 break;
251                         }
252                 }
253                 rad_assert(found >= 0);
254
255                 if (!lrad_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
256                         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
257                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
258                         return 0; /* leak proxy_listener */
259                         
260                 }
261                     
262                 if (!lrad_packet_list_id_alloc(proxy_list, request->proxy)) {
263                         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
264                         DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
265                         return 0;
266                 }
267         }
268         rad_assert(request->proxy->sockfd >= 0);
269
270         /*
271          *      FIXME: Hack until we get rid of rad_listen_t, and put
272          *      the information into the packet_list.
273          */
274         proxy = -1;
275         for (i = 0; i < 32; i++) {
276                 if (proxy_fds[i] == request->proxy->sockfd) {
277                         proxy = i;
278                         break;
279                 }
280         }
281
282         if (proxy < 0) {
283                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
284                 DEBUG2("ERROR: All sockets are full.");
285                 return 0;
286         }
287
288         rad_assert(proxy_fds[proxy] != -1);
289         rad_assert(proxy_listeners[proxy] != NULL);
290         request->proxy_listener = proxy_listeners[proxy];
291
292         if (!lrad_packet_list_insert(proxy_list, &request->proxy)) {
293                 /* FIXME: free id? */
294                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
295                 DEBUG2("ERROR: Failed to insert entry into proxy list");
296                 return 0;
297         }
298         
299         PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
300
301         DEBUG3(" proxy: allocating destination %s port %d - Id %d",
302                inet_ntop(request->proxy->dst_ipaddr.af,
303                          &request->proxy->dst_ipaddr.ipaddr, buf, sizeof(buf)),
304                request->proxy->dst_port,
305                request->proxy->id);
306         
307         request->in_proxy_hash = TRUE;
308
309         return 1;
310 }
311
312
313 /*
314  *      Called as BOTH an event, and in-line from other functions.
315  */
316 static void wait_for_proxy_id_to_expire(void *ctx)
317 {
318         REQUEST *request = ctx;
319         home_server *home = request->home_server;
320
321         rad_assert(request->magic == REQUEST_MAGIC);
322         rad_assert(request->proxy != NULL);
323
324         request->when = request->proxy_when;
325         request->when.tv_sec += home->response_window;
326
327         if ((request->num_proxied_requests == request->num_proxied_responses) ||
328             timercmp(&now, &request->when, >)) {
329                 if (request->packet) {
330                         DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
331                                request->number, request->packet->id,
332                                (unsigned int) (request->timestamp - start_time));
333                 } else {
334                         DEBUG2("Cleaning up request %d with timestamp +%d",
335                                request->number,
336                                (unsigned int) (request->timestamp - start_time));
337                 }
338                 lrad_event_delete(el, request);
339                 remove_from_proxy_hash(request);
340                 remove_from_request_hash(request);
341                 request_free(&request);
342                 return;
343         }
344
345         if (!lrad_event_insert(el, wait_for_proxy_id_to_expire,
346                                request, &request->when)) {
347                 rad_panic("Failed to insert event");
348         }
349 }
350
351
352 static void wait_for_child_to_die(void *ctx)
353 {
354         REQUEST *request = ctx;
355
356         rad_assert(request->magic == REQUEST_MAGIC);
357
358         if ((request->child_state == REQUEST_QUEUED) |
359             (request->child_state == REQUEST_RUNNING)) {
360                 request->delay += (request->delay >> 1);
361                 tv_add(&request->when, request->delay);
362                 
363                 DEBUG2("Child is still stuck for request %d", request->number);
364                 if (!lrad_event_insert(el, wait_for_child_to_die,
365                                        request, &request->when)) {
366                         rad_panic("Failed to insert event");
367                 }
368                 return;
369         }
370         
371         DEBUG2("Child is finally responsive for request %d", request->number);
372         remove_from_request_hash(request);
373
374         if (request->proxy) {
375                 return wait_for_proxy_id_to_expire(request);
376         }
377
378         request_free(&request);
379 }
380
381
382 static void cleanup_delay(void *ctx)
383 {
384         REQUEST *request = ctx;
385
386         rad_assert(request->magic == REQUEST_MAGIC);
387         rad_assert(request->child_state == REQUEST_CLEANUP_DELAY);
388
389         remove_from_request_hash(request);
390
391         if (request->proxy) {
392                 return wait_for_proxy_id_to_expire(request);
393         }
394
395         DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
396                request->number, request->packet->id,
397                (unsigned int) (request->timestamp - start_time));
398
399         request_free(&request); 
400 }
401
402
403 static void reject_delay(void *ctx)
404 {
405         REQUEST *request = ctx;
406
407         rad_assert(request->magic == REQUEST_MAGIC);
408         rad_assert(request->child_state == REQUEST_REJECT_DELAY);
409
410         DEBUG2("Sending delayed reject for request %d", request->number);
411
412         request->listener->send(request->listener, request);
413
414         request->when.tv_sec += mainconfig.cleanup_delay;
415         request->child_state = REQUEST_CLEANUP_DELAY;
416
417         if (!lrad_event_insert(el, cleanup_delay,
418                                request, &request->when)) {
419                 rad_panic("Failed to insert event");
420         }
421 }
422
423
424 static void revive_home_server(void *ctx)
425 {
426         home_server *home = ctx;
427
428         home->state = HOME_STATE_ALIVE;
429         DEBUG2("Marking home server alive again... we have no idea if it really is alive or not.");
430 }
431
432
433 static void no_response_to_ping(void *ctx)
434 {
435         REQUEST *request = ctx;
436         home_server *home = request->home_server;
437         char buffer[128];
438
439         home->num_received_pings = 0;
440
441         DEBUG2("No response to ping %d from home server %s port %d",
442                request->number,
443                inet_ntop(request->proxy->dst_ipaddr.af,
444                          &request->proxy->dst_ipaddr.ipaddr,
445                          buffer, sizeof(buffer)),
446                request->proxy->dst_port);
447
448         wait_for_proxy_id_to_expire(request);   
449 }
450
451
452 static void received_response_to_ping(REQUEST *request)
453 {
454         home_server *home = request->home_server;
455         char buffer[128];
456
457         home->num_received_pings++;
458
459         DEBUG2("Received response to ping %d (%d in current sequence)",
460                request->number, home->num_received_pings);
461
462         if (home->num_received_pings < home->num_pings_to_alive) {
463                 wait_for_proxy_id_to_expire(request);
464                 return;
465         }
466
467         DEBUG2("Marking home server %s port %d alive",
468                inet_ntop(request->proxy->dst_ipaddr.af,
469                          &request->proxy->dst_ipaddr.ipaddr,
470                          buffer, sizeof(buffer)),
471                request->proxy->dst_port);
472
473         if (!lrad_event_delete(el, home)) {
474                 DEBUG2("Hmm... no event for home server, WTF?");
475         }
476
477         if (!lrad_event_delete(el, request)) {
478                 DEBUG2("Hmm... no event for request, WTF?");
479         }
480
481         wait_for_proxy_id_to_expire(request);
482
483         home->state = HOME_STATE_ALIVE;
484 }
485
486
487 static void ping_home_server(void *ctx)
488 {
489         uint32_t jitter;
490         home_server *home = ctx;
491         REQUEST *request;
492         VALUE_PAIR *vp;
493
494         if (home->state == HOME_STATE_ALIVE) {
495                 radlog(L_INFO, "Suspicious proxy state... continuing");
496                 return;
497         }
498
499         request = request_alloc();
500         request->number = request_num_counter++;
501
502         request->proxy = rad_alloc(1);
503         rad_assert(request->proxy != NULL);
504
505         gettimeofday(&request->when, NULL);
506         home->when = request->when;
507
508         if (home->ping_check == HOME_PING_CHECK_STATUS_SERVER) {
509                 request->proxy->code = PW_STATUS_SERVER;
510
511                 vp = pairmake("Message-Authenticator", "0x00", T_OP_SET);
512                 if (!vp) rad_panic("Out of memory");
513                 pairadd(&request->proxy->vps, vp);
514
515         } else if (home->type == HOME_TYPE_AUTH) {
516                 request->proxy->code = PW_AUTHENTICATION_REQUEST;
517
518                 vp = pairmake("User-Name", home->ping_user_name, T_OP_SET);
519                 if (!vp) rad_panic("Out of memory");
520                 pairadd(&request->proxy->vps, vp);
521
522                 vp = pairmake("User-Password", home->ping_user_password, T_OP_SET);
523                 if (!vp) rad_panic("Out of memory");
524                 pairadd(&request->proxy->vps, vp);
525
526                 vp = pairmake("Service-Type", "Authenticate-Only", T_OP_SET);
527                 if (!vp) rad_panic("Out of memory");
528                 pairadd(&request->proxy->vps, vp);
529
530                 vp = pairmake("Message-Authenticator", "0x00", T_OP_SET);
531                 if (!vp) rad_panic("Out of memory");
532                 pairadd(&request->proxy->vps, vp);
533
534         } else {
535                 request->proxy->code = PW_ACCOUNTING_REQUEST;
536
537                 vp = pairmake("User-Name", home->ping_user_name, T_OP_SET);
538                 if (!vp) rad_panic("Out of memory");
539                 pairadd(&request->proxy->vps, vp);
540
541                 vp = pairmake("Acct-Status-Type", "Stop", T_OP_SET);
542                 if (!vp) rad_panic("Out of memory");
543                 pairadd(&request->proxy->vps, vp);
544
545                 vp = pairmake("Acct-Session-Id", "00000000", T_OP_SET);
546                 if (!vp) rad_panic("Out of memory");
547                 pairadd(&request->proxy->vps, vp);
548
549                 vp = pairmake("Event-Timestamp", "0", T_OP_SET);
550                 if (!vp) rad_panic("Out of memory");
551                 vp->vp_date = now.tv_sec;
552                 pairadd(&request->proxy->vps, vp);
553         }
554
555         vp = pairmake("NAS-Identifier", "Ping! Are you alive?", T_OP_SET);
556         if (!vp) rad_panic("Out of memory");
557         pairadd(&request->proxy->vps, vp);
558
559         request->proxy->dst_ipaddr = home->ipaddr;
560         request->proxy->dst_port = home->port;
561         request->home_server = home;
562
563         rad_assert(request->proxy_listener == NULL);
564
565         if (!insert_into_proxy_hash(request)) {
566                 DEBUG2("Failed inserting ping %d into proxy hash.  Discarding it.",
567                        request->number);
568                 request_free(&request);
569                 return;
570         }
571         rad_assert(request->proxy_listener != NULL);
572         request->proxy_listener->send(request->proxy_listener,
573                                       request);
574
575         /*
576          *      FIXME: add a separate timeout for ping packets!
577          */
578         request->child_state = REQUEST_PROXIED;
579         request->when.tv_sec += mainconfig.cleanup_delay;
580
581         if (!lrad_event_insert(el, no_response_to_ping,
582                                request, &request->when)) {
583                 rad_panic("Failed to insert event");
584         }
585
586         /*
587          *      Add +/- 2s of jitter, as suggested in RFC 3539
588          *      and in the Issues and Fixes draft.
589          */
590         home->when.tv_sec += home->ping_interval - 2;
591
592         jitter = lrad_rand();
593         jitter ^= (jitter >> 10);
594         jitter &= ((1 << 23) - 1); /* 22 bits of 1 */
595
596         tv_add(&home->when, jitter);
597
598         if (!lrad_event_insert(el, ping_home_server,
599                                home, &home->when)) {
600                 rad_panic("Failed to insert event");
601         }
602 }
603
604
605 /* maybe check this against wait_for_proxy_id_to_expire? */
606 static void no_response_to_proxied_request(void *ctx)
607 {
608         REQUEST *request = ctx;
609         home_server *home;
610         struct timeval when;
611         char buffer[128];
612         
613         rad_assert(request->magic == REQUEST_MAGIC);
614         rad_assert(request->child_state == REQUEST_PROXIED);
615
616         radlog(L_ERR, "Rejecting request %d due to lack of any response from home server %s port %d",
617                request->number,
618                inet_ntop(request->proxy->dst_ipaddr.af,
619                          &request->proxy->dst_ipaddr.ipaddr,
620                          buffer, sizeof(buffer)),
621                request->proxy->dst_port);
622
623         if ((request->proxy->code == PW_ACCOUNTING_REQUEST) ||
624             (request->proxy->code == PW_STATUS_SERVER)) {
625                 remove_from_request_hash(request);
626                 wait_for_proxy_id_to_expire(request);
627
628         } else {
629                 /* FIXME: run it through post-auth reject section? */
630
631                 request->reply->code = PW_AUTHENTICATION_REJECT;
632
633                 request->listener->send(request->listener, request);
634
635                 request->child_state = REQUEST_CLEANUP_DELAY;
636                 request->when.tv_sec += mainconfig.cleanup_delay;
637                         
638                 /* cleanup_delay calls wait_for_proxy_id_to_expire */
639                 if (!lrad_event_insert(el, cleanup_delay,
640                                        request, &request->when)) {
641                         rad_panic("Failed to insert event");
642                 }
643         }
644                 
645         home = request->home_server;
646         if (home->state == HOME_STATE_IS_DEAD) {
647                 /* FIXME: assert that some event is set for the home server */
648                 return;
649         }
650
651         /*
652          *      Enable the zombie period when we notice that the home
653          *      server hasn't responded.  We also back-date the start
654          *      of the zombie period to when the proxied request was
655          *      sent.
656          */
657         if (home->state == HOME_STATE_ALIVE) {
658                 DEBUG2("WARNING: Home server %s port %d may be dead.",
659                        inet_ntop(request->proxy->dst_ipaddr.af,
660                                  &request->proxy->dst_ipaddr.ipaddr,
661                                  buffer, sizeof(buffer)),
662                        request->proxy->dst_port);
663                 home->state = HOME_STATE_ZOMBIE;
664                 home->zombie_period_start = now;
665                 home->zombie_period_start.tv_sec -= home->response_window;
666                 return;
667         }
668
669         when = home->zombie_period_start;
670         when.tv_sec += home->zombie_period;
671
672         if (timercmp(&now, &when, <)) {
673                 return;
674         }
675
676         /*
677          *      It's been a zombie for too long, mark it as
678          *      dead.
679          */
680         home->state = HOME_STATE_IS_DEAD;
681         home->num_received_pings = 0;
682         home->when = request->when;
683         
684         if (home->ping_check != HOME_PING_CHECK_NONE) {
685                 rad_assert((home->ping_check == HOME_PING_CHECK_STATUS_SERVER) ||
686                            (home->ping_user_name != NULL));
687                 home->when.tv_sec += home->ping_interval;
688                 if (!lrad_event_insert(el, ping_home_server,
689                                                home, &home->when)) {
690                         rad_panic("Failed to insert event");
691                 }
692         } else {
693                 home->when.tv_sec += home->revive_interval;
694                 if (!lrad_event_insert(el, revive_home_server,
695                                        home, &home->when)) {
696                         rad_panic("Failed to insert event");
697                 }
698         }
699 }
700
701
702 static void wait_a_bit(void *ctx)
703 {
704         struct timeval when;
705         REQUEST *request = ctx;
706         lrad_event_callback_t callback = NULL;
707
708         rad_assert(request->magic == REQUEST_MAGIC);
709
710         switch (request->child_state) {
711         case REQUEST_QUEUED:
712         case REQUEST_RUNNING:
713                 when = request->received;
714                 when.tv_sec += mainconfig.max_request_time;
715
716                 if (timercmp(&now, &when, <)) {
717                         callback = wait_a_bit;
718                 } else {
719                         /* FIXME: kill unresponsive children? */
720                         radlog(L_ERR, "WARNING: Unresponsive child (id %lu) for request %d, in module %s component %s",
721                                (unsigned long)request->child_pid, request->number,
722                                request->module ? request->module : "<server core>",
723                                request->component ? request->component : "<server core>");             
724
725                         request->master_state = REQUEST_STOP_PROCESSING;
726
727                         request->delay = 500000;
728                         tv_add(&request->when, request->delay);
729                         callback = wait_for_child_to_die;
730                 }
731                 request->delay += request->delay >> 1;
732                 break;
733
734         case REQUEST_PROXIED:
735         case REQUEST_REJECT_DELAY:
736         case REQUEST_CLEANUP_DELAY:
737                 rad_assert(request->next_callback != NULL);
738
739                 request->when = request->next_when;
740                 callback = request->next_callback;
741                 request->next_callback = NULL;
742                 break;
743
744         case REQUEST_DONE:
745                 request->child_pid = NO_SUCH_CHILD_PID;
746                 if (request->proxy) {
747                         return wait_for_proxy_id_to_expire(request);
748                 }
749                 return;
750
751         default:
752                 rad_panic("Internal sanity check failure");
753                 return;
754         }
755
756 #if 0
757         /*
758          *      FIXME: Print time as "+%d.%06d", as that's more
759          *      understandable than 32-bit numbers.
760          */
761         DEBUG2("Inserting event for request %d at time %d.%06d",
762                request->number,
763                (int) request->when.tv_sec, (int) request->when.tv_usec);
764 #endif
765
766         if (!lrad_event_insert(el, callback,
767                                request, &request->when)) {
768                 rad_panic("Failed to insert event");
769         }
770 }
771
772
773 static int request_pre_handler(REQUEST *request)
774 {
775         int rcode;
776
777         rad_assert(request->magic == REQUEST_MAGIC);
778         rad_assert(request->packet != NULL);
779         rad_assert(request->packet->dst_port != 0);
780
781         request->child_state = REQUEST_RUNNING;
782
783         /*
784          *      Don't decode the packet if it's an internal "fake"
785          *      request.  Instead, just return so that the caller can
786          *      process it.
787          */
788         if (request->packet->dst_port == 0) {
789                 request->username = pairfind(request->packet->vps,
790                                              PW_USER_NAME);
791                 request->password = pairfind(request->packet->vps,
792                                              PW_USER_PASSWORD);
793                 return 1;
794         }
795
796         /*
797          *      Put the decoded packet into it's proper place.
798          */
799         if (request->proxy_reply != NULL) {
800                 rcode = request->proxy_listener->decode(request->proxy_listener,
801                                                         request);
802         } else {
803                 rcode = request->listener->decode(request->listener, request);
804         }
805
806         if (rcode < 0) {
807                 radlog(L_ERR, "%s Dropping packet without response.", librad_errstr);
808                 request->child_state = REQUEST_DONE;
809                 return 0;
810         }
811
812         if (!request->proxy) {
813                 request->username = pairfind(request->packet->vps,
814                                              PW_USER_NAME);
815         } else {
816                 int post_proxy_type = 0;
817                 VALUE_PAIR *vp;
818
819                 /*
820                  *      Delete any reply we had accumulated until now.
821                  */
822                 pairfree(&request->reply->vps);
823                 
824                 /*
825                  *      Run the packet through the post-proxy stage,
826                  *      BEFORE playing games with the attributes.
827                  */
828                 vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
829                 if (vp) {
830                         DEBUG2("  Found Post-Proxy-Type %s", vp->vp_strvalue);
831                         post_proxy_type = vp->lvalue;
832                 }
833                 rcode = module_post_proxy(post_proxy_type, request);
834                 
835                 /*
836                  *      Delete the Proxy-State Attributes from the reply.
837                  *      These include Proxy-State attributes from us and
838                  *      remote server.
839                  */
840                 pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
841                 
842                 /*
843                  *      Add the attributes left in the proxy reply to
844                  *      the reply list.
845                  */
846                 pairadd(&request->reply->vps, request->proxy_reply->vps);
847                 request->proxy_reply->vps = NULL;
848                 
849                 /*
850                  *      Free proxy request pairs.
851                  */
852                 pairfree(&request->proxy->vps);
853                 
854                 /*
855                  *      FIXME: If the packet is an Access-Challenge,
856                  *      THEN add it to a cache, which does:
857                  *
858                  *      (src IP, State) -> (home server ip/port)
859                  *
860                  *      This allows the load-balancing code to
861                  *      work for EAP...
862                  *
863                  *      Alternately, we can delete the State from the home
864                  *      server, and use our own..  that might be better.
865                  */
866                 
867                 switch (rcode) {
868                 default:  /* Don't Do Anything */
869                         break;
870                 case RLM_MODULE_FAIL:
871                         /* FIXME: debug print stuff */
872                         request->child_state = REQUEST_DONE;
873                         return 0;
874
875                 case RLM_MODULE_HANDLED:
876                         /* FIXME: debug print stuff */
877                         request->child_state = REQUEST_DONE;
878                         return 0;
879                 }
880         }
881
882         return 1;
883 }
884
885
886 /*
887  *      Return 1 if we did proxy it, or the proxy attempt failed
888  *      completely.  Either way, the caller doesn't touch the request
889  *      any more if we return 1.
890  */
891 static int successfully_proxied_request(REQUEST *request)
892 {
893         int rcode;
894         int pre_proxy_type = 0;
895         VALUE_PAIR *realmpair;
896         VALUE_PAIR *strippedname;
897         VALUE_PAIR *vp;
898         char *realmname;
899         home_server *home;
900         struct timeval when;
901         REALM *realm = NULL;
902         char buffer[128];
903
904         realmpair = pairfind(request->config_items, PW_PROXY_TO_REALM);
905         if (!realmpair ||
906             (realmpair->length == 0)) {
907                 return 0;
908         }
909
910         realmname = (char *) realmpair->vp_strvalue;
911
912         realm = realm_find(realmname);
913         if (!realm) {
914                 DEBUG2("ERROR: Cannot proxy to unknown realm %s",
915                        realmname);
916         reject_request:
917                 /*
918                  *      Failed proxying means silently discard
919                  *      accounting responses.
920                  */
921                 if (request->packet->code == PW_ACCOUNTING_REQUEST) {
922                         request->child_state = REQUEST_DONE;
923                         return 1;
924                 }
925                 
926                 rad_assert(request->packet->code == PW_AUTHENTICATION_REQUEST);
927                 
928                 request->reply->code = PW_AUTHENTICATION_REJECT;
929
930                 return 0;
931         }
932
933         if (((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
934              !realm->auth_pool) ||
935             ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
936              !realm->acct_pool)) {
937                 DEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
938                        realmname);
939                 return 0;
940         }
941         
942         home = home_server_ldb(realm, request->packet->code);
943         if (!home) {
944                 DEBUG2("ERROR: Failed to find live home server for realm %s",
945                        realmname);
946                 goto reject_request;
947         }
948
949         /*
950          *      Remember that we sent the request to a Realm.
951          */
952         pairadd(&request->packet->vps,
953                 pairmake("Realm", realmname, T_OP_EQ));
954
955         /*
956          *      We read the packet from a detail file, AND it came from
957          *      the server we're about to send it to.  Don't do that.
958          */
959         if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
960             (request->listener->type == RAD_LISTEN_DETAIL) &&
961             (home->ipaddr.af == AF_INET) &&
962             (request->packet->src_ipaddr.af == AF_INET) &&
963             (home->ipaddr.ipaddr.ip4addr.s_addr == request->packet->src_ipaddr.ipaddr.ip4addr.s_addr)) {
964                 DEBUG2("    rlm_realm: Packet came from realm %s, proxy cancelled", realmname);
965                 return 0;
966         }
967
968         /*
969          *      Allocate the proxy packet, only if it wasn't already
970          *      allocated by a module.  This check is mainly to support
971          *      the proxying of EAP-TTLS and EAP-PEAP tunneled requests.
972          *
973          *      In those cases, the EAP module creates a "fake"
974          *      request, and recursively passes it through the
975          *      authentication stage of the server.  The module then
976          *      checks if the request was supposed to be proxied, and
977          *      if so, creates a proxy packet from the TUNNELED request,
978          *      and not from the EAP request outside of the tunnel.
979          *
980          *      The proxy then works like normal, except that the response
981          *      packet is "eaten" by the EAP module, and encapsulated into
982          *      an EAP packet.
983          */
984         if (!request->proxy) {
985                 if ((request->proxy = rad_alloc(TRUE)) == NULL) {
986                         radlog(L_ERR|L_CONS, "no memory");
987                         exit(1);
988                 }
989
990                 /*
991                  *      Copy the request, then look up name and
992                  *      plain-text password in the copy.
993                  *
994                  *      Note that the User-Name attribute is the
995                  *      *original* as sent over by the client.  The
996                  *      Stripped-User-Name attribute is the one hacked
997                  *      through the 'hints' file.
998                  */
999                 request->proxy->vps =  paircopy(request->packet->vps);
1000         }
1001
1002         /*
1003          *      Strip the name, if told to.
1004          *
1005          *      Doing it here catches the case of proxied tunneled
1006          *      requests.
1007          */
1008         if (realm->striprealm == TRUE &&
1009            (strippedname = pairfind(request->proxy->vps, PW_STRIPPED_USER_NAME)) != NULL) {
1010                 /*
1011                  *      If there's a Stripped-User-Name attribute in
1012                  *      the request, then use THAT as the User-Name
1013                  *      for the proxied request, instead of the
1014                  *      original name.
1015                  *
1016                  *      This is done by making a copy of the
1017                  *      Stripped-User-Name attribute, turning it into
1018                  *      a User-Name attribute, deleting the
1019                  *      Stripped-User-Name and User-Name attributes
1020                  *      from the vps list, and making the new
1021                  *      User-Name the head of the vps list.
1022                  */
1023                 vp = pairfind(request->proxy->vps, PW_USER_NAME);
1024                 if (!vp) {
1025                         vp = paircreate(PW_USER_NAME, PW_TYPE_STRING);
1026                         if (!vp) {
1027                                 radlog(L_ERR|L_CONS, "no memory");
1028                                 exit(1);
1029                         }
1030                         vp->next = request->proxy->vps;
1031                         request->proxy->vps = vp;
1032                 }
1033                 memcpy(vp->vp_strvalue, strippedname->vp_strvalue,
1034                        sizeof(vp->vp_strvalue));
1035                 vp->length = strippedname->length;
1036
1037                 /*
1038                  *      Do NOT delete Stripped-User-Name.
1039                  */
1040         }
1041         
1042         /*
1043          *      If there is no PW_CHAP_CHALLENGE attribute but
1044          *      there is a PW_CHAP_PASSWORD we need to add it
1045          *      since we can't use the request authenticator
1046          *      anymore - we changed it.
1047          */
1048         if (pairfind(request->proxy->vps, PW_CHAP_PASSWORD) &&
1049             pairfind(request->proxy->vps, PW_CHAP_CHALLENGE) == NULL) {
1050                 vp = paircreate(PW_CHAP_CHALLENGE, PW_TYPE_STRING);
1051                 if (!vp) {
1052                         radlog(L_ERR|L_CONS, "no memory");
1053                         exit(1);
1054                 }
1055                 vp->length = AUTH_VECTOR_LEN;
1056                 memcpy(vp->vp_strvalue, request->packet->vector, AUTH_VECTOR_LEN);
1057                 pairadd(&(request->proxy->vps), vp);
1058         }
1059
1060         /*
1061          *      The RFC's say we have to do this, but FreeRADIUS
1062          *      doesn't need it.
1063          */
1064         vp = paircreate(PW_PROXY_STATE, PW_TYPE_STRING);
1065         if (!vp) {
1066                 radlog(L_ERR|L_CONS, "no memory");
1067                 exit(1);
1068         }
1069         sprintf(vp->vp_strvalue, "%d", request->packet->id);
1070         vp->length = strlen(vp->vp_strvalue);
1071
1072         pairadd(&request->proxy->vps, vp);
1073
1074         request->proxy->code = request->packet->code;
1075         request->proxy->dst_ipaddr = home->ipaddr;
1076         request->proxy->dst_port = home->port;
1077         request->home_server = home;
1078
1079         /*
1080          *      Call the pre-proxy routines.
1081          */
1082         vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
1083         if (vp) {
1084                 DEBUG2("  Found Pre-Proxy-Type %s", vp->vp_strvalue);
1085                 pre_proxy_type = vp->lvalue;
1086         }
1087         rcode = module_pre_proxy(pre_proxy_type, request);
1088         switch (rcode) {
1089         case RLM_MODULE_FAIL:
1090         case RLM_MODULE_INVALID:
1091         case RLM_MODULE_NOTFOUND:
1092         case RLM_MODULE_REJECT:
1093         case RLM_MODULE_USERLOCK:
1094         default:
1095                 /* FIXME: debug print failed stuff */
1096                 goto reject_request;
1097
1098         case RLM_MODULE_HANDLED:
1099                 return 0;
1100
1101         /*
1102          *      Only proxy the packet if the pre-proxy code succeeded.
1103          */
1104         case RLM_MODULE_NOOP:
1105         case RLM_MODULE_OK:
1106         case RLM_MODULE_UPDATED:
1107                 break;
1108         }
1109
1110         /*
1111          *      If it's a fake request, don't send the proxy
1112          *      packet.  The outer tunnel session will take
1113          *      care of doing that.
1114          */
1115         if (request->packet->dst_port == 0) {
1116                 return 1;
1117         }
1118         
1119         if (!insert_into_proxy_hash(request)) {
1120                 DEBUG("ERROR: Failed to proxy request %d", request->number);
1121                 goto reject_request;
1122         }
1123
1124         request->proxy_listener->encode(request->proxy_listener, request);
1125
1126         when = request->received;
1127         when.tv_sec += mainconfig.max_request_time;
1128         
1129         gettimeofday(&request->proxy_when, NULL);
1130
1131         request->next_when = request->proxy_when;
1132         request->next_when.tv_sec += home->response_window;
1133
1134         rad_assert(home->response_window > 0);
1135         
1136         if (timercmp(&when, &request->next_when, <)) {
1137                 request->next_when = when;
1138         }
1139         request->next_callback = no_response_to_proxied_request;
1140
1141         DEBUG2("Proxying request %d to realm %s, home server %s port %d",
1142                request->number, realmname,
1143                inet_ntop(request->proxy->dst_ipaddr.af,
1144                          &request->proxy->dst_ipaddr.ipaddr,
1145                          buffer, sizeof(buffer)),
1146                request->proxy->dst_port);
1147         
1148         /*
1149          *      Note that we set proxied AFTER creating the packet,
1150          *      but BEFORE actually sending it.
1151          *
1152          *      Once we send it, the request is tainted, as
1153          *      another thread may have picked it up.  Don't
1154          *      touch it!
1155          */
1156         request->num_proxied_requests = 1;
1157         request->num_proxied_responses = 0;
1158         request->child_state = REQUEST_PROXIED;
1159         request->proxy_listener->send(request->proxy_listener,
1160                                       request);
1161         return 1;
1162 }
1163
1164
1165 static void request_post_handler(REQUEST *request)
1166 {
1167         int child_state = -1;
1168         struct timeval when;
1169         VALUE_PAIR *vp;
1170
1171         if (request->master_state == REQUEST_STOP_PROCESSING) {
1172                 DEBUG2("Request %d was cancelled.", request->number);
1173                 request->child_state = REQUEST_DONE;
1174                 return;
1175         }
1176
1177         if (request->child_state != REQUEST_RUNNING) {
1178                 rad_panic("Internal sanity check failed");
1179         }
1180
1181         /*
1182          *      FIXME: check for Auth-Type = Reject, and reject it if so?
1183          *      this means don't proxy it.
1184          *
1185          *      FIXME: check if we can't proxy it because all of the
1186          *      home servers are dead or busy, and set post-auth-type
1187          *      "proxy fail", or something like that.
1188          */
1189
1190         if (mainconfig.proxy_requests &&
1191             (request->packet->code != PW_STATUS_SERVER) &&
1192             (request->reply->code == 0) &&
1193             !request->proxy &&
1194             successfully_proxied_request(request)) {
1195                 return;
1196         }
1197
1198         /*
1199          *      Fake requests don't get encoded or signed.  The caller
1200          *      also requires the reply VP's, so we don't free them
1201          *      here!
1202          */
1203         if (request->packet->dst_port == 0) {
1204                 /* FIXME: DEBUG going to the next request */
1205                 request->child_state = REQUEST_DONE;
1206                 return;
1207         }
1208
1209         /*
1210          *      Copy Proxy-State from the request to the reply.
1211          */
1212         vp = paircopy2(request->packet->vps, PW_PROXY_STATE);
1213         if (vp) pairadd(&request->reply->vps, vp);
1214
1215         /*
1216          *      Access-Requests get delayed or cached.
1217          */
1218         if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1219                 gettimeofday(&request->next_when, NULL);
1220
1221                 if (request->reply->code == 0) {
1222                         DEBUG2("There was no response configured: rejecting request %d",
1223                                request->number);
1224                         request->reply->code = PW_AUTHENTICATION_REJECT;
1225                 }
1226                 
1227                 /*
1228                  *      If configured, delay Access-Reject packets.
1229                  */
1230                 if ((request->reply->code == PW_AUTHENTICATION_REJECT) &&
1231                     (mainconfig.reject_delay > 0)) {
1232                         when = request->received;
1233                         when.tv_sec += mainconfig.reject_delay;
1234                         
1235                         if (timercmp(&when, &request->next_when, >)) {
1236                                 DEBUG2("Delaying reject of request %d for %d seconds",
1237                                        request->number,
1238                                        mainconfig.reject_delay);
1239                                 request->next_when = when;
1240                                 request->next_callback = reject_delay;
1241                                 request->child_state = REQUEST_REJECT_DELAY;
1242                                 return;
1243                         }
1244                 }
1245
1246                 request->next_when.tv_sec += mainconfig.cleanup_delay;
1247                 request->next_callback = cleanup_delay;
1248                 child_state = REQUEST_CLEANUP_DELAY;
1249
1250         } else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1251                 request->next_callback = NULL; /* just to be safe */
1252                 child_state = REQUEST_DONE;
1253
1254                 /*
1255                  *      FIXME: Status-Server should probably not be
1256                  *      handled here...
1257                  */
1258         } else if (request->packet->code == PW_STATUS_SERVER) {
1259                 request->next_callback = NULL;
1260                 child_state = REQUEST_DONE;
1261
1262         } else {
1263                 rad_panic("Unknown packet type");
1264         }
1265
1266         /*
1267          *      Encode, sign, and send.  The accounting request
1268          *      handler takes care of suppressing responses when
1269          *      request->reply->code == 0.
1270          */
1271         request->listener->send(request->listener, request);
1272
1273         /*
1274          *      Clean up.  These are no longer needed.
1275          */
1276         pairfree(&request->config_items);
1277
1278         pairfree(&request->packet->vps);
1279         request->username = NULL;
1280         request->password = NULL;
1281
1282         pairfree(&request->reply->vps);
1283
1284         if (request->proxy) {
1285                 pairfree(&request->proxy->vps);
1286         }
1287         if (request->proxy_reply) {
1288                 pairfree(&request->proxy_reply->vps);
1289         }
1290
1291         DEBUG2("Finished request %d state %d", request->number, child_state);
1292
1293         request->child_state = child_state;
1294 }
1295
1296
1297 static void received_retransmit(REQUEST *request, const RADCLIENT *client)
1298 {
1299         char buffer[128];
1300
1301         switch (request->child_state) {
1302         case REQUEST_QUEUED:
1303         case REQUEST_RUNNING:
1304                 radlog(L_ERR, "Discarding duplicate request from "
1305                        "client %s port %d - ID: %d due to unfinished request %d",
1306                        client->shortname,
1307                        request->packet->src_port,request->packet->id,
1308                        request->number);
1309                 break;
1310
1311         case REQUEST_PROXIED:
1312                 DEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d",
1313                        inet_ntop(request->proxy->dst_ipaddr.af,
1314                                  &request->proxy->dst_ipaddr.ipaddr,
1315                                  buffer, sizeof(buffer)),
1316                        request->proxy->dst_port,
1317                        request->proxy->id);
1318                 request->num_proxied_requests++;
1319                 request->proxy_listener->send(request->proxy_listener,
1320                                               request);
1321                 break;
1322
1323         case REQUEST_REJECT_DELAY:
1324                 DEBUG2("Waiting to send Access-Reject "
1325                        "to client %s port %d - ID: %d",
1326                        client->shortname,
1327                        request->packet->src_port, request->packet->id);
1328                 break;
1329
1330         case REQUEST_CLEANUP_DELAY:
1331         case REQUEST_DONE:
1332                 DEBUG2("Sending duplicate reply "
1333                        "to client %s port %d - ID: %d",
1334                        client->shortname,
1335                        request->packet->src_port, request->packet->id);
1336                 request->listener->send(request->listener, request);
1337                 break;
1338         }
1339 }
1340
1341
1342 static void received_conflicting_request(REQUEST *request,
1343                                          const RADCLIENT *client)
1344 {
1345         radlog(L_ERR, "Received conflicting packet from "
1346                "client %s port %d - ID: %d due to unfinished request %d.  Giving up on old request.",
1347                client->shortname,
1348                request->packet->src_port, request->packet->id,
1349                request->number);
1350
1351         switch (request->child_state) {
1352         case REQUEST_QUEUED:
1353         case REQUEST_RUNNING:
1354                 request->master_state = REQUEST_STOP_PROCESSING;
1355                 request->delay += request->delay >> 1;
1356
1357                 tv_add(&request->when, request->delay);
1358
1359                 if (!lrad_event_insert(el,
1360                                        wait_for_child_to_die,
1361                                        request, &request->when)) {
1362                         rad_panic("Failed to insert event");
1363                 }
1364                 return;
1365
1366         default:
1367                 break;
1368         }
1369
1370         remove_from_request_hash(request);
1371
1372         /*
1373          *      The request stays in the event queue.  At some point,
1374          *      the child will notice, and we can then delete it.
1375          */
1376 }
1377
1378
1379 static int can_handle_new_request(RADIUS_PACKET *packet,
1380                                   const RADCLIENT *client)
1381 {
1382         /*
1383          *      Count the total number of requests, to see if
1384          *      there are too many.  If so, return with an
1385          *      error.
1386          */
1387         if (mainconfig.max_requests) {
1388                 int request_count = lrad_packet_list_num_elements(pl);
1389                 
1390                 /*
1391                  *      This is a new request.  Let's see if
1392                  *      it makes us go over our configured
1393                  *      bounds.
1394                  */
1395                 if (request_count > mainconfig.max_requests) {
1396                         radlog(L_ERR, "Dropping request (%d is too many): "
1397                                "from client %s port %d - ID: %d", request_count,
1398                                client->shortname,
1399                                packet->src_port, packet->id);
1400                         radlog(L_INFO, "WARNING: Please check the %s file.\n"
1401                                "\tThe value for 'max_requests' is probably set too low.\n", mainconfig.radiusd_conf);
1402                         return 0;
1403                 } /* else there were a small number of requests */
1404         } /* else there was no configured limit for requests */
1405
1406         /*
1407          *      FIXME: Add per-client checks.  If one client is sending
1408          *      too many packets, start discarding them.
1409          *
1410          *      We increment the counters here, and decrement them
1411          *      when the response is sent... somewhere in this file.
1412          */
1413         
1414         /*
1415          *      FUTURE: Add checks for system load.  If the system is
1416          *      busy, start dropping requests...
1417          *
1418          *      We can probably keep some statistics ourselves...  if
1419          *      there are more requests coming in than we can handle,
1420          *      start dropping some.
1421          */
1422         
1423         return 1;
1424 }
1425
1426
1427 int received_request(rad_listen_t *listener,
1428                      RADIUS_PACKET *packet, REQUEST **prequest,
1429                      const RADCLIENT *client)
1430 {
1431         RADIUS_PACKET **packet_p;
1432         REQUEST *request = NULL;
1433
1434         packet_p = lrad_packet_list_find(pl, packet);
1435         if (packet_p) {
1436                 request = lrad_packet2myptr(REQUEST, packet, packet_p);
1437
1438                 if (memcmp(request->packet->vector, packet->vector,
1439                            sizeof(packet->vector)) == 0) {
1440                         received_retransmit(request, client);
1441                         return 0;
1442                 }
1443                 received_conflicting_request(request, client);
1444                 request = NULL;
1445
1446         } else if (!can_handle_new_request(packet, client)) {
1447                 return 0;
1448         }
1449
1450         /*
1451          *      Create and initialize the new request.
1452          */
1453         request = request_alloc(); /* never fails */
1454         
1455         if ((request->reply = rad_alloc(0)) == NULL) {
1456                 radlog(L_ERR, "No memory");
1457                 exit(1);
1458         }
1459
1460         request->listener = listener;
1461         request->packet = packet;
1462         request->packet->timestamp = request->timestamp;
1463         request->number = request_num_counter++;
1464         strlcpy(request->secret, client->secret, sizeof(request->secret));
1465         
1466         /*
1467          *      Remember the request in the list.
1468          */
1469         if (!lrad_packet_list_insert(pl, &request->packet)) {
1470                 radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", request->number);
1471                 request_free(&request);
1472                 return 0;
1473         }
1474         request->in_request_hash = TRUE;
1475         
1476         /*
1477          *      The request passes many of our sanity checks.
1478          *      From here on in, if anything goes wrong, we
1479          *      send a reject message, instead of dropping the
1480          *      packet.
1481          */
1482
1483         /*
1484          *      Build the reply template from the request.
1485          */
1486
1487         request->reply->sockfd = request->packet->sockfd;
1488         request->reply->dst_ipaddr = request->packet->src_ipaddr;
1489         request->reply->src_ipaddr = request->packet->dst_ipaddr;
1490         request->reply->dst_port = request->packet->src_port;
1491         request->reply->src_port = request->packet->dst_port;
1492         request->reply->id = request->packet->id;
1493         request->reply->code = 0; /* UNKNOWN code */
1494         memcpy(request->reply->vector, request->packet->vector,
1495                sizeof(request->reply->vector));
1496         request->reply->vps = NULL;
1497         request->reply->data = NULL;
1498         request->reply->data_len = 0;
1499
1500         request->master_state = REQUEST_ACTIVE;
1501         request->child_state = REQUEST_QUEUED;
1502         request->next_callback = NULL;
1503
1504         gettimeofday(&request->received, NULL);
1505         request->when = request->received;
1506         request->delay = USEC / 10;
1507
1508         tv_add(&request->when, request->delay);
1509
1510         if (!lrad_event_insert(el, wait_a_bit,
1511                                request, &request->when)) {
1512                 rad_panic("Failed to insert event");
1513         }
1514
1515         *prequest = request;
1516         return 1;
1517 }
1518
1519
1520 REQUEST *received_proxy_response(RADIUS_PACKET *packet)
1521 {
1522         char            buffer[128];
1523         home_server     *home;
1524         REQUEST         *request;
1525
1526         if (!home_server_find(&packet->src_ipaddr, packet->src_port)) {
1527                 radlog(L_ERR, "Ignoring request from unknown home server %s port %d",
1528                        inet_ntop(packet->src_ipaddr.af,
1529                                  &packet->src_ipaddr.ipaddr,
1530                                  buffer, sizeof(buffer)),
1531                                packet->src_port);
1532                 rad_free(&packet);
1533                 return NULL;
1534         }
1535
1536         /*
1537          *      Also removes from the proxy hash if responses == requests
1538          */
1539         request = lookup_in_proxy_hash(packet);
1540
1541         if (!request) {
1542                 radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s port %d - ID %d",
1543                        inet_ntop(packet->src_ipaddr.af,
1544                                  &packet->src_ipaddr.ipaddr,
1545                                  buffer, sizeof(buffer)),
1546                        packet->src_port, packet->id);
1547                 rad_free(&packet);
1548                 return NULL;
1549         }
1550
1551         home = request->home_server;
1552
1553         gettimeofday(&now, NULL);
1554         home->state = HOME_STATE_ALIVE;
1555
1556         if (request->reply && request->reply->code != 0) {
1557                 DEBUG2("We already replied to this request.  Discarding response from home server.");
1558                 rad_free(&packet);
1559                 return NULL;
1560         }
1561
1562         /*
1563          *      We had previously received a reply, so we don't need
1564          *      to do anything here.
1565          */
1566         if (request->proxy_reply) {
1567                 if (memcmp(request->proxy_reply->vector,
1568                            packet->vector,
1569                            sizeof(request->proxy_reply->vector)) == 0) {
1570                         DEBUG2("Discarding duplicate reply from home server %s port %d  - ID: %d for request %d",
1571                                inet_ntop(packet->src_ipaddr.af,
1572                                          &packet->src_ipaddr.ipaddr,
1573                                          buffer, sizeof(buffer)),
1574                                packet->src_port, packet->id,
1575                                request->number);
1576                 } else {
1577                         /*
1578                          *      ? The home server gave us a new proxy
1579                          *      reply, which doesn't match the old
1580                          *      one.  Delete it.
1581                          */
1582                         DEBUG2("Ignoring conflicting proxy reply");
1583                 }
1584
1585                 /* assert that there's an event queued for request? */
1586                 rad_free(&packet);
1587                 return NULL;
1588         }
1589
1590         switch (request->child_state) {
1591         case REQUEST_QUEUED:
1592         case REQUEST_RUNNING:
1593                 rad_panic("Internal sanity check failed for child state");
1594                 break;
1595
1596         case REQUEST_REJECT_DELAY:
1597         case REQUEST_CLEANUP_DELAY:
1598         case REQUEST_DONE:
1599                 radlog(L_ERR, "Reply from home server %s port %d  - ID: %d arrived too late for request %d. Try increasing 'retry_delay' or 'max_request_time'",
1600                        inet_ntop(packet->src_ipaddr.af,
1601                                  &packet->src_ipaddr.ipaddr,
1602                                  buffer, sizeof(buffer)),
1603                        packet->src_port, packet->id,
1604                        request->number);
1605                 /* assert that there's an event queued for request? */
1606                 rad_free(&packet);
1607                 return NULL;
1608                 
1609         case REQUEST_PROXIED:
1610                 break;
1611         }
1612
1613         request->proxy_reply = packet;
1614
1615         /*
1616          *      There's no incoming request, so it's a proxied packet
1617          *      we originated.
1618          */
1619         if (!request->packet) {
1620                 received_response_to_ping(request);
1621                 return NULL;
1622         }
1623
1624         request->child_state = REQUEST_QUEUED;
1625         request->when = now;
1626         request->delay = USEC / 10;
1627         tv_add(&request->when, request->delay);
1628
1629         /*
1630          *      Wait a bit will take care of max_request_time
1631          */
1632         if (!lrad_event_insert(el, wait_a_bit,
1633                                request, &request->when)) {
1634                 rad_panic("Failed to insert event");
1635         }
1636
1637         return request;
1638 }
1639
1640
1641 /*
1642  *      Externally-visibly functions.
1643  */
1644 int radius_event_init(int spawn_flag)
1645 {
1646         if (el) return 0;
1647
1648         time(&start_time);
1649
1650         el = lrad_event_list_create();
1651         if (!el) return 0;
1652
1653         pl = lrad_packet_list_create(0);
1654         if (!el) return 0;
1655
1656         request_num_counter = 0;
1657
1658         /*
1659          *      Move all of the thread calls to this file?
1660          *
1661          *      It may be best for the mutexes to be in this file...
1662          */
1663         have_children = spawn_flag;
1664
1665         if (mainconfig.proxy_requests) {
1666                 int i;
1667                 rad_listen_t *listener;
1668                         
1669                 /*
1670                  *      Create the tree for managing proxied requests and
1671                  *      responses.
1672                  */
1673                 proxy_list = lrad_packet_list_create(1);
1674                 if (!proxy_list) return 0;
1675                 
1676 #ifdef HAVE_PTHREAD_H
1677                 if (pthread_mutex_init(&proxy_mutex, NULL) != 0) {
1678                         radlog(L_ERR, "FATAL: Failed to initialize proxy mutex: %s",
1679                                strerror(errno));
1680                         exit(1);
1681                 }
1682 #endif
1683
1684                 /*
1685                  *      Mark the Fd's as unused.
1686                  */
1687                 for (i = 0; i < 32; i++) proxy_fds[i] = -1;
1688                 
1689                 i = -1;
1690
1691                 for (listener = mainconfig.listen;
1692                      listener != NULL;
1693                      listener = listener->next) {
1694                         if (listener->type == RAD_LISTEN_PROXY) {
1695                                 /*
1696                                  *      FIXME: This works only because we
1697                                  *      start off with one proxy socket.
1698                                  */
1699                                 rad_assert(proxy_fds[listener->fd & 0x1f] == -1);
1700                                 rad_assert(proxy_listeners[listener->fd & 0x1f] == NULL);
1701
1702                                 proxy_fds[listener->fd & 0x1f] = listener->fd;
1703                                 proxy_listeners[listener->fd & 0x1f] = listener;
1704                                 if (!lrad_packet_list_socket_add(proxy_list, listener->fd)) {
1705                                         rad_assert(0 == 1);
1706                                 }
1707                                 i = listener->fd;
1708                         }
1709                 }
1710
1711                 if (mainconfig.proxy_requests) rad_assert(i >= 0);
1712         }
1713
1714         thread_pool_init(spawn_flag);
1715
1716         return 1;
1717 }
1718
1719
1720 static int request_hash_cb(void *ctx, void *data)
1721 {
1722         ctx = ctx;              /* -Wunused */
1723         REQUEST *request = lrad_packet2myptr(REQUEST, packet, data);
1724
1725         rad_assert(request->in_proxy_hash == FALSE);
1726
1727         lrad_event_delete(el, request);
1728         remove_from_request_hash(request);
1729         request_free(&request);
1730
1731         return 0;
1732 }
1733
1734
1735 static int proxy_hash_cb(void *ctx, void *data)
1736 {
1737         ctx = ctx;              /* -Wunused */
1738         REQUEST *request = lrad_packet2myptr(REQUEST, proxy, data);
1739
1740         lrad_packet_list_yank(proxy_list, request->proxy);
1741         request->in_proxy_hash = FALSE;
1742
1743         if (!request->in_request_hash) {
1744                 lrad_event_delete(el, request);
1745                 request_free(&request);
1746         }
1747
1748         return 0;
1749 }
1750
1751
1752 void radius_event_free(void)
1753 {
1754         /*
1755          *      FIXME: Stop all threads, or at least check that
1756          *      they're all waiting on the semaphore, and the queues
1757          *      are empty.
1758          */
1759
1760         /*
1761          *      There are requests in the proxy hash that aren't
1762          *      referenced from anywhere else.  Remove them first.
1763          */
1764         if (proxy_list) {
1765                 PTHREAD_MUTEX_LOCK(&proxy_mutex);
1766                 lrad_packet_list_walk(proxy_list, NULL, proxy_hash_cb);
1767                 PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
1768                 lrad_packet_list_free(proxy_list);
1769                 proxy_list = NULL;
1770         }
1771
1772         lrad_packet_list_walk(pl, NULL, request_hash_cb);
1773
1774         lrad_packet_list_free(pl);
1775         pl = NULL;
1776
1777         lrad_event_list_free(el);
1778 }
1779
1780 int radius_event_process(struct timeval **pptv)
1781 {
1782         int rcode;
1783         struct timeval when;
1784
1785         if (!el) return 0;
1786
1787         if (lrad_event_list_num_elements(el) == 0) {
1788                 *pptv = NULL;
1789                 return 1;
1790         }
1791
1792         gettimeofday(&now, NULL);
1793         when = now;
1794
1795         do {
1796                 rcode = lrad_event_run(el, &when);
1797         } while (rcode == 1);
1798
1799         gettimeofday(&now, NULL);
1800
1801         if ((when.tv_sec == 0) && (when.tv_usec == 0)) {
1802                 if (lrad_event_list_num_elements(el) == 0) {
1803                         *pptv = NULL;
1804                         return 1;
1805                 }
1806                 rad_panic("Internal sanity check failed");
1807                 
1808         } else if (timercmp(&now, &when, >)) {
1809                 DEBUG2("WTF?");
1810                 when.tv_sec = 0;
1811                 when.tv_usec = 1;
1812
1813         } else {
1814                 when.tv_sec -= now.tv_sec;
1815                 when.tv_usec -= now.tv_usec;
1816                 if (when.tv_usec < 0) {
1817                         when.tv_sec--;
1818                         when.tv_usec += USEC;
1819                 }
1820         }
1821         **pptv = when;
1822
1823         return 1;
1824 }
1825
1826 void radius_handle_request(REQUEST *request, RAD_REQUEST_FUNP fun)
1827 {
1828         if (!request_pre_handler(request)) {
1829                 DEBUG2("Going to the next request at X");
1830                 return;
1831         }
1832         
1833         rad_assert(fun != NULL);
1834         rad_assert(request != NULL);
1835         
1836         fun(request);
1837         
1838         request_post_handler(request);
1839         DEBUG2("Going to the next request");
1840         return;
1841 }
1842