Fix #5504: UdpClient.JoinMulticastGroup().
authorMartin Baulig <martin.baulig@gmail.com>
Thu, 28 Jun 2012 17:43:19 +0000 (19:43 +0200)
committerMartin Baulig <martin.baulig@gmail.com>
Thu, 28 Jun 2012 17:47:43 +0000 (19:47 +0200)
* configure.in: Check for if_nametoindex().

* socket-io.c (ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal):
  Mac OS doesn't allow interface = 0; use the interface id from the first
  non-loopback interface.

* UdpClientTest.cs: Enable JoinMulticastGroup1_IPv6,
  JoinMulticastGroup2_IPv6 and JoinMulticastGroup3_IPv6 on the Mac.

configure.in
mcs/class/System/Test/System.Net.Sockets/UdpClientTest.cs
mono/metadata/socket-io.c

index ac6a5a7a76167af32902cf7453d33894f143a8d4..ca608b16c1a2c746e7de68808cc86d90cb871b87 100644 (file)
@@ -1739,7 +1739,24 @@ if test x$target_win32 = xno; then
        ], [
                AC_MSG_RESULT(no)
        ])
-
+       dnl **********************************
+       dnl *** Check for if_nametoindex   ***
+       dnl **********************************
+       AC_MSG_CHECKING(for if_nametoindex)
+               AC_TRY_LINK([
+               #include <stdio.h>
+               #include <sys/types.h>
+               #include <sys/socket.h>
+               #include <net/if.h>
+       ], [
+               if_nametoindex(NULL);
+       ], [
+               # Yes, we have it...
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_IF_NAMETOINDEX, 1, [Have if_nametoindex])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
                        
        dnl **********************************
        dnl *** Checks for MonoPosixHelper ***
index 23599c918bb3dcc72656a90e6991d29d2c24a4cd..77a5d5fa397892d1cff1ecd80b6c7c45fdff7eaf 100644 (file)
@@ -502,7 +502,6 @@ namespace MonoTests.System.Net.Sockets {
                }
 
                [Test] // JoinMulticastGroup (IPAddress)
-               [Category ("NotOnMac")]
                public void JoinMulticastGroup1_IPv6 ()
                {
 #if NET_2_0
@@ -612,7 +611,6 @@ namespace MonoTests.System.Net.Sockets {
                }
 
                [Test] // JoinMulticastGroup (In32, IPAddress)
-               [Category ("NotOnMac")]
                public void JoinMulticastGroup2_IPv6 ()
                {
 #if NET_2_0
@@ -704,7 +702,6 @@ namespace MonoTests.System.Net.Sockets {
                }
 
                [Test] // JoinMulticastGroup (IPAddress, Int32)
-               [Category ("NotOnMac")]
                public void JoinMulticastGroup3_IPv6 ()
                {
 #if NET_2_0
index 6071a0cab1b91798f58cc0bb7f52bcb02f1801fe..4a72add60c6ff45b0bde17d5a925424b8aed148c 100644 (file)
@@ -2079,6 +2079,42 @@ static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
 #endif /* AF_INET6 */
 #endif
 
+#if defined(HAVE_GETIFADDRS) && defined(HAVE_IF_NAMETOINDEX)
+static int
+get_local_interface_id (int family)
+{
+       struct ifaddrs *ifap = NULL, *ptr;
+       int idx = 0;
+       
+       if (getifaddrs (&ifap)) {
+               return 0;
+       }
+       
+       for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
+               if (!ptr->ifa_addr || !ptr->ifa_name)
+                       continue;
+               if (ptr->ifa_addr->sa_family != family)
+                       continue;
+               if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
+                       continue;
+               if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
+                       continue;
+                       
+               idx = if_nametoindex (ptr->ifa_name);
+               break;
+       }
+       
+       freeifaddrs (ifap);
+       return idx;
+}
+#else
+static int
+get_local_interface_id (int family)
+{
+       return 0;
+}
+#endif
+
 void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val, gint32 *error)
 {
        struct linger linger;
@@ -2174,7 +2210,22 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g
 
                                field=mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
                                mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
-
+                               
+#if defined(__APPLE__)
+                               /*
+                               * Bug #5504:
+                               *
+                               * Mac OS Lion doesn't allow ipv6mr_interface = 0.
+                               *
+                               * Tests on Windows and Linux show that the multicast group is only
+                               * joined on one NIC when interface = 0, so we simply use the interface
+                               * id from the first non-loopback interface (this is also what
+                               * Dns.GetHostName (string.Empty) would return).
+                               */
+                               if (!mreq6.ipv6mr_interface)
+                                       mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
+#endif
+                                       
                                ret = _wapi_setsockopt (sock, system_level,
                                                        system_name, &mreq6,
                                                        sizeof (mreq6));
@@ -2469,7 +2520,6 @@ get_local_ips (int family, int *nips)
        }
        
        if (getifaddrs (&ifap)) {
-               fprintf(stderr, "get_local_ips() error: %s\n", strerror (errno));
                return NULL;
        }