All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
socket.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or (at
5  * your option) any later version.
6  *
7  * This program 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
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; 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: 0afa8c54eebbea5596422eac72e0c0c5a9bf0e3b $
19  * @file socket.c
20  * @brief Functions for establishing and managing low level sockets.
21  *
22  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  * @author Alan DeKok <aland@freeradius.org>
24  *
25  * @copyright 2015 The FreeRADIUS project
26  */
27 
28 #include <freeradius-devel/libradius.h>
29 #include <freeradius-devel/udpfromto.h>
30 
31 #include <fcntl.h>
32 
33 #ifdef HAVE_SYS_UN_H
34 # include <sys/un.h>
35 # ifndef SUN_LEN
36 # define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
37 # endif
38 
39 /** Open a Unix socket
40  *
41  * @note If the file doesn't exist then errno will be set to ENOENT.
42  *
43  * The following code demonstrates using this function with a connection timeout:
44  @code {.c}
45  sockfd = fr_socket_client_unix(path, true);
46  if (sockfd < 0) {
47  fr_perror();
48  exit(1);
49  }
50  if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) {
51  error:
52  fr_perror();
53  close(sockfd);
54  goto error;
55  }
56  //Optionally, if blocking operation is required
57  if (fr_blocking(sockfd) < 0) goto error;
58  @endcode
59  *
60  * @param path to the file bound to the unix socket.
61  * @param async Whether to set the socket to nonblocking, allowing use of
62  * #fr_socket_wait_for_connect.
63  * @return
64  * - Socket FD on success.
65  * - -1 on failure.
66  */
67 int fr_socket_client_unix(char const *path, bool async)
68 {
69  int sockfd = -1;
70  size_t len;
71  socklen_t socklen;
72  struct sockaddr_un saremote;
73 
74  len = strlen(path);
75  if (len >= sizeof(saremote.sun_path)) {
76  fr_strerror_printf("Path too long, maximum length is %zu", sizeof(saremote.sun_path) - 1);
77  errno = EINVAL;
78  return -1;
79  }
80 
81  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
82  if (sockfd < 0) {
83  fr_strerror_printf("Failed creating UNIX socket: %s", fr_syserror(errno));
84  return -1;
85  }
86 
87  if (async && (fr_nonblock(sockfd) < 0)) {
88  close(sockfd);
89  return -1;
90  }
91 
92  saremote.sun_family = AF_UNIX;
93  memcpy(saremote.sun_path, path, len + 1); /* SUN_LEN does strlen */
94 
95  socklen = SUN_LEN(&saremote);
96 
97  /*
98  * Although we ignore SIGPIPE, some operating systems
99  * like BSD and OSX ignore the ignoring.
100  *
101  * Fortunately, those operating systems usually support
102  * SO_NOSIGPIPE, to prevent them raising the signal in
103  * the first place.
104  */
105 #ifdef SO_NOSIGPIPE
106  {
107  int set = 1;
108 
109  setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
110  }
111 #endif
112 
113  if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) {
114  /*
115  * POSIX says the only time we will get this,
116  * is if the socket has been marked as
117  * nonblocking. This is not an error, the caller
118  * must check the state of errno, and wait for
119  * the connection to complete.
120  */
121  if (errno == EINPROGRESS) return sockfd;
122 
123  close(sockfd);
124  fr_strerror_printf("Failed connecting to %s: %s", path, fr_syserror(errno));
125 
126  return -1;
127  }
128  return sockfd;
129 }
130 #else
131 int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
132 {
133  fprintf(stderr, "Unix domain sockets not supported on this system");
134  return -1;
135 }
136 #endif /* WITH_SYS_UN_H */
137 
138 /** Establish a connected TCP socket
139  *
140  * The following code demonstrates using this function with a connection timeout:
141  @code {.c}
142  sockfd = fr_socket_client_tcp(NULL, ipaddr, port, true);
143  if (sockfd < 0) {
144  fr_perror();
145  exit(1);
146  }
147  if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) {
148  error:
149  fr_perror();
150  close(sockfd);
151  goto error;
152  }
153  //Optionally, if blocking operation is required
154  if (fr_blocking(sockfd) < 0) goto error;
155  @endcode
156  *
157  * @param src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific
158  * address.
159  * @param dst_ipaddr Where to connect to.
160  * @param dst_port Where to connect to.
161  * @param async Whether to set the socket to nonblocking, allowing use of
162  * #fr_socket_wait_for_connect.
163  * @return
164  * - FD on success
165  * - -1 on failure.
166  */
167 int fr_socket_client_tcp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
168 {
169  int sockfd;
170  struct sockaddr_storage salocal;
171  socklen_t salen;
172 
173  if (!dst_ipaddr) return -1;
174 
175  sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0);
176  if (sockfd < 0) {
177  fr_strerror_printf("Error creating TCP socket: %s", fr_syserror(errno));
178  return sockfd;
179  }
180 
181  if (async && (fr_nonblock(sockfd) < 0)) {
182  close(sockfd);
183  return -1;
184  }
185 
186  /*
187  * Allow the caller to bind us to a specific source IP.
188  */
189  if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) {
190  if (!fr_ipaddr_to_sockaddr(src_ipaddr, 0, &salocal, &salen)) {
191  close(sockfd);
192  return -1;
193  }
194 
195  if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
196  fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno));
197  close(sockfd);
198  return -1;
199  }
200  }
201 
202  if (!fr_ipaddr_to_sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) {
203  close(sockfd);
204  return -1;
205  }
206 
207  /*
208  * Although we ignore SIGPIPE, some operating systems
209  * like BSD and OSX ignore the ignoring.
210  *
211  * Fortunately, those operating systems usually support
212  * SO_NOSIGPIPE, to prevent them raising the signal in
213  * the first place.
214  */
215 #ifdef SO_NOSIGPIPE
216  {
217  int set = 1;
218 
219  setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
220  }
221 #endif
222 
223  if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
224  /*
225  * POSIX says the only time we will get this,
226  * is if the socket has been marked as
227  * nonblocking. This is not an error, the caller
228  * must check the state of errno, and wait for
229  * the connection to complete.
230  */
231  if (errno == EINPROGRESS) return sockfd;
232 
233  fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno));
234  close(sockfd);
235  return -1;
236  }
237 
238  return sockfd;
239 }
240 
241 /** Establish a connected UDP socket
242  *
243  * Connected UDP sockets can be used with write(), unlike unconnected sockets
244  * which must be used with sendto and recvfrom.
245  *
246  * The following code demonstrates using this function with a connection timeout:
247  @code {.c}
248  sockfd = fr_socket_client_udp(NULL, ipaddr, port, true);
249  if (sockfd < 0) {
250  fr_perror();
251  exit(1);
252 }
253  if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) {
254  error:
255  fr_perror();
256  close(sockfd);
257  goto error;
258 }
259 //Optionally, if blocking operation is required
260  if (fr_blocking(sockfd) < 0) goto error;
261  @endcode
262  *
263  * @param src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific
264  * address.
265  * @param dst_ipaddr Where to send datagrams.
266  * @param dst_port Where to send datagrams.
267  * @param async Whether to set the socket to nonblocking, allowing use of
268  * #fr_socket_wait_for_connect.
269  * @return
270  * - FD on success.
271  * - -1 on failure.
272  */
273 int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
274 {
275  int sockfd;
276  struct sockaddr_storage salocal;
277  socklen_t salen;
278 
279  if (!dst_ipaddr) return -1;
280 
281  sockfd = socket(dst_ipaddr->af, SOCK_DGRAM, 0);
282  if (sockfd < 0) {
283  fr_strerror_printf("Error creating UDP socket: %s", fr_syserror(errno));
284  return sockfd;
285  }
286 
287  if (async && (fr_nonblock(sockfd) < 0)) {
288  close(sockfd);
289  return -1;
290  }
291 
292  /*
293  * Allow the caller to bind us to a specific source IP.
294  */
295  if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) {
296  if (!fr_ipaddr_to_sockaddr(src_ipaddr, 0, &salocal, &salen)) {
297  close(sockfd);
298  return -1;
299  }
300 
301  if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
302  fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno));
303  close(sockfd);
304  return -1;
305  }
306  }
307 
308  if (!fr_ipaddr_to_sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) {
309  close(sockfd);
310  return -1;
311  }
312 
313  /*
314  * Although we ignore SIGPIPE, some operating systems
315  * like BSD and OSX ignore the ignoring.
316  *
317  * Fortunately, those operating systems usually support
318  * SO_NOSIGPIPE, to prevent them raising the signal in
319  * the first place.
320  */
321 #ifdef SO_NOSIGPIPE
322  {
323  int set = 1;
324 
325  setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
326  }
327 #endif
328 
329  if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) {
330  /*
331  * POSIX says the only time we will get this,
332  * is if the socket has been marked as
333  * nonblocking. This is not an error, the caller
334  * must check the state of errno, and wait for
335  * the connection to complete.
336  */
337  if (errno == EINPROGRESS) return sockfd;
338 
339  fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno));
340  close(sockfd);
341  return -1;
342  }
343 
344  return sockfd;
345 }
346 
347 /** Wait for a socket to be connected, with an optional timeout
348  *
349  * @note On error the caller is expected to ``close(sockfd)``.
350  *
351  * @param sockfd the socket to wait on.
352  * @param timeout How long to wait for socket to open.
353  * @return
354  * - 0 on success.
355  * - -1 on connection error.
356  * - -2 on timeout.
357  * - -3 on select error.
358  */
359 int fr_socket_wait_for_connect(int sockfd, struct timeval const *timeout)
360 {
361  int ret;
362  struct timeval tv = *timeout;
363  fd_set error_set;
364  fd_set write_set; /* POSIX says sockets are open when they become writeable */
365 
366  FD_ZERO(&error_set);
367  FD_ZERO(&write_set);
368 
369  FD_SET(sockfd, &error_set);
370  FD_SET(sockfd, &write_set);
371 
372  /* Don't let signals mess up the select */
373  do {
374  ret = select(sockfd + 1, NULL, &write_set, &error_set, &tv);
375  } while ((ret == -1) && (errno == EINTR));
376 
377  switch (ret) {
378  case 1: /* ok (maybe) */
379  {
380  int error;
381  socklen_t socklen = sizeof(error);
382 
383  if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&error, &socklen)) {
384  fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno));
385  return -1;
386  }
387 
388  if (FD_ISSET(sockfd, &error_set)) {
389  fr_strerror_printf("Failed connecting socket: Unknown error");
390  return -1;
391  }
392  }
393  return 0;
394 
395  case 0: /* timeout */
396  if (!fr_assert(timeout)) return -1;
397  fr_strerror_printf("Connection timed out after %" PRIu64"ms",
398  (timeout->tv_sec * (uint64_t)1000) + (timeout->tv_usec / 1000));
399  return -2;
400 
401  case -1: /* select error */
402  fr_strerror_printf("Failed waiting for connection: %s", fr_syserror(errno));
403  return -3;
404 
405  default:
406  fr_assert(0);
407  return -1;
408  }
409 }
410 
411 /** Open an IPv4 / IPv6, and UDP / TCP socket, server side.
412  *
413  * @param[in] proto IPPROTO_UDP or IPPROTO_TCP
414  * @param[in] ipaddr The IP address to listen on
415  * @param[in,out] port the port to listen on
416  * @param[in] port_name if port==0, the name of the port
417  * @param[in] async whether we block or not on reads and writes
418  * @return
419  * - Socket FD on success.
420  * - -1 on failure.
421  */
422 int fr_socket_server_base(int proto, fr_ipaddr_t *ipaddr, int *port, char const *port_name, bool async)
423 {
424 #ifdef FD_CLOEXEC
425  int rcode;
426 #endif
427  int sockfd;
428  int sock_type;
429 
430  if (!proto) proto = IPPROTO_UDP;
431 
432  if ((proto != IPPROTO_UDP) && (proto != IPPROTO_TCP)) {
433  fr_strerror_printf("Unknown IP protocol %d", proto);
434  return -1;
435  }
436 
437  if (!ipaddr || ((ipaddr->af != AF_INET) && (ipaddr->af != AF_INET6))) {
438  fr_strerror_printf("No address specified");
439  return -1;
440  }
441 
442  if (!*port) {
443  struct servent *svp;
444  char const *proto_name;
445 
446  if (!port_name) {
447  fr_strerror_printf("No port specified");
448  return -1;
449  }
450 
451  if (proto == IPPROTO_UDP) {
452  proto_name = "udp";
453  } else {
454  proto_name = "tcp";
455  }
456 
457  svp = getservbyname(port_name, proto_name);
458  if (!svp) {
459  fr_strerror_printf("Unknown port %s", port_name);
460  return -1;
461  }
462 
463 
464  *port = ntohs(svp->s_port);
465  }
466 
467  if (proto == IPPROTO_UDP) {
468  sock_type = SOCK_DGRAM;
469  } else {
470  sock_type = SOCK_STREAM;
471  }
472 
473  sockfd = socket(ipaddr->af, sock_type, proto);
474  if (sockfd < 0) {
475  fr_strerror_printf("Failed creating UNIX socket: %s", fr_syserror(errno));
476  return -1;
477  }
478 
479 #ifdef FD_CLOEXEC
480  /*
481  * We don't want child processes inheriting these
482  * file descriptors.
483  */
484  rcode = fcntl(sockfd, F_GETFD);
485  if (rcode >= 0) {
486  if (fcntl(sockfd, F_SETFD, rcode | FD_CLOEXEC) < 0) {
487  close(sockfd);
488  fr_strerror_printf("Failed setting close on exec: %s", fr_syserror(errno));
489  return -1;
490  }
491  }
492 #endif
493 
494  if (async && (fr_nonblock(sockfd) < 0)) {
495  close(sockfd);
496  return -1;
497  }
498 
499 #ifdef WITH_UDPFROMTO
500  /*
501  * Initialize udpfromto for UDP sockets.
502  */
503  if ((proto == IPPROTO_UDP) && (udpfromto_init(sockfd) != 0)) {
504  fr_strerror_printf("Failed initializing udpfromto: %s", fr_syserror(errno));
505  close(sockfd);
506  return -1;
507  }
508 #endif
509 
510 #ifdef HAVE_STRUCT_SOCKADDR_IN6
511  /*
512  * Listening on '::' does NOT get you IPv4 to
513  * IPv6 mapping. You've got to listen on an IPv4
514  * address, too. This makes the rest of the server
515  * design a little simpler.
516  */
517  if (ipaddr->af == AF_INET6) {
518 # ifdef IPV6_V6ONLY
519  if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) {
520  int on = 1;
521 
522  if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
523  (char *)&on, sizeof(on)) < 0) {
524  fr_strerror_printf("Failed setting socket to IPv6 only: %s", fr_syserror(errno));
525  close(sockfd);
526  return -1;
527  }
528  }
529 # endif /* IPV6_V6ONLY */
530  }
531 #endif /* HAVE_STRUCT_SOCKADDR_IN6 */
532 
533 #if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG)
534  /*
535  * Set the "don't fragment" flag on UDP sockets. Most
536  * routers don't have good support for fragmented UDP
537  * packets.
538  */
539  if ((proto == IPPROTO_UDP) && (ipaddr->af == AF_INET)) {
540  int flag;
541 
542 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
543 
544  /*
545  * Disable PMTU discovery. On Linux, this
546  * also makes sure that the "don't fragment"
547  * flag is zero.
548  */
549  flag = IP_PMTUDISC_DONT;
550 
551  if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)) < 0) {
552  fr_strerror_printf("Failed disabling PMTU discovery: %s", fr_syserror(errno));
553  close(sockfd);
554  return -1;
555  }
556 #endif
557 
558 #if defined(IP_DONTFRAG)
559  /*
560  * Ensure that the "don't fragment" flag is zero.
561  */
562  flag = 0;
563 
564  if (setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &flag, sizeof(flag)) < 0) {
565  fr_strerror_printf("Failed setting don't fragment flag: %s", fr_syserror(errno));
566  close(sockfd);
567  return -1;
568  }
569 #endif
570  }
571 #endif /* lots of things */
572 
573 #if defined(WITH_TCP)
574  if (proto == IPPROTO_TCP) {
575  int on = 1;
576 
577  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
578  close(sockfd);
579  fr_strerror_printf("Failed to reuse address: %s", fr_syserror(errno));
580  return -1;
581  }
582  }
583 #endif
584 
585 #ifdef SO_TIMESTAMP
586  if (proto == IPPROTO_UDP) {
587  int on = 1;
588 
589  /*
590  * Enable receive timestamps, these should reflect
591  * when the packet was received, not when it was read
592  * from the socket.
593  */
594  if (setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(int)) < 0) {
595  close(sockfd);
596  fr_strerror_printf("Failed enabling socket timestamps: %s", fr_syserror(errno));
597  return -1;
598  }
599  }
600 #endif
601 
602  return sockfd;
603 }
604 
605 /** Bind to an IPv4 / IPv6, and UDP / TCP socket, server side.
606  *
607  * @param[in] sockfd the socket which was opened via fr_socket_server_base()
608  * @param[in,out] ipaddr The IP address to bind to
609  * @param[in] port the port to bind to
610  * @param[in] interface the interface name to bind to
611  * @return
612  * - 0 on success
613  * - -1 on failure.
614  */
615 int fr_socket_server_bind(int sockfd, fr_ipaddr_t *ipaddr, int *port, char const *interface)
616 {
617  int rcode;
618  uint16_t my_port;
619  struct sockaddr_storage salocal;
620  socklen_t salen;
621 
622  /*
623  * Bind to a device BEFORE touching IP addresses.
624  */
625  if (interface) {
626 #ifdef SO_BINDTODEVICE
627  struct ifreq ifreq;
628 
629  memset(&ifreq, 0, sizeof(ifreq));
630  strlcpy(ifreq.ifr_name, interface, sizeof(ifreq.ifr_name));
631 
632  rcode = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifreq, sizeof(ifreq));
633  if (rcode < 0) {
634  fr_strerror_printf("Failed binding to interface %s: %s", interface, fr_syserror(errno));
635  return -1;
636  } /* else it worked. */
637 #else
638 
639 # ifdef HAVE_STRUCT_SOCKADDR_IN6
640 # ifdef HAVE_NET_IF_H
641  /*
642  * Odds are that any system supporting "bind to
643  * device" also supports IPv6, so this next bit
644  * isn't necessary. But it's here for
645  * completeness.
646  *
647  * If we're doing IPv6, and the scope hasn't yet
648  * been defined, set the scope to the scope of
649  * the interface.
650  */
651  if (ipaddr->af == AF_INET6) {
652  if (ipaddr->zone_id == 0) {
653  ipaddr->zone_id = if_nametoindex(interface);
654  if (ipaddr->zone_id == 0) {
655  fr_strerror_printf("Failed finding interface %s: %s", interface, fr_syserror(errno));
656  return -1;
657  }
658  } /* else scope was defined: we're OK. */
659  } else
660 # endif
661 #endif
662  {
663  /*
664  * IPv4: no link local addresses,
665  * and no bind to device.
666  */
667  fr_strerror_printf("Failed binding to interface %s: \"bind to device\" is unsupported", interface);
668  return -1;
669  }
670 #endif
671  } /* else no interface */
672 
673  if (!port) return 0;
674 
675  /*
676  * Set up sockaddr stuff.
677  */
678  my_port = *port;
679  if (!fr_ipaddr_to_sockaddr(ipaddr, my_port, &salocal, &salen)) {
680  return -1;
681  }
682 
683  rcode = bind(sockfd, (struct sockaddr *) &salocal, salen);
684  if (rcode < 0) return rcode;
685 
686  /*
687  * FreeBSD jail issues. We bind to 0.0.0.0, but the
688  * kernel instead binds us to a 1.2.3.4. So once the
689  * socket is bound, ask it what it's IP address is.
690  */
691  salen = sizeof(salocal);
692  memset(&salocal, 0, salen);
693  if (getsockname(sockfd, (struct sockaddr *) &salocal, &salen) < 0) {
694  fr_strerror_printf("Failed getting socket name: %s", fr_syserror(errno));
695  return -1;
696  }
697 
698  if (!fr_ipaddr_from_sockaddr(&salocal, salen, ipaddr, &my_port)) {
699  return -1;
700  }
701 
702  *port = my_port;
703 
704  return 0;
705 }
static int sockfd
Definition: radclient.c:59
int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async)
Definition: socket.c:131
int fr_socket_client_udp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected UDP socket.
Definition: socket.c:273
int fr_nonblock(int fd)
int fr_ipaddr_from_sockaddr(struct sockaddr_storage const *sa, socklen_t salen, fr_ipaddr_t *ipaddr, uint16_t *port)
Definition: inet.c:1095
#define UNUSED
Definition: libradius.h:134
static float timeout
Definition: radclient.c:43
int fr_socket_server_bind(int sockfd, fr_ipaddr_t *ipaddr, int *port, char const *interface)
Bind to an IPv4 / IPv6, and UDP / TCP socket, server side.
Definition: socket.c:615
static char const * proto
Definition: radclient.c:63
int af
Address family.
Definition: inet.h:42
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
union fr_ipaddr_t::@1 ipaddr
#define fr_assert(_x)
Definition: libradius.h:505
int fr_socket_client_tcp(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, bool async)
Establish a connected TCP socket.
Definition: socket.c:167
uint32_t zone_id
A host may have multiple link-local interfaces the scope ID allows the application to specify which o...
Definition: inet.h:48
int fr_socket_wait_for_connect(int sockfd, struct timeval const *timeout)
Wait for a socket to be connected, with an optional timeout.
Definition: socket.c:359
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
int fr_socket_server_base(int proto, fr_ipaddr_t *ipaddr, int *port, char const *port_name, bool async)
Open an IPv4 / IPv6, and UDP / TCP socket, server side.
Definition: socket.c:422
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
IPv4/6 prefix.
Definition: inet.h:41
int fr_ipaddr_to_sockaddr(fr_ipaddr_t const *ipaddr, uint16_t port, struct sockaddr_storage *sa, socklen_t *salen)
Definition: inet.c:1057