2 * $Id: mnc_multicast.c,v 1.8 2004/09/22 19:14:23 colmmacc Exp $
4 * mnc_multicast.c -- Multicast NetCat
6 * Colm MacCarthaigh, <colm@apache.org>
8 * copyright (c) 2007, Colm MacCarthaigh.
9 * Copyright (c) 2004 - 2006, HEAnet Ltd.
11 * This software is an open source.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
17 * Redistributions of source code must retain the above copyright notice,
18 * this list of conditions and the following disclaimer.
20 * Redistributions in binary form must reproduce the above copyright notice,
21 * this list of conditions and the following disclaimer in the documentation
22 * and/or other materials provided with the distribution.
24 * Neither the name of the HEAnet Ltd. nor the names of its contributors may
25 * be used to endorse or promote products derived from this software without
26 * specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
55 #include <sys/types.h>
64 #ifndef MCAST_JOIN_GROUP
66 #ifdef IP_ADD_SOURCE_MEMBERSHIP
67 int mnc_join_ipv4_ssm(int socket
, struct addrinfo
* group
,
68 struct addrinfo
* source
, char * iface
)
70 struct ip_mreq_source multicast_request
;
74 /* See if interface is a literal IPv4 address */
75 if ((multicast_request
.imr_interface
.s_addr
=
76 inet_addr(iface
)) == INADDR_NONE
)
78 mnc_warning("Invalid interface address\n");
84 /* set the interface to the default */
85 multicast_request
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
88 multicast_request
.imr_multiaddr
.s_addr
=
89 ((struct sockaddr_in
*)group
->ai_addr
)->sin_addr
.s_addr
;
91 multicast_request
.imr_sourceaddr
.s_addr
=
92 ((struct sockaddr_in
*)source
->ai_addr
)->sin_addr
.s_addr
;
94 /* Set the socket option */
95 if (setsockopt(socket
, IPPROTO_IP
, IP_ADD_SOURCE_MEMBERSHIP
,
96 (char *) &multicast_request
,
97 sizeof(multicast_request
)) != 0)
99 mnc_warning("Could not join the multicast group: %s\n",
109 int mnc_join_ipv4_ssm(int socket
, struct addrinfo
* group
,
110 struct addrinfo
* source
, char * iface
)
112 mnc_warning("Sorry, No support for IPv4 source-specific multicast in this build\n");
118 int mnc_join_ipv6_ssm(int socket
, struct addrinfo
* group
,
119 struct addrinfo
* source
, char * iface
)
121 mnc_warning("Sorry, No support for IPv6 source-specific multicast in this build\n");
125 #else /* if MCAST_JOIN_GROUP .. */
127 #define mnc_join_ipv6_asm(a, b, c) mnc_join_ip_asm((a), (b), (c))
128 #define mnc_join_ipv4_asm(a, b, c) mnc_join_ip_asm((a), (b), (c))
130 int mnc_join_ip_asm(int socket
, struct addrinfo
* group
, char * iface
)
132 struct group_req multicast_request
;
135 if (group
->ai_family
== AF_INET6
)
137 ip_proto
= IPPROTO_IPV6
;
141 ip_proto
= IPPROTO_IP
;
146 if ((multicast_request
.gr_interface
= if_nametoindex(iface
))
149 mnc_warning("Ignoring unknown interface: %s\n", iface
);
154 multicast_request
.gr_interface
= 0;
157 memcpy(&multicast_request
.gr_group
, group
->ai_addr
, group
->ai_addrlen
);
159 /* Set the socket option */
160 if (setsockopt(socket
, ip_proto
, MCAST_JOIN_GROUP
, (char *)
161 &multicast_request
, sizeof(multicast_request
)) != 0)
163 mnc_warning("Could not join the multicast group: %s\n",
172 #endif /* MCAST_JOIN_GROUP */
174 #ifndef MCAST_JOIN_SOURCE_GROUP
175 int mnc_join_ipv4_asm(int socket
, struct addrinfo
* group
, char * iface
)
177 struct ip_mreq multicast_request
;
181 /* See if interface is a literal IPv4 address */
182 if ((multicast_request
.imr_interface
.s_addr
=
183 inet_addr(iface
)) == INADDR_NONE
)
185 mnc_warning("Invalid interface address\n");
191 /* Set the interface to the default */
192 multicast_request
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
195 multicast_request
.imr_multiaddr
.s_addr
=
196 ((struct sockaddr_in
*)group
->ai_addr
)->sin_addr
.s_addr
;
198 /* Set the socket option */
199 if (setsockopt(socket
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
200 (char *) &multicast_request
,
201 sizeof(multicast_request
)) != 0)
203 mnc_warning("Could not join the multicast group: %s\n",
212 int mnc_join_ipv6_asm(int socket
, struct addrinfo
* group
, char * iface
)
214 mnc_warning("Sorry, No support for IPv6 any-source multicast in this build\n");
218 #else /* if MCAST_JOIN_SOURCE_GROUP ... */
220 #define mnc_join_ipv4_ssm(a, b, c, d) mnc_join_ip_ssm((a), (b), (c), (d))
221 #define mnc_join_ipv6_ssm(a, b, c, d) mnc_join_ip_ssm((a), (b), (c), (d))
223 int mnc_join_ip_ssm(int socket
, struct addrinfo
* group
,
224 struct addrinfo
* source
,
227 struct group_source_req multicast_request
;
230 if (group
->ai_family
== AF_INET6
)
232 ip_proto
= IPPROTO_IPV6
;
236 ip_proto
= IPPROTO_IP
;
241 if ((multicast_request
.gsr_interface
= if_nametoindex(iface
))
244 mnc_warning("Ignoring unknown interface: %s\n", iface
);
249 multicast_request
.gsr_interface
= 0;
252 memcpy(&multicast_request
.gsr_group
, group
->ai_addr
, group
->ai_addrlen
);
253 memcpy(&multicast_request
.gsr_source
, source
->ai_addr
,
256 /* Set the socket option */
257 if (setsockopt(socket
, ip_proto
, MCAST_JOIN_SOURCE_GROUP
,
258 (char *) &multicast_request
,
259 sizeof(multicast_request
)) != 0)
261 mnc_warning("Could not join the multicast group: %s\n",
269 #endif /* MCAST_JOIN_SOURCE_GROUP */
271 int multicast_setup_listen(int socket
, struct addrinfo
* group
,
272 struct addrinfo
* source
, char * iface
)
277 /* bind to the group address before anything */
278 if (bind(socket
, group
->ai_addr
, group
->ai_addrlen
) != 0)
280 mnc_warning("Could not bind to group-id\n");
284 if (group
->ai_family
== AF_INET
)
286 struct sockaddr_in sin
;
288 sin
.sin_family
= group
->ai_family
;
289 sin
.sin_port
= group
->ai_port
;
290 sin
.sin_addr
= INADDR_ANY
;
292 if (bind(socket
, (struct sockaddr
*) sin
,
295 mnc_warning("Could not bind to ::\n");
299 else if (group
->ai_family
== AF_INET6
)
301 struct sockaddr_in6 sin6
;
303 sin6
.sin6_family
= group
->ai_family
;
304 sin6
.sin6_port
= group
->ai_port
;
305 sin6
.sin6_addr
= in6addr_any
;
307 if (bind(socket
, (struct sockaddr
*) sin6
,
310 mnc_warning("Could not bind to ::\n");
316 /* Set a receive buffer size of 64k */
318 if (setsockopt(socket
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
,
319 sizeof(rcvbuf
)) < 0) {
320 mnc_warning("Could not set receive buffer to 64k\n");
325 if (group
->ai_family
== AF_INET6
)
327 /* Use whatever IPv6 API is appropriate */
329 mnc_join_ipv6_ssm(socket
, group
, source
, iface
);
331 else if (group
->ai_family
== AF_INET
)
333 /* Use the fully portable IPv4 API */
335 mnc_join_ipv4_ssm(socket
, group
, source
, iface
);
339 mnc_warning("Only IPv4 and IPv6 are supported\n");
345 if (group
->ai_family
== AF_INET6
)
347 /* Use the fully portable IPv4 API */
349 mnc_join_ipv6_asm(socket
, group
, iface
);
351 else if (group
->ai_family
== AF_INET
)
353 /* Use the fully portable IPv4 API */
355 mnc_join_ipv4_asm(socket
, group
, iface
);
359 mnc_warning("Only IPv4 and IPv6 are supported\n");
364 /* We should never get here */
369 int multicast_setup_send(int socket
, struct addrinfo
* group
,
370 struct addrinfo
* source
)
376 /* bind to the address before anything */
377 if (bind(socket
, source
->ai_addr
, source
->ai_addrlen
) != 0)
379 mnc_warning("Could not bind to source-address\n");
384 if (group
->ai_family
== AF_INET
)
386 if (setsockopt(socket
, IPPROTO_IP
, IP_MULTICAST_TTL
, (char *)
387 &ttl
, sizeof(ttl
)) != 0)
389 mnc_warning("Could not increase the TTL\n");
393 else if (group
->ai_family
== AF_INET6
)
395 if (setsockopt(socket
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
396 (char *) &ttl
, sizeof(ttl
)) != 0)
398 mnc_warning("Could not increase the hop-count\n");