#include <mono/metadata/threadpool-internals.h>
#include <mono/metadata/domain-internals.h>
#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-memory-model.h>
#include <time.h>
#ifdef HAVE_SYS_TIME_H
#undef AF_INET6
#endif
-#ifdef PLATFORM_ANDROID
-// not yet actually implemented...
-#undef AF_INET6
-#endif
-
#define LOGDEBUG(...)
/* define LOGDEBUG(...) g_message(__VA_ARGS__) */
static MonoImage *get_socket_assembly (void)
{
- static const char *version = NULL;
- static gboolean moonlight;
MonoDomain *domain = mono_domain_get ();
- if (version == NULL) {
- version = mono_get_runtime_info ()->framework_version;
- moonlight = !strcmp (version, "2.1");
- }
-
if (domain->socket_assembly == NULL) {
MonoImage *socket_assembly;
- if (moonlight) {
- socket_assembly = mono_image_loaded ("System.Net");
- if (!socket_assembly) {
- MonoAssembly *sa = mono_assembly_open ("System.Net.dll", NULL);
-
- if (!sa) {
- g_assert_not_reached ();
- } else {
- socket_assembly = mono_assembly_get_image (sa);
- }
- }
- } else {
- socket_assembly = mono_image_loaded ("System");
- if (!socket_assembly) {
- MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);
-
- if (!sa) {
- g_assert_not_reached ();
- } else {
- socket_assembly = mono_assembly_get_image (sa);
- }
+ socket_assembly = mono_image_loaded ("System");
+ if (!socket_assembly) {
+ MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);
+
+ if (!sa) {
+ g_assert_not_reached ();
+ } else {
+ socket_assembly = mono_assembly_get_image (sa);
}
}
-
- domain->socket_assembly = socket_assembly;
+ mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
}
return domain->socket_assembly;
g_assert (domain->sockaddr_data_field);
}
- /* Make sure there is space for the family and size bytes */
-#ifdef HAVE_SYS_UN_H
- if (saddr->sa_family == AF_UNIX) {
- /* sa_len includes the entire sockaddr size, so we don't need the
- * N bytes (sizeof (unsigned short)) of the family. */
- data=mono_array_new_cached(domain, mono_get_byte_class (), sa_size);
- } else
-#endif
- {
- /* May be the +2 here is too conservative, as sa_len returns
- * the length of the entire sockaddr_in/in6, including
- * sizeof (unsigned short) of the family */
- data=mono_array_new_cached(domain, mono_get_byte_class (), sa_size+2);
- }
+ /* May be the +2 here is too conservative, as sa_len returns
+ * the length of the entire sockaddr_in/in6, including
+ * sizeof (unsigned short) of the family */
+ /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
+ data=mono_array_new_cached(domain, mono_get_byte_class (), sa_size+2);
/* The data buffer is laid out as follows:
* bytes 0 and 1 are the address family
#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;
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));
}
if (getifaddrs (&ifap)) {
- fprintf(stderr, "get_local_ips() error: %s\n", strerror (errno));
return NULL;
}