]> git.saurik.com Git - apple/network_cmds.git/blob - mnc.tproj/mnc_multicast.c
network_cmds-543.200.16.tar.gz
[apple/network_cmds.git] / mnc.tproj / mnc_multicast.c
1 /*
2 * $Id: mnc_multicast.c,v 1.8 2004/09/22 19:14:23 colmmacc Exp $
3 *
4 * mnc_multicast.c -- Multicast NetCat
5 *
6 * Colm MacCarthaigh, <colm@apache.org>
7 *
8 * copyright (c) 2007, Colm MacCarthaigh.
9 * Copyright (c) 2004 - 2006, HEAnet Ltd.
10 *
11 * This software is an open source.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * Redistributions of source code must retain the above copyright notice,
18 * this list of conditions and the following disclaimer.
19 *
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.
23 *
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.
27 *
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.
39 *
40 */
41
42 #ifndef WINDOWS
43
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <net/if.h>
49 #include <string.h>
50 #include <netdb.h>
51 #include <errno.h>
52
53 #else
54
55 #include <sys/types.h>
56 #include <winsock2.h>
57 #include <ws2tcpip.h>
58 #include <stdlib.h>
59
60 #endif
61
62 #include "mnc.h"
63
64 #ifndef MCAST_JOIN_GROUP
65
66 #ifdef IP_ADD_SOURCE_MEMBERSHIP
67 int mnc_join_ipv4_ssm(int socket, struct addrinfo * group,
68 struct addrinfo * source, char * iface)
69 {
70 struct ip_mreq_source multicast_request;
71
72 if (iface != NULL)
73 {
74 /* See if interface is a literal IPv4 address */
75 if ((multicast_request.imr_interface.s_addr =
76 inet_addr(iface)) == INADDR_NONE)
77 {
78 mnc_warning("Invalid interface address\n");
79 return -1;
80 }
81 }
82 else
83 {
84 /* set the interface to the default */
85 multicast_request.imr_interface.s_addr = htonl(INADDR_ANY);
86 }
87
88 multicast_request.imr_multiaddr.s_addr =
89 ((struct sockaddr_in *)group->ai_addr)->sin_addr.s_addr;
90
91 multicast_request.imr_sourceaddr.s_addr =
92 ((struct sockaddr_in *)source->ai_addr)->sin_addr.s_addr;
93
94 /* Set the socket option */
95 if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
96 (char *) &multicast_request,
97 sizeof(multicast_request)) != 0)
98 {
99 mnc_warning("Could not join the multicast group: %s\n",
100 strerror(errno));
101
102 return -1;
103 }
104
105 return 0;
106 }
107 #else
108
109 int mnc_join_ipv4_ssm(int socket, struct addrinfo * group,
110 struct addrinfo * source, char * iface)
111 {
112 mnc_warning("Sorry, No support for IPv4 source-specific multicast in this build\n");
113
114 return -1;
115 }
116 #endif
117
118 int mnc_join_ipv6_ssm(int socket, struct addrinfo * group,
119 struct addrinfo * source, char * iface)
120 {
121 mnc_warning("Sorry, No support for IPv6 source-specific multicast in this build\n");
122
123 return -1;
124 }
125 #else /* if MCAST_JOIN_GROUP .. */
126
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))
129
130 int mnc_join_ip_asm(int socket, struct addrinfo * group, char * iface)
131 {
132 struct group_req multicast_request;
133 int ip_proto;
134
135 if (group->ai_family == AF_INET6)
136 {
137 ip_proto = IPPROTO_IPV6;
138 }
139 else
140 {
141 ip_proto = IPPROTO_IP;
142 }
143
144 if (iface != NULL)
145 {
146 if ((multicast_request.gr_interface = if_nametoindex(iface))
147 == 0)
148 {
149 mnc_warning("Ignoring unknown interface: %s\n", iface);
150 }
151 }
152 else
153 {
154 multicast_request.gr_interface = 0;
155 }
156
157 memcpy(&multicast_request.gr_group, group->ai_addr, group->ai_addrlen);
158
159 /* Set the socket option */
160 if (setsockopt(socket, ip_proto, MCAST_JOIN_GROUP, (char *)
161 &multicast_request, sizeof(multicast_request)) != 0)
162 {
163 mnc_warning("Could not join the multicast group: %s\n",
164 strerror(errno));
165
166 return -1;
167 }
168
169 return 0;
170 }
171
172 #endif /* MCAST_JOIN_GROUP */
173
174 #ifndef MCAST_JOIN_SOURCE_GROUP
175 int mnc_join_ipv4_asm(int socket, struct addrinfo * group, char * iface)
176 {
177 struct ip_mreq multicast_request;
178
179 if (iface != NULL)
180 {
181 /* See if interface is a literal IPv4 address */
182 if ((multicast_request.imr_interface.s_addr =
183 inet_addr(iface)) == INADDR_NONE)
184 {
185 mnc_warning("Invalid interface address\n");
186 return -1;
187 }
188 }
189 else
190 {
191 /* Set the interface to the default */
192 multicast_request.imr_interface.s_addr = htonl(INADDR_ANY);
193 }
194
195 multicast_request.imr_multiaddr.s_addr =
196 ((struct sockaddr_in *)group->ai_addr)->sin_addr.s_addr;
197
198 /* Set the socket option */
199 if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
200 (char *) &multicast_request,
201 sizeof(multicast_request)) != 0)
202 {
203 mnc_warning("Could not join the multicast group: %s\n",
204 strerror(errno));
205
206 return -1;
207 }
208
209 return 0;
210 }
211
212 int mnc_join_ipv6_asm(int socket, struct addrinfo * group, char * iface)
213 {
214 mnc_warning("Sorry, No support for IPv6 any-source multicast in this build\n");
215
216 return -1;
217 }
218 #else /* if MCAST_JOIN_SOURCE_GROUP ... */
219
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))
222
223 int mnc_join_ip_ssm(int socket, struct addrinfo * group,
224 struct addrinfo * source,
225 char * iface)
226 {
227 struct group_source_req multicast_request;
228 int ip_proto;
229
230 if (group->ai_family == AF_INET6)
231 {
232 ip_proto = IPPROTO_IPV6;
233 }
234 else
235 {
236 ip_proto = IPPROTO_IP;
237 }
238
239 if (iface != NULL)
240 {
241 if ((multicast_request.gsr_interface = if_nametoindex(iface))
242 == 0)
243 {
244 mnc_warning("Ignoring unknown interface: %s\n", iface);
245 }
246 }
247 else
248 {
249 multicast_request.gsr_interface = 0;
250 }
251
252 memcpy(&multicast_request.gsr_group, group->ai_addr, group->ai_addrlen);
253 memcpy(&multicast_request.gsr_source, source->ai_addr,
254 source->ai_addrlen);
255
256 /* Set the socket option */
257 if (setsockopt(socket, ip_proto, MCAST_JOIN_SOURCE_GROUP,
258 (char *) &multicast_request,
259 sizeof(multicast_request)) != 0)
260 {
261 mnc_warning("Could not join the multicast group: %s\n",
262 strerror(errno));
263
264 return -1;
265 }
266
267 return 0;
268 }
269 #endif /* MCAST_JOIN_SOURCE_GROUP */
270
271 int multicast_setup_listen(int socket, struct addrinfo * group,
272 struct addrinfo * source, char * iface)
273 {
274 size_t rcvbuf;
275
276 #ifndef WINDOWS
277 /* bind to the group address before anything */
278 if (bind(socket, group->ai_addr, group->ai_addrlen) != 0)
279 {
280 mnc_warning("Could not bind to group-id\n");
281 return -1;
282 }
283 #else
284 if (group->ai_family == AF_INET)
285 {
286 struct sockaddr_in sin;
287
288 sin.sin_family = group->ai_family;
289 sin.sin_port = group->ai_port;
290 sin.sin_addr = INADDR_ANY;
291
292 if (bind(socket, (struct sockaddr *) sin,
293 sizeof(sin)) != 0)
294 {
295 mnc_warning("Could not bind to ::\n");
296 return -1;
297 }
298 }
299 else if (group->ai_family == AF_INET6)
300 {
301 struct sockaddr_in6 sin6;
302
303 sin6.sin6_family = group->ai_family;
304 sin6.sin6_port = group->ai_port;
305 sin6.sin6_addr = in6addr_any;
306
307 if (bind(socket, (struct sockaddr *) sin6,
308 sizeof(sin6)) != 0)
309 {
310 mnc_warning("Could not bind to ::\n");
311 return -1;
312 }
313 }
314 #endif
315
316 /* Set a receive buffer size of 64k */
317 rcvbuf = 1 << 15;
318 if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
319 sizeof(rcvbuf)) < 0) {
320 mnc_warning("Could not set receive buffer to 64k\n");
321 }
322
323 if (source != NULL)
324 {
325 if (group->ai_family == AF_INET6)
326 {
327 /* Use whatever IPv6 API is appropriate */
328 return
329 mnc_join_ipv6_ssm(socket, group, source, iface);
330 }
331 else if (group->ai_family == AF_INET)
332 {
333 /* Use the fully portable IPv4 API */
334 return
335 mnc_join_ipv4_ssm(socket, group, source, iface);
336 }
337 else
338 {
339 mnc_warning("Only IPv4 and IPv6 are supported\n");
340 return -1;
341 }
342 }
343 else
344 {
345 if (group->ai_family == AF_INET6)
346 {
347 /* Use the fully portable IPv4 API */
348 return
349 mnc_join_ipv6_asm(socket, group, iface);
350 }
351 else if (group->ai_family == AF_INET)
352 {
353 /* Use the fully portable IPv4 API */
354 return
355 mnc_join_ipv4_asm(socket, group, iface);
356 }
357 else
358 {
359 mnc_warning("Only IPv4 and IPv6 are supported\n");
360 return -1;
361 }
362 }
363
364 /* We should never get here */
365 return -1;
366 }
367
368
369 int multicast_setup_send(int socket, struct addrinfo * group,
370 struct addrinfo * source)
371 {
372 int ttl = 255;
373
374 if (source != NULL)
375 {
376 /* bind to the address before anything */
377 if (bind(socket, source->ai_addr, source->ai_addrlen) != 0)
378 {
379 mnc_warning("Could not bind to source-address\n");
380 return -1;
381 }
382 }
383
384 if (group->ai_family == AF_INET)
385 {
386 if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)
387 &ttl, sizeof(ttl)) != 0)
388 {
389 mnc_warning("Could not increase the TTL\n");
390 return -1;
391 }
392 }
393 else if (group->ai_family == AF_INET6)
394 {
395 if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
396 (char *) &ttl, sizeof(ttl)) != 0)
397 {
398 mnc_warning("Could not increase the hop-count\n");
399 return -1;
400 }
401 }
402
403 return 0;
404 }