Apache HTTPD
multicast.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
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"
22
23#ifdef HAVE_GETIFADDRS
24#include <net/if.h>
25#include <ifaddrs.h>
26#endif
27
28#ifdef HAVE_STRUCT_IPMREQ
29static void fill_mip_v4(struct ip_mreq *mip, apr_sockaddr_t *mcast,
31{
32 mip->imr_multiaddr = mcast->sa.sin.sin_addr;
33 if (iface == NULL) {
34 mip->imr_interface.s_addr = INADDR_ANY;
35 }
36 else {
37 mip->imr_interface = iface->sa.sin.sin_addr;
38 }
39}
40
41/* This function is only interested in AF_INET6 sockets, so a noop
42 * "return 0" implementation for the !APR_HAVE_IPV6 build is
43 * sufficient. */
44static unsigned int find_if_index(const apr_sockaddr_t *iface)
45{
46 unsigned int index = 0;
47#if defined(HAVE_GETIFADDRS) && APR_HAVE_IPV6
48 struct ifaddrs *ifp, *ifs;
49
58 if (getifaddrs(&ifs) != 0) {
59 return 0;
60 }
61
62 for (ifp = ifs; ifp; ifp = ifp->ifa_next) {
63 if (ifp->ifa_addr != NULL && ifp->ifa_addr->sa_family == AF_INET6) {
64 if (memcmp(&iface->sa.sin6.sin6_addr,
65 &((struct sockaddr_in6*)ifp->ifa_addr)->sin6_addr,
66 sizeof(iface->sa.sin6.sin6_addr)) == 0) {
67 index = if_nametoindex(ifp->ifa_name);
68 break;
69 }
70 }
71 }
72
74#endif
75 return index;
76}
77
78#if APR_HAVE_IPV6
79static void fill_mip_v6(struct ipv6_mreq *mip, const apr_sockaddr_t *mcast,
80 const apr_sockaddr_t *iface)
81{
82 memcpy(&mip->ipv6mr_multiaddr, mcast->ipaddr_ptr,
83 sizeof(mip->ipv6mr_multiaddr));
84
85 if (iface == NULL) {
86 mip->ipv6mr_interface = 0;
87 }
88 else {
89 mip->ipv6mr_interface = find_if_index(iface);
90 }
91}
92
93#endif
94
96{
98 return 1;
99 return 0;
100}
101
102#if APR_HAVE_IPV6
103static int sock_is_ipv6(apr_socket_t *sock)
104{
106 return 1;
107 return 0;
108}
109#endif
110
114{
115 struct ip_mreq mip4;
117#if APR_HAVE_IPV6
118 struct ipv6_mreq mip6;
119#endif
120#ifdef GROUP_FILTER_SIZE
121 struct group_source_req mip;
122 int ip_proto;
123#endif
124
125 if (source != NULL) {
126#ifdef GROUP_FILTER_SIZE
127 if (sock_is_ipv4(sock)) {
129 }
130#if APR_HAVE_IPV6
131 else if (sock_is_ipv6(sock)) {
133 }
134#endif
135 else {
136 return APR_ENOTIMPL;
137 }
138
139 if (type == IP_ADD_MEMBERSHIP)
141 else if (type == IP_DROP_MEMBERSHIP)
143 else
144 return APR_ENOTIMPL;
145
146 mip.gsr_interface = find_if_index(iface);
147 memcpy(&mip.gsr_group, mcast->ipaddr_ptr, sizeof(mip.gsr_group));
148 memcpy(&mip.gsr_source, source->ipaddr_ptr, sizeof(mip.gsr_source));
149
150 if (setsockopt(sock->socketdes, ip_proto, type, (const void *) &mip,
151 sizeof(mip)) == -1) {
152 rv = errno;
153 }
154#else
155 /* We do not support Source-Specific Multicast. */
156 return APR_ENOTIMPL;
157#endif
158 }
159 else {
160 if (sock_is_ipv4(sock)) {
161
163
165 (const void *) &mip4, sizeof(mip4)) == -1) {
166 rv = errno;
167 }
168 }
169#if APR_HAVE_IPV6 && defined(IPV6_JOIN_GROUP) && defined(IPV6_LEAVE_GROUP)
170 else if (sock_is_ipv6(sock)) {
171 if (type == IP_ADD_MEMBERSHIP) {
173 }
174 else if (type == IP_DROP_MEMBERSHIP) {
176 }
177 else {
178 return APR_ENOTIMPL;
179 }
180
182
184 (const void *) &mip6, sizeof(mip6)) == -1) {
185 rv = errno;
186 }
187 }
188#endif
189 else {
190 rv = APR_ENOTIMPL;
191 }
192 }
193 return rv;
194}
195
196/* Set the IP_MULTICAST_TTL or IP_MULTICAST_LOOP option, or IPv6
197 * equivalents, for the socket, to the given value. Note that this
198 * function *only works* for those particular option types. */
201{
203
204 if (sock_is_ipv4(sock)) {
205 /* For the IP_MULTICAST_* options, this must be a (char *)
206 * pointer. */
208 (const void *) &value, sizeof(value)) == -1) {
209 rv = errno;
210 }
211 }
212#if APR_HAVE_IPV6
213 else if (sock_is_ipv6(sock)) {
214 /* For the IPV6_* options, an (int *) pointer must be used. */
215 int ivalue = value;
216
217 if (type == IP_MULTICAST_TTL) {
219 }
220 else if (type == IP_MULTICAST_LOOP) {
222 }
223 else {
224 return APR_ENOTIMPL;
225 }
226
228 (const void *) &ivalue, sizeof(ivalue)) == -1) {
229 rv = errno;
230 }
231 }
232#endif
233 else {
234 rv = APR_ENOTIMPL;
235 }
236
237 return rv;
238}
239#endif
240
245{
246#if defined(IP_ADD_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ)
248#else
249 return APR_ENOTIMPL;
250#endif
251}
252
257{
258#if defined(IP_DROP_MEMBERSHIP) && defined(HAVE_STRUCT_IPMREQ)
260#else
261 return APR_ENOTIMPL;
262#endif
263}
264
266{
267#if defined(IP_MULTICAST_TTL) && defined(HAVE_STRUCT_IPMREQ)
269#else
270 return APR_ENOTIMPL;
271#endif
272}
273
276{
277#if defined(IP_MULTICAST_LOOP) && defined(HAVE_STRUCT_IPMREQ)
279#else
280 return APR_ENOTIMPL;
281#endif
282}
283
286{
287#if defined(IP_MULTICAST_IF) && defined(HAVE_STRUCT_IPMREQ)
289
290 if (sock_is_ipv4(sock)) {
292 (const void *) &iface->sa.sin.sin_addr,
293 sizeof(iface->sa.sin.sin_addr)) == -1) {
294 rv = errno;
295 }
296 }
297#if APR_HAVE_IPV6
298 else if (sock_is_ipv6(sock)) {
299 unsigned int idx = find_if_index(iface);
301 (const void *) &idx, sizeof(idx)) == -1) {
302 rv = errno;
303 }
304 }
305#endif
306 else {
307 rv = APR_ENOTIMPL;
308 }
309 return rv;
310#else
311 return APR_ENOTIMPL;
312#endif
313}
#define setsockopt
APR Network library.
APR Portability Routines.
APR Support functions.
#define APR_ENOTIMPL
Definition apr_errno.h:476
const void apr_status_t(*) apr_status_t(* APR_DECLARE)(void) apr_pool_pre_cleanup_register(apr_pool_t *p
Definition apr_pools.h:646
apr_size_t size
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
int type
apr_sockaddr_t apr_sockaddr_t apr_sockaddr_t * source
apr_sockaddr_t * join
apr_sockaddr_t apr_sockaddr_t * iface
apr_byte_t ttl
apr_sockaddr_t * addr
apr_int32_t opt
apr_socket_t * sock
#define APR_INET
return NULL
Definition mod_so.c:359
union apr_sockaddr_t::@55 sa
struct sockaddr_in sin
apr_int32_t family
apr_sockaddr_t * local_addr