APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock, apr_sockaddr_t *iface) { #if defined(IP_MULTICAST_IF) && defined(HAVE_STRUCT_IPMREQ) apr_status_t rv = APR_SUCCESS; if (sock_is_ipv4(sock)) { if (setsockopt(sock->socketdes, IPPROTO_IP, IP_MULTICAST_IF, (const void *) &iface->sa.sin.sin_addr, sizeof(iface->sa.sin.sin_addr)) == -1) { rv = errno; } } #if APR_HAVE_IPV6 else if (sock_is_ipv6(sock)) { unsigned int idx = find_if_index(iface); if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const void *) &idx, sizeof(idx)) == -1) { rv = errno; } } #endif else { rv = APR_ENOTIMPL; } return rv; #else return APR_ENOTIMPL; #endif }
/* Set the IP_MULTICAST_TTL or IP_MULTICAST_LOOP option, or IPv6 * equivalents, for the socket, to the given value. Note that this * function *only works* for those particular option types. */ static apr_status_t do_mcast_opt(int type, apr_socket_t *sock, apr_byte_t value) { apr_status_t rv = APR_SUCCESS; if (sock_is_ipv4(sock)) { /* For the IP_MULTICAST_* options, this must be a (char *) * pointer. */ if (setsockopt(sock->socketdes, IPPROTO_IP, type, (const void *) &value, sizeof(value)) == -1) { rv = errno; } } #if APR_HAVE_IPV6 else if (sock_is_ipv6(sock)) { /* For the IPV6_* options, an (int *) pointer must be used. */ int ivalue = value; if (type == IP_MULTICAST_TTL) { type = IPV6_MULTICAST_HOPS; } else if (type == IP_MULTICAST_LOOP) { type = IPV6_MULTICAST_LOOP; } else { return APR_ENOTIMPL; } if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, (const void *) &ivalue, sizeof(ivalue)) == -1) { rv = errno; } } #endif else { rv = APR_ENOTIMPL; } return rv; }
static apr_status_t do_mcast_opt(int type, apr_socket_t *sock, apr_byte_t value) { apr_status_t rv = APR_SUCCESS; if (sock_is_ipv4(sock)) { if (setsockopt(sock->socketdes, IPPROTO_IP, type, (const void *) &value, sizeof(value)) == -1) { rv = errno; } } #if APR_HAVE_IPV6 else if (sock_is_ipv6(sock) && type == IP_MULTICAST_LOOP) { unsigned int loopopt = value; type = IPV6_MULTICAST_LOOP; if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, (const void *) &loopopt, sizeof(loopopt)) == -1) { rv = errno; } } else if (sock_is_ipv6(sock)) { if (type == IP_MULTICAST_TTL) { type = IPV6_MULTICAST_HOPS; } else { return APR_ENOTIMPL; } if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, &value, sizeof(value)) == -1) { rv = errno; } } #endif else { rv = APR_ENOTIMPL; } return rv; }
static apr_status_t do_mcast(int type, apr_socket_t *sock, apr_sockaddr_t *mcast, apr_sockaddr_t *iface, apr_sockaddr_t *source) { struct ip_mreq mip4; apr_status_t rv = APR_SUCCESS; #if APR_HAVE_IPV6 struct ipv6_mreq mip6; #endif #ifdef GROUP_FILTER_SIZE struct group_source_req mip; int ip_proto; #endif if (source != NULL) { #ifdef GROUP_FILTER_SIZE if (sock_is_ipv4(sock)) { ip_proto = IPPROTO_IP; } #if APR_HAVE_IPV6 else if (sock_is_ipv6(sock)) { ip_proto = IPPROTO_IPV6; } #endif else { return APR_ENOTIMPL; } if (type == IP_ADD_MEMBERSHIP) type = MCAST_JOIN_SOURCE_GROUP; else if (type == IP_DROP_MEMBERSHIP) type = MCAST_LEAVE_SOURCE_GROUP; else return APR_ENOTIMPL; mip.gsr_interface = find_if_index(iface); memcpy(&mip.gsr_group, mcast->ipaddr_ptr, sizeof(mip.gsr_group)); memcpy(&mip.gsr_source, source->ipaddr_ptr, sizeof(mip.gsr_source)); if (setsockopt(sock->socketdes, ip_proto, type, (const void *) &mip, sizeof(mip)) == -1) { rv = errno; } #else /* We do not support Source-Specific Multicast. */ return APR_ENOTIMPL; #endif } else { if (sock_is_ipv4(sock)) { fill_mip_v4(&mip4, mcast, iface); if (setsockopt(sock->socketdes, IPPROTO_IP, type, (const void *) &mip4, sizeof(mip4)) == -1) { rv = errno; } } #if APR_HAVE_IPV6 && defined(IPV6_JOIN_GROUP) && defined(IPV6_LEAVE_GROUP) else if (sock_is_ipv6(sock)) { if (type == IP_ADD_MEMBERSHIP) { type = IPV6_JOIN_GROUP; } else if (type == IP_DROP_MEMBERSHIP) { type = IPV6_LEAVE_GROUP; } else { return APR_ENOTIMPL; } fill_mip_v6(&mip6, mcast, iface); if (setsockopt(sock->socketdes, IPPROTO_IPV6, type, (const void *) &mip6, sizeof(mip6)) == -1) { rv = errno; } } #endif else { rv = APR_ENOTIMPL; } } return rv; }
bool addr_is_ipv4(_addr *a) { return sock_is_ipv4(a); }