X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fsocket-io.c;h=961fc37272e722a7363a9f7010b7cfaedd49c3fc;hb=3f4e44cc635ba89e6f6e11dce7ff5a189b82284a;hp=3720704f84ab4ed3204438ce1302c22d9232cac2;hpb=f947c6d78c90c0bba83865abb46cc95dcf2e0095;p=mono.git diff --git a/mono/metadata/socket-io.c b/mono/metadata/socket-io.c index 3720704f84a..961fc37272e 100644 --- a/mono/metadata/socket-io.c +++ b/mono/metadata/socket-io.c @@ -5,12 +5,14 @@ * Dick Porter (dick@ximian.com) * Gonzalo Paniagua Javier (gonzalo@ximian.com) * - * (C) 2001 Ximian, Inc. - * Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com) + * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) */ #include +#ifndef DISABLE_SOCKETS + #include #include #include @@ -19,12 +21,23 @@ #endif #include +#include +#ifndef HOST_WIN32 +#include +#include +#include +#include +#include +#include +#endif + #include #include #include #include #include #include +#include #include #include #include @@ -58,7 +71,7 @@ #include "mono/io-layer/socket-wrappers.h" -#ifdef PLATFORM_WIN32 +#if defined(HOST_WIN32) /* This is a kludge to make this file build under cygwin: * w32api/ws2tcpip.h has definitions for some AF_INET6 values and * prototypes for some but not all required functions (notably @@ -68,7 +81,21 @@ #undef AF_INET6 #endif -#undef DEBUG +#ifdef PLATFORM_ANDROID +// not yet actually implemented... +#undef AF_INET6 +#endif + +#define LOGDEBUG(...) +/* define LOGDEBUG(...) g_message(__VA_ARGS__) */ + +/* + * Some older versions of libc provide IPV6 support without defining the AI_ADDRCONFIG + * flag for getaddrinfo. + */ +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif static gint32 convert_family(MonoAddressFamily mono_family) { @@ -116,11 +143,15 @@ static gint32 convert_family(MonoAddressFamily mono_family) break; case AddressFamily_Sna: +#ifdef AF_SNA family=AF_SNA; +#endif break; case AddressFamily_DecNet: +#ifdef AF_DECnet family=AF_DECnet; +#endif break; case AddressFamily_AppleTalk: @@ -167,13 +198,17 @@ static MonoAddressFamily convert_to_mono_family(guint16 af_family) break; #endif +#ifdef AF_SNA case AF_SNA: family=AddressFamily_Sna; break; +#endif +#ifdef AF_DECnet case AF_DECnet: family=AddressFamily_DecNet; break; +#endif case AF_APPLETALK: family=AddressFamily_AppleTalk; @@ -215,7 +250,9 @@ static gint32 convert_type(MonoSocketType mono_type) break; case SocketType_Rdm: +#ifdef SOCK_RDM type=SOCK_RDM; +#endif break; case SocketType_Seqpacket: @@ -288,24 +325,22 @@ static gint32 convert_socketflags (gint32 sflags) flags |= MSG_PEEK; if (sflags & SocketFlags_DontRoute) flags |= MSG_DONTROUTE; -#if 0 + /* Ignore Partial - see bug 349688. Don't return -1, because * according to the comment in that bug ms runtime doesn't for * UDP sockets (this means we will silently ignore it for TCP * too) */ - if (sflags & SocketFlags_Partial) #ifdef MSG_MORE + if (sflags & SocketFlags_Partial) flags |= MSG_MORE; -#else - return -1; -#endif #endif +#if 0 + /* Don't do anything for MaxIOVectorLength */ if (sflags & SocketFlags_MaxIOVectorLength) - /* FIXME: Don't know what to do for MaxIOVectorLength query */ return -1; - - return (flags ? flags : -1); +#endif + return flags; } /* @@ -387,11 +422,23 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level, break; #endif case SocketOptionName_ExclusiveAddressUse: +#ifdef SO_EXCLUSIVEADDRUSE + *system_name = SO_EXCLUSIVEADDRUSE; + break; +#endif case SocketOptionName_UseLoopback: +#ifdef SO_USELOOPBACK + *system_name = SO_USELOOPBACK; + break; +#endif case SocketOptionName_MaxConnections: - /* Can't figure out how to map these, so fall - * through - */ +#ifdef SO_MAXCONN + *system_name = SO_MAXCONN; + break; +#elif defined(SOMAXCONN) + *system_name = SOMAXCONN; + break; +#endif default: g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name); return(-1); @@ -506,6 +553,7 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level, switch(mono_name) { case SocketOptionName_IpTimeToLive: + case SocketOptionName_HopLimit: *system_name = IPV6_UNICAST_HOPS; break; case SocketOptionName_MulticastInterface: @@ -612,14 +660,16 @@ static MonoImage *get_socket_assembly (void) { static const char *version = NULL; static gboolean moonlight; - static MonoImage *socket_assembly = NULL; + MonoDomain *domain = mono_domain_get (); if (version == NULL) { version = mono_get_runtime_info ()->framework_version; moonlight = !strcmp (version, "2.1"); } - if (socket_assembly == NULL) { + if (domain->socket_assembly == NULL) { + MonoImage *socket_assembly; + if (moonlight) { socket_assembly = mono_image_loaded ("System.Net"); if (!socket_assembly) { @@ -643,9 +693,11 @@ static MonoImage *get_socket_assembly (void) } } } + + domain->socket_assembly = socket_assembly; } - return(socket_assembly); + return domain->socket_assembly; } #ifdef AF_INET6 @@ -663,6 +715,7 @@ static gint32 get_family_hint(void) ipv4_field = mono_class_get_field_from_name (socket_class, "ipv4Supported"); ipv6_field = mono_class_get_field_from_name (socket_class, "ipv6Supported"); vtable = mono_class_vtable (mono_domain_get (), socket_class); + g_assert (vtable); mono_runtime_class_init (vtable); mono_field_static_get_value (vtable, ipv4_field, &ipv4_enabled); @@ -746,9 +799,7 @@ void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock, { MONO_ARCH_SAVE_REGS; -#ifdef DEBUG - g_message (G_GNUC_PRETTY_FUNCTION ": closing 0x%x", sock); -#endif + LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock)); *error = 0; @@ -762,9 +813,7 @@ gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(voi { MONO_ARCH_SAVE_REGS; -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError()); -#endif + LOGDEBUG (g_message("%s: returning %d", __func__, WSAGetLastError())); return(WSAGetLastError()); } @@ -811,15 +860,24 @@ void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock, } gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock, - gint32 *error) + gint32 *error, + gboolean blocking) { SOCKET newsock; MONO_ARCH_SAVE_REGS; *error = 0; - +#ifdef HOST_WIN32 + { + MonoInternalThread* curthread = mono_thread_internal_current (); + curthread->interrupt_on_stop = (gpointer)TRUE; + newsock = _wapi_accept (sock, NULL, 0); + curthread->interrupt_on_stop = (gpointer)FALSE; + } +#else newsock = _wapi_accept (sock, NULL, 0); +#endif if(newsock==INVALID_SOCKET) { *error = WSAGetLastError (); return(NULL); @@ -849,31 +907,35 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr, { MonoDomain *domain = mono_domain_get (); MonoObject *sockaddr_obj; - MonoClass *sockaddr_class; - MonoClassField *field; MonoArray *data; MonoAddressFamily family; /* Build a System.Net.SocketAddress object instance */ - sockaddr_class=mono_class_from_name(get_socket_assembly (), "System.Net", "SocketAddress"); - sockaddr_obj=mono_object_new(domain, sockaddr_class); + if (!domain->sockaddr_class) { + domain->sockaddr_class=mono_class_from_name (get_socket_assembly (), "System.Net", "SocketAddress"); + g_assert (domain->sockaddr_class); + } + sockaddr_obj=mono_object_new(domain, domain->sockaddr_class); /* Locate the SocketAddress data buffer in the object */ - field=mono_class_get_field_from_name(sockaddr_class, "data"); + if (!domain->sockaddr_data_field) { + domain->sockaddr_data_field=mono_class_get_field_from_name (domain->sockaddr_class, "data"); + 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(domain, mono_get_byte_class (), sa_size); + 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(domain, mono_get_byte_class (), sa_size+2); + data=mono_array_new_cached(domain, mono_get_byte_class (), sa_size+2); } /* The data buffer is laid out as follows: @@ -907,7 +969,7 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr, mono_array_set(data, guint8, 6, (address>>8) & 0xff); mono_array_set(data, guint8, 7, (address) & 0xff); - mono_field_set_value (sockaddr_obj, field, data); + mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data); return(sockaddr_obj); #ifdef AF_INET6 @@ -937,7 +999,7 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr, mono_array_set(data, guint8, 27, (sa_in->sin6_scope_id >> 24) & 0xff); - mono_field_set_value (sockaddr_obj, field, data); + mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data); return(sockaddr_obj); #endif @@ -949,7 +1011,7 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr, mono_array_set (data, guint8, i+2, saddr->sa_data[i]); } - mono_field_set_value (sockaddr_obj, field, data); + mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data); return sockaddr_obj; #endif @@ -959,56 +1021,92 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr, } } -extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 *error) +static int +get_sockaddr_size (int family) +{ + int size; + + size = 0; + if (family == AF_INET) { + size = sizeof (struct sockaddr_in); +#ifdef AF_INET6 + } else if (family == AF_INET6) { + size = sizeof (struct sockaddr_in6); +#endif +#ifdef HAVE_SYS_UN_H + } else if (family == AF_UNIX) { + size = sizeof (struct sockaddr_un); +#endif + } + return size; +} + +extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 af, gint32 *error) { - gchar sa[32]; /* sockaddr in not big enough for sockaddr_in6 */ + gchar *sa; socklen_t salen; int ret; + MonoObject *result; MONO_ARCH_SAVE_REGS; *error = 0; - salen=sizeof(sa); + salen = get_sockaddr_size (convert_family (af)); + if (salen == 0) { + *error = WSAEAFNOSUPPORT; + return NULL; + } + sa = (salen <= 128) ? alloca (salen) : g_malloc0 (salen); ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen); if(ret==SOCKET_ERROR) { *error = WSAGetLastError (); + if (salen > 128) + g_free (sa); return(NULL); } -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": bound to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port)); -#endif + LOGDEBUG (g_message("%s: bound to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port))); - return(create_object_from_sockaddr((struct sockaddr *)sa, salen, - error)); + result = create_object_from_sockaddr((struct sockaddr *)sa, salen, error); + if (salen > 128) + g_free (sa); + return result; } -extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 *error) +extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 af, gint32 *error) { - gchar sa[32]; /* sockaddr in not big enough for sockaddr_in6 */ + gchar *sa; socklen_t salen; int ret; + MonoObject *result; MONO_ARCH_SAVE_REGS; *error = 0; - salen=sizeof(sa); + salen = get_sockaddr_size (convert_family (af)); + if (salen == 0) { + *error = WSAEAFNOSUPPORT; + return NULL; + } + sa = (salen <= 128) ? alloca (salen) : g_malloc0 (salen); + /* Note: linux returns just 2 for AF_UNIX. Always. */ ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen); - if(ret==SOCKET_ERROR) { *error = WSAGetLastError (); + if (salen > 128) + g_free (sa); return(NULL); } -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": connected to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port)); -#endif + LOGDEBUG (g_message("%s: connected to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port))); - return(create_object_from_sockaddr((struct sockaddr *)sa, salen, - error)); + result = create_object_from_sockaddr((struct sockaddr *)sa, salen, error); + if (salen > 128) + g_free (sa); + return result; } static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj, @@ -1138,9 +1236,7 @@ extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoO return; } -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)); -#endif + LOGDEBUG (g_message("%s: binding to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port))); ret = _wapi_bind (sock, sa, sa_size); if(ret==SOCKET_ERROR) { @@ -1160,7 +1256,7 @@ MonoBoolean ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode, gint timeout, gint32 *error) { - MonoThread *thread = NULL; + MonoInternalThread *thread = NULL; mono_pollfd *pfds; int ret; time_t start; @@ -1196,7 +1292,7 @@ ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode, int leave = 0; if (thread == NULL) { - thread = mono_thread_current (); + thread = mono_thread_internal_current (); } leave = mono_thread_test_state (thread, ThreadState_AbortRequested | ThreadState_StopRequested); @@ -1213,7 +1309,7 @@ ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode, } while (ret == -1 && errno == EINTR); if (ret == -1) { -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 *error = WSAGetLastError (); #else *error = errno_to_WSA (errno, __func__); @@ -1246,9 +1342,7 @@ extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, Mo return; } -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)); -#endif + LOGDEBUG (g_message("%s: connecting to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port))); ret = _wapi_connect (sock, sa, sa_size); if(ret==SOCKET_ERROR) { @@ -1286,10 +1380,7 @@ extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, *error = 0; -#ifdef DEBUG - g_message("%s: disconnecting from socket %p (reuse %d)", __func__, - sock, reuse); -#endif + LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse)); /* I _think_ the extension function pointers need to be looked * up for each socket. FIXME: check the best way to store @@ -1367,8 +1458,18 @@ gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArr *error = WSAEOPNOTSUPP; return (0); } - + +#ifdef HOST_WIN32 + { + MonoInternalThread* curthread = mono_thread_internal_current (); + curthread->interrupt_on_stop = (gpointer)TRUE; + ret = _wapi_recv (sock, buf, count, recvflags); + curthread->interrupt_on_stop = (gpointer)FALSE; + } +#else ret = _wapi_recv (sock, buf, count, recvflags); +#endif + if(ret==SOCKET_ERROR) { *error = WSAGetLastError (); return(0); @@ -1474,15 +1575,11 @@ gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray return(0); } -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen); -#endif + LOGDEBUG (g_message("%s: alen: %d", __func__, alen)); buf=mono_array_addr(buffer, guchar, offset); -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count); -#endif + LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count)); sendflags = convert_socketflags (flags); if (sendflags == -1) { @@ -1551,15 +1648,11 @@ gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArra return(0); } -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen); -#endif + LOGDEBUG (g_message("%s: alen: %d", __func__, alen)); buf=mono_array_addr(buffer, guchar, offset); -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count); -#endif + LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count)); sendflags = convert_socketflags (flags); if (sendflags == -1) { @@ -1591,7 +1684,7 @@ static SOCKET Socket_to_SOCKET(MonoObject *sockobj) #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL) void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error) { - MonoThread *thread = NULL; + MonoInternalThread *thread = NULL; MonoObject *obj; mono_pollfd *pfds; int nfds, idx; @@ -1601,7 +1694,7 @@ void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gi MonoClass *sock_arr_class; MonoArray *socks; time_t start; - mono_array_size_t socks_size; + uintptr_t socks_size; MONO_ARCH_SAVE_REGS; @@ -1647,7 +1740,7 @@ void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gi if (ret == -1 && errno == EINTR) { int leave = 0; if (thread == NULL) - thread = mono_thread_current (); + thread = mono_thread_internal_current (); leave = mono_thread_test_state (thread, ThreadState_AbortRequested | ThreadState_StopRequested); @@ -1664,7 +1757,7 @@ void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gi } while (ret == -1 && errno == EINTR); if (ret == -1) { -#ifdef PLATFORM_WIN32 +#ifdef HOST_WIN32 *error = WSAGetLastError (); #else *error = errno_to_WSA (errno, __func__); @@ -1680,7 +1773,7 @@ void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gi } sock_arr_class= ((MonoObject *)*sockets)->vtable->klass; - socks_size = ((mono_array_size_t)ret) + 3; /* space for the NULL delimiters */ + socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */ socks = mono_array_new_full (mono_domain_get (), sock_arr_class, &socks_size, NULL); mode = idx = 0; @@ -1730,7 +1823,11 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc int time_ms = 0; socklen_t time_ms_size = sizeof (time_ms); #ifdef SO_PEERCRED +# if defined(__OpenBSD__) + struct sockpeercred cred; +# else struct ucred cred; +# endif socklen_t credsize = sizeof(cred); #endif MonoDomain *domain=mono_domain_get(); @@ -1742,8 +1839,18 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc *error = 0; - ret=convert_sockopt_level_and_name(level, name, &system_level, - &system_name); +#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR) + if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) { + system_level = SOL_SOCKET; + system_name = SO_REUSEADDR; + ret = 0; + } else +#endif + { + + ret = convert_sockopt_level_and_name (level, name, &system_level, &system_name); + } + if(ret==-1) { *error = WSAENOPROTOOPT; return; @@ -1850,9 +1957,12 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc #endif default: +#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR) + if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) + val = val ? 0 : 1; +#endif obj = int_to_object (domain, val); } - *obj_val=obj; } @@ -1902,7 +2012,6 @@ static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr) return(inaddr); } -#endif #ifdef AF_INET6 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr) @@ -1929,9 +2038,11 @@ static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr) return(in6addr); } #endif /* AF_INET6 */ +#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; int system_level; int system_name; int ret; @@ -1966,6 +2077,15 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g ret=convert_sockopt_level_and_name(level, name, &system_level, &system_name); + +#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR) + if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) { + system_name = SO_REUSEADDR; + int_val = int_val ? 0 : 1; + ret = 0; + } +#endif + if(ret==-1) { *error = WSAENOPROTOOPT; return; @@ -1977,18 +2097,9 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g /* Only one of obj_val, byte_val or int_val has data */ if(obj_val!=NULL) { MonoClassField *field; - struct linger linger; int valsize; switch(name) { - case SocketOptionName_DontLinger: - linger.l_onoff=0; - linger.l_linger=0; - valsize=sizeof(linger); - ret = _wapi_setsockopt (sock, system_level, - system_name, &linger, valsize); - break; - case SocketOptionName_Linger: /* Dig out "bool enabled" and "int seconds" * fields @@ -2076,17 +2187,31 @@ void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, g return; } } else if (byte_val!=NULL) { - int valsize=mono_array_length(byte_val); - guchar *buf=mono_array_addr(byte_val, guchar, 0); - - ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize); - if(ret==SOCKET_ERROR) { - *error = WSAGetLastError (); - return; + int valsize = mono_array_length (byte_val); + guchar *buf = mono_array_addr (byte_val, guchar, 0); + + switch(name) { + case SocketOptionName_DontLinger: + if (valsize == 1) { + linger.l_onoff = (*buf) ? 0 : 1; + linger.l_linger = 0; + ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger)); + } else { + *error = WSAEINVAL; + } + break; + default: + ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize); + break; } } else { /* ReceiveTimeout/SendTimeout get here */ switch(name) { + case SocketOptionName_DontLinger: + linger.l_onoff = !int_val; + linger.l_linger = 0; + ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger)); + break; case SocketOptionName_DontFragment: #ifdef HAVE_IP_MTU_DISCOVER /* Fiddle with the value slightly if we're @@ -2284,29 +2409,32 @@ static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name, gboolean add_local_ips) { MonoDomain *domain = mono_domain_get (); - int i; + int i = 0; struct in_addr *local_in = NULL; int nlocal_in = 0; - if(he->h_length!=4 || he->h_addrtype!=AF_INET) { - return(FALSE); - } + if (he != NULL) { + if(he->h_length!=4 || he->h_addrtype!=AF_INET) { + return(FALSE); + } - *h_name=mono_string_new(domain, he->h_name); + *h_name=mono_string_new(domain, he->h_name); - i=0; - while(he->h_aliases[i]!=NULL) { - i++; - } - - *h_aliases=mono_array_new(domain, mono_get_string_class (), i); - i=0; - while(he->h_aliases[i]!=NULL) { - MonoString *alias; + while(he->h_aliases[i]!=NULL) { + i++; + } - alias=mono_string_new(domain, he->h_aliases[i]); - mono_array_setref (*h_aliases, i, alias); - i++; + *h_aliases=mono_array_new(domain, mono_get_string_class (), i); + i=0; + while(he->h_aliases[i]!=NULL) { + MonoString *alias; + + alias=mono_string_new(domain, he->h_aliases[i]); + mono_array_setref (*h_aliases, i, alias); + i++; + } + } else if (!add_local_ips) { + return FALSE; } if (add_local_ips) { @@ -2330,10 +2458,15 @@ static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name, } g_free (local_in); + } else if (he == NULL) { + /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */ + *h_addr_list = mono_array_new(domain, mono_get_string_class (), 1); + mono_array_setref (*h_addr_list, 0, mono_string_new (domain, "127.0.0.1")); + return TRUE; } } - if (nlocal_in == 0) { + if (nlocal_in == 0 && he != NULL) { i = 0; while (he->h_addr_list[i]!=NULL) { i++; @@ -2389,10 +2522,6 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, family_hint = get_family_hint (); - if(he1 == NULL && he2 == NULL) { - return(FALSE); - } - /* * Check if address length and family are correct */ @@ -2446,7 +2575,7 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, mono_array_setref (*h_aliases, i, alias); i++; } - } else { + } else if (!add_local_ips) { return(FALSE); } @@ -2524,6 +2653,13 @@ static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, g_free (local_in); g_free (local_in6); return TRUE; + } else if (he1 == NULL && he2 == NULL) { + /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */ + *h_addr_list = mono_array_new(domain, mono_get_string_class (), 1); + mono_array_setref (*h_addr_list, 0, mono_string_new (domain, "127.0.0.1")); + g_free (local_in); + g_free (local_in6); + return TRUE; } g_free (local_in); @@ -2673,8 +2809,12 @@ addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name, mono_array_setref (*h_addr_list, addr_index, addr_string); - if(!i && ai->ai_canonname != NULL) { - *h_name=mono_string_new(domain, ai->ai_canonname); + if(!i) { + if (ai->ai_canonname != NULL) { + *h_name=mono_string_new(domain, ai->ai_canonname); + } else { + *h_name=mono_string_new(domain, buffer); + } } addr_index++; @@ -2702,8 +2842,10 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo MONO_ARCH_SAVE_REGS; hostname=mono_string_to_utf8 (host); + if (*hostname == '\0') + add_local_ips = TRUE; #ifdef HAVE_SIOCGIFCONF - if (gethostname (this_hostname, sizeof (this_hostname)) != -1) { + if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) { if (!strcmp (hostname, this_hostname)) add_local_ips = TRUE; } @@ -2714,7 +2856,7 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_CANONNAME; - if (getaddrinfo(hostname, NULL, &hints, &info) == -1) { + if (*hostname && getaddrinfo(hostname, NULL, &hints, &info) == -1) { return(FALSE); } @@ -2732,9 +2874,11 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo MONO_ARCH_SAVE_REGS; hostname=mono_string_to_utf8 (host); + if (*hostname == '\0') + add_local_ips = TRUE; #ifdef HAVE_SIOCGIFCONF - if (gethostname (this_hostname, sizeof (this_hostname)) != -1) { + if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) { if (!strcmp (hostname, this_hostname)) add_local_ips = TRUE; } @@ -2745,13 +2889,15 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo buffer1 = g_malloc0(buffer_size1); buffer2 = g_malloc0(buffer_size2); - while (gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1, + hp1 = NULL; + hp2 = NULL; + while (*hostname && gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1, &hp1, &herr) == ERANGE) { buffer_size1 *= 2; buffer1 = g_realloc(buffer1, buffer_size1); } - if (hp1 == NULL) + if (*hostname && hp1 == NULL) { while (gethostbyname2_r(hostname, AF_INET6, &he2, buffer2, buffer_size2, &hp2, &herr) == ERANGE) { @@ -2759,8 +2905,6 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo buffer2 = g_realloc(buffer2, buffer_size2); } } - else - hp2 = NULL; return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases, h_addr_list, add_local_ips); @@ -2785,19 +2929,26 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo MONO_ARCH_SAVE_REGS; hostname=mono_string_to_utf8(host); + if (*hostname == '\0') + add_local_ips = TRUE; #ifdef HAVE_SIOCGIFCONF - if (gethostname (this_hostname, sizeof (this_hostname)) != -1) { + if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) { if (!strcmp (hostname, this_hostname)) add_local_ips = TRUE; } #endif +#ifndef HOST_WIN32 + he = NULL; + if (*hostname) + he = _wapi_gethostbyname (hostname); +#else he = _wapi_gethostbyname (hostname); +#endif g_free(hostname); - if(he==NULL) { + if (*hostname && he==NULL) return(FALSE); - } return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips)); } @@ -2845,7 +2996,6 @@ inet_pton (int family, const char *address, void *inaddrp) extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list) { char *address; - gboolean v1; #ifdef AF_INET6 struct sockaddr_in saddr; @@ -2860,8 +3010,6 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *a gboolean ret; #endif - v1 = mono_framework_version () == 1; - address = mono_string_to_utf8 (addr); #ifdef AF_INET6 @@ -2882,10 +3030,6 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *a } g_free(address); - if (v1) { - flags = NI_NAMEREQD; - } - if(family == AF_INET) { #if HAVE_SOCKADDR_IN_SIN_LEN saddr.sin_len = sizeof (saddr); @@ -2909,7 +3053,7 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *a memset (&hints, 0, sizeof(hints)); hints.ai_family = get_family_hint (); hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_CANONNAME; + hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; if( getaddrinfo (hostname, NULL, &hints, &info) == -1 ) { return(FALSE); @@ -2923,12 +3067,7 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *a } if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) { - if (v1) { - ret = FALSE; - } else { - ret = ipaddr_to_IPHostEntry (address, h_name, - h_aliases, h_addr_list); - } + ret = ipaddr_to_IPHostEntry (address, h_name, h_aliases, h_addr_list); } else { ret = hostent_to_IPHostEntry (he, h_name, h_aliases, h_addr_list, FALSE); @@ -2956,6 +3095,43 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_ return(TRUE); } +gboolean +ves_icall_System_Net_Sockets_Socket_SendFile (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags) +{ + HANDLE file; + gint32 error; + TRANSMIT_FILE_BUFFERS buffers; + + MONO_ARCH_SAVE_REGS; + + if (filename == NULL) + return FALSE; + + file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, &error); + if (file == INVALID_HANDLE_VALUE) { + SetLastError (error); + return FALSE; + } + + memset (&buffers, 0, sizeof (buffers)); + if (pre_buffer != NULL) { + buffers.Head = mono_array_addr (pre_buffer, guchar, 0); + buffers.HeadLength = mono_array_length (pre_buffer); + } + if (post_buffer != NULL) { + buffers.Tail = mono_array_addr (post_buffer, guchar, 0); + buffers.TailLength = mono_array_length (post_buffer); + } + + if (!TransmitFile (sock, file, 0, 0, NULL, &buffers, flags)) { + CloseHandle (file); + return FALSE; + } + + CloseHandle (file); + return TRUE; +} + void mono_network_init(void) { WSADATA wsadata; @@ -2963,14 +3139,12 @@ void mono_network_init(void) err=WSAStartup(MAKEWORD(2,0), &wsadata); if(err!=0) { - g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking"); + g_error("%s: Couldn't initialise networking", __func__); exit(-1); } -#ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription); - g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus); -#endif + LOGDEBUG (g_message("%s: Using socket library: %s", __func__, wsadata.szDescription)); + LOGDEBUG (g_message("%s: Socket system status: %s", __func__, wsadata.szSystemStatus)); } void mono_network_cleanup(void) @@ -2978,3 +3152,5 @@ void mono_network_cleanup(void) WSACleanup(); } + +#endif /* #ifndef DISABLE_SOCKETS */