X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fsocket-io.c;h=bc0b4e95f1084896d262e3b4f0c7964f25a99577;hb=7f519b3a28bde0d3ecc7e899f1eee0f2fb00d51c;hp=72888dee513a4db4f760b96b7b9e38bcf5bb43c4;hpb=2ad715bd3eafdf5dac8ad87b8e879f67614726d3;p=mono.git diff --git a/mono/metadata/socket-io.c b/mono/metadata/socket-io.c index 72888dee513..bc0b4e95f10 100644 --- a/mono/metadata/socket-io.c +++ b/mono/metadata/socket-io.c @@ -5,8 +5,8 @@ * 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 @@ -19,12 +19,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 +69,7 @@ #include "mono/io-layer/socket-wrappers.h" -#ifdef PLATFORM_WIN32 +#ifdef 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 +79,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 +141,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 +196,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 +248,9 @@ static gint32 convert_type(MonoSocketType mono_type) break; case SocketType_Rdm: +#ifdef SOCK_RDM type=SOCK_RDM; +#endif break; case SocketType_Seqpacket: @@ -288,17 +323,22 @@ static gint32 convert_socketflags (gint32 sflags) flags |= MSG_PEEK; if (sflags & SocketFlags_DontRoute) flags |= MSG_DONTROUTE; - if (sflags & SocketFlags_Partial) + + /* 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) + */ #ifdef MSG_MORE + if (sflags & SocketFlags_Partial) flags |= MSG_MORE; -#else - return -1; #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; } /* @@ -380,11 +420,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); @@ -601,44 +653,83 @@ static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level, return(0); } -#define STASH_SYS_ASS(this) \ - if(system_assembly == NULL) { \ - system_assembly=mono_image_loaded ("System"); \ - if (!system_assembly) { \ - MonoAssembly *sa = mono_assembly_open ("System.dll", NULL); \ - if (!sa) g_assert_not_reached (); \ - else {system_assembly = mono_assembly_get_image (sa);} \ - } \ +static MonoImage *get_socket_assembly (void) +{ + static const char *version = NULL; + static gboolean moonlight; + static MonoImage *socket_assembly = NULL; + + if (version == NULL) { + version = mono_get_runtime_info ()->framework_version; + moonlight = !strcmp (version, "2.1"); } - -static MonoImage *system_assembly=NULL; - + + if (socket_assembly == NULL) { + 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); + } + } + } + } + + return(socket_assembly); +} #ifdef AF_INET6 static gint32 get_family_hint(void) { - MonoClass *socket_class; - MonoClassField *ipv6_field, *ipv4_field; - gint32 ipv6_enabled = -1, ipv4_enabled = -1; - MonoVTable *vtable; - - socket_class = mono_class_from_name (system_assembly, - "System.Net.Sockets", "Socket"); - 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); - - mono_field_static_get_value(vtable, ipv4_field, &ipv4_enabled); - mono_field_static_get_value(vtable, ipv6_field, &ipv6_enabled); - - if(ipv4_enabled == 1 && ipv6_enabled == 1) { - return(PF_UNSPEC); - } else if(ipv4_enabled == 1) { - return(PF_INET); - } else { - return(PF_INET6); + MonoDomain *domain = mono_domain_get (); + + if (!domain->inet_family_hint) { + MonoClass *socket_class; + MonoClassField *ipv6_field, *ipv4_field; + gint32 ipv6_enabled = -1, ipv4_enabled = -1; + MonoVTable *vtable; + + socket_class = mono_class_from_name (get_socket_assembly (), "System.Net.Sockets", "Socket"); + 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); + mono_field_static_get_value (vtable, ipv6_field, &ipv6_enabled); + + mono_domain_lock (domain); + if (ipv4_enabled == 1 && ipv6_enabled == 1) { + domain->inet_family_hint = 1; + } else if (ipv4_enabled == 1) { + domain->inet_family_hint = 2; + } else { + domain->inet_family_hint = 3; + } + mono_domain_unlock (domain); + } + switch (domain->inet_family_hint) { + case 1: return PF_UNSPEC; + case 2: return PF_INET; + case 3: return PF_INET6; + default: + return PF_UNSPEC; } } #endif @@ -652,8 +743,6 @@ gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, g MONO_ARCH_SAVE_REGS; - STASH_SYS_ASS(this); - *error = 0; sock_family=convert_family(family); @@ -703,9 +792,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; @@ -719,9 +806,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()); } @@ -730,7 +815,7 @@ gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock, gint32 *error) { int ret; - gulong amount; + int amount; MONO_ARCH_SAVE_REGS; @@ -768,15 +853,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); @@ -812,25 +906,25 @@ static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr, MonoAddressFamily family; /* Build a System.Net.SocketAddress object instance */ - sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress"); + sockaddr_class=mono_class_from_name_cached (get_socket_assembly (), "System.Net", "SocketAddress"); sockaddr_obj=mono_object_new(domain, sockaddr_class); /* Locate the SocketAddress data buffer in the object */ - field=mono_class_get_field_from_name(sockaddr_class, "data"); + field=mono_class_get_field_from_name_cached (sockaddr_class, "data"); /* 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: @@ -934,9 +1028,7 @@ extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SO 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)); @@ -960,9 +1052,7 @@ extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(S 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)); @@ -1095,9 +1185,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) { @@ -1117,7 +1205,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; @@ -1153,7 +1241,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); @@ -1170,7 +1258,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__); @@ -1203,9 +1291,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) { @@ -1243,10 +1329,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 @@ -1324,8 +1407,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); @@ -1334,6 +1427,35 @@ gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArr return(ret); } +gint32 ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error) +{ + int ret, count; + DWORD recv; + WSABUF *wsabufs; + DWORD recvflags = 0; + + MONO_ARCH_SAVE_REGS; + + *error = 0; + + wsabufs = mono_array_addr (buffers, WSABUF, 0); + count = mono_array_length (buffers); + + recvflags = convert_socketflags (flags); + if (recvflags == -1) { + *error = WSAEOPNOTSUPP; + return(0); + } + + ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL); + if (ret == SOCKET_ERROR) { + *error = WSAGetLastError (); + return(0); + } + + return(recv); +} + gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error) { int ret; @@ -1402,15 +1524,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) { @@ -1427,6 +1545,35 @@ gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray return(ret); } +gint32 ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error) +{ + int ret, count; + DWORD sent; + WSABUF *wsabufs; + DWORD sendflags = 0; + + MONO_ARCH_SAVE_REGS; + + *error = 0; + + wsabufs = mono_array_addr (buffers, WSABUF, 0); + count = mono_array_length (buffers); + + sendflags = convert_socketflags (flags); + if (sendflags == -1) { + *error = WSAEOPNOTSUPP; + return(0); + } + + ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL); + if (ret == SOCKET_ERROR) { + *error = WSAGetLastError (); + return(0); + } + + return(sent); +} + gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error) { int ret; @@ -1450,15 +1597,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) { @@ -1482,7 +1625,7 @@ static SOCKET Socket_to_SOCKET(MonoObject *sockobj) MonoClassField *field; field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket"); - sock=*(SOCKET *)(((char *)sockobj)+field->offset); + sock=GPOINTER_TO_INT (*(gpointer *)(((char *)sockobj)+field->offset)); return(sock); } @@ -1490,7 +1633,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; @@ -1500,6 +1643,7 @@ void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gi MonoClass *sock_arr_class; MonoArray *socks; time_t start; + uintptr_t socks_size; MONO_ARCH_SAVE_REGS; @@ -1522,7 +1666,7 @@ void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gi return; } - pfds [idx].fd = GPOINTER_TO_INT (Socket_to_SOCKET (obj)); + pfds [idx].fd = Socket_to_SOCKET (obj); pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS; idx++; } @@ -1545,7 +1689,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); @@ -1562,7 +1706,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__); @@ -1578,9 +1722,9 @@ void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gi } sock_arr_class= ((MonoObject *)*sockets)->vtable->klass; - ret += 3; /* space for the NULL delimiters */ - socks = mono_array_new_full (mono_domain_get (), sock_arr_class, (guint32*)&ret, NULL); - ret -= 3; + 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; for (i = 0; i < count && ret > 0; i++) { mono_pollfd *pfd; @@ -1687,7 +1831,7 @@ void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET soc switch(name) { case SocketOptionName_Linger: /* build a System.Net.Sockets.LingerOption */ - obj_class=mono_class_from_name(system_assembly, + obj_class=mono_class_from_name(get_socket_assembly (), "System.Net.Sockets", "LingerOption"); obj=mono_object_new(domain, obj_class); @@ -1830,6 +1974,7 @@ static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr) 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; @@ -1875,18 +2020,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 @@ -1974,17 +2110,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 @@ -2182,29 +2332,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) { @@ -2228,10 +2381,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++; @@ -2287,10 +2445,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 */ @@ -2344,7 +2498,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); } @@ -2422,6 +2576,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); @@ -2571,8 +2732,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++; @@ -2600,8 +2765,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; } @@ -2610,9 +2777,9 @@ MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, Mo 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) { + if (*hostname && getaddrinfo(hostname, NULL, &hints, &info) == -1) { return(FALSE); } @@ -2630,9 +2797,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; } @@ -2643,13 +2812,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) { @@ -2657,8 +2828,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); @@ -2683,19 +2852,22 @@ 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 - he = _wapi_gethostbyname (hostname); + he = NULL; + if (*hostname) + he = _wapi_gethostbyname (hostname); 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)); } @@ -2743,8 +2915,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; - const char *version; - gboolean v1; #ifdef AF_INET6 struct sockaddr_in saddr; @@ -2759,11 +2929,6 @@ extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *a gboolean ret; #endif - MONO_ARCH_SAVE_REGS; - - version = mono_get_runtime_info ()->framework_version; - v1 = (version[0] == '1'); - address = mono_string_to_utf8 (addr); #ifdef AF_INET6 @@ -2784,10 +2949,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); @@ -2811,7 +2972,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); @@ -2825,12 +2986,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); @@ -2858,6 +3014,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; @@ -2865,14 +3058,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)