The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
list.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: e88e9a8f8c4da7c81d0c0011d8ee515b5e584637 $
19 *
20 * @file protocols/radius/list.c
21 * @brief Functions to deal with outgoing lists / sets of packets.
22 *
23 * @copyright 2000-2017 The FreeRADIUS server project
24 */
25
26RCSID("$Id: e88e9a8f8c4da7c81d0c0011d8ee515b5e584637 $")
27
28#include "radius.h"
29#include "tcp.h"
30#include "list.h"
31
32#include <fcntl.h>
33#include <freeradius-devel/util/udp.h>
34#include <freeradius-devel/util/syserror.h>
35
36/*
37 * See if two packets are identical.
38 *
39 * Note that we do NOT compare the authentication vectors.
40 * That's because if the authentication vector is different,
41 * it means that the NAS has given up on the earlier request.
42 */
43int8_t fr_packet_cmp(void const *a_v, void const *b_v)
44{
45 fr_packet_t const *a = a_v, *b = b_v;
46 int8_t ret;
47
48 /*
49 * 256-way fanout for RADIUS IDs, then by FD. And then
50 * since there are sometimes multiple clients for one FD,
51 * source port. The comparison on dst_port is largely
52 * redundant with the comparison on FD, but it's not
53 * _completely_ redundant.
54 */
55 CMP_RETURN(a, b, id);
56 CMP_RETURN(a, b, socket.fd);
57 CMP_RETURN(a, b, socket.inet.src_port);
58 CMP_RETURN(a, b, socket.inet.dst_port);
59
60 /*
61 * Usually many client IPs, and few server IPs
62 */
63 ret = fr_ipaddr_cmp(&a->socket.inet.src_ipaddr, &b->socket.inet.src_ipaddr);
64 if (ret != 0) return ret;
65
66 return fr_ipaddr_cmp(&a->socket.inet.dst_ipaddr, &b->socket.inet.dst_ipaddr);
67}
68
69/*
70 * Create a fake "request" from a reply, for later lookup.
71 */
73 fr_packet_t const *reply)
74{
75 fr_socket_addr_swap(&request->socket, &reply->socket);
76 request->id = reply->id;
77}
78
79/*
80 * We need to keep track of the socket & it's IP/port.
81 */
82typedef struct {
84
87 void *ctx;
88
90
92
93 uint8_t id[32];
94
96 size_t bufsize;
97 size_t used;
99
100
101#define FNV_MAGIC_PRIME (0x01000193)
102#define MAX_SOCKETS (256)
103#define SOCKOFFSET_MASK (MAX_SOCKETS - 1)
104#define SOCK2OFFSET(_sockfd) ((_sockfd * FNV_MAGIC_PRIME) & SOCKOFFSET_MASK)
105
106/*
107 * Structure defining a list of packets (incoming or outgoing)
108 * that should be managed.
109 */
120
121
122/*
123 * Ugh. Doing this on every sent/received packet is not nice.
124 */
126{
127 int i, start;
128
129 i = start = SOCK2OFFSET(sockfd);
130
131 do { /* make this hack slightly more efficient */
132 if (pl->sockets[i].socket.fd == sockfd) return &pl->sockets[i];
133
134 i = (i + 1) & SOCKOFFSET_MASK;
135 } while (i != start);
136
137 return NULL;
138}
139
141{
143
144 if (!pl) {
145 fr_strerror_const("Invalid argument");
146 return false;
147 }
148
149 ps = fr_socket_find(pl, sockfd);
150 if (!ps) {
151 fr_strerror_const("No such socket");
152 return false;
153 }
154
155 ps->dont_use = true;
156 return true;
157}
158
160{
162
163 if (!pl) return false;
164
165 ps = fr_socket_find(pl, sockfd);
166 if (!ps) return false;
167
168 ps->dont_use = false;
169 return true;
170}
171
172
174{
176
177 if (!pl) return false;
178
179 ps = fr_socket_find(pl, sockfd);
180 if (!ps) return false;
181
182 if (ps->num_outgoing != 0) return false;
183
184 TALLOC_FREE(ps->buffer);
185
186 ps->socket.fd = -1;
187 pl->num_sockets--;
188
189 return true;
190}
191
192
194 fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
195 void *ctx)
196{
197 int i, start;
198 struct sockaddr_storage src;
199 socklen_t sizeof_src;
201
202 if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) {
203 fr_strerror_const("Invalid argument");
204 return false;
205 }
206
207 if (pl->num_sockets >= MAX_SOCKETS) {
208 fr_strerror_const("Too many open sockets");
209 return false;
210 }
211
212 ps = NULL;
213 i = start = SOCK2OFFSET(sockfd);
214
215 do {
216 if (pl->sockets[i].socket.fd == -1) {
217 ps = &pl->sockets[i];
218 break;
219 }
220
221 i = (i + 1) & SOCKOFFSET_MASK;
222 } while (i != start);
223
224 if (!ps) {
225 fr_strerror_const("All socket entries are full");
226 return false;
227 }
228
229 memset(ps, 0, sizeof(*ps));
230 ps->socket.fd = -1;
231 ps->ctx = ctx;
232 ps->socket.type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
233
234 /*
235 * Get address family, etc. first, so we know if we
236 * need to do udpfromto.
237 *
238 * FIXME: udpfromto also does this, but it's not
239 * a critical problem.
240 */
241 sizeof_src = sizeof(src);
242 memset(&src, 0, sizeof_src);
243 if (getsockname(sockfd, (struct sockaddr *) &src, &sizeof_src) < 0) {
244 fr_strerror_printf("%s", fr_syserror(errno));
245 return false;
246 }
247
248 if (fr_ipaddr_from_sockaddr(&ps->socket.inet.src_ipaddr, &ps->socket.inet.src_port, &src, sizeof_src) < 0) {
249 fr_strerror_const("Failed to get IP");
250 return false;
251 }
252
253 ps->socket.inet.dst_ipaddr = *dst_ipaddr;
254 ps->socket.inet.dst_port = dst_port;
255
256 ps->src_any = fr_ipaddr_is_inaddr_any(&ps->socket.inet.src_ipaddr);
257 if (ps->src_any < 0) return false;
258
259 ps->dst_any = fr_ipaddr_is_inaddr_any(&ps->socket.inet.dst_ipaddr);
260 if (ps->dst_any < 0) return false;
261
262 if (proto == IPPROTO_TCP) {
263 ps->buffer = talloc_array(pl, uint8_t, RADIUS_MAX_PACKET_SIZE);
264 if (!ps->buffer) return false;
265
267 ps->used = 0;
268 }
269
270 /*
271 * As the last step before returning.
272 */
273 ps->socket.fd = sockfd;
274 pl->num_sockets++;
275
276 return true;
277}
278
280{
281 if (!pl) return;
282
283 talloc_free(pl->tree);
284 talloc_free(pl);
285}
286
287
288/*
289 * Caller is responsible for managing the packet entries.
290 */
292{
293 int i;
295
296 pl = talloc_zero(NULL, fr_packet_list_t);
297 if (!pl) return NULL;
298 pl->tree = fr_rb_inline_alloc(pl, fr_packet_t, node, fr_packet_cmp, NULL); /* elements not talloc safe */
299 if (!pl->tree) {
301 return NULL;
302 }
303
304 for (i = 0; i < MAX_SOCKETS; i++) {
305 pl->sockets[i].socket.fd = -1;
306 }
307
308 pl->alloc_id = alloc_id;
309
310 return pl;
311}
312
313
314/*
315 * If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST
316 * be called before inserting the packet into the list!
317 */
319 fr_packet_t *request)
320{
321 if (!pl || !request) return 0;
322
323 return fr_rb_insert(pl->tree, request);
324}
325
327{
328 if (!pl || !request) return 0;
329
330 return fr_rb_find(pl->tree, request);
331}
332
333
334/*
335 * This presumes that the reply has dst_ipaddr && dst_port set up
336 * correctly (i.e. real IP, or "*").
337 */
339{
340 fr_packet_t my_request, *request;
342
343 if (!pl || !reply) return NULL;
344
345 ps = fr_socket_find(pl, reply->socket.fd);
346 if (!ps) return NULL;
347
348 /*
349 * TCP sockets are always bound to the correct src/dst IP/port
350 */
351 if (ps->socket.type == SOCK_STREAM) {
352 fr_socket_addr_swap(&reply->socket, &ps->socket);
353 my_request.socket = ps->socket;
354 } else {
355 my_request.socket = ps->socket;
356
357 if (!ps->src_any) my_request.socket.inet.src_ipaddr = reply->socket.inet.dst_ipaddr;
358 my_request.socket.inet.dst_ipaddr = reply->socket.inet.src_ipaddr;
359 my_request.socket.inet.dst_port = reply->socket.inet.src_port;
360 }
361
362 /*
363 * Initialize request from reply, AND from the source
364 * IP & port of this socket. The client may have bound
365 * the socket to 0, in which case it's some random port,
366 * that is NOT in the original request->socket.inet.src_port.
367 */
368 my_request.socket.fd = reply->socket.fd;
369 my_request.id = reply->id;
370 request = &my_request;
371
372 return fr_rb_find(pl->tree, request);
373}
374
375
377{
378 if (!pl || !request) return false;
379
380 return fr_rb_delete(pl->tree, request);
381}
382
384{
385 if (!pl) return 0;
386
387 return fr_rb_num_elements(pl->tree);
388}
389
390
391/*
392 * 1 == ID was allocated & assigned
393 * 0 == couldn't allocate ID.
394 *
395 * Note that this ALSO assigns a socket to use, and updates
396 * packet->request->socket.inet.src_ipaddr && packet->request->socket.inet.src_port
397 *
398 * In multi-threaded systems, the calls to id_alloc && id_free
399 * should be protected by a mutex. This does NOT have to be
400 * the same mutex as the one protecting the insert/find/yank
401 * calls!
402 *
403 * We assume that the packet has dst_ipaddr && dst_port
404 * already initialized. We will use those to find an
405 * outgoing socket. The request MAY also have src_ipaddr set.
406 *
407 * We also assume that the sender doesn't care which protocol
408 * should be used.
409 */
411 fr_packet_t *request, void **pctx)
412{
413 int i, j, k, fd, id, start_i, start_j, start_k;
414 int src_any = 0;
415 int type;
416 fr_packet_socket_t *ps = NULL;
417
418 if ((request->socket.inet.dst_ipaddr.af == AF_UNSPEC) ||
419 (request->socket.inet.dst_port == 0)) {
420 fr_strerror_const("No destination address/port specified");
421 return false;
422 }
423
424 /*
425 * Special case: unspec == "don't care"
426 */
427 if (request->socket.inet.src_ipaddr.af == AF_UNSPEC) {
428 memset(&request->socket.inet.src_ipaddr, 0, sizeof(request->socket.inet.src_ipaddr));
429 request->socket.inet.src_ipaddr.af = request->socket.inet.dst_ipaddr.af;
430 }
431
432 src_any = fr_ipaddr_is_inaddr_any(&request->socket.inet.src_ipaddr);
433 if (src_any < 0) {
434 fr_strerror_const("Can't check src_ipaddr");
435 return false;
436 }
437
438 /*
439 * MUST specify a destination address.
440 */
441 if (fr_ipaddr_is_inaddr_any(&request->socket.inet.dst_ipaddr) != 0) {
442 fr_strerror_const("Must specify a dst_ipaddr");
443 return false;
444 }
445
446 if (!pl->num_sockets) {
447 fr_strerror_const("No sockets have been added to the packet list");
448 return false;
449 }
450
451 /*
452 * FIXME: Go to an LRU system. This prevents ID reuse
453 * for as long as possible. The main problem with that
454 * approach is that it requires us to populate the
455 * LRU/FIFO when we add a new socket, or a new destination,
456 * which can be expensive.
457 *
458 * The LRU can be avoided if the caller takes care to free
459 * Id's only when all responses have been received, OR after
460 * a timeout.
461 *
462 * Right now, the random approach is almost OK... it's
463 * brute-force over all of the available ID's, BUT using
464 * random numbers for everything spreads the load a bit.
465 *
466 * The old method had a hash lookup on allocation AND
467 * on free. The new method has brute-force on allocation,
468 * and near-zero cost on free.
469 */
470
471 id = fd = -1;
472 if (request->id >= 0 && request->id < 256)
473 id = request->id;
474 start_i = fr_rand() & SOCKOFFSET_MASK;
475
476 type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
477
478#define ID_i ((i + start_i) & SOCKOFFSET_MASK)
479 for (i = 0; i < MAX_SOCKETS; i++) {
480 if (pl->sockets[ID_i].socket.fd == -1) continue; /* paranoia */
481
482 ps = &(pl->sockets[ID_i]);
483
484 /*
485 * This socket is marked as "don't use for new
486 * packets". But we can still receive packets
487 * that are outstanding.
488 */
489 if (ps->dont_use) continue;
490
491 /*
492 * All IDs are allocated: ignore it.
493 */
494 if (ps->num_outgoing == 256) continue;
495
496 if (ps->socket.type != type) continue;
497
498 /*
499 * Address families don't match, skip it.
500 */
501 if (ps->socket.inet.src_ipaddr.af != request->socket.inet.dst_ipaddr.af) continue;
502
503 /*
504 * MUST match dst port, if we have one.
505 */
506 if ((ps->socket.inet.dst_port != 0) &&
507 (ps->socket.inet.dst_port != request->socket.inet.dst_port)) continue;
508
509 /*
510 * MUST match requested src port, if one has been given.
511 */
512 if ((request->socket.inet.src_port != 0) &&
513 (ps->socket.inet.src_port != request->socket.inet.src_port)) continue;
514
515 /*
516 * We don't care about the source IP, but this
517 * socket is link local, and the requested
518 * destination is not link local. Ignore it.
519 */
520 if (src_any && (ps->socket.inet.src_ipaddr.af == AF_INET) &&
521 (((ps->socket.inet.src_ipaddr.addr.v4.s_addr >> 24) & 0xff) == 127) &&
522 (((request->socket.inet.dst_ipaddr.addr.v4.s_addr >> 24) & 0xff) != 127)) continue;
523
524 /*
525 * We're sourcing from *, and they asked for a
526 * specific source address: ignore it.
527 */
528 if (ps->src_any && !src_any) continue;
529
530 /*
531 * We're sourcing from a specific IP, and they
532 * asked for a source IP that isn't us: ignore
533 * it.
534 */
535 if (!ps->src_any && !src_any &&
536 (fr_ipaddr_cmp(&request->socket.inet.src_ipaddr,
537 &ps->socket.inet.src_ipaddr) != 0)) continue;
538
539 /*
540 * UDP sockets are allowed to match
541 * destination IPs exactly, OR a socket
542 * with destination * is allowed to match
543 * any requested destination.
544 *
545 * TCP sockets must match the destination
546 * exactly. They *always* have dst_any=0,
547 * so the first check always matches.
548 */
549 if (!ps->dst_any &&
550 (fr_ipaddr_cmp(&request->socket.inet.dst_ipaddr,
551 &ps->socket.inet.dst_ipaddr) != 0)) continue;
552
553 /*
554 * Otherwise, this socket is OK to use.
555 */
556
557 /*
558 * An explicit ID was requested
559 */
560
561 if (id != -1) {
562 if ((ps->id[(id >> 3) & 0x1f] & (1 << (id & 0x07))) != 0) continue;
563
564 ps->id[(id >> 3) & 0x1f] |= (1 << (id & 0x07));
565 fd = i;
566 break;
567 }
568
569 /*
570 * Look for a free Id, starting from a random number.
571 */
572 start_j = fr_rand() & 0x1f;
573#define ID_j ((j + start_j) & 0x1f)
574 for (j = 0; j < 32; j++) {
575 if (ps->id[ID_j] == 0xff) continue;
576
577
578 start_k = fr_rand() & 0x07;
579#define ID_k ((k + start_k) & 0x07)
580 for (k = 0; k < 8; k++) {
581 if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
582
583 ps->id[ID_j] |= (1 << ID_k);
584 id = (ID_j * 8) + ID_k;
585 fd = i;
586 break;
587 }
588 if (fd >= 0) break;
589 }
590#undef ID_i
591#undef ID_j
592#undef ID_k
593 break;
594 }
595
596 /*
597 * Ask the caller to allocate a new ID.
598 */
599 if (fd < 0) {
600 fr_strerror_const("Failed finding socket, caller must allocate a new one");
601 return false;
602 }
603
604 /*
605 * Set the ID, source IP, and source port.
606 */
607 request->id = id;
608
609 request->socket.fd = ps->socket.fd;
610 request->socket.inet.src_ipaddr = ps->socket.inet.src_ipaddr;
611 request->socket.inet.src_port = ps->socket.inet.src_port;
612
613 /*
614 * If we managed to insert it, we're done.
615 */
616 if (fr_packet_list_insert(pl, request)) {
617 if (pctx) *pctx = ps->ctx;
618 ps->num_outgoing++;
619 pl->num_outgoing++;
620 return true;
621 }
622
623 /*
624 * Mark the ID as free. This is the one line from
625 * id_free() that we care about here.
626 */
627 ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
628
629 request->id = -1;
630 request->socket.fd = -1;
631 request->socket.inet.src_ipaddr.af = AF_UNSPEC;
632 request->socket.inet.src_port = 0;
633
634 return false;
635}
636
637/*
638 * Should be called AFTER yanking it from the list, so that
639 * any newly inserted entries don't collide with this one.
640 */
642 fr_packet_t *request, bool yank)
643{
645
646 if (!pl || !request) return false;
647
648 if (yank && !fr_packet_list_yank(pl, request)) return false;
649
650 ps = fr_socket_find(pl, request->socket.fd);
651 if (!ps) return false;
652
653 ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
654
655 ps->num_outgoing--;
656 pl->num_outgoing--;
657
658 request->id = -1;
659 request->socket.inet.src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
660 request->socket.inet.src_port = 0;
661
662 return true;
663}
664
666{
667 int i, maxfd;
668
669 if (!pl || !set) return 0;
670
671 maxfd = -1;
672
673 for (i = 0; i < MAX_SOCKETS; i++) {
674 if (pl->sockets[i].socket.fd == -1) continue;
675 FD_SET(pl->sockets[i].socket.fd, set);
676 if (pl->sockets[i].socket.fd > maxfd) {
677 maxfd = pl->sockets[i].socket.fd;
678 }
679 }
680
681 if (maxfd < 0) return -1;
682
683 return maxfd + 1;
684}
685
686/*
687 * Round-robins the receivers, without priority.
688 *
689 * FIXME: Add socket.fd, if -1, do round-robin, else do socket.fd
690 * IF in fdset.
691 */
692int fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set, TALLOC_CTX *ctx, fr_packet_t **packet_p, uint32_t max_attributes, bool require_message_authenticator)
693{
694 int start;
695 fr_packet_t *packet;
696
697 if (!pl || !set) return 0;
698
699 start = pl->last_recv;
700 do {
702
703 start++;
704 start &= SOCKOFFSET_MASK;
705
706 if (pl->sockets[start].socket.fd == -1) continue;
707
708 if (!FD_ISSET(pl->sockets[start].socket.fd, set)) continue;
709
710 if (pl->sockets[start].socket.type == SOCK_STREAM) {
711 int rcode;
712 ps = &pl->sockets[start];
713
714 ps->used = 0;
715 rcode = fr_tcp_read_packet(ps->socket.fd, ps->buffer, ps->bufsize,
716 &ps->used, max_attributes, require_message_authenticator);
717 if (rcode <= 0) return rcode;
718
719 if (ps->used < RADIUS_HEADER_LENGTH) {
720 fr_strerror_printf("TCP packet too short: %zu", ps->used);
721 return -1;
722 }
723
724 packet = fr_packet_alloc(ctx, false);
725 if (!packet) return -1;
726
727 packet->data = talloc_memdup(packet, ps->buffer, rcode);
728 if (!packet->data) {
729 talloc_free(packet);
730 return -1;
731 }
732
733 packet->data_len = rcode;
734 packet->socket = ps->socket;
735
736 if (ps->used == (size_t) rcode) {
737 ps->used = 0;
738 } else {
739 fr_assert(ps->used > (size_t) rcode);
740
741 memmove(ps->buffer, ps->buffer + rcode, ps->used - rcode);
742 ps->used -= rcode;
743 }
744
745 } else {
746 packet = fr_packet_recv(ctx, pl->sockets[start].socket.fd, UDP_FLAGS_NONE,
747 max_attributes, require_message_authenticator);
748 }
749 if (!packet) continue;
750
751 /*
752 * Call fr_packet_list_find_byreply(). If it
753 * doesn't find anything, discard the reply.
754 */
755
756 pl->last_recv = start;
757 packet->socket.type = pl->sockets[start].socket.type;
758 *packet_p = packet;
759 return 0;
760 } while (start != pl->last_recv);
761
762 return 0;
763}
764
766{
767 uint32_t num_elements;
768
769 if (!pl) return 0;
770
771 num_elements = fr_rb_num_elements(pl->tree);
772 if (num_elements < pl->num_outgoing) return 0; /* panic! */
773
774 return num_elements - pl->num_outgoing;
775}
776
778{
779 if (!pl) return 0;
780
781 return pl->num_outgoing;
782}
#define RCSID(id)
Definition build.h:512
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:122
static int sockfd
Definition dhcpclient.c:55
talloc_free(hp)
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1448
int fr_ipaddr_is_inaddr_any(fr_ipaddr_t const *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition inet.c:62
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1353
int af
Address family.
Definition inet.h:63
IPv4/6 prefix.
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
fr_packet_t * fr_packet_list_find_byreply(fr_packet_list_t *pl, fr_packet_t *reply)
Definition list.c:338
#define ID_k
uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl)
Definition list.c:765
void fr_packet_list_free(fr_packet_list_t *pl)
Definition list.c:279
uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
Definition list.c:777
int8_t fr_packet_cmp(void const *a_v, void const *b_v)
Definition list.c:43
static fr_packet_socket_t * fr_socket_find(fr_packet_list_t *pl, int sockfd)
Definition list.c:125
bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd)
Definition list.c:173
size_t used
Definition list.c:97
uint8_t * buffer
Definition list.c:95
#define ID_i
#define ID_j
fr_packet_socket_t sockets[MAX_SOCKETS]
Definition list.c:118
bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd)
Definition list.c:140
int num_sockets
Definition list.c:116
int fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set, TALLOC_CTX *ctx, fr_packet_t **packet_p, uint32_t max_attributes, bool require_message_authenticator)
Definition list.c:692
uint8_t id[32]
Definition list.c:93
fr_packet_t * fr_packet_list_find(fr_packet_list_t *pl, fr_packet_t *request)
Definition list.c:326
#define SOCK2OFFSET(_sockfd)
Definition list.c:104
fr_packet_list_t * fr_packet_list_create(int alloc_id)
Definition list.c:291
bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd)
Definition list.c:159
uint32_t num_outgoing
Definition list.c:114
bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto, fr_packet_t *request, void **pctx)
Definition list.c:410
bool fr_packet_list_yank(fr_packet_list_t *pl, fr_packet_t *request)
Definition list.c:376
#define MAX_SOCKETS
Definition list.c:102
fr_socket_t socket
Definition list.c:83
bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, void *ctx)
Definition list.c:193
void fr_request_from_reply(fr_packet_t *request, fr_packet_t const *reply)
Definition list.c:72
bool fr_packet_list_insert(fr_packet_list_t *pl, fr_packet_t *request)
Definition list.c:318
uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
Definition list.c:383
uint32_t num_outgoing
Definition list.c:89
fr_rb_tree_t * tree
Definition list.c:111
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
Definition list.c:665
#define SOCKOFFSET_MASK
Definition list.c:103
bool fr_packet_list_id_free(fr_packet_list_t *pl, fr_packet_t *request, bool yank)
Definition list.c:641
size_t bufsize
Definition list.c:96
Constants for the RADIUS protocol.
unsigned short uint16_t
unsigned int uint32_t
unsigned char uint8_t
#define RADIUS_HEADER_LENGTH
Definition net.h:80
fr_packet_t * fr_packet_recv(TALLOC_CTX *ctx, int fd, int flags, uint32_t max_attributes, bool require_message_authenticator)
Receive UDP client requests, and fill in the basics of a fr_packet_t structure.
Definition packet.c:191
#define fr_assert(_expr)
Definition rad_assert.h:37
#define RADIUS_MAX_PACKET_SIZE
Definition radius.h:40
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:104
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition rb.c:781
void * fr_rb_find(fr_rb_tree_t const *tree, void const *data)
Find an element in the tree, returning the data, not the node.
Definition rb.c:577
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition rb.c:626
bool fr_rb_delete(fr_rb_tree_t *tree, void const *data)
Remove node and free data (if a free function was specified)
Definition rb.c:741
#define fr_rb_inline_alloc(_ctx, _type, _field, _data_cmp, _data_free)
Allocs a red black tree.
Definition rb.h:269
The main red black tree structure.
Definition rb.h:71
fr_aka_sim_id_type_t type
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
ssize_t fr_tcp_read_packet(int sockfd, uint8_t *buffer, size_t size, size_t *total, uint32_t max_attributes, bool require_message_authenticator)
Definition tcp.c:35
RADIUS over TCP.
#define UDP_FLAGS_NONE
Definition udp.h:37
fr_socket_t socket
This packet was received on.
Definition packet.h:57
int id
Packet ID (used to link requests/responses).
Definition packet.h:60
uint8_t * data
Packet data (body).
Definition packet.h:63
size_t data_len
Length of packet data.
Definition packet.h:64
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:75
int fd
File descriptor if this is a live socket.
Definition socket.h:78
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:76
static void fr_socket_addr_swap(fr_socket_t *dst, fr_socket_t const *src)
Swap src/dst information of a fr_socket_t.
Definition socket.h:118
Holds information necessary for binding or connecting to a socket.
Definition socket.h:60
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223