LIBSSDP
 All Classes Files Functions Variables Typedefs Macros
socket_helpers.c
Go to the documentation of this file.
1 
7 #include <arpa/inet.h>
8 #include <errno.h>
9 #include <ifaddrs.h>
10 #ifdef linux
11 #include <linux/version.h>
12 #endif
13 #include <netinet/in.h>
14 #include <net/if.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/socket.h>
18 #include <unistd.h>
19 
20 #include "log.h"
21 #include "net_definitions.h"
22 #include "net_utils.h"
23 #include "socket_helpers.h"
24 #include "ssdp_static_defs.h"
25 
26 #if defined BSD || defined __APPLE__
27 #define CHECK_KERNEL_VERSION(...) TRUE
28 #else
29 #define CHECK_KERNEL_VERSION(...) LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
30 #endif
31 
32 int set_send_timeout(SOCKET sock, int timeout) {
33  struct timeval stimeout;
34  stimeout.tv_sec = timeout;
35  stimeout.tv_usec = 0;
36 
37  PRINT_DEBUG("Setting send-timeout to %d", (int)stimeout.tv_sec);
38 
39  if(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&stimeout,
40  sizeof(stimeout)) < 0) {
41  PRINT_ERROR("Failed to set send-timeout: %s", strerror(errno));
42  return errno;
43  }
44 
45  return 0;
46 }
47 
48 int set_receive_timeout(SOCKET sock, int timeout) {
49  struct timeval rtimeout;
50  rtimeout.tv_sec = timeout;
51  rtimeout.tv_usec = 0;
52 
53  PRINT_DEBUG("Setting receive-timeout to %d", (int)rtimeout.tv_sec);
54 
55  if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&rtimeout,
56  sizeof(rtimeout)) < 0) {
57  PRINT_ERROR("Failed to set receive-timeout: %s", strerror(errno));
58  return errno;
59  }
60 
61  return 0;
62 }
63 
64 int set_reuseaddr(SOCKET sock) {
65  int reuse = 1;
66  PRINT_DEBUG("Setting reuseaddr");
67  if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
68  PRINT_ERROR("Failed setting resuseaddr: %s", strerror(errno));
69  return errno;
70  }
71 
72  return 0;
73 }
74 
75 int set_reuseport(SOCKET sock) {
76  int reuse = 1;
77  PRINT_DEBUG("Setting reuseport");
78 #if (defined(linux) && CHECK_KERNEL_VERSION()) || \
79 defined BSD || defined __APPLE__
80  if(setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
81  PRINT_ERROR("Failed setting resuseport: %s", strerror(errno));
82  return errno;
83  }
84 #else
85  PRINT_WARN("Not supported, falling back to reuseaddr.");
86  return set_reuseaddr(sock);
87 #endif
88 
89  return 0;
90 }
91 
92 
93 int set_keepalive(SOCKET sock, BOOL keepalive) {
94  PRINT_DEBUG("Setting keepalive to %d", keepalive);
95  if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, sizeof(BOOL)) < 0) {
96  PRINT_ERROR("(%d) %s", errno, strerror(errno));
97  return 1;
98  }
99 
100  return 0;
101 }
102 
103 int set_ttl(SOCKET sock, int family, int ttl) {
104  PRINT_DEBUG("Setting TTL to %d", ttl);
105  if(setsockopt(sock,
106  (family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6),
107  (family == AF_INET ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS),
108  (char *)&ttl,
109  sizeof(ttl)) < 0) {
110  PRINT_ERROR("(%d) %s", errno, strerror(errno));
111  return 1;
112  }
113 
114  return 0;
115 }
116 
117 // TODO: fix family to 'BOOL ipv6'
118 int disable_multicast_loopback(SOCKET sock, int family) {
119  unsigned char loop = FALSE;
120  PRINT_DEBUG("Disabling loopback multicast traffic");
121  if(setsockopt(sock,
122  family == AF_INET ? IPPROTO_IP :
123  IPPROTO_IPV6,
124  family == AF_INET ? IP_MULTICAST_LOOP :
125  IPV6_MULTICAST_LOOP,
126  &loop,
127  sizeof(loop)) < 0) {
128  PRINT_ERROR("(%d) %s", errno, strerror(errno));
129  return 1;
130  }
131 
132  return 0;
133 }
134 
135 int join_multicast_group(SOCKET sock, char *multicast_group, char *interface_ip) {
136  struct ifaddrs *ifa, *interfaces = NULL;
137  BOOL is_bindall = FALSE;
138  BOOL is_mc_ipv6 = FALSE;
139  BOOL is_ipv6 = FALSE;
140  struct sockaddr_storage sa_interface;
141 
142  PRINT_DEBUG("join_multicast_group(%d, \"%s\", \"%s\")", sock,
143  multicast_group, interface_ip);
144 
145  /* Check if multicast_group is a IPv6 address*/
146  if (inet_pton(AF_INET6, interface_ip,
147  (void *)&((struct sockaddr_in6 *)&sa_interface)->sin6_addr) > 0) {
148  is_mc_ipv6 = TRUE;
149  }
150  else {
151  /* Check if multicast_group is a IPv4 address */
152  int res;
153 
154  if ((res = inet_pton(AF_INET, interface_ip,
155  (void *)&((struct sockaddr_in *)&sa_interface)->sin_addr)) < 1) {
156  if (res == 0) {
157  PRINT_ERROR("interface_ip is NULL");
158  } else {
159  PRINT_ERROR("Given multicast group address '%s' is neither an IPv4 nor"
160  " IPv6, cannot continue (%d)", interface_ip);
161  }
162  return 1;
163  }
164  }
165 
166  PRINT_DEBUG("Multicast group address is IPv%d", (is_mc_ipv6 ? 6 : 4));
167 
168  /* If interface_ip is empty string set it to "0.0.0.0" */
169  if(interface_ip != NULL && strlen(interface_ip) == 0) {
170  if(is_mc_ipv6) {
171  strncpy(interface_ip, "::", IPv6_STR_MAX_SIZE);
172  }
173  else {
174  strncpy(interface_ip, "0.0.0.0", IPv6_STR_MAX_SIZE);
175  }
176  PRINT_DEBUG("interface_ip was empty, set to '%s'", interface_ip);
177  }
178 
179  /* Check if interface_ip is a IPv6 address*/
180  if (inet_pton(AF_INET6, interface_ip,
181  (void *)&((struct sockaddr_in6 *)&sa_interface)->sin6_addr) > 0) {
182  is_ipv6 = TRUE;
183  }
184  else {
185  /* Check if interface_ip is a IPv4 address */
186  int res;
187 
188  if ((res = inet_pton(AF_INET, interface_ip,
189  (void *)&((struct sockaddr_in *)&sa_interface)->sin_addr)) < 1) {
190  if (res == 0) {
191  PRINT_ERROR("interface_ip is NULL");
192  } else {
193  PRINT_ERROR("Given interface address '%s' is neither an IPv4 nor IPv6,"
194  " cannot continue", interface_ip);
195  }
196  return 1;
197  }
198  }
199 
200  PRINT_DEBUG("Interface address is IPv%d", (is_mc_ipv6 ? 6 : 4));
201 
202  /* Check if the address is a bind-on-all address*/
203  if(strcmp("0.0.0.0", interface_ip) == 0 ||
204  strcmp("::", interface_ip) == 0) {
205  is_bindall = TRUE;
206  }
207 
208  PRINT_DEBUG("Interface address is %s", (is_bindall ? "a bind-all address" :
209  interface_ip));
210 
211  /* Get all interfaces and IPs */
212  if(getifaddrs(&interfaces) < 0) {
213  PRINT_ERROR("Could not find any interfaces: (%d) %s\n", errno,
214  strerror(errno));
215  return 1;
216  }
217 
218  /* DEBUG BEGIN */
219  PRINT_DEBUG("List of available interfaces and IPs:");
220  PRINT_DEBUG("********************");
221  for (ifa = interfaces; ifa != NULL; ifa = ifa->ifa_next) {
222  struct in_addr *ifaddr4 =
223  (struct in_addr *)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
224  struct in6_addr *ifaddr6 =
225  (struct in6_addr *)&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
226  char ip[IPv6_STR_MAX_SIZE];
227  if(ifa->ifa_addr->sa_family != AF_INET &&
228  ifa->ifa_addr->sa_family != AF_INET6) {
229  PRINT_DEBUG("Not an internet address, skipping interface.");
230  continue;
231  }
232  if(inet_ntop(ifa->ifa_addr->sa_family,
233  ifa->ifa_addr->sa_family == AF_INET ? (void *)ifaddr4 :
234  (void *)ifaddr6,
235  ip,
236  IPv6_STR_MAX_SIZE) == NULL) {
237  PRINT_ERROR("Failed to extract address, skipping interface: (%d) %s",
238  errno,
239  strerror(errno));
240  continue;
241  }
242  PRINT_DEBUG("IF: %s; IP: %s", ifa->ifa_name, ip);
243  }
244  PRINT_DEBUG("********************");
245  /* DEBUG END */
246 
247  PRINT_DEBUG("Start looping through available interfaces and IPs");
248 
249  /* Loop throgh all the interfaces */
250  for (ifa = interfaces; ifa != NULL; ifa = ifa->ifa_next) {
251 
252  /* Skip loopback addresses */
253  if(ifa->ifa_flags & IFF_LOOPBACK) {
254  PRINT_DEBUG("Loopback address detected, skipping");
255  continue;
256  }
257 
258  /* Helpers */
259  struct in_addr *ifaddr4 =
260  (struct in_addr *)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
261  struct in6_addr *ifaddr6 =
262  (struct in6_addr *)&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
263  int ss_family = ifa->ifa_addr->sa_family;
264 
265  /* Skip if not a required type of IP address */
266  if((!is_ipv6 && ss_family != AF_INET) ||
267  (is_ipv6 && ss_family != AF_INET6)) {
268  PRINT_DEBUG("Skipping interface (%s) address, wrong type (%d)",
269  ifa->ifa_name,
270  ss_family);
271  continue;
272  }
273 
274  /* Extract IP in string format */
275  char ip[IPv6_STR_MAX_SIZE];
276  if(inet_ntop(ss_family,
277  ss_family == AF_INET ? (void *)ifaddr4 :
278  (void *)ifaddr6,
279  ip,
280  IPv6_STR_MAX_SIZE) == NULL) {
281  PRINT_ERROR("Failed to extract address, will skip current interface:"
282  " (%d) %s", errno, strerror(errno));
283  continue;
284  }
285 
286  /* If not using a bindall IP then skip all
287  IP that do not match the desired IP */
288  if(!is_bindall && strcmp(ip, interface_ip) != 0) {
289  PRINT_DEBUG("Skipping interface (%s) address, wrong IP (%s != %s)",
290  ifa->ifa_name,
291  ip,
292  interface_ip);
293  continue;
294  }
295 
296  PRINT_DEBUG("Found candidate interface %s, type %d, IP %s", ifa->ifa_name,
297  ss_family, ip);
298 
299  struct ip_mreq mreq;
300  struct ipv6_mreq mreq6;
301 
302  if(!is_ipv6) {
303  memset(&mreq, 0, sizeof(struct ip_mreq));
304  mreq.imr_interface.s_addr = ifaddr4->s_addr;
305  }
306  else {
307  memset(&mreq6, 0, sizeof(struct ipv6_mreq));
308  mreq6.ipv6mr_interface = if_nametoindex(ifa->ifa_name);
309  }
310 
311  int res;
312  if((res = inet_pton(ss_family,
313  multicast_group,
314  (is_ipv6 ? (void *)&mreq6.ipv6mr_multiaddr :
315  (void *)&mreq.imr_multiaddr))) < 1) {
316  if (res == 0) {
317  PRINT_ERROR("interface_ip is NULL");
318  } else {
319  PRINT_ERROR("Incompatible multicast group");
320  }
321  return 1;
322  }
323 
324  #ifdef DEBUG___
325  {
326  PRINT_DEBUG("%s", (is_ipv6 ? "IPV6_ADD_MEMBERSHIP" :
327  "IP_ADD_MEMBERSHIP"));
328  char a[IPv6_STR_MAX_SIZE];
329  if(is_ipv6) {
330  PRINT_DEBUG("mreq6.ipv6mr_interface: %d", mreq6.ipv6mr_interface);
331  }
332  else {
333  inet_ntop(ss_family, (void *)&mreq.imr_interface, a, IPv6_STR_MAX_SIZE);
334  PRINT_DEBUG("mreq.imr_interface: %s", a);
335  }
336  inet_ntop(ss_family,
337  is_ipv6 ? (void *)&mreq6.ipv6mr_multiaddr :
338  (void *)&mreq.imr_multiaddr,
339  a,
341  PRINT_DEBUG("mreq%smr_multiaddr: %s", (is_ipv6 ? "6.ipv6" : ".i"), a);
342  }
343  #endif
344 
345  PRINT_DEBUG("Joining multicast group '%s' on interface IP '%s'",
346  multicast_group, ip);
347 
348  if(setsockopt(sock,
349  is_ipv6 ? IPPROTO_IPV6 :
350  IPPROTO_IP,
351  is_ipv6 ? IPV6_ADD_MEMBERSHIP :
352  IP_ADD_MEMBERSHIP,
353  is_ipv6 ? (void *)&mreq6 :
354  (void *)&mreq,
355  is_ipv6 ? sizeof(struct ipv6_mreq) :
356  sizeof(struct ip_mreq)) < 0) {
357  PRINT_ERROR("(%d) %s", errno, strerror(errno));
358  close(sock);
359  freeifaddrs(interfaces);
360  return 1;
361  }
362  }
363 
364  PRINT_DEBUG("Finished looping through interfaces and IPs");
365 
366  /* Free ifaddrs interfaces */
367  if(interfaces != NULL) {
368  freeifaddrs(interfaces);
369  interfaces = NULL;
370  }
371 
372  return 0;
373 }
374 
376  SOCKET sock;
377  int protocol;
378  int ifindex = 0;
379  struct ip_mreq mreq;
380  struct ipv6_mreq mreq6;
381  struct sockaddr_storage *saddr;
382 
383  saddr = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage));
384  memset(saddr, 0, sizeof(struct sockaddr_storage));
385  memset(&mreq, 0, sizeof(mreq));
386  memset(&mreq6, 0, sizeof(mreq6));
387 
388  /* If 'conf->sa' (sockaddr) given instead of 'conf->if_ip' (char *)
389  then fill 'conf->if_ip' with the IP from the sockaddr */
390  if(conf->sa != NULL) {
391  void *sock_addr;
392  if (conf->sa->ss_family == AF_INET) {
393  sock_addr = (void *)&((struct sockaddr_in *)conf->sa)->sin_addr;
394  } else {
395  sock_addr = (void *)&((struct sockaddr_in6 *)conf->sa)->sin6_addr;
396  }
397  inet_ntop(conf->sa->ss_family, sock_addr, conf->if_ip, IPv6_STR_MAX_SIZE);
398  }
399 
400  /* Find the index of the interface */
401  ifindex = find_interface(saddr, conf->interface, conf->if_ip);
402  if(ifindex < 0) {
403  PRINT_ERROR("The requested interface '%s' could not be found",
404  conf->interface);
405  free(saddr);
406  return SOCKET_ERROR;
407  }
408 
409  #ifdef DEBUG___
410  {
411  char a[100];
412  memset(a, '\0', 100);
413  if(!inet_ntop(saddr->ss_family, (saddr->ss_family == AF_INET ?
414  (void *)&((struct sockaddr_in *)saddr)->sin_addr :
415  (void *)&((struct sockaddr_in6 *)saddr)->sin6_addr), a, 100)) {
416  PRINT_ERROR("setup_socket(); inet_ntop(): (%d) %s", errno,
417  strerror(errno));
418  }
419  PRINT_DEBUG("find_interface() returned: saddr->sin_addr: %s", a);
420  }
421  #endif
422 
423  /* If muticast requested, check if it really is a multicast address */
424  if (conf->is_multicast && (conf->ip != NULL && strlen(conf->ip) > 0)) {
425  if(!is_address_multicast(conf->ip)) {
426  PRINT_ERROR("The specified IP (%s) is not a multicast address\n",
427  conf->ip);
428  free(saddr);
429  if(conf->sa != NULL) {
430  free(conf->interface);
431  }
432  return SOCKET_ERROR;
433  }
434  }
435 
436  /* Set protocol version */
437  if (conf->is_ipv6) {
438  saddr->ss_family = AF_INET6;
439  protocol = IPPROTO_IPV6;
440  }
441  else {
442  saddr->ss_family = AF_INET;
443  protocol = IPPROTO_IP;
444  }
445 
446  /* init socket */
447  sock = socket(saddr->ss_family, conf->is_udp ? SOCK_DGRAM : SOCK_STREAM,
448  protocol);
449 
450  if (sock < 0) {
451  PRINT_ERROR("Failed to create socket. (%d) %s", errno, strerror(errno));
452  free(saddr);
453  if (conf->sa != NULL) {
454  free(conf->interface);
455  }
456  return SOCKET_ERROR;
457  }
458 
459  /* Set reuseaddr */
460  if (set_reuseaddr(sock)) {
461  free(saddr);
462  if(conf->sa != NULL) {
463  free(conf->interface);
464  }
465  return SOCKET_ERROR;
466  }
467 
468  /* Set reuseport */
469  if (set_reuseport(sock)) {
470  free(saddr);
471  if(conf->sa != NULL) {
472  free(conf->interface);
473  }
474  return SOCKET_ERROR;
475  }
476 
477  /* Set keepalive */
478  if (set_keepalive(sock, conf->keepalive)) {
479  free(saddr);
480  if (conf->sa != NULL) {
481  free(conf->interface);
482  }
483  return SOCKET_ERROR;
484  }
485 
486  /* Set TTL */
487  if (!conf->is_server && conf->is_multicast) {
488  if (set_ttl(sock, (conf->is_ipv6 ? AF_INET6 : AF_INET), conf->ttl) < 0) {
489  free(saddr);
490  if (conf->sa != NULL) {
491  free(conf->interface);
492  }
493  return SOCKET_ERROR;
494  }
495  }
496 
497  /* Set receive timeout */
498  if ((conf->recv_timeout > 0) &&
499  set_receive_timeout(sock, conf->recv_timeout)) {
500  free(saddr);
501  if (conf->sa != NULL) {
502  free(conf->interface);
503  }
504  return SOCKET_ERROR;
505  }
506 
507  /* Set send timeout */
508  if ((conf->send_timeout > 0) &&
509  set_send_timeout(sock, conf->send_timeout)) {
510  free(saddr);
511  if (conf->sa != NULL) {
512  free(conf->interface);
513  }
514  return SOCKET_ERROR;
515  }
516 
517  /* Setup address structure containing address information to use to connect */
518  if (conf->is_ipv6) {
519  PRINT_DEBUG("is_ipv6 == TRUE");
520  struct sockaddr_in6 * saddr6 = (struct sockaddr_in6 *)saddr;
521  saddr6->sin6_port = htons(conf->port);
522  if(conf->is_udp && conf->is_multicast) {
523  PRINT_DEBUG(" is_udp == TRUE && is_multicast == TRUE");
524  if (conf->ip == NULL || strlen(conf->ip) < 1) {
525  inet_pton(saddr->ss_family, SSDP_ADDR6_LL, &mreq6.ipv6mr_multiaddr);
526  }
527  else {
528  inet_pton(saddr->ss_family, conf->ip, &mreq6.ipv6mr_multiaddr);
529  }
530  if(conf->interface != NULL && strlen(conf->interface) > 0) {
531  mreq6.ipv6mr_interface = (unsigned int)ifindex;
532  }
533  else {
534  mreq6.ipv6mr_interface = (unsigned int)0;
535  }
536  //saddr6->sin6_addr = mreq6.ipv6mr_multiaddr;
537 
538  #ifdef DEBUG___
539  {
540  if(!conf->is_server) {
541  PRINT_DEBUG(" IPV6_MULTICAST_IF");
542  }
543  char a[100];
544  PRINT_DEBUG(" mreq6->ipv6mr_interface: %d", ifindex);
545  inet_ntop(saddr->ss_family, (void *)&mreq6.ipv6mr_multiaddr, a, 100);
546  PRINT_DEBUG(" mreq6->ipv6mr_multiaddr: %s", a);
547  }
548  #endif
549 
550  if(!conf->is_server && setsockopt(sock,
551  protocol,
552  IPV6_MULTICAST_IF,
553  &mreq6.ipv6mr_interface,
554  sizeof(mreq6.ipv6mr_interface)) < 0) {
555  PRINT_ERROR("setsockopt() IPV6_MULTICAST_IF: (%d) %s", errno,
556  strerror(errno));
557  free(saddr);
558  if(conf->sa != NULL) {
559  free(conf->interface);
560  }
561  return SOCKET_ERROR;
562  }
563  }
564  }
565  else {
566  PRINT_DEBUG("is_ipv6 == FALSE");
567  struct sockaddr_in *saddr4 = (struct sockaddr_in *)saddr;
568  saddr4->sin_port = htons(conf->port);
569  if (conf->is_udp && conf->is_multicast) {
570  PRINT_DEBUG(" is_udp == TRUE && is_multicast == TRUE");
571  if (conf->ip == NULL || strlen(conf->ip) < 1) {
572  inet_pton(saddr->ss_family, SSDP_ADDR, &mreq.imr_multiaddr);
573  }
574  else {
575  inet_pton(saddr->ss_family, conf->ip, &mreq.imr_multiaddr);
576  }
577  if ((conf->if_ip != NULL && strlen(conf->if_ip) > 0) ||
578  (conf->interface != NULL && strlen(conf->interface) > 0)) {
579  mreq.imr_interface.s_addr = saddr4->sin_addr.s_addr;
580  }
581  else {
582  mreq.imr_interface.s_addr = htonl(INADDR_ANY);
583  }
584  //saddr4->sin_addr = mreq.imr_multiaddr;
585  #ifdef DEBUG___
586  {
587  if (!conf->is_server) {
588  PRINT_DEBUG(" IP_MULTICAST_IF");
589  }
590  char a[100];
591  inet_ntop(saddr->ss_family, (void *)&mreq.imr_interface, a, 100);
592  PRINT_DEBUG(" mreq->imr_interface: %s", a);
593  inet_ntop(saddr->ss_family, (void *)&mreq.imr_multiaddr, a, 100);
594  PRINT_DEBUG(" mreq->imr_multiaddr: %s", a);
595  }
596  #endif
597  if (!conf->is_server && setsockopt(sock, protocol, IP_MULTICAST_IF,
598  &mreq.imr_interface, sizeof(mreq.imr_interface)) < 0) {
599  PRINT_ERROR("setsockopt() IP_MULTICAST_IF: (%d) %s", errno,
600  strerror(errno));
601  free(saddr);
602  if (conf->sa != NULL) {
603  free(conf->interface);
604  }
605  return SOCKET_ERROR;
606  }
607  }
608  }
609 
610  /* Enable/disable loopback multicast */
611  if (conf->is_server && conf->is_multicast && !conf->loopback &&
612  disable_multicast_loopback(sock, saddr->ss_family)) {
613  free(saddr);
614  if (conf->sa != NULL) {
615  free(conf->interface);
616  }
617  return SOCKET_ERROR;
618  }
619 
620  /* If server requested, bind the socket to the given address and port */
621  // TODO: Fix for IPv6
622  if(conf->is_server) {
623 
624  struct sockaddr_in bindaddr;
625  bindaddr.sin_family = saddr->ss_family;
626  bindaddr.sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
627  bindaddr.sin_port = ((struct sockaddr_in *)saddr)->sin_port;
628 
629  #ifdef DEBUG___
630  PRINT_DEBUG("is_server == TRUE");
631  char a[100];
632  inet_ntop(bindaddr.sin_family,
633  (void *)&((struct sockaddr_in *)&bindaddr)->sin_addr, a, 100);
634  PRINT_DEBUG(" bind() to: saddr->sin_family: %d(%d)",
635  ((struct sockaddr_in *)&bindaddr)->sin_family, AF_INET);
636  PRINT_DEBUG(" bind() to: saddr->sin_addr: %s (port %d)", a,
637  ntohs(((struct sockaddr_in *)&bindaddr)->sin_port));
638  #endif
639 
640  if (bind(sock, (struct sockaddr *)&bindaddr,
641  (bindaddr.sin_family == AF_INET ? sizeof(struct sockaddr_in) :
642  sizeof(struct sockaddr_in6))) < 0) {
643  PRINT_ERROR("setup_socket(); bind(): (%d) %s", errno, strerror(errno));
644  free(saddr);
645  if(conf->sa != NULL) {
646  free(conf->interface);
647  }
648  return SOCKET_ERROR;
649  }
650  if (!conf->is_udp) {
651  PRINT_DEBUG(" is_udp == FALSE");
652  if (listen(sock, conf->queue_length) == SOCKET_ERROR) {
653  PRINT_ERROR("setup_socket(); listen(): (%d) %s", errno,
654  strerror(errno));
655  close(sock);
656  free(saddr);
657  if(conf->sa != NULL) {
658  free(conf->interface);
659  }
660  return SOCKET_ERROR;
661  }
662  }
663  }
664 
665  /* Make sure we have a string IP before joining multicast groups */
666  /* NOTE: Workaround until refactoring is complete */
667  char iface_ip[IPv6_STR_MAX_SIZE];
668  if (conf->if_ip == NULL || strlen(conf->if_ip) < 1) {
669  void *sock_addr;
670 
671  if (conf->is_ipv6) {
672  sock_addr = (void *)&((struct sockaddr_in6 *)saddr)->sin6_addr;
673  } else {
674  sock_addr = (void *)&((struct sockaddr_in *)saddr)->sin_addr;
675  }
676 
677  if (inet_ntop(conf->is_ipv6 ? AF_INET6 : AF_INET, sock_addr, iface_ip,
678  IPv6_STR_MAX_SIZE) == NULL) {
679  PRINT_ERROR("Failed to get string representation of the interface "
680  "IP address: (%d) %s", errno, strerror(errno));
681  free(saddr);
682  return SOCKET_ERROR;
683  }
684  }
685  else {
686  strcpy(iface_ip, conf->if_ip);
687  }
688 
689  /* Join the multicast group on required interfaces */
690  if (conf->is_server && conf->is_multicast && join_multicast_group(sock,
691  conf->is_ipv6 ? SSDP_ADDR6_SL : SSDP_ADDR, iface_ip)) {
692  PRINT_ERROR("Failed to join required multicast group");
693  return SOCKET_ERROR;
694  }
695 
696  free(saddr);
697 
698  return sock;
699 }
700 
#define IPv6_STR_MAX_SIZE
int set_receive_timeout(SOCKET sock, int timeout)
int join_multicast_group(SOCKET sock, char *multicast_group, char *interface_ip)
int set_keepalive(SOCKET sock, BOOL keepalive)
int SOCKET
int set_reuseport(SOCKET sock)
int find_interface(struct sockaddr_storage *saddr, const char *interface, const char *address)
Definition: net_utils.c:192
int set_reuseaddr(SOCKET sock)
BOOL is_address_multicast(const char *address)
Definition: net_utils.c:583
#define SSDP_ADDR6_SL
int set_send_timeout(SOCKET sock, int timeout)
#define TRUE
#define FALSE
int set_ttl(SOCKET sock, int family, int ttl)
SOCKET setup_socket(socket_conf_s *conf)
#define SSDP_ADDR6_LL
struct sockaddr_storage * sa
int disable_multicast_loopback(SOCKET sock, int family)
int BOOL
#define SSDP_ADDR
static configuration_s conf
Definition: main.c:73
#define SOCKET_ERROR
const char * ip