1
/* Copyright 2004-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
#include "apr_arch_networkio.h"
18
#include "apr_network_io.h"
19
#include "apr_support.h"
20
#include "apr_portable.h"
21
#include "apr_arch_inherit.h"
23
#ifdef HAVE_GETIFADDRS
28
#ifdef HAVE_STRUCT_IPMREQ
29
/* Only UDP and Raw Sockets can be used for Multicast */
30
static apr_status_t mcast_check_type(apr_socket_t *sock)
35
rv = apr_socket_type_get(sock, &type);
37
if (rv != APR_SUCCESS) {
40
else if (type == SOCK_DGRAM || type == SOCK_RAW) {
48
static void fill_mip_v4(struct ip_mreq *mip, apr_sockaddr_t *mcast,
49
apr_sockaddr_t *iface)
51
mip->imr_multiaddr = mcast->sa.sin.sin_addr;
53
mip->imr_interface.s_addr = INADDR_ANY;
56
mip->imr_interface = iface->sa.sin.sin_addr;
61
static unsigned int find_if_index(const apr_sockaddr_t *iface)
63
unsigned int index = 0;
64
#ifdef HAVE_GETIFADDRS
65
struct ifaddrs *ifp, *ifs;
68
* TODO: getifaddrs is only portable to *BSD and OS X. Using ioctl
69
* and SIOCGIFCONF is needed for Linux/Solaris support.
71
* There is a wrapper that takes the messy ioctl interface into
72
* getifaddrs. The license is acceptable, but, It is a fairly large
75
if (getifaddrs(&ifs) != 0) {
79
for (ifp = ifs; ifp; ifp = ifp->ifa_next) {
80
if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family == AF_INET6) {
81
if (memcmp(&iface->sa.sin6.sin6_addr,
82
&ifp->ifa_addr->sa_data[0],
83
sizeof(iface->sa.sin6.sin6_addr)) == 0) {
84
index = if_nametoindex(ifp->ifa_name);
95
static void fill_mip_v6(struct ipv6_mreq *mip, const apr_sockaddr_t *mcast,
96
const apr_sockaddr_t *iface)
98
memcpy(&mip->ipv6mr_multiaddr, mcast->ipaddr_ptr,
99
sizeof(mip->ipv6mr_multiaddr));
102
mip->ipv6mr_interface = 0;
105
mip->ipv6mr_interface = find_if_index(iface);
111
static int sock_is_ipv4(apr_socket_t *sock)
113
if (sock->local_addr->family == APR_INET)
119
static int sock_is_ipv6(apr_socket_t *sock)
121
if (sock->local_addr->family == APR_INET6)
127
static apr_status_t do_mcast(int type, apr_socket_t *sock,
128
apr_sockaddr_t *mcast, apr_sockaddr_t *iface,
129
apr_sockaddr_t *source)
132
apr_status_t rv = APR_SUCCESS;
134
struct ipv6_mreq mip6;
136
#if MCAST_JOIN_SOURCE_GROUP
137
struct group_source_req mip;
141
rv = mcast_check_type(sock);
143
if (rv != APR_SUCCESS) {
147
if (source != NULL) {
148
#if MCAST_JOIN_SOURCE_GROUP
149
if (sock_is_ipv4(sock)) {
150
ip_proto = IPPROTO_IP;
153
else if (sock_is_ipv6(sock)) {
154
ip_proto = IPPROTO_IPV6;
161
if (type == IP_ADD_MEMBERSHIP)
162
type = MCAST_JOIN_SOURCE_GROUP;
163
else if (type == IP_DROP_MEMBERSHIP)
164
type = MCAST_LEAVE_SOURCE_GROUP;
168
mip.gsr_interface = find_if_index(iface);
169
memcpy(&mip.gsr_group, mcast->ipaddr_ptr, sizeof(mip.gsr_group));
170
memcpy(&mip.gsr_source, source->ipaddr_ptr, sizeof(mip.gsr_source));
172
if (setsockopt(sock->socketdes, ip_proto, type, (const void *) &mip,
173
sizeof(mip)) == -1) {
177
/* We do not support Source-Specific Multicast. */
182
if (sock_is_ipv4(sock)) {
184
fill_mip_v4(&mip4, mcast, iface);
186
if (setsockopt(sock->socketdes, IPPROTO_IP, type,
187
(const void *) &mip4, sizeof(mip4)) == -1) {
191
#if APR_HAVE_IPV6 && defined(IPV6_JOIN_GROUP) && defined(IPV6_LEAVE_GROUP)
192
else if (sock_is_ipv6(sock)) {
193
if (type == IP_ADD_MEMBERSHIP) {
194
type = IPV6_JOIN_GROUP;
196
else if (type == IP_DROP_MEMBERSHIP) {
197
type = IPV6_LEAVE_GROUP;
203
fill_mip_v6(&mip6, mcast, iface);
205
if (setsockopt(sock->socketdes, IPPROTO_IPV6, type,
206
&mip6, sizeof(mip6)) == -1) {
218
static apr_status_t do_mcast_opt(int type, apr_socket_t *sock,
221
apr_status_t rv = APR_SUCCESS;
223
rv = mcast_check_type(sock);
225
if (rv != APR_SUCCESS) {
229
if (sock_is_ipv4(sock)) {
230
if (setsockopt(sock->socketdes, IPPROTO_IP, type,
231
(const void *) &value, sizeof(value)) == -1) {
236
else if (sock_is_ipv6(sock) && type == IP_MULTICAST_LOOP) {
237
unsigned int loopopt = value;
238
type = IPV6_MULTICAST_LOOP;
239
if (setsockopt(sock->socketdes, IPPROTO_IPV6, type,
240
&loopopt, sizeof(loopopt)) == -1) {
244
else if (sock_is_ipv6(sock)) {
245
if (type == IP_MULTICAST_TTL) {
246
type = IPV6_MULTICAST_HOPS;
252
if (setsockopt(sock->socketdes, IPPROTO_IPV6, type,
253
&value, sizeof(value)) == -1) {
266
APR_DECLARE(apr_status_t) apr_mcast_join(apr_socket_t *sock,
267
apr_sockaddr_t *join,
268
apr_sockaddr_t *iface,
269
apr_sockaddr_t *source)
271
#if defined(IP_ADD_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ)
272
return do_mcast(IP_ADD_MEMBERSHIP, sock, join, iface, source);
278
APR_DECLARE(apr_status_t) apr_mcast_leave(apr_socket_t *sock,
279
apr_sockaddr_t *addr,
280
apr_sockaddr_t *iface,
281
apr_sockaddr_t *source)
283
#if defined(IP_DROP_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ)
284
return do_mcast(IP_DROP_MEMBERSHIP, sock, addr, iface, source);
290
APR_DECLARE(apr_status_t) apr_mcast_hops(apr_socket_t *sock, apr_byte_t ttl)
292
#if defined(IP_MULTICAST_TTL) && defined(HAVE_STRUCT_IPMREQ)
293
return do_mcast_opt(IP_MULTICAST_TTL, sock, ttl);
299
APR_DECLARE(apr_status_t) apr_mcast_loopback(apr_socket_t *sock,
302
#if defined(IP_MULTICAST_LOOP) && defined(HAVE_STRUCT_IPMREQ)
303
return do_mcast_opt(IP_MULTICAST_LOOP, sock, opt);
309
APR_DECLARE(apr_status_t) apr_mcast_interface(apr_socket_t *sock,
310
apr_sockaddr_t *iface)
312
#if defined(IP_MULTICAST_IF) && defined(HAVE_STRUCT_IPMREQ)
313
apr_status_t rv = APR_SUCCESS;
315
if (sock_is_ipv4(sock)) {
316
if (setsockopt(sock->socketdes, IPPROTO_IP, IP_MULTICAST_IF,
317
(const void *) &iface->sa.sin.sin_addr,
318
sizeof(iface->sa.sin.sin_addr)) == -1) {
323
else if (sock_is_ipv6(sock)) {
324
unsigned int idx = find_if_index(iface);
325
if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_MULTICAST_IF,
326
&idx, sizeof(idx)) == -1) {