15d5bc9d92818d7823cec9abbb8d220ff74da989
[freeradius.git] / src / lib / packet.c
1 /*
2  * packet.c     Generic packet manipulation functions.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library 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 GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000-2006  The FreeRADIUS server project
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/libradius.h>
27
28 #ifdef WITH_UDPFROMTO
29 #include        <freeradius-devel/udpfromto.h>
30 #endif
31
32 #include <fcntl.h>
33
34 /*
35  *      Take the key fields of a request packet, and convert it to a
36  *      hash.
37  */
38 uint32_t fr_request_packet_hash(const RADIUS_PACKET *packet)
39 {
40         uint32_t hash;
41
42         if (packet->hash) return packet->hash;
43
44         hash = fr_hash(&packet->sockfd, sizeof(packet->sockfd));
45         hash = fr_hash_update(&packet->src_port, sizeof(packet->src_port),
46                                 hash);
47         hash = fr_hash_update(&packet->dst_port,
48                                 sizeof(packet->dst_port), hash);
49         hash = fr_hash_update(&packet->src_ipaddr.af,
50                                 sizeof(packet->src_ipaddr.af), hash);
51
52         /*
53          *      The caller ensures that src & dst AF are the same.
54          */
55         switch (packet->src_ipaddr.af) {
56         case AF_INET:
57                 hash = fr_hash_update(&packet->src_ipaddr.ipaddr.ip4addr,
58                                         sizeof(packet->src_ipaddr.ipaddr.ip4addr),
59                                         hash);
60                 hash = fr_hash_update(&packet->dst_ipaddr.ipaddr.ip4addr,
61                                         sizeof(packet->dst_ipaddr.ipaddr.ip4addr),
62                                         hash);
63                 break;
64         case AF_INET6:
65                 hash = fr_hash_update(&packet->src_ipaddr.ipaddr.ip6addr,
66                                         sizeof(packet->src_ipaddr.ipaddr.ip6addr),
67                                         hash);
68                 hash = fr_hash_update(&packet->dst_ipaddr.ipaddr.ip6addr,
69                                         sizeof(packet->dst_ipaddr.ipaddr.ip6addr),
70                                         hash);
71                 break;
72         default:
73                 break;
74         }
75
76         return fr_hash_update(&packet->id, sizeof(packet->id), hash);
77 }
78
79
80 /*
81  *      Take the key fields of a reply packet, and convert it to a
82  *      hash.
83  *
84  *      i.e. take a reply packet, and find the hash of the request packet
85  *      that asked for the reply.  To do this, we hash the reverse fields
86  *      of the request.  e.g. where the request does (src, dst), we do
87  *      (dst, src)
88  */
89 uint32_t fr_reply_packet_hash(const RADIUS_PACKET *packet)
90 {
91         uint32_t hash;
92
93         hash = fr_hash(&packet->sockfd, sizeof(packet->sockfd));
94         hash = fr_hash_update(&packet->id, sizeof(packet->id), hash);
95         hash = fr_hash_update(&packet->src_port, sizeof(packet->src_port),
96                                 hash);
97         hash = fr_hash_update(&packet->dst_port,
98                                 sizeof(packet->dst_port), hash);
99         hash = fr_hash_update(&packet->src_ipaddr.af,
100                                 sizeof(packet->src_ipaddr.af), hash);
101
102         /*
103          *      The caller ensures that src & dst AF are the same.
104          */
105         switch (packet->src_ipaddr.af) {
106         case AF_INET:
107                 hash = fr_hash_update(&packet->dst_ipaddr.ipaddr.ip4addr,
108                                         sizeof(packet->dst_ipaddr.ipaddr.ip4addr),
109                                         hash);
110                 hash = fr_hash_update(&packet->src_ipaddr.ipaddr.ip4addr,
111                                         sizeof(packet->src_ipaddr.ipaddr.ip4addr),
112                                         hash);
113                 break;
114         case AF_INET6:
115                 hash = fr_hash_update(&packet->dst_ipaddr.ipaddr.ip6addr,
116                                         sizeof(packet->dst_ipaddr.ipaddr.ip6addr),
117                                         hash);
118                 hash = fr_hash_update(&packet->src_ipaddr.ipaddr.ip6addr,
119                                         sizeof(packet->src_ipaddr.ipaddr.ip6addr),
120                                         hash);
121                 break;
122         default:
123                 break;
124         }
125
126         return fr_hash_update(&packet->id, sizeof(packet->id), hash);
127 }
128
129
130 /*
131  *      See if two packets are identical.
132  *
133  *      Note that we do NOT compare the authentication vectors.
134  *      That's because if the authentication vector is different,
135  *      it means that the NAS has given up on the earlier request.
136  */
137 int fr_packet_cmp(const RADIUS_PACKET *a, const RADIUS_PACKET *b)
138 {
139         int rcode;
140
141         if (a->sockfd < b->sockfd) return -1;
142         if (a->sockfd > b->sockfd) return +1;
143
144         if (a->id < b->id) return -1;
145         if (a->id > b->id) return +1;
146
147         if (a->src_port < b->src_port) return -1;
148         if (a->src_port > b->src_port) return +1;
149
150         if (a->dst_port < b->dst_port) return -1;
151         if (a->dst_port > b->dst_port) return +1;
152
153         rcode = fr_ipaddr_cmp(&a->dst_ipaddr, &b->dst_ipaddr);
154         if (rcode != 0) return rcode;
155         return fr_ipaddr_cmp(&a->src_ipaddr, &b->src_ipaddr);
156 }
157
158 int fr_inaddr_any(fr_ipaddr_t *ipaddr)
159 {
160
161         if (ipaddr->af == AF_INET) {
162                 if (ipaddr->ipaddr.ip4addr.s_addr == INADDR_ANY) {
163                         return 1;
164                 }
165                 
166 #ifdef HAVE_STRUCT_SOCKADDR_IN6
167         } else if (ipaddr->af == AF_INET6) {
168                 if (IN6_IS_ADDR_UNSPECIFIED(&(ipaddr->ipaddr.ip6addr))) {
169                         return 1;
170                 }
171 #endif
172                 
173         } else {
174                 fr_strerror_printf("Unknown address family");
175                 return -1;
176         }
177
178         return 0;
179 }
180
181
182 /*
183  *      Create a fake "request" from a reply, for later lookup.
184  */
185 void fr_request_from_reply(RADIUS_PACKET *request,
186                              const RADIUS_PACKET *reply)
187 {
188         request->sockfd = reply->sockfd;
189         request->id = reply->id;
190         request->src_port = reply->dst_port;
191         request->dst_port = reply->src_port;
192         request->src_ipaddr = reply->dst_ipaddr;
193         request->dst_ipaddr = reply->src_ipaddr;
194 }
195
196
197 int fr_nonblock(UNUSED int fd)
198 {
199         int flags = 0;
200
201 #ifdef O_NONBLOCK
202
203         flags = fcntl(fd, F_GETFL, NULL);
204         if (flags >= 0) {
205                 flags |= O_NONBLOCK;
206                 return fcntl(fd, F_SETFL, flags);
207         }
208 #endif
209         return flags;
210 }
211
212 /*
213  *      Open a socket on the given IP and port.
214  */
215 int fr_socket(fr_ipaddr_t *ipaddr, int port)
216 {
217         int sockfd;
218         struct sockaddr_storage salocal;
219         socklen_t       salen;
220
221         if ((port < 0) || (port > 65535)) {
222                 fr_strerror_printf("Port %d is out of allowed bounds", port);
223                 return -1;
224         }
225
226         sockfd = socket(ipaddr->af, SOCK_DGRAM, 0);
227         if (sockfd < 0) {
228                 fr_strerror_printf("cannot open socket: %s", strerror(errno));
229                 return sockfd;
230         }
231
232 #ifdef WITH_UDPFROMTO
233         /*
234          *      Initialize udpfromto for all sockets.
235          */
236         if (udpfromto_init(sockfd) != 0) {
237                 close(sockfd);
238                 fr_strerror_printf("cannot initialize udpfromto: %s", strerror(errno));
239                 return -1;
240         }
241 #endif
242
243         if (fr_nonblock(sockfd) < 0) {
244                 close(sockfd);
245                 return -1;
246         }
247
248         if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) {
249                 return sockfd;
250         }
251
252 #ifdef HAVE_STRUCT_SOCKADDR_IN6
253         if (ipaddr->af == AF_INET6) {
254                 /*
255                  *      Listening on '::' does NOT get you IPv4 to
256                  *      IPv6 mapping.  You've got to listen on an IPv4
257                  *      address, too.  This makes the rest of the server
258                  *      design a little simpler.
259                  */
260 #ifdef IPV6_V6ONLY
261
262                 if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) {
263                         int on = 1;
264
265                         setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
266                                    (char *)&on, sizeof(on));
267                 }
268 #endif /* IPV6_V6ONLY */
269         }
270 #endif /* HAVE_STRUCT_SOCKADDR_IN6 */
271
272         if (ipaddr->af == AF_INET) {
273                 UNUSED int flag;
274                 
275 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
276                 /*
277                  *      Disable PMTU discovery.  On Linux, this
278                  *      also makes sure that the "don't fragment"
279                  *      flag is zero.
280                  */
281                 flag = IP_PMTUDISC_DONT;
282                 setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER,
283                            &flag, sizeof(flag));
284 #endif
285
286 #if defined(IP_DONTFRAG)
287                 /*
288                  *      Ensure that the "don't fragment" flag is zero.
289                  */
290                 flag = 0;
291                 setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG,
292                            &flag, sizeof(flag));
293 #endif
294         }
295
296         if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
297                 close(sockfd);
298                 fr_strerror_printf("cannot bind socket: %s", strerror(errno));
299                 return -1;
300         }
301
302         return sockfd;
303 }
304
305
306 /*
307  *      We need to keep track of the socket & it's IP/port.
308  */
309 typedef struct fr_packet_socket_t {
310         int             sockfd;
311         void            *ctx;
312
313         int             num_outgoing;
314
315         int             src_any;
316         fr_ipaddr_t     src_ipaddr;
317         int             src_port;
318
319         int             dst_any;
320         fr_ipaddr_t     dst_ipaddr;
321         int             dst_port;
322
323         int             dont_use;
324
325 #ifdef WITH_TCP
326         int             proto;
327 #endif
328
329         uint8_t         id[32];
330 } fr_packet_socket_t;
331
332
333 #define FNV_MAGIC_PRIME (0x01000193)
334 #define MAX_SOCKETS (256)
335 #define SOCKOFFSET_MASK (MAX_SOCKETS - 1)
336 #define SOCK2OFFSET(sockfd) ((sockfd * FNV_MAGIC_PRIME) & SOCKOFFSET_MASK)
337
338 #define MAX_QUEUES (8)
339
340 /*
341  *      Structure defining a list of packets (incoming or outgoing)
342  *      that should be managed.
343  */
344 struct fr_packet_list_t {
345         fr_hash_table_t *ht;
346
347         int             alloc_id;
348         int             num_outgoing;
349         int             last_recv;
350         int             num_sockets;
351
352         fr_packet_socket_t sockets[MAX_SOCKETS];
353 };
354
355
356 /*
357  *      Ugh.  Doing this on every sent/received packet is not nice.
358  */
359 static fr_packet_socket_t *fr_socket_find(fr_packet_list_t *pl,
360                                           int sockfd)
361 {
362         int i, start;
363
364         i = start = SOCK2OFFSET(sockfd);
365
366         do {                    /* make this hack slightly more efficient */
367                 if (pl->sockets[i].sockfd == sockfd) return &pl->sockets[i];
368
369                 i = (i + 1) & SOCKOFFSET_MASK;
370         } while (i != start);
371
372         return NULL;
373 }
374
375 int fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd)
376 {
377         fr_packet_socket_t *ps;
378
379         if (!pl) {
380                 fr_strerror_printf("Invalid argument");
381                 return 0;
382         }
383
384         ps = fr_socket_find(pl, sockfd);
385         if (!ps) {
386                 fr_strerror_printf("No such socket");
387                 return 0;
388         }
389
390         ps->dont_use = 1;
391         return 1;
392 }
393
394 int fr_packet_list_socket_remove(fr_packet_list_t *pl, int sockfd,
395                                  void **pctx)
396 {
397         fr_packet_socket_t *ps;
398
399         if (!pl) return 0;
400
401         ps = fr_socket_find(pl, sockfd);
402         if (!ps) return 0;
403
404         /*
405          *      FIXME: Allow the caller forcibly discard these?
406          */
407         if (ps->num_outgoing != 0) return 0;
408
409         ps->sockfd = -1;
410         pl->num_sockets--;
411         if (pctx) *pctx = ps->ctx;
412
413         return 1;
414 }
415
416 int fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto,
417                               fr_ipaddr_t *dst_ipaddr, int dst_port,
418                               void *ctx)
419 {
420         int i, start;
421         struct sockaddr_storage src;
422         socklen_t               sizeof_src;
423         fr_packet_socket_t      *ps;
424
425         if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) {
426                 fr_strerror_printf("Invalid argument");
427                 return 0;
428         }
429
430         if (pl->num_sockets >= MAX_SOCKETS) {
431                 fr_strerror_printf("Too many open sockets");
432                 return 0;
433         }
434
435 #ifndef WITH_TCP
436         if (proto != IPPROTO_UDP) {
437                 fr_strerror_printf("only UDP is supported");
438                 return 0;
439         }
440 #endif
441
442         ps = NULL;
443         i = start = SOCK2OFFSET(sockfd);
444
445         do {
446                 if (pl->sockets[i].sockfd == -1) {
447                         ps =  &pl->sockets[i];
448                         start = i;
449                         break;
450                 }
451
452                 i = (i + 1) & SOCKOFFSET_MASK;
453         } while (i != start);
454
455         if (!ps) {
456                 fr_strerror_printf("All socket entries are full");
457                 return 0;
458         }
459
460         memset(ps, 0, sizeof(*ps));
461         ps->ctx = ctx;
462 #ifdef WITH_TCP
463         ps->proto = proto;
464 #endif
465
466         /*
467          *      Get address family, etc. first, so we know if we
468          *      need to do udpfromto.
469          *
470          *      FIXME: udpfromto also does this, but it's not
471          *      a critical problem.
472          */
473         sizeof_src = sizeof(src);
474         memset(&src, 0, sizeof_src);
475         if (getsockname(sockfd, (struct sockaddr *) &src,
476                         &sizeof_src) < 0) {
477                 fr_strerror_printf("%s", strerror(errno));
478                 return 0;
479         }
480
481         if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->src_ipaddr,
482                                 &ps->src_port)) {
483                 fr_strerror_printf("Failed to get IP");
484                 return 0;
485         }
486
487         ps->dst_ipaddr = *dst_ipaddr;
488         ps->dst_port = dst_port;
489
490         ps->src_any = fr_inaddr_any(&ps->src_ipaddr);
491         if (ps->src_any < 0) return 0;
492
493         ps->dst_any = fr_inaddr_any(&ps->dst_ipaddr);
494         if (ps->dst_any < 0) return 0;
495
496         /*
497          *      As the last step before returning.
498          */
499         ps->sockfd = sockfd;
500         pl->num_sockets++;
501
502         return 1;
503 }
504
505 static uint32_t packet_entry_hash(const void *data)
506 {
507         return fr_request_packet_hash(*(const RADIUS_PACKET * const *) data);
508 }
509
510 static int packet_entry_cmp(const void *one, const void *two)
511 {
512         const RADIUS_PACKET * const *a = one;
513         const RADIUS_PACKET * const *b = two;
514
515         if (!a || !*a || !b || !*b) return -1; /* work-around for bug #35 */
516
517         return fr_packet_cmp(*a, *b);
518 }
519
520 void fr_packet_list_free(fr_packet_list_t *pl)
521 {
522         if (!pl) return;
523
524         fr_hash_table_free(pl->ht);
525         free(pl);
526 }
527
528
529 /*
530  *      Caller is responsible for managing the packet entries.
531  */
532 fr_packet_list_t *fr_packet_list_create(int alloc_id)
533 {
534         int i;
535         fr_packet_list_t        *pl;
536
537         pl = malloc(sizeof(*pl));
538         if (!pl) return NULL;
539         memset(pl, 0, sizeof(*pl));
540
541         pl->ht = fr_hash_table_create(packet_entry_hash,
542                                         packet_entry_cmp,
543                                         NULL);
544         if (!pl->ht) {
545                 fr_packet_list_free(pl);
546                 return NULL;
547         }
548
549         for (i = 0; i < MAX_SOCKETS; i++) {
550                 pl->sockets[i].sockfd = -1;
551         }
552
553         pl->alloc_id = alloc_id;
554
555         return pl;
556 }
557
558
559 /*
560  *      If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST
561  *      be called before inserting the packet into the list!
562  */
563 int fr_packet_list_insert(fr_packet_list_t *pl,
564                             RADIUS_PACKET **request_p)
565 {
566         if (!pl || !request_p || !*request_p) return 0;
567
568         (*request_p)->hash = fr_request_packet_hash(*request_p);
569
570         return fr_hash_table_insert(pl->ht, request_p);
571 }
572
573 RADIUS_PACKET **fr_packet_list_find(fr_packet_list_t *pl,
574                                       RADIUS_PACKET *request)
575 {
576         if (!pl || !request) return 0;
577
578         return fr_hash_table_finddata(pl->ht, &request);
579 }
580
581
582 /*
583  *      This presumes that the reply has dst_ipaddr && dst_port set up
584  *      correctly (i.e. real IP, or "*").
585  */
586 RADIUS_PACKET **fr_packet_list_find_byreply(fr_packet_list_t *pl,
587                                               RADIUS_PACKET *reply)
588 {
589         RADIUS_PACKET my_request, *request;
590         fr_packet_socket_t *ps;
591
592         if (!pl || !reply) return NULL;
593
594         ps = fr_socket_find(pl, reply->sockfd);
595         if (!ps) return NULL;
596
597         /*
598          *      Initialize request from reply, AND from the source
599          *      IP & port of this socket.  The client may have bound
600          *      the socket to 0, in which case it's some random port,
601          *      that is NOT in the original request->src_port.
602          */
603         my_request.sockfd = reply->sockfd;
604         my_request.id = reply->id;
605
606         if (ps->src_any) {
607                 my_request.src_ipaddr = ps->src_ipaddr;
608         } else {
609                 my_request.src_ipaddr = reply->dst_ipaddr;
610         }
611         my_request.src_port = ps->src_port;
612
613         my_request.dst_ipaddr = reply->src_ipaddr;
614         my_request.dst_port = reply->src_port;
615         my_request.hash = 0;
616
617         request = &my_request;
618
619         return fr_hash_table_finddata(pl->ht, &request);
620 }
621
622
623 RADIUS_PACKET **fr_packet_list_yank(fr_packet_list_t *pl,
624                                       RADIUS_PACKET *request)
625 {
626         if (!pl || !request) return NULL;
627
628         return fr_hash_table_yank(pl->ht, &request);
629 }
630
631 int fr_packet_list_num_elements(fr_packet_list_t *pl)
632 {
633         if (!pl) return 0;
634
635         return fr_hash_table_num_elements(pl->ht);
636 }
637
638
639 /*
640  *      1 == ID was allocated & assigned
641  *      0 == error allocating memory
642  *      -1 == all ID's are used, caller should open a new socket.
643  *
644  *      Note that this ALSO assigns a socket to use, and updates
645  *      packet->request->src_ipaddr && packet->request->src_port
646  *
647  *      In multi-threaded systems, the calls to id_alloc && id_free
648  *      should be protected by a mutex.  This does NOT have to be
649  *      the same mutex as the one protecting the insert/find/yank
650  *      calls!
651  *
652  *      We assume that the packet has dst_ipaddr && dst_port
653  *      already initialized.  We will use those to find an
654  *      outgoing socket.  The request MAY also have src_ipaddr set.
655  *
656  *      We also assume that the sender doesn't care which protocol
657  *      should be used.
658  */
659 int fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto,
660                             RADIUS_PACKET *request, void **pctx)
661 {
662         int i, j, k, fd, id, start_i, start_j, start_k;
663         int src_any = 0;
664         fr_packet_socket_t *ps;
665
666         if ((request->dst_ipaddr.af == AF_UNSPEC) ||
667             (request->dst_port == 0)) {
668                 fr_strerror_printf("No destination address/port specified");
669                 return 0;
670         }
671
672 #ifndef WITH_TCP
673         if ((proto != 0) && (proto != IPPROTO_UDP)) {
674                 fr_strerror_printf("Invalid destination protocol");
675                 return 0;
676         }
677 #endif
678
679         /*
680          *      Special case: unspec == "don't care"
681          */
682         if (request->src_ipaddr.af == AF_UNSPEC) {
683                 memset(&request->src_ipaddr, 0, sizeof(request->src_ipaddr));
684                 request->src_ipaddr.af = request->dst_ipaddr.af;
685         }
686
687         src_any = fr_inaddr_any(&request->src_ipaddr);
688         if (src_any < 0) return 0;
689
690         /*
691          *      MUST specify a destination address.
692          */
693         if (fr_inaddr_any(&request->dst_ipaddr) != 0) return 0;
694
695         /*
696          *      FIXME: Go to an LRU system.  This prevents ID re-use
697          *      for as long as possible.  The main problem with that
698          *      approach is that it requires us to populate the
699          *      LRU/FIFO when we add a new socket, or a new destination,
700          *      which can be expensive.
701          *
702          *      The LRU can be avoided if the caller takes care to free
703          *      Id's only when all responses have been received, OR after
704          *      a timeout.
705          *
706          *      Right now, the random approach is almost OK... it's
707          *      brute-force over all of the available ID's, BUT using
708          *      random numbers for everything spreads the load a bit.
709          *
710          *      The old method had a hash lookup on allocation AND
711          *      on free.  The new method has brute-force on allocation,
712          *      and near-zero cost on free.
713          */
714
715         id = fd = -1;
716         start_i = fr_rand() & SOCKOFFSET_MASK;
717
718 #define ID_i ((i + start_i) & SOCKOFFSET_MASK)
719         for (i = 0; i < MAX_SOCKETS; i++) {
720                 if (pl->sockets[ID_i].sockfd == -1) continue; /* paranoia */
721
722                 ps = &(pl->sockets[ID_i]);
723
724                 /*
725                  *      This socket is marked as "don't use for new
726                  *      packets".  But we can still receive packets
727                  *      that are outstanding.
728                  */
729                 if (ps->dont_use) continue;
730
731                 /*
732                  *      All IDs are allocated: ignore it.
733                  */
734                 if (ps->num_outgoing == 256) continue;
735
736 #ifdef WITH_TCP
737                 if (ps->proto != proto) continue;
738 #endif
739
740                 /*
741                  *      MUST match dst port, if we have one.
742                  */
743                 if ((ps->dst_port != 0) && 
744                     (ps->dst_port != request->dst_port)) continue;
745
746                 /*
747                  *      MUST match requested src port, if one has been given.
748                  */
749                 if ((request->src_port != 0) && 
750                     (ps->src_port != request->src_port)) continue;
751
752                 /*
753                  *      We're sourcing from *, and they asked for a
754                  *      specific source address: ignore it.
755                  */
756                 if (ps->src_any && !src_any) continue;
757
758                 /*
759                  *      We're sourcing from a specific IP, and they
760                  *      asked for a source IP that isn't us: ignore
761                  *      it.
762                  */
763                 if (!ps->src_any && !src_any &&
764                     (fr_ipaddr_cmp(&request->src_ipaddr,
765                                    &ps->src_ipaddr) != 0)) continue;
766
767                 /*
768                  *      UDP sockets are allowed to match
769                  *      destination IPs exactly, OR a socket
770                  *      with destination * is allowed to match
771                  *      any requested destination.
772                  *
773                  *      TCP sockets must match the destination
774                  *      exactly.  They *always* have dst_any=0,
775                  *      so the first check always matches.
776                  */
777                 if (!ps->dst_any &&
778                     (fr_ipaddr_cmp(&request->dst_ipaddr,
779                                    &ps->dst_ipaddr) != 0)) continue;
780                 
781                 /*
782                  *      Otherwise, this socket is OK to use.
783                  */
784
785                 /*
786                  *      Look for a free Id, starting from a random number.
787                  */
788                 start_j = fr_rand() & 0x1f;
789 #define ID_j ((j + start_j) & 0x1f)
790                 for (j = 0; j < 32; j++) {
791                         if (ps->id[ID_j] == 0xff) continue;
792
793
794                         start_k = fr_rand() & 0x07;
795 #define ID_k ((k + start_k) & 0x07)
796                         for (k = 0; k < 8; k++) {
797                                 if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
798
799                                 ps->id[ID_j] |= (1 << ID_k);
800                                 id = (ID_j * 8) + ID_k;
801                                 fd = i;
802                                 break;
803                         }
804                         if (fd >= 0) break;
805                 }
806 #undef ID_i
807 #undef ID_j
808 #undef ID_k
809                 if (fd >= 0) break;
810                 break;
811         }
812
813         /*
814          *      Ask the caller to allocate a new ID.
815          */
816         if (fd < 0) return 0;
817
818         ps->num_outgoing++;
819         pl->num_outgoing++;
820
821         /*
822          *      Set the ID, source IP, and source port.
823          */
824         request->id = id;
825
826         request->sockfd = ps->sockfd;
827         request->src_ipaddr = ps->src_ipaddr;
828         request->src_port = ps->src_port;
829
830         if (pctx) *pctx = ps->ctx;
831
832         return 1;
833 }
834
835 /*
836  *      Should be called AFTER yanking it from the list, so that
837  *      any newly inserted entries don't collide with this one.
838  */
839 int fr_packet_list_id_free(fr_packet_list_t *pl,
840                              RADIUS_PACKET *request)
841 {
842         fr_packet_socket_t *ps;
843
844         if (!pl || !request) return 0;
845
846         ps = fr_socket_find(pl, request->sockfd);
847         if (!ps) return 0;
848
849 #if 0
850         if (!ps->id[(request->id >> 3) & 0x1f] & (1 << (request->id & 0x07))) {
851                 exit(1);
852         }
853 #endif
854
855         ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
856         request->hash = 0;      /* invalidate the cached hash */
857
858         ps->num_outgoing--;
859         pl->num_outgoing--;
860
861         return 1;
862 }
863
864 int fr_packet_list_walk(fr_packet_list_t *pl, void *ctx,
865                           fr_hash_table_walk_t callback)
866 {
867         if (!pl || !callback) return 0;
868
869         return fr_hash_table_walk(pl->ht, callback, ctx);
870 }
871
872 int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
873 {
874         int i, maxfd;
875
876         if (!pl || !set) return 0;
877
878         maxfd = -1;
879
880         for (i = 0; i < MAX_SOCKETS; i++) {
881                 if (pl->sockets[i].sockfd == -1) continue;
882                 FD_SET(pl->sockets[i].sockfd, set);
883                 if (pl->sockets[i].sockfd > maxfd) {
884                         maxfd = pl->sockets[i].sockfd;
885                 }
886         }
887
888         if (maxfd < 0) return -1;
889
890         return maxfd + 1;
891 }
892
893 /*
894  *      Round-robins the receivers, without priority.
895  *
896  *      FIXME: Add sockfd, if -1, do round-robin, else do sockfd
897  *              IF in fdset.
898  */
899 RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set)
900 {
901         int start;
902         RADIUS_PACKET *packet;
903
904         if (!pl || !set) return NULL;
905
906         start = pl->last_recv;
907         do {
908                 start++;
909                 start &= SOCKOFFSET_MASK;
910
911                 if (pl->sockets[start].sockfd == -1) continue;
912
913                 if (!FD_ISSET(pl->sockets[start].sockfd, set)) continue;
914
915 #ifdef WITH_TCP
916                 if (pl->sockets[start].proto == IPPROTO_TCP) {
917                         packet = fr_tcp_recv(pl->sockets[start].sockfd, 0);
918                 } else
919 #endif
920                 packet = rad_recv(pl->sockets[start].sockfd, 0);
921                 if (!packet) continue;
922
923                 /*
924                  *      Call fr_packet_list_find_byreply().  If it
925                  *      doesn't find anything, discard the reply.
926                  */
927
928                 pl->last_recv = start;
929                 return packet;
930         } while (start != pl->last_recv);
931
932         return NULL;
933 }
934
935 int fr_packet_list_num_incoming(fr_packet_list_t *pl)
936 {
937         int num_elements;
938
939         if (!pl) return 0;
940
941         num_elements = fr_hash_table_num_elements(pl->ht);
942         if (num_elements < pl->num_outgoing) return 0; /* panic! */
943
944         return num_elements - pl->num_outgoing;
945 }
946
947 int fr_packet_list_num_outgoing(fr_packet_list_t *pl)
948 {
949         if (!pl) return 0;
950
951         return pl->num_outgoing;
952 }