X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fw32socket-unix.c;h=28a5a63a5b42c892dd703e7d1f6f5a4f88d2e167;hb=ef7a4c06206976de7ef2e974267407347ddb75a4;hp=4b3d863e7462966aab904acaa4b56d3c38e2b0e1;hpb=e343ad0cfd404c92761cd6e0f683ccd46402897b;p=mono.git diff --git a/mono/metadata/w32socket-unix.c b/mono/metadata/w32socket-unix.c index 4b3d863e746..28a5a63a5b4 100644 --- a/mono/metadata/w32socket-unix.c +++ b/mono/metadata/w32socket-unix.c @@ -1,5 +1,6 @@ -/* - * w32socket-unix.c: Unix specific socket code. +/** + * \file + * Unix specific socket code. * * Copyright 2016 Microsoft * Licensed under the MIT license. See LICENSE file in the project root for full license information. @@ -11,6 +12,7 @@ #include #include #include +#include #include #ifdef HAVE_SYS_IOCTL_H #include @@ -26,7 +28,6 @@ #endif #include #include -#include #ifdef HAVE_SYS_UIO_H #include #endif @@ -45,183 +46,169 @@ #ifdef HAVE_SYS_SENDFILE_H #include #endif +#include #include "w32socket.h" #include "w32socket-internals.h" -#include "w32handle.h" +#include "w32error.h" +#include "fdhandle.h" #include "utils/mono-logger-internals.h" #include "utils/mono-poll.h" +#include "utils/mono-compiler.h" typedef struct { - int domain; - int type; - int protocol; - int saved_error; - int still_readable; -} MonoW32HandleSocket; + MonoFDHandle fdhandle; + gint domain; + gint type; + gint protocol; + gint saved_error; + gint still_readable; +} SocketHandle; + +static SocketHandle* +socket_data_create (MonoFDType type, gint fd) +{ + SocketHandle *sockethandle; -static guint32 in_cleanup = 0; + sockethandle = g_new0 (SocketHandle, 1); + mono_fdhandle_init ((MonoFDHandle*) sockethandle, type, fd); + + return sockethandle; +} static void -socket_close (gpointer handle, gpointer data) +socket_data_close (MonoFDHandle *fdhandle) { - int ret; - MonoW32HandleSocket *socket_handle = (MonoW32HandleSocket *)data; - MonoThreadInfo *info = mono_thread_info_current (); + MonoThreadInfo *info; + SocketHandle* sockethandle; + gint ret; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle); + sockethandle = (SocketHandle*) fdhandle; + g_assert (sockethandle); - /* Shutdown the socket for reading, to interrupt any potential - * receives that may be blocking for data. See bug 75705. */ - shutdown (GPOINTER_TO_UINT (handle), SHUT_RD); + info = mono_thread_info_current (); - do { - ret = close (GPOINTER_TO_UINT(handle)); - } while (ret == -1 && errno == EINTR && - !mono_thread_info_is_interrupt_state (info)); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd); + /* Shutdown the socket for reading, to interrupt any potential + * receives that may be blocking for data. See bug 75705. */ + MONO_ENTER_GC_SAFE; + shutdown (((MonoFDHandle*) sockethandle)->fd, SHUT_RD); + MONO_EXIT_GC_SAFE; + +retry_close: + MONO_ENTER_GC_SAFE; + ret = close (((MonoFDHandle*) sockethandle)->fd); + MONO_EXIT_GC_SAFE; if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: close error: %s", __func__, g_strerror (errno)); - if (!in_cleanup) - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + if (errno == EINTR && !mono_thread_info_is_interrupt_state (info)) + goto retry_close; } - if (!in_cleanup) - socket_handle->saved_error = 0; + sockethandle->saved_error = 0; } static void -socket_details (gpointer data) +socket_data_destroy (MonoFDHandle *fdhandle) { - /* FIXME: do something */ -} + SocketHandle *sockethandle; -static const gchar* -socket_typename (void) -{ - return "Socket"; -} + sockethandle = (SocketHandle*) fdhandle; + g_assert (sockethandle); -static gsize -socket_typesize (void) -{ - return sizeof (MonoW32HandleSocket); + g_free (sockethandle); } -static MonoW32HandleOps ops = { - socket_close, /* close */ - NULL, /* signal */ - NULL, /* own */ - NULL, /* is_owned */ - NULL, /* special_wait */ - NULL, /* prewait */ - socket_details, /* details */ - socket_typename, /* typename */ - socket_typesize, /* typesize */ -}; - void mono_w32socket_initialize (void) { - mono_w32handle_register_ops (MONO_W32HANDLE_SOCKET, &ops); -} - -static gboolean -cleanup_close (gpointer handle, gpointer data, gpointer user_data) -{ - if (mono_w32handle_get_type (handle) == MONO_W32HANDLE_SOCKET) - mono_w32handle_force_close (handle, data); + MonoFDHandleCallback socket_data_callbacks = { + .close = socket_data_close, + .destroy = socket_data_destroy + }; - return FALSE; + mono_fdhandle_register (MONO_FDTYPE_SOCKET, &socket_data_callbacks); } void mono_w32socket_cleanup (void) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: cleaning up", __func__); - - in_cleanup = 1; - mono_w32handle_foreach (cleanup_close, NULL); - in_cleanup = 0; } SOCKET mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking) { - gpointer handle; - gpointer new_handle; - MonoW32HandleSocket *socket_handle; - MonoW32HandleSocket new_socket_handle; - SOCKET new_fd; + SocketHandle *sockethandle, *accepted_socket_data; MonoThreadInfo *info; + gint accepted_fd; if (addr != NULL && *addrlen < sizeof(struct sockaddr)) { mono_w32socket_set_last_error (WSAEFAULT); return INVALID_SOCKET; } - handle = GUINT_TO_POINTER (sock); - if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); return INVALID_SOCKET; } - info = mono_thread_info_current (); - - do { - new_fd = accept (sock, addr, addrlen); - } while (new_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); - - if (new_fd == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, g_strerror(errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return INVALID_SOCKET; } - if (new_fd >= mono_w32handle_fd_reserve) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__); - - mono_w32socket_set_last_error (WSASYSCALLFAILURE); + info = mono_thread_info_current (); - close (new_fd); + do { + MONO_ENTER_GC_SAFE; + accepted_fd = accept (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); + MONO_EXIT_GC_SAFE; + } while (accepted_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); + if (accepted_fd == -1) { + gint error = mono_w32socket_convert_error (errno); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, g_strerror(errno)); + mono_w32socket_set_last_error (error); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return INVALID_SOCKET; } - new_socket_handle.domain = socket_handle->domain; - new_socket_handle.type = socket_handle->type; - new_socket_handle.protocol = socket_handle->protocol; - new_socket_handle.still_readable = 1; + accepted_socket_data = socket_data_create (MONO_FDTYPE_SOCKET, accepted_fd); + accepted_socket_data->domain = sockethandle->domain; + accepted_socket_data->type = sockethandle->type; + accepted_socket_data->protocol = sockethandle->protocol; + accepted_socket_data->still_readable = 1; - new_handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, new_fd, - &new_socket_handle); - if(new_handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating socket handle", __func__); - mono_w32socket_set_last_error (ERROR_GEN_FAILURE); - return INVALID_SOCKET; - } + mono_fdhandle_insert ((MonoFDHandle*) accepted_socket_data); - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with", - __func__, new_handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning accepted handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) accepted_socket_data)->fd)); - return new_fd; + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + return ((MonoFDHandle*) accepted_socket_data)->fd; } int mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking) { - gpointer handle; - MonoW32HandleSocket *socket_handle; + SocketHandle *sockethandle; + gint ret; - handle = GUINT_TO_POINTER (sock); - if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } - if (connect (sock, addr, addrlen) == -1) { + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + MONO_ENTER_GC_SAFE; + ret = connect (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); + MONO_EXIT_GC_SAFE; + if (ret == -1) { MonoThreadInfo *info; mono_pollfd fds; gint errnum, so_error; @@ -248,29 +235,41 @@ mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, g if (errnum != WSAEWOULDBLOCK) { /* ECONNRESET means the socket was closed by another thread */ /* Async close on mac raises ECONNABORTED. */ - socket_handle->saved_error = errnum; + sockethandle->saved_error = errnum; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } info = mono_thread_info_current (); - fds.fd = sock; + fds.fd = ((MonoFDHandle*) sockethandle)->fd; fds.events = MONO_POLLOUT; - while (mono_poll (&fds, 1, -1) == -1 && !mono_thread_info_is_interrupt_state (info)) { + for (;;) { + MONO_ENTER_GC_SAFE; + ret = mono_poll (&fds, 1, -1); + MONO_EXIT_GC_SAFE; + if (ret != -1 || mono_thread_info_is_interrupt_state (info)) + break; + if (errno != EINTR) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } } len = sizeof(so_error); - if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) { + MONO_ENTER_GC_SAFE; + ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_ERROR, &so_error, &len); + MONO_EXIT_GC_SAFE; + if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } @@ -278,16 +277,18 @@ mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, g gint errnum = mono_w32socket_convert_error (so_error); /* Need to save this socket error */ - socket_handle->saved_error = errnum; + sockethandle->saved_error = errnum; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s", __func__, g_strerror (so_error)); mono_w32socket_set_last_error (errnum); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } @@ -300,21 +301,27 @@ mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocki int mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking) { - gpointer handle; - MonoW32HandleSocket *socket_handle; + SocketHandle *sockethandle; int ret; MonoThreadInfo *info; - handle = GUINT_TO_POINTER (sock); - if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } info = mono_thread_info_current (); do { - ret = recvfrom (sock, buf, len, flags, from, fromlen); + MONO_ENTER_GC_SAFE; + ret = recvfrom (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, from, fromlen); + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == 0 && len > 0) { @@ -336,7 +343,7 @@ mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sock * still_readable != 1 then shutdown * (SHUT_RD|SHUT_RDWR) has been called locally. */ - if (socket_handle->still_readable != 1) { + if (sockethandle->still_readable != 1) { ret = -1; errno = EINTR; } @@ -346,8 +353,10 @@ mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sock gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, g_strerror(errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return ret; } @@ -374,18 +383,22 @@ msghdr_iov_free (struct msghdr *hdr) int mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking) { - MonoW32HandleSocket *socket_handle; + SocketHandle *sockethandle; MonoThreadInfo *info; - gpointer handle; gint ret; struct msghdr hdr; g_assert (overlapped == NULL); g_assert (complete == NULL); - handle = GUINT_TO_POINTER (sock); - if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } @@ -394,14 +407,16 @@ mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 wsabuf_to_msghdr (buffers, count, &hdr); do { - ret = recvmsg (sock, &hdr, *flags); + MONO_ENTER_GC_SAFE; + ret = recvmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, *flags); + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); msghdr_iov_free (&hdr); if (ret == 0) { /* see mono_w32socket_recvfrom */ - if (socket_handle->still_readable != 1) { + if (sockethandle->still_readable != 1) { ret = -1; errno = EINTR; } @@ -411,32 +426,41 @@ mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, g_strerror(errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } *received = ret; *flags = hdr.msg_flags; + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } int mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocking) { - gpointer handle; + SocketHandle *sockethandle; int ret; MonoThreadInfo *info; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } info = mono_thread_info_current (); do { - ret = send (sock, buf, len, flags); + MONO_ENTER_GC_SAFE; + ret = send (((MonoFDHandle*) sockethandle)->fd, buf, len, flags); + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1) { @@ -447,42 +471,55 @@ mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocki /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on * a blocking socket. See bug #599488 */ if (errnum == EAGAIN) { - ret = fcntl (sock, F_GETFL, 0); + MONO_ENTER_GC_SAFE; + ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0); + MONO_EXIT_GC_SAFE; if (ret != -1 && (ret & O_NONBLOCK) == 0) errnum = ETIMEDOUT; } #endif /* O_NONBLOCK */ mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return ret; } int mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking) { - gpointer handle; + SocketHandle *sockethandle; int ret; MonoThreadInfo *info; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } info = mono_thread_info_current (); do { - ret = sendto (sock, buf, len, flags, to, tolen); + MONO_ENTER_GC_SAFE; + ret = sendto (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, to, tolen); + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return ret; } @@ -491,15 +528,20 @@ mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 { struct msghdr hdr; MonoThreadInfo *info; - gpointer handle; + SocketHandle *sockethandle; gint ret; g_assert (overlapped == NULL); g_assert (complete == NULL); - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } @@ -508,7 +550,9 @@ mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 wsabuf_to_msghdr (buffers, count, &hdr); do { - ret = sendmsg (sock, &hdr, flags); + MONO_ENTER_GC_SAFE; + ret = sendmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, flags); + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); msghdr_iov_free (&hdr); @@ -517,10 +561,12 @@ mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } *sent = ret; + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } @@ -530,7 +576,7 @@ BOOL mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking) { MonoThreadInfo *info; - gpointer handle; + SocketHandle *sockethandle; gint file; gssize ret; #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) @@ -539,17 +585,24 @@ mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_B gchar *buffer; #endif - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); - return FALSE; + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; } /* Write the header */ if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) { - ret = mono_w32socket_send (sock, buffers->Head, buffers->HeadLength, 0, FALSE); - if (ret == SOCKET_ERROR) + ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Head, buffers->HeadLength, 0, FALSE); + if (ret == SOCKET_ERROR) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return FALSE; + } } info = mono_thread_info_current (); @@ -557,35 +610,44 @@ mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_B file = GPOINTER_TO_INT (file_handle); #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) + MONO_ENTER_GC_SAFE; ret = fstat (file, &statbuf); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } do { + MONO_ENTER_GC_SAFE; #ifdef __linux__ - ret = sendfile (sock, file, NULL, statbuf.st_size); + ret = sendfile (((MonoFDHandle*) sockethandle)->fd, file, NULL, statbuf.st_size); #elif defined(DARWIN) /* TODO: header/tail could be sent in the 5th argument */ /* TODO: Might not send the entire file for non-blocking sockets */ - ret = sendfile (file, sock, 0, &statbuf.st_size, NULL, 0); + ret = sendfile (file, ((MonoFDHandle*) sockethandle)->fd, 0, &statbuf.st_size, NULL, 0); #endif + MONO_EXIT_GC_SAFE; } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); #else buffer = g_malloc (SF_BUFFER_SIZE); do { do { + MONO_ENTER_GC_SAFE; ret = read (file, buffer, SF_BUFFER_SIZE); + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1 || ret == 0) break; do { - ret = send (sock, buffer, ret, 0); /* short sends? enclose this in a loop? */ + MONO_ENTER_GC_SAFE; + ret = send (((MonoFDHandle*) sockethandle)->fd, buffer, ret, 0); /* short sends? enclose this in a loop? */ + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); @@ -595,59 +657,55 @@ mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_B if (ret == -1) { gint errnum = errno; mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return FALSE; } /* Write the tail */ if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) { - ret = mono_w32socket_send (sock, buffers->Tail, buffers->TailLength, 0, FALSE); - if (ret == SOCKET_ERROR) + ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Tail, buffers->TailLength, 0, FALSE); + if (ret == SOCKET_ERROR) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return FALSE; + } } if ((flags & TF_DISCONNECT) == TF_DISCONNECT) - CloseHandle (handle); + mono_w32socket_close (((MonoFDHandle*) sockethandle)->fd); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return TRUE; } SOCKET mono_w32socket_socket (int domain, int type, int protocol) { - MonoW32HandleSocket socket_handle = {0}; - gpointer handle; - SOCKET sock; - - socket_handle.domain = domain; - socket_handle.type = type; - socket_handle.protocol = protocol; - socket_handle.still_readable = 1; - - sock = socket (domain, type, protocol); - if (sock == -1 && domain == AF_INET && type == SOCK_RAW && - protocol == 0) { - /* Retry with protocol == 4 (see bug #54565) */ - // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565 - socket_handle.protocol = 4; - sock = socket (AF_INET, SOCK_RAW, 4); - } + SocketHandle *sockethandle; + gint fd; + +retry_socket: + MONO_ENTER_GC_SAFE; + fd = socket (domain, type, protocol); + MONO_EXIT_GC_SAFE; + if (fd == -1) { + if (domain == AF_INET && type == SOCK_RAW && protocol == 0) { + /* Retry with protocol == 4 (see bug #54565) */ + // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565 + protocol = 4; + goto retry_socket; + } - if (sock == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return INVALID_SOCKET; } - if (sock >= mono_w32handle_fd_reserve) { - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big (%d >= %d)", - __func__, sock, mono_w32handle_fd_reserve); - - mono_w32socket_set_last_error (WSASYSCALLFAILURE); - close (sock); - - return INVALID_SOCKET; - } + sockethandle = socket_data_create(MONO_FDTYPE_SOCKET, fd); + sockethandle->domain = domain; + sockethandle->type = type; + sockethandle->protocol = protocol; + sockethandle->still_readable = 1; /* .net seems to set this by default for SOCK_STREAM, not for * SOCK_DGRAM (see bug #36322) @@ -667,111 +725,142 @@ mono_w32socket_socket (int domain, int type, int protocol) { int ret, true_ = 1; - ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_)); + MONO_ENTER_GC_SAFE; + ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_)); + MONO_EXIT_GC_SAFE; if (ret == -1) { - close (sock); gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + + MONO_ENTER_GC_SAFE; + close (((MonoFDHandle*) sockethandle)->fd); + MONO_EXIT_GC_SAFE; + + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return INVALID_SOCKET; } } + mono_fdhandle_insert ((MonoFDHandle*) sockethandle); - handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, sock, &socket_handle); - if (handle == INVALID_HANDLE_VALUE) { - g_warning ("%s: error creating socket handle", __func__); - mono_w32socket_set_last_error (WSASYSCALLFAILURE); - close (sock); - return INVALID_SOCKET; - } - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, handle); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd)); - return sock; + return ((MonoFDHandle*) sockethandle)->fd; } gint mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen) { - gpointer handle; + SocketHandle *sockethandle; int ret; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } - ret = bind (sock, addr, addrlen); + MONO_ENTER_GC_SAFE; + ret = bind (((MonoFDHandle*) sockethandle)->fd, addr, addrlen); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, g_strerror(errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } gint mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen) { - gpointer handle; + SocketHandle *sockethandle; gint ret; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } - ret = getpeername (sock, name, namelen); + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + MONO_ENTER_GC_SAFE; + ret = getpeername (((MonoFDHandle*) sockethandle)->fd, name, namelen); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } gint mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen) { - gpointer handle; + SocketHandle *sockethandle; gint ret; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } - ret = getsockname (sock, name, namelen); + MONO_ENTER_GC_SAFE; + ret = getsockname (((MonoFDHandle*) sockethandle)->fd, name, namelen); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } gint mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen) { - gpointer handle; + SocketHandle *sockethandle; gint ret; struct timeval tv; gpointer tmp_val; - MonoW32HandleSocket *socket_handle; - handle = GUINT_TO_POINTER (sock); - if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } @@ -782,11 +871,14 @@ mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optva *optlen = sizeof (tv); } - ret = getsockopt (sock, level, optname, tmp_val, optlen); + MONO_ENTER_GC_SAFE; + ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } @@ -798,19 +890,20 @@ mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optva if (optname == SO_ERROR) { if (*((int *)optval) != 0) { *((int *) optval) = mono_w32socket_convert_error (*((int *)optval)); - socket_handle->saved_error = *((int *)optval); + sockethandle->saved_error = *((int *)optval); } else { - *((int *)optval) = socket_handle->saved_error; + *((int *)optval) = sockethandle->saved_error; } } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } gint mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen) { - gpointer handle; + SocketHandle *sockethandle; gint ret; gpointer tmp_val; #if defined (__linux__) @@ -819,9 +912,14 @@ mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer #endif struct timeval tv; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } @@ -848,11 +946,14 @@ mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer } #endif - ret = setsockopt (sock, level, optname, tmp_val, optlen); + MONO_ENTER_GC_SAFE; + ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } @@ -862,71 +963,94 @@ mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer int type; socklen_t type_len = sizeof (type); - if (!getsockopt (sock, level, SO_TYPE, &type, &type_len)) { - if (type == SOCK_DGRAM || type == SOCK_STREAM) - setsockopt (sock, level, SO_REUSEPORT, tmp_val, optlen); + MONO_ENTER_GC_SAFE; + ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_TYPE, &type, &type_len); + MONO_EXIT_GC_SAFE; + if (!ret) { + if (type == SOCK_DGRAM || type == SOCK_STREAM) { + MONO_ENTER_GC_SAFE; + setsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_REUSEPORT, tmp_val, optlen); + MONO_EXIT_GC_SAFE; + } } } #endif + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return ret; } gint mono_w32socket_listen (SOCKET sock, gint backlog) { - gpointer handle; + SocketHandle *sockethandle; gint ret; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } - ret = listen (sock, backlog); + MONO_ENTER_GC_SAFE; + ret = listen (((MonoFDHandle*) sockethandle)->fd, backlog); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } gint mono_w32socket_shutdown (SOCKET sock, gint how) { - MonoW32HandleSocket *socket_handle; - gpointer handle; + SocketHandle *sockethandle; gint ret; - handle = GUINT_TO_POINTER (sock); - if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } if (how == SHUT_RD || how == SHUT_RDWR) - socket_handle->still_readable = 0; + sockethandle->still_readable = 0; - ret = shutdown (sock, how); + MONO_ENTER_GC_SAFE; + ret = shutdown (((MonoFDHandle*) sockethandle)->fd, how); + MONO_EXIT_GC_SAFE; if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return ret; } gint mono_w32socket_disconnect (SOCKET sock, gboolean reuse) { - MonoW32HandleSocket *socket_handle; - gpointer handle; + SocketHandle *sockethandle; SOCKET newsock; gint ret; @@ -936,17 +1060,25 @@ mono_w32socket_disconnect (SOCKET sock, gboolean reuse) * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn) * if we really wanted to */ - handle = GUINT_TO_POINTER (sock); - if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } - newsock = socket (socket_handle->domain, socket_handle->type, socket_handle->protocol); + MONO_ENTER_GC_SAFE; + newsock = socket (sockethandle->domain, sockethandle->type, sockethandle->protocol); + MONO_EXIT_GC_SAFE; if (newsock == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errnum)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } @@ -955,32 +1087,46 @@ mono_w32socket_disconnect (SOCKET sock, gboolean reuse) * should not be a race condition between the old fd being * closed and the new socket fd being copied over */ do { - ret = dup2 (newsock, sock); + MONO_ENTER_GC_SAFE; + ret = dup2 (newsock, ((MonoFDHandle*) sockethandle)->fd); + MONO_EXIT_GC_SAFE; } while (ret == -1 && errno == EAGAIN); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dup2 error: %s", __func__, g_strerror (errnum)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + MONO_ENTER_GC_SAFE; close (newsock); + MONO_EXIT_GC_SAFE; + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } static gboolean extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved) { - return mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0; + gboolean ret; + MONO_ENTER_GC_UNSAFE; + ret = mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0; + MONO_EXIT_GC_UNSAFE; + return ret; } static gboolean extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send, OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags) { - return mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE); + gboolean ret; + MONO_ENTER_GC_UNSAFE; + ret = mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE); + MONO_EXIT_GC_UNSAFE; + return ret; } static struct { @@ -995,13 +1141,18 @@ static struct { gint mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written) { - gpointer handle; + SocketHandle *sockethandle; gint ret; gchar *buffer; - handle = GUINT_TO_POINTER (sock); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } @@ -1014,18 +1165,21 @@ mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, * actually set an error here... */ mono_w32socket_set_last_error (WSAEINVAL); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } if (outputlen < sizeof(gpointer)) { /* Or here... */ mono_w32socket_set_last_error (WSAEINVAL); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } if (output == NULL) { /* Or here */ mono_w32socket_set_last_error (WSAEINVAL); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } @@ -1034,11 +1188,13 @@ mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) { memcpy (output, &extension_functions[i].func, sizeof(gpointer)); *written = sizeof(gpointer); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } } mono_w32socket_set_last_error (WSAEINVAL); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } @@ -1047,14 +1203,18 @@ mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, if (inputlen < 3 * sizeof (guint32)) { mono_w32socket_set_last_error (WSAEINVAL); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } onoff = *((guint32*) input); - ret = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32)); + MONO_ENTER_GC_SAFE; + ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32)); + MONO_EXIT_GC_SAFE; if (ret < 0) { mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } @@ -1071,40 +1231,51 @@ mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, keepalivetime /= 1000; if (keepalivetime == 0 || rem >= 500) keepalivetime++; - ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32)); + MONO_ENTER_GC_SAFE; + ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32)); + MONO_EXIT_GC_SAFE; if (ret == 0) { rem = keepaliveinterval % 1000; keepaliveinterval /= 1000; if (keepaliveinterval == 0 || rem >= 500) keepaliveinterval++; - ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32)); + MONO_ENTER_GC_SAFE; + ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32)); + MONO_EXIT_GC_SAFE; } if (ret != 0) { mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } #endif + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL; - ret = ioctl (sock, command, buffer); + MONO_ENTER_GC_SAFE; + ret = ioctl (((MonoFDHandle*) sockethandle)->fd, command, buffer); + MONO_EXIT_GC_SAFE; if (ret == -1) { g_free (buffer); gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } if (!buffer) { *written = 0; + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } @@ -1120,53 +1291,90 @@ mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, g_free (buffer); *written = inputlen; + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } +gboolean +mono_w32socket_close (SOCKET sock) +{ + if (!mono_fdhandle_close (sock)) { + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + return TRUE; +} + gint -mono_w32socket_set_blocking (SOCKET socket, gboolean blocking) +mono_w32socket_set_blocking (SOCKET sock, gboolean blocking) { +#ifdef O_NONBLOCK + SocketHandle *sockethandle; gint ret; - gpointer handle; - handle = GINT_TO_POINTER (socket); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } -#ifdef O_NONBLOCK /* This works better than ioctl(...FIONBIO...) * on Linux (it causes connect to return * EINPROGRESS, but the ioctl doesn't seem to) */ - ret = fcntl (socket, F_GETFL, 0); - if (ret != -1) - ret = fcntl (socket, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK))); -#endif /* O_NONBLOCK */ + MONO_ENTER_GC_SAFE; + ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0); + MONO_EXIT_GC_SAFE; + if (ret == -1) { + gint errnum = mono_w32socket_convert_error (errno); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno)); + mono_w32socket_set_last_error (errnum); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + return SOCKET_ERROR; + } + MONO_ENTER_GC_SAFE; + ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK))); + MONO_EXIT_GC_SAFE; if (ret == -1) { - gint errnum = errno; - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + gint errnum = mono_w32socket_convert_error (errno); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno)); + mono_w32socket_set_last_error (errnum); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; +#else + mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED); + return SOCKET_ERROR; +#endif /* O_NONBLOCK */ } gint -mono_w32socket_get_available (SOCKET socket, guint64 *amount) +mono_w32socket_get_available (SOCKET sock, guint64 *amount) { + SocketHandle *sockethandle; gint ret; - gpointer handle; - handle = GINT_TO_POINTER (socket); - if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { - mono_w32socket_set_last_error (WSAENOTSOCK); + if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (WSAENOTSOCK); return SOCKET_ERROR; } -#if defined (PLATFORM_MACOSX) +#if defined (HOST_DARWIN) // ioctl (socket, FIONREAD, XXX) returns the size of // the UDP header as well on Darwin. // @@ -1178,31 +1386,43 @@ mono_w32socket_get_available (SOCKET socket, guint64 *amount) // the ip buffer. socklen_t optlen = sizeof (int); - ret = getsockopt (socket, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen); + MONO_ENTER_GC_SAFE; + ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen); + MONO_EXIT_GC_SAFE; + if (ret == -1) { + gint errnum = mono_w32socket_convert_error (errno); + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__, g_strerror (errno)); + mono_w32socket_set_last_error (errnum); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + return SOCKET_ERROR; + } #else - ret = ioctl (socket, FIONREAD, (gulong*) amount); -#endif - + MONO_ENTER_GC_SAFE; + ret = ioctl (((MonoFDHandle*) sockethandle)->fd, FIONREAD, (gulong*) amount); + MONO_EXIT_GC_SAFE; if (ret == -1) { - gint errnum = errno; + gint errnum = mono_w32socket_convert_error (errno); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno)); - mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); + mono_w32socket_set_last_error (errnum); + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return SOCKET_ERROR; } +#endif + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); return 0; } void mono_w32socket_set_last_error (gint32 error) { - SetLastError (error); + mono_w32error_set_last (error); } gint32 mono_w32socket_get_last_error (void) { - return GetLastError (); + return mono_w32error_get_last (); } gint32 @@ -1310,14 +1530,21 @@ mono_w32socket_convert_error (gint error) case ENETDOWN: return WSAENETDOWN; #endif case ENODEV: return WSAENETDOWN; +#ifdef EPROTOTYPE + case EPROTOTYPE: return WSAEPROTOTYPE; +#endif +#ifdef ENXIO + case ENXIO: return WSAENXIO; +#endif default: g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error)); } } gboolean -ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto) +ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto, MonoError *error) { + error_init (error); #if defined (SO_REUSEPORT) return TRUE; #else @@ -1329,3 +1556,23 @@ ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto) return FALSE; #endif } + +gboolean +mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle) +{ + SocketHandle *sockethandle; + + if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle), (MonoFDHandle**) &sockethandle)) { + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) { + mono_fdhandle_unref ((MonoFDHandle*) sockethandle); + mono_w32error_set_last (ERROR_INVALID_HANDLE); + return FALSE; + } + + *duplicate_handle = handle; + return TRUE; +}