From d87105bf992169370d976e839f665ad3546a89e6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Sun, 30 Jun 2013 13:22:22 +0200
Subject: [PATCH] Stdio.UDP: Support IPv6 in {add,drop}_membership()

FIXME: The second argument (interface address) is not supported yet.
---
 src/modules/_Stdio/udp.c | 84 ++++++++++++++++++++++++++++++----------
 1 file changed, 64 insertions(+), 20 deletions(-)

diff --git a/src/modules/_Stdio/udp.c b/src/modules/_Stdio/udp.c
index 2c1b8e3c80..2f6d630d5a 100644
--- a/src/modules/_Stdio/udp.c
+++ b/src/modules/_Stdio/udp.c
@@ -410,27 +410,49 @@ void udp_add_membership(INT32 args)
   get_inet_addr(&addr, group, NULL, -1, THIS->inet_flags);
   INVALIDATE_CURRENT_TIME();
 
-  /* FIXME: Implement support for IPv6! */
+#ifdef AF_INET6
+  if (THIS->inet_flags & PIKE_INET_FLAG_IPV6) {
+    struct ipv6_mreq sock;
+
+    if (address)
+      Pike_error("Interface address is not supported for IPv6.\n");
+
+    /* NB: This sets imr_interface to IN6ADDR_ANY,
+     *     and clears imr_ifindex if it exists.
+     */
+    MEMSET(&sock, 0, sizeof(sock));
+
+    if(SOCKADDR_FAMILY(addr) != AF_INET6)
+      Pike_error("Mixing IPv6 and other multicast is not supported.\n");
+
+    sock.ipv6mr_multiaddr = addr.ipv6.sin6_addr;
+
+    pop_n_elems(args);
+    push_int( fd_setsockopt(FD, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
+			    (char *)&sock, sizeof(sock)) );
+    return;
+  }
+#endif /* AF_INET6 */
+
+  /* NB: This sets imr_interface to INADDR_ANY,
+   *     and clears imr_ifindex if it exists.
+   */
+  MEMSET(&sock, 0, sizeof(sock));
+
   if(SOCKADDR_FAMILY(addr) != AF_INET)
-    Pike_error("Multicast only supported for IPv4.\n");
+    Pike_error("Mixing IPv6 and IPv4 multicast is not supported.\n");
 
   sock.imr_multiaddr = addr.ipv4.sin_addr;
 
-  if( !address )
-    sock.imr_interface.s_addr = htonl( INADDR_ANY );
-  else {
+  if (address) {
     get_inet_addr(&addr, address, NULL, -1, THIS->inet_flags);
     INVALIDATE_CURRENT_TIME();
 
-    /* FIXME: Implement support for IPv6! */
     if(SOCKADDR_FAMILY(addr) != AF_INET)
-      Pike_error("Multicast only supported for IPv4.\n");
+      Pike_error("Mixing IPv6 and IPv4 multicast is not supported.\n");
 
     sock.imr_interface = addr.ipv4.sin_addr;
   }
-#if 0
-  sock.imr_ifindex = face;
-#endif
 
   pop_n_elems(args);
   push_int( fd_setsockopt(FD, IPPROTO_IP, IP_ADD_MEMBERSHIP,
@@ -455,27 +477,49 @@ void udp_drop_membership(INT32 args)
   get_inet_addr(&addr, group, NULL, -1, THIS->inet_flags);
   INVALIDATE_CURRENT_TIME();
 
-  /* FIXME: Implement support for IPv6! */
+#ifdef AF_INET6
+  if (THIS->inet_flags & PIKE_INET_FLAG_IPV6) {
+    struct ipv6_mreq sock;
+
+    if (address)
+      Pike_error("Interface address is not supported for IPv6.\n");
+
+    /* NB: This sets imr_interface to IN6ADDR_ANY,
+     *     and clears imr_ifindex if it exists.
+     */
+    MEMSET(&sock, 0, sizeof(sock));
+
+    if(SOCKADDR_FAMILY(addr) != AF_INET6)
+      Pike_error("Mixing IPv6 and other multicast is not supported.\n");
+
+    sock.ipv6mr_multiaddr = addr.ipv6.sin6_addr;
+
+    pop_n_elems(args);
+    push_int( fd_setsockopt(FD, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP,
+			    (char *)&sock, sizeof(sock)) );
+    return;
+  }
+#endif /* AF_INET6 */
+
+  /* NB: This sets imr_interface to INADDR_ANY,
+   *     and clears imr_ifindex if it exists.
+   */
+  MEMSET(&sock, 0, sizeof(sock));
+
   if(SOCKADDR_FAMILY(addr) != AF_INET)
-    Pike_error("Multicast only supported for IPv4.\n");
+    Pike_error("Mixing IPv6 and IPv4 multicast is not supported.\n");
 
   sock.imr_multiaddr = addr.ipv4.sin_addr;
 
-  if( !address )
-    sock.imr_interface.s_addr = htonl( INADDR_ANY );
-  else {
+  if (address) {
     get_inet_addr(&addr, address, NULL, -1, THIS->inet_flags);
     INVALIDATE_CURRENT_TIME();
 
-    /* FIXME: Implement support for IPv6! */
     if(SOCKADDR_FAMILY(addr) != AF_INET)
-      Pike_error("Multicast only supported for IPv4.\n");
+      Pike_error("Mixing IPv6 and IPv4 multicast is not supported.\n");
 
     sock.imr_interface = addr.ipv4.sin_addr;
   }
-#if 0
-  sock.imr_ifindex = face;
-#endif
 
   pop_n_elems(args);
   push_int( fd_setsockopt(FD, IPPROTO_IP, IP_DROP_MEMBERSHIP,
-- 
GitLab