1 /* GNet - Networking library
2 * Copyright (C) 2000, 2002-3 David Helder
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 #include "gnet-private.h"
21 #include "mcast.h"
22
23 #define GNET_UDP_SOCKET(s) ((GUdpSocket*)(s))
24 #define GNET_IS_MCAST_SOCKET(s) ((s)&&(GNET_UDP_SOCKET(s)->type == GNET_MCAST_SOCKET_TYPE_COOKIE))
25
26 /**
27 * gnet_mcast_socket_new
28 *
29 * Creates a #GMcastSocket bound to all interfaces and an arbitrary
30 * port.
31 *
32 * Returns: a new #GMcastSocket; NULL on error.
33 *
34 **/
35 GMcastSocket*
gnet_mcast_socket_new(void)36 gnet_mcast_socket_new (void)
37 {
38 return gnet_mcast_socket_new_full (NULL, 0);
39 }
40
41
42
43 /**
44 * gnet_mcast_socket_new_with_port
45 * @port: port to bind to
46 *
47 * Creates a #GMcastSocket bound to all interfaces and port @port.
48 * If @port is 0, an arbitrary port will be used. Use this
49 * constructor if you know the port of the group you will join. Most
50 * applications will use this constructor.
51 *
52 * Returns: a new #GMcastSocket; NULL on error.
53 *
54 **/
55 GMcastSocket*
gnet_mcast_socket_new_with_port(gint port)56 gnet_mcast_socket_new_with_port (gint port)
57 {
58 return gnet_mcast_socket_new_full (NULL, port);
59 }
60
61
62
63 /**
64 * gnet_mcast_socket_new_full
65 * @iface: interface to bind to (NULL for all interfaces)
66 * @port: port to bind to (0 for an arbitrary port)
67 *
68 * Creates a #GMcastSocket bound to interface @iface and port @port.
69 * If @iface is NULL, all interfaces will be used. If @port is 0, an
70 * arbitrary port will be used. To receive packets from this group,
71 * call gnet_mcast_socket_join_group() next. Loopback is disabled by
72 * default.
73 *
74 * Returns: a new #GMcastSocket; NULL on error.
75 *
76 **/
77 GMcastSocket*
gnet_mcast_socket_new_full(const GInetAddr * iface,gint port)78 gnet_mcast_socket_new_full (const GInetAddr* iface, gint port)
79 {
80 struct sockaddr_storage sa;
81 GMcastSocket* ms;
82 GUdpSocket* us;
83 const int on = 1;
84 int sockfd;
85
86 /* Create sockfd and address */
87 sockfd = _gnet_create_listen_socket (SOCK_DGRAM, iface, port, &sa);
88 if (!GNET_IS_SOCKET_VALID(sockfd))
89 {
90 g_warning ("socket() failed");
91 return NULL;
92 }
93
94 /* Set socket option to share the UDP port */
95 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
96 (void*) &on, sizeof(on)) != 0)
97 g_warning("Can't reuse mcast socket\n");
98
99 /* Bind to the socket to some local address and port */
100 if (bind(sockfd, &GNET_SOCKADDR_SA(sa), GNET_SOCKADDR_LEN(sa)) != 0)
101 {
102 GNET_CLOSE_SOCKET (sockfd);
103 return NULL;
104 }
105
106 /* Create socket */
107 ms = g_new0(GMcastSocket, 1);
108 us = (GUdpSocket *) ms;
109 us->type = GNET_MCAST_SOCKET_TYPE_COOKIE;
110 us->sockfd = sockfd;
111 us->sa = sa;
112 us->ref_count = 1;
113
114 gnet_mcast_socket_set_loopback (ms, FALSE);
115
116 return ms;
117 }
118
119
120
121 /**
122 * gnet_mcast_socket_delete:
123 * @socket: a #GMcastSocket, or NULL
124 *
125 * Deletes a #GMcastSocket. Does nothing if @socket is NULL.
126 *
127 **/
128 void
gnet_mcast_socket_delete(GMcastSocket * socket)129 gnet_mcast_socket_delete (GMcastSocket* socket)
130 {
131 g_return_if_fail (socket == NULL || GNET_IS_MCAST_SOCKET (socket));
132
133 gnet_udp_socket_unref ((GUdpSocket *) socket);
134 }
135
136
137
138 /**
139 * gnet_mcast_socket_ref
140 * @socket: a #GMcastSocket
141 *
142 * Adds a reference to a #GMcastSocket.
143 *
144 **/
145 void
gnet_mcast_socket_ref(GMcastSocket * socket)146 gnet_mcast_socket_ref (GMcastSocket* socket)
147 {
148 g_return_if_fail (socket != NULL);
149 g_return_if_fail (GNET_IS_MCAST_SOCKET (socket));
150
151 gnet_udp_socket_ref ((GUdpSocket *) socket);
152 }
153
154
155 /**
156 * gnet_mcast_socket_unref
157 * @socket: a #GMcastSocket
158 *
159 * Removes a reference from a #GMcastSocket. A #GMcastSocket is
160 * deleted when the reference count reaches 0.
161 *
162 **/
163 void
gnet_mcast_socket_unref(GMcastSocket * socket)164 gnet_mcast_socket_unref (GMcastSocket* socket)
165 {
166 g_return_if_fail (socket != NULL);
167 g_return_if_fail (GNET_IS_MCAST_SOCKET (socket));
168
169 gnet_udp_socket_unref ((GUdpSocket *) socket);
170 }
171
172
173
174 /**
175 * gnet_mcast_socket_get_io_channel:
176 * @socket: a #GMcastSocket
177 *
178 * Gets the #GIOChannel of a #GMcastSocket.
179 *
180 * Use the channel with g_io_add_watch() to check if the socket is
181 * readable or writable. If the channel is readable, call
182 * gnet_mcast_socket_receive() to receive a packet. If the channel
183 * is writable, call gnet_mcast_socket_send() to send a packet. This
184 * is not a normal giochannel - do not read from or write to it.
185 *
186 * Every #GMcastSocket has one and only one #GIOChannel. If you ref
187 * the channel, then you must unref it eventually. Do not close the
188 * channel. The channel is closed by GNet when the socket is
189 * deleted.
190 *
191 * Returns: a #GIOChannel.
192 *
193 **/
194 GIOChannel*
gnet_mcast_socket_get_io_channel(GMcastSocket * socket)195 gnet_mcast_socket_get_io_channel (GMcastSocket* socket)
196 {
197 g_return_val_if_fail (socket != NULL, NULL);
198 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), NULL);
199
200 return gnet_udp_socket_get_io_channel((GUdpSocket*) socket);
201 }
202
203
204 /**
205 * gnet_mcast_socket_get_local_inetaddr
206 * @socket: a #GMcastSocket
207 *
208 * Gets the local host's address from a #GMcastSocket.
209 *
210 * Returns: a #GInetAddr.
211 *
212 **/
213 GInetAddr*
gnet_mcast_socket_get_local_inetaddr(const GMcastSocket * socket)214 gnet_mcast_socket_get_local_inetaddr (const GMcastSocket* socket)
215 {
216 g_return_val_if_fail (socket != NULL, NULL);
217 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), NULL);
218
219 return gnet_udp_socket_get_local_inetaddr((GUdpSocket*) socket);
220 }
221
222
223
224 /**
225 * gnet_mcast_socket_join_group
226 * @socket: a #GMcastSocket
227 * @inetaddr: address of the group
228 *
229 * Joins a multicast group. Join only one group per socket.
230 *
231 * Returns: 0 on success.
232 *
233 **/
234 gint
gnet_mcast_socket_join_group(GMcastSocket * socket,const GInetAddr * inetaddr)235 gnet_mcast_socket_join_group (GMcastSocket* socket,
236 const GInetAddr* inetaddr)
237 {
238 GUdpSocket *udpsocket;
239 gint rv = -1;
240
241 g_return_val_if_fail (socket != NULL, -1);
242 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), -1);
243
244 udpsocket = GNET_UDP_SOCKET (socket);
245
246 if (GNET_INETADDR_FAMILY(inetaddr) == AF_INET)
247 {
248 struct ip_mreq mreq;
249
250 /* Create the multicast request structure */
251 memcpy(&mreq.imr_multiaddr, GNET_INETADDR_ADDRP(inetaddr),
252 sizeof(mreq.imr_multiaddr));
253 mreq.imr_interface.s_addr = g_htonl(INADDR_ANY);
254
255 /* Join the group */
256 rv = setsockopt (udpsocket->sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
257 (void*) &mreq, sizeof(mreq));
258 }
259 #ifdef HAVE_IPV6
260 else if (GNET_INETADDR_FAMILY(inetaddr) == AF_INET6)
261 {
262 struct ipv6_mreq mreq;
263
264 /* Create the multicast request structure */
265 memcpy(&mreq.ipv6mr_multiaddr, GNET_INETADDR_ADDRP(inetaddr),
266 sizeof(mreq.ipv6mr_multiaddr));
267 mreq.ipv6mr_interface = 0;
268
269 /* Join the group */
270 rv = setsockopt (udpsocket->sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
271 (void*) &mreq, sizeof(mreq));
272 }
273 #endif
274 else
275 g_assert_not_reached ();
276
277 return rv;
278 }
279
280
281 /**
282 * gnet_mcast_socket_leave_group
283 * @socket: a #GMcastSocket
284 * @inetaddr: address of the group
285 *
286 * Leaves a mulitcast group.
287 *
288 * Returns: 0 on success.
289 *
290 **/
291 gint
gnet_mcast_socket_leave_group(GMcastSocket * socket,const GInetAddr * inetaddr)292 gnet_mcast_socket_leave_group (GMcastSocket* socket,
293 const GInetAddr* inetaddr)
294 {
295 GUdpSocket *udpsocket;
296
297 gint rv = -1;
298
299 g_return_val_if_fail (socket != NULL, -1);
300 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), -1);
301
302 udpsocket = GNET_UDP_SOCKET (socket);
303
304 if (GNET_INETADDR_FAMILY(inetaddr) == AF_INET)
305 {
306 struct ip_mreq mreq;
307
308 /* Create the multicast request structure */
309 memcpy(&mreq.imr_multiaddr, GNET_INETADDR_ADDRP(inetaddr),
310 sizeof(mreq.imr_multiaddr));
311 mreq.imr_interface.s_addr = g_htonl(INADDR_ANY);
312
313 /* Join the group */
314 rv = setsockopt (udpsocket->sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
315 (void*) &mreq, sizeof(mreq));
316 }
317 #ifdef HAVE_IPV6
318 else if (GNET_INETADDR_FAMILY(inetaddr) == AF_INET6)
319 {
320 struct ipv6_mreq mreq;
321
322 /* Create the multicast request structure */
323 memcpy(&mreq.ipv6mr_multiaddr, GNET_INETADDR_ADDRP(inetaddr),
324 sizeof(mreq.ipv6mr_multiaddr));
325 mreq.ipv6mr_interface = 0;
326
327 /* Join the group */
328 rv = setsockopt (udpsocket->sockfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
329 (void*) &mreq, sizeof(mreq));
330 }
331 #endif
332 else
333 g_assert_not_reached ();
334
335 return rv;
336 }
337
338
339
340 /**
341 * gnet_mcast_socket_get_ttl
342 * @socket: a #GMcastSocket
343 *
344 * Gets the multicast time-to-live (TTL) of a #GMcastSocket. All IP
345 * multicast packets have a TTL field. This field is decremented by
346 * a router before it forwards the packet. If the TTL reaches zero,
347 * the packet is discarded. The default value is sufficient for most
348 * applications.
349 *
350 * The table below shows the scope for a given TTL. The scope is
351 * only an estimate.
352 *
353 * <table>
354 * <title>TTL and scope</title>
355 * <tgroup cols="2" align="left">
356 * <thead>
357 * <row>
358 * <entry>TTL</entry>
359 * <entry>Scope</entry>
360 * </row>
361 * </thead>
362 * <tbody>
363 * <row>
364 * <entry>0</entry>
365 * <entry>node local</entry>
366 * </row>
367 * <row>
368 * <entry>1</entry>
369 * <entry>link local</entry>
370 * </row>
371 * <row>
372 * <entry>2-32</entry>
373 * <entry>site local</entry>
374 * </row>
375 * <row>
376 * <entry>33-64</entry>
377 * <entry>region local</entry>
378 * </row>
379 * <row>
380 * <entry>65-128</entry>
381 * <entry>continent local</entry>
382 * </row>
383 * <row>
384 * <entry>129-255</entry>
385 * <entry>unrestricted (global)</entry>
386 * </row>
387 * </tbody>
388 * </tgroup>
389 * </table>
390 *
391 * Returns: the TTL (an integer between 0 and 255), -1 if the kernel
392 * default is being used, or an integer less than -1 on error.
393 *
394 **/
395 gint
gnet_mcast_socket_get_ttl(const GMcastSocket * socket)396 gnet_mcast_socket_get_ttl (const GMcastSocket* socket)
397 {
398 GUdpSocket *udpsocket;
399 guchar ttl;
400 socklen_t ttl_size;
401 int rv = -1;
402
403 g_return_val_if_fail (socket != NULL, -2);
404 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), -2);
405
406 udpsocket = GNET_UDP_SOCKET (socket);
407
408 ttl_size = sizeof(ttl);
409
410 /* Get the IPv4 TTL if the socket is bound to an IPv4 address */
411 if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET)
412 {
413 rv = getsockopt (udpsocket->sockfd, IPPROTO_IP,
414 IP_MULTICAST_TTL, (void*) &ttl, &ttl_size);
415 }
416
417 /* Get the IPv6 TTL if the socket is bound to an IPv6 address */
418 #ifdef HAVE_IPV6
419 else if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET6)
420 {
421 rv = getsockopt (udpsocket->sockfd, IPPROTO_IPV6,
422 IPV6_MULTICAST_HOPS, (void*) &ttl, &ttl_size);
423 }
424 #endif
425 else
426 g_assert_not_reached ();
427
428 if (rv == -1)
429 return -2;
430
431 return ttl;
432 }
433
434
435 /**
436 * gnet_mcast_socket_set_ttl
437 * @socket: a #GMcastSocket
438 * @ttl: value to set TTL to
439 *
440 * Sets the time-to-live (TTL) default of a #GMcastSocket. Set the TTL
441 * to -1 to use the kernel default. The default value is sufficient
442 * for most applications.
443 *
444 * Returns: 0 if successful.
445 *
446 **/
447 gint
gnet_mcast_socket_set_ttl(GMcastSocket * socket,gint ttl)448 gnet_mcast_socket_set_ttl (GMcastSocket* socket, gint ttl)
449 {
450 GUdpSocket *udpsocket;
451 guchar ttlb;
452 int rv1, rv2;
453 #ifdef HAVE_IPV6
454 GIPv6Policy policy;
455 #endif
456
457 g_return_val_if_fail (socket != NULL, -1);
458 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), -1);
459
460 udpsocket = GNET_UDP_SOCKET (socket);
461
462 rv1 = -1;
463 rv2 = -1;
464
465 /* If the bind address is anything IPv4 *or* the bind address is
466 0::0 IPv6 and IPv6 policy allows IPv4, set IP_TTL. In the latter case,
467 if we bind to 0::0 and the host is dual-stacked, then all IPv4
468 interfaces will be bound to also. */
469 if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET
470 #ifdef HAVE_IPV6
471 || (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET6 &&
472 IN6_IS_ADDR_UNSPECIFIED(&GNET_SOCKADDR_SA6(udpsocket->sa).sin6_addr) &&
473 ((policy = gnet_ipv6_get_policy()) == GIPV6_POLICY_IPV4_THEN_IPV6 ||
474 policy == GIPV6_POLICY_IPV6_THEN_IPV4))
475 #endif
476 )
477 {
478 ttlb = ttl;
479 rv1 = setsockopt (udpsocket->sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
480 (void*) &ttlb, sizeof(ttlb));
481 }
482
483
484 /* If the bind address is IPv6, set IPV6_UNICAST_HOPS */
485 #ifdef HAVE_IPV6
486 if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET6)
487 {
488 ttlb = ttl;
489 rv2 = setsockopt (udpsocket->sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
490 (void*) &ttlb, sizeof(ttlb));
491 }
492 #endif
493
494 if (rv1 == -1 && rv2 == -1)
495 return -1;
496
497 return 0;
498 }
499
500
501
502 /**
503 * gnet_mcast_socket_is_loopback
504 * @socket: a #GMcastSocket
505 *
506 * Checks if a #GMcastSocket has loopback enabled. If loopback is
507 * enabled, all packets sent by the host will also be received by the
508 * host. Loopback is disabled by default.
509 *
510 * Returns: 0 if loopback is disabled, 1 if enabled, and -1 on error.
511 *
512 **/
513 gint
gnet_mcast_socket_is_loopback(const GMcastSocket * socket)514 gnet_mcast_socket_is_loopback (const GMcastSocket* socket)
515 {
516 GUdpSocket *udpsocket;
517 socklen_t flag_size;
518 int rv = -1;
519 gint is_loopback = 0;
520
521 g_return_val_if_fail (socket != NULL, -1);
522 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), -1);
523
524 udpsocket = GNET_UDP_SOCKET (socket);
525
526 /* Get IPv4 loopback if it's bound to a IPv4 address */
527 if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET)
528 {
529 guchar flag;
530
531 flag_size = sizeof (flag);
532 rv = getsockopt (udpsocket->sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
533 (char *) &flag, &flag_size);
534 if (flag)
535 is_loopback = 1;
536 }
537
538 /* Otherwise, get IPv6 loopback */
539 #ifdef HAVE_IPV6
540 else if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET6)
541 {
542 guint flag;
543
544 flag_size = sizeof (flag);
545 rv = getsockopt (udpsocket->sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
546 (void *) &flag, &flag_size);
547 if (flag)
548 is_loopback = 1;
549 }
550 #endif
551 else
552 g_assert_not_reached();
553
554 if (rv == -1)
555 return -1;
556
557 return is_loopback;
558 }
559
560
561
562 /**
563 * gnet_mcast_socket_set_loopback
564 * @socket: a #GMcastSocket
565 * @enable: should loopback be enabled?
566 *
567 * Enables (or disables) loopback on a #GMcastSocket. Loopback is
568 * disabled by default.
569 *
570 * Returns: 0 if successful.
571 *
572 **/
573 gint
gnet_mcast_socket_set_loopback(GMcastSocket * socket,gboolean enable)574 gnet_mcast_socket_set_loopback (GMcastSocket* socket, gboolean enable)
575 {
576 GUdpSocket *udpsocket;
577 int rv1, rv2;
578 #ifdef HAVE_IPV6
579 GIPv6Policy policy;
580 #endif
581
582 g_return_val_if_fail (socket != NULL, -1);
583 g_return_val_if_fail (GNET_IS_MCAST_SOCKET (socket), -1);
584
585 udpsocket = GNET_UDP_SOCKET (socket);
586
587 rv1 = -1;
588 rv2 = -1;
589
590 /* Set IPv4 loopback. (As in set_ttl().) */
591 if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET
592 #ifdef HAVE_IPV6
593 || (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET6 &&
594 IN6_IS_ADDR_UNSPECIFIED(&GNET_SOCKADDR_SA6 (udpsocket->sa).sin6_addr) &&
595 ((policy = gnet_ipv6_get_policy()) == GIPV6_POLICY_IPV4_THEN_IPV6 ||
596 policy == GIPV6_POLICY_IPV6_THEN_IPV4))
597 #endif
598 )
599 {
600 guchar flag;
601
602 flag = (guchar) enable;
603
604 rv1 = setsockopt (udpsocket->sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
605 (char *) &flag, sizeof(flag));
606 }
607
608 /* Set IPv6 loopback */
609 #ifdef HAVE_IPV6
610 if (GNET_SOCKADDR_FAMILY (udpsocket->sa) == AF_INET6)
611 {
612 guint flag;
613
614 flag = (guint) enable;
615
616 rv2 = setsockopt (udpsocket->sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
617 (void *) &flag, sizeof(flag));
618 }
619 #endif
620
621 if (rv1 == -1 && rv2 == -1)
622 return -1;
623
624 return 0;
625 }
626
627
628
629 /**
630 * gnet_mcast_socket_send
631 * @socket: a #GMcastSocket
632 * @buffer: buffer to send
633 * @length: length of buffer
634 * @dst: destination address
635 *
636 * Sends data to a host using a #GMcastSocket.
637 *
638 * Returns: 0 if successful.
639 *
640 **/
641 gint
gnet_mcast_socket_send(GMcastSocket * socket,const gchar * buffer,gint length,const GInetAddr * dst)642 gnet_mcast_socket_send (GMcastSocket* socket, const gchar* buffer, gint length,
643 const GInetAddr* dst)
644 {
645 return gnet_udp_socket_send((GUdpSocket*) socket, buffer, length, dst);
646 }
647
648
649 /**
650 * gnet_mcast_socket_receive
651 * @socket: a #GMcastSocket
652 * @buffer: buffer to write to
653 * @length: length of @buffer
654 * @src: pointer to source address (optional)
655 *
656 * Receives data using a #GMcastSocket. If @src is set, the source
657 * address is stored in the location @src points to. The address is
658 * caller owned.
659 *
660 * Returns: the number of bytes received, -1 if unsuccessful.
661 *
662 **/
663 gint
gnet_mcast_socket_receive(GMcastSocket * socket,gchar * buffer,gint length,GInetAddr ** src)664 gnet_mcast_socket_receive (GMcastSocket* socket, gchar* buffer, gint length,
665 GInetAddr** src)
666 {
667 return gnet_udp_socket_receive((GUdpSocket*) socket, buffer, length, src);
668 }
669
670
671 /**
672 * gnet_mcast_socket_has_packet:
673 * @socket: a #GMcastSocket
674 *
675 * Tests if a #GMcastSocket has a packet waiting to be received.
676 *
677 * Returns: TRUE if there is packet waiting, FALSE otherwise.
678 *
679 **/
680 gboolean
gnet_mcast_socket_has_packet(const GMcastSocket * socket)681 gnet_mcast_socket_has_packet (const GMcastSocket* socket)
682 {
683 return gnet_udp_socket_has_packet((const GUdpSocket*) socket);
684 }
685
686