libsocket
libinetsocket.c
Go to the documentation of this file.
1 #ifndef _GNU_SOURCE
2 #define _GNU_SOURCE
3 #endif
4 
5 #include "conf.h"
6 #define LIBSOCKET_VERSION 2.4
7 #ifdef BD_ANDROID
8 #define LIBSOCKET_LINUX 0
9 #else
10 #define LIBSOCKET_LINUX 1
11 #endif
12 #define LIBSOCKET_FREEBSD 0
13 #define LIBSOCKET_SUNOS 0
14 
15 #include <errno.h>
16 #include <net/if.h>
17 #include <netdb.h> // getaddrinfo()
18 #include <netinet/in.h> // e.g. struct sockaddr_in on OpenBSD
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <unistd.h> // read()/write()
27 
41 /*
42  The committers of the libsocket project, all rights reserved
43  (c) 2012, dermesser <lbo@spheniscida.de>
44 
45  Redistribution and use in source and binary forms, with or without
46  modification, are permitted provided that the following conditions are met:
47 
48  1. Redistributions of source code must retain the above copyright notice,
49  this list of conditions and the following disclaimer.
50  2. Redistributions in binary form must reproduce the above copyright notice,
51  this list of conditions and the following disclaimer in the documentation
52  and/or other materials provided with the distribution.
53 
54  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS “AS IS” AND ANY
55  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
56  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
57  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
58  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 
65 */
66 
67 /*
68  * Structure of the functions defined here:
69  *
70  * <Declarations>
71  * <Checks on passed arguments>
72  * <actual code>
73  *
74  */
75 
76 /* Macro definitions */
77 
78 //# define VERBOSE // Write errors on stderr?
79 
80 #define LIBSOCKET_BACKLOG \
81  128
82 
83 // Symbolic macros
84 #define LIBSOCKET_TCP 1
85 #define LIBSOCKET_UDP 2
86 
87 #define LIBSOCKET_IPv4 3
88 #define LIBSOCKET_IPv6 4
89 #define LIBSOCKET_BOTH \
90  5
91 
93 #define LIBSOCKET_READ 1
94 #define LIBSOCKET_WRITE 2
95 
96 #define LIBSOCKET_NUMERIC \
97  1
98 
100 
103 #define debug_write(str) \
104  { \
105  int verbose_errno_save = errno; \
106  write(2, str, strlen(str)); \
107  errno = verbose_errno_save; \
108  }
109 
110 #ifdef __FreeBSD__
111 #define _TRADITIONAL_RDNS
112 #endif
113 
127 static inline signed int check_error(int return_value) {
128 #ifdef VERBOSE
129  const char *errbuf;
130 #endif
131  if (return_value < 0) {
132 #ifdef VERBOSE
133  errbuf = strerror(errno);
134  debug_write(errbuf);
135 #endif
136  return -1;
137  }
138 
139  return 0;
140 }
141 
155 int create_inet_stream_socket(const char *host, const char *service,
156  char proto_osi3, int flags) {
157  int sfd, return_value;
158  struct addrinfo hint, *result, *result_check;
159 #ifdef VERBOSE
160  const char *errstring;
161 #endif
162 
163  if (host == NULL || service == NULL) return -1;
164 
165  memset(&hint, 0, sizeof hint);
166 
167  // set address family
168  switch (proto_osi3) {
169  case LIBSOCKET_IPv4:
170  hint.ai_family = AF_INET;
171  break;
172  case LIBSOCKET_IPv6:
173  hint.ai_family = AF_INET6;
174  break;
175  case LIBSOCKET_BOTH:
176  hint.ai_family = AF_UNSPEC;
177  break;
178  default:
179  return -1;
180  }
181 
182  // Transport protocol is TCP
183  hint.ai_socktype = SOCK_STREAM;
184 
185  if (0 != (return_value = getaddrinfo(host, service, &hint, &result))) {
186 #ifdef VERBOSE
187  errstring = gai_strerror(return_value);
188  debug_write(errstring);
189 #endif
190  return -1;
191  }
192 
193  // As described in "The Linux Programming Interface", Michael Kerrisk 2010,
194  // chapter 59.11 (p. 1220ff)
195 
196  for (result_check = result; result_check != NULL;
197  result_check = result_check->ai_next) // go through the linked list of
198  // struct addrinfo elements
199  {
200  sfd = socket(result_check->ai_family, result_check->ai_socktype | flags,
201  result_check->ai_protocol);
202 
203  if (sfd < 0) // Error!!!
204  continue;
205 
206  if (-1 != connect(sfd, result_check->ai_addr,
207  result_check->ai_addrlen)) // connected without error
208  break;
209 
210  close(sfd);
211  }
212 
213  // We do now have a working socket STREAM connection to our target
214 
215  if (result_check == NULL) // Have we?
216  {
217 #ifdef VERBOSE
218  debug_write(
219  "create_inet_stream_socket: Could not connect to any address!\n");
220 #endif
221  int errno_saved = errno;
222  close(sfd);
223  errno = errno_saved;
224  freeaddrinfo(result);
225  return -1;
226  }
227  // Yes :)
228 
229  freeaddrinfo(result);
230 
231  return sfd;
232 }
233 
250 int create_inet_dgram_socket(char proto_osi3, int flags) {
251  int sfd;
252 
253  if (proto_osi3 != LIBSOCKET_IPv4 && proto_osi3 != LIBSOCKET_IPv6) {
254 #ifdef VERBOSE
255  debug_write(
256  "create_inet_dgram_socket: osi3 argument invalid for DGRAM "
257  "sockets\n");
258 #endif
259  return -1;
260  }
261 
262  switch (proto_osi3) {
263  case LIBSOCKET_IPv4:
264  sfd = socket(AF_INET, SOCK_DGRAM | flags, 0);
265  break;
266  case LIBSOCKET_IPv6:
267  sfd = socket(AF_INET6, SOCK_DGRAM | flags, 0);
268  break;
269  default:
270  return -1;
271  }
272 
273  if (-1 == check_error(sfd)) return -1;
274 
275  return sfd;
276 }
277 
303 ssize_t sendto_inet_dgram_socket(int sfd, const void *buf, size_t size,
304  const char *host, const char *service,
305  int sendto_flags) {
306  struct sockaddr_storage oldsock;
307  struct addrinfo *result, *result_check, hint;
308  socklen_t oldsocklen = sizeof(struct sockaddr_storage);
309  int return_value;
310 #ifdef VERBOSE
311  const char *errstring;
312 #endif
313 
314  if (sfd < 0) return -1;
315 
316  if (buf == NULL) return -1;
317 
318  if (size == 0) return 0;
319 
320  if (host == NULL || service == NULL) return -1;
321 
322  if (-1 == check_error(getsockname(sfd, (struct sockaddr *)&oldsock,
323  (socklen_t *)&oldsocklen)))
324  return -1;
325 
326  memset(&hint, 0, sizeof(struct addrinfo));
327 
328  /*
329  * This works for Linux > 2.6.32
330  socklen_t dom_len = sizeof(hint.ai_family);
331  getsockopt(sfd,SOL_SOCKET,SO_DOMAIN,&hint.ai_family,&dom_len);
332  */
333  hint.ai_family = oldsock.ss_family;
334  hint.ai_socktype = SOCK_DGRAM;
335 
336  if (0 != (return_value = getaddrinfo(host, service, &hint, &result))) {
337 #ifdef VERBOSE
338  errstring = gai_strerror(return_value);
339  debug_write(errstring);
340 #endif
341  return -1;
342  }
343 
344  for (result_check = result; result_check != NULL;
345  result_check = result_check->ai_next) // go through the linked list of
346  // struct addrinfo elements
347  {
348  if (-1 != (return_value = sendto(
349  sfd, buf, size, sendto_flags, result_check->ai_addr,
350  result_check->ai_addrlen))) // connected without error
351  {
352  break; // Exit loop if send operation was successful
353  } else {
354  check_error(return_value);
355  }
356  }
357 
358  freeaddrinfo(result);
359 
360  return return_value;
361 }
362 
385 ssize_t recvfrom_inet_dgram_socket(int sfd, void *buffer, size_t size,
386  char *src_host, size_t src_host_len,
387  char *src_service, size_t src_service_len,
388  int recvfrom_flags, int numeric) {
389  struct sockaddr_storage client;
390 
391 #ifdef _TRADITIONAL_RDNS
392  struct sockaddr_storage oldsockaddr;
393  socklen_t oldsockaddrlen = sizeof(struct sockaddr_storage);
394  struct hostent *he;
395  void *addrptr;
396  size_t addrlen;
397  uint16_t sport = 0;
398 #endif
399 
400  ssize_t bytes;
401 
402 #ifndef _TRADITIONAL_RDNS
403  int retval;
404 #endif
405 
406 #ifdef VERBOSE
407  const char *errstr;
408 #endif
409  if (sfd < 0) return -1;
410 
411  if (buffer == NULL || size == 0)
412  return -1;
413  else
414  memset(buffer, 0, size);
415 
416  if (src_host) memset(src_host, 0, src_host_len);
417  if (src_service) memset(src_service, 0, src_service_len);
418 
419  socklen_t stor_addrlen = sizeof(struct sockaddr_storage);
420 
421  if (-1 == check_error(bytes = recvfrom(sfd, buffer, size, recvfrom_flags,
422  (struct sockaddr *)&client,
423  &stor_addrlen)))
424  return -1;
425 
426  if (src_host_len > 0 ||
427  src_service_len >
428  0) // If one of the things is wanted. If you give a null pointer
429  // with a positive _len parameter, you won't get the address.
430  {
431  if (numeric == LIBSOCKET_NUMERIC) {
432  numeric = NI_NUMERICHOST | NI_NUMERICSERV;
433  }
434 
435  // getnameinfo() doesn't work on FreeBSD (here)
436 #ifndef _TRADITIONAL_RDNS
437  if (0 !=
438  (retval = getnameinfo(
439  (struct sockaddr *)&client, sizeof(struct sockaddr_storage),
440  src_host, src_host_len, src_service, src_service_len,
441  numeric))) // Write information to the provided memory
442  {
443 #ifdef VERBOSE
444  errstr = gai_strerror(retval);
445  debug_write(errstr);
446 #endif
447  return -1;
448  }
449 #endif
450 
451  // so use traditional methods
452 #ifdef _TRADITIONAL_RDNS
453  if (-1 == check_error(getsockname(sfd, (struct sockaddr *)&oldsockaddr,
454  &oldsockaddrlen)))
455  return -1;
456 
457  if (oldsockaddrlen >
458  sizeof(struct sockaddr_storage)) // If getsockname truncated the
459  // struct
460  return -1;
461 
462  if (oldsockaddr.ss_family == AF_INET) {
463  addrptr = &(((struct sockaddr_in *)&client)->sin_addr);
464  addrlen = sizeof(struct in_addr);
465  sport = ntohs(((struct sockaddr_in *)&client)->sin_port);
466  } else if (oldsockaddr.ss_family == AF_INET6) {
467  addrptr = &(((struct sockaddr_in6 *)&client)->sin6_addr);
468  addrlen = sizeof(struct in6_addr);
469  sport = ntohs(((struct sockaddr_in6 *)&client)->sin6_port);
470  }
471 
472  if (NULL ==
473  (he = gethostbyaddr(addrptr, addrlen, oldsockaddr.ss_family))) {
474  check_error(-1);
475  return -1;
476  }
477 
478  strncpy(src_host, he->h_name, src_host_len);
479  snprintf(src_service, src_service_len, "%u", sport);
480 #endif
481  }
482 
483  return bytes;
484 }
485 
500 int connect_inet_dgram_socket(int sfd, const char *host, const char *service) {
501  struct addrinfo *result, *result_check, hint;
502  struct sockaddr_storage oldsockaddr;
503  struct sockaddr deconnect;
504  socklen_t oldsockaddrlen = sizeof(struct sockaddr_storage);
505  int return_value;
506 #ifdef VERBOSE
507  const char *errstring;
508 #endif
509 
510  if (sfd < 0) return -1;
511 
512  if (host == NULL) {
513  // This does not work on FreeBSD systems. We pretend to disconnect the
514  // socket although we don't do so. This is not very severe for the
515  // application
516 #ifndef __FreeBSD__
517  memset(&deconnect, 0, sizeof(struct sockaddr));
518 
519  deconnect.sa_family = AF_UNSPEC;
520 
521  if (check_error(connect(sfd, &deconnect, sizeof(struct sockaddr))))
522  return -1;
523 #endif
524  return 0;
525  }
526 
527  if (-1 == check_error(getsockname(sfd, (struct sockaddr *)&oldsockaddr,
528  &oldsockaddrlen)))
529  return -1;
530 
531  if (oldsockaddrlen >
532  sizeof(struct sockaddr_storage)) // If getsockname truncated the struct
533  return -1;
534 
535  memset(&hint, 0, sizeof(struct addrinfo));
536 
537  hint.ai_family = ((struct sockaddr_in *)&oldsockaddr)
538  ->sin_family; // AF_INET or AF_INET6 - offset is same
539  // at sockaddr_in and sockaddr_in6
540  hint.ai_socktype = SOCK_DGRAM;
541 
542  if (0 != (return_value = getaddrinfo(host, service, &hint, &result))) {
543 #ifdef VERBOSE
544  errstring = gai_strerror(return_value);
545  debug_write(errstring);
546 #endif
547  return -1;
548  }
549 
550  // As described in "The Linux Programming Interface", Michael Kerrisk 2010,
551  // chapter 59.11 (p. 1220ff)
552 
553  for (result_check = result; result_check != NULL;
554  result_check = result_check->ai_next) // go through the linked list of
555  // struct addrinfo elements
556  {
557  if (-1 != (return_value = connect(
558  sfd, result_check->ai_addr,
559  result_check->ai_addrlen))) // connected without error
560  {
561  break;
562  } else {
563  check_error(return_value);
564  }
565  }
566 
567  // We do now have a working (updated) socket connection to our target
568 
569  if (result_check == NULL) // or not?
570  {
571 #ifdef VERBOSE
572  debug_write(
573  "connect_inet_dgram_socket: Could not connect to any address!\n");
574 #endif
575  freeaddrinfo(result);
576  return -1;
577  }
578 
579  freeaddrinfo(result);
580 
581  return 0;
582 }
583 
595 int destroy_inet_socket(int sfd) {
596  if (sfd < 0) return -1;
597 
598  if (-1 == check_error(close(sfd))) return -1;
599 
600  return 0;
601 }
602 
619 int shutdown_inet_stream_socket(int sfd, int method) {
620  if (sfd < 0) return -1;
621 
622  if ((method != LIBSOCKET_READ) && (method != LIBSOCKET_WRITE) &&
623  (method != (LIBSOCKET_READ | LIBSOCKET_WRITE)))
624  return -1;
625 
626  if (method & LIBSOCKET_READ) // READ is set (0001 && 0001 => 0001 => true)
627  {
628  if (-1 == check_error(shutdown(sfd, SHUT_RD))) return -1;
629  }
630 
631  if (method &
632  LIBSOCKET_WRITE) // WRITE is set (0010 && 0010 => 0010 => true)
633  {
634  if (-1 == check_error(shutdown(sfd, SHUT_WR))) return -1;
635  }
636 
637  return 0;
638 }
639 
640 /*
641  * Server part
642  *
643  */
644 
669 // Bind address Port TCP/UDP IPv4/6
670 int create_inet_server_socket(const char *bind_addr, const char *bind_port,
671  char proto_osi4, char proto_osi3, int flags) {
672  int sfd, domain, type, retval;
673  struct addrinfo *result, *result_check, hints;
674 #ifdef VERBOSE
675  const char *errstr;
676 #endif
677 
678  // if ( flags != SOCK_NONBLOCK && flags != SOCK_CLOEXEC && flags !=
679  // (SOCK_CLOEXEC|SOCK_NONBLOCK) && flags != 0 ) return -1;
680 
681  if (bind_addr == NULL || bind_port == NULL) return -1;
682 
683  switch (proto_osi4) {
684  case LIBSOCKET_TCP:
685  type = SOCK_STREAM;
686  break;
687  case LIBSOCKET_UDP:
688  type = SOCK_DGRAM;
689  break;
690  default:
691  return -1;
692  }
693  switch (proto_osi3) {
694  case LIBSOCKET_IPv4:
695  domain = AF_INET;
696  break;
697  case LIBSOCKET_IPv6:
698  domain = AF_INET6;
699  break;
700  case LIBSOCKET_BOTH:
701  domain = AF_UNSPEC;
702  break;
703  default:
704  return -1;
705  }
706 
707  memset(&hints, 0, sizeof(struct addrinfo));
708 
709  hints.ai_socktype = type;
710  hints.ai_family = domain;
711  hints.ai_flags = AI_PASSIVE;
712 
713  if (0 != (retval = getaddrinfo(bind_addr, bind_port, &hints, &result))) {
714 #ifdef VERBOSE
715  errstr = gai_strerror(retval);
716  debug_write(errstr);
717 #endif
718  return -1;
719  }
720 
721  // As described in "The Linux Programming Interface", Michael Kerrisk 2010,
722  // chapter 59.11 (p. 1220ff)
723  for (result_check = result; result_check != NULL;
724  result_check = result_check->ai_next) // go through the linked list of
725  // struct addrinfo elements
726  {
727  sfd = socket(result_check->ai_family, result_check->ai_socktype | flags,
728  result_check->ai_protocol);
729 
730  if (sfd < 0) // Error at socket()!!!
731  continue;
732 
733  retval = bind(sfd, result_check->ai_addr,
734  (socklen_t)result_check->ai_addrlen);
735 
736  if (retval != 0) // Error at bind()!!!
737  {
738  close(sfd);
739  continue;
740  }
741 
742  if (type == LIBSOCKET_TCP) retval = listen(sfd, LIBSOCKET_BACKLOG);
743 
744  if (retval == 0) // If we came until here, there wasn't an error
745  // anywhere. It is safe to cancel the loop here
746  break;
747  else
748  close(sfd);
749  }
750 
751  if (result_check == NULL) {
752 #ifdef VERBOSE
753  debug_write(
754  "create_inet_server_socket: Could not bind to any address!\n");
755 #endif
756  freeaddrinfo(result);
757  return -1;
758  }
759 
760  // We do now have a working socket on which we may call accept()
761 
762  freeaddrinfo(result);
763 
764  return sfd;
765 }
766 
789 // Socket Src string Src str len Src service
790 // Src service len NUMERIC?
791 int accept_inet_stream_socket(int sfd, char *src_host, size_t src_host_len,
792  char *src_service, size_t src_service_len,
793  int flags, int accept_flags) {
794  struct sockaddr_storage client_info;
795  int client_sfd;
796 
797 #ifndef _TRADITIONAL_RDNS
798  int retval;
799 #endif
800 
801 #ifdef _TRADITIONAL_RDNS
802  struct sockaddr_storage oldsockaddr;
803  socklen_t oldsockaddrlen = sizeof(struct sockaddr_storage);
804  struct hostent *he;
805  void *addrptr;
806  size_t in_addrlen;
807  uint16_t sport = 0;
808 #endif
809 
810 #ifdef VERBOSE
811  const char *errstr;
812 #endif
813  socklen_t addrlen = sizeof(struct sockaddr_storage);
814 
815  // Portable behavior
816 #if LIBSOCKET_LINUX
817  if (-1 ==
818  check_error((client_sfd = accept4(sfd, (struct sockaddr *)&client_info,
819  &addrlen, accept_flags)))) // blocks
820  return -1;
821 #else
822  if (-1 ==
823  check_error((client_sfd = accept(sfd, (struct sockaddr *)&client_info,
824  &addrlen)))) // blocks
825  return -1;
826 #endif
827 
828  if (src_host_len > 0 ||
829  src_service_len >
830  0) // If one of the things is wanted. If you give a null pointer
831  // with a positive _len parameter, you won't get the address.
832  {
833  if (flags == LIBSOCKET_NUMERIC) {
834  flags = NI_NUMERICHOST | NI_NUMERICSERV;
835  } else {
836  flags = 0; // To prevent errors: Unknown flags are ignored
837  }
838 
839 #ifndef _TRADITIONAL_RDNS
840  if (0 != (retval = getnameinfo(
841  (struct sockaddr *)&client_info,
842  sizeof(struct sockaddr_storage), src_host, src_host_len,
843  src_service, src_service_len,
844  flags))) // Write information to the provided memory
845  {
846 #ifdef VERBOSE
847  errstr = gai_strerror(retval);
848  debug_write(errstr);
849 #endif
850  }
851 #endif
852 
853 #ifdef _TRADITIONAL_RDNS
854  if (-1 == check_error(getsockname(sfd, (struct sockaddr *)&oldsockaddr,
855  &oldsockaddrlen)))
856  return -1;
857 
858  if (oldsockaddrlen >
859  sizeof(struct sockaddr_storage)) // If getsockname truncated the
860  // struct
861  return -1;
862 
863  if (oldsockaddr.ss_family == AF_INET) {
864  addrptr = &(((struct sockaddr_in *)&client_info)->sin_addr);
865  in_addrlen = sizeof(struct in_addr);
866  sport = ntohs(((struct sockaddr_in *)&client_info)->sin_port);
867  } else if (oldsockaddr.ss_family == AF_INET6) {
868  addrptr = &(((struct sockaddr_in6 *)&client_info)->sin6_addr);
869  in_addrlen = sizeof(struct in6_addr);
870  sport = ntohs(((struct sockaddr_in6 *)&client_info)->sin6_port);
871  }
872 
873  if (NULL ==
874  (he = gethostbyaddr(addrptr, in_addrlen, oldsockaddr.ss_family))) {
875  check_error(-1);
876  // Don't return with error on name resolution failure
877  }
878 
879  strncpy(src_host, he->h_name, src_host_len);
880  snprintf(src_service, src_service_len, "%u", sport);
881 #endif
882  }
883 
884  return client_sfd;
885 }
886 
902 int get_address_family(const char *hostname) {
903  int return_value;
904  struct addrinfo hint, *result;
905 #ifdef VERBOSE
906  const char *errstring;
907 #endif
908  int af;
909 
910  if (hostname == NULL) return -1;
911 
912  memset(&hint, 0, sizeof hint);
913 
914  hint.ai_family = AF_UNSPEC;
915 
916  if (0 != (return_value = getaddrinfo(hostname, "0", &hint, &result))) {
917 #ifdef VERBOSE
918  errstring = gai_strerror(return_value);
919  debug_write(errstring);
920 #endif
921  return -1;
922  }
923 
924  if (result == NULL) return -1;
925 
926  if (result->ai_family == AF_INET) {
927  af = LIBSOCKET_IPv4;
928  } else if (result->ai_family == AF_INET6) {
929  af = LIBSOCKET_IPv6;
930  } else {
931  af = -1;
932  }
933 
934  return af;
935 }
936 
963 #ifdef LIBSOCKET_LINUX
964 int create_multicast_socket(const char *group, const char *port,
965  const char *if_name) {
966  int sfd, return_value;
967  struct sockaddr maddr, localif;
968  struct addrinfo hints, *result;
969  struct ip_mreqn mreq4;
970  struct ipv6_mreq mreq6;
971  struct in_addr any;
972  struct ifreq interface;
973 
974  memset(&maddr, 0, sizeof(maddr));
975  memset(&localif, 0, sizeof(localif));
976  memset(&mreq4, 0, sizeof(mreq4));
977  memset(&mreq6, 0, sizeof(mreq6));
978  memset(&hints, 0, sizeof(hints));
979  memset(&interface, 0, sizeof(interface));
980 
981  if (-1 == check_error(sfd = create_inet_server_socket(
982  group, port, LIBSOCKET_UDP, LIBSOCKET_BOTH, 0))) {
983  return -1;
984  }
985 
986  hints.ai_socktype = SOCK_DGRAM;
987  hints.ai_family = AF_UNSPEC;
988 
989  if (0 != (return_value = getaddrinfo(group, port, &hints, &result))) {
990  int errno_saved = errno;
991 #ifdef VERBOSE
992  const char *errstring = gai_strerror(return_value);
993  debug_write(errstring);
994 #endif
995  close(sfd);
996  errno = errno_saved;
997 
998  return -1;
999  }
1000 
1001  if (result->ai_family == AF_INET) {
1002  // Result is IPv4 address.
1003  mreq4.imr_multiaddr = ((struct sockaddr_in *)result->ai_addr)->sin_addr;
1004 
1005  if (if_name == NULL) {
1006  mreq4.imr_ifindex = 0;
1007  any.s_addr = INADDR_ANY;
1008  mreq4.imr_address = any;
1009  } else {
1010  memcpy(interface.ifr_name, if_name,
1011  strlen(if_name) > IFNAMSIZ ? IFNAMSIZ : strlen(if_name));
1012 
1013  if (-1 == check_error(ioctl(sfd, SIOCGIFINDEX, &interface))) {
1014  int errno_saved = errno;
1015  close(sfd);
1016  errno = errno_saved;
1017  return -1;
1018  }
1019 
1020  mreq4.imr_ifindex = interface.ifr_ifindex;
1021  }
1022 
1023  if (-1 == check_error(setsockopt(sfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1024  &mreq4, sizeof(struct ip_mreqn)))) {
1025  int errno_saved = errno;
1026  close(sfd);
1027  errno = errno_saved;
1028  return -1;
1029  }
1030  if (-1 == check_error(setsockopt(sfd, IPPROTO_IP, IP_MULTICAST_IF,
1031  &mreq4, sizeof(struct ip_mreqn)))) {
1032  int errno_saved = errno;
1033  close(sfd);
1034  errno = errno_saved;
1035  return -1;
1036  }
1037 
1038  // Setup finished.
1039  //
1040  } else if (result->ai_family == AF_INET6) {
1041  mreq6.ipv6mr_multiaddr =
1042  ((struct sockaddr_in6 *)result->ai_addr)->sin6_addr;
1043  mreq6.ipv6mr_interface = 0;
1044 
1045  if (if_name == NULL)
1046  mreq6.ipv6mr_interface = 0;
1047  else {
1048  memcpy(interface.ifr_name, if_name,
1049  strlen(if_name) > IFNAMSIZ ? IFNAMSIZ : strlen(if_name));
1050 
1051  if (-1 == check_error(ioctl(sfd, SIOCGIFINDEX, &interface))) {
1052  int errno_saved = errno;
1053  close(sfd);
1054  errno = errno_saved;
1055  return -1;
1056  }
1057 
1058  mreq6.ipv6mr_interface = interface.ifr_ifindex;
1059  }
1060 
1061  if (-1 == check_error(setsockopt(sfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
1062  &mreq6, sizeof(struct ipv6_mreq)))) {
1063  int errno_saved = errno;
1064  close(sfd);
1065  errno = errno_saved;
1066  return -1;
1067  }
1068  if (-1 == check_error(setsockopt(sfd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
1069  &mreq6.ipv6mr_interface,
1070  sizeof(mreq6.ipv6mr_interface)))) {
1071  int errno_saved = errno;
1072  close(sfd);
1073  errno = errno_saved;
1074  return -1;
1075  }
1076  }
1077 
1078  return sfd;
1079 }
1080 
1081 #endif
1082 
1087 #undef debug_write
int create_inet_server_socket(const char *bind_addr, const char *bind_port, char proto_osi4, char proto_osi3, int flags)
Create a TCP or UDP server socket.
int get_address_family(const char *hostname)
Look up which address families a host supports.
ssize_t sendto_inet_dgram_socket(int sfd, const void *buf, size_t size, const char *host, const char *service, int sendto_flags)
This function is the equivalent to sendto(2)
int destroy_inet_socket(int sfd)
Close a socket.
int create_multicast_socket(const char *group, const char *port, const char *if_name)
Create a datagram socket and join to the multicast group address.
int accept_inet_stream_socket(int sfd, char *src_host, size_t src_host_len, char *src_service, size_t src_service_len, int flags, int accept_flags)
Accept a connection attempt on a server socket.
int create_inet_stream_socket(const char *host, const char *service, char proto_osi3, int flags)
Create and connect a new TCP/IP socket.
int shutdown_inet_stream_socket(int sfd, int method)
Perform a shutdown(2) call on a socket.
static signed int check_error(int return_value)
Checks return value for error.
int connect_inet_dgram_socket(int sfd, const char *host, const char *service)
Connect a UDP socket.
ssize_t recvfrom_inet_dgram_socket(int sfd, void *buffer, size_t size, char *src_host, size_t src_host_len, char *src_service, size_t src_service_len, int recvfrom_flags, int numeric)
Receive data from a UDP/IP socket.
int create_inet_dgram_socket(char proto_osi3, int flags)
Creates a new UDP/IP socket.