#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-memory-model.h>
#include <mono/utils/networking.h>
+#include <mono/utils/w32handle.h>
#include <time.h>
#ifdef HAVE_SYS_TIME_H
#endif
#include "mono/io-layer/socket-wrappers.h"
+#ifdef HOST_WIN32
+#include "mono/metadata/socket-io-windows-internals.h"
+#endif
#define LOGDEBUG(...)
/* define LOGDEBUG(...) g_message(__VA_ARGS__) */
return domain->socket_assembly;
}
-static gint32
-get_family_hint (MonoError *error)
-{
- MonoDomain *domain = mono_domain_get ();
-
- mono_error_init (error);
-
- if (!domain->inet_family_hint) {
- MonoImage *socket_assembly;
- MonoClass *socket_class;
- MonoClassField *ipv6_field, *ipv4_field;
- gint32 ipv6_enabled = -1, ipv4_enabled = -1;
- MonoVTable *vtable;
-
- socket_assembly = get_socket_assembly ();
- g_assert (socket_assembly);
-
- socket_class = mono_class_load_from_name (socket_assembly, "System.Net.Sockets", "Socket");
-
- ipv4_field = mono_class_get_field_from_name (socket_class, "ipv4_supported");
- g_assert (ipv4_field);
-
- ipv6_field = mono_class_get_field_from_name (socket_class, "ipv6_supported");
- g_assert (ipv6_field);
-
- vtable = mono_class_vtable (mono_domain_get (), socket_class);
- g_assert (vtable);
-
- mono_runtime_class_init_full (vtable, error);
- return_val_if_nok (error, -1);
-
- 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;
- }
-}
-
gpointer
ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObject *this_obj, gint32 family, gint32 type, gint32 proto, gint32 *werror)
{
* polling system does not notify when the socket is closed */
mono_threadpool_ms_io_remove_socket (GPOINTER_TO_INT (sock));
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
closesocket (sock);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
}
gint32
return NULL;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
#ifdef HOST_WIN32
{
MonoInternalThread *curthread = mono_thread_internal_current ();
curthread->interrupt_on_stop = (gpointer)TRUE;
- newsock = _wapi_accept (sock, NULL, 0);
+ newsock = alertable_accept (sock, NULL, 0, blocking);
curthread->interrupt_on_stop = (gpointer)FALSE;
}
#else
newsock = _wapi_accept (sock, NULL, 0);
#endif
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
+
+ if (newsock == INVALID_SOCKET)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
+ if (interrupted)
*werror = WSAEINTR;
- return NULL;
- }
- if (newsock == INVALID_SOCKET) {
- *werror = WSAGetLastError ();
+ if (*werror)
return NULL;
- }
return GUINT_TO_POINTER (newsock);
}
*werror = 0;
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = _wapi_listen (sock, backlog);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret == SOCKET_ERROR)
*werror = WSAGetLastError ();
/* Locate the SocketAddress data buffer in the object */
if (!domain->sockaddr_data_field) {
- domain->sockaddr_data_field = mono_class_get_field_from_name (domain->sockaddr_class, "data");
+ domain->sockaddr_data_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Buffer");
g_assert (domain->sockaddr_data_field);
}
+ /* Locate the SocketAddress data buffer length in the object */
+ if (!domain->sockaddr_data_length_field) {
+ domain->sockaddr_data_length_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Size");
+ g_assert (domain->sockaddr_data_length_field);
+ }
+
/* 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 */
struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr;
guint16 port = ntohs (sa_in->sin_port);
guint32 address = ntohl (sa_in->sin_addr.s_addr);
+ int buffer_size = 8;
- if (sa_size < 8) {
+ if (sa_size < buffer_size) {
mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
return NULL;
}
mono_array_set (data, guint8, 7, (address) & 0xff);
mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
+ mono_field_set_value (sockaddr_obj, domain->sockaddr_data_length_field, &buffer_size);
return sockaddr_obj;
} else if (saddr->sa_family == AF_INET6) {
struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)saddr;
int i;
+ int buffer_size = 28;
guint16 port = ntohs (sa_in->sin6_port);
- if (sa_size < 28) {
+ if (sa_size < buffer_size) {
mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
return NULL;
}
(sa_in->sin6_scope_id >> 24) & 0xff);
mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
+ mono_field_set_value (sockaddr_obj, domain->sockaddr_data_length_field, &buffer_size);
return sockaddr_obj;
}
#ifdef HAVE_SYS_UN_H
else if (saddr->sa_family == AF_UNIX) {
int i;
+ int buffer_size = sa_size + 2;
for (i = 0; i < sa_size; i++)
mono_array_set (data, guint8, i + 2, saddr->sa_data [i]);
mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
+ mono_field_set_value (sockaddr_obj, domain->sockaddr_data_length_field, &buffer_size);
return sockaddr_obj;
}
}
sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret == SOCKET_ERROR) {
*werror = WSAGetLastError ();
sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
/* Note: linux returns just 2 for AF_UNIX. Always. */
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret == SOCKET_ERROR) {
*werror = WSAGetLastError ();
static struct sockaddr*
create_sockaddr_from_object (MonoObject *saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
{
- MonoClassField *field;
+ MonoDomain *domain = mono_domain_get ();
MonoArray *data;
gint32 family;
int len;
mono_error_init (error);
- /* Dig the SocketAddress data buffer out of the object */
- field = mono_class_get_field_from_name (saddr_obj->vtable->klass, "data");
- data = *(MonoArray **)(((char *)saddr_obj) + field->offset);
+ if (!domain->sockaddr_class)
+ domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
+
+ /* Locate the SocketAddress data buffer in the object */
+ if (!domain->sockaddr_data_field) {
+ domain->sockaddr_data_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Buffer");
+ g_assert (domain->sockaddr_data_field);
+ }
+
+ /* Locate the SocketAddress data buffer length in the object */
+ if (!domain->sockaddr_data_length_field) {
+ domain->sockaddr_data_length_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Size");
+ g_assert (domain->sockaddr_data_length_field);
+ }
+
+ data = *(MonoArray **)(((char *)saddr_obj) + domain->sockaddr_data_field->offset);
/* The data buffer is laid out as follows:
* byte 0 is the address family low byte
* UNIX:
* the rest is the file name
*/
- len = mono_array_length (data);
- if (len < 2) {
- mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
- return NULL;
- }
-
+ len = *(int *)(((char *)saddr_obj) + domain->sockaddr_data_length_field->offset);
+ g_assert (len >= 2);
+
family = convert_family ((MonoAddressFamily)(mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8)));
if (family == AF_INET) {
struct sockaddr_in *sa;
return FALSE;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = mono_poll (pfds, 1, timeout);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
mono_thread_info_uninstall_interrupt (&interrupted);
if (interrupted) {
}
void
-ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror)
+ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror, gboolean blocking)
{
MonoError error;
struct sockaddr *sa;
return;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret = alertable_connect (sock, sa, sa_size, blocking);
+#else
ret = _wapi_connect (sock, sa, sa_size);
+#endif
- MONO_FINISH_BLOCKING;
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return;
- }
+ MONO_EXIT_GC_SAFE;
if (ret == SOCKET_ERROR)
*werror = WSAGetLastError ();
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
g_free (sa);
}
LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
/* I _think_ the extension function pointers need to be looked
* up for each socket. FIXME: check the best way to store
ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&disco_guid, sizeof (GUID),
(gchar *)&_wapi_disconnectex, sizeof (void *), &output_bytes, NULL, NULL);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret != 0) {
/* make sure that WSAIoctl didn't put crap in the
*/
_wapi_disconnectex = NULL;
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
/*
* Use the SIO_GET_EXTENSION_FUNCTION_POINTER to
ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&trans_guid, sizeof(GUID),
(gchar *)&_wapi_transmitfile, sizeof(void *), &output_bytes, NULL, NULL);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret != 0)
_wapi_transmitfile = NULL;
return;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
if (_wapi_disconnectex != NULL) {
- if (!_wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0))
+ if (!_wapi_disconnectex (sock, NULL, reuse ? TF_REUSE_SOCKET : 0, 0))
*werror = WSAGetLastError ();
} else if (_wapi_transmitfile != NULL) {
- if (!_wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET))
+ if (!_wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | (reuse ? TF_REUSE_SOCKET : 0)))
*werror = WSAGetLastError ();
} else {
*werror = ERROR_NOT_SUPPORTED;
}
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
mono_thread_info_uninstall_interrupt (&interrupted);
if (interrupted)
}
gint32
-ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror)
+ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror, gboolean blocking)
{
int ret;
guchar *buf;
if (interrupted)
return 0;
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
#ifdef HOST_WIN32
{
curthread->interrupt_on_stop = (gpointer)TRUE;
- ret = _wapi_recv (sock, buf, count, recvflags);
+ ret = alertable_recv (sock, buf, count, recvflags, blocking);
curthread->interrupt_on_stop = (gpointer)FALSE;
}
#else
ret = _wapi_recv (sock, buf, count, recvflags);
#endif
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
+ if (interrupted)
*werror = WSAEINTR;
- return 0;
- }
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
+ if (*werror)
return 0;
- }
return ret;
}
gint32
-ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror)
+ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror, gboolean blocking)
{
int ret, count;
gboolean interrupted;
return 0;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret = alertable_WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL, blocking);
+#else
ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL);
+#endif
+
+ MONO_EXIT_GC_SAFE;
- MONO_FINISH_BLOCKING;
+ if (ret == SOCKET_ERROR)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
+ if (interrupted)
*werror = WSAEINTR;
- return 0;
- }
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
+ if (*werror)
return 0;
- }
return recv;
}
gint32
-ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *werror)
+ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *werror, gboolean blocking)
{
MonoError error;
int ret;
return 0;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret = alertable_recvfrom (sock, buf, count, recvflags, sa, &sa_size, blocking);
+#else
ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
+#endif
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
- g_free (sa);
+
+ if (interrupted)
*werror = WSAEINTR;
- return 0;
- }
- if (ret==SOCKET_ERROR) {
- g_free (sa);
- *werror = WSAGetLastError ();
+ if (*werror) {
+ g_free(sa);
return 0;
}
}
gint32
-ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror)
+ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror, gboolean blocking)
{
int ret;
guchar *buf;
return 0;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret = alertable_send (sock, buf, count, sendflags, blocking);
+#else
ret = _wapi_send (sock, buf, count, sendflags);
+#endif
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
+ if (interrupted)
*werror = WSAEINTR;
- return 0;
- }
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
+ if (*werror)
return 0;
- }
return ret;
}
gint32
-ves_icall_System_Net_Sockets_Socket_Send_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror)
+ves_icall_System_Net_Sockets_Socket_Send_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror, gboolean blocking)
{
int ret, count;
DWORD sent;
return 0;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret = alertable_WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL, blocking);
+#else
ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL);
+#endif
+
+ MONO_EXIT_GC_SAFE;
- MONO_FINISH_BLOCKING;
+ if (ret == SOCKET_ERROR)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
+ if (interrupted)
*werror = WSAEINTR;
- return 0;
- }
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
+ if (*werror)
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 *werror)
+ves_icall_System_Net_Sockets_Socket_SendTo_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *werror, gboolean blocking)
{
MonoError error;
int ret;
return 0;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret = alertable_sendto (sock, buf, count, sendflags, sa, sa_size, blocking);
+#else
ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
+#endif
+
+ MONO_EXIT_GC_SAFE;
- MONO_FINISH_BLOCKING;
+ if (ret == SOCKET_ERROR)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
- g_free (sa);
+ if (interrupted)
*werror = WSAEINTR;
- return 0;
- }
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
+ g_free(sa);
+
+ if (*werror)
+ return 0;
- g_free (sa);
-
return ret;
}
MonoSafeHandle *safe_handle;
MonoClassField *field;
- field = mono_class_get_field_from_name (sockobj->vtable->klass, "safe_handle");
+ field = mono_class_get_field_from_name (sockobj->vtable->klass, "m_Handle");
safe_handle = ((MonoSafeHandle *)(*(gpointer *)(((char *)sockobj) + field->offset)));
if (safe_handle == NULL)
return;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = mono_poll (pfds, nfds, timeout);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
mono_thread_info_uninstall_interrupt (&interrupted);
if (interrupted) {
int system_level = 0;
int system_name = 0;
int ret;
- int val;
+ int val = 0;
socklen_t valsize = sizeof (val);
struct linger linger;
socklen_t lingersize = sizeof (linger);
return;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
/* No need to deal with MulticastOption names here, because
* you cant getsockopt AddMembership or DropMembership (the
ret = _wapi_getsockopt (sock, system_level, system_name, &val, &valsize);
}
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret == SOCKET_ERROR) {
*werror = WSAGetLastError ();
valsize = mono_array_length (*byte_val);
buf = mono_array_addr (*byte_val, guchar, 0);
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret == SOCKET_ERROR)
*werror = WSAGetLastError ();
int i;
field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Numbers");
+ g_assert (field);
data = *(MonoArray **)(((char *)ipaddr) + field->offset);
-/* Solaris has only the 8 bit version. */
-#ifndef s6_addr16
for (i = 0; i < 8; i++) {
- guint16 s = mono_array_get (data, guint16, i);
+ const guint16 s = GUINT16_TO_BE (mono_array_get (data, guint16, i));
+
+/* Solaris/MacOS have only the 8 bit version. */
+#ifndef s6_addr16
in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
in6addr.s6_addr[2 * i] = s & 0xff;
- }
#else
- for (i = 0; i < 8; i++)
- in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
+ in6addr.s6_addr16[i] = s;
#endif
+ }
return in6addr;
}
#endif
* Get group address
*/
field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Group");
+ g_assert (field);
address = *(MonoObject **)(((char *)obj_val) + field->offset);
if (address)
return;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
/* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
ret = _wapi_shutdown (sock, how);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
if (interrupted) {
*werror = WSAEINTR;
- return;
}
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
}
gint
o_len = mono_array_length (output);
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (ret == SOCKET_ERROR) {
*werror = WSAGetLastError ();
return is_ok (error);
}
-static int
-get_addrinfo_family_hint (MonoError *error)
-{
- int hint;
-
- mono_error_init (error);
-
- hint = get_family_hint (error);
- return_val_if_nok (error, 0);
-
- switch (hint) {
- case PF_UNSPEC:
- return MONO_HINT_UNSPECIFIED;
- case PF_INET:
- return MONO_HINT_IPV4;
-#ifdef PF_INET6
- case PF_INET6:
- return MONO_HINT_IPV6;
-#endif
- default:
- g_error ("invalid hint");
- return 0;
- }
-}
-
MonoBoolean
-ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
+ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gint32 hint)
{
+ MonoError error;
gboolean add_local_ips = FALSE, add_info_ok = TRUE;
gchar this_hostname [256];
MonoAddressInfo *info = NULL;
- char *hostname = mono_string_to_utf8 (host);
- MonoError error;
- int hint;
- hint = get_addrinfo_family_hint (&error);
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
+ char *hostname = mono_string_to_utf8_checked (host, &error);
+ if (mono_error_set_pending_exception (&error))
return FALSE;
- }
if (*hostname == '\0') {
add_local_ips = TRUE;
}
}
+#ifdef HOST_WIN32
+ // Win32 APIs already returns local interface addresses for empty hostname ("")
+ // so we never want to add them manually.
+ add_local_ips = FALSE;
+ if (mono_get_address_info(hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
+ add_info_ok = FALSE;
+#else
if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
add_info_ok = FALSE;
+#endif
g_free(hostname);
}
MonoBoolean
-ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
+ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gint32 hint)
{
char *address;
struct sockaddr_in saddr;
struct sockaddr_in6 saddr6;
MonoAddressInfo *info = NULL;
MonoError error;
- gint32 family, hint;
+ gint32 family;
gchar hostname [NI_MAXHOST] = { 0 };
gboolean ret;
- address = mono_string_to_utf8 (addr);
+ address = mono_string_to_utf8_checked (addr, &error);
+ if (mono_error_set_pending_exception (&error))
+ return FALSE;
if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
family = AF_INET;
g_free (address);
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
switch (family) {
case AF_INET: {
g_assert_not_reached ();
}
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
if (!ret)
return FALSE;
- hint = get_addrinfo_family_hint (&error);
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return FALSE;
- }
if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
return FALSE;
}
gboolean
-ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags)
+ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags, gint32 *werror, gboolean blocking)
{
HANDLE file;
- gint32 werror;
gboolean ret;
gboolean interrupted;
TRANSMIT_FILE_BUFFERS buffers;
/* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
- file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, &werror);
+ file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, werror);
if (file == INVALID_HANDLE_VALUE) {
- SetLastError (werror);
+ SetLastError (*werror);
return FALSE;
}
return FALSE;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
+#ifdef HOST_WIN32
+ ret = alertable_TransmitFile (sock, file, 0, 0, NULL, &buffers, flags, blocking);
+#else
ret = TransmitFile (sock, file, 0, 0, NULL, &buffers, flags);
+#endif
+
+ MONO_EXIT_GC_SAFE;
- MONO_FINISH_BLOCKING;
+ if (!ret)
+ *werror = WSAGetLastError ();
mono_thread_info_uninstall_interrupt (&interrupted);
if (interrupted) {
CloseHandle (file);
- SetLastError (WSAEINTR);
+ *werror = WSAEINTR;
return FALSE;
}
- MONO_PREPARE_BLOCKING;
+ MONO_ENTER_GC_SAFE;
CloseHandle (file);
- MONO_FINISH_BLOCKING;
+ MONO_EXIT_GC_SAFE;
+
+ if (*werror)
+ return FALSE;
return ret;
}
gboolean
-ves_icall_System_Net_Sockets_Socket_SupportPortReuse (void)
+ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
{
#if defined (SO_REUSEPORT) || defined (HOST_WIN32)
- return TRUE;
+ return TRUE;
#else
- return FALSE;
+#ifdef __linux__
+ /* Linux always supports double binding for UDP, even on older kernels. */
+ if (proto == ProtocolType_Udp)
+ return TRUE;
+#endif
+ return FALSE;
#endif
}