The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 88f29cf4609e07ea86a224e0006ea542a536e2cd $
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 
26 RCSID("$Id: 88f29cf4609e07ea86a224e0006ea542a536e2cd $")
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  */
43 int8_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  */
82 typedef struct {
84 
85  int src_any;
86  int dst_any;
87  void *ctx;
88 
90 
91  bool dont_use;
92 
93  uint8_t id[32];
95 
96 
97 #define FNV_MAGIC_PRIME (0x01000193)
98 #define MAX_SOCKETS (256)
99 #define SOCKOFFSET_MASK (MAX_SOCKETS - 1)
100 #define SOCK2OFFSET(_sockfd) ((_sockfd * FNV_MAGIC_PRIME) & SOCKOFFSET_MASK)
101 
102 /*
103  * Structure defining a list of packets (incoming or outgoing)
104  * that should be managed.
105  */
108 
109  int alloc_id;
113 
115 };
116 
117 
118 /*
119  * Ugh. Doing this on every sent/received packet is not nice.
120  */
122 {
123  int i, start;
124 
125  i = start = SOCK2OFFSET(sockfd);
126 
127  do { /* make this hack slightly more efficient */
128  if (pl->sockets[i].socket.fd == sockfd) return &pl->sockets[i];
129 
130  i = (i + 1) & SOCKOFFSET_MASK;
131  } while (i != start);
132 
133  return NULL;
134 }
135 
137 {
138  fr_packet_socket_t *ps;
139 
140  if (!pl) {
141  fr_strerror_const("Invalid argument");
142  return false;
143  }
144 
145  ps = fr_socket_find(pl, sockfd);
146  if (!ps) {
147  fr_strerror_const("No such socket");
148  return false;
149  }
150 
151  ps->dont_use = true;
152  return true;
153 }
154 
156 {
157  fr_packet_socket_t *ps;
158 
159  if (!pl) return false;
160 
161  ps = fr_socket_find(pl, sockfd);
162  if (!ps) return false;
163 
164  ps->dont_use = false;
165  return true;
166 }
167 
168 
170 {
171  fr_packet_socket_t *ps;
172 
173  if (!pl) return false;
174 
175  ps = fr_socket_find(pl, sockfd);
176  if (!ps) return false;
177 
178  if (ps->num_outgoing != 0) return false;
179 
180  ps->socket.fd = -1;
181  pl->num_sockets--;
182 
183  return true;
184 }
185 
186 
188  fr_ipaddr_t *dst_ipaddr, uint16_t dst_port,
189  void *ctx)
190 {
191  int i, start;
192  struct sockaddr_storage src;
193  socklen_t sizeof_src;
194  fr_packet_socket_t *ps;
195 
196  if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) {
197  fr_strerror_const("Invalid argument");
198  return false;
199  }
200 
201  if (pl->num_sockets >= MAX_SOCKETS) {
202  fr_strerror_const("Too many open sockets");
203  return false;
204  }
205 
206  ps = NULL;
207  i = start = SOCK2OFFSET(sockfd);
208 
209  do {
210  if (pl->sockets[i].socket.fd == -1) {
211  ps = &pl->sockets[i];
212  break;
213  }
214 
215  i = (i + 1) & SOCKOFFSET_MASK;
216  } while (i != start);
217 
218  if (!ps) {
219  fr_strerror_const("All socket entries are full");
220  return false;
221  }
222 
223  memset(ps, 0, sizeof(*ps));
224  ps->ctx = ctx;
225  ps->socket.type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
226 
227  /*
228  * Get address family, etc. first, so we know if we
229  * need to do udpfromto.
230  *
231  * FIXME: udpfromto also does this, but it's not
232  * a critical problem.
233  */
234  sizeof_src = sizeof(src);
235  memset(&src, 0, sizeof_src);
236  if (getsockname(sockfd, (struct sockaddr *) &src, &sizeof_src) < 0) {
237  fr_strerror_printf("%s", fr_syserror(errno));
238  return false;
239  }
240 
241  if (fr_ipaddr_from_sockaddr(&ps->socket.inet.src_ipaddr, &ps->socket.inet.src_port, &src, sizeof_src) < 0) {
242  fr_strerror_const("Failed to get IP");
243  return false;
244  }
245 
246  ps->socket.inet.dst_ipaddr = *dst_ipaddr;
247  ps->socket.inet.dst_port = dst_port;
248 
249  ps->src_any = fr_ipaddr_is_inaddr_any(&ps->socket.inet.src_ipaddr);
250  if (ps->src_any < 0) return false;
251 
252  ps->dst_any = fr_ipaddr_is_inaddr_any(&ps->socket.inet.dst_ipaddr);
253  if (ps->dst_any < 0) return false;
254 
255  /*
256  * As the last step before returning.
257  */
258  ps->socket.fd = sockfd;
259  pl->num_sockets++;
260 
261  return true;
262 }
263 
265 {
266  if (!pl) return;
267 
268  talloc_free(pl->tree);
269  talloc_free(pl);
270 }
271 
272 
273 /*
274  * Caller is responsible for managing the packet entries.
275  */
277 {
278  int i;
279  fr_packet_list_t *pl;
280 
281  pl = talloc_zero(NULL, fr_packet_list_t);
282  if (!pl) return NULL;
283  pl->tree = fr_rb_inline_alloc(pl, fr_packet_t, node, fr_packet_cmp, NULL); /* elements not talloc safe */
284  if (!pl->tree) {
286  return NULL;
287  }
288 
289  for (i = 0; i < MAX_SOCKETS; i++) {
290  pl->sockets[i].socket.fd = -1;
291  }
292 
293  pl->alloc_id = alloc_id;
294 
295  return pl;
296 }
297 
298 
299 /*
300  * If pl->alloc_id is set, then fr_packet_list_id_alloc() MUST
301  * be called before inserting the packet into the list!
302  */
304  fr_packet_t *request)
305 {
306  if (!pl || !request) return 0;
307 
308  return fr_rb_insert(pl->tree, request);
309 }
310 
312 {
313  if (!pl || !request) return 0;
314 
315  return fr_rb_find(pl->tree, request);
316 }
317 
318 
319 /*
320  * This presumes that the reply has dst_ipaddr && dst_port set up
321  * correctly (i.e. real IP, or "*").
322  */
324 {
325  fr_packet_t my_request, *request;
326  fr_packet_socket_t *ps;
327 
328  if (!pl || !reply) return NULL;
329 
330  ps = fr_socket_find(pl, reply->socket.fd);
331  if (!ps) return NULL;
332 
333  /*
334  * TCP sockets are always bound to the correct src/dst IP/port
335  */
336  if (ps->socket.type == SOCK_STREAM) {
337  fr_socket_addr_swap(&reply->socket, &ps->socket);
338  my_request.socket = ps->socket;
339  } else {
340  my_request.socket = ps->socket;
341 
342  if (!ps->src_any) my_request.socket.inet.src_ipaddr = reply->socket.inet.dst_ipaddr;
343  my_request.socket.inet.dst_ipaddr = reply->socket.inet.src_ipaddr;
344  my_request.socket.inet.dst_port = reply->socket.inet.src_port;
345  }
346 
347  /*
348  * Initialize request from reply, AND from the source
349  * IP & port of this socket. The client may have bound
350  * the socket to 0, in which case it's some random port,
351  * that is NOT in the original request->socket.inet.src_port.
352  */
353  my_request.socket.fd = reply->socket.fd;
354  my_request.id = reply->id;
355  request = &my_request;
356 
357  return fr_rb_find(pl->tree, request);
358 }
359 
360 
362 {
363  if (!pl || !request) return false;
364 
365  return fr_rb_delete(pl->tree, request);
366 }
367 
369 {
370  if (!pl) return 0;
371 
372  return fr_rb_num_elements(pl->tree);
373 }
374 
375 
376 /*
377  * 1 == ID was allocated & assigned
378  * 0 == couldn't allocate ID.
379  *
380  * Note that this ALSO assigns a socket to use, and updates
381  * packet->request->socket.inet.src_ipaddr && packet->request->socket.inet.src_port
382  *
383  * In multi-threaded systems, the calls to id_alloc && id_free
384  * should be protected by a mutex. This does NOT have to be
385  * the same mutex as the one protecting the insert/find/yank
386  * calls!
387  *
388  * We assume that the packet has dst_ipaddr && dst_port
389  * already initialized. We will use those to find an
390  * outgoing socket. The request MAY also have src_ipaddr set.
391  *
392  * We also assume that the sender doesn't care which protocol
393  * should be used.
394  */
396  fr_packet_t *request, void **pctx)
397 {
398  int i, j, k, fd, id, start_i, start_j, start_k;
399  int src_any = 0;
400  int type;
401  fr_packet_socket_t *ps= NULL;
402 
403  if ((request->socket.inet.dst_ipaddr.af == AF_UNSPEC) ||
404  (request->socket.inet.dst_port == 0)) {
405  fr_strerror_const("No destination address/port specified");
406  return false;
407  }
408 
409  /*
410  * Special case: unspec == "don't care"
411  */
412  if (request->socket.inet.src_ipaddr.af == AF_UNSPEC) {
413  memset(&request->socket.inet.src_ipaddr, 0, sizeof(request->socket.inet.src_ipaddr));
414  request->socket.inet.src_ipaddr.af = request->socket.inet.dst_ipaddr.af;
415  }
416 
417  src_any = fr_ipaddr_is_inaddr_any(&request->socket.inet.src_ipaddr);
418  if (src_any < 0) {
419  fr_strerror_const("Can't check src_ipaddr");
420  return false;
421  }
422 
423  /*
424  * MUST specify a destination address.
425  */
426  if (fr_ipaddr_is_inaddr_any(&request->socket.inet.dst_ipaddr) != 0) {
427  fr_strerror_const("Must specify a dst_ipaddr");
428  return false;
429  }
430 
431  /*
432  * FIXME: Go to an LRU system. This prevents ID reuse
433  * for as long as possible. The main problem with that
434  * approach is that it requires us to populate the
435  * LRU/FIFO when we add a new socket, or a new destination,
436  * which can be expensive.
437  *
438  * The LRU can be avoided if the caller takes care to free
439  * Id's only when all responses have been received, OR after
440  * a timeout.
441  *
442  * Right now, the random approach is almost OK... it's
443  * brute-force over all of the available ID's, BUT using
444  * random numbers for everything spreads the load a bit.
445  *
446  * The old method had a hash lookup on allocation AND
447  * on free. The new method has brute-force on allocation,
448  * and near-zero cost on free.
449  */
450 
451  id = fd = -1;
452  if (request->id >= 0 && request->id < 256)
453  id = request->id;
454  start_i = fr_rand() & SOCKOFFSET_MASK;
455 
456  type = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM;
457 
458 #define ID_i ((i + start_i) & SOCKOFFSET_MASK)
459  for (i = 0; i < MAX_SOCKETS; i++) {
460  if (pl->sockets[ID_i].socket.fd == -1) continue; /* paranoia */
461 
462  ps = &(pl->sockets[ID_i]);
463 
464  /*
465  * This socket is marked as "don't use for new
466  * packets". But we can still receive packets
467  * that are outstanding.
468  */
469  if (ps->dont_use) continue;
470 
471  /*
472  * All IDs are allocated: ignore it.
473  */
474  if (ps->num_outgoing == 256) continue;
475 
476  if (ps->socket.type != type) continue;
477 
478  /*
479  * Address families don't match, skip it.
480  */
481  if (ps->socket.inet.src_ipaddr.af != request->socket.inet.dst_ipaddr.af) continue;
482 
483  /*
484  * MUST match dst port, if we have one.
485  */
486  if ((ps->socket.inet.dst_port != 0) &&
487  (ps->socket.inet.dst_port != request->socket.inet.dst_port)) continue;
488 
489  /*
490  * MUST match requested src port, if one has been given.
491  */
492  if ((request->socket.inet.src_port != 0) &&
493  (ps->socket.inet.src_port != request->socket.inet.src_port)) continue;
494 
495  /*
496  * We don't care about the source IP, but this
497  * socket is link local, and the requested
498  * destination is not link local. Ignore it.
499  */
500  if (src_any && (ps->socket.inet.src_ipaddr.af == AF_INET) &&
501  (((ps->socket.inet.src_ipaddr.addr.v4.s_addr >> 24) & 0xff) == 127) &&
502  (((request->socket.inet.dst_ipaddr.addr.v4.s_addr >> 24) & 0xff) != 127)) continue;
503 
504  /*
505  * We're sourcing from *, and they asked for a
506  * specific source address: ignore it.
507  */
508  if (ps->src_any && !src_any) continue;
509 
510  /*
511  * We're sourcing from a specific IP, and they
512  * asked for a source IP that isn't us: ignore
513  * it.
514  */
515  if (!ps->src_any && !src_any &&
516  (fr_ipaddr_cmp(&request->socket.inet.src_ipaddr,
517  &ps->socket.inet.src_ipaddr) != 0)) continue;
518 
519  /*
520  * UDP sockets are allowed to match
521  * destination IPs exactly, OR a socket
522  * with destination * is allowed to match
523  * any requested destination.
524  *
525  * TCP sockets must match the destination
526  * exactly. They *always* have dst_any=0,
527  * so the first check always matches.
528  */
529  if (!ps->dst_any &&
530  (fr_ipaddr_cmp(&request->socket.inet.dst_ipaddr,
531  &ps->socket.inet.dst_ipaddr) != 0)) continue;
532 
533  /*
534  * Otherwise, this socket is OK to use.
535  */
536 
537  /*
538  * An explicit ID was requested
539  */
540 
541  if (id != -1) {
542  if ((ps->id[(id >> 3) & 0x1f] & (1 << (id & 0x07))) != 0) continue;
543 
544  ps->id[(id >> 3) & 0x1f] |= (1 << (id & 0x07));
545  fd = i;
546  break;
547  }
548 
549  /*
550  * Look for a free Id, starting from a random number.
551  */
552  start_j = fr_rand() & 0x1f;
553 #define ID_j ((j + start_j) & 0x1f)
554  for (j = 0; j < 32; j++) {
555  if (ps->id[ID_j] == 0xff) continue;
556 
557 
558  start_k = fr_rand() & 0x07;
559 #define ID_k ((k + start_k) & 0x07)
560  for (k = 0; k < 8; k++) {
561  if ((ps->id[ID_j] & (1 << ID_k)) != 0) continue;
562 
563  ps->id[ID_j] |= (1 << ID_k);
564  id = (ID_j * 8) + ID_k;
565  fd = i;
566  break;
567  }
568  if (fd >= 0) break;
569  }
570 #undef ID_i
571 #undef ID_j
572 #undef ID_k
573  break;
574  }
575 
576  /*
577  * Ask the caller to allocate a new ID.
578  */
579  if (fd < 0) {
580  fr_strerror_const("Failed finding socket, caller must allocate a new one");
581  return false;
582  }
583 
584  /*
585  * Set the ID, source IP, and source port.
586  */
587  request->id = id;
588 
589  request->socket.fd = ps->socket.fd;
590  request->socket.inet.src_ipaddr = ps->socket.inet.src_ipaddr;
591  request->socket.inet.src_port = ps->socket.inet.src_port;
592 
593  /*
594  * If we managed to insert it, we're done.
595  */
596  if (fr_packet_list_insert(pl, request)) {
597  if (pctx) *pctx = ps->ctx;
598  ps->num_outgoing++;
599  pl->num_outgoing++;
600  return true;
601  }
602 
603  /*
604  * Mark the ID as free. This is the one line from
605  * id_free() that we care about here.
606  */
607  ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
608 
609  request->id = -1;
610  request->socket.fd = -1;
611  request->socket.inet.src_ipaddr.af = AF_UNSPEC;
612  request->socket.inet.src_port = 0;
613 
614  return false;
615 }
616 
617 /*
618  * Should be called AFTER yanking it from the list, so that
619  * any newly inserted entries don't collide with this one.
620  */
622  fr_packet_t *request, bool yank)
623 {
624  fr_packet_socket_t *ps;
625 
626  if (!pl || !request) return false;
627 
628  if (yank && !fr_packet_list_yank(pl, request)) return false;
629 
630  ps = fr_socket_find(pl, request->socket.fd);
631  if (!ps) return false;
632 
633  ps->id[(request->id >> 3) & 0x1f] &= ~(1 << (request->id & 0x07));
634 
635  ps->num_outgoing--;
636  pl->num_outgoing--;
637 
638  request->id = -1;
639  request->socket.inet.src_ipaddr.af = AF_UNSPEC; /* id_alloc checks this */
640  request->socket.inet.src_port = 0;
641 
642  return true;
643 }
644 
646 {
647  int i, maxfd;
648 
649  if (!pl || !set) return 0;
650 
651  maxfd = -1;
652 
653  for (i = 0; i < MAX_SOCKETS; i++) {
654  if (pl->sockets[i].socket.fd == -1) continue;
655  FD_SET(pl->sockets[i].socket.fd, set);
656  if (pl->sockets[i].socket.fd > maxfd) {
657  maxfd = pl->sockets[i].socket.fd;
658  }
659  }
660 
661  if (maxfd < 0) return -1;
662 
663  return maxfd + 1;
664 }
665 
666 /*
667  * Round-robins the receivers, without priority.
668  *
669  * FIXME: Add socket.fd, if -1, do round-robin, else do socket.fd
670  * IF in fdset.
671  */
672 fr_packet_t *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set, uint32_t max_attributes, bool require_ma)
673 {
674  int start;
675  fr_packet_t *packet;
676 
677  if (!pl || !set) return NULL;
678 
679  start = pl->last_recv;
680  do {
681  start++;
682  start &= SOCKOFFSET_MASK;
683 
684  if (pl->sockets[start].socket.fd == -1) continue;
685 
686  if (!FD_ISSET(pl->sockets[start].socket.fd, set)) continue;
687 
688  if (pl->sockets[start].socket.type == SOCK_STREAM) {
689  packet = fr_tcp_recv(pl->sockets[start].socket.fd, false);
690  } else
691  packet = fr_packet_recv(NULL, pl->sockets[start].socket.fd, UDP_FLAGS_NONE,
692  max_attributes, require_ma);
693  if (!packet) continue;
694 
695  /*
696  * Call fr_packet_list_find_byreply(). If it
697  * doesn't find anything, discard the reply.
698  */
699 
700  pl->last_recv = start;
701  packet->socket.type = pl->sockets[start].socket.type;
702  return packet;
703  } while (start != pl->last_recv);
704 
705  return NULL;
706 }
707 
709 {
710  uint32_t num_elements;
711 
712  if (!pl) return 0;
713 
714  num_elements = fr_rb_num_elements(pl->tree);
715  if (num_elements < pl->num_outgoing) return 0; /* panic! */
716 
717  return num_elements - pl->num_outgoing;
718 }
719 
721 {
722  if (!pl) return 0;
723 
724  return pl->num_outgoing;
725 }
#define RCSID(id)
Definition: build.h:444
#define CMP_RETURN(_a, _b, _field)
Return if the comparison is not 0 (is unequal)
Definition: build.h:119
static int sockfd
Definition: dhcpclient.c:56
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:1427
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:1332
int af
Address family.
Definition: inet.h:64
IPv4/6 prefix.
Definition: merged_model.c:272
talloc_free(reap)
#define ID_k
uint32_t fr_packet_list_num_incoming(fr_packet_list_t *pl)
Definition: list.c:708
void fr_packet_list_free(fr_packet_list_t *pl)
Definition: list.c:264
uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
Definition: list.c:720
static fr_packet_socket_t * fr_socket_find(fr_packet_list_t *pl, int sockfd)
Definition: list.c:121
int8_t fr_packet_cmp(void const *a_v, void const *b_v)
Definition: list.c:43
fr_packet_t * fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set, uint32_t max_attributes, bool require_ma)
Definition: list.c:672
bool fr_packet_list_socket_del(fr_packet_list_t *pl, int sockfd)
Definition: list.c:169
#define ID_i
#define ID_j
fr_packet_socket_t sockets[MAX_SOCKETS]
Definition: list.c:114
fr_packet_t * fr_packet_list_find(fr_packet_list_t *pl, fr_packet_t *request)
Definition: list.c:311
bool fr_packet_list_socket_freeze(fr_packet_list_t *pl, int sockfd)
Definition: list.c:136
int num_sockets
Definition: list.c:112
int alloc_id
Definition: list.c:109
uint8_t id[32]
Definition: list.c:93
int last_recv
Definition: list.c:111
fr_packet_list_t * fr_packet_list_create(int alloc_id)
Definition: list.c:276
fr_packet_t * fr_packet_list_find_byreply(fr_packet_list_t *pl, fr_packet_t *reply)
Definition: list.c:323
#define SOCK2OFFSET(_sockfd)
Definition: list.c:100
void * ctx
Definition: list.c:87
bool fr_packet_list_socket_thaw(fr_packet_list_t *pl, int sockfd)
Definition: list.c:155
uint32_t num_outgoing
Definition: list.c:110
bool dont_use
Definition: list.c:91
bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto, fr_packet_t *request, void **pctx)
Definition: list.c:395
bool fr_packet_list_yank(fr_packet_list_t *pl, fr_packet_t *request)
Definition: list.c:361
#define MAX_SOCKETS
Definition: list.c:98
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:187
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:303
uint32_t fr_packet_list_num_elements(fr_packet_list_t *pl)
Definition: list.c:368
uint32_t num_outgoing
Definition: list.c:89
fr_rb_tree_t * tree
Definition: list.c:107
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
Definition: list.c:645
#define SOCKOFFSET_MASK
Definition: list.c:99
bool fr_packet_list_id_free(fr_packet_list_t *pl, fr_packet_t *request, bool yank)
Definition: list.c:621
Constants for the RADIUS protocol.
unsigned short uint16_t
Definition: merged_model.c:31
unsigned int uint32_t
Definition: merged_model.c:33
unsigned char uint8_t
Definition: merged_model.c:30
fr_packet_t * fr_packet_recv(TALLOC_CTX *ctx, int fd, int flags, uint32_t max_attributes, bool require_ma)
Receive UDP client requests, and fill in the basics of a fr_packet_t structure.
Definition: packet.c:211
static char const * proto(int id, int porttype)
Definition: radwho.c:85
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: rand.c:106
uint32_t fr_rb_num_elements(fr_rb_tree_t *tree)
Return how many nodes there are in a tree.
Definition: rb.c:775
bool fr_rb_insert(fr_rb_tree_t *tree, void const *data)
Insert data into a tree.
Definition: rb.c:624
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:736
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:576
#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
fr_packet_t * fr_tcp_recv(int sockfd, int flags)
Definition: tcp.c:31
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
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