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;
}
Beispiel #3
0
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); }