diff --git a/CHANGES b/CHANGES index d0d974d..e5d3261 100644 --- a/CHANGES +++ b/CHANGES @@ -47,6 +47,8 @@ Coding: Renamed xioopts_t to xioparms_t to avoid confusion with xioopts module. + Moved multicast related code from xioopts.c to xio-ip.c and xio-ip6.c + Porting: Removed Config/ because its contents have not been maintained for many years. diff --git a/test.sh b/test.sh index 24dde14..676b8dd 100755 --- a/test.sh +++ b/test.sh @@ -7991,6 +7991,14 @@ elif ! feat=$(testfeats ip4 udp) || ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" +elif ! a=$(testaddrs UDP4-RECV UDP4-SENDTO); then + $PRINTF "test $F_n $TEST... ${YELLOW}Address $a not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +elif ! o=$(testoptions ip-add-membership bind) >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" else tf="$td/test$N.stdout" te="$td/test$N.stderr" @@ -8012,19 +8020,26 @@ kill "$pid1" 2>/dev/null; wait; if [ "$rc2" -ne 0 ]; then $PRINTF "$FAILED: $TRACE $SOCAT:\n" echo "$CMD1 &" + cat "${te}1" >&2 echo "$CMD2" - cat "${te}1" - cat "${te}2" + cat "${te}2" >&2 numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then $PRINTF "$FAILED\n" + echo "$CMD1 &" + cat "${te}1" >&2 + echo "$CMD2" + cat "${te}2" >&2 cat "$tdiff" numFAIL=$((numFAIL+1)) listFAIL="$listFAIL $N" else $PRINTF "$OK\n" - if [ -n "$debug" ]; then cat $te; fi + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$VERBOSE" ]; then echo "$CMD1"; fi + if [ "$DEBUG" ]; then cat "${te}1" >&2; fi numOK=$((numOK+1)) fi fi ;; # NUMCOND, feats @@ -12580,7 +12595,7 @@ N=$((N+1)) # fixed in 1.7.3.2 NAME=USE_IPV6_JOIN_GROUP case "$TESTS" in -*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ip6%*|*%udp%*|*%udp6%*|*%dgram%*|*%$NAME%*) +*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ip6%*|*%udp%*|*%udp6%*|*%dgram%*|*%multicast%*|*%$NAME%*) TEST="$NAME: is option ipv6-join-group used" # Invoke socat with option ipv6-join-group on UDP6 address. # Terminate immediately, do not transfer data. diff --git a/xio-ip.c b/xio-ip.c index fe2b608..0d595e9 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -131,7 +131,7 @@ unsigned long res_opts() { socktype: SOCK_STREAM, SOCK_DGRAM, ... protocol: IPPROTO_UDP, IPPROTO_TCP sau: an uninitialized storage for the resulting socket address - returns: STAT_OK, STAT_RETRYLATER + returns: STAT_OK, STAT_RETRYLATER, STAT_NORETRY, prints message */ int xiogetaddrinfo(const char *node, const char *service, int family, int socktype, int protocol, @@ -662,6 +662,201 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num, #endif /* defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA) */ +#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) +int xiotype_ip_add_membership( + char *tokp, + const struct optname *ent, + struct opt *opt) +{ + /* we do not resolve the addresses here because we do not yet know + if we are coping with a IPv4 or IPv6 socat address */ + const char *ends[] = { ":", NULL }; + const char *nests[] = { "[","]", NULL }; + char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1; + int parsres; + + /* parse first IP address, expect ':' */ + /*! result= */ + parsres = + nestlex((const char **)&tokp, &buffp, &bufspc, + ends, NULL, NULL, nests, + true, false, false); + if (parsres < 0) { + Error1("option too long: \"%s\"", tokp); + return -1; + } else if (parsres > 0) { + Error1("syntax error in \"%s\"", tokp); + return -1; + } + if (*tokp != ':') { + Error1("syntax in option %s: missing ':'", tokp); + } + *buffp++ = '\0'; + if ((opt->value.u_string/*multiaddr*/ = strdup(buff)) == NULL) { + Error1("strdup(\"%s\"): out of memory", buff); + return -1; + } + + ++tokp; + /* parse second IP address, expect ':' or '\0'' */ + buffp = buff; + /*! result= */ + parsres = + nestlex((const char **)&tokp, &buffp, &bufspc, + ends, NULL, NULL, nests, + true, false, false); + if (parsres < 0) { + Error1("option too long: \"%s\"", tokp); + return -1; + } else if (parsres > 0) { + Error1("syntax error in \"%s\"", tokp); + return -1; + } + *buffp++ = '\0'; + if ((opt->value2.u_string/*param2*/ = strdup(buff)) == NULL) { + Error1("strdup(\"%s\"): out of memory", buff); + free(opt->value.u_string); + return -1; + } + + +#if HAVE_STRUCT_IP_MREQN + if (*tokp++ == ':') { + strncpy(opt->value3.u_string/*ifindex*/, tokp, IF_NAMESIZE); /* ok */ + Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}", + ent->desc->defname, + opt->value.u_string/*multiaddr*/, + opt->value2.u_string/*param2*/, + opt->value3.u_string/*ifindex*/); + } else { + /*0 opt->value3.u_string = NULL; / * is NULL from init */ + Info3("setting option \"%s\" to {\"%s\",\"%s\"}", + ent->desc->defname, + opt->value.u_string/*multiaddr*/, + opt->value2.u_string/*param2*/); + } +#else /* !HAVE_STRUCT_IP_MREQN */ + Info3("setting option \"%s\" to {\"%s\",\"%s\"}", + ent->desc->defname, + opt->value.u_string/*multiaddr*/, + opt->value2.u_string/*param2*/); +#endif /* !HAVE_STRUCT_IP_MREQN */ + return 0; +} +#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */ + +#if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) +int xioapply_ip_add_membership( + xiosingle_t *xfd, + struct opt *opt) +{ + union { +#if HAVE_STRUCT_IP_MREQN + struct ip_mreqn mreqn; +#endif + struct ip_mreq mreq; + } ip4_mreqn = {{{0}}}; + /* IPv6 not supported - seems to have different handling */ +/* +mc:addr:ifname|ifind +mc:ifname|ifind +mc:addr +*/ + union sockaddr_union sockaddr1; + socklen_t socklen1 = sizeof(sockaddr1.ip4); + union sockaddr_union sockaddr2; + socklen_t socklen2 = sizeof(sockaddr2.ip4); + + /* first parameter is alway multicast address */ + /*! result */ + xiogetaddrinfo(opt->value.u_string/*multiaddr*/, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr1, &socklen1, 0, 0); + ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr; + if (0) { + ; /* for canonical reasons */ +#if HAVE_STRUCT_IP_MREQN + } else if (opt->value3.u_string/*ifindex*/ != NULL) { + /* three parameters */ + /* second parameter is interface address */ + xiogetaddrinfo(opt->value2.u_string/*param2*/, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr2, &socklen2, 0, 0); + ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; + /* third parameter is interface */ + if (ifindex(opt->value3.u_string/*ifindex*/, + (unsigned int *)&ip4_mreqn.mreqn.imr_ifindex, -1) + < 0) { + Error1("cannot resolve interface \"%s\"", + opt->value3.u_string/*ifindex*/); + } +#endif /* HAVE_STRUCT_IP_MREQN */ + } else { + /* two parameters */ + if (0) { + ; /* for canonical reasons */ +#if HAVE_STRUCT_IP_MREQN + /* there is a form with two parameters that uses mreqn */ + } else if (ifindex(opt->value2.u_string/*param2*/, + (unsigned int *)&ip4_mreqn.mreqn.imr_ifindex, + -1) + >= 0) { + /* yes, second param converts to interface */ + ip4_mreqn.mreq.imr_interface.s_addr = htonl(0); +#endif /* HAVE_STRUCT_IP_MREQN */ + } else { + /*! result */ + xiogetaddrinfo(opt->value2.u_string/*param2*/, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr2, &socklen2, 0, 0); + ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; + } + } + +#if LATER + if (0) { + ; /* for canonical reasons */ + } else if (xfd->para.socket.la.soa.sa_family == PF_INET) { + } else if (xfd->para.socket.la.soa.sa_family == PF_INET6) { + ip6_mreqn.mreq.imr_multiaddr = sockaddr1.ip6.sin6_addr; + ip6_mreqn.mreq.imr_interface = sockaddr2.ip6.sin6_addr; + } +#endif + +#if HAVE_STRUCT_IP_MREQN + if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, + &ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) { + Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s", + xfd->fd, opt->desc->major, opt->desc->minor, + ip4_mreqn.mreqn.imr_multiaddr.s_addr, + ip4_mreqn.mreqn.imr_address.s_addr, + ip4_mreqn.mreqn.imr_ifindex, + sizeof(ip4_mreqn.mreqn), + strerror(errno)); + opt->desc = ODESC_ERROR; + return -1; + } +#else + if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, + &ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) { + Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s", + xfd->fd, opt->desc->major, opt->desc->minor, + ip4_mreqn.mreq.imr_multiaddr, + ip4_mreqn.mreq.imr_interface, + sizeof(ip4_mreqn.mreq), + strerror(errno)); + opt->desc = ODESC_ERROR; + return -1; + } +#endif + return 0; +} +#endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */ + + #if HAVE_STRUCT_IP_MREQ_SOURCE int xiotype_ip_add_source_membership(char *token, const struct optname *ent, struct opt *opt) { /* we do not resolve the addresses here because we do not yet know @@ -688,7 +883,10 @@ int xiotype_ip_add_source_membership(char *token, const struct optname *ent, str Error1("syntax in option %s: missing ':'", token); } *buffp++ = '\0'; - opt->value.u_ip_mreq_source.mcaddr = strdup(buff); /*!!! NULL */ + if ((opt->value.u_string/*mcaddr*/ = strdup(buff)) == NULL) { + Error1("strdup(\"%s\"): out of memory", buff); + return -1; + } ++tokp; /* parse second IP address, expect ':' or '\0'' */ @@ -709,7 +907,11 @@ int xiotype_ip_add_source_membership(char *token, const struct optname *ent, str Error1("syntax in option %s: missing ':'", token); } *buffp++ = '\0'; - opt->value.u_ip_mreq_source.ifaddr = strdup(buff); /*!!! NULL */ + if ((opt->value2.u_string/*ifaddr*/ = strdup(buff)) == NULL) { + Error1("strdup(\"%s\"): out of memory", buff); + free(opt->value.u_string); + return -1; + } ++tokp; /* parse third IP address, expect ':' or '\0'' */ @@ -730,13 +932,18 @@ int xiotype_ip_add_source_membership(char *token, const struct optname *ent, str Error1("syntax in option %s: trailing cruft", token); } *buffp++ = '\0'; - opt->value.u_ip_mreq_source.srcaddr = strdup(buff); /*!!! NULL */ + if ((opt->value3.u_string/*srcaddr*/ = strdup(buff)) == NULL) { + Error1("strdup(\"%s\"): out of memory", buff); + free(opt->value.u_string); + free(opt->value2.u_string); + return -1; + } Info4("setting option \"%s\" to {0x%08x,0x%08x,0x%08x}", ent->desc->defname, - ntohl(*(unsigned int *)opt->value.u_ip_mreq_source.mcaddr), - ntohl(*(unsigned int *)opt->value.u_ip_mreq_source.ifaddr), - ntohl(*(unsigned int *)opt->value.u_ip_mreq_source.srcaddr)); + ntohl(*(unsigned int *)opt->value.u_string/*mcaddr*/), + ntohl(*(unsigned int *)opt->value2.u_string/*ifaddr*/), + ntohl(*(unsigned int *)opt->value3.u_string/*srcaddr*/)); return 0; } @@ -752,19 +959,19 @@ int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt) { /* first parameter is always multicast address */ /*! result */ - xiogetaddrinfo(opt->value.u_ip_mreq_source.mcaddr, NULL, + xiogetaddrinfo(opt->value.u_string/*mcaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr1, &socklen1, 0, 0); ip4_mreq_src.imr_multiaddr = sockaddr1.ip4.sin_addr; /* second parameter is interface address */ - xiogetaddrinfo(opt->value.u_ip_mreq_source.ifaddr, NULL, + xiogetaddrinfo(opt->value2.u_string/*ifaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr2, &socklen2, 0, 0); ip4_mreq_src.imr_interface = sockaddr2.ip4.sin_addr; /* third parameter is source address */ - xiogetaddrinfo(opt->value.u_ip_mreq_source.srcaddr, NULL, + xiogetaddrinfo(opt->value3.u_string/*srcaddr*/, NULL, xfd->para.socket.la.soa.sa_family, SOCK_DGRAM, IPPROTO_IP, &sockaddr3, &socklen3, 0, 0); diff --git a/xio-ip.h b/xio-ip.h index 8b3c922..ad6c8cb 100644 --- a/xio-ip.h +++ b/xio-ip.h @@ -49,6 +49,8 @@ int xiolog_ancillary_ip(struct cmsghdr *cmsg, int *num, char *nambuff, int namlen, char *envbuff, int envlen, char *valbuff, int vallen); +extern int xiotype_ip_add_membership(char *token, const struct optname *ent, struct opt *opt); +extern int xioapply_ip_add_membership(xiosingle_t *xfd, struct opt *opt); extern int xiotype_ip_add_source_membership(char* token, const struct optname *ent, struct opt *opt); extern int xioapply_ip_add_source_membership(struct single *xfd, struct opt *opt); diff --git a/xio-ip6.c b/xio-ip6.c index 98e5c7a..682f62a 100644 --- a/xio-ip6.c +++ b/xio-ip6.c @@ -81,6 +81,7 @@ const struct optdesc opt_ipv6_recvpathmtu = { "ipv6-recvpathmtu", "recvpathmtu", int xioip6_pton(const char *src, struct in6_addr *dst) { union sockaddr_union sockaddr; socklen_t sockaddrlen = sizeof(sockaddr); + int res; if (src[0] == '[') { char plainaddr[INET6_ADDRSTRLEN]; @@ -92,8 +93,9 @@ int xioip6_pton(const char *src, struct in6_addr *dst) { *clos = '\0'; return xioip6_pton(plainaddr, dst); } - if (xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, - 0, 0) + if ((res = + xiogetaddrinfo(src, NULL, PF_INET6, 0, 0, &sockaddr, &sockaddrlen, + 0, 0)) != STAT_OK) { return STAT_NORETRY; } @@ -457,4 +459,47 @@ xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen, return -1; } + +#if defined(HAVE_STRUCT_IPV6_MREQ) +int xioapply_ipv6_join_group( + xiosingle_t *xfd, + struct opt *opt) +{ + struct ipv6_mreq ip6_mreq = {{{{0}}}}; + union sockaddr_union sockaddr1; + socklen_t socklen1 = sizeof(sockaddr1.ip6); + int res; + + /* Always two parameters */ + /* First parameter is multicast address */ + if ((res = + xiogetaddrinfo(opt->value.u_string/*multiaddr*/, NULL, + xfd->para.socket.la.soa.sa_family, + SOCK_DGRAM, IPPROTO_IP, + &sockaddr1, &socklen1, 0, 0)) != STAT_OK) { + return res; + } + ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr; + if (ifindex(opt->value2.u_string/*param2*/, + &ip6_mreq.ipv6mr_interface, -1) + < 0) { + Error1("interface \"%s\" not found", + opt->value2.u_string/*param2*/); + ip6_mreq.ipv6mr_interface = htonl(0); + } + + if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, + &ip6_mreq, sizeof(ip6_mreq)) < 0) { + Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s", + xfd->fd, opt->desc->major, opt->desc->minor, + ip6_mreq.ipv6mr_interface, + sizeof(ip6_mreq), + strerror(errno)); + opt->desc = ODESC_ERROR; + return -1; + } + return 0; +} +#endif /* defined(HAVE_STRUCT_IPV6_MREQ) */ + #endif /* WITH_IP6 */ diff --git a/xio-ip6.h b/xio-ip6.h index e99e559..6da27e1 100644 --- a/xio-ip6.h +++ b/xio-ip6.h @@ -48,6 +48,7 @@ extern int xiosetsockaddrenv_ip6(int idx, char *namebuff, size_t namelen, char *valuebuff, size_t valuelen, struct sockaddr_in6 *sa, int ipproto); +extern int xioapply_ipv6_join_group(xiosingle_t *xfd, struct opt *opt); #endif /* WITH_IP6 */ diff --git a/xio.h b/xio.h index 80fdfce..4e5bc49 100644 --- a/xio.h +++ b/xio.h @@ -375,22 +375,6 @@ union integral { #if HAVE_STRUCT_TIMESPEC struct timespec u_timespec; #endif /* HAVE_STRUCT_TIMESPEC */ -#if HAVE_STRUCT_IP_MREQ || HAVE_STRUCT_IP_MREQN - struct { - char *multiaddr; - char *param2; /* address, interface */ -#if HAVE_STRUCT_IP_MREQN - char ifindex[IF_NAMESIZE+1]; -#endif - } u_ip_mreq; -#endif -#if HAVE_STRUCT_IP_MREQ_SOURCE - struct { - char *mcaddr; - char *ifaddr; /* address, interface */ - char *srcaddr; /* source address */ - } u_ip_mreq_source; -#endif #if WITH_IP4 struct in_addr u_ip4addr; #endif diff --git a/xioopts.c b/xioopts.c index 73dac1b..64a4793 100644 --- a/xioopts.c +++ b/xioopts.c @@ -2477,76 +2477,10 @@ int parseopts_table(const char **a, groups_t groups, struct opt **opts, (*opts)[i].value.u_int, (*opts)[i].value2.u_int, (*opts)[i].value3.u_string); break; + #if defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) - case TYPE_IP_MREQN: - { - /* we do not resolve the addresses here because we do not yet know - if we are coping with a IPv4 or IPv6 socat address */ - const char *ends[] = { ":", NULL }; - const char *nests[] = { "[","]", NULL }; - char buff[512], *buffp=buff; size_t bufspc = sizeof(buff)-1; - - /* parse first IP address, expect ':' */ - tokp = token; - /*! result= */ - parsres = - nestlex((const char **)&tokp, &buffp, &bufspc, - ends, NULL, NULL, nests, - true, false, false); - if (parsres < 0) { - Error1("option too long: \"%s\"", *a); - return -1; - } else if (parsres > 0) { - Error1("syntax error in \"%s\"", *a); - return -1; - } - if (*tokp != ':') { - Error1("syntax in option %s: missing ':'", token); - } - *buffp++ = '\0'; - (*opts)[i].value.u_ip_mreq.multiaddr = strdup(buff); /*!!! NULL */ - - ++tokp; - /* parse second IP address, expect ':' or '\0'' */ - buffp = buff; - /*! result= */ - parsres = - nestlex((const char **)&tokp, &buffp, &bufspc, - ends, NULL, NULL, nests, - true, false, false); - if (parsres < 0) { - Error1("option too long: \"%s\"", *a); - return -1; - } else if (parsres > 0) { - Error1("syntax error in \"%s\"", *a); - return -1; - } - *buffp++ = '\0'; - (*opts)[i].value.u_ip_mreq.param2 = strdup(buff); /*!!! NULL */ - -#if HAVE_STRUCT_IP_MREQN - if (*tokp++ == ':') { - strncpy((*opts)[i].value.u_ip_mreq.ifindex, tokp, IF_NAMESIZE); /* ok */ - Info4("setting option \"%s\" to {\"%s\",\"%s\",\"%s\"}", - ent->desc->defname, - (*opts)[i].value.u_ip_mreq.multiaddr, - (*opts)[i].value.u_ip_mreq.param2, - (*opts)[i].value.u_ip_mreq.ifindex); - } else { - (*opts)[i].value.u_ip_mreq.ifindex[0] = '\0'; - Info3("setting option \"%s\" to {\"%s\",\"%s\"}", - ent->desc->defname, - (*opts)[i].value.u_ip_mreq.multiaddr, - (*opts)[i].value.u_ip_mreq.param2); - } -#else /* !HAVE_STRUCT_IP_MREQN */ - Info3("setting option \"%s\" to {0x%08x,0x%08x}", - ent->desc->defname, - (*opts)[i].value.u_ip_mreq.multiaddr, - (*opts)[i].value.u_ip_mreq.param2); -#endif /* !HAVE_STRUCT_IP_MREQN */ - } + xiotype_ip_add_membership(token, ent, opt); break; #endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */ @@ -4029,110 +3963,10 @@ int applyopts_single(struct single *xfd, struct opt *opts, enum e_phase phase) { switch (opt->desc->optcode) { #if WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)) case OPT_IP_ADD_MEMBERSHIP: - { - union { -#if HAVE_STRUCT_IP_MREQN - struct ip_mreqn mreqn; -#endif - struct ip_mreq mreq; - } ip4_mreqn = {{{0}}}; - /* IPv6 not supported - seems to have different handling */ -/* -mc:addr:ifname|ifind -mc:ifname|ifind -mc:addr -*/ - union sockaddr_union sockaddr1; - socklen_t socklen1 = sizeof(sockaddr1.ip4); - union sockaddr_union sockaddr2; - socklen_t socklen2 = sizeof(sockaddr2.ip4); - - /* first parameter is alway multicast address */ - /*! result */ - xiogetaddrinfo(opt->value.u_ip_mreq.multiaddr, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr1, &socklen1, 0, 0); - ip4_mreqn.mreq.imr_multiaddr = sockaddr1.ip4.sin_addr; - if (0) { - ; /* for canonical reasons */ -#if HAVE_STRUCT_IP_MREQN - } else if (opt->value.u_ip_mreq.ifindex[0] != '\0') { - /* three parameters */ - /* second parameter is interface address */ - xiogetaddrinfo(opt->value.u_ip_mreq.param2, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr2, &socklen2, 0, 0); - ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; - /* third parameter is interface */ - if (ifindex(opt->value.u_ip_mreq.ifindex, - (unsigned int *)&ip4_mreqn.mreqn.imr_ifindex, -1) - < 0) { - Error1("cannot resolve interface \"%s\"", - opt->value.u_ip_mreq.ifindex); - } -#endif /* HAVE_STRUCT_IP_MREQN */ - } else { - /* two parameters */ - if (0) { - ; /* for canonical reasons */ -#if HAVE_STRUCT_IP_MREQN - /* there is a form with two parameters that uses mreqn */ - } else if (ifindex(opt->value.u_ip_mreq.param2, - (unsigned int *)&ip4_mreqn.mreqn.imr_ifindex, - -1) - >= 0) { - /* yes, second param converts to interface */ - ip4_mreqn.mreq.imr_interface.s_addr = htonl(0); -#endif /* HAVE_STRUCT_IP_MREQN */ - } else { - /*! result */ - xiogetaddrinfo(opt->value.u_ip_mreq.param2, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr2, &socklen2, 0, 0); - ip4_mreqn.mreq.imr_interface = sockaddr2.ip4.sin_addr; - } - } - -#if LATER - if (0) { - ; /* for canonical reasons */ - } else if (xfd->para.socket.la.soa.sa_family == PF_INET) { - } else if (xfd->para.socket.la.soa.sa_family == PF_INET6) { - ip6_mreqn.mreq.imr_multiaddr = sockaddr1.ip6.sin6_addr; - ip6_mreqn.mreq.imr_interface = sockaddr2.ip6.sin6_addr; - } -#endif - -#if HAVE_STRUCT_IP_MREQN - if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, - &ip4_mreqn.mreqn, sizeof(ip4_mreqn.mreqn)) < 0) { - Error8("setsockopt(%d, %d, %d, {0x%08x,0x%08x,%d}, "F_Zu"): %s", - xfd->fd, opt->desc->major, opt->desc->minor, - ip4_mreqn.mreqn.imr_multiaddr.s_addr, - ip4_mreqn.mreqn.imr_address.s_addr, - ip4_mreqn.mreqn.imr_ifindex, - sizeof(ip4_mreqn.mreqn), - strerror(errno)); - opt->desc = ODESC_ERROR; continue; - } -#else - if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, - &ip4_mreqn.mreq, sizeof(ip4_mreqn.mreq)) < 0) { - Error7("setsockopt(%d, %d, %d, {0x%08x,0x%08x}, "F_Zu"): %s", - xfd->fd, opt->desc->major, opt->desc->minor, - ip4_mreqn.mreq.imr_multiaddr, - ip4_mreqn.mreq.imr_interface, - sizeof(ip4_mreqn.mreq), - strerror(errno)); - opt->desc = ODESC_ERROR; continue; - } -#endif - break; + if (xioapply_ip_add_membership(xfd, opt) < 0) { + continue; } - break; + break; #endif /* WITH_IP4 && (defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN)) */ #if WITH_IP4 && defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) @@ -4140,43 +3974,15 @@ mc:addr if (xioapply_ip_add_source_membership(xfd, opt) < 0) { continue; } - break; + break; #endif /* WITH_IP4 && defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP) */ #if WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ) case OPT_IPV6_JOIN_GROUP: - { - struct ipv6_mreq ip6_mreq = {{{{0}}}}; - union sockaddr_union sockaddr1; - socklen_t socklen1 = sizeof(sockaddr1.ip6); - - /* always two parameters */ - /* first parameter is multicast address */ - /*! result */ - xiogetaddrinfo(opt->value.u_ip_mreq.multiaddr, NULL, - xfd->para.socket.la.soa.sa_family, - SOCK_DGRAM, IPPROTO_IP, - &sockaddr1, &socklen1, 0, 0); - ip6_mreq.ipv6mr_multiaddr = sockaddr1.ip6.sin6_addr; - if (ifindex(opt->value.u_ip_mreq.param2, - &ip6_mreq.ipv6mr_interface, -1) - < 0) { - Error1("interface \"%s\" not found", - opt->value.u_ip_mreq.param2); - ip6_mreq.ipv6mr_interface = htonl(0); - } - - if (Setsockopt(xfd->fd, opt->desc->major, opt->desc->minor, - &ip6_mreq, sizeof(ip6_mreq)) < 0) { - Error6("setsockopt(%d, %d, %d, {...,0x%08x}, "F_Zu"): %s", - xfd->fd, opt->desc->major, opt->desc->minor, - ip6_mreq.ipv6mr_interface, - sizeof(ip6_mreq), - strerror(errno)); - opt->desc = ODESC_ERROR; continue; - } + if (xioapply_ipv6_join_group(xfd, opt) < 0) { + continue; } - break; + break; #endif /* WITH_IP6 && defined(HAVE_STRUCT_IPV6_MREQ) */ default: /* ignore here */