The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 23c34a82cf085a4570b3d63f01ab92fa520b588e $
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: 23c34a82cf085a4570b3d63f01ab92fa520b588e $")
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 /*
447 * FIXME: Go to an LRU system. This prevents ID reuse
448 * for as long as possible. The main problem with that
449 * approach is that it requires us to populate the
450 * LRU/FIFO when we add a new socket, or a new destination,
451 * which can be expensive.
452 *
453 * The LRU can be avoided if the caller takes care to free
454 * Id's only when all responses have been received, OR after
455 * a timeout.
456 *
457 * Right now, the random approach is almost OK... it's
458 * brute-force over all of the available ID's, BUT using
459 * random numbers for everything spreads the load a bit.
460 *
461 * The old method had a hash lookup on allocation AND
462 * on free. The new method has brute-force on allocation,
463 * and near-zero cost on free.
464 */
465
466 id = fd = -1;
467 if (request->id >= 0 && request->id < 256)
468 id = request->id;
469 start_i = fr_rand() & SOCKOFFSET_MASK;
470
471 type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
472
473#define ID_i ((i + start_i) & SOCKOFFSET_MASK)
474 for (i = 0; i < MAX_SOCKETS; i++) {
475 if (pl->sockets[ID_i].socket.fd == -1) continue; /* paranoia */
476
477 ps = &(pl->sockets[ID_i]);
478
479 /*
480 * This socket is marked as "don't use for new
481 * packets". But we can still receive packets
482 * that are outstanding.
483 */
484 if (ps->dont_use) continue;
485
486 /*
487 * All IDs are allocated: ignore it.
488 */
489 if (ps->num_outgoing == 256) continue;
490
491 if (ps->socket.type != type) continue;
492
493 /*
494 * Address families don't match, skip it.
495 */
496 if (ps->socket.inet.src_ipaddr.af != request->socket.inet.dst_ipaddr.af) continue;
497
498 /*
499 * MUST match dst port, if we have one.
500 */
501 if ((ps->socket.inet.dst_port != 0) &&
502 (ps->socket.inet.dst_port != request->socket.inet.dst_port)) continue;
503
504 /*
505 * MUST match requested src port, if one has been given.
506 */
507 if ((request->socket.inet.src_port != 0) &&
508 (ps->socket.inet.src_port != request->socket.inet.src_port)) continue;
509
510 /*
511 * We don't care about the source IP, but this
512 * socket is link local, and the requested
513 * destination is not link local. Ignore it.
514 */
515 if (src_any && (ps->socket.inet.src_ipaddr.af == AF_INET) &&
516 (((ps->socket.inet.src_ipaddr.addr.v4.s_addr >> 24) & 0xff) == 127) &&
517 (((request->socket.inet.dst_ipaddr.addr.v4.s_addr >> 24) & 0xff) != 127)) continue;
518
519 /*
520 * We're sourcing from *, and they asked for a
521 * specific source address: ignore it.
522 */
523 if (ps->src_any && !src_any) continue;
524
525 /*
526 * We're sourcing from a specific IP, and they
527 * asked for a source IP that isn't us: ignore
528 * it.
529 */
530 if (!ps->src_any && !src_any &&
531 (fr_ipaddr_cmp(&request->socket.inet.src_ipaddr,
532 &ps->socket.inet.src_ipaddr) != 0)) continue;
533
534 /*
535 * UDP sockets are allowed to match
536 * destination IPs exactly, OR a socket
537 * with destination * is allowed to match
538 * any requested destination.
539 *
540 * TCP sockets must match the destination
541 * exactly. They *always* have dst_any=0,
542 * so the first check always matches.
543 */
544 if (!ps->dst_any &&
545 (fr_ipaddr_cmp(&request->socket.inet.dst_ipaddr,
546 &ps->socket.inet.dst_ipaddr) != 0)) continue;
547
548 /*
549 * Otherwise, this socket is OK to use.
550 */
551
552 /*
553 * An explicit ID was requested
554 */
555
556 if (id != -1) {
557 if ((ps->id[(id >> 3) & 0x1f] & (1 << (id & 0x07))) != 0) continue;
558
559 ps->id[(id >> 3) & 0x1f] |= (1 << (id & 0x07));
560 fd = i;
561 break;
562 }
563
564 /*
565 * Look for a free Id, starting from a random number.
566 */
567 start_j = fr_rand() & 0x1f;
568#define ID_j ((j + start_j) & 0x1f)
569 for (j = 0; j < 32; j++) {
570 if (ps->id[ID_j] == 0xff) continue;
571
572
573 start_k = fr_rand() & 0x07;
574#define ID_k ((k + start_k) & 0x07)
575 for (k = 0; k < 8; k++) {
576 if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
577
578 ps->id[ID_j] |= (1 << ID_k);
579 id = (ID_j * 8) + ID_k;
580 fd = i;
581 break;
582 }
583 if (fd >= 0) break;
584 }
585#undef ID_i
586#undef ID_j
587#undef ID_k
588 break;
589 }
590
591 /*
592 * Ask the caller to allocate a new ID.
593 */
594 if (fd < 0) {
595 fr_strerror_const("Failed finding socket, caller must allocate a new one");
596 return false;
597 }
598
599 /*
600 * Set the ID, source IP, and source port.
601 */
602 request->id = id;
603
604 request->socket.fd = ps->socket.fd;
605 request->socket.inet.src_ipaddr = ps->socket.inet.src_ipaddr;
606 request->socket.inet.src_port = ps->socket.inet.src_port;
607
608 /*
609 * If we managed to insert it, we're done.
610 */
611 if (fr_packet_list_insert(pl, request)) {
612 if (pctx) *pctx = ps->ctx;
613 ps->num_outgoing++;
614 pl->num_outgoing++;
615 return true;
616 }
617
618 /*
619 * Mark the ID as free. This is the one line from
620 * id_free() that we care about here.
621 */
622 ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
623
624 request->id = -1;
625 request->socket.fd = -1;
626 request->socket.inet.src_ipaddr.af = AF_UNSPEC;
627 request->socket.inet.src_port = 0;
628
629 return false;
630}
631
632/*
633 * Should be called AFTER yanking it from the list, so that
634 * any newly inserted entries don't collide with this one.
635 */
637 fr_packet_t *request, bool yank)
638{
640
641 if (!pl || !request) return false;
642
643 if (yank && !fr_packet_list_yank(pl, request)) return false;
644
645 ps = fr_socket_find(pl, request->socket.fd);
646 if (!ps) return false;
647
648 ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
649
650 ps->num_outgoing--;
651 pl->num_outgoing--;
652
653 request->id = -1;
654 request->socket.inet.src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
655 request->socket.inet.src_port = 0;
656
657 return true;
658}
659
661{
662 int i, maxfd;
663
664 if (!pl || !set) return 0;
665
666 maxfd = -1;
667
668 for (i = 0; i < MAX_SOCKETS; i++) {
669 if (pl->sockets[i].socket.fd == -1) continue;
670 FD_SET(pl->sockets[i].socket.fd, set);
671 if (pl->sockets[i].socket.fd > maxfd) {
672 maxfd = pl->sockets[i].socket.fd;
673 }
674 }
675
676 if (maxfd < 0) return -1;
677
678 return maxfd + 1;
679}
680
681/*
682 * Round-robins the receivers, without priority.
683 *
684 * FIXME: Add socket.fd, if -1, do round-robin, else do socket.fd
685 * IF in fdset.
686 */
687int 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)
688{
689 int start;
690 fr_packet_t *packet;
691
692 if (!pl || !set) return 0;
693
694 start = pl->last_recv;
695 do {
697
698 start++;
699 start &= SOCKOFFSET_MASK;
700
701 if (pl->sockets[start].socket.fd == -1) continue;
702
703 if (!FD_ISSET(pl->sockets[start].socket.fd, set)) continue;
704
705 if (pl->sockets[start].socket.type == SOCK_STREAM) {
706 int rcode;
707 ps = &pl->sockets[start];
708
709 rcode = fr_tcp_read_packet(ps->socket.fd, ps->buffer, ps->bufsize,
710 &ps->used, max_attributes, require_message_authenticator);
711 if (rcode <= 0) return rcode;
712
714
715 packet = fr_packet_alloc(ctx, false);
716 if (!packet) return -1;
717
718 packet->data = talloc_memdup(packet, ps->buffer, rcode);
719 if (!packet->data) {
720 talloc_free(packet);
721 return -1;
722 }
723
724 packet->data_len = rcode;
725 packet->socket = ps->socket;
726
727 if (ps->used == (size_t) rcode) {
728 ps->used = 0;
729 } else {
730 fr_assert(ps->used > (size_t) rcode);
731
732 memmove(ps->buffer, ps->buffer + rcode, ps->used - rcode);
733 ps->used -= rcode;
734 }
735
736 } else {
737 packet = fr_packet_recv(ctx, pl->sockets[start].socket.fd, UDP_FLAGS_NONE,
738 max_attributes, require_message_authenticator);
739 }
740 if (!packet) continue;
741
742 /*
743 * Call fr_packet_list_find_byreply(). If it
744 * doesn't find anything, discard the reply.
745 */
746
747 pl->last_recv = start;
748 packet->socket.type = pl->sockets[start].socket.type;
749 *packet_p = packet;
750 return 0;
751 } while (start != pl->last_recv);
752
753 return 0;
754}
755
757{
758 uint32_t num_elements;
759
760 if (!pl) return 0;
761
762 num_elements = fr_rb_num_elements(pl->tree);
763 if (num_elements < pl->num_outgoing) return 0; /* panic! */
764
765 return num_elements - pl->num_outgoing;
766}
767
769{
770 if (!pl) return 0;
771
772 return pl->num_outgoing;
773}
#define RCSID(id)
Definition build.h:487
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition build.h:121
static int sockfd
Definition dhcpclient.c:56
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:1449
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:63
int8_t fr_ipaddr_cmp(fr_ipaddr_t const *a, fr_ipaddr_t const *b)
Compare two ip addresses.
Definition inet.c:1354
int af
Address family.
Definition inet.h:64
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:756
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:768
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:687
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:660
#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:636
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:38
#define RADIUS_MAX_PACKET_SIZE
Definition radius.h:41
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition rand.c:105
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:271
The main red black tree structure.
Definition rb.h:73
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:78
int fd
File descriptor if this is a live socket.
Definition socket.h:81
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:79
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:121
Holds information necessary for binding or connecting to a socket.
Definition socket.h:63
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223