123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include "fspr_arch_networkio.h"
- #include "fspr_network_io.h"
- #include "fspr_support.h"
- #include "fspr_portable.h"
- #include "fspr_arch_inherit.h"
- #ifdef HAVE_GETIFADDRS
- #include <net/if.h>
- #include <ifaddrs.h>
- #endif
- #ifdef HAVE_STRUCT_IPMREQ
- /* Only UDP and Raw Sockets can be used for Multicast */
- static fspr_status_t mcast_check_type(fspr_socket_t *sock)
- {
- int type;
- fspr_status_t rv;
- rv = fspr_socket_type_get(sock, &type);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- else if (type == SOCK_DGRAM || type == SOCK_RAW) {
- return APR_SUCCESS;
- }
- else {
- return APR_ENOTIMPL;
- }
- }
- static void fill_mip_v4(struct ip_mreq *mip, fspr_sockaddr_t *mcast,
- fspr_sockaddr_t *iface)
- {
- mip->imr_multiaddr = mcast->sa.sin.sin_addr;
- if (iface == NULL) {
- mip->imr_interface.s_addr = INADDR_ANY;
- }
- else {
- mip->imr_interface = iface->sa.sin.sin_addr;
- }
- }
- static unsigned int find_if_index(const fspr_sockaddr_t *iface)
- {
- unsigned int index = 0;
- #if defined(HAVE_GETIFADDRS) && APR_HAVE_IPV6
- struct ifaddrs *ifp, *ifs;
- /**
- * TODO: getifaddrs is only portable to *BSD and OS X. Using ioctl
- * and SIOCGIFCONF is needed for Linux/Solaris support.
- *
- * There is a wrapper that takes the messy ioctl interface into
- * getifaddrs. The license is acceptable, but, It is a fairly large
- * chunk of code.
- */
- if (getifaddrs(&ifs) != 0) {
- return 0;
- }
- for (ifp = ifs; ifp; ifp = ifp->ifa_next) {
- if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family == AF_INET6) {
- if (memcmp(&iface->sa.sin6.sin6_addr,
- &ifp->ifa_addr->sa_data[0],
- sizeof(iface->sa.sin6.sin6_addr)) == 0) {
- index = if_nametoindex(ifp->ifa_name);
- break;
- }
- }
- }
- freeifaddrs(ifs);
- #endif
- return index;
- }
- #if APR_HAVE_IPV6
- static void fill_mip_v6(struct ipv6_mreq *mip, const fspr_sockaddr_t *mcast,
- const fspr_sockaddr_t *iface)
- {
- memcpy(&mip->ipv6mr_multiaddr, mcast->ipaddr_ptr,
- sizeof(mip->ipv6mr_multiaddr));
- if (iface == NULL) {
- mip->ipv6mr_interface = 0;
- }
- else {
- mip->ipv6mr_interface = find_if_index(iface);
- }
- }
- #endif
- static int sock_is_ipv4(fspr_socket_t *sock)
- {
- if (sock->local_addr->family == APR_INET)
- return 1;
- return 0;
- }
- #if APR_HAVE_IPV6
- static int sock_is_ipv6(fspr_socket_t *sock)
- {
- if (sock->local_addr->family == APR_INET6)
- return 1;
- return 0;
- }
- #endif
- static fspr_status_t do_mcast(int type, fspr_socket_t *sock,
- fspr_sockaddr_t *mcast, fspr_sockaddr_t *iface,
- fspr_sockaddr_t *source)
- {
- struct ip_mreq mip4;
- fspr_status_t rv = APR_SUCCESS;
- #if APR_HAVE_IPV6
- struct ipv6_mreq mip6;
- #endif
- #if MCAST_JOIN_SOURCE_GROUP
- struct group_source_req mip;
- int ip_proto;
- #endif
- rv = mcast_check_type(sock);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- if (source != NULL) {
- #if MCAST_JOIN_SOURCE_GROUP
- 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,
- &mip6, sizeof(mip6)) == -1) {
- rv = errno;
- }
- }
- #endif
- else {
- rv = APR_ENOTIMPL;
- }
- }
- return rv;
- }
- static fspr_status_t do_mcast_opt(int type, fspr_socket_t *sock,
- fspr_byte_t value)
- {
- fspr_status_t rv = APR_SUCCESS;
- rv = mcast_check_type(sock);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- 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,
- &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;
- }
- #endif
- APR_DECLARE(fspr_status_t) fspr_mcast_join(fspr_socket_t *sock,
- fspr_sockaddr_t *join,
- fspr_sockaddr_t *iface,
- fspr_sockaddr_t *source)
- {
- #if defined(IP_ADD_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ)
- return do_mcast(IP_ADD_MEMBERSHIP, sock, join, iface, source);
- #else
- return APR_ENOTIMPL;
- #endif
- }
- APR_DECLARE(fspr_status_t) fspr_mcast_leave(fspr_socket_t *sock,
- fspr_sockaddr_t *addr,
- fspr_sockaddr_t *iface,
- fspr_sockaddr_t *source)
- {
- #if defined(IP_DROP_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ)
- return do_mcast(IP_DROP_MEMBERSHIP, sock, addr, iface, source);
- #else
- return APR_ENOTIMPL;
- #endif
- }
- APR_DECLARE(fspr_status_t) fspr_mcast_hops(fspr_socket_t *sock, fspr_byte_t ttl)
- {
- #if defined(IP_MULTICAST_TTL) && defined(HAVE_STRUCT_IPMREQ)
- return do_mcast_opt(IP_MULTICAST_TTL, sock, ttl);
- #else
- return APR_ENOTIMPL;
- #endif
- }
- APR_DECLARE(fspr_status_t) fspr_mcast_loopback(fspr_socket_t *sock,
- fspr_byte_t opt)
- {
- #if defined(IP_MULTICAST_LOOP) && defined(HAVE_STRUCT_IPMREQ)
- return do_mcast_opt(IP_MULTICAST_LOOP, sock, opt);
- #else
- return APR_ENOTIMPL;
- #endif
- }
- APR_DECLARE(fspr_status_t) fspr_mcast_interface(fspr_socket_t *sock,
- fspr_sockaddr_t *iface)
- {
- #if defined(IP_MULTICAST_IF) && defined(HAVE_STRUCT_IPMREQ)
- fspr_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,
- &idx, sizeof(idx)) == -1) {
- rv = errno;
- }
- }
- #endif
- else {
- rv = APR_ENOTIMPL;
- }
- return rv;
- #else
- return APR_ENOTIMPL;
- #endif
- }
|