io-trace.h \
io-layer.h \
io-portability.h \
- sockets.h \
uglify.h \
wapi.h \
wapi-remap.h
io-layer.h \
locking.c \
posix.c \
- sockets.c \
- sockets.h \
- socket-private.h \
- socket-wrappers.h \
uglify.h \
wapi_glob.h \
wapi_glob.c \
g_assert (ret == 0);
}
-guint32
-errno_to_WSA (guint32 code, const gchar *function_name)
-{
- gint result = -1;
- char *sys_error;
- gchar *msg;
-
- switch (code) {
- case 0: result = ERROR_SUCCESS; break;
- case EACCES: result = WSAEACCES; break;
-#ifdef EADDRINUSE
- case EADDRINUSE: result = WSAEADDRINUSE; break;
-#endif
-#ifdef EAFNOSUPPORT
- case EAFNOSUPPORT: result = WSAEAFNOSUPPORT; break;
-#endif
-#if EAGAIN != EWOULDBLOCK
- case EAGAIN: result = WSAEWOULDBLOCK; break;
-#endif
-#ifdef EALREADY
- case EALREADY: result = WSAEALREADY; break;
-#endif
- case EBADF: result = WSAENOTSOCK; break;
-#ifdef ECONNABORTED
- case ECONNABORTED: result = WSAENETDOWN; break;
-#endif
-#ifdef ECONNREFUSED
- case ECONNREFUSED: result = WSAECONNREFUSED; break;
-#endif
-#ifdef ECONNRESET
- case ECONNRESET: result = WSAECONNRESET; break;
-#endif
- case EFAULT: result = WSAEFAULT; break;
-#ifdef EHOSTUNREACH
- case EHOSTUNREACH: result = WSAEHOSTUNREACH; break;
-#endif
-#ifdef EINPROGRESS
- case EINPROGRESS: result = WSAEINPROGRESS; break;
-#endif
- case EINTR: result = WSAEINTR; break;
- case EINVAL: result = WSAEINVAL; break;
- /*FIXME: case EIO: result = WSAE????; break; */
-#ifdef EISCONN
- case EISCONN: result = WSAEISCONN; break;
-#endif
- /* FIXME: case ELOOP: result = WSA????; break; */
- case EMFILE: result = WSAEMFILE; break;
-#ifdef EMSGSIZE
- case EMSGSIZE: result = WSAEMSGSIZE; break;
-#endif
- /* FIXME: case ENAMETOOLONG: result = WSAEACCES; break; */
-#ifdef ENETUNREACH
- case ENETUNREACH: result = WSAENETUNREACH; break;
-#endif
-#ifdef ENOBUFS
- case ENOBUFS: result = WSAENOBUFS; break; /* not documented */
-#endif
- /* case ENOENT: result = WSAE????; break; */
- case ENOMEM: result = WSAENOBUFS; break;
-#ifdef ENOPROTOOPT
- case ENOPROTOOPT: result = WSAENOPROTOOPT; break;
-#endif
-#ifdef ENOSR
- case ENOSR: result = WSAENETDOWN; break;
-#endif
-#ifdef ENOTCONN
- case ENOTCONN: result = WSAENOTCONN; break;
-#endif
- /*FIXME: case ENOTDIR: result = WSAE????; break; */
-#ifdef ENOTSOCK
- case ENOTSOCK: result = WSAENOTSOCK; break;
-#endif
- case ENOTTY: result = WSAENOTSOCK; break;
-#ifdef EOPNOTSUPP
- case EOPNOTSUPP: result = WSAEOPNOTSUPP; break;
-#endif
- case EPERM: result = WSAEACCES; break;
- case EPIPE: result = WSAESHUTDOWN; break;
-#ifdef EPROTONOSUPPORT
- case EPROTONOSUPPORT: result = WSAEPROTONOSUPPORT; break;
-#endif
-#if ERESTARTSYS
- case ERESTARTSYS: result = WSAENETDOWN; break;
-#endif
- /*FIXME: case EROFS: result = WSAE????; break; */
-#ifdef ESOCKTNOSUPPORT
- case ESOCKTNOSUPPORT: result = WSAESOCKTNOSUPPORT; break;
-#endif
-#ifdef ETIMEDOUT
- case ETIMEDOUT: result = WSAETIMEDOUT; break;
-#endif
-#ifdef EWOULDBLOCK
- case EWOULDBLOCK: result = WSAEWOULDBLOCK; break;
-#endif
-#ifdef EADDRNOTAVAIL
- case EADDRNOTAVAIL: result = WSAEADDRNOTAVAIL; break;
-#endif
- /* This might happen with unix sockets */
- case ENOENT: result = WSAECONNREFUSED; break;
-#ifdef EDESTADDRREQ
- case EDESTADDRREQ: result = WSAEDESTADDRREQ; break;
-#endif
-#ifdef EHOSTDOWN
- case EHOSTDOWN: result = WSAEHOSTDOWN; break;
-#endif
-#ifdef ENETDOWN
- case ENETDOWN: result = WSAENETDOWN; break;
-#endif
- case ENODEV: result = WSAENETDOWN; break;
- default:
- sys_error = strerror (code);
- msg = g_locale_to_utf8 (sys_error, strlen (sys_error), NULL, NULL, NULL);
- if (function_name == NULL)
- function_name = __func__;
-
- g_warning ("%s: Need to translate %d [%s] into winsock error",
- function_name, code, msg);
-
- g_free (msg);
- result = WSASYSCALLFAILURE;
- }
-
- return result;
-}
-
gint
_wapi_get_win32_file_error (gint err)
{
guint32 GetLastError (void);
void SetLastError (guint32 code);
-guint32 errno_to_WSA (guint32 code, const char *function_name);
gint _wapi_get_win32_file_error (gint err);
void _wapi_error_cleanup (void);
+++ /dev/null
-/*
- * socket-private.h: Private definitions for socket handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- */
-
-#ifndef _WAPI_SOCKET_PRIVATE_H_
-#define _WAPI_SOCKET_PRIVATE_H_
-
-#include <config.h>
-#include <glib.h>
-
-#include "wapi-private.h"
-
-struct _WapiHandle_socket
-{
- int domain;
- int type;
- int protocol;
- int saved_error;
- int still_readable;
-};
-
-void
-_wapi_socket_init (void);
-
-#endif /* _WAPI_SOCKET_PRIVATE_H_ */
+++ /dev/null
-/*
- * Special header file to be included only in selected C files.
- * We need to use the _wapi_ equivalents of the socket API when
- * working with io-layer handles. On windows we define the wrappers to use
- * the normal win32 functions.
- */
-
-#include <config.h>
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-# include <sys/socket.h>
-#endif
-
-#ifndef HAVE_SOCKLEN_T
-#define socklen_t int
-#endif
-
-#ifdef HOST_WIN32
-#define _wapi_accept accept
-#define _wapi_bind bind
-#define _wapi_connect connect
-#define _wapi_getpeername getpeername
-#define _wapi_getsockname getsockname
-#define _wapi_getsockopt getsockopt
-#define _wapi_listen listen
-#define _wapi_recv recv
-#define _wapi_recvfrom recvfrom
-#define _wapi_send send
-#define _wapi_sendto sendto
-#define _wapi_setsockopt setsockopt
-#define _wapi_shutdown shutdown
-#define _wapi_socket WSASocket
-#define _wapi_select select
-
-/* No need to wrap FD_ZERO because it doesnt involve file
- * descriptors
-*/
-#define _wapi_FD_CLR FD_CLR
-#define _wapi_FD_ISSET FD_ISSET
-#define _wapi_FD_SET FD_SET
-
-#define _wapi_cleanup_networking() ;
-#else
-
-#define WSA_FLAG_OVERLAPPED 0x01
-
-extern guint32 _wapi_accept(guint32 handle, struct sockaddr *addr,
- socklen_t *addrlen);
-extern int _wapi_bind(guint32 handle, struct sockaddr *my_addr,
- socklen_t addrlen);
-extern int _wapi_connect(guint32 handle, const struct sockaddr *serv_addr,
- socklen_t addrlen);
-extern int _wapi_getpeername(guint32 handle, struct sockaddr *name,
- socklen_t *namelen);
-extern int _wapi_getsockname(guint32 handle, struct sockaddr *name,
- socklen_t *namelen);
-extern int _wapi_getsockopt(guint32 handle, int level, int optname,
- void *optval, socklen_t *optlen);
-extern int _wapi_listen(guint32 handle, int backlog);
-extern int _wapi_recv(guint32 handle, void *buf, size_t len, int recv_flags);
-extern int _wapi_recvfrom(guint32 handle, void *buf, size_t len,
- int recv_flags, struct sockaddr *from,
- socklen_t *fromlen);
-extern int _wapi_send(guint32 handle, const void *msg, size_t len,
- int send_flags);
-extern int _wapi_sendto(guint32 handle, const void *msg, size_t len,
- int send_flags, const struct sockaddr *to,
- socklen_t tolen);
-extern int _wapi_setsockopt(guint32 handle, int level, int optname,
- const void *optval, socklen_t optlen);
-extern int _wapi_shutdown(guint32 handle, int how);
-extern guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
- guint32 unused2, guint32 flags);
-
-#ifdef HAVE_SYS_SELECT_H
-extern int _wapi_select(int nfds, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds, struct timeval *timeout);
-
-extern void _wapi_FD_CLR(guint32 handle, fd_set *set);
-extern int _wapi_FD_ISSET(guint32 handle, fd_set *set);
-extern void _wapi_FD_SET(guint32 handle, fd_set *set);
-#endif
-
-extern void _wapi_cleanup_networking (void);
-#endif /* HOST_WIN32 */
-
+++ /dev/null
-/*
- * sockets.c: Socket handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- */
-
-#include <config.h>
-
-#ifndef DISABLE_SOCKETS
-
-#include <glib.h>
-#include <pthread.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#ifdef HAVE_SYS_UIO_H
-# include <sys/uio.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-# include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_FILIO_H
-#include <sys/filio.h> /* defines FIONBIO and FIONREAD */
-#endif
-#ifdef HAVE_SYS_SOCKIO_H
-#include <sys/sockio.h> /* defines SIOCATMARK */
-#endif
-#include <unistd.h>
-#include <fcntl.h>
-
-#ifndef HAVE_MSG_NOSIGNAL
-#include <signal.h>
-#endif
-
-#include <mono/io-layer/wapi.h>
-#include <mono/io-layer/wapi-private.h>
-#include <mono/io-layer/socket-private.h>
-#include <mono/io-layer/socket-wrappers.h>
-#include <mono/io-layer/io-trace.h>
-#include <mono/utils/mono-poll.h>
-#include <mono/utils/mono-once.h>
-#include <mono/utils/mono-logger-internals.h>
-#include <mono/metadata/w32handle.h>
-
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#ifdef HAVE_SYS_SENDFILE_H
-#include <sys/sendfile.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-
-static guint32 in_cleanup = 0;
-
-static void socket_close (gpointer handle, gpointer data);
-static void socket_details (gpointer data);
-static const gchar* socket_typename (void);
-static gsize socket_typesize (void);
-
-static MonoW32HandleOps _wapi_socket_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
-_wapi_socket_init (void)
-{
- mono_w32handle_register_ops (MONO_W32HANDLE_SOCKET, &_wapi_socket_ops);
-}
-
-static void socket_close (gpointer handle, gpointer data)
-{
- int ret;
- struct _WapiHandle_socket *socket_handle = (struct _WapiHandle_socket *)data;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle);
-
- /* 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);
-
- do {
- ret = close (GPOINTER_TO_UINT(handle));
- } 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: close error: %s", __func__, strerror (errno));
- errnum = errno_to_WSA (errnum, __func__);
- if (!in_cleanup)
- WSASetLastError (errnum);
- }
-
- if (!in_cleanup)
- socket_handle->saved_error = 0;
-}
-
-static void socket_details (gpointer data)
-{
- /* FIXME: do something */
-}
-
-static const gchar* socket_typename (void)
-{
- return "Socket";
-}
-
-static gsize socket_typesize (void)
-{
- return sizeof (struct _WapiHandle_socket);
-}
-
-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);
-
- return FALSE;
-}
-
-void _wapi_cleanup_networking(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;
-}
-
-void WSASetLastError(int error)
-{
- SetLastError (error);
-}
-
-int WSAGetLastError(void)
-{
- return(GetLastError ());
-}
-
-int closesocket(guint32 fd)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(0);
- }
-
- mono_w32handle_unref (handle);
- return(0);
-}
-
-guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- gpointer new_handle;
- struct _WapiHandle_socket *socket_handle;
- struct _WapiHandle_socket new_socket_handle = {0};
- gboolean ok;
- int new_fd;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
- WSASetLastError (WSAEFAULT);
- return(INVALID_SOCKET);
- }
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(INVALID_SOCKET);
- }
-
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE) {
- g_warning ("%s: error looking up socket handle %p",
- __func__, handle);
- WSASetLastError (WSAENOTSOCK);
- return(INVALID_SOCKET);
- }
-
- do {
- new_fd = accept (fd, 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__, strerror(errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- 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__);
-
- WSASetLastError (WSASYSCALLFAILURE);
-
- close (new_fd);
-
- 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;
-
- 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__);
- WSASetLastError (ERROR_GEN_FAILURE);
- return(INVALID_SOCKET);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with",
- __func__, new_handle);
-
- return(new_fd);
-}
-
-int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- ret = bind (fd, my_addr, addrlen);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, strerror(errno));
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
- return(ret);
-}
-
-int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
- socklen_t addrlen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- struct _WapiHandle_socket *socket_handle;
- gboolean ok;
- gint errnum;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- if (connect (fd, serv_addr, addrlen) == -1) {
- mono_pollfd fds;
- int so_error;
- socklen_t len;
-
- errnum = errno;
-
- if (errno != EINTR) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__,
- strerror (errnum));
-
- errnum = errno_to_WSA (errnum, __func__);
- if (errnum == WSAEINPROGRESS)
- errnum = WSAEWOULDBLOCK; /* see bug #73053 */
-
- WSASetLastError (errnum);
-
- /*
- * On solaris x86 getsockopt (SO_ERROR) is not set after
- * connect () fails so we need to save this error.
- *
- * But don't do this for EWOULDBLOCK (bug 317315)
- */
- if (errnum != WSAEWOULDBLOCK) {
- ok = mono_w32handle_lookup (handle,
- MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE) {
- /* ECONNRESET means the socket was closed by another thread */
- /* Async close on mac raises ECONNABORTED. */
- if (errnum != WSAECONNRESET && errnum != WSAENETDOWN)
- g_warning ("%s: error looking up socket handle %p (error %d)", __func__, handle, errnum);
- } else {
- socket_handle->saved_error = errnum;
- }
- }
- return(SOCKET_ERROR);
- }
-
- fds.fd = fd;
- fds.events = MONO_POLLOUT;
- while (mono_poll (&fds, 1, -1) == -1 &&
- !mono_thread_info_is_interrupt_state (info)) {
- if (errno != EINTR) {
- errnum = errno_to_WSA (errno, __func__);
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s",
- __func__, strerror (errno));
-
- WSASetLastError (errnum);
- return(SOCKET_ERROR);
- }
- }
-
- len = sizeof(so_error);
- if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &so_error,
- &len) == -1) {
- errnum = errno_to_WSA (errno, __func__);
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s",
- __func__, strerror (errno));
-
- WSASetLastError (errnum);
- return(SOCKET_ERROR);
- }
-
- if (so_error != 0) {
- errnum = errno_to_WSA (so_error, __func__);
-
- /* Need to save this socket error */
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE) {
- g_warning ("%s: error looking up socket handle %p", __func__, handle);
- } else {
- socket_handle->saved_error = errnum;
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s",
- __func__, strerror (so_error));
-
- WSASetLastError (errnum);
- return(SOCKET_ERROR);
- }
- }
-
- return(0);
-}
-
-int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- ret = getpeername (fd, name, namelen);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__,
- strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
- return(ret);
-}
-
-int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- ret = getsockname (fd, name, namelen);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__,
- strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
- return(ret);
-}
-
-int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
- socklen_t *optlen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
- struct timeval tv;
- void *tmp_val;
- struct _WapiHandle_socket *socket_handle;
- gboolean ok;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- tmp_val = optval;
- if (level == SOL_SOCKET &&
- (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
- tmp_val = &tv;
- *optlen = sizeof (tv);
- }
-
- ret = getsockopt (fd, level, optname, tmp_val, optlen);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__,
- strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
- if (level == SOL_SOCKET &&
- (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
- *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
- *optlen = sizeof (int);
- }
-
- if (optname == SO_ERROR) {
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE) {
- g_warning ("%s: error looking up socket handle %p",
- __func__, handle);
-
- /* can't extract the last error */
- *((int *) optval) = errno_to_WSA (*((int *)optval),
- __func__);
- } else {
- if (*((int *)optval) != 0) {
- *((int *) optval) = errno_to_WSA (*((int *)optval),
- __func__);
- socket_handle->saved_error = *((int *)optval);
- } else {
- *((int *)optval) = socket_handle->saved_error;
- }
- }
- }
-
- return(ret);
-}
-
-int _wapi_listen(guint32 fd, int backlog)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- ret = listen (fd, backlog);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
- return(0);
-}
-
-int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
-{
- return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
-}
-
-int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
- struct sockaddr *from, socklen_t *fromlen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- struct _WapiHandle_socket *socket_handle;
- gboolean ok;
- int ret;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- do {
- ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
- } while (ret == -1 && errno == EINTR &&
- !mono_thread_info_is_interrupt_state (info));
-
- if (ret == 0 && len > 0) {
- /* According to the Linux man page, recvfrom only
- * returns 0 when the socket has been shut down
- * cleanly. Turn this into an EINTR to simulate win32
- * behaviour of returning EINTR when a socket is
- * closed while the recvfrom is blocking (we use a
- * shutdown() in socket_close() to trigger this.) See
- * bug 75705.
- */
- /* Distinguish between the socket being shut down at
- * the local or remote ends, and reads that request 0
- * bytes to be read
- */
-
- /* If this returns FALSE, it means the socket has been
- * closed locally. If it returns TRUE, but
- * still_readable != 1 then shutdown
- * (SHUT_RD|SHUT_RDWR) has been called locally.
- */
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE || socket_handle->still_readable != 1) {
- ret = -1;
- errno = EINTR;
- }
- }
-
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, strerror(errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
- return(ret);
-}
-
-static int
-_wapi_recvmsg(guint32 fd, struct msghdr *msg, int recv_flags)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- struct _WapiHandle_socket *socket_handle;
- gboolean ok;
- int ret;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- do {
- ret = recvmsg (fd, msg, recv_flags);
- } while (ret == -1 && errno == EINTR &&
- !mono_thread_info_is_interrupt_state (info));
-
- if (ret == 0) {
- /* see _wapi_recvfrom */
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE || socket_handle->still_readable != 1) {
- ret = -1;
- errno = EINTR;
- }
- }
-
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, strerror(errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
- return(ret);
-}
-
-int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- do {
- ret = send (fd, msg, len, send_flags);
- } 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__, strerror (errno));
-
-#ifdef O_NONBLOCK
- /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
- * a blocking socket. See bug #599488 */
- if (errnum == EAGAIN) {
- ret = fcntl (fd, F_GETFL, 0);
- if (ret != -1 && (ret & O_NONBLOCK) == 0)
- errnum = ETIMEDOUT;
- }
-#endif /* O_NONBLOCK */
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
- return(ret);
-}
-
-int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
- const struct sockaddr *to, socklen_t tolen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- do {
- ret = sendto (fd, msg, len, send_flags, to, tolen);
- } 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__, strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
- return(ret);
-}
-
-static int
-_wapi_sendmsg(guint32 fd, const struct msghdr *msg, int send_flags)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- do {
- ret = sendmsg (fd, msg, send_flags);
- } 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: sendmsg error: %s", __func__, strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
- return(ret);
-}
-
-int _wapi_setsockopt(guint32 fd, int level, int optname,
- const void *optval, socklen_t optlen)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
- const void *tmp_val;
-#if defined (__linux__)
- /* This has its address taken so it cannot be moved to the if block which uses it */
- int bufsize = 0;
-#endif
- struct timeval tv;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- tmp_val = optval;
- if (level == SOL_SOCKET &&
- (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
- int ms = *((int *) optval);
- tv.tv_sec = ms / 1000;
- tv.tv_usec = (ms % 1000) * 1000; // micro from milli
- tmp_val = &tv;
- optlen = sizeof (tv);
- }
-#if defined (__linux__)
- else if (level == SOL_SOCKET &&
- (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
- /* According to socket(7) the Linux kernel doubles the
- * buffer sizes "to allow space for bookkeeping
- * overhead."
- */
- bufsize = *((int *) optval);
-
- bufsize /= 2;
- tmp_val = &bufsize;
- }
-#endif
-
- ret = setsockopt (fd, level, optname, tmp_val, optlen);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__,
- strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
-#if defined (SO_REUSEPORT)
- /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
- if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
- int type;
- socklen_t type_len = sizeof (type);
-
- if (!getsockopt (fd, level, SO_TYPE, &type, &type_len)) {
- if (type == SOCK_DGRAM || type == SOCK_STREAM)
- setsockopt (fd, level, SO_REUSEPORT, tmp_val, optlen);
- }
- }
-#endif
-
- return(ret);
-}
-
-int _wapi_shutdown(guint32 fd, int how)
-{
- struct _WapiHandle_socket *socket_handle;
- gboolean ok;
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- if (how == SHUT_RD ||
- how == SHUT_RDWR) {
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE) {
- g_warning ("%s: error looking up socket handle %p",
- __func__, handle);
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- socket_handle->still_readable = 0;
- }
-
- ret = shutdown (fd, how);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__,
- strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
- return(ret);
-}
-
-guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
- guint32 unused2, guint32 unused3)
-{
- struct _WapiHandle_socket socket_handle = {0};
- gpointer handle;
- int fd;
-
- socket_handle.domain = domain;
- socket_handle.type = type;
- socket_handle.protocol = protocol;
- socket_handle.still_readable = 1;
-
- fd = socket (domain, type, protocol);
- if (fd == -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;
- fd = socket (AF_INET, SOCK_RAW, 4);
- }
-
- if (fd == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, strerror (errno));
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(INVALID_SOCKET);
- }
-
- if (fd >= mono_w32handle_fd_reserve) {
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big (%d >= %d)",
- __func__, fd, mono_w32handle_fd_reserve);
-
- WSASetLastError (WSASYSCALLFAILURE);
- close (fd);
-
- return(INVALID_SOCKET);
- }
-
- /* .net seems to set this by default for SOCK_STREAM, not for
- * SOCK_DGRAM (see bug #36322)
- * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
- *
- * It seems winsock has a rather different idea of what
- * SO_REUSEADDR means. If it's set, then a new socket can be
- * bound over an existing listening socket. There's a new
- * windows-specific option called SO_EXCLUSIVEADDRUSE but
- * using that means the socket MUST be closed properly, or a
- * denial of service can occur. Luckily for us, winsock
- * behaves as though any other system would when SO_REUSEADDR
- * is true, so we don't need to do anything else here. See
- * bug 53992.
- * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
- */
- {
- int ret, true_ = 1;
-
- ret = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &true_,
- sizeof (true_));
- if (ret == -1) {
- int errnum = errno;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__);
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- close (fd);
-
- return(INVALID_SOCKET);
- }
- }
-
-
- handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, fd, &socket_handle);
- if (handle == INVALID_HANDLE_VALUE) {
- g_warning ("%s: error creating socket handle", __func__);
- WSASetLastError (WSASYSCALLFAILURE);
- close (fd);
- return(INVALID_SOCKET);
- }
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, handle);
-
- return(fd);
-}
-
-static gboolean socket_disconnect (guint32 fd)
-{
- struct _WapiHandle_socket *socket_handle;
- gboolean ok;
- gpointer handle = GUINT_TO_POINTER (fd);
- int newsock, ret;
-
- ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET,
- (gpointer *)&socket_handle);
- if (ok == FALSE) {
- g_warning ("%s: error looking up socket handle %p", __func__,
- handle);
- WSASetLastError (WSAENOTSOCK);
- return(FALSE);
- }
-
- newsock = socket (socket_handle->domain, socket_handle->type,
- socket_handle->protocol);
- if (newsock == -1) {
- gint errnum = errno;
-
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(FALSE);
- }
-
- /* According to Stevens "Advanced Programming in the UNIX
- * Environment: UNIX File I/O" dup2() is atomic so there
- * should not be a race condition between the old fd being
- * closed and the new socket fd being copied over
- */
- do {
- ret = dup2 (newsock, fd);
- } 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__, strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(FALSE);
- }
-
- close (newsock);
-
- return(TRUE);
-}
-
-static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped,
- guint32 flags, guint32 reserved)
-{
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, fd);
-
- if (reserved != 0) {
- WSASetLastError (WSAEINVAL);
- return(FALSE);
- }
-
- /* We could check the socket type here and fail unless its
- * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
- * if we really wanted to
- */
-
- return(socket_disconnect (fd));
-}
-
-#define SF_BUFFER_SIZE 16384
-static gint
-wapi_sendfile (guint32 socket, gpointer fd, guint32 bytes_to_write, guint32 bytes_per_send, guint32 flags)
-{
- MonoThreadInfo *info = mono_thread_info_current ();
-#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
- gint file = GPOINTER_TO_INT (fd);
- gint n;
- gint errnum;
- gssize res;
- struct stat statbuf;
-
- n = fstat (file, &statbuf);
- if (n == -1) {
- errnum = errno;
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
- return SOCKET_ERROR;
- }
- do {
-#ifdef __linux__
- res = sendfile (socket, 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 */
- res = sendfile (file, socket, 0, &statbuf.st_size, NULL, 0);
-#endif
- } while (res != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
- if (res == -1) {
- errnum = errno;
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
- return SOCKET_ERROR;
- }
-#else
- /* Default implementation */
- gint file = GPOINTER_TO_INT (fd);
- gchar *buffer;
- gint n;
-
- buffer = g_malloc (SF_BUFFER_SIZE);
- do {
- do {
- n = read (file, buffer, SF_BUFFER_SIZE);
- } while (n == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
- if (n == -1)
- break;
- if (n == 0) {
- g_free (buffer);
- return 0; /* We're done reading */
- }
- do {
- n = send (socket, buffer, n, 0); /* short sends? enclose this in a loop? */
- } while (n == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
- } while (n != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
-
- if (n == -1) {
- gint errnum = errno;
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
- g_free (buffer);
- return SOCKET_ERROR;
- }
- g_free (buffer);
-#endif
- return 0;
-}
-
-gboolean
-TransmitFile (guint32 socket, gpointer file, guint32 bytes_to_write, guint32 bytes_per_send, WapiOverlapped *ol,
- WapiTransmitFileBuffers *buffers, guint32 flags)
-{
- gpointer sock = GUINT_TO_POINTER (socket);
- gint ret;
-
- if (mono_w32handle_get_type (sock) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return FALSE;
- }
-
- /* Write the header */
- if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
- ret = _wapi_send (socket, buffers->Head, buffers->HeadLength, 0);
- if (ret == SOCKET_ERROR)
- return FALSE;
- }
-
- ret = wapi_sendfile (socket, file, bytes_to_write, bytes_per_send, flags);
- if (ret == SOCKET_ERROR)
- return FALSE;
-
- /* Write the tail */
- if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
- ret = _wapi_send (socket, buffers->Tail, buffers->TailLength, 0);
- if (ret == SOCKET_ERROR)
- return FALSE;
- }
-
- if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
- closesocket (socket);
-
- return TRUE;
-}
-
-static struct
-{
- WapiGuid guid;
- gpointer func;
-} extension_functions[] = {
- {WSAID_DISCONNECTEX, wapi_disconnectex},
- {WSAID_TRANSMITFILE, TransmitFile},
- {{0}, NULL},
-};
-
-int
-WSAIoctl (guint32 fd, gint32 command,
- gchar *input, gint i_len,
- gchar *output, gint o_len, glong *written,
- void *unused1, void *unused2)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
- gchar *buffer = NULL;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return SOCKET_ERROR;
- }
-
- if (command == SIO_GET_EXTENSION_FUNCTION_POINTER) {
- int i = 0;
- WapiGuid *guid = (WapiGuid *)input;
-
- if (i_len < sizeof(WapiGuid)) {
- /* As far as I can tell, windows doesn't
- * actually set an error here...
- */
- WSASetLastError (WSAEINVAL);
- return(SOCKET_ERROR);
- }
-
- if (o_len < sizeof(gpointer)) {
- /* Or here... */
- WSASetLastError (WSAEINVAL);
- return(SOCKET_ERROR);
- }
-
- if (output == NULL) {
- /* Or here */
- WSASetLastError (WSAEINVAL);
- return(SOCKET_ERROR);
- }
-
- while(extension_functions[i].func != NULL) {
- if (!memcmp (guid, &extension_functions[i].guid,
- sizeof(WapiGuid))) {
- memcpy (output, &extension_functions[i].func,
- sizeof(gpointer));
- *written = sizeof(gpointer);
- return(0);
- }
-
- i++;
- }
-
- WSASetLastError (WSAEINVAL);
- return(SOCKET_ERROR);
- }
-
- if (command == SIO_KEEPALIVE_VALS) {
- uint32_t onoff;
- uint32_t keepalivetime;
- uint32_t keepaliveinterval;
-
- if (i_len < (3 * sizeof (uint32_t))) {
- WSASetLastError (WSAEINVAL);
- return SOCKET_ERROR;
- }
- memcpy (&onoff, input, sizeof (uint32_t));
- memcpy (&keepalivetime, input + sizeof (uint32_t), sizeof (uint32_t));
- memcpy (&keepaliveinterval, input + 2 * sizeof (uint32_t), sizeof (uint32_t));
- ret = setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (uint32_t));
- if (ret < 0) {
- gint errnum = errno;
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
- return SOCKET_ERROR;
- }
- if (onoff != 0) {
-#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
- /* Values are in ms, but we need s */
- uint32_t rem;
-
- /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
- rem = keepalivetime % 1000;
- keepalivetime /= 1000;
- if (keepalivetime == 0 || rem >= 500)
- keepalivetime++;
- ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (uint32_t));
- if (ret == 0) {
- rem = keepaliveinterval % 1000;
- keepaliveinterval /= 1000;
- if (keepaliveinterval == 0 || rem >= 500)
- keepaliveinterval++;
- ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (uint32_t));
- }
- if (ret != 0) {
- gint errnum = errno;
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
- return SOCKET_ERROR;
- }
- return 0;
-#endif
- }
- return 0;
- }
-
- if (i_len > 0) {
- buffer = (char *)g_memdup (input, i_len);
- }
-
- ret = ioctl (fd, command, buffer);
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__,
- strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
- g_free (buffer);
-
- return(SOCKET_ERROR);
- }
-
- if (buffer == NULL) {
- *written = 0;
- } else {
- /* We just copy the buffer to the output. Some ioctls
- * don't even output any data, but, well...
- *
- * NB windows returns WSAEFAULT if o_len is too small
- */
- i_len = (i_len > o_len) ? o_len : i_len;
-
- if (i_len > 0 && output != NULL) {
- memcpy (output, buffer, i_len);
- }
-
- g_free (buffer);
- *written = i_len;
- }
-
- return(0);
-}
-
-#ifndef PLATFORM_PORT_PROVIDES_IOCTLSOCKET
-int ioctlsocket(guint32 fd, unsigned long command, gpointer arg)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
- int ret;
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(SOCKET_ERROR);
- }
-
- switch(command){
- case FIONBIO:
-#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(fd, F_GETFL, 0);
- if (ret != -1) {
- if (*(gboolean *)arg) {
- ret |= O_NONBLOCK;
- } else {
- ret &= ~O_NONBLOCK;
- }
- ret = fcntl(fd, F_SETFL, ret);
- }
- break;
-#endif /* O_NONBLOCK */
- /* Unused in Mono */
- case SIOCATMARK:
- ret = ioctl (fd, command, arg);
- break;
-
- case FIONREAD:
- {
-#if defined (PLATFORM_MACOSX)
-
- // ioctl (fd, FIONREAD, XXX) returns the size of
- // the UDP header as well on
- // Darwin.
- //
- // Use getsockopt SO_NREAD instead to get the
- // right values for TCP and UDP.
- //
- // ai_canonname can be null in some cases on darwin, where the runtime assumes it will
- // be the value of the ip buffer.
-
- socklen_t optlen = sizeof (int);
- ret = getsockopt (fd, SOL_SOCKET, SO_NREAD, arg, &optlen);
-#else
- ret = ioctl (fd, command, arg);
-#endif
- break;
- }
- default:
- WSASetLastError (WSAEINVAL);
- return(SOCKET_ERROR);
- }
-
- if (ret == -1) {
- gint errnum = errno;
- MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, strerror (errno));
-
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
- return(0);
-}
-
-int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
- fd_set *exceptfds, struct timeval *timeout)
-{
- int ret, maxfd;
- MonoThreadInfo *info = mono_thread_info_current ();
-
- for (maxfd = FD_SETSIZE-1; maxfd >= 0; maxfd--) {
- if ((readfds && FD_ISSET (maxfd, readfds)) ||
- (writefds && FD_ISSET (maxfd, writefds)) ||
- (exceptfds && FD_ISSET (maxfd, exceptfds))) {
- break;
- }
- }
-
- if (maxfd == -1) {
- WSASetLastError (WSAEINVAL);
- return(SOCKET_ERROR);
- }
-
- do {
- ret = select(maxfd + 1, readfds, writefds, exceptfds,
- timeout);
- } 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: select error: %s", __func__, strerror (errno));
- errnum = errno_to_WSA (errnum, __func__);
- WSASetLastError (errnum);
-
- return(SOCKET_ERROR);
- }
-
- return(ret);
-}
-
-void _wapi_FD_CLR(guint32 fd, fd_set *set)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
-
- if (fd >= FD_SETSIZE) {
- WSASetLastError (WSAEINVAL);
- return;
- }
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return;
- }
-
- FD_CLR (fd, set);
-}
-
-int _wapi_FD_ISSET(guint32 fd, fd_set *set)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
-
- if (fd >= FD_SETSIZE) {
- WSASetLastError (WSAEINVAL);
- return(0);
- }
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return(0);
- }
-
- return(FD_ISSET (fd, set));
-}
-
-void _wapi_FD_SET(guint32 fd, fd_set *set)
-{
- gpointer handle = GUINT_TO_POINTER (fd);
-
- if (fd >= FD_SETSIZE) {
- WSASetLastError (WSAEINVAL);
- return;
- }
-
- if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
- WSASetLastError (WSAENOTSOCK);
- return;
- }
-
- FD_SET (fd, set);
-}
-#endif
-
-static void
-wsabuf_to_msghdr (WapiWSABuf *buffers, guint32 count, struct msghdr *hdr)
-{
- guint32 i;
-
- memset (hdr, 0, sizeof (struct msghdr));
- hdr->msg_iovlen = count;
- hdr->msg_iov = g_new0 (struct iovec, count);
- for (i = 0; i < count; i++) {
- hdr->msg_iov [i].iov_base = buffers [i].buf;
- hdr->msg_iov [i].iov_len = buffers [i].len;
- }
-}
-
-static void
-msghdr_iov_free (struct msghdr *hdr)
-{
- g_free (hdr->msg_iov);
-}
-
-int WSARecv (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *received,
- guint32 *flags, WapiOverlapped *overlapped,
- WapiOverlappedCB *complete)
-{
- int ret;
- struct msghdr hdr;
-
- g_assert (overlapped == NULL);
- g_assert (complete == NULL);
-
- wsabuf_to_msghdr (buffers, count, &hdr);
- ret = _wapi_recvmsg (fd, &hdr, *flags);
- msghdr_iov_free (&hdr);
-
- if(ret == SOCKET_ERROR) {
- return(ret);
- }
-
- *received = ret;
- *flags = hdr.msg_flags;
-
- return(0);
-}
-
-int WSASend (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *sent,
- guint32 flags, WapiOverlapped *overlapped,
- WapiOverlappedCB *complete)
-{
- int ret;
- struct msghdr hdr;
-
- g_assert (overlapped == NULL);
- g_assert (complete == NULL);
-
- wsabuf_to_msghdr (buffers, count, &hdr);
- ret = _wapi_sendmsg (fd, &hdr, flags);
- msghdr_iov_free (&hdr);
-
- if(ret == SOCKET_ERROR)
- return ret;
-
- *sent = ret;
- return 0;
-}
-
-#endif /* ifndef DISABLE_SOCKETS */
+++ /dev/null
-/*
- * sockets.h: Socket handles
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2002 Ximian, Inc.
- */
-
-#ifndef _WAPI_SOCKETS_H_
-#define _WAPI_SOCKETS_H_
-
-#include "mono/io-layer/wapi.h"
-
-G_BEGIN_DECLS
-
-#define WSADESCRIPTION_LEN 256
-#define WSASYS_STATUS_LEN 128
-
-typedef struct
-{
- guint16 wVersion;
- guint16 wHighVersion;
- char szDescription[WSADESCRIPTION_LEN+1];
- char szSystemStatus[WSASYS_STATUS_LEN+1];
- guint16 iMaxSockets;
- guint16 iMaxUdpDg;
- guchar *lpVendorInfo;
-} WapiWSAData;
-
-#define INVALID_SOCKET (guint32)(~0)
-#define SOCKET_ERROR -1
-
-#define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
-#define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
-
-typedef struct
-{
- guint32 Data1;
- guint16 Data2;
- guint16 Data3;
- guint8 Data4[8];
-} WapiGuid;
-
-typedef struct
-{
- gpointer Head;
- guint32 HeadLength;
- gpointer Tail;
- guint32 TailLength;
-} WapiTransmitFileBuffers;
-
-typedef enum {
- TF_USE_DEFAULT_WORKER = 0,
- TF_DISCONNECT = 0x01,
- TF_REUSE_SOCKET = 0x02,
- TF_WRITE_BEHIND = 0x04,
- TF_USE_SYSTEM_THREAD = 0x10,
- TF_USE_KERNEL_APC = 0x20
-} WapiTransmitFileFlags;
-
-typedef struct
-{
- guint32 len;
- gpointer buf;
-} WapiWSABuf;
-
-/* If we need to support more WSAIoctl commands then define these
- * using the bitfield flags method
- */
-#define SIO_GET_EXTENSION_FUNCTION_POINTER 0xC8000006
-#define SIO_KEEPALIVE_VALS 0x98000004
-
-typedef gboolean (*WapiDisconnectExFn)(guint32, WapiOverlapped *, guint32,
- guint32);
-typedef gboolean (*WapiTransmitFileFn)(guint32, gpointer, guint32, guint32,
- WapiOverlapped *,
- WapiTransmitFileBuffers *,
- WapiTransmitFileFlags);
-
-extern void WSASetLastError(int error);
-extern int WSAGetLastError(void);
-extern int closesocket(guint32 handle);
-
-extern int ioctlsocket(guint32 handle, unsigned long command, gpointer arg);
-extern int WSAIoctl (guint32 handle, gint32 command,
- gchar *input, gint i_len,
- gchar *output, gint o_len, glong *written,
- void *unused1, void *unused2);
-extern int WSARecv (guint32 handle, WapiWSABuf *buffers, guint32 count,
- guint32 *received, guint32 *flags,
- WapiOverlapped *overlapped, WapiOverlappedCB *complete);
-extern int WSASend (guint32 handle, WapiWSABuf *buffers, guint32 count,
- guint32 *sent, guint32 flags,
- WapiOverlapped *overlapped, WapiOverlappedCB *complete);
-
-gboolean TransmitFile (guint32 socket, gpointer file, guint32 bytes_to_write, guint32 bytes_per_send, WapiOverlapped *ol,
- WapiTransmitFileBuffers *tb, guint32 flags);
-G_END_DECLS
-#endif /* _WAPI_SOCKETS_H_ */
typedef gpointer HANDLE;
typedef gpointer *LPHANDLE;
-typedef guint32 SOCKET;
typedef gpointer HMODULE;
typedef gpointer HINSTANCE;
typedef gpointer HWND;
typedef WapiFileTime *LPFILETIME;
typedef WapiSystemTime SYSTEMTIME;
typedef WapiSystemTime *LPSYSTEMTIME;
-typedef WapiWSAData WSADATA;
-typedef WapiWSAData *LDWSADATA;
-typedef WapiWSABuf WSABUF;
-typedef WapiWSABuf *LPWSABUF;
typedef WapiFindData WIN32_FIND_DATA;
typedef WapiFindData *LPWIN32_FIND_DATA;
typedef WapiFileAttributesData WIN32_FILE_ATTRIBUTE_DATA;
typedef WapiGetFileExInfoLevels GET_FILEEX_INFO_LEVELS;
-typedef WapiTransmitFileBuffers TRANSMIT_FILE_BUFFERS;
-typedef WapiTransmitFileBuffers *PTRANSMIT_FILE_BUFFERS;
-typedef WapiTransmitFileBuffers *LPTRANSMIT_FILE_BUFFERS;
-typedef WapiDisconnectExFn LPFN_DISCONNECTEX;
-typedef WapiTransmitFileFn LPFN_TRANSMITFILE;
-typedef WapiGuid GUID;
-typedef WapiGuid *LPGUID;
#define CONST const
#define VOID void
extern gboolean _wapi_has_shut_down;
#include <mono/io-layer/io-private.h>
-#include <mono/io-layer/socket-private.h>
#include <mono/metadata/w32handle.h>
struct _WapiHandle_shared_ref
#define GetLastError wapi_GetLastError
#define SetLastError wapi_SetLastError
-#define TransmitFile wapi_TransmitFile
#define CloseHandle wapi_CloseHandle
#define CreateFile wapi_CreateFile
#define DeleteFile wapi_DeleteFile
#define GetVolumeInformation wapi_GetVolumeInformation
#define ImpersonateLoggedOnUser wapi_ImpersonateLoggedOnUser
#define RevertToSelf wapi_RevertToSelf
-#define WSASetLastError wapi_WSASetLastError
-#define WSAGetLastError wapi_WSAGetLastError
-#define WSAIoctl wapi_WSAIoctl
-#define WSARecv wapi_WSARecv
-#define WSASend wapi_WSASend
#define GetSystemInfo wapi_GetSystemInfo
#endif /* __WAPI_REMAP_H__ */
#include "io-trace.h"
#include "io.h"
-#include "socket-private.h"
#include "mono/utils/mono-lazy-init.h"
#include "mono/metadata/w32handle.h"
wapi_init (void)
{
_wapi_io_init ();
- _wapi_socket_init ();
}
void
#include <mono/io-layer/io.h>
#include <mono/io-layer/io-portability.h>
#include <mono/io-layer/error.h>
-#include <mono/io-layer/sockets.h>
G_BEGIN_DECLS
w32event-win32.c \
w32process-win32.c \
w32process-win32-internals.h \
- socket-io-windows.c
+ w32socket-win32.c
platform_sources = $(win32_sources)
w32process-unix-osx.c \
w32process-unix-bsd.c \
w32process-unix-haiku.c \
- w32process-unix-default.c
+ w32process-unix-default.c \
+ w32socket-unix.c
platform_sources = $(unix_sources)
endif
opcodes.c \
property-bag.h \
property-bag.c \
- socket-io.c \
- socket-io.h \
+ w32socket.c \
+ w32socket.h \
+ w32socket-internals.h \
w32process.c \
w32process.h \
w32process-internals.h \
#include <mono/metadata/exception-internals.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/threadpool.h>
-#include <mono/metadata/socket-io.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/gc-internals.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/reflection-internals.h>
#include <mono/metadata/abi-details.h>
+#include <mono/metadata/w32socket.h>
#include <mono/utils/mono-uri.h>
#include <mono/utils/mono-logger-internals.h>
#include <mono/utils/mono-path.h>
#include <mono/metadata/file-io.h>
#include <mono/metadata/console-io.h>
#include <mono/metadata/mono-route.h>
-#include <mono/metadata/socket-io.h>
+#include <mono/metadata/w32socket.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/tokentype.h>
#include <mono/metadata/metadata-internals.h>
+++ /dev/null
-/*
-* socket-io-windows-internals.h: Windows specific socket code.
-*
-* Copyright 2016 Microsoft
-* Licensed under the MIT license. See LICENSE file in the project root for full license information.
-*/
-#ifndef __MONO_METADATA_SOCKET_IO_WINDOWS_INTERNALS_H__
-#define __MONO_METADATA_SOCKET_IO_WINDOWS_INTERNALS_H__
-
-#include <config.h>
-#include <glib.h>
-#include <mono/io-layer/io-layer.h>
-
-SOCKET alertable_accept (SOCKET s, struct sockaddr *addr, int *addrlen, gboolean blocking);
-int alertable_connect (SOCKET s, const struct sockaddr *name, int namelen, gboolean blocking);
-int alertable_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking);
-int alertable_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen, gboolean blocking);
-int alertable_WSARecv (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, gboolean blocking);
-int alertable_send (SOCKET s, char *buf, int len, int flags, gboolean blocking);
-int alertable_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking);
-int alertable_WSASend (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, DWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, gboolean blocking);
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
-BOOL alertable_TransmitFile (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, LPOVERLAPPED lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwReserved, gboolean blocking);
-#endif
-
-#endif // __MONO_METADATA_SOCKET_IO_WINDOWS_INTERNALS_H__
+++ /dev/null
-/*
-* socket-io-windows.c: Windows specific socket code.
-*
-* Copyright 2016 Microsoft
-* Licensed under the MIT license. See LICENSE file in the project root for full license information.
-*/
-#include <config.h>
-#include <glib.h>
-
-#include "mono/metadata/socket-io-windows-internals.h"
-
-#define LOGDEBUG(...)
-
-static gboolean set_blocking (SOCKET sock, gboolean block)
-{
- u_long non_block = block ? 0 : 1;
- return ioctlsocket (sock, FIONBIO, &non_block) != SOCKET_ERROR;
-}
-
-static DWORD get_socket_timeout (SOCKET sock, int optname)
-{
- DWORD timeout = 0;
- int optlen = sizeof (DWORD);
- if (getsockopt (sock, SOL_SOCKET, optname, (char *)&timeout, &optlen) == SOCKET_ERROR) {
- WSASetLastError (0);
- return WSA_INFINITE;
- }
- if (timeout == 0)
- timeout = WSA_INFINITE; // 0 means infinite
- return timeout;
-}
-
-/*
-* Performs an alertable wait for the specified event (FD_ACCEPT_BIT,
-* FD_CONNECT_BIT, FD_READ_BIT, FD_WRITE_BIT) on the specified socket.
-* Returns TRUE if the event is fired without errors. Calls WSASetLastError()
-* with WSAEINTR and returns FALSE if the thread is alerted. If the event is
-* fired but with an error WSASetLastError() is called to set the error and the
-* function returns FALSE.
-*/
-static gboolean alertable_socket_wait (SOCKET sock, int event_bit)
-{
- static char *EVENT_NAMES[] = { "FD_READ", "FD_WRITE", NULL /*FD_OOB*/, "FD_ACCEPT", "FD_CONNECT", "FD_CLOSE" };
- gboolean success = FALSE;
- int error = -1;
- DWORD timeout = WSA_INFINITE;
- if (event_bit == FD_READ_BIT || event_bit == FD_WRITE_BIT) {
- timeout = get_socket_timeout (sock, event_bit == FD_READ_BIT ? SO_RCVTIMEO : SO_SNDTIMEO);
- }
- WSASetLastError (0);
- WSAEVENT event = WSACreateEvent ();
- if (event != WSA_INVALID_EVENT) {
- if (WSAEventSelect (sock, event, (1 << event_bit) | FD_CLOSE) != SOCKET_ERROR) {
- LOGDEBUG (g_message ("%06d - Calling WSAWaitForMultipleEvents () on socket %d", GetCurrentThreadId (), sock));
- DWORD ret = WSAWaitForMultipleEvents (1, &event, TRUE, timeout, TRUE);
- if (ret == WSA_WAIT_IO_COMPLETION) {
- LOGDEBUG (g_message ("%06d - WSAWaitForMultipleEvents () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), sock));
- error = WSAEINTR;
- } else if (ret == WSA_WAIT_TIMEOUT) {
- error = WSAETIMEDOUT;
- } else {
- g_assert (ret == WSA_WAIT_EVENT_0);
- WSANETWORKEVENTS ne = { 0 };
- if (WSAEnumNetworkEvents (sock, event, &ne) != SOCKET_ERROR) {
- if (ne.lNetworkEvents & (1 << event_bit) && ne.iErrorCode[event_bit]) {
- LOGDEBUG (g_message ("%06d - %s error %d on socket %d", GetCurrentThreadId (), EVENT_NAMES[event_bit], ne.iErrorCode[event_bit], sock));
- error = ne.iErrorCode[event_bit];
- } else if (ne.lNetworkEvents & FD_CLOSE_BIT && ne.iErrorCode[FD_CLOSE_BIT]) {
- LOGDEBUG (g_message ("%06d - FD_CLOSE error %d on socket %d", GetCurrentThreadId (), ne.iErrorCode[FD_CLOSE_BIT], sock));
- error = ne.iErrorCode[FD_CLOSE_BIT];
- } else {
- LOGDEBUG (g_message ("%06d - WSAEnumNetworkEvents () finished successfully on socket %d", GetCurrentThreadId (), sock));
- success = TRUE;
- error = 0;
- }
- }
- }
- WSAEventSelect (sock, NULL, 0);
- }
- WSACloseEvent (event);
- }
- if (error != -1) {
- WSASetLastError (error);
- }
- return success;
-}
-
-#define ALERTABLE_SOCKET_CALL(event_bit, blocking, repeat, ret, op, sock, ...) \
- LOGDEBUG (g_message ("%06d - Performing %s " #op " () on socket %d", GetCurrentThreadId (), blocking ? "blocking" : "non-blocking", sock)); \
- if (blocking) { \
- if (set_blocking(sock, FALSE)) { \
- while (-1 == (int) (ret = op (sock, __VA_ARGS__))) { \
- int _error = WSAGetLastError ();\
- if (_error != WSAEWOULDBLOCK && _error != WSA_IO_PENDING) \
- break; \
- if (!alertable_socket_wait (sock, event_bit) || !repeat) \
- break; \
- } \
- int _saved_error = WSAGetLastError (); \
- set_blocking (sock, TRUE); \
- WSASetLastError (_saved_error); \
- } \
- } else { \
- ret = op (sock, __VA_ARGS__); \
- } \
- int _saved_error = WSAGetLastError (); \
- LOGDEBUG (g_message ("%06d - Finished %s " #op " () on socket %d (ret = %d, WSAGetLastError() = %d)", GetCurrentThreadId (), \
- blocking ? "blocking" : "non-blocking", sock, ret, _saved_error)); \
- WSASetLastError (_saved_error);
-
-SOCKET alertable_accept (SOCKET s, struct sockaddr *addr, int *addrlen, gboolean blocking)
-{
- SOCKET newsock = INVALID_SOCKET;
- ALERTABLE_SOCKET_CALL (FD_ACCEPT_BIT, blocking, TRUE, newsock, accept, s, addr, addrlen);
- return newsock;
-}
-
-int alertable_connect (SOCKET s, const struct sockaddr *name, int namelen, gboolean blocking)
-{
- int ret = SOCKET_ERROR;
- ALERTABLE_SOCKET_CALL (FD_CONNECT_BIT, blocking, FALSE, ret, connect, s, name, namelen);
- ret = WSAGetLastError () != 0 ? SOCKET_ERROR : 0;
- return ret;
-}
-
-int alertable_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking)
-{
- int ret = SOCKET_ERROR;
- ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, recv, s, buf, len, flags);
- return ret;
-}
-
-int alertable_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen, gboolean blocking)
-{
- int ret = SOCKET_ERROR;
- ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, recvfrom, s, buf, len, flags, from, fromlen);
- return ret;
-}
-
-int alertable_WSARecv (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, gboolean blocking)
-{
- int ret = SOCKET_ERROR;
- ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, WSARecv, s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
- return ret;
-}
-
-int alertable_send (SOCKET s, char *buf, int len, int flags, gboolean blocking)
-{
- int ret = SOCKET_ERROR;
- ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, send, s, buf, len, flags);
- return ret;
-}
-
-int alertable_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
-{
- int ret = SOCKET_ERROR;
- ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, sendto, s, buf, len, flags, to, tolen);
- return ret;
-}
-
-int alertable_WSASend (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, DWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, gboolean blocking)
-{
- int ret = SOCKET_ERROR;
- ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, WSASend, s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
- return ret;
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
-BOOL alertable_TransmitFile (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, LPOVERLAPPED lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwReserved, gboolean blocking)
-{
- LOGDEBUG (g_message ("%06d - Performing %s TransmitFile () on socket %d", GetCurrentThreadId (), blocking ? "blocking" : "non-blocking", hSocket));
-
- int error = 0;
- if (blocking) {
- g_assert (lpOverlapped == NULL);
- OVERLAPPED overlapped = { 0 };
- overlapped.hEvent = WSACreateEvent ();
- if (overlapped.hEvent == WSA_INVALID_EVENT)
- return FALSE;
- if (!TransmitFile (hSocket, hFile, nNumberOfBytesToWrite, nNumberOfBytesPerSend, &overlapped, lpTransmitBuffers, dwReserved)) {
- error = WSAGetLastError ();
- if (error == WSA_IO_PENDING) {
- error = 0;
- // NOTE: .NET's Socket.SendFile() doesn't honor the Socket's SendTimeout so we shouldn't either
- DWORD ret = WaitForSingleObjectEx (overlapped.hEvent, INFINITE, TRUE);
- if (ret == WAIT_IO_COMPLETION) {
- LOGDEBUG (g_message ("%06d - WaitForSingleObjectEx () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), hSocket));
- error = WSAEINTR;
- } else if (ret == WAIT_TIMEOUT) {
- error = WSAETIMEDOUT;
- } else if (ret != WAIT_OBJECT_0) {
- error = GetLastError ();
- }
- }
- }
- WSACloseEvent (overlapped.hEvent);
- } else {
- if (!TransmitFile (hSocket, hFile, nNumberOfBytesToWrite, nNumberOfBytesPerSend, lpOverlapped, lpTransmitBuffers, dwReserved)) {
- error = WSAGetLastError ();
- }
- }
-
- LOGDEBUG (g_message ("%06d - Finished %s TransmitFile () on socket %d (ret = %d, WSAGetLastError() = %d)", GetCurrentThreadId (), \
- blocking ? "blocking" : "non-blocking", hSocket, error == 0, error));
- WSASetLastError (error);
-
- return error == 0;
-}
-#endif /* #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
+++ /dev/null
-/*
- * socket-io.c: Socket IO internal calls
- *
- * Authors:
- * Dick Porter (dick@ximian.com)
- * Gonzalo Paniagua Javier (gonzalo@ximian.com)
- *
- * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
- * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
- *
- * This file has been re-licensed under the MIT License:
- * http://opensource.org/licenses/MIT
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include <config.h>
-
-#ifndef DISABLE_SOCKETS
-
-#if defined(__APPLE__) || defined(__FreeBSD__)
-#define __APPLE_USE_RFC_3542
-#endif
-
-#include <glib.h>
-#include <string.h>
-#include <stdlib.h>
-#ifdef HOST_WIN32
-#include <ws2tcpip.h>
-#else
-#include <sys/socket.h>
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <errno.h>
-
-#include <sys/types.h>
-
-#include <mono/metadata/object.h>
-#include <mono/io-layer/io-layer.h>
-#include <mono/metadata/socket-io.h>
-#include <mono/metadata/exception.h>
-#include <mono/metadata/assembly.h>
-#include <mono/metadata/appdomain.h>
-#include <mono/metadata/file-io.h>
-#include <mono/metadata/threads.h>
-#include <mono/metadata/threads-types.h>
-#include <mono/metadata/threadpool-io.h>
-#include <mono/utils/mono-poll.h>
-/* FIXME change this code to not mess so much with the internals */
-#include <mono/metadata/class-internals.h>
-#include <mono/metadata/domain-internals.h>
-#include <mono/utils/mono-threads.h>
-#include <mono/utils/mono-memory-model.h>
-#include <mono/utils/networking.h>
-#include <mono/metadata/w32handle.h>
-
-#include <time.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_SYS_FILIO_H
-#include <sys/filio.h> /* defines FIONBIO and FIONREAD */
-#endif
-#ifdef HAVE_SYS_SOCKIO_H
-#include <sys/sockio.h> /* defines SIOCATMARK */
-#endif
-#ifdef HAVE_SYS_UN_H
-#include <sys/un.h>
-#endif
-
-#ifdef HAVE_GETIFADDRS
-// <net/if.h> must be included before <ifaddrs.h>
-#include <ifaddrs.h>
-#endif
-
-#if defined(_MSC_VER) && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
-#include <MSWSock.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__) */
-
-static void
-abort_syscall (gpointer data)
-{
- mono_thread_info_abort_socket_syscall_for_close ((MonoNativeThreadId) (gsize) data);
-}
-
-static gint32
-convert_family (MonoAddressFamily mono_family)
-{
- switch (mono_family) {
- case AddressFamily_Unknown:
- case AddressFamily_ImpLink:
- case AddressFamily_Pup:
- case AddressFamily_Chaos:
- case AddressFamily_Iso:
- case AddressFamily_Ecma:
- case AddressFamily_DataKit:
- case AddressFamily_Ccitt:
- case AddressFamily_DataLink:
- case AddressFamily_Lat:
- case AddressFamily_HyperChannel:
- case AddressFamily_NetBios:
- case AddressFamily_VoiceView:
- case AddressFamily_FireFox:
- case AddressFamily_Banyan:
- case AddressFamily_Atm:
- case AddressFamily_Cluster:
- case AddressFamily_Ieee12844:
- case AddressFamily_NetworkDesigners:
- g_warning ("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
- return -1;
- case AddressFamily_Unspecified:
- return AF_UNSPEC;
- case AddressFamily_Unix:
- return AF_UNIX;
- case AddressFamily_InterNetwork:
- return AF_INET;
- case AddressFamily_AppleTalk:
- return AF_APPLETALK;
- case AddressFamily_InterNetworkV6:
- return AF_INET6;
- case AddressFamily_DecNet:
-#ifdef AF_DECnet
- return AF_DECnet;
-#else
- return -1;
-#endif
- case AddressFamily_Ipx:
-#ifdef AF_IPX
- return AF_IPX;
-#else
- return -1;
-#endif
- case AddressFamily_Sna:
-#ifdef AF_SNA
- return AF_SNA;
-#else
- return -1;
-#endif
- case AddressFamily_Irda:
-#ifdef AF_IRDA
- return AF_IRDA;
-#else
- return -1;
-#endif
- default:
- g_warning ("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
- return -1;
- }
-}
-
-static MonoAddressFamily
-convert_to_mono_family (guint16 af_family)
-{
- switch (af_family) {
- case AF_UNSPEC:
- return AddressFamily_Unspecified;
- case AF_UNIX:
- return AddressFamily_Unix;
- case AF_INET:
- return AddressFamily_InterNetwork;
-#ifdef AF_IPX
- case AF_IPX:
- return AddressFamily_Ipx;
-#endif
-#ifdef AF_SNA
- case AF_SNA:
- return AddressFamily_Sna;
-#endif
-#ifdef AF_DECnet
- case AF_DECnet:
- return AddressFamily_DecNet;
-#endif
- case AF_APPLETALK:
- return AddressFamily_AppleTalk;
- case AF_INET6:
- return AddressFamily_InterNetworkV6;
-#ifdef AF_IRDA
- case AF_IRDA:
- return AddressFamily_Irda;
-#endif
- default:
- g_warning ("unknown address family 0x%x", af_family);
- return AddressFamily_Unknown;
- }
-}
-
-static gint32
-convert_type (MonoSocketType mono_type)
-{
- switch (mono_type) {
- case SocketType_Stream:
- return SOCK_STREAM;
- case SocketType_Dgram:
- return SOCK_DGRAM;
- case SocketType_Raw:
- return SOCK_RAW;
- case SocketType_Rdm:
-#ifdef SOCK_RDM
- return SOCK_RDM;
-#else
- return -1;
-#endif
- case SocketType_Seqpacket:
- return SOCK_SEQPACKET;
- case SocketType_Unknown:
- g_warning ("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
- return -1;
- default:
- g_warning ("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
- return -1;
- }
-}
-
-static gint32
-convert_proto (MonoProtocolType mono_proto)
-{
- switch (mono_proto) {
- case ProtocolType_IP:
- case ProtocolType_IPv6:
- case ProtocolType_Icmp:
- case ProtocolType_Igmp:
- case ProtocolType_Ggp:
- case ProtocolType_Tcp:
- case ProtocolType_Pup:
- case ProtocolType_Udp:
- case ProtocolType_Idp:
- /* These protocols are known (on my system at least) */
- return mono_proto;
- case ProtocolType_ND:
- case ProtocolType_Raw:
- case ProtocolType_Ipx:
- case ProtocolType_Spx:
- case ProtocolType_SpxII:
- case ProtocolType_Unknown:
- /* These protocols arent */
- g_warning ("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
- return -1;
- default:
- return -1;
- }
-}
-
-/* Convert MonoSocketFlags */
-static gint32
-convert_socketflags (gint32 sflags)
-{
- gint32 flags = 0;
-
- if (!sflags)
- /* SocketFlags.None */
- return 0;
-
- if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek |
- SocketFlags_DontRoute | SocketFlags_Partial))
- /* Contains invalid flag values */
- return -1;
-
- if (sflags & SocketFlags_OutOfBand)
- flags |= MSG_OOB;
- if (sflags & SocketFlags_Peek)
- flags |= MSG_PEEK;
- if (sflags & SocketFlags_DontRoute)
- flags |= MSG_DONTROUTE;
-
- /* 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;
-#endif
-#if 0
- /* Don't do anything for MaxIOVectorLength */
- if (sflags & SocketFlags_MaxIOVectorLength)
- return -1;
-#endif
- return flags;
-}
-
-/*
- * Returns:
- * 0 on success (mapped mono_level and mono_name to system_level and system_name
- * -1 on error
- * -2 on non-fatal error (ie, must ignore)
- */
-static gint32
-convert_sockopt_level_and_name (MonoSocketOptionLevel mono_level, MonoSocketOptionName mono_name, int *system_level, int *system_name)
-{
- switch (mono_level) {
- case SocketOptionLevel_Socket:
- *system_level = SOL_SOCKET;
-
- switch (mono_name) {
- case SocketOptionName_DontLinger:
- /* This is SO_LINGER, because the setsockopt
- * internal call maps DontLinger to SO_LINGER
- * with l_onoff=0
- */
- *system_name = SO_LINGER;
- break;
- case SocketOptionName_Debug:
- *system_name = SO_DEBUG;
- break;
-#ifdef SO_ACCEPTCONN
- case SocketOptionName_AcceptConnection:
- *system_name = SO_ACCEPTCONN;
- break;
-#endif
- case SocketOptionName_ReuseAddress:
- *system_name = SO_REUSEADDR;
- break;
- case SocketOptionName_KeepAlive:
- *system_name = SO_KEEPALIVE;
- break;
- case SocketOptionName_DontRoute:
- *system_name = SO_DONTROUTE;
- break;
- case SocketOptionName_Broadcast:
- *system_name = SO_BROADCAST;
- break;
- case SocketOptionName_Linger:
- *system_name = SO_LINGER;
- break;
- case SocketOptionName_OutOfBandInline:
- *system_name = SO_OOBINLINE;
- break;
- case SocketOptionName_SendBuffer:
- *system_name = SO_SNDBUF;
- break;
- case SocketOptionName_ReceiveBuffer:
- *system_name = SO_RCVBUF;
- break;
- case SocketOptionName_SendLowWater:
- *system_name = SO_SNDLOWAT;
- break;
- case SocketOptionName_ReceiveLowWater:
- *system_name = SO_RCVLOWAT;
- break;
- case SocketOptionName_SendTimeout:
- *system_name = SO_SNDTIMEO;
- break;
- case SocketOptionName_ReceiveTimeout:
- *system_name = SO_RCVTIMEO;
- break;
- case SocketOptionName_Error:
- *system_name = SO_ERROR;
- break;
- case SocketOptionName_Type:
- *system_name = SO_TYPE;
- break;
-#ifdef SO_PEERCRED
- case SocketOptionName_PeerCred:
- *system_name = SO_PEERCRED;
- 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:
-#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;
- }
- break;
-
- case SocketOptionLevel_IP:
- *system_level = mono_networking_get_ip_protocol ();
-
- switch (mono_name) {
- case SocketOptionName_IPOptions:
- *system_name = IP_OPTIONS;
- break;
-#ifdef IP_HDRINCL
- case SocketOptionName_HeaderIncluded:
- *system_name = IP_HDRINCL;
- break;
-#endif
-#ifdef IP_TOS
- case SocketOptionName_TypeOfService:
- *system_name = IP_TOS;
- break;
-#endif
-#ifdef IP_TTL
- case SocketOptionName_IpTimeToLive:
- *system_name = IP_TTL;
- break;
-#endif
- case SocketOptionName_MulticastInterface:
- *system_name = IP_MULTICAST_IF;
- break;
- case SocketOptionName_MulticastTimeToLive:
- *system_name = IP_MULTICAST_TTL;
- break;
- case SocketOptionName_MulticastLoopback:
- *system_name = IP_MULTICAST_LOOP;
- break;
- case SocketOptionName_AddMembership:
- *system_name = IP_ADD_MEMBERSHIP;
- break;
- case SocketOptionName_DropMembership:
- *system_name = IP_DROP_MEMBERSHIP;
- break;
-#ifdef HAVE_IP_PKTINFO
- case SocketOptionName_PacketInformation:
- *system_name = IP_PKTINFO;
- break;
-#endif /* HAVE_IP_PKTINFO */
-
- case SocketOptionName_DontFragment:
-#ifdef HAVE_IP_DONTFRAGMENT
- *system_name = IP_DONTFRAGMENT;
- break;
-#elif defined HAVE_IP_MTU_DISCOVER
- /* Not quite the same */
- *system_name = IP_MTU_DISCOVER;
- break;
-#else
- /* If the flag is not available on this system, we can ignore this error */
- return -2;
-#endif /* HAVE_IP_DONTFRAGMENT */
- case SocketOptionName_AddSourceMembership:
- case SocketOptionName_DropSourceMembership:
- case SocketOptionName_BlockSource:
- case SocketOptionName_UnblockSource:
- /* Can't figure out how to map these, so fall
- * through
- */
- default:
- g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
- return -1;
- }
- break;
-
- case SocketOptionLevel_IPv6:
- *system_level = mono_networking_get_ipv6_protocol ();
-
- switch (mono_name) {
- case SocketOptionName_IpTimeToLive:
- case SocketOptionName_HopLimit:
- *system_name = IPV6_UNICAST_HOPS;
- break;
- case SocketOptionName_MulticastInterface:
- *system_name = IPV6_MULTICAST_IF;
- break;
- case SocketOptionName_MulticastTimeToLive:
- *system_name = IPV6_MULTICAST_HOPS;
- break;
- case SocketOptionName_MulticastLoopback:
- *system_name = IPV6_MULTICAST_LOOP;
- break;
- case SocketOptionName_AddMembership:
- *system_name = IPV6_JOIN_GROUP;
- break;
- case SocketOptionName_DropMembership:
- *system_name = IPV6_LEAVE_GROUP;
- break;
- case SocketOptionName_IPv6Only:
-#ifdef IPV6_V6ONLY
- *system_name = IPV6_V6ONLY;
-#else
- return -1;
-#endif
- break;
- case SocketOptionName_PacketInformation:
-#ifdef HAVE_IPV6_PKTINFO
- *system_name = IPV6_PKTINFO;
-#endif
- break;
- case SocketOptionName_HeaderIncluded:
- case SocketOptionName_IPOptions:
- case SocketOptionName_TypeOfService:
- case SocketOptionName_DontFragment:
- case SocketOptionName_AddSourceMembership:
- case SocketOptionName_DropSourceMembership:
- case SocketOptionName_BlockSource:
- case SocketOptionName_UnblockSource:
- /* Can't figure out how to map these, so fall
- * through
- */
- default:
- g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
- return -1;
- }
- break; /* SocketOptionLevel_IPv6 */
-
- case SocketOptionLevel_Tcp:
- *system_level = mono_networking_get_tcp_protocol ();
-
- switch (mono_name) {
- case SocketOptionName_NoDelay:
- *system_name = TCP_NODELAY;
- break;
-#if 0
- /* The documentation is talking complete
- * bollocks here: rfc-1222 is titled
- * 'Advancing the NSFNET Routing Architecture'
- * and doesn't mention either of the words
- * "expedite" or "urgent".
- */
- case SocketOptionName_BsdUrgent:
- case SocketOptionName_Expedited:
-#endif
- default:
- g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
- return -1;
- }
- break;
-
- case SocketOptionLevel_Udp:
- g_warning ("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
-
- switch(mono_name) {
- case SocketOptionName_NoChecksum:
- case SocketOptionName_ChecksumCoverage:
- default:
- g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
- return -1;
- }
- return -1;
- break;
-
- default:
- g_warning ("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
- return -1;
- }
-
- return 0;
-}
-
-static MonoImage*
-get_socket_assembly (void)
-{
- MonoDomain *domain = mono_domain_get ();
-
- if (domain->socket_assembly == NULL) {
- MonoImage *socket_assembly;
-
- 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);
- }
- }
- mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
- }
-
- return domain->socket_assembly;
-}
-
-gpointer
-ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObject *this_obj, gint32 family, gint32 type, gint32 proto, gint32 *werror)
-{
- SOCKET sock;
- gint32 sock_family;
- gint32 sock_proto;
- gint32 sock_type;
-
- *werror = 0;
-
- sock_family = convert_family ((MonoAddressFamily)family);
- if (sock_family == -1) {
- *werror = WSAEAFNOSUPPORT;
- return NULL;
- }
-
- sock_proto = convert_proto ((MonoProtocolType)proto);
- if (sock_proto == -1) {
- *werror = WSAEPROTONOSUPPORT;
- return NULL;
- }
-
- sock_type = convert_type ((MonoSocketType)type);
- if (sock_type == -1) {
- *werror = WSAESOCKTNOSUPPORT;
- return NULL;
- }
-
- sock = _wapi_socket (sock_family, sock_type, sock_proto,
- NULL, 0, WSA_FLAG_OVERLAPPED);
-
- if (sock == INVALID_SOCKET) {
- *werror = WSAGetLastError ();
- return NULL;
- }
-
- return GUINT_TO_POINTER (sock);
-}
-
-/* FIXME: the SOCKET parameter (here and in other functions in this
- * file) is really an IntPtr which needs to be converted to a guint32.
- */
-void
-ves_icall_System_Net_Sockets_Socket_Close_internal (SOCKET sock, gint32 *werror)
-{
- LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
-
- *werror = 0;
-
- /* Clear any pending work item from this socket if the underlying
- * polling system does not notify when the socket is closed */
- mono_threadpool_io_remove_socket (GPOINTER_TO_INT (sock));
-
- MONO_ENTER_GC_SAFE;
- closesocket (sock);
- MONO_EXIT_GC_SAFE;
-}
-
-gint32
-ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal (void)
-{
- LOGDEBUG (g_message("%s: returning %d", __func__, WSAGetLastError ()));
-
- return WSAGetLastError ();
-}
-
-gint32
-ves_icall_System_Net_Sockets_Socket_Available_internal (SOCKET sock, gint32 *werror)
-{
- int ret;
- int amount;
-
- *werror = 0;
-
- /* FIXME: this might require amount to be unsigned long. */
- ret = ioctlsocket (sock, FIONREAD, &amount);
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
- return 0;
- }
-
- return amount;
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_Blocking_internal (SOCKET sock, gboolean block, gint32 *werror)
-{
- int ret;
-
- *werror = 0;
-
- /*
- * block == TRUE/FALSE means we will block/not block.
- * But the ioctlsocket call takes TRUE/FALSE for non-block/block
- */
- block = !block;
-
- ret = ioctlsocket (sock, FIONBIO, (gulong *)&block);
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-}
-
-gpointer
-ves_icall_System_Net_Sockets_Socket_Accept_internal (SOCKET sock, gint32 *werror, gboolean blocking)
-{
- gboolean interrupted;
- SOCKET newsock;
-
- *werror = 0;
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return NULL;
- }
-
- MONO_ENTER_GC_SAFE;
-
-#ifdef HOST_WIN32
- {
- MonoInternalThread *curthread = mono_thread_internal_current ();
- curthread->interrupt_on_stop = (gpointer)TRUE;
- newsock = alertable_accept (sock, NULL, 0, blocking);
- curthread->interrupt_on_stop = (gpointer)FALSE;
- }
-#else
- newsock = _wapi_accept (sock, NULL, 0);
-#endif
-
- MONO_EXIT_GC_SAFE;
-
- if (newsock == INVALID_SOCKET)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-
- if (*werror)
- return NULL;
-
- return GUINT_TO_POINTER (newsock);
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock, guint32 backlog, gint32 *werror)
-{
- int ret;
-
- *werror = 0;
-
- MONO_ENTER_GC_SAFE;
-
- ret = _wapi_listen (sock, backlog);
-
- MONO_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-}
-
-// Check whether it's ::ffff::0:0.
-static gboolean
-is_ipv4_mapped_any (const struct in6_addr *addr)
-{
- int i;
-
- for (i = 0; i < 10; i++) {
- if (addr->s6_addr [i])
- return FALSE;
- }
- if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
- return FALSE;
- for (i = 12; i < 16; i++) {
- if (addr->s6_addr [i])
- return FALSE;
- }
- return TRUE;
-}
-
-static MonoObject*
-create_object_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error)
-{
- MonoDomain *domain = mono_domain_get ();
- MonoObject *sockaddr_obj;
- MonoArray *data;
- MonoAddressFamily family;
-
- mono_error_init (error);
-
- /* Build a System.Net.SocketAddress object instance */
- if (!domain->sockaddr_class)
- domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
- sockaddr_obj = mono_object_new_checked (domain, domain->sockaddr_class, error);
- return_val_if_nok (error, NULL);
-
- /* 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);
- }
-
- /* May be the +2 here is too conservative, as sa_len returns
- * the length of the entire sockaddr_in/in6, including
- * sizeof (unsigned short) of the family */
- /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
- data = mono_array_new_cached (domain, mono_get_byte_class (), sa_size + 2, error);
- return_val_if_nok (error, NULL);
-
- /* The data buffer is laid out as follows:
- * bytes 0 and 1 are the address family
- * bytes 2 and 3 are the port info
- * the rest is the address info
- */
-
- family = convert_to_mono_family (saddr->sa_family);
- if (family == AddressFamily_Unknown) {
- *werror = WSAEAFNOSUPPORT;
- return NULL;
- }
-
- mono_array_set (data, guint8, 0, family & 0x0FF);
- mono_array_set (data, guint8, 1, (family >> 8) & 0x0FF);
-
- if (saddr->sa_family == AF_INET) {
- 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 < buffer_size) {
- mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
- return NULL;
- }
-
- mono_array_set (data, guint8, 2, (port>>8) & 0xff);
- mono_array_set (data, guint8, 3, (port) & 0xff);
- mono_array_set (data, guint8, 4, (address>>24) & 0xff);
- mono_array_set (data, guint8, 5, (address>>16) & 0xff);
- mono_array_set (data, guint8, 6, (address>>8) & 0xff);
- 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 < buffer_size) {
- mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
- return NULL;
- }
-
- mono_array_set (data, guint8, 2, (port>>8) & 0xff);
- mono_array_set (data, guint8, 3, (port) & 0xff);
-
- if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
- // Map ::ffff:0:0 to :: (bug #5502)
- for (i = 0; i < 16; i++)
- mono_array_set (data, guint8, 8 + i, 0);
- } else {
- for (i = 0; i < 16; i++) {
- mono_array_set (data, guint8, 8 + i,
- sa_in->sin6_addr.s6_addr [i]);
- }
- }
-
- mono_array_set (data, guint8, 24, sa_in->sin6_scope_id & 0xff);
- mono_array_set (data, guint8, 25,
- (sa_in->sin6_scope_id >> 8) & 0xff);
- mono_array_set (data, guint8, 26,
- (sa_in->sin6_scope_id >> 16) & 0xff);
- mono_array_set (data, guint8, 27,
- (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;
- }
-#endif
- else {
- *werror = WSAEAFNOSUPPORT;
- return NULL;
- }
-}
-
-static int
-get_sockaddr_size (int family)
-{
- int size;
-
- size = 0;
- if (family == AF_INET) {
- size = sizeof (struct sockaddr_in);
- } else if (family == AF_INET6) {
- size = sizeof (struct sockaddr_in6);
- }
-#ifdef HAVE_SYS_UN_H
- else if (family == AF_UNIX) {
- size = sizeof (struct sockaddr_un);
- }
-#endif
- return size;
-}
-
-MonoObject*
-ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal (SOCKET sock, gint32 af, gint32 *werror)
-{
- gchar *sa;
- socklen_t salen;
- int ret;
- MonoObject *result;
- MonoError error;
-
- *werror = 0;
-
- salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
- if (salen == 0) {
- *werror = WSAEAFNOSUPPORT;
- return NULL;
- }
- sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
-
- MONO_ENTER_GC_SAFE;
-
- ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
-
- MONO_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
- if (salen > 128)
- g_free (sa);
- return NULL;
- }
-
- 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)));
-
- result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
- if (salen > 128)
- g_free (sa);
- if (!mono_error_ok (&error))
- mono_error_set_pending_exception (&error);
- return result;
-}
-
-MonoObject*
-ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (SOCKET sock, gint32 af, gint32 *werror)
-{
- gchar *sa;
- socklen_t salen;
- int ret;
- MonoObject *result;
- MonoError error;
-
- *werror = 0;
-
- salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
- if (salen == 0) {
- *werror = WSAEAFNOSUPPORT;
- return NULL;
- }
- sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
- /* Note: linux returns just 2 for AF_UNIX. Always. */
-
- MONO_ENTER_GC_SAFE;
-
- ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
-
- MONO_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
- if (salen > 128)
- g_free (sa);
- return NULL;
- }
-
- 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)));
-
- result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
- if (salen > 128)
- g_free (sa);
- if (!mono_error_ok (&error))
- mono_error_set_pending_exception (&error);
- return result;
-}
-
-static struct sockaddr*
-create_sockaddr_from_object (MonoObject *saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
-{
- MonoDomain *domain = mono_domain_get ();
- MonoArray *data;
- gint32 family;
- int len;
-
- mono_error_init (error);
-
- 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
- * byte 1 is the address family high byte
- * INET:
- * bytes 2 and 3 are the port info
- * the rest is the address info
- * UNIX:
- * the rest is the file name
- */
- 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;
- guint16 port;
- guint32 address;
-
- if (len < 8) {
- mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
- return NULL;
- }
-
- sa = g_new0 (struct sockaddr_in, 1);
- port = (mono_array_get (data, guint8, 2) << 8) +
- mono_array_get (data, guint8, 3);
- address = (mono_array_get (data, guint8, 4) << 24) +
- (mono_array_get (data, guint8, 5) << 16 ) +
- (mono_array_get (data, guint8, 6) << 8) +
- mono_array_get (data, guint8, 7);
-
- sa->sin_family = family;
- sa->sin_addr.s_addr = htonl (address);
- sa->sin_port = htons (port);
-
- *sa_size = sizeof (struct sockaddr_in);
- return (struct sockaddr *)sa;
- } else if (family == AF_INET6) {
- struct sockaddr_in6 *sa;
- int i;
- guint16 port;
- guint32 scopeid;
-
- if (len < 28) {
- mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
- return NULL;
- }
-
- sa = g_new0 (struct sockaddr_in6, 1);
- port = mono_array_get (data, guint8, 3) +
- (mono_array_get (data, guint8, 2) << 8);
- scopeid = mono_array_get (data, guint8, 24) +
- (mono_array_get (data, guint8, 25) << 8) +
- (mono_array_get (data, guint8, 26) << 16) +
- (mono_array_get (data, guint8, 27) << 24);
-
- sa->sin6_family = family;
- sa->sin6_port = htons (port);
- sa->sin6_scope_id = scopeid;
-
- for (i = 0; i < 16; i++)
- sa->sin6_addr.s6_addr [i] = mono_array_get (data, guint8, 8 + i);
-
- *sa_size = sizeof (struct sockaddr_in6);
- return (struct sockaddr *)sa;
- }
-#ifdef HAVE_SYS_UN_H
- else if (family == AF_UNIX) {
- struct sockaddr_un *sock_un;
- int i;
-
- /* Need a byte for the '\0' terminator/prefix, and the first
- * two bytes hold the SocketAddress family
- */
- if (len - 2 >= sizeof (sock_un->sun_path)) {
- mono_error_set_exception_instance (error, mono_get_exception_index_out_of_range ());
- return NULL;
- }
-
- sock_un = g_new0 (struct sockaddr_un, 1);
-
- sock_un->sun_family = family;
- for (i = 0; i < len - 2; i++)
- sock_un->sun_path [i] = mono_array_get (data, guint8, i + 2);
-
- *sa_size = len;
- return (struct sockaddr *)sock_un;
- }
-#endif
- else {
- *werror = WSAEAFNOSUPPORT;
- return 0;
- }
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_Bind_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror)
-{
- MonoError error;
- struct sockaddr *sa;
- socklen_t sa_size;
- int ret;
-
- *werror = 0;
-
- sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
- if (*werror != 0)
- return;
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return;
- }
-
- 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)
- *werror = WSAGetLastError ();
-
- g_free (sa);
-}
-
-enum {
- SelectModeRead,
- SelectModeWrite,
- SelectModeError
-};
-
-MonoBoolean
-ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
- gint timeout, gint32 *werror)
-{
- MonoInternalThread *thread = mono_thread_internal_current ();
- mono_pollfd *pfds;
- int ret;
- gboolean interrupted;
- time_t start;
-
- *werror = 0;
-
- pfds = g_new0 (mono_pollfd, 1);
- pfds->fd = GPOINTER_TO_INT (sock);
-
- switch (mode) {
- case SelectModeRead:
- pfds->events = MONO_POLLIN;
- break;
- case SelectModeWrite:
- pfds->events = MONO_POLLOUT;
- break;
- default:
- pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL;
- break;
- }
-
- timeout = (timeout >= 0) ? (timeout / 1000) : -1;
- start = time (NULL);
-
- do {
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- g_free (pfds);
- *werror = WSAEINTR;
- return FALSE;
- }
-
- MONO_ENTER_GC_SAFE;
-
- ret = mono_poll (pfds, 1, timeout);
-
- MONO_EXIT_GC_SAFE;
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
- g_free (pfds);
- *werror = WSAEINTR;
- return FALSE;
- }
-
- if (timeout > 0 && ret < 0) {
- int err = errno;
- int sec = time (NULL) - start;
-
- timeout -= sec * 1000;
- if (timeout < 0) {
- timeout = 0;
- }
-
- errno = err;
- }
-
- if (ret == -1 && errno == EINTR) {
- if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
- g_free (pfds);
- return FALSE;
- }
-
- /* Suspend requested? */
- mono_thread_interruption_checkpoint ();
-
- errno = EINTR;
- }
- } while (ret == -1 && errno == EINTR);
-
- if (ret == -1) {
-#ifdef HOST_WIN32
- *werror = (errno > 0 && errno < WSABASEERR) ? errno + WSABASEERR : errno;
-#else
- *werror = errno_to_WSA (errno, __func__);
-#endif
- g_free (pfds);
- return FALSE;
- }
-
- g_free (pfds);
- return ret != 0;
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror, gboolean blocking)
-{
- MonoError error;
- struct sockaddr *sa;
- socklen_t sa_size;
- int ret;
- gboolean interrupted;
-
- *werror = 0;
-
- sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
- if (*werror != 0)
- return;
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return;
- }
-
- 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)));
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return;
- }
-
- 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_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-
- g_free (sa);
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
-/* These #defines from mswsock.h from wine. Defining them here allows
- * us to build this file on a mingw box that doesn't know the magic
- * numbers, but still run on a newer windows box that does.
- */
-#ifndef WSAID_DISCONNECTEX
-#define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
-typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
-#endif
-
-#ifndef WSAID_TRANSMITFILE
-#define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
-typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
-#endif
-
-void
-ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolean reuse, gint32 *werror)
-{
- int ret;
- glong output_bytes = 0;
- GUID disco_guid = WSAID_DISCONNECTEX;
- GUID trans_guid = WSAID_TRANSMITFILE;
- LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
- LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
- gboolean interrupted;
-
- *werror = 0;
-
- LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
-
- 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
- * pointers to functions in managed objects that still works
- * on 64bit platforms.
- */
- ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&disco_guid, sizeof (GUID),
- (gchar *)&_wapi_disconnectex, sizeof (void *), &output_bytes, NULL, NULL);
-
- MONO_EXIT_GC_SAFE;
-
- if (ret != 0) {
- /* make sure that WSAIoctl didn't put crap in the
- * output pointer
- */
- _wapi_disconnectex = NULL;
-
- MONO_ENTER_GC_SAFE;
-
- /*
- * Use the SIO_GET_EXTENSION_FUNCTION_POINTER to
- * determine the address of the disconnect method without
- * taking a hard dependency on a single provider
- *
- * For an explanation of why this is done, you can read
- * the article at http://www.codeproject.com/internet/jbsocketserver3.asp
- */
- ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&trans_guid, sizeof(GUID),
- (gchar *)&_wapi_transmitfile, sizeof(void *), &output_bytes, NULL, NULL);
-
- MONO_EXIT_GC_SAFE;
-
- if (ret != 0)
- _wapi_transmitfile = NULL;
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return;
- }
-
- MONO_ENTER_GC_SAFE;
-
- if (_wapi_disconnectex != NULL) {
- 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 | (reuse ? TF_REUSE_SOCKET : 0)))
- *werror = WSAGetLastError ();
- } else {
- *werror = ERROR_NOT_SUPPORTED;
- }
-
- MONO_EXIT_GC_SAFE;
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
-
-gint32
-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;
- gint32 alen;
- int recvflags = 0;
- gboolean interrupted;
- MonoInternalThread* curthread G_GNUC_UNUSED = mono_thread_internal_current ();
-
- *werror = 0;
-
- alen = mono_array_length (buffer);
- if (offset > alen - count)
- return 0;
-
- buf = mono_array_addr (buffer, guchar, offset);
-
- recvflags = convert_socketflags (flags);
- if (recvflags == -1) {
- *werror = WSAEOPNOTSUPP;
- return 0;
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted)
- return 0;
-
- MONO_ENTER_GC_SAFE;
-
-#ifdef HOST_WIN32
- {
- curthread->interrupt_on_stop = (gpointer)TRUE;
- ret = alertable_recv (sock, buf, count, recvflags, blocking);
- curthread->interrupt_on_stop = (gpointer)FALSE;
- }
-#else
- ret = _wapi_recv (sock, buf, count, recvflags);
-#endif
-
- MONO_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-
- if (*werror)
- return 0;
-
- return ret;
-}
-
-gint32
-ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror, gboolean blocking)
-{
- int ret, count;
- gboolean interrupted;
- DWORD recv;
- WSABUF *wsabufs;
- DWORD recvflags = 0;
-
- *werror = 0;
-
- wsabufs = mono_array_addr (buffers, WSABUF, 0);
- count = mono_array_length (buffers);
-
- recvflags = convert_socketflags (flags);
- if (recvflags == -1) {
- *werror = WSAEOPNOTSUPP;
- return 0;
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return 0;
- }
-
- 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;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-
- 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, gboolean blocking)
-{
- MonoError error;
- int ret;
- guchar *buf;
- gint32 alen;
- int recvflags = 0;
- struct sockaddr *sa;
- socklen_t sa_size;
- gboolean interrupted;
-
- *werror = 0;
-
- alen = mono_array_length (buffer);
- if (offset > alen - count)
- return 0;
-
- sa = create_sockaddr_from_object (*sockaddr, &sa_size, werror, &error);
- if (*werror != 0)
- return 0;
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return 0;
- }
-
- buf = mono_array_addr (buffer, guchar, offset);
-
- recvflags = convert_socketflags (flags);
- if (recvflags == -1) {
- *werror = WSAEOPNOTSUPP;
- return 0;
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- g_free (sa);
- *werror = WSAEINTR;
- return 0;
- }
-
- 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_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
-
- if (interrupted)
- *werror = WSAEINTR;
-
- if (*werror) {
- g_free(sa);
- return 0;
- }
-
- /* If we didn't get a socket size, then we're probably a
- * connected connection-oriented socket and the stack hasn't
- * returned the remote address. All we can do is return null.
- */
- if (sa_size) {
- *sockaddr = create_object_from_sockaddr (sa, sa_size, werror, &error);
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- g_free (sa);
- return 0;
- }
- } else {
- *sockaddr = NULL;
- }
-
- g_free (sa);
-
- return ret;
-}
-
-gint32
-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;
- gint32 alen;
- int sendflags = 0;
- gboolean interrupted;
-
- *werror = 0;
-
- alen = mono_array_length (buffer);
- if (offset > alen - count)
- return 0;
-
- LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
-
- buf = mono_array_addr (buffer, guchar, offset);
-
- LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
-
- sendflags = convert_socketflags (flags);
- if (sendflags == -1) {
- *werror = WSAEOPNOTSUPP;
- return 0;
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return 0;
- }
-
- 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_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-
- if (*werror)
- return 0;
-
- return ret;
-}
-
-gint32
-ves_icall_System_Net_Sockets_Socket_Send_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror, gboolean blocking)
-{
- int ret, count;
- DWORD sent;
- WSABUF *wsabufs;
- DWORD sendflags = 0;
- gboolean interrupted;
-
- *werror = 0;
-
- wsabufs = mono_array_addr (buffers, WSABUF, 0);
- count = mono_array_length (buffers);
-
- sendflags = convert_socketflags (flags);
- if (sendflags == -1) {
- *werror = WSAEOPNOTSUPP;
- return 0;
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return 0;
- }
-
- 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;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-
- 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, gboolean blocking)
-{
- MonoError error;
- int ret;
- guchar *buf;
- gint32 alen;
- int sendflags = 0;
- struct sockaddr *sa;
- socklen_t sa_size;
- gboolean interrupted;
-
- *werror = 0;
-
- alen = mono_array_length (buffer);
- if (offset > alen - count) {
- return 0;
- }
-
- sa = create_sockaddr_from_object(sockaddr, &sa_size, werror, &error);
- if (*werror != 0)
- return 0;
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return 0;
- }
-
- LOGDEBUG (g_message ("%s: alen: %d", __func__, alen));
-
- buf = mono_array_addr (buffer, guchar, offset);
-
- LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
-
- sendflags = convert_socketflags (flags);
- if (sendflags == -1) {
- g_free (sa);
- *werror = WSAEOPNOTSUPP;
- return 0;
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- g_free (sa);
- *werror = WSAEINTR;
- return 0;
- }
-
- 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;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted)
- *werror = WSAEINTR;
-
- g_free(sa);
-
- if (*werror)
- return 0;
-
- return ret;
-}
-
-static SOCKET
-Socket_to_SOCKET (MonoObject *sockobj)
-{
- MonoSafeHandle *safe_handle;
- MonoClassField *field;
-
- 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 -1;
-
- return (SOCKET)safe_handle->handle;
-}
-
-#define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
-
-void
-ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32 timeout, gint32 *werror)
-{
- MonoError error;
- MonoInternalThread *thread = mono_thread_internal_current ();
- MonoObject *obj;
- mono_pollfd *pfds;
- int nfds, idx;
- int ret;
- int i, count;
- int mode;
- MonoClass *sock_arr_class;
- MonoArray *socks;
- time_t start;
- uintptr_t socks_size;
- gboolean interrupted;
-
- *werror = 0;
-
- /* *sockets -> READ, null, WRITE, null, ERROR, null */
- count = mono_array_length (*sockets);
- nfds = count - 3; /* NULL separators */
- pfds = g_new0 (mono_pollfd, nfds);
- mode = idx = 0;
- for (i = 0; i < count; i++) {
- obj = mono_array_get (*sockets, MonoObject *, i);
- if (obj == NULL) {
- mode++;
- continue;
- }
-
- if (idx >= nfds) {
- /* The socket array was bogus */
- g_free (pfds);
- *werror = WSAEFAULT;
- return;
- }
-
- pfds [idx].fd = Socket_to_SOCKET (obj);
- pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
- idx++;
- }
-
- timeout = (timeout >= 0) ? (timeout / 1000) : -1;
- start = time (NULL);
- do {
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- g_free (pfds);
- *werror = WSAEINTR;
- return;
- }
-
- MONO_ENTER_GC_SAFE;
-
- ret = mono_poll (pfds, nfds, timeout);
-
- MONO_EXIT_GC_SAFE;
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
- g_free (pfds);
- *werror = WSAEINTR;
- return;
- }
-
- if (timeout > 0 && ret < 0) {
- int err = errno;
- int sec = time (NULL) - start;
-
- timeout -= sec * 1000;
- if (timeout < 0)
- timeout = 0;
- errno = err;
- }
-
- if (ret == -1 && errno == EINTR) {
- if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
- g_free (pfds);
- *sockets = NULL;
- return;
- }
-
- /* Suspend requested? */
- mono_thread_interruption_checkpoint ();
-
- errno = EINTR;
- }
- } while (ret == -1 && errno == EINTR);
-
- if (ret == -1) {
-#ifdef HOST_WIN32
- *werror = (errno > 0 && errno < WSABASEERR) ? errno + WSABASEERR : errno;
-#else
- *werror = errno_to_WSA (errno, __func__);
-#endif
- g_free (pfds);
- return;
- }
-
- if (ret == 0) {
- g_free (pfds);
- *sockets = NULL;
- return;
- }
-
- sock_arr_class = ((MonoObject *)*sockets)->vtable->klass;
- socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
- socks = mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, &error);
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- g_free (pfds);
- return;
- }
-
- mode = idx = 0;
- for (i = 0; i < count && ret > 0; i++) {
- mono_pollfd *pfd;
-
- obj = mono_array_get (*sockets, MonoObject *, i);
- if (obj == NULL) {
- mode++;
- idx++;
- continue;
- }
-
- pfd = &pfds [i - mode];
- if (pfd->revents == 0)
- continue;
-
- ret--;
- if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
- mono_array_setref (socks, idx++, obj);
- } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
- mono_array_setref (socks, idx++, obj);
- } else if ((pfd->revents & POLL_ERRORS) != 0) {
- mono_array_setref (socks, idx++, obj);
- }
- }
-
- *sockets = socks;
- g_free (pfds);
-}
-
-static MonoObject*
-int_to_object (MonoDomain *domain, int val, MonoError *error)
-{
- return mono_value_box_checked (domain, mono_get_int32_class (), &val, error);
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *werror)
-{
- int system_level = 0;
- int system_name = 0;
- int ret;
- int val = 0;
- socklen_t valsize = sizeof (val);
- struct linger linger;
- socklen_t lingersize = sizeof (linger);
- int time_ms = 0;
- socklen_t time_ms_size = sizeof (time_ms);
-#ifdef SO_PEERCRED
-# if defined(__OpenBSD__)
- struct sockpeercred cred;
-# else
- struct ucred cred;
-# endif
- socklen_t credsize = sizeof (cred);
-#endif
- MonoError error;
- MonoDomain *domain = mono_domain_get ();
- MonoObject *obj;
- MonoClass *obj_class;
- MonoClassField *field;
-
- *werror = 0;
-
-#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
- if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
- system_level = SOL_SOCKET;
- system_name = SO_REUSEADDR;
- ret = 0;
- } else
-#endif
- {
- ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
- }
-
- if (ret == -1) {
- *werror = WSAENOPROTOOPT;
- return;
- }
- if (ret == -2) {
- *obj_val = int_to_object (domain, 0, &error);
- mono_error_set_pending_exception (&error);
- return;
- }
-
- MONO_ENTER_GC_SAFE;
-
- /* No need to deal with MulticastOption names here, because
- * you cant getsockopt AddMembership or DropMembership (the
- * int getsockopt will error, causing an exception)
- */
- switch (name) {
- case SocketOptionName_Linger:
- case SocketOptionName_DontLinger:
- ret = _wapi_getsockopt (sock, system_level, system_name, &linger, &lingersize);
- break;
-
- case SocketOptionName_SendTimeout:
- case SocketOptionName_ReceiveTimeout:
- ret = _wapi_getsockopt (sock, system_level, system_name, (char *)&time_ms, &time_ms_size);
- break;
-
-#ifdef SO_PEERCRED
- case SocketOptionName_PeerCred:
- ret = _wapi_getsockopt (sock, system_level, system_name, &cred, &credsize);
- break;
-#endif
-
- default:
- ret = _wapi_getsockopt (sock, system_level, system_name, &val, &valsize);
- }
-
- MONO_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
- return;
- }
-
- switch (name) {
- case SocketOptionName_Linger:
- /* build a System.Net.Sockets.LingerOption */
- obj_class = mono_class_load_from_name (get_socket_assembly (),
- "System.Net.Sockets",
- "LingerOption");
- obj = mono_object_new_checked (domain, obj_class, &error);
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return;
- }
-
- /* Locate and set the fields "bool enabled" and "int
- * lingerTime"
- */
- field = mono_class_get_field_from_name(obj_class, "enabled");
- *(guint8 *)(((char *)obj)+field->offset) = linger.l_onoff;
-
- field = mono_class_get_field_from_name(obj_class, "lingerTime");
- *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
- break;
- case SocketOptionName_DontLinger:
- /* construct a bool int in val - true if linger is off */
- obj = int_to_object (domain, !linger.l_onoff, &error);
- mono_error_set_pending_exception (&error);
- break;
- case SocketOptionName_SendTimeout:
- case SocketOptionName_ReceiveTimeout:
- obj = int_to_object (domain, time_ms, &error);
- mono_error_set_pending_exception (&error);
- break;
-
-#ifdef SO_PEERCRED
- case SocketOptionName_PeerCred: {
- /*
- * build a Mono.Posix.PeerCred+PeerCredData if
- * possible
- */
- static MonoImage *mono_posix_image = NULL;
- MonoPeerCredData *cred_data;
-
- if (mono_posix_image == NULL) {
- mono_posix_image = mono_image_loaded ("Mono.Posix");
- if (!mono_posix_image) {
- MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
- if (!sa) {
- *werror = WSAENOPROTOOPT;
- return;
- } else {
- mono_posix_image = mono_assembly_get_image (sa);
- }
- }
- }
-
- obj_class = mono_class_load_from_name (mono_posix_image,
- "Mono.Posix",
- "PeerCredData");
- obj = mono_object_new_checked (domain, obj_class, &error);
- if (!mono_error_ok (&error)) {
- mono_error_set_pending_exception (&error);
- return;
- }
- cred_data = (MonoPeerCredData *)obj;
- cred_data->pid = cred.pid;
- cred_data->uid = cred.uid;
- cred_data->gid = cred.gid;
- break;
- }
-#endif
-
- default:
-#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
- if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
- val = val ? 0 : 1;
-#endif
- obj = int_to_object (domain, val, &error);
- mono_error_set_pending_exception (&error);
- }
-
- *obj_val = obj;
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *werror)
-{
- int system_level = 0;
- int system_name = 0;
- int ret;
- guchar *buf;
- socklen_t valsize;
-
- *werror = 0;
-
- ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
- &system_name);
- if (ret == -1) {
- *werror = WSAENOPROTOOPT;
- return;
- }
- if (ret == -2)
- return;
-
- valsize = mono_array_length (*byte_val);
- buf = mono_array_addr (*byte_val, guchar, 0);
-
- MONO_ENTER_GC_SAFE;
-
- ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
-
- MONO_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-}
-
-#if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
-static struct in_addr
-ipaddress_to_struct_in_addr (MonoObject *ipaddr)
-{
- struct in_addr inaddr;
- MonoClassField *field;
-
- field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Address");
-
- /* No idea why .net uses a 64bit type to hold a 32bit value...
- *
- * Internal value of IPAddess is in little-endian order
- */
- inaddr.s_addr = GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr) + field->offset));
-
- return inaddr;
-}
-
-static struct in6_addr
-ipaddress_to_struct_in6_addr (MonoObject *ipaddr)
-{
- struct in6_addr in6addr;
- MonoClassField *field;
- MonoArray *data;
- int i;
-
- field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Numbers");
- g_assert (field);
- data = *(MonoArray **)(((char *)ipaddr) + field->offset);
-
- for (i = 0; i < 8; 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
- in6addr.s6_addr16[i] = s;
-#endif
- }
- return in6addr;
-}
-#endif
-
-#if defined(__APPLE__) || defined(__FreeBSD__)
-
-static int
-get_local_interface_id (int family)
-{
-#if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
- return 0;
-#else
- struct ifaddrs *ifap = NULL, *ptr;
- int idx = 0;
-
- if (getifaddrs (&ifap))
- return 0;
-
- for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
- if (!ptr->ifa_addr || !ptr->ifa_name)
- continue;
- if (ptr->ifa_addr->sa_family != family)
- continue;
- if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
- continue;
- if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
- continue;
-
- idx = if_nametoindex (ptr->ifa_name);
- break;
- }
-
- freeifaddrs (ifap);
- return idx;
-#endif
-}
-
-#endif /* defined(__APPLE__) || defined(__FreeBSD__) */
-
-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 *werror)
-{
- struct linger linger;
- int system_level = 0;
- int system_name = 0;
- int ret;
- int sol_ip;
- int sol_ipv6;
-
- *werror = 0;
-
- sol_ipv6 = mono_networking_get_ipv6_protocol ();
- sol_ip = mono_networking_get_ip_protocol ();
-
- ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
- &system_name);
-
-#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
- if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
- system_name = SO_REUSEADDR;
- int_val = int_val ? 0 : 1;
- ret = 0;
- }
-#endif
-
- if (ret == -1) {
- *werror = WSAENOPROTOOPT;
- return;
- }
- if (ret == -2)
- return;
-
- /* Only one of obj_val, byte_val or int_val has data */
- if (obj_val) {
- MonoClassField *field;
- int valsize;
-
- switch (name) {
- case SocketOptionName_Linger:
- /* Dig out "bool enabled" and "int lingerTime"
- * fields
- */
- field = mono_class_get_field_from_name (obj_val->vtable->klass, "enabled");
- linger.l_onoff = *(guint8 *)(((char *)obj_val) + field->offset);
- field = mono_class_get_field_from_name (obj_val->vtable->klass, "lingerTime");
- linger.l_linger = *(guint32 *)(((char *)obj_val) + field->offset);
-
- valsize = sizeof (linger);
- ret = _wapi_setsockopt (sock, system_level,
- system_name, &linger, valsize);
- break;
- case SocketOptionName_AddMembership:
- case SocketOptionName_DropMembership:
-#if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
- {
- MonoObject *address = NULL;
-
- if (system_level == sol_ipv6) {
- struct ipv6_mreq mreq6;
-
- /*
- * 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)
- mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
-
- field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Interface");
- mreq6.ipv6mr_interface = *(guint64 *)(((char *)obj_val) + field->offset);
-
-#if defined(__APPLE__) || defined(__FreeBSD__)
- /*
- * Bug #5504:
- *
- * Mac OS Lion doesn't allow ipv6mr_interface = 0.
- *
- * Tests on Windows and Linux show that the multicast group is only
- * joined on one NIC when interface = 0, so we simply use the interface
- * id from the first non-loopback interface (this is also what
- * Dns.GetHostName (string.Empty) would return).
- */
- if (!mreq6.ipv6mr_interface)
- mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
-#endif
-
- ret = _wapi_setsockopt (sock, system_level,
- system_name, &mreq6,
- sizeof (mreq6));
- } else if (system_level == sol_ip) {
-#ifdef HAVE_STRUCT_IP_MREQN
- struct ip_mreqn mreq = {{0}};
-#else
- struct ip_mreq mreq = {{0}};
-#endif /* HAVE_STRUCT_IP_MREQN */
-
- /*
- * pain! MulticastOption holds two IPAddress
- * members, so I have to dig the value out of
- * those :-(
- */
- field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
- address = *(MonoObject **)(((char *)obj_val) + field->offset);
-
- /* address might not be defined and if so, set the address to ADDR_ANY.
- */
- if (address)
- mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
-
- field = mono_class_get_field_from_name (obj_val->vtable->klass, "localAddress");
- address = *(MonoObject **)(((char *)obj_val) + field->offset);
-
-#ifdef HAVE_STRUCT_IP_MREQN
- if (address)
- mreq.imr_address = ipaddress_to_struct_in_addr (address);
-
- field = mono_class_get_field_from_name (obj_val->vtable->klass, "ifIndex");
- mreq.imr_ifindex = *(gint32 *)(((char *)obj_val) + field->offset);
-#else
- if (address)
- mreq.imr_interface = ipaddress_to_struct_in_addr (address);
-#endif /* HAVE_STRUCT_IP_MREQN */
-
- ret = _wapi_setsockopt (sock, system_level,
- system_name, &mreq,
- sizeof (mreq));
- }
- break;
- }
-#endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
- default:
- /* Cause an exception to be thrown */
- *werror = WSAEINVAL;
- return;
- }
- } else if (byte_val!=NULL) {
- 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 {
- *werror = 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_MulticastInterface:
-#ifndef HOST_WIN32
-#ifdef HAVE_STRUCT_IP_MREQN
- int_val = GUINT32_FROM_BE (int_val);
- if ((int_val & 0xff000000) == 0) {
- /* int_val is interface index */
- struct ip_mreqn mreq = {{0}};
- mreq.imr_ifindex = int_val;
- ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &mreq, sizeof (mreq));
- break;
- }
- int_val = GUINT32_TO_BE (int_val);
-#endif /* HAVE_STRUCT_IP_MREQN */
-#endif /* HOST_WIN32 */
- /* int_val is in_addr */
- ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
- break;
- case SocketOptionName_DontFragment:
-#ifdef HAVE_IP_MTU_DISCOVER
- /* Fiddle with the value slightly if we're
- * turning DF on
- */
- if (int_val == 1)
- int_val = IP_PMTUDISC_DO;
- /* Fall through */
-#endif
-
- default:
- ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
- }
- }
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-}
-
-void
-ves_icall_System_Net_Sockets_Socket_Shutdown_internal (SOCKET sock, gint32 how, gint32 *werror)
-{
- int ret;
- gboolean interrupted;
-
- *werror = 0;
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- return;
- }
-
- 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_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
- *werror = WSAEINTR;
- }
-
-}
-
-gint
-ves_icall_System_Net_Sockets_Socket_IOControl_internal (SOCKET sock, gint32 code, MonoArray *input, MonoArray *output, gint32 *werror)
-{
- glong output_bytes = 0;
- gchar *i_buffer, *o_buffer;
- gint i_len, o_len;
- gint ret;
-
- *werror = 0;
-
- if ((guint32)code == FIONBIO)
- /* Invalid command. Must use Socket.Blocking */
- return -1;
-
- if (input == NULL) {
- i_buffer = NULL;
- i_len = 0;
- } else {
- i_buffer = mono_array_addr (input, gchar, 0);
- i_len = mono_array_length (input);
- }
-
- if (output == NULL) {
- o_buffer = NULL;
- o_len = 0;
- } else {
- o_buffer = mono_array_addr (output, gchar, 0);
- o_len = mono_array_length (output);
- }
-
- MONO_ENTER_GC_SAFE;
-
- ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
-
- MONO_EXIT_GC_SAFE;
-
- if (ret == SOCKET_ERROR) {
- *werror = WSAGetLastError ();
- return -1;
- }
-
- return (gint)output_bytes;
-}
-
-static gboolean
-addrinfo_to_IPHostEntry (MonoAddressInfo *info, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips, MonoError *error)
-{
- gint32 count, i;
- MonoAddressEntry *ai = NULL;
- struct in_addr *local_in = NULL;
- int nlocal_in = 0;
- struct in6_addr *local_in6 = NULL;
- int nlocal_in6 = 0;
- int addr_index;
- MonoDomain *domain = mono_domain_get ();
-
- mono_error_init (error);
- addr_index = 0;
- *h_aliases = mono_array_new_checked (domain, mono_get_string_class (), 0, error);
- return_val_if_nok (error, FALSE);
- if (add_local_ips) {
- local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
- local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
- if (nlocal_in || nlocal_in6) {
- char addr [INET6_ADDRSTRLEN];
- *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error);
- if (!is_ok (error))
- goto leave;
-
- if (nlocal_in) {
- MonoString *addr_string;
- int i;
-
- for (i = 0; i < nlocal_in; i++) {
- MonoAddress maddr;
- mono_address_init (&maddr, AF_INET, &local_in [i]);
- if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
- addr_string = mono_string_new (domain, addr);
- mono_array_setref (*h_addr_list, addr_index, addr_string);
- addr_index++;
- }
- }
- }
-
- if (nlocal_in6) {
- MonoString *addr_string;
- int i;
-
- for (i = 0; i < nlocal_in6; i++) {
- MonoAddress maddr;
- mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
- if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
- addr_string = mono_string_new (domain, addr);
- mono_array_setref (*h_addr_list, addr_index, addr_string);
- addr_index++;
- }
- }
- }
-
- leave:
- g_free (local_in);
- g_free (local_in6);
- if (info)
- mono_free_address_info (info);
- return is_ok (error);;
- }
-
- g_free (local_in);
- g_free (local_in6);
- }
-
- for (count = 0, ai = info->entries; ai != NULL; ai = ai->next) {
- if (ai->family != AF_INET && ai->family != AF_INET6)
- continue;
- count++;
- }
-
- *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), count, error);
- if (!is_ok (error))
- goto leave2;
-
- for (ai = info->entries, i = 0; ai != NULL; ai = ai->next) {
- MonoAddress maddr;
- MonoString *addr_string;
- char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
-
- if ((ai->family != PF_INET) && (ai->family != PF_INET6))
- continue;
-
- mono_address_init (&maddr, ai->family, &ai->address);
- if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
- addr_string = mono_string_new (domain, buffer);
- else
- addr_string = mono_string_new (domain, "");
-
- mono_array_setref (*h_addr_list, addr_index, addr_string);
-
- if (!i) {
- i++;
- if (ai->canonical_name != NULL) {
- *h_name = mono_string_new (domain, ai->canonical_name);
- } else {
- *h_name = mono_string_new (domain, buffer);
- }
- }
-
- addr_index++;
- }
-
-leave2:
- if (info)
- mono_free_address_info (info);
-
- return is_ok (error);
-}
-
-MonoBoolean
-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_checked (host, &error);
- if (mono_error_set_pending_exception (&error))
- return FALSE;
-
- if (*hostname == '\0') {
- add_local_ips = TRUE;
- *h_name = host;
- }
-
- if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
- if (!strcmp (hostname, this_hostname)) {
- add_local_ips = TRUE;
- *h_name = host;
- }
- }
-
-#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);
-
- if (add_info_ok) {
- MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, add_local_ips, &error);
- mono_error_set_pending_exception (&error);
- return result;
- }
- return FALSE;
-}
-
-MonoBoolean
-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;
- gchar hostname [NI_MAXHOST] = { 0 };
- gboolean ret;
-
- 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;
- saddr.sin_family = AF_INET;
- } else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
- family = AF_INET6;
- saddr6.sin6_family = AF_INET6;
- } else {
- g_free (address);
- return FALSE;
- }
-
- g_free (address);
-
- MONO_ENTER_GC_SAFE;
-
- switch (family) {
- case AF_INET: {
-#if HAVE_SOCKADDR_IN_SIN_LEN
- saddr.sin_len = sizeof (saddr);
-#endif
- ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
- break;
- }
- case AF_INET6: {
-#if HAVE_SOCKADDR_IN6_SIN_LEN
- saddr6.sin6_len = sizeof (saddr6);
-#endif
- ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
- break;
- }
- default:
- g_assert_not_reached ();
- }
-
- MONO_EXIT_GC_SAFE;
-
- if (!ret)
- return FALSE;
-
- if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
- return FALSE;
-
- MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE, &error);
- mono_error_set_pending_exception (&error);
- return result;
-}
-
-MonoBoolean
-ves_icall_System_Net_Dns_GetHostName_internal (MonoString **h_name)
-{
- gchar hostname [NI_MAXHOST] = { 0 };
- int ret;
-
- ret = gethostname (hostname, sizeof (hostname));
- if (ret == -1)
- return FALSE;
-
- *h_name = mono_string_new (mono_domain_get (), hostname);
-
- return TRUE;
-}
-
-#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
-gboolean
-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;
- gboolean ret;
- gboolean interrupted;
- TRANSMIT_FILE_BUFFERS buffers;
-
- if (filename == NULL)
- return FALSE;
-
- /* 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);
-
- if (file == INVALID_HANDLE_VALUE) {
- SetLastError (*werror);
- 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);
- }
-
- mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
- if (interrupted) {
- CloseHandle (file);
- SetLastError (WSAEINTR);
- return FALSE;
- }
-
- 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;
-
- if (!ret)
- *werror = WSAGetLastError ();
-
- mono_thread_info_uninstall_interrupt (&interrupted);
- if (interrupted) {
- CloseHandle (file);
- *werror = WSAEINTR;
- return FALSE;
- }
-
- MONO_ENTER_GC_SAFE;
-
- CloseHandle (file);
-
- MONO_EXIT_GC_SAFE;
-
- if (*werror)
- return FALSE;
-
- return ret;
-}
-#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
-
-gboolean
-ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
-{
-#if defined (SO_REUSEPORT) || defined (HOST_WIN32)
- return TRUE;
-#else
-#ifdef __linux__
- /* Linux always supports double binding for UDP, even on older kernels. */
- if (proto == ProtocolType_Udp)
- return TRUE;
-#endif
- return FALSE;
-#endif
-}
-
-void
-mono_network_init (void)
-{
- mono_networking_init ();
-}
-
-void
-mono_network_cleanup (void)
-{
- _wapi_cleanup_networking ();
- mono_networking_shutdown ();
-}
-
-void
-icall_cancel_blocking_socket_operation (MonoThread *thread)
-{
- MonoInternalThread *internal;
-
- internal = thread->internal_thread;
- g_assert (internal);
-
- mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
-}
-
-#endif /* #ifndef DISABLE_SOCKETS */
+++ /dev/null
-/*
- * socket-io.h: Socket IO internal calls
- *
- * Author:
- * Dick Porter (dick@ximian.com)
- *
- * (C) 2001 Ximian, Inc.
- */
-
-#ifndef _MONO_METADATA_SOCKET_H_
-#define _MONO_METADATA_SOCKET_H_
-
-#include <config.h>
-#include <glib.h>
-
-#include <mono/metadata/object-internals.h>
-#include <mono/io-layer/io-layer.h>
-
-/* This is a copy of System.Net.Sockets.SocketType */
-typedef enum {
- SocketType_Stream=1,
- SocketType_Dgram=2,
- SocketType_Raw=3,
- SocketType_Rdm=4,
- SocketType_Seqpacket=5,
- SocketType_Unknown=-1
-} MonoSocketType;
-
-/* This is a copy of System.Net.Sockets.AddressFamily */
-typedef enum {
- AddressFamily_Unknown=-1,
- AddressFamily_Unspecified=0,
- AddressFamily_Unix=1,
- AddressFamily_InterNetwork=2,
- AddressFamily_ImpLink=3,
- AddressFamily_Pup=4,
- AddressFamily_Chaos=5,
- AddressFamily_NS=6,
- AddressFamily_Ipx=6,
- AddressFamily_Iso=7,
- AddressFamily_Osi=7,
- AddressFamily_Ecma=8,
- AddressFamily_DataKit=9,
- AddressFamily_Ccitt=10,
- AddressFamily_Sna=11,
- AddressFamily_DecNet=12,
- AddressFamily_DataLink=13,
- AddressFamily_Lat=14,
- AddressFamily_HyperChannel=15,
- AddressFamily_AppleTalk=16,
- AddressFamily_NetBios=17,
- AddressFamily_VoiceView=18,
- AddressFamily_FireFox=19,
- AddressFamily_Banyan=21,
- AddressFamily_Atm=22,
- AddressFamily_InterNetworkV6=23,
- AddressFamily_Cluster=24,
- AddressFamily_Ieee12844=25,
- AddressFamily_Irda=26,
- AddressFamily_NetworkDesigners=28
-} MonoAddressFamily;
-
-/* This is a copy of System.Net.Sockets.ProtocolType */
-typedef enum {
- ProtocolType_IP=0,
- ProtocolType_Icmp=1,
- ProtocolType_Igmp=2,
- ProtocolType_Ggp=3,
- ProtocolType_Tcp=6,
- ProtocolType_Pup=12,
- ProtocolType_Udp=17,
- ProtocolType_Idp=22,
- ProtocolType_IPv6=41,
- ProtocolType_ND=77,
- ProtocolType_Raw=255,
- ProtocolType_Unspecified=0,
- ProtocolType_Ipx=1000,
- ProtocolType_Spx=1256,
- ProtocolType_SpxII=1257,
- ProtocolType_Unknown=-1
-} MonoProtocolType;
-
-/* This is a copy of System.Net.Sockets.SocketOptionLevel */
-typedef enum {
- SocketOptionLevel_Socket=65535,
- SocketOptionLevel_IP=0,
- SocketOptionLevel_IPv6=41,
- SocketOptionLevel_Tcp=6,
- SocketOptionLevel_Udp=17
-} MonoSocketOptionLevel;
-
-/* This is a copy of System.Net.Sockets.SocketOptionName */
-typedef enum {
- SocketOptionName_Debug=1,
- SocketOptionName_AcceptConnection=2,
- SocketOptionName_ReuseAddress=4,
- SocketOptionName_KeepAlive=8,
- SocketOptionName_DontRoute=16,
- SocketOptionName_IPProtectionLevel = 23,
- SocketOptionName_IPv6Only = 27,
- SocketOptionName_Broadcast=32,
- SocketOptionName_UseLoopback=64,
- SocketOptionName_Linger=128,
- SocketOptionName_OutOfBandInline=256,
- SocketOptionName_DontLinger= -129,
- SocketOptionName_ExclusiveAddressUse= -5,
- SocketOptionName_SendBuffer= 4097,
- SocketOptionName_ReceiveBuffer=4098,
- SocketOptionName_SendLowWater=4099,
- SocketOptionName_ReceiveLowWater=4100,
- SocketOptionName_SendTimeout=4101,
- SocketOptionName_ReceiveTimeout=4102,
- SocketOptionName_Error=4103,
- SocketOptionName_Type=4104,
- SocketOptionName_MaxConnections=2147483647,
- SocketOptionName_IPOptions=1,
- SocketOptionName_HeaderIncluded=2,
- SocketOptionName_TypeOfService=3,
- SocketOptionName_IpTimeToLive=4,
- SocketOptionName_MulticastInterface=9,
- SocketOptionName_MulticastTimeToLive=10,
- SocketOptionName_MulticastLoopback=11,
- SocketOptionName_AddMembership=12,
- SocketOptionName_DropMembership=13,
- SocketOptionName_DontFragment=14,
- SocketOptionName_AddSourceMembership=15,
- SocketOptionName_DropSourceMembership=16,
- SocketOptionName_BlockSource=17,
- SocketOptionName_UnblockSource=18,
- SocketOptionName_PacketInformation=19,
- SocketOptionName_NoDelay=1,
- SocketOptionName_BsdUrgent=2,
- SocketOptionName_Expedited=2,
- SocketOptionName_NoChecksum=1,
- SocketOptionName_ChecksumCoverage=20,
- SocketOptionName_HopLimit=21,
-
- /* This is Mono-specific, keep it in sync with
- * Mono.Posix/PeerCred.cs
- */
- SocketOptionName_PeerCred=10001
-} MonoSocketOptionName;
-
-/* This is a copy of System.Net.Sockets.SocketFlags */
-typedef enum {
- SocketFlags_None = 0x0000,
- SocketFlags_OutOfBand = 0x0001,
- SocketFlags_MaxIOVectorLength = 0x0010,
- SocketFlags_Peek = 0x0002,
- SocketFlags_DontRoute = 0x0004,
- SocketFlags_Partial = 0x8000
-} MonoSocketFlags;
-
-typedef struct
-{
- MonoObject obj;
- gint pid;
- gint uid;
- gint gid;
-} MonoPeerCredData;
-
-extern gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this_obj, gint32 family, gint32 type, gint32 proto, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock, gint32 *error);
-extern gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void);
-extern gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock, gboolean block, gint32 *error);
-extern gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock, gint32 *error, gboolean blocking);
-extern void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock, guint32 backlog, gint32 *error);
-extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 af, gint32 *error);
-extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 af, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error, gboolean blocking);
-extern gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error, gboolean blocking);
-extern gint32 ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error, gboolean blocking);
-extern gint32 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error, gboolean blocking);
-extern gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error, gboolean blocking);
-extern gint32 ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error, gboolean blocking);
-extern gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error, gboolean blocking);
-extern void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock, gint32 how, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error);
-extern 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);
-extern int ves_icall_System_Net_Sockets_Socket_IOControl_internal (SOCKET sock, gint32 code, MonoArray *input, MonoArray *output, gint32 *error);
-extern MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gint32 hint);
-extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gint32 hint);
-extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name);
-extern MonoBoolean ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode, gint timeout, gint32 *error);
-extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, MonoBoolean reuse, gint32 *error);
-extern gboolean ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags, gint32 *error, gboolean blocking);
-void icall_cancel_blocking_socket_operation (MonoThread *thread);
-extern gboolean ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto);
-
-extern void mono_network_init(void);
-extern void mono_network_cleanup(void);
-
-#endif /* _MONO_METADATA_SOCKET_H_ */
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-lazy-init.h>
#include <mono/utils/mono-logger-internals.h>
+#include <mono/io-layer/io-layer.h>
typedef struct {
gboolean (*init) (gint wakeup_pipe_fd);
#include <glib.h>
#include <mono/metadata/object-internals.h>
-#include <mono/metadata/socket-io.h>
typedef struct _MonoIOSelectorJob MonoIOSelectorJob;
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-rand.h>
#include <mono/utils/refcount.h>
+#include <mono/io-layer/io-layer.h>
#define CPU_USAGE_LOW 80
#define CPU_USAGE_HIGH 95
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/refcount.h>
+#include <mono/io-layer/io-layer.h>
typedef struct {
MonoDomain *domain;
--- /dev/null
+/*
+* w32socket-internals.h
+*
+* Copyright 2016 Microsoft
+* Licensed under the MIT license. See LICENSE file in the project root for full license information.
+*/
+#ifndef __MONO_METADATA_W32SOCKET_INTERNALS_H__
+#define __MONO_METADATA_W32SOCKET_INTERNALS_H__
+
+#include <config.h>
+#include <glib.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include <mono/io-layer/io-layer.h>
+
+#ifndef HAVE_SOCKLEN_T
+#define socklen_t int
+#endif
+
+#ifndef HOST_WIN32
+
+#define TF_DISCONNECT 0x01
+#define TF_REUSE_SOCKET 0x02
+
+typedef struct {
+ guint32 len;
+ gpointer buf;
+} WSABUF;
+
+typedef struct {
+ guint32 Internal;
+ guint32 InternalHigh;
+ guint32 Offset;
+ guint32 OffsetHigh;
+ gpointer hEvent;
+ gpointer handle1;
+ gpointer handle2;
+} OVERLAPPED;
+
+typedef struct {
+ gpointer Head;
+ guint32 HeadLength;
+ gpointer Tail;
+ guint32 TailLength;
+} TRANSMIT_FILE_BUFFERS;
+
+typedef struct {
+ guint32 Data1;
+ guint16 Data2;
+ guint16 Data3;
+ guint8 Data4[8];
+} GUID;
+
+typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, OVERLAPPED*, guint32, guint32);
+typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, guint32, guint32, OVERLAPPED*, TRANSMIT_FILE_BUFFERS*, guint32);
+
+#endif
+
+void
+mono_w32socket_initialize (void);
+
+void
+mono_w32socket_cleanup (void);
+
+SOCKET
+mono_w32socket_accept (SOCKET s, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking);
+
+int
+mono_w32socket_connect (SOCKET s, const struct sockaddr *name, int namelen, gboolean blocking);
+
+int
+mono_w32socket_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking);
+
+int
+mono_w32socket_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking);
+
+int
+mono_w32socket_recvbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 *lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking);
+
+int
+mono_w32socket_send (SOCKET s, char *buf, int len, int flags, gboolean blocking);
+
+int
+mono_w32socket_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking);
+
+int
+mono_w32socket_sendbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking);
+
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
+
+BOOL
+mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, TRANSMIT_FILE_BUFFERS *lpTransmitBuffers, guint32 dwReserved, gboolean blocking);
+
+#endif
+
+#ifndef HOST_WIN32
+
+SOCKET
+mono_w32socket_socket (int domain, int type, int protocol);
+
+gint
+mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen);
+
+gint
+mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen);
+
+gint
+mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen);
+
+gint
+mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen);
+
+gint
+mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen);
+
+gint
+mono_w32socket_listen (SOCKET sock, gint backlog);
+
+gint
+mono_w32socket_shutdown (SOCKET sock, gint how);
+
+gint
+mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written);
+
+#endif /* HOST_WIN32 */
+
+gint
+mono_w32socket_disconnect (SOCKET sock, gboolean reuse);
+
+gint
+mono_w32socket_set_blocking (SOCKET socket, gboolean blocking);
+
+gint
+mono_w32socket_get_available (SOCKET socket, guint64 *amount);
+
+void
+mono_w32socket_set_last_error (gint32 error);
+
+gint32
+mono_w32socket_get_last_error (void);
+
+gint32
+mono_w32socket_convert_error (gint error);
+
+#endif // __MONO_METADATA_W32SOCKET_INTERNALS_H__
--- /dev/null
+/*
+ * w32socket-unix.c: Unix specific socket code.
+ *
+ * Copyright 2016 Microsoft
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <arpa/inet.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h> /* defines FIONBIO and FIONREAD */
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h> /* defines SIOCATMARK */
+#endif
+#ifndef HAVE_MSG_NOSIGNAL
+#include <signal.h>
+#endif
+#ifdef HAVE_SYS_SENDFILE_H
+#include <sys/sendfile.h>
+#endif
+
+#include "w32socket.h"
+#include "w32socket-internals.h"
+#include "w32handle.h"
+#include "utils/mono-logger-internals.h"
+#include "utils/mono-poll.h"
+
+typedef struct {
+ int domain;
+ int type;
+ int protocol;
+ int saved_error;
+ int still_readable;
+} MonoW32HandleSocket;
+
+static guint32 in_cleanup = 0;
+
+static void
+socket_close (gpointer handle, gpointer data)
+{
+ int ret;
+ MonoW32HandleSocket *socket_handle = (MonoW32HandleSocket *)data;
+ MonoThreadInfo *info = mono_thread_info_current ();
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle);
+
+ /* 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);
+
+ do {
+ ret = close (GPOINTER_TO_UINT(handle));
+ } 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: close error: %s", __func__, g_strerror (errno));
+ if (!in_cleanup)
+ mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
+ }
+
+ if (!in_cleanup)
+ socket_handle->saved_error = 0;
+}
+
+static void
+socket_details (gpointer data)
+{
+ /* FIXME: do something */
+}
+
+static const gchar*
+socket_typename (void)
+{
+ return "Socket";
+}
+
+static gsize
+socket_typesize (void)
+{
+ return sizeof (MonoW32HandleSocket);
+}
+
+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);
+
+ return FALSE;
+}
+
+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;
+ MonoThreadInfo *info;
+
+ 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);
+ 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));
+ 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);
+
+ close (new_fd);
+
+ 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;
+
+ 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_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with",
+ __func__, new_handle);
+
+ return new_fd;
+}
+
+int
+mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking)
+{
+ gpointer handle;
+ 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);
+ return SOCKET_ERROR;
+ }
+
+ if (connect (sock, addr, addrlen) == -1) {
+ MonoThreadInfo *info;
+ mono_pollfd fds;
+ gint errnum, so_error;
+ socklen_t len;
+
+ errnum = errno;
+
+ if (errno != EINTR) {
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__,
+ g_strerror (errnum));
+
+ errnum = mono_w32socket_convert_error (errnum);
+ if (errnum == WSAEINPROGRESS)
+ errnum = WSAEWOULDBLOCK; /* see bug #73053 */
+
+ mono_w32socket_set_last_error (errnum);
+
+ /*
+ * On solaris x86 getsockopt (SO_ERROR) is not set after
+ * connect () fails so we need to save this error.
+ *
+ * But don't do this for EWOULDBLOCK (bug 317315)
+ */
+ if (errnum != WSAEWOULDBLOCK) {
+ /* ECONNRESET means the socket was closed by another thread */
+ /* Async close on mac raises ECONNABORTED. */
+ socket_handle->saved_error = errnum;
+ }
+ return SOCKET_ERROR;
+ }
+
+ info = mono_thread_info_current ();
+
+ fds.fd = sock;
+ fds.events = MONO_POLLOUT;
+ while (mono_poll (&fds, 1, -1) == -1 && !mono_thread_info_is_interrupt_state (info)) {
+ 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));
+ return SOCKET_ERROR;
+ }
+ }
+
+ len = sizeof(so_error);
+ if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &len) == -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));
+ return SOCKET_ERROR;
+ }
+
+ if (so_error != 0) {
+ gint errnum = mono_w32socket_convert_error (so_error);
+
+ /* Need to save this socket error */
+ socket_handle->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);
+ return SOCKET_ERROR;
+ }
+ }
+
+ return 0;
+}
+
+int
+mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
+{
+ return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking);
+}
+
+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;
+ 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);
+ return SOCKET_ERROR;
+ }
+
+ info = mono_thread_info_current ();
+
+ do {
+ ret = recvfrom (sock, buf, len, flags, from, fromlen);
+ } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
+
+ if (ret == 0 && len > 0) {
+ /* According to the Linux man page, recvfrom only
+ * returns 0 when the socket has been shut down
+ * cleanly. Turn this into an EINTR to simulate win32
+ * behaviour of returning EINTR when a socket is
+ * closed while the recvfrom is blocking (we use a
+ * shutdown() in socket_close() to trigger this.) See
+ * bug 75705.
+ */
+ /* Distinguish between the socket being shut down at
+ * the local or remote ends, and reads that request 0
+ * bytes to be read
+ */
+
+ /* If this returns FALSE, it means the socket has been
+ * closed locally. If it returns TRUE, but
+ * still_readable != 1 then shutdown
+ * (SHUT_RD|SHUT_RDWR) has been called locally.
+ */
+ if (socket_handle->still_readable != 1) {
+ ret = -1;
+ errno = EINTR;
+ }
+ }
+
+ if (ret == -1) {
+ 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));
+ return SOCKET_ERROR;
+ }
+ return ret;
+}
+
+static void
+wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr)
+{
+ guint32 i;
+
+ memset (hdr, 0, sizeof (struct msghdr));
+ hdr->msg_iovlen = count;
+ hdr->msg_iov = g_new0 (struct iovec, count);
+ for (i = 0; i < count; i++) {
+ hdr->msg_iov [i].iov_base = buffers [i].buf;
+ hdr->msg_iov [i].iov_len = buffers [i].len;
+ }
+}
+
+static void
+msghdr_iov_free (struct msghdr *hdr)
+{
+ g_free (hdr->msg_iov);
+}
+
+int
+mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking)
+{
+ MonoW32HandleSocket *socket_handle;
+ 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);
+ return SOCKET_ERROR;
+ }
+
+ info = mono_thread_info_current ();
+
+ wsabuf_to_msghdr (buffers, count, &hdr);
+
+ do {
+ ret = recvmsg (sock, &hdr, *flags);
+ } 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) {
+ ret = -1;
+ errno = EINTR;
+ }
+ }
+
+ if (ret == -1) {
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ *received = ret;
+ *flags = hdr.msg_flags;
+
+ return 0;
+}
+
+int
+mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
+{
+ gpointer handle;
+ int ret;
+ MonoThreadInfo *info;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ info = mono_thread_info_current ();
+
+ do {
+ ret = send (sock, buf, len, flags);
+ } 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));
+
+#ifdef O_NONBLOCK
+ /* 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);
+ if (ret != -1 && (ret & O_NONBLOCK) == 0)
+ errnum = ETIMEDOUT;
+ }
+#endif /* O_NONBLOCK */
+ mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
+ return SOCKET_ERROR;
+ }
+ 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;
+ int ret;
+ MonoThreadInfo *info;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ info = mono_thread_info_current ();
+
+ do {
+ ret = sendto (sock, buf, len, flags, to, tolen);
+ } 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));
+ return SOCKET_ERROR;
+ }
+ return ret;
+}
+
+int
+mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking)
+{
+ struct msghdr hdr;
+ MonoThreadInfo *info;
+ gpointer handle;
+ 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);
+ return SOCKET_ERROR;
+ }
+
+ info = mono_thread_info_current ();
+
+ wsabuf_to_msghdr (buffers, count, &hdr);
+
+ do {
+ ret = sendmsg (sock, &hdr, flags);
+ } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
+
+ msghdr_iov_free (&hdr);
+
+ if (ret == -1) {
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ *sent = ret;
+ return 0;
+}
+
+#define SF_BUFFER_SIZE 16384
+
+BOOL
+mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking)
+{
+ MonoThreadInfo *info;
+ gpointer handle;
+ gint file;
+ gssize ret;
+#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
+ struct stat statbuf;
+#else
+ 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;
+ }
+
+ /* 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)
+ return FALSE;
+ }
+
+ info = mono_thread_info_current ();
+
+ file = GPOINTER_TO_INT (file_handle);
+
+#if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
+ ret = fstat (file, &statbuf);
+ if (ret == -1) {
+ gint errnum = errno;
+ mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
+ return SOCKET_ERROR;
+ }
+
+ do {
+#ifdef __linux__
+ ret = sendfile (sock, 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);
+#endif
+ } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
+#else
+ buffer = g_malloc (SF_BUFFER_SIZE);
+
+ do {
+ do {
+ ret = read (file, buffer, SF_BUFFER_SIZE);
+ } 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? */
+ } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
+ } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
+
+ g_free (buffer);
+#endif
+
+ if (ret == -1) {
+ gint errnum = errno;
+ mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
+ 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)
+ return FALSE;
+ }
+
+ if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
+ CloseHandle (handle);
+
+ 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);
+ }
+
+ 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;
+ }
+
+ /* .net seems to set this by default for SOCK_STREAM, not for
+ * SOCK_DGRAM (see bug #36322)
+ * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
+ *
+ * It seems winsock has a rather different idea of what
+ * SO_REUSEADDR means. If it's set, then a new socket can be
+ * bound over an existing listening socket. There's a new
+ * windows-specific option called SO_EXCLUSIVEADDRUSE but
+ * using that means the socket MUST be closed properly, or a
+ * denial of service can occur. Luckily for us, winsock
+ * behaves as though any other system would when SO_REUSEADDR
+ * is true, so we don't need to do anything else here. See
+ * bug 53992.
+ * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
+ */
+ {
+ int ret, true_ = 1;
+
+ ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
+ 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));
+ return INVALID_SOCKET;
+ }
+ }
+
+
+ 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);
+
+ return sock;
+}
+
+gint
+mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
+{
+ gpointer handle;
+ int ret;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ ret = bind (sock, addr, addrlen);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ return 0;
+}
+
+gint
+mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
+{
+ gpointer handle;
+ gint ret;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ ret = getpeername (sock, name, namelen);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ return 0;
+}
+
+gint
+mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
+{
+ gpointer handle;
+ gint ret;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ ret = getsockname (sock, name, namelen);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ return 0;
+}
+
+gint
+mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
+{
+ gpointer handle;
+ 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);
+ return SOCKET_ERROR;
+ }
+
+ tmp_val = optval;
+ if (level == SOL_SOCKET &&
+ (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
+ tmp_val = &tv;
+ *optlen = sizeof (tv);
+ }
+
+ ret = getsockopt (sock, level, optname, tmp_val, optlen);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
+ *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
+ *optlen = sizeof (int);
+ }
+
+ if (optname == SO_ERROR) {
+ if (*((int *)optval) != 0) {
+ *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
+ socket_handle->saved_error = *((int *)optval);
+ } else {
+ *((int *)optval) = socket_handle->saved_error;
+ }
+ }
+
+ return 0;
+}
+
+gint
+mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen)
+{
+ gpointer handle;
+ gint ret;
+ gpointer tmp_val;
+#if defined (__linux__)
+ /* This has its address taken so it cannot be moved to the if block which uses it */
+ gint bufsize = 0;
+#endif
+ struct timeval tv;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ tmp_val = optval;
+ if (level == SOL_SOCKET &&
+ (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
+ int ms = *((int *) optval);
+ tv.tv_sec = ms / 1000;
+ tv.tv_usec = (ms % 1000) * 1000; // micro from milli
+ tmp_val = &tv;
+ optlen = sizeof (tv);
+ }
+#if defined (__linux__)
+ else if (level == SOL_SOCKET &&
+ (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
+ /* According to socket(7) the Linux kernel doubles the
+ * buffer sizes "to allow space for bookkeeping
+ * overhead."
+ */
+ bufsize = *((int *) optval);
+
+ bufsize /= 2;
+ tmp_val = &bufsize;
+ }
+#endif
+
+ ret = setsockopt (sock, level, optname, tmp_val, optlen);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+#if defined (SO_REUSEPORT)
+ /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
+ if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
+ 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);
+ }
+ }
+#endif
+
+ return ret;
+}
+
+gint
+mono_w32socket_listen (SOCKET sock, gint backlog)
+{
+ gpointer handle;
+ gint ret;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ ret = listen (sock, backlog);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ return 0;
+}
+
+gint
+mono_w32socket_shutdown (SOCKET sock, gint how)
+{
+ MonoW32HandleSocket *socket_handle;
+ gpointer handle;
+ gint ret;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ if (how == SHUT_RD || how == SHUT_RDWR)
+ socket_handle->still_readable = 0;
+
+ ret = shutdown (sock, how);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ return ret;
+}
+
+gint
+mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
+{
+ MonoW32HandleSocket *socket_handle;
+ gpointer handle;
+ SOCKET newsock;
+ gint ret;
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, sock);
+
+ /* We could check the socket type here and fail unless its
+ * 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);
+ return SOCKET_ERROR;
+ }
+
+ newsock = socket (socket_handle->domain, socket_handle->type, socket_handle->protocol);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ /* According to Stevens "Advanced Programming in the UNIX
+ * Environment: UNIX File I/O" dup2() is atomic so there
+ * 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);
+ } 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));
+ return SOCKET_ERROR;
+ }
+
+ close (newsock);
+
+ return 0;
+}
+
+static gboolean
+extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
+{
+ return mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
+}
+
+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);
+}
+
+static struct {
+ GUID guid;
+ gpointer func;
+} extension_functions[] = {
+ { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, extension_disconect },
+ { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, extension_transmit_file },
+ { {0} , NULL },
+};
+
+gint
+mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
+{
+ gpointer handle;
+ gint ret;
+ gchar *buffer;
+
+ handle = GUINT_TO_POINTER (sock);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+ if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
+ gint i;
+ GUID *guid;
+
+ if (inputlen < sizeof(GUID)) {
+ /* As far as I can tell, windows doesn't
+ * actually set an error here...
+ */
+ mono_w32socket_set_last_error (WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ if (outputlen < sizeof(gpointer)) {
+ /* Or here... */
+ mono_w32socket_set_last_error (WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ if (output == NULL) {
+ /* Or here */
+ mono_w32socket_set_last_error (WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ guid = (GUID*) input;
+ for (i = 0; extension_functions[i].func; i++) {
+ if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
+ memcpy (output, &extension_functions[i].func, sizeof(gpointer));
+ *written = sizeof(gpointer);
+ return 0;
+ }
+ }
+
+ mono_w32socket_set_last_error (WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
+ guint32 onoff;
+
+ if (inputlen < 3 * sizeof (guint32)) {
+ mono_w32socket_set_last_error (WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ onoff = *((guint32*) input);
+
+ ret = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
+ if (ret < 0) {
+ mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
+ return SOCKET_ERROR;
+ }
+
+#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
+ if (onoff != 0) {
+ /* Values are in ms, but we need s */
+ guint32 keepalivetime, keepaliveinterval, rem;
+
+ keepalivetime = *(((guint32*) input) + 1);
+ keepaliveinterval = *(((guint32*) input) + 2);
+
+ /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
+ rem = keepalivetime % 1000;
+ keepalivetime /= 1000;
+ if (keepalivetime == 0 || rem >= 500)
+ keepalivetime++;
+ ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
+ if (ret == 0) {
+ rem = keepaliveinterval % 1000;
+ keepaliveinterval /= 1000;
+ if (keepaliveinterval == 0 || rem >= 500)
+ keepaliveinterval++;
+ ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
+ }
+ if (ret != 0) {
+ mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
+ return SOCKET_ERROR;
+ }
+
+ return 0;
+ }
+#endif
+
+ return 0;
+ }
+
+ buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
+
+ ret = ioctl (sock, command, buffer);
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ if (!buffer) {
+ *written = 0;
+ return 0;
+ }
+
+ /* We just copy the buffer to the output. Some ioctls
+ * don't even output any data, but, well...
+ *
+ * NB windows returns WSAEFAULT if outputlen is too small */
+ inputlen = (inputlen > outputlen) ? outputlen : inputlen;
+
+ if (inputlen > 0 && output != NULL)
+ memcpy (output, buffer, inputlen);
+
+ g_free (buffer);
+ *written = inputlen;
+
+ return 0;
+}
+
+gint
+mono_w32socket_set_blocking (SOCKET socket, gboolean blocking)
+{
+ gint ret;
+ gpointer handle;
+
+ handle = GINT_TO_POINTER (socket);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (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 */
+
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ return 0;
+}
+
+gint
+mono_w32socket_get_available (SOCKET socket, guint64 *amount)
+{
+ gint ret;
+ gpointer handle;
+
+ handle = GINT_TO_POINTER (socket);
+ if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
+ mono_w32socket_set_last_error (WSAENOTSOCK);
+ return SOCKET_ERROR;
+ }
+
+#if defined (PLATFORM_MACOSX)
+ // ioctl (socket, FIONREAD, XXX) returns the size of
+ // the UDP header as well on Darwin.
+ //
+ // Use getsockopt SO_NREAD instead to get the
+ // right values for TCP and UDP.
+ //
+ // ai_canonname can be null in some cases on darwin,
+ // where the runtime assumes it will be the value of
+ // the ip buffer.
+
+ socklen_t optlen = sizeof (int);
+ ret = getsockopt (socket, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
+#else
+ ret = ioctl (socket, FIONREAD, (gulong*) amount);
+#endif
+
+ 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));
+ return SOCKET_ERROR;
+ }
+
+ return 0;
+}
+
+void
+mono_w32socket_set_last_error (gint32 error)
+{
+ SetLastError (error);
+}
+
+gint32
+mono_w32socket_get_last_error (void)
+{
+ return GetLastError ();
+}
+
+gint32
+mono_w32socket_convert_error (gint error)
+{
+ switch (error) {
+ case 0: return ERROR_SUCCESS;
+ case EACCES: return WSAEACCES;
+#ifdef EADDRINUSE
+ case EADDRINUSE: return WSAEADDRINUSE;
+#endif
+#ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
+#endif
+#if EAGAIN != EWOULDBLOCK
+ case EAGAIN: return WSAEWOULDBLOCK;
+#endif
+#ifdef EALREADY
+ case EALREADY: return WSAEALREADY;
+#endif
+ case EBADF: return WSAENOTSOCK;
+#ifdef ECONNABORTED
+ case ECONNABORTED: return WSAENETDOWN;
+#endif
+#ifdef ECONNREFUSED
+ case ECONNREFUSED: return WSAECONNREFUSED;
+#endif
+#ifdef ECONNRESET
+ case ECONNRESET: return WSAECONNRESET;
+#endif
+ case EFAULT: return WSAEFAULT;
+#ifdef EHOSTUNREACH
+ case EHOSTUNREACH: return WSAEHOSTUNREACH;
+#endif
+#ifdef EINPROGRESS
+ case EINPROGRESS: return WSAEINPROGRESS;
+#endif
+ case EINTR: return WSAEINTR;
+ case EINVAL: return WSAEINVAL;
+ /*FIXME: case EIO: return WSAE????; */
+#ifdef EISCONN
+ case EISCONN: return WSAEISCONN;
+#endif
+ /* FIXME: case ELOOP: return WSA????; */
+ case EMFILE: return WSAEMFILE;
+#ifdef EMSGSIZE
+ case EMSGSIZE: return WSAEMSGSIZE;
+#endif
+ /* FIXME: case ENAMETOOLONG: return WSAEACCES; */
+#ifdef ENETUNREACH
+ case ENETUNREACH: return WSAENETUNREACH;
+#endif
+#ifdef ENOBUFS
+ case ENOBUFS: return WSAENOBUFS; /* not documented */
+#endif
+ /* case ENOENT: return WSAE????; */
+ case ENOMEM: return WSAENOBUFS;
+#ifdef ENOPROTOOPT
+ case ENOPROTOOPT: return WSAENOPROTOOPT;
+#endif
+#ifdef ENOSR
+ case ENOSR: return WSAENETDOWN;
+#endif
+#ifdef ENOTCONN
+ case ENOTCONN: return WSAENOTCONN;
+#endif
+ /*FIXME: case ENOTDIR: return WSAE????; */
+#ifdef ENOTSOCK
+ case ENOTSOCK: return WSAENOTSOCK;
+#endif
+ case ENOTTY: return WSAENOTSOCK;
+#ifdef EOPNOTSUPP
+ case EOPNOTSUPP: return WSAEOPNOTSUPP;
+#endif
+ case EPERM: return WSAEACCES;
+ case EPIPE: return WSAESHUTDOWN;
+#ifdef EPROTONOSUPPORT
+ case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
+#endif
+#if ERESTARTSYS
+ case ERESTARTSYS: return WSAENETDOWN;
+#endif
+ /*FIXME: case EROFS: return WSAE????; */
+#ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
+#endif
+#ifdef ETIMEDOUT
+ case ETIMEDOUT: return WSAETIMEDOUT;
+#endif
+#ifdef EWOULDBLOCK
+ case EWOULDBLOCK: return WSAEWOULDBLOCK;
+#endif
+#ifdef EADDRNOTAVAIL
+ case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
+#endif
+ /* This might happen with unix sockets */
+ case ENOENT: return WSAECONNREFUSED;
+#ifdef EDESTADDRREQ
+ case EDESTADDRREQ: return WSAEDESTADDRREQ;
+#endif
+#ifdef EHOSTDOWN
+ case EHOSTDOWN: return WSAEHOSTDOWN;
+#endif
+#ifdef ENETDOWN
+ case ENETDOWN: return WSAENETDOWN;
+#endif
+ case ENODEV: return WSAENETDOWN;
+ 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)
+{
+#if defined (SO_REUSEPORT)
+ return TRUE;
+#else
+#ifdef __linux__
+ /* Linux always supports double binding for UDP, even on older kernels. */
+ if (proto == ProtocolType_Udp)
+ return TRUE;
+#endif
+ return FALSE;
+#endif
+}
--- /dev/null
+/*
+ * w32socket-win32.c: Windows specific socket code.
+ *
+ * Copyright 2016 Microsoft
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <ws2tcpip.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <sys/types.h>
+
+#include "w32socket.h"
+#include "w32socket-internals.h"
+
+#define LOGDEBUG(...)
+
+void
+mono_w32socket_initialize (void)
+{
+}
+
+void
+mono_w32socket_cleanup (void)
+{
+}
+
+static gboolean set_blocking (SOCKET sock, gboolean block)
+{
+ u_long non_block = block ? 0 : 1;
+ return ioctlsocket (sock, FIONBIO, &non_block) != SOCKET_ERROR;
+}
+
+static DWORD get_socket_timeout (SOCKET sock, int optname)
+{
+ DWORD timeout = 0;
+ int optlen = sizeof (DWORD);
+ if (getsockopt (sock, SOL_SOCKET, optname, (char *)&timeout, &optlen) == SOCKET_ERROR) {
+ WSASetLastError (0);
+ return WSA_INFINITE;
+ }
+ if (timeout == 0)
+ timeout = WSA_INFINITE; // 0 means infinite
+ return timeout;
+}
+
+/*
+* Performs an alertable wait for the specified event (FD_ACCEPT_BIT,
+* FD_CONNECT_BIT, FD_READ_BIT, FD_WRITE_BIT) on the specified socket.
+* Returns TRUE if the event is fired without errors. Calls WSASetLastError()
+* with WSAEINTR and returns FALSE if the thread is alerted. If the event is
+* fired but with an error WSASetLastError() is called to set the error and the
+* function returns FALSE.
+*/
+static gboolean alertable_socket_wait (SOCKET sock, int event_bit)
+{
+ static char *EVENT_NAMES[] = { "FD_READ", "FD_WRITE", NULL /*FD_OOB*/, "FD_ACCEPT", "FD_CONNECT", "FD_CLOSE" };
+ gboolean success = FALSE;
+ int error = -1;
+ DWORD timeout = WSA_INFINITE;
+ if (event_bit == FD_READ_BIT || event_bit == FD_WRITE_BIT) {
+ timeout = get_socket_timeout (sock, event_bit == FD_READ_BIT ? SO_RCVTIMEO : SO_SNDTIMEO);
+ }
+ WSASetLastError (0);
+ WSAEVENT event = WSACreateEvent ();
+ if (event != WSA_INVALID_EVENT) {
+ if (WSAEventSelect (sock, event, (1 << event_bit) | FD_CLOSE) != SOCKET_ERROR) {
+ LOGDEBUG (g_message ("%06d - Calling WSAWaitForMultipleEvents () on socket %d", GetCurrentThreadId (), sock));
+ DWORD ret = WSAWaitForMultipleEvents (1, &event, TRUE, timeout, TRUE);
+ if (ret == WSA_WAIT_IO_COMPLETION) {
+ LOGDEBUG (g_message ("%06d - WSAWaitForMultipleEvents () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), sock));
+ error = WSAEINTR;
+ } else if (ret == WSA_WAIT_TIMEOUT) {
+ error = WSAETIMEDOUT;
+ } else {
+ g_assert (ret == WSA_WAIT_EVENT_0);
+ WSANETWORKEVENTS ne = { 0 };
+ if (WSAEnumNetworkEvents (sock, event, &ne) != SOCKET_ERROR) {
+ if (ne.lNetworkEvents & (1 << event_bit) && ne.iErrorCode[event_bit]) {
+ LOGDEBUG (g_message ("%06d - %s error %d on socket %d", GetCurrentThreadId (), EVENT_NAMES[event_bit], ne.iErrorCode[event_bit], sock));
+ error = ne.iErrorCode[event_bit];
+ } else if (ne.lNetworkEvents & FD_CLOSE_BIT && ne.iErrorCode[FD_CLOSE_BIT]) {
+ LOGDEBUG (g_message ("%06d - FD_CLOSE error %d on socket %d", GetCurrentThreadId (), ne.iErrorCode[FD_CLOSE_BIT], sock));
+ error = ne.iErrorCode[FD_CLOSE_BIT];
+ } else {
+ LOGDEBUG (g_message ("%06d - WSAEnumNetworkEvents () finished successfully on socket %d", GetCurrentThreadId (), sock));
+ success = TRUE;
+ error = 0;
+ }
+ }
+ }
+ WSAEventSelect (sock, NULL, 0);
+ }
+ WSACloseEvent (event);
+ }
+ if (error != -1) {
+ WSASetLastError (error);
+ }
+ return success;
+}
+
+#define ALERTABLE_SOCKET_CALL(event_bit, blocking, repeat, ret, op, sock, ...) \
+ LOGDEBUG (g_message ("%06d - Performing %s " #op " () on socket %d", GetCurrentThreadId (), blocking ? "blocking" : "non-blocking", sock)); \
+ if (blocking) { \
+ if (set_blocking(sock, FALSE)) { \
+ while (-1 == (int) (ret = op (sock, __VA_ARGS__))) { \
+ int _error = WSAGetLastError ();\
+ if (_error != WSAEWOULDBLOCK && _error != WSA_IO_PENDING) \
+ break; \
+ if (!alertable_socket_wait (sock, event_bit) || !repeat) \
+ break; \
+ } \
+ int _saved_error = WSAGetLastError (); \
+ set_blocking (sock, TRUE); \
+ WSASetLastError (_saved_error); \
+ } \
+ } else { \
+ ret = op (sock, __VA_ARGS__); \
+ } \
+ int _saved_error = WSAGetLastError (); \
+ LOGDEBUG (g_message ("%06d - Finished %s " #op " () on socket %d (ret = %d, WSAGetLastError() = %d)", GetCurrentThreadId (), \
+ blocking ? "blocking" : "non-blocking", sock, ret, _saved_error)); \
+ WSASetLastError (_saved_error);
+
+SOCKET mono_w32socket_accept (SOCKET s, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking)
+{
+ MonoInternalThread *curthread = mono_thread_internal_current ();
+ SOCKET newsock = INVALID_SOCKET;
+ curthread->interrupt_on_stop = (gpointer)TRUE;
+ ALERTABLE_SOCKET_CALL (FD_ACCEPT_BIT, blocking, TRUE, newsock, accept, s, addr, addrlen);
+ curthread->interrupt_on_stop = (gpointer)FALSE;
+ return newsock;
+}
+
+int mono_w32socket_connect (SOCKET s, const struct sockaddr *name, int namelen, gboolean blocking)
+{
+ int ret = SOCKET_ERROR;
+ ALERTABLE_SOCKET_CALL (FD_CONNECT_BIT, blocking, FALSE, ret, connect, s, name, namelen);
+ ret = WSAGetLastError () != 0 ? SOCKET_ERROR : 0;
+ return ret;
+}
+
+int mono_w32socket_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking)
+{
+ MonoInternalThread *curthread = mono_thread_internal_current ();
+ int ret = SOCKET_ERROR;
+ curthread->interrupt_on_stop = (gpointer)TRUE;
+ ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, recv, s, buf, len, flags);
+ curthread->interrupt_on_stop = (gpointer)FALSE;
+ return ret;
+}
+
+int mono_w32socket_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking)
+{
+ int ret = SOCKET_ERROR;
+ ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, recvfrom, s, buf, len, flags, from, fromlen);
+ return ret;
+}
+
+int mono_w32socket_recvbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 *lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking)
+{
+ int ret = SOCKET_ERROR;
+ ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, WSARecv, s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
+ return ret;
+}
+
+int mono_w32socket_send (SOCKET s, char *buf, int len, int flags, gboolean blocking)
+{
+ int ret = SOCKET_ERROR;
+ ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, send, s, buf, len, flags);
+ return ret;
+}
+
+int mono_w32socket_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
+{
+ int ret = SOCKET_ERROR;
+ ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, sendto, s, buf, len, flags, to, tolen);
+ return ret;
+}
+
+int mono_w32socket_sendbuffers (SOCKET s, WSABUF *lpBuffers, guint32 dwBufferCount, guint32 *lpNumberOfBytesRecvd, guint32 lpFlags, gpointer lpOverlapped, gpointer lpCompletionRoutine, gboolean blocking)
+{
+ int ret = SOCKET_ERROR;
+ ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, WSASend, s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
+ return ret;
+}
+
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
+BOOL mono_w32socket_transmit_file (SOCKET hSocket, gpointer hFile, TRANSMIT_FILE_BUFFERS *lpTransmitBuffers, guint32 dwReserved, gboolean blocking)
+{
+ LOGDEBUG (g_message ("%06d - Performing %s TransmitFile () on socket %d", GetCurrentThreadId (), blocking ? "blocking" : "non-blocking", hSocket));
+
+ int error = 0;
+ if (blocking) {
+ OVERLAPPED overlapped = { 0 };
+ overlapped.hEvent = WSACreateEvent ();
+ if (overlapped.hEvent == WSA_INVALID_EVENT)
+ return FALSE;
+ if (!TransmitFile (hSocket, hFile, 0, 0, &overlapped, lpTransmitBuffers, dwReserved)) {
+ error = WSAGetLastError ();
+ if (error == WSA_IO_PENDING) {
+ error = 0;
+ // NOTE: .NET's Socket.SendFile() doesn't honor the Socket's SendTimeout so we shouldn't either
+ DWORD ret = WaitForSingleObjectEx (overlapped.hEvent, INFINITE, TRUE);
+ if (ret == WAIT_IO_COMPLETION) {
+ LOGDEBUG (g_message ("%06d - WaitForSingleObjectEx () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), hSocket));
+ error = WSAEINTR;
+ } else if (ret == WAIT_TIMEOUT) {
+ error = WSAETIMEDOUT;
+ } else if (ret != WAIT_OBJECT_0) {
+ error = GetLastError ();
+ }
+ }
+ }
+ WSACloseEvent (overlapped.hEvent);
+ } else {
+ if (!TransmitFile (hSocket, hFile, 0, 0, NULL, lpTransmitBuffers, dwReserved)) {
+ error = WSAGetLastError ();
+ }
+ }
+
+ LOGDEBUG (g_message ("%06d - Finished %s TransmitFile () on socket %d (ret = %d, WSAGetLastError() = %d)", GetCurrentThreadId (), \
+ blocking ? "blocking" : "non-blocking", hSocket, error == 0, error));
+ WSASetLastError (error);
+
+ return error == 0;
+}
+#endif /* #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
+
+gint
+mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
+{
+ LPFN_DISCONNECTEX disconnect;
+ LPFN_TRANSMITFILE transmit_file;
+ DWORD output_bytes;
+ gint ret;
+
+ /* Use the SIO_GET_EXTENSION_FUNCTION_POINTER to determine
+ * the address of the disconnect method without taking
+ * a hard dependency on a single provider
+ *
+ * For an explanation of why this is done, you can read the
+ * article at http://www.codeproject.com/internet/jbsocketserver3.asp
+ *
+ * I _think_ the extension function pointers need to be looked
+ * up for each socket.
+ *
+ * FIXME: check the best way to store pointers to functions in
+ * managed objects that still works on 64bit platforms. */
+
+ GUID disconnect_guid = WSAID_DISCONNECTEX;
+ ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &disconnect_guid, sizeof (GUID), &disconnect, sizeof (LPFN_DISCONNECTEX), &output_bytes, NULL, NULL);
+ if (ret == 0) {
+ if (!disconnect (sock, NULL, reuse ? TF_REUSE_SOCKET : 0, 0))
+ return WSAGetLastError ();
+
+ return 0;
+ }
+
+ GUID transmit_file_guid = WSAID_TRANSMITFILE;
+ ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &transmit_file_guid, sizeof (GUID), &transmit_file, sizeof (LPFN_TRANSMITFILE), &output_bytes, NULL, NULL);
+ if (ret == 0) {
+ if (!transmit_file (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | (reuse ? TF_REUSE_SOCKET : 0)))
+ return WSAGetLastError ();
+
+ return 0;
+ }
+
+ return ERROR_NOT_SUPPORTED;
+}
+
+gint
+mono_w32socket_set_blocking (SOCKET sock, gboolean blocking)
+{
+ gulong nonblocking_long = !blocking;
+ return ioctlsocket (sock, FIONBIO, &nonblocking_long);
+}
+
+gint
+mono_w32socket_get_available (SOCKET sock, guint64 *amount)
+{
+ return ioctlsocket (sock, FIONREAD, (int*) amount);
+}
+
+void
+mono_w32socket_set_last_error (gint32 error)
+{
+ WSASetLastError (error);
+}
+
+gint32
+mono_w32socket_get_last_error (void)
+{
+ return WSAGetLastError ();
+}
+
+gint32
+mono_w32socket_convert_error (gint error)
+{
+ return (error > 0 && error < WSABASEERR) ? error + WSABASEERR : error;
+}
+
+gboolean
+ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
+{
+ return TRUE;
+}
--- /dev/null
+/*
+ * socket-io.c: Socket IO internal calls
+ *
+ * Authors:
+ * Dick Porter (dick@ximian.com)
+ * Gonzalo Paniagua Javier (gonzalo@ximian.com)
+ *
+ * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
+ * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ *
+ * This file has been re-licensed under the MIT License:
+ * http://opensource.org/licenses/MIT
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include <config.h>
+
+#ifndef DISABLE_SOCKETS
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#define __APPLE_USE_RFC_3542
+#endif
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef HOST_WIN32
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <sys/types.h>
+
+#include <mono/metadata/object.h>
+#include <mono/io-layer/io-layer.h>
+#include <mono/metadata/exception.h>
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/file-io.h>
+#include <mono/metadata/threads.h>
+#include <mono/metadata/threads-types.h>
+#include <mono/metadata/threadpool-io.h>
+#include <mono/utils/mono-poll.h>
+/* FIXME change this code to not mess so much with the internals */
+#include <mono/metadata/class-internals.h>
+#include <mono/metadata/domain-internals.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-memory-model.h>
+#include <mono/utils/networking.h>
+#include <mono/metadata/w32handle.h>
+#include <mono/metadata/w32socket.h>
+#include <mono/metadata/w32socket-internals.h>
+
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h> /* defines FIONBIO and FIONREAD */
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h> /* defines SIOCATMARK */
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#ifdef HAVE_GETIFADDRS
+// <net/if.h> must be included before <ifaddrs.h>
+#include <ifaddrs.h>
+#endif
+
+#if defined(_MSC_VER) && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
+#include <MSWSock.h>
+#endif
+
+#define LOGDEBUG(...)
+/* define LOGDEBUG(...) g_message(__VA_ARGS__) */
+
+#ifdef HOST_WIN32
+
+static SOCKET
+mono_w32socket_socket (int domain, int type, int protocol)
+{
+ return WSASocket (domain, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
+}
+
+static gint
+mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
+{
+ return bind (sock, addr, addrlen);
+}
+
+static gint
+mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
+{
+ return getpeername (sock, name, namelen);
+}
+
+static gint
+mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
+{
+ return getsockname (sock, name, namelen);
+}
+
+static gint
+mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
+{
+ return getsockopt (sock, level, optname, optval, optlen);
+}
+
+static gint
+mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen)
+{
+ return setsockopt (sock, level, optname, optval, optlen);
+}
+
+static gint
+mono_w32socket_listen (SOCKET sock, gint backlog)
+{
+ return listen (sock, backlog);
+}
+
+static gint
+mono_w32socket_shutdown (SOCKET sock, gint how)
+{
+ return shutdown (sock, how);
+}
+
+static gint
+mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
+{
+ return WSAIoctl (sock, command, input, inputlen, output, outputlen, written, NULL, NULL);
+}
+
+#endif /* HOST_WIN32 */
+
+static void
+abort_syscall (gpointer data)
+{
+ mono_thread_info_abort_socket_syscall_for_close ((MonoNativeThreadId) (gsize) data);
+}
+
+static gint32
+convert_family (MonoAddressFamily mono_family)
+{
+ switch (mono_family) {
+ case AddressFamily_Unknown:
+ case AddressFamily_ImpLink:
+ case AddressFamily_Pup:
+ case AddressFamily_Chaos:
+ case AddressFamily_Iso:
+ case AddressFamily_Ecma:
+ case AddressFamily_DataKit:
+ case AddressFamily_Ccitt:
+ case AddressFamily_DataLink:
+ case AddressFamily_Lat:
+ case AddressFamily_HyperChannel:
+ case AddressFamily_NetBios:
+ case AddressFamily_VoiceView:
+ case AddressFamily_FireFox:
+ case AddressFamily_Banyan:
+ case AddressFamily_Atm:
+ case AddressFamily_Cluster:
+ case AddressFamily_Ieee12844:
+ case AddressFamily_NetworkDesigners:
+ g_warning ("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
+ return -1;
+ case AddressFamily_Unspecified:
+ return AF_UNSPEC;
+ case AddressFamily_Unix:
+ return AF_UNIX;
+ case AddressFamily_InterNetwork:
+ return AF_INET;
+ case AddressFamily_AppleTalk:
+ return AF_APPLETALK;
+ case AddressFamily_InterNetworkV6:
+ return AF_INET6;
+ case AddressFamily_DecNet:
+#ifdef AF_DECnet
+ return AF_DECnet;
+#else
+ return -1;
+#endif
+ case AddressFamily_Ipx:
+#ifdef AF_IPX
+ return AF_IPX;
+#else
+ return -1;
+#endif
+ case AddressFamily_Sna:
+#ifdef AF_SNA
+ return AF_SNA;
+#else
+ return -1;
+#endif
+ case AddressFamily_Irda:
+#ifdef AF_IRDA
+ return AF_IRDA;
+#else
+ return -1;
+#endif
+ default:
+ g_warning ("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
+ return -1;
+ }
+}
+
+static MonoAddressFamily
+convert_to_mono_family (guint16 af_family)
+{
+ switch (af_family) {
+ case AF_UNSPEC:
+ return AddressFamily_Unspecified;
+ case AF_UNIX:
+ return AddressFamily_Unix;
+ case AF_INET:
+ return AddressFamily_InterNetwork;
+#ifdef AF_IPX
+ case AF_IPX:
+ return AddressFamily_Ipx;
+#endif
+#ifdef AF_SNA
+ case AF_SNA:
+ return AddressFamily_Sna;
+#endif
+#ifdef AF_DECnet
+ case AF_DECnet:
+ return AddressFamily_DecNet;
+#endif
+ case AF_APPLETALK:
+ return AddressFamily_AppleTalk;
+ case AF_INET6:
+ return AddressFamily_InterNetworkV6;
+#ifdef AF_IRDA
+ case AF_IRDA:
+ return AddressFamily_Irda;
+#endif
+ default:
+ g_warning ("unknown address family 0x%x", af_family);
+ return AddressFamily_Unknown;
+ }
+}
+
+static gint32
+convert_type (MonoSocketType mono_type)
+{
+ switch (mono_type) {
+ case SocketType_Stream:
+ return SOCK_STREAM;
+ case SocketType_Dgram:
+ return SOCK_DGRAM;
+ case SocketType_Raw:
+ return SOCK_RAW;
+ case SocketType_Rdm:
+#ifdef SOCK_RDM
+ return SOCK_RDM;
+#else
+ return -1;
+#endif
+ case SocketType_Seqpacket:
+ return SOCK_SEQPACKET;
+ case SocketType_Unknown:
+ g_warning ("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
+ return -1;
+ default:
+ g_warning ("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
+ return -1;
+ }
+}
+
+static gint32
+convert_proto (MonoProtocolType mono_proto)
+{
+ switch (mono_proto) {
+ case ProtocolType_IP:
+ case ProtocolType_IPv6:
+ case ProtocolType_Icmp:
+ case ProtocolType_Igmp:
+ case ProtocolType_Ggp:
+ case ProtocolType_Tcp:
+ case ProtocolType_Pup:
+ case ProtocolType_Udp:
+ case ProtocolType_Idp:
+ /* These protocols are known (on my system at least) */
+ return mono_proto;
+ case ProtocolType_ND:
+ case ProtocolType_Raw:
+ case ProtocolType_Ipx:
+ case ProtocolType_Spx:
+ case ProtocolType_SpxII:
+ case ProtocolType_Unknown:
+ /* These protocols arent */
+ g_warning ("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
+ return -1;
+ default:
+ return -1;
+ }
+}
+
+/* Convert MonoSocketFlags */
+static gint32
+convert_socketflags (gint32 sflags)
+{
+ gint32 flags = 0;
+
+ if (!sflags)
+ /* SocketFlags.None */
+ return 0;
+
+ if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek |
+ SocketFlags_DontRoute | SocketFlags_Partial))
+ /* Contains invalid flag values */
+ return -1;
+
+ if (sflags & SocketFlags_OutOfBand)
+ flags |= MSG_OOB;
+ if (sflags & SocketFlags_Peek)
+ flags |= MSG_PEEK;
+ if (sflags & SocketFlags_DontRoute)
+ flags |= MSG_DONTROUTE;
+
+ /* 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;
+#endif
+#if 0
+ /* Don't do anything for MaxIOVectorLength */
+ if (sflags & SocketFlags_MaxIOVectorLength)
+ return -1;
+#endif
+ return flags;
+}
+
+/*
+ * Returns:
+ * 0 on success (mapped mono_level and mono_name to system_level and system_name
+ * -1 on error
+ * -2 on non-fatal error (ie, must ignore)
+ */
+static gint32
+convert_sockopt_level_and_name (MonoSocketOptionLevel mono_level, MonoSocketOptionName mono_name, int *system_level, int *system_name)
+{
+ switch (mono_level) {
+ case SocketOptionLevel_Socket:
+ *system_level = SOL_SOCKET;
+
+ switch (mono_name) {
+ case SocketOptionName_DontLinger:
+ /* This is SO_LINGER, because the setsockopt
+ * internal call maps DontLinger to SO_LINGER
+ * with l_onoff=0
+ */
+ *system_name = SO_LINGER;
+ break;
+ case SocketOptionName_Debug:
+ *system_name = SO_DEBUG;
+ break;
+#ifdef SO_ACCEPTCONN
+ case SocketOptionName_AcceptConnection:
+ *system_name = SO_ACCEPTCONN;
+ break;
+#endif
+ case SocketOptionName_ReuseAddress:
+ *system_name = SO_REUSEADDR;
+ break;
+ case SocketOptionName_KeepAlive:
+ *system_name = SO_KEEPALIVE;
+ break;
+ case SocketOptionName_DontRoute:
+ *system_name = SO_DONTROUTE;
+ break;
+ case SocketOptionName_Broadcast:
+ *system_name = SO_BROADCAST;
+ break;
+ case SocketOptionName_Linger:
+ *system_name = SO_LINGER;
+ break;
+ case SocketOptionName_OutOfBandInline:
+ *system_name = SO_OOBINLINE;
+ break;
+ case SocketOptionName_SendBuffer:
+ *system_name = SO_SNDBUF;
+ break;
+ case SocketOptionName_ReceiveBuffer:
+ *system_name = SO_RCVBUF;
+ break;
+ case SocketOptionName_SendLowWater:
+ *system_name = SO_SNDLOWAT;
+ break;
+ case SocketOptionName_ReceiveLowWater:
+ *system_name = SO_RCVLOWAT;
+ break;
+ case SocketOptionName_SendTimeout:
+ *system_name = SO_SNDTIMEO;
+ break;
+ case SocketOptionName_ReceiveTimeout:
+ *system_name = SO_RCVTIMEO;
+ break;
+ case SocketOptionName_Error:
+ *system_name = SO_ERROR;
+ break;
+ case SocketOptionName_Type:
+ *system_name = SO_TYPE;
+ break;
+#ifdef SO_PEERCRED
+ case SocketOptionName_PeerCred:
+ *system_name = SO_PEERCRED;
+ 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:
+#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;
+ }
+ break;
+
+ case SocketOptionLevel_IP:
+ *system_level = mono_networking_get_ip_protocol ();
+
+ switch (mono_name) {
+ case SocketOptionName_IPOptions:
+ *system_name = IP_OPTIONS;
+ break;
+#ifdef IP_HDRINCL
+ case SocketOptionName_HeaderIncluded:
+ *system_name = IP_HDRINCL;
+ break;
+#endif
+#ifdef IP_TOS
+ case SocketOptionName_TypeOfService:
+ *system_name = IP_TOS;
+ break;
+#endif
+#ifdef IP_TTL
+ case SocketOptionName_IpTimeToLive:
+ *system_name = IP_TTL;
+ break;
+#endif
+ case SocketOptionName_MulticastInterface:
+ *system_name = IP_MULTICAST_IF;
+ break;
+ case SocketOptionName_MulticastTimeToLive:
+ *system_name = IP_MULTICAST_TTL;
+ break;
+ case SocketOptionName_MulticastLoopback:
+ *system_name = IP_MULTICAST_LOOP;
+ break;
+ case SocketOptionName_AddMembership:
+ *system_name = IP_ADD_MEMBERSHIP;
+ break;
+ case SocketOptionName_DropMembership:
+ *system_name = IP_DROP_MEMBERSHIP;
+ break;
+#ifdef HAVE_IP_PKTINFO
+ case SocketOptionName_PacketInformation:
+ *system_name = IP_PKTINFO;
+ break;
+#endif /* HAVE_IP_PKTINFO */
+
+ case SocketOptionName_DontFragment:
+#ifdef HAVE_IP_DONTFRAGMENT
+ *system_name = IP_DONTFRAGMENT;
+ break;
+#elif defined HAVE_IP_MTU_DISCOVER
+ /* Not quite the same */
+ *system_name = IP_MTU_DISCOVER;
+ break;
+#else
+ /* If the flag is not available on this system, we can ignore this error */
+ return -2;
+#endif /* HAVE_IP_DONTFRAGMENT */
+ case SocketOptionName_AddSourceMembership:
+ case SocketOptionName_DropSourceMembership:
+ case SocketOptionName_BlockSource:
+ case SocketOptionName_UnblockSource:
+ /* Can't figure out how to map these, so fall
+ * through
+ */
+ default:
+ g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
+ return -1;
+ }
+ break;
+
+ case SocketOptionLevel_IPv6:
+ *system_level = mono_networking_get_ipv6_protocol ();
+
+ switch (mono_name) {
+ case SocketOptionName_IpTimeToLive:
+ case SocketOptionName_HopLimit:
+ *system_name = IPV6_UNICAST_HOPS;
+ break;
+ case SocketOptionName_MulticastInterface:
+ *system_name = IPV6_MULTICAST_IF;
+ break;
+ case SocketOptionName_MulticastTimeToLive:
+ *system_name = IPV6_MULTICAST_HOPS;
+ break;
+ case SocketOptionName_MulticastLoopback:
+ *system_name = IPV6_MULTICAST_LOOP;
+ break;
+ case SocketOptionName_AddMembership:
+ *system_name = IPV6_JOIN_GROUP;
+ break;
+ case SocketOptionName_DropMembership:
+ *system_name = IPV6_LEAVE_GROUP;
+ break;
+ case SocketOptionName_IPv6Only:
+#ifdef IPV6_V6ONLY
+ *system_name = IPV6_V6ONLY;
+#else
+ return -1;
+#endif
+ break;
+ case SocketOptionName_PacketInformation:
+#ifdef HAVE_IPV6_PKTINFO
+ *system_name = IPV6_PKTINFO;
+#endif
+ break;
+ case SocketOptionName_HeaderIncluded:
+ case SocketOptionName_IPOptions:
+ case SocketOptionName_TypeOfService:
+ case SocketOptionName_DontFragment:
+ case SocketOptionName_AddSourceMembership:
+ case SocketOptionName_DropSourceMembership:
+ case SocketOptionName_BlockSource:
+ case SocketOptionName_UnblockSource:
+ /* Can't figure out how to map these, so fall
+ * through
+ */
+ default:
+ g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
+ return -1;
+ }
+ break; /* SocketOptionLevel_IPv6 */
+
+ case SocketOptionLevel_Tcp:
+ *system_level = mono_networking_get_tcp_protocol ();
+
+ switch (mono_name) {
+ case SocketOptionName_NoDelay:
+ *system_name = TCP_NODELAY;
+ break;
+#if 0
+ /* The documentation is talking complete
+ * bollocks here: rfc-1222 is titled
+ * 'Advancing the NSFNET Routing Architecture'
+ * and doesn't mention either of the words
+ * "expedite" or "urgent".
+ */
+ case SocketOptionName_BsdUrgent:
+ case SocketOptionName_Expedited:
+#endif
+ default:
+ g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
+ return -1;
+ }
+ break;
+
+ case SocketOptionLevel_Udp:
+ g_warning ("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
+
+ switch(mono_name) {
+ case SocketOptionName_NoChecksum:
+ case SocketOptionName_ChecksumCoverage:
+ default:
+ g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
+ return -1;
+ }
+ return -1;
+ break;
+
+ default:
+ g_warning ("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
+ return -1;
+ }
+
+ return 0;
+}
+
+static MonoImage*
+get_socket_assembly (void)
+{
+ MonoDomain *domain = mono_domain_get ();
+
+ if (domain->socket_assembly == NULL) {
+ MonoImage *socket_assembly;
+
+ 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);
+ }
+ }
+ mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
+ }
+
+ return domain->socket_assembly;
+}
+
+gpointer
+ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObject *this_obj, gint32 family, gint32 type, gint32 proto, gint32 *werror)
+{
+ SOCKET sock;
+ gint32 sock_family;
+ gint32 sock_proto;
+ gint32 sock_type;
+
+ *werror = 0;
+
+ sock_family = convert_family ((MonoAddressFamily)family);
+ if (sock_family == -1) {
+ *werror = WSAEAFNOSUPPORT;
+ return NULL;
+ }
+
+ sock_proto = convert_proto ((MonoProtocolType)proto);
+ if (sock_proto == -1) {
+ *werror = WSAEPROTONOSUPPORT;
+ return NULL;
+ }
+
+ sock_type = convert_type ((MonoSocketType)type);
+ if (sock_type == -1) {
+ *werror = WSAESOCKTNOSUPPORT;
+ return NULL;
+ }
+
+ sock = mono_w32socket_socket (sock_family, sock_type, sock_proto);
+
+ if (sock == INVALID_SOCKET) {
+ *werror = mono_w32socket_get_last_error ();
+ return NULL;
+ }
+
+ return GUINT_TO_POINTER (sock);
+}
+
+/* FIXME: the SOCKET parameter (here and in other functions in this
+ * file) is really an IntPtr which needs to be converted to a guint32.
+ */
+void
+ves_icall_System_Net_Sockets_Socket_Close_internal (gsize sock, gint32 *werror)
+{
+ LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
+
+ *werror = 0;
+
+ /* Clear any pending work item from this socket if the underlying
+ * polling system does not notify when the socket is closed */
+ mono_threadpool_io_remove_socket (GPOINTER_TO_INT (sock));
+
+ MONO_ENTER_GC_SAFE;
+ CloseHandle (GINT_TO_POINTER (sock));
+ MONO_EXIT_GC_SAFE;
+}
+
+gint32
+ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal (void)
+{
+ LOGDEBUG (g_message("%s: returning %d", __func__, mono_w32socket_get_last_error ()));
+
+ return mono_w32socket_get_last_error ();
+}
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Available_internal (gsize sock, gint32 *werror)
+{
+ int ret;
+ guint64 amount;
+
+ *werror = 0;
+
+ /* FIXME: this might require amount to be unsigned long. */
+ ret = mono_w32socket_get_available (sock, &amount);
+ if (ret == SOCKET_ERROR) {
+ *werror = mono_w32socket_get_last_error ();
+ return 0;
+ }
+
+ return amount;
+}
+
+void
+ves_icall_System_Net_Sockets_Socket_Blocking_internal (gsize sock, gboolean block, gint32 *werror)
+{
+ int ret;
+
+ *werror = 0;
+
+ ret = mono_w32socket_set_blocking (sock, block);
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+}
+
+gpointer
+ves_icall_System_Net_Sockets_Socket_Accept_internal (gsize sock, gint32 *werror, gboolean blocking)
+{
+ gboolean interrupted;
+ SOCKET newsock;
+
+ *werror = 0;
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ return NULL;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ newsock = mono_w32socket_accept (sock, NULL, 0, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (newsock == INVALID_SOCKET)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ if (*werror)
+ return NULL;
+
+ return GUINT_TO_POINTER (newsock);
+}
+
+void
+ves_icall_System_Net_Sockets_Socket_Listen_internal(gsize sock, guint32 backlog, gint32 *werror)
+{
+ int ret;
+
+ *werror = 0;
+
+ MONO_ENTER_GC_SAFE;
+
+ ret = mono_w32socket_listen (sock, backlog);
+
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+}
+
+// Check whether it's ::ffff::0:0.
+static gboolean
+is_ipv4_mapped_any (const struct in6_addr *addr)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ if (addr->s6_addr [i])
+ return FALSE;
+ }
+ if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
+ return FALSE;
+ for (i = 12; i < 16; i++) {
+ if (addr->s6_addr [i])
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static MonoObject*
+create_object_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error)
+{
+ MonoDomain *domain = mono_domain_get ();
+ MonoObject *sockaddr_obj;
+ MonoArray *data;
+ MonoAddressFamily family;
+
+ mono_error_init (error);
+
+ /* Build a System.Net.SocketAddress object instance */
+ if (!domain->sockaddr_class)
+ domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
+ sockaddr_obj = mono_object_new_checked (domain, domain->sockaddr_class, error);
+ return_val_if_nok (error, NULL);
+
+ /* 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);
+ }
+
+ /* May be the +2 here is too conservative, as sa_len returns
+ * the length of the entire sockaddr_in/in6, including
+ * sizeof (unsigned short) of the family */
+ /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
+ data = mono_array_new_cached (domain, mono_get_byte_class (), sa_size + 2, error);
+ return_val_if_nok (error, NULL);
+
+ /* The data buffer is laid out as follows:
+ * bytes 0 and 1 are the address family
+ * bytes 2 and 3 are the port info
+ * the rest is the address info
+ */
+
+ family = convert_to_mono_family (saddr->sa_family);
+ if (family == AddressFamily_Unknown) {
+ *werror = WSAEAFNOSUPPORT;
+ return NULL;
+ }
+
+ mono_array_set (data, guint8, 0, family & 0x0FF);
+ mono_array_set (data, guint8, 1, (family >> 8) & 0x0FF);
+
+ if (saddr->sa_family == AF_INET) {
+ 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 < buffer_size) {
+ mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
+ return NULL;
+ }
+
+ mono_array_set (data, guint8, 2, (port>>8) & 0xff);
+ mono_array_set (data, guint8, 3, (port) & 0xff);
+ mono_array_set (data, guint8, 4, (address>>24) & 0xff);
+ mono_array_set (data, guint8, 5, (address>>16) & 0xff);
+ mono_array_set (data, guint8, 6, (address>>8) & 0xff);
+ 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 < buffer_size) {
+ mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
+ return NULL;
+ }
+
+ mono_array_set (data, guint8, 2, (port>>8) & 0xff);
+ mono_array_set (data, guint8, 3, (port) & 0xff);
+
+ if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
+ // Map ::ffff:0:0 to :: (bug #5502)
+ for (i = 0; i < 16; i++)
+ mono_array_set (data, guint8, 8 + i, 0);
+ } else {
+ for (i = 0; i < 16; i++) {
+ mono_array_set (data, guint8, 8 + i,
+ sa_in->sin6_addr.s6_addr [i]);
+ }
+ }
+
+ mono_array_set (data, guint8, 24, sa_in->sin6_scope_id & 0xff);
+ mono_array_set (data, guint8, 25,
+ (sa_in->sin6_scope_id >> 8) & 0xff);
+ mono_array_set (data, guint8, 26,
+ (sa_in->sin6_scope_id >> 16) & 0xff);
+ mono_array_set (data, guint8, 27,
+ (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;
+ }
+#endif
+ else {
+ *werror = WSAEAFNOSUPPORT;
+ return NULL;
+ }
+}
+
+static int
+get_sockaddr_size (int family)
+{
+ int size;
+
+ size = 0;
+ if (family == AF_INET) {
+ size = sizeof (struct sockaddr_in);
+ } else if (family == AF_INET6) {
+ size = sizeof (struct sockaddr_in6);
+ }
+#ifdef HAVE_SYS_UN_H
+ else if (family == AF_UNIX) {
+ size = sizeof (struct sockaddr_un);
+ }
+#endif
+ return size;
+}
+
+MonoObject*
+ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal (gsize sock, gint32 af, gint32 *werror)
+{
+ gchar *sa;
+ socklen_t salen;
+ int ret;
+ MonoObject *result;
+ MonoError error;
+
+ *werror = 0;
+
+ salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
+ if (salen == 0) {
+ *werror = WSAEAFNOSUPPORT;
+ return NULL;
+ }
+ sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
+
+ MONO_ENTER_GC_SAFE;
+
+ ret = mono_w32socket_getsockname (sock, (struct sockaddr *)sa, &salen);
+
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR) {
+ *werror = mono_w32socket_get_last_error ();
+ if (salen > 128)
+ g_free (sa);
+ return NULL;
+ }
+
+ 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)));
+
+ result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
+ if (salen > 128)
+ g_free (sa);
+ if (!mono_error_ok (&error))
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
+MonoObject*
+ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (gsize sock, gint32 af, gint32 *werror)
+{
+ gchar *sa;
+ socklen_t salen;
+ int ret;
+ MonoObject *result;
+ MonoError error;
+
+ *werror = 0;
+
+ salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
+ if (salen == 0) {
+ *werror = WSAEAFNOSUPPORT;
+ return NULL;
+ }
+ sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
+ /* Note: linux returns just 2 for AF_UNIX. Always. */
+
+ MONO_ENTER_GC_SAFE;
+
+ ret = mono_w32socket_getpeername (sock, (struct sockaddr *)sa, &salen);
+
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR) {
+ *werror = mono_w32socket_get_last_error ();
+ if (salen > 128)
+ g_free (sa);
+ return NULL;
+ }
+
+ 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)));
+
+ result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
+ if (salen > 128)
+ g_free (sa);
+ if (!mono_error_ok (&error))
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
+static struct sockaddr*
+create_sockaddr_from_object (MonoObject *saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
+{
+ MonoDomain *domain = mono_domain_get ();
+ MonoArray *data;
+ gint32 family;
+ int len;
+
+ mono_error_init (error);
+
+ 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
+ * byte 1 is the address family high byte
+ * INET:
+ * bytes 2 and 3 are the port info
+ * the rest is the address info
+ * UNIX:
+ * the rest is the file name
+ */
+ 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;
+ guint16 port;
+ guint32 address;
+
+ if (len < 8) {
+ mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
+ return NULL;
+ }
+
+ sa = g_new0 (struct sockaddr_in, 1);
+ port = (mono_array_get (data, guint8, 2) << 8) +
+ mono_array_get (data, guint8, 3);
+ address = (mono_array_get (data, guint8, 4) << 24) +
+ (mono_array_get (data, guint8, 5) << 16 ) +
+ (mono_array_get (data, guint8, 6) << 8) +
+ mono_array_get (data, guint8, 7);
+
+ sa->sin_family = family;
+ sa->sin_addr.s_addr = htonl (address);
+ sa->sin_port = htons (port);
+
+ *sa_size = sizeof (struct sockaddr_in);
+ return (struct sockaddr *)sa;
+ } else if (family == AF_INET6) {
+ struct sockaddr_in6 *sa;
+ int i;
+ guint16 port;
+ guint32 scopeid;
+
+ if (len < 28) {
+ mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
+ return NULL;
+ }
+
+ sa = g_new0 (struct sockaddr_in6, 1);
+ port = mono_array_get (data, guint8, 3) +
+ (mono_array_get (data, guint8, 2) << 8);
+ scopeid = mono_array_get (data, guint8, 24) +
+ (mono_array_get (data, guint8, 25) << 8) +
+ (mono_array_get (data, guint8, 26) << 16) +
+ (mono_array_get (data, guint8, 27) << 24);
+
+ sa->sin6_family = family;
+ sa->sin6_port = htons (port);
+ sa->sin6_scope_id = scopeid;
+
+ for (i = 0; i < 16; i++)
+ sa->sin6_addr.s6_addr [i] = mono_array_get (data, guint8, 8 + i);
+
+ *sa_size = sizeof (struct sockaddr_in6);
+ return (struct sockaddr *)sa;
+ }
+#ifdef HAVE_SYS_UN_H
+ else if (family == AF_UNIX) {
+ struct sockaddr_un *sock_un;
+ int i;
+
+ /* Need a byte for the '\0' terminator/prefix, and the first
+ * two bytes hold the SocketAddress family
+ */
+ if (len - 2 >= sizeof (sock_un->sun_path)) {
+ mono_error_set_exception_instance (error, mono_get_exception_index_out_of_range ());
+ return NULL;
+ }
+
+ sock_un = g_new0 (struct sockaddr_un, 1);
+
+ sock_un->sun_family = family;
+ for (i = 0; i < len - 2; i++)
+ sock_un->sun_path [i] = mono_array_get (data, guint8, i + 2);
+
+ *sa_size = len;
+ return (struct sockaddr *)sock_un;
+ }
+#endif
+ else {
+ *werror = WSAEAFNOSUPPORT;
+ return 0;
+ }
+}
+
+void
+ves_icall_System_Net_Sockets_Socket_Bind_internal (gsize sock, MonoObject *sockaddr, gint32 *werror)
+{
+ MonoError error;
+ struct sockaddr *sa;
+ socklen_t sa_size;
+ int ret;
+
+ *werror = 0;
+
+ sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
+ if (*werror != 0)
+ return;
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return;
+ }
+
+ 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 = mono_w32socket_bind (sock, sa, sa_size);
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ g_free (sa);
+}
+
+enum {
+ SelectModeRead,
+ SelectModeWrite,
+ SelectModeError
+};
+
+MonoBoolean
+ves_icall_System_Net_Sockets_Socket_Poll_internal (gsize sock, gint mode,
+ gint timeout, gint32 *werror)
+{
+ MonoInternalThread *thread = mono_thread_internal_current ();
+ mono_pollfd *pfds;
+ int ret;
+ gboolean interrupted;
+ time_t start;
+
+ *werror = 0;
+
+ pfds = g_new0 (mono_pollfd, 1);
+ pfds->fd = GPOINTER_TO_INT (sock);
+
+ switch (mode) {
+ case SelectModeRead:
+ pfds->events = MONO_POLLIN;
+ break;
+ case SelectModeWrite:
+ pfds->events = MONO_POLLOUT;
+ break;
+ default:
+ pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL;
+ break;
+ }
+
+ timeout = (timeout >= 0) ? (timeout / 1000) : -1;
+ start = time (NULL);
+
+ do {
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ g_free (pfds);
+ *werror = WSAEINTR;
+ return FALSE;
+ }
+
+ MONO_ENTER_GC_SAFE;
+
+ ret = mono_poll (pfds, 1, timeout);
+
+ MONO_EXIT_GC_SAFE;
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted) {
+ g_free (pfds);
+ *werror = WSAEINTR;
+ return FALSE;
+ }
+
+ if (timeout > 0 && ret < 0) {
+ int err = errno;
+ int sec = time (NULL) - start;
+
+ timeout -= sec * 1000;
+ if (timeout < 0) {
+ timeout = 0;
+ }
+
+ errno = err;
+ }
+
+ if (ret == -1 && errno == EINTR) {
+ if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
+ g_free (pfds);
+ return FALSE;
+ }
+
+ /* Suspend requested? */
+ mono_thread_interruption_checkpoint ();
+
+ errno = EINTR;
+ }
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ *werror = mono_w32socket_convert_error (errno);
+ g_free (pfds);
+ return FALSE;
+ }
+
+ g_free (pfds);
+ return ret != 0;
+}
+
+void
+ves_icall_System_Net_Sockets_Socket_Connect_internal (gsize sock, MonoObject *sockaddr, gint32 *werror, gboolean blocking)
+{
+ MonoError error;
+ struct sockaddr *sa;
+ socklen_t sa_size;
+ int ret;
+ gboolean interrupted;
+
+ *werror = 0;
+
+ sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
+ if (*werror != 0)
+ return;
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return;
+ }
+
+ 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)));
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ return;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_connect (sock, sa, sa_size, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ g_free (sa);
+}
+
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
+
+void
+ves_icall_System_Net_Sockets_Socket_Disconnect_internal (gsize sock, MonoBoolean reuse, gint32 *werror)
+{
+ gboolean interrupted;
+
+ LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ return;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ *werror = mono_w32socket_disconnect (sock, reuse);
+ MONO_EXIT_GC_SAFE;
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+}
+#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Receive_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror, gboolean blocking)
+{
+ int ret;
+ gchar *buf;
+ gint32 alen;
+ int recvflags = 0;
+ gboolean interrupted;
+ MonoInternalThread* curthread G_GNUC_UNUSED = mono_thread_internal_current ();
+
+ *werror = 0;
+
+ alen = mono_array_length (buffer);
+ if (offset > alen - count)
+ return 0;
+
+ buf = mono_array_addr (buffer, gchar, offset);
+
+ recvflags = convert_socketflags (flags);
+ if (recvflags == -1) {
+ *werror = WSAEOPNOTSUPP;
+ return 0;
+ }
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted)
+ return 0;
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_recv (sock, buf, count, recvflags, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ if (*werror)
+ return 0;
+
+ return ret;
+}
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Receive_array_internal (gsize sock, MonoArray *buffers, gint32 flags, gint32 *werror, gboolean blocking)
+{
+ int ret, count;
+ gboolean interrupted;
+ guint32 recv;
+ WSABUF *wsabufs;
+ guint32 recvflags = 0;
+
+ *werror = 0;
+
+ wsabufs = mono_array_addr (buffers, WSABUF, 0);
+ count = mono_array_length (buffers);
+
+ recvflags = convert_socketflags (flags);
+ if (recvflags == -1) {
+ *werror = WSAEOPNOTSUPP;
+ return 0;
+ }
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ return 0;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_recvbuffers (sock, wsabufs, count, &recv, &recvflags, NULL, NULL, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ if (*werror)
+ return 0;
+
+ return recv;
+}
+
+gint32
+ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *werror, gboolean blocking)
+{
+ MonoError error;
+ int ret;
+ gchar *buf;
+ gint32 alen;
+ int recvflags = 0;
+ struct sockaddr *sa;
+ socklen_t sa_size;
+ gboolean interrupted;
+
+ *werror = 0;
+
+ alen = mono_array_length (buffer);
+ if (offset > alen - count)
+ return 0;
+
+ sa = create_sockaddr_from_object (*sockaddr, &sa_size, werror, &error);
+ if (*werror != 0)
+ return 0;
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return 0;
+ }
+
+ buf = mono_array_addr (buffer, gchar, offset);
+
+ recvflags = convert_socketflags (flags);
+ if (recvflags == -1) {
+ *werror = WSAEOPNOTSUPP;
+ return 0;
+ }
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ g_free (sa);
+ *werror = WSAEINTR;
+ return 0;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_recvfrom (sock, buf, count, recvflags, sa, &sa_size, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ if (*werror) {
+ g_free(sa);
+ return 0;
+ }
+
+ /* If we didn't get a socket size, then we're probably a
+ * connected connection-oriented socket and the stack hasn't
+ * returned the remote address. All we can do is return null.
+ */
+ if (sa_size) {
+ *sockaddr = create_object_from_sockaddr (sa, sa_size, werror, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ g_free (sa);
+ return 0;
+ }
+ } else {
+ *sockaddr = NULL;
+ }
+
+ g_free (sa);
+
+ return ret;
+}
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Send_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror, gboolean blocking)
+{
+ int ret;
+ gchar *buf;
+ gint32 alen;
+ int sendflags = 0;
+ gboolean interrupted;
+
+ *werror = 0;
+
+ alen = mono_array_length (buffer);
+ if (offset > alen - count)
+ return 0;
+
+ LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
+
+ buf = mono_array_addr (buffer, gchar, offset);
+
+ LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
+
+ sendflags = convert_socketflags (flags);
+ if (sendflags == -1) {
+ *werror = WSAEOPNOTSUPP;
+ return 0;
+ }
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ return 0;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_send (sock, buf, count, sendflags, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ if (*werror)
+ return 0;
+
+ return ret;
+}
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Send_array_internal (gsize sock, MonoArray *buffers, gint32 flags, gint32 *werror, gboolean blocking)
+{
+ int ret, count;
+ guint32 sent;
+ WSABUF *wsabufs;
+ guint32 sendflags = 0;
+ gboolean interrupted;
+
+ *werror = 0;
+
+ wsabufs = mono_array_addr (buffers, WSABUF, 0);
+ count = mono_array_length (buffers);
+
+ sendflags = convert_socketflags (flags);
+ if (sendflags == -1) {
+ *werror = WSAEOPNOTSUPP;
+ return 0;
+ }
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ return 0;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_sendbuffers (sock, wsabufs, count, &sent, sendflags, NULL, NULL, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ if (*werror)
+ return 0;
+
+ return sent;
+}
+
+gint32
+ves_icall_System_Net_Sockets_Socket_SendTo_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *werror, gboolean blocking)
+{
+ MonoError error;
+ int ret;
+ gchar *buf;
+ gint32 alen;
+ int sendflags = 0;
+ struct sockaddr *sa;
+ socklen_t sa_size;
+ gboolean interrupted;
+
+ *werror = 0;
+
+ alen = mono_array_length (buffer);
+ if (offset > alen - count) {
+ return 0;
+ }
+
+ sa = create_sockaddr_from_object(sockaddr, &sa_size, werror, &error);
+ if (*werror != 0)
+ return 0;
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return 0;
+ }
+
+ LOGDEBUG (g_message ("%s: alen: %d", __func__, alen));
+
+ buf = mono_array_addr (buffer, gchar, offset);
+
+ LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
+
+ sendflags = convert_socketflags (flags);
+ if (sendflags == -1) {
+ g_free (sa);
+ *werror = WSAEOPNOTSUPP;
+ return 0;
+ }
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ g_free (sa);
+ *werror = WSAEINTR;
+ return 0;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_sendto (sock, buf, count, sendflags, sa, sa_size, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted)
+ *werror = WSAEINTR;
+
+ g_free(sa);
+
+ if (*werror)
+ return 0;
+
+ return ret;
+}
+
+static SOCKET
+Socket_to_SOCKET (MonoObject *sockobj)
+{
+ MonoSafeHandle *safe_handle;
+ MonoClassField *field;
+
+ 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 -1;
+
+ return (SOCKET)safe_handle->handle;
+}
+
+#define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
+
+void
+ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32 timeout, gint32 *werror)
+{
+ MonoError error;
+ MonoInternalThread *thread = mono_thread_internal_current ();
+ MonoObject *obj;
+ mono_pollfd *pfds;
+ int nfds, idx;
+ int ret;
+ int i, count;
+ int mode;
+ MonoClass *sock_arr_class;
+ MonoArray *socks;
+ time_t start;
+ uintptr_t socks_size;
+ gboolean interrupted;
+
+ *werror = 0;
+
+ /* *sockets -> READ, null, WRITE, null, ERROR, null */
+ count = mono_array_length (*sockets);
+ nfds = count - 3; /* NULL separators */
+ pfds = g_new0 (mono_pollfd, nfds);
+ mode = idx = 0;
+ for (i = 0; i < count; i++) {
+ obj = mono_array_get (*sockets, MonoObject *, i);
+ if (obj == NULL) {
+ mode++;
+ continue;
+ }
+
+ if (idx >= nfds) {
+ /* The socket array was bogus */
+ g_free (pfds);
+ *werror = WSAEFAULT;
+ return;
+ }
+
+ pfds [idx].fd = Socket_to_SOCKET (obj);
+ pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
+ idx++;
+ }
+
+ timeout = (timeout >= 0) ? (timeout / 1000) : -1;
+ start = time (NULL);
+ do {
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ g_free (pfds);
+ *werror = WSAEINTR;
+ return;
+ }
+
+ MONO_ENTER_GC_SAFE;
+
+ ret = mono_poll (pfds, nfds, timeout);
+
+ MONO_EXIT_GC_SAFE;
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted) {
+ g_free (pfds);
+ *werror = WSAEINTR;
+ return;
+ }
+
+ if (timeout > 0 && ret < 0) {
+ int err = errno;
+ int sec = time (NULL) - start;
+
+ timeout -= sec * 1000;
+ if (timeout < 0)
+ timeout = 0;
+ errno = err;
+ }
+
+ if (ret == -1 && errno == EINTR) {
+ if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
+ g_free (pfds);
+ *sockets = NULL;
+ return;
+ }
+
+ /* Suspend requested? */
+ mono_thread_interruption_checkpoint ();
+
+ errno = EINTR;
+ }
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ *werror = mono_w32socket_convert_error (errno);
+ g_free (pfds);
+ return;
+ }
+
+ if (ret == 0) {
+ g_free (pfds);
+ *sockets = NULL;
+ return;
+ }
+
+ sock_arr_class = ((MonoObject *)*sockets)->vtable->klass;
+ socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
+ socks = mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ g_free (pfds);
+ return;
+ }
+
+ mode = idx = 0;
+ for (i = 0; i < count && ret > 0; i++) {
+ mono_pollfd *pfd;
+
+ obj = mono_array_get (*sockets, MonoObject *, i);
+ if (obj == NULL) {
+ mode++;
+ idx++;
+ continue;
+ }
+
+ pfd = &pfds [i - mode];
+ if (pfd->revents == 0)
+ continue;
+
+ ret--;
+ if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
+ mono_array_setref (socks, idx++, obj);
+ } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
+ mono_array_setref (socks, idx++, obj);
+ } else if ((pfd->revents & POLL_ERRORS) != 0) {
+ mono_array_setref (socks, idx++, obj);
+ }
+ }
+
+ *sockets = socks;
+ g_free (pfds);
+}
+
+static MonoObject*
+int_to_object (MonoDomain *domain, int val, MonoError *error)
+{
+ return mono_value_box_checked (domain, mono_get_int32_class (), &val, error);
+}
+
+void
+ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (gsize sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *werror)
+{
+ int system_level = 0;
+ int system_name = 0;
+ int ret;
+ int val = 0;
+ socklen_t valsize = sizeof (val);
+ struct linger linger;
+ socklen_t lingersize = sizeof (linger);
+ int time_ms = 0;
+ socklen_t time_ms_size = sizeof (time_ms);
+#ifdef SO_PEERCRED
+# if defined(__OpenBSD__)
+ struct sockpeercred cred;
+# else
+ struct ucred cred;
+# endif
+ socklen_t credsize = sizeof (cred);
+#endif
+ MonoError error;
+ MonoDomain *domain = mono_domain_get ();
+ MonoObject *obj;
+ MonoClass *obj_class;
+ MonoClassField *field;
+
+ *werror = 0;
+
+#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
+ if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
+ system_level = SOL_SOCKET;
+ system_name = SO_REUSEADDR;
+ ret = 0;
+ } else
+#endif
+ {
+ ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
+ }
+
+ if (ret == -1) {
+ *werror = WSAENOPROTOOPT;
+ return;
+ }
+ if (ret == -2) {
+ *obj_val = int_to_object (domain, 0, &error);
+ mono_error_set_pending_exception (&error);
+ return;
+ }
+
+ MONO_ENTER_GC_SAFE;
+
+ /* No need to deal with MulticastOption names here, because
+ * you cant getsockopt AddMembership or DropMembership (the
+ * int getsockopt will error, causing an exception)
+ */
+ switch (name) {
+ case SocketOptionName_Linger:
+ case SocketOptionName_DontLinger:
+ ret = mono_w32socket_getsockopt (sock, system_level, system_name, &linger, &lingersize);
+ break;
+
+ case SocketOptionName_SendTimeout:
+ case SocketOptionName_ReceiveTimeout:
+ ret = mono_w32socket_getsockopt (sock, system_level, system_name, (char *)&time_ms, &time_ms_size);
+ break;
+
+#ifdef SO_PEERCRED
+ case SocketOptionName_PeerCred:
+ ret = mono_w32socket_getsockopt (sock, system_level, system_name, &cred, &credsize);
+ break;
+#endif
+
+ default:
+ ret = mono_w32socket_getsockopt (sock, system_level, system_name, &val, &valsize);
+ }
+
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR) {
+ *werror = mono_w32socket_get_last_error ();
+ return;
+ }
+
+ switch (name) {
+ case SocketOptionName_Linger:
+ /* build a System.Net.Sockets.LingerOption */
+ obj_class = mono_class_load_from_name (get_socket_assembly (),
+ "System.Net.Sockets",
+ "LingerOption");
+ obj = mono_object_new_checked (domain, obj_class, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return;
+ }
+
+ /* Locate and set the fields "bool enabled" and "int
+ * lingerTime"
+ */
+ field = mono_class_get_field_from_name(obj_class, "enabled");
+ *(guint8 *)(((char *)obj)+field->offset) = linger.l_onoff;
+
+ field = mono_class_get_field_from_name(obj_class, "lingerTime");
+ *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
+ break;
+ case SocketOptionName_DontLinger:
+ /* construct a bool int in val - true if linger is off */
+ obj = int_to_object (domain, !linger.l_onoff, &error);
+ mono_error_set_pending_exception (&error);
+ break;
+ case SocketOptionName_SendTimeout:
+ case SocketOptionName_ReceiveTimeout:
+ obj = int_to_object (domain, time_ms, &error);
+ mono_error_set_pending_exception (&error);
+ break;
+
+#ifdef SO_PEERCRED
+ case SocketOptionName_PeerCred: {
+ /*
+ * build a Mono.Posix.PeerCred+PeerCredData if
+ * possible
+ */
+ static MonoImage *mono_posix_image = NULL;
+ MonoPeerCredData *cred_data;
+
+ if (mono_posix_image == NULL) {
+ mono_posix_image = mono_image_loaded ("Mono.Posix");
+ if (!mono_posix_image) {
+ MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
+ if (!sa) {
+ *werror = WSAENOPROTOOPT;
+ return;
+ } else {
+ mono_posix_image = mono_assembly_get_image (sa);
+ }
+ }
+ }
+
+ obj_class = mono_class_load_from_name (mono_posix_image,
+ "Mono.Posix",
+ "PeerCredData");
+ obj = mono_object_new_checked (domain, obj_class, &error);
+ if (!mono_error_ok (&error)) {
+ mono_error_set_pending_exception (&error);
+ return;
+ }
+ cred_data = (MonoPeerCredData *)obj;
+ cred_data->pid = cred.pid;
+ cred_data->uid = cred.uid;
+ cred_data->gid = cred.gid;
+ break;
+ }
+#endif
+
+ default:
+#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
+ if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
+ val = val ? 0 : 1;
+#endif
+ obj = int_to_object (domain, val, &error);
+ mono_error_set_pending_exception (&error);
+ }
+
+ *obj_val = obj;
+}
+
+void
+ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (gsize sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *werror)
+{
+ int system_level = 0;
+ int system_name = 0;
+ int ret;
+ guchar *buf;
+ socklen_t valsize;
+
+ *werror = 0;
+
+ ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
+ &system_name);
+ if (ret == -1) {
+ *werror = WSAENOPROTOOPT;
+ return;
+ }
+ if (ret == -2)
+ return;
+
+ valsize = mono_array_length (*byte_val);
+ buf = mono_array_addr (*byte_val, guchar, 0);
+
+ MONO_ENTER_GC_SAFE;
+
+ ret = mono_w32socket_getsockopt (sock, system_level, system_name, buf, &valsize);
+
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+}
+
+#if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
+static struct in_addr
+ipaddress_to_struct_in_addr (MonoObject *ipaddr)
+{
+ struct in_addr inaddr;
+ MonoClassField *field;
+
+ field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Address");
+
+ /* No idea why .net uses a 64bit type to hold a 32bit value...
+ *
+ * Internal value of IPAddess is in little-endian order
+ */
+ inaddr.s_addr = GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr) + field->offset));
+
+ return inaddr;
+}
+
+static struct in6_addr
+ipaddress_to_struct_in6_addr (MonoObject *ipaddr)
+{
+ struct in6_addr in6addr;
+ MonoClassField *field;
+ MonoArray *data;
+ int i;
+
+ field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Numbers");
+ g_assert (field);
+ data = *(MonoArray **)(((char *)ipaddr) + field->offset);
+
+ for (i = 0; i < 8; 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
+ in6addr.s6_addr16[i] = s;
+#endif
+ }
+ return in6addr;
+}
+#endif
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+
+static int
+get_local_interface_id (int family)
+{
+#if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
+ return 0;
+#else
+ struct ifaddrs *ifap = NULL, *ptr;
+ int idx = 0;
+
+ if (getifaddrs (&ifap))
+ return 0;
+
+ for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
+ if (!ptr->ifa_addr || !ptr->ifa_name)
+ continue;
+ if (ptr->ifa_addr->sa_family != family)
+ continue;
+ if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
+ continue;
+ if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
+ continue;
+
+ idx = if_nametoindex (ptr->ifa_name);
+ break;
+ }
+
+ freeifaddrs (ifap);
+ return idx;
+#endif
+}
+
+#endif /* defined(__APPLE__) || defined(__FreeBSD__) */
+
+void
+ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal (gsize sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val, gint32 *werror)
+{
+ struct linger linger;
+ int system_level = 0;
+ int system_name = 0;
+ int ret;
+ int sol_ip;
+ int sol_ipv6;
+
+ *werror = 0;
+
+ sol_ipv6 = mono_networking_get_ipv6_protocol ();
+ sol_ip = mono_networking_get_ip_protocol ();
+
+ ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
+ &system_name);
+
+#if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
+ if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
+ system_name = SO_REUSEADDR;
+ int_val = int_val ? 0 : 1;
+ ret = 0;
+ }
+#endif
+
+ if (ret == -1) {
+ *werror = WSAENOPROTOOPT;
+ return;
+ }
+ if (ret == -2)
+ return;
+
+ /* Only one of obj_val, byte_val or int_val has data */
+ if (obj_val) {
+ MonoClassField *field;
+ int valsize;
+
+ switch (name) {
+ case SocketOptionName_Linger:
+ /* Dig out "bool enabled" and "int lingerTime"
+ * fields
+ */
+ field = mono_class_get_field_from_name (obj_val->vtable->klass, "enabled");
+ linger.l_onoff = *(guint8 *)(((char *)obj_val) + field->offset);
+ field = mono_class_get_field_from_name (obj_val->vtable->klass, "lingerTime");
+ linger.l_linger = *(guint32 *)(((char *)obj_val) + field->offset);
+
+ valsize = sizeof (linger);
+ ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, valsize);
+ break;
+ case SocketOptionName_AddMembership:
+ case SocketOptionName_DropMembership:
+#if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
+ {
+ MonoObject *address = NULL;
+
+ if (system_level == sol_ipv6) {
+ struct ipv6_mreq mreq6;
+
+ /*
+ * 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)
+ mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
+
+ field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Interface");
+ mreq6.ipv6mr_interface = *(guint64 *)(((char *)obj_val) + field->offset);
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ /*
+ * Bug #5504:
+ *
+ * Mac OS Lion doesn't allow ipv6mr_interface = 0.
+ *
+ * Tests on Windows and Linux show that the multicast group is only
+ * joined on one NIC when interface = 0, so we simply use the interface
+ * id from the first non-loopback interface (this is also what
+ * Dns.GetHostName (string.Empty) would return).
+ */
+ if (!mreq6.ipv6mr_interface)
+ mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
+#endif
+
+ ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq6, sizeof (mreq6));
+ } else if (system_level == sol_ip) {
+#ifdef HAVE_STRUCT_IP_MREQN
+ struct ip_mreqn mreq = {{0}};
+#else
+ struct ip_mreq mreq = {{0}};
+#endif /* HAVE_STRUCT_IP_MREQN */
+
+ /*
+ * pain! MulticastOption holds two IPAddress
+ * members, so I have to dig the value out of
+ * those :-(
+ */
+ field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
+ address = *(MonoObject **)(((char *)obj_val) + field->offset);
+
+ /* address might not be defined and if so, set the address to ADDR_ANY.
+ */
+ if (address)
+ mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
+
+ field = mono_class_get_field_from_name (obj_val->vtable->klass, "localAddress");
+ address = *(MonoObject **)(((char *)obj_val) + field->offset);
+
+#ifdef HAVE_STRUCT_IP_MREQN
+ if (address)
+ mreq.imr_address = ipaddress_to_struct_in_addr (address);
+
+ field = mono_class_get_field_from_name (obj_val->vtable->klass, "ifIndex");
+ mreq.imr_ifindex = *(gint32 *)(((char *)obj_val) + field->offset);
+#else
+ if (address)
+ mreq.imr_interface = ipaddress_to_struct_in_addr (address);
+#endif /* HAVE_STRUCT_IP_MREQN */
+
+ ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
+ }
+ break;
+ }
+#endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
+ default:
+ /* Cause an exception to be thrown */
+ *werror = WSAEINVAL;
+ return;
+ }
+ } else if (byte_val!=NULL) {
+ 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 = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
+ } else {
+ *werror = WSAEINVAL;
+ }
+ break;
+ default:
+ ret = mono_w32socket_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 = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
+ break;
+ case SocketOptionName_MulticastInterface:
+#ifndef HOST_WIN32
+#ifdef HAVE_STRUCT_IP_MREQN
+ int_val = GUINT32_FROM_BE (int_val);
+ if ((int_val & 0xff000000) == 0) {
+ /* int_val is interface index */
+ struct ip_mreqn mreq = {{0}};
+ mreq.imr_ifindex = int_val;
+ ret = mono_w32socket_setsockopt (sock, system_level, system_name, (char *) &mreq, sizeof (mreq));
+ break;
+ }
+ int_val = GUINT32_TO_BE (int_val);
+#endif /* HAVE_STRUCT_IP_MREQN */
+#endif /* HOST_WIN32 */
+ /* int_val is in_addr */
+ ret = mono_w32socket_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
+ break;
+ case SocketOptionName_DontFragment:
+#ifdef HAVE_IP_MTU_DISCOVER
+ /* Fiddle with the value slightly if we're
+ * turning DF on
+ */
+ if (int_val == 1)
+ int_val = IP_PMTUDISC_DO;
+ /* Fall through */
+#endif
+
+ default:
+ ret = mono_w32socket_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
+ }
+ }
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+}
+
+void
+ves_icall_System_Net_Sockets_Socket_Shutdown_internal (gsize sock, gint32 how, gint32 *werror)
+{
+ int ret;
+ gboolean interrupted;
+
+ *werror = 0;
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ return;
+ }
+
+ MONO_ENTER_GC_SAFE;
+
+ /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
+ ret = mono_w32socket_shutdown (sock, how);
+
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted) {
+ *werror = WSAEINTR;
+ }
+
+}
+
+gint
+ves_icall_System_Net_Sockets_Socket_IOControl_internal (gsize sock, gint32 code, MonoArray *input, MonoArray *output, gint32 *werror)
+{
+ glong output_bytes = 0;
+ gchar *i_buffer, *o_buffer;
+ gint i_len, o_len;
+ gint ret;
+
+ *werror = 0;
+
+ if ((guint32)code == FIONBIO)
+ /* Invalid command. Must use Socket.Blocking */
+ return -1;
+
+ if (input == NULL) {
+ i_buffer = NULL;
+ i_len = 0;
+ } else {
+ i_buffer = mono_array_addr (input, gchar, 0);
+ i_len = mono_array_length (input);
+ }
+
+ if (output == NULL) {
+ o_buffer = NULL;
+ o_len = 0;
+ } else {
+ o_buffer = mono_array_addr (output, gchar, 0);
+ o_len = mono_array_length (output);
+ }
+
+ MONO_ENTER_GC_SAFE;
+
+ ret = mono_w32socket_ioctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes);
+
+ MONO_EXIT_GC_SAFE;
+
+ if (ret == SOCKET_ERROR) {
+ *werror = mono_w32socket_get_last_error ();
+ return -1;
+ }
+
+ return (gint)output_bytes;
+}
+
+static gboolean
+addrinfo_to_IPHostEntry (MonoAddressInfo *info, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips, MonoError *error)
+{
+ gint32 count, i;
+ MonoAddressEntry *ai = NULL;
+ struct in_addr *local_in = NULL;
+ int nlocal_in = 0;
+ struct in6_addr *local_in6 = NULL;
+ int nlocal_in6 = 0;
+ int addr_index;
+ MonoDomain *domain = mono_domain_get ();
+
+ mono_error_init (error);
+ addr_index = 0;
+ *h_aliases = mono_array_new_checked (domain, mono_get_string_class (), 0, error);
+ return_val_if_nok (error, FALSE);
+ if (add_local_ips) {
+ local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
+ local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
+ if (nlocal_in || nlocal_in6) {
+ char addr [INET6_ADDRSTRLEN];
+ *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error);
+ if (!is_ok (error))
+ goto leave;
+
+ if (nlocal_in) {
+ MonoString *addr_string;
+ int i;
+
+ for (i = 0; i < nlocal_in; i++) {
+ MonoAddress maddr;
+ mono_address_init (&maddr, AF_INET, &local_in [i]);
+ if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
+ addr_string = mono_string_new (domain, addr);
+ mono_array_setref (*h_addr_list, addr_index, addr_string);
+ addr_index++;
+ }
+ }
+ }
+
+ if (nlocal_in6) {
+ MonoString *addr_string;
+ int i;
+
+ for (i = 0; i < nlocal_in6; i++) {
+ MonoAddress maddr;
+ mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
+ if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
+ addr_string = mono_string_new (domain, addr);
+ mono_array_setref (*h_addr_list, addr_index, addr_string);
+ addr_index++;
+ }
+ }
+ }
+
+ leave:
+ g_free (local_in);
+ g_free (local_in6);
+ if (info)
+ mono_free_address_info (info);
+ return is_ok (error);;
+ }
+
+ g_free (local_in);
+ g_free (local_in6);
+ }
+
+ for (count = 0, ai = info->entries; ai != NULL; ai = ai->next) {
+ if (ai->family != AF_INET && ai->family != AF_INET6)
+ continue;
+ count++;
+ }
+
+ *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), count, error);
+ if (!is_ok (error))
+ goto leave2;
+
+ for (ai = info->entries, i = 0; ai != NULL; ai = ai->next) {
+ MonoAddress maddr;
+ MonoString *addr_string;
+ char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
+
+ if ((ai->family != PF_INET) && (ai->family != PF_INET6))
+ continue;
+
+ mono_address_init (&maddr, ai->family, &ai->address);
+ if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
+ addr_string = mono_string_new (domain, buffer);
+ else
+ addr_string = mono_string_new (domain, "");
+
+ mono_array_setref (*h_addr_list, addr_index, addr_string);
+
+ if (!i) {
+ i++;
+ if (ai->canonical_name != NULL) {
+ *h_name = mono_string_new (domain, ai->canonical_name);
+ } else {
+ *h_name = mono_string_new (domain, buffer);
+ }
+ }
+
+ addr_index++;
+ }
+
+leave2:
+ if (info)
+ mono_free_address_info (info);
+
+ return is_ok (error);
+}
+
+MonoBoolean
+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_checked (host, &error);
+ if (mono_error_set_pending_exception (&error))
+ return FALSE;
+
+ if (*hostname == '\0') {
+ add_local_ips = TRUE;
+ *h_name = host;
+ }
+
+ if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
+ if (!strcmp (hostname, this_hostname)) {
+ add_local_ips = TRUE;
+ *h_name = host;
+ }
+ }
+
+#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);
+
+ if (add_info_ok) {
+ MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, add_local_ips, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+ }
+ return FALSE;
+}
+
+MonoBoolean
+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;
+ gchar hostname [NI_MAXHOST] = { 0 };
+ gboolean ret;
+
+ 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;
+ saddr.sin_family = AF_INET;
+ } else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
+ family = AF_INET6;
+ saddr6.sin6_family = AF_INET6;
+ } else {
+ g_free (address);
+ return FALSE;
+ }
+
+ g_free (address);
+
+ MONO_ENTER_GC_SAFE;
+
+ switch (family) {
+ case AF_INET: {
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ saddr.sin_len = sizeof (saddr);
+#endif
+ ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
+ break;
+ }
+ case AF_INET6: {
+#if HAVE_SOCKADDR_IN6_SIN_LEN
+ saddr6.sin6_len = sizeof (saddr6);
+#endif
+ ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+
+ MONO_EXIT_GC_SAFE;
+
+ if (!ret)
+ return FALSE;
+
+ if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
+ return FALSE;
+
+ MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
+MonoBoolean
+ves_icall_System_Net_Dns_GetHostName_internal (MonoString **h_name)
+{
+ gchar hostname [NI_MAXHOST] = { 0 };
+ int ret;
+
+ ret = gethostname (hostname, sizeof (hostname));
+ if (ret == -1)
+ return FALSE;
+
+ *h_name = mono_string_new (mono_domain_get (), hostname);
+
+ return TRUE;
+}
+
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
+gboolean
+ves_icall_System_Net_Sockets_Socket_SendFile_internal (gsize sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags, gint32 *werror, gboolean blocking)
+{
+ HANDLE file;
+ gboolean ret;
+ gboolean interrupted;
+ TRANSMIT_FILE_BUFFERS buffers;
+
+ if (filename == NULL)
+ return FALSE;
+
+ /* 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);
+
+ if (file == INVALID_HANDLE_VALUE) {
+ SetLastError (*werror);
+ 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);
+ }
+
+ mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
+ if (interrupted) {
+ CloseHandle (file);
+ SetLastError (WSAEINTR);
+ return FALSE;
+ }
+
+ MONO_ENTER_GC_SAFE;
+ ret = mono_w32socket_transmit_file (sock, file, &buffers, flags, blocking);
+ MONO_EXIT_GC_SAFE;
+
+ if (!ret)
+ *werror = mono_w32socket_get_last_error ();
+
+ mono_thread_info_uninstall_interrupt (&interrupted);
+ if (interrupted) {
+ CloseHandle (file);
+ *werror = WSAEINTR;
+ return FALSE;
+ }
+
+ MONO_ENTER_GC_SAFE;
+
+ CloseHandle (file);
+
+ MONO_EXIT_GC_SAFE;
+
+ if (*werror)
+ return FALSE;
+
+ return ret;
+}
+#endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
+
+void
+mono_network_init (void)
+{
+ mono_networking_init ();
+ mono_w32socket_initialize ();
+}
+
+void
+mono_network_cleanup (void)
+{
+ mono_w32socket_cleanup ();
+ mono_networking_shutdown ();
+}
+
+void
+icall_cancel_blocking_socket_operation (MonoThread *thread)
+{
+ MonoInternalThread *internal;
+
+ internal = thread->internal_thread;
+ g_assert (internal);
+
+ mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
+}
+
+#endif /* #ifndef DISABLE_SOCKETS */
--- /dev/null
+/*
+ * w32socket.h: System.Net.Sockets.Socket support
+ *
+ * Author:
+ * Dick Porter (dick@ximian.com)
+ *
+ * (C) 2001 Ximian, Inc.
+ */
+
+#ifndef _MONO_METADATA_W32SOCKET_H_
+#define _MONO_METADATA_W32SOCKET_H_
+
+#include <config.h>
+#include <glib.h>
+
+#include <mono/metadata/object-internals.h>
+
+#define INVALID_SOCKET ((SOCKET)(guint32)(~0))
+#define SOCKET_ERROR (-1)
+
+#ifndef HOST_WIN32
+typedef gint SOCKET;
+#endif
+
+/* This is a copy of System.Net.Sockets.SocketType */
+typedef enum {
+ SocketType_Stream=1,
+ SocketType_Dgram=2,
+ SocketType_Raw=3,
+ SocketType_Rdm=4,
+ SocketType_Seqpacket=5,
+ SocketType_Unknown=-1
+} MonoSocketType;
+
+/* This is a copy of System.Net.Sockets.AddressFamily */
+typedef enum {
+ AddressFamily_Unknown=-1,
+ AddressFamily_Unspecified=0,
+ AddressFamily_Unix=1,
+ AddressFamily_InterNetwork=2,
+ AddressFamily_ImpLink=3,
+ AddressFamily_Pup=4,
+ AddressFamily_Chaos=5,
+ AddressFamily_NS=6,
+ AddressFamily_Ipx=6,
+ AddressFamily_Iso=7,
+ AddressFamily_Osi=7,
+ AddressFamily_Ecma=8,
+ AddressFamily_DataKit=9,
+ AddressFamily_Ccitt=10,
+ AddressFamily_Sna=11,
+ AddressFamily_DecNet=12,
+ AddressFamily_DataLink=13,
+ AddressFamily_Lat=14,
+ AddressFamily_HyperChannel=15,
+ AddressFamily_AppleTalk=16,
+ AddressFamily_NetBios=17,
+ AddressFamily_VoiceView=18,
+ AddressFamily_FireFox=19,
+ AddressFamily_Banyan=21,
+ AddressFamily_Atm=22,
+ AddressFamily_InterNetworkV6=23,
+ AddressFamily_Cluster=24,
+ AddressFamily_Ieee12844=25,
+ AddressFamily_Irda=26,
+ AddressFamily_NetworkDesigners=28
+} MonoAddressFamily;
+
+/* This is a copy of System.Net.Sockets.ProtocolType */
+typedef enum {
+ ProtocolType_IP=0,
+ ProtocolType_Icmp=1,
+ ProtocolType_Igmp=2,
+ ProtocolType_Ggp=3,
+ ProtocolType_Tcp=6,
+ ProtocolType_Pup=12,
+ ProtocolType_Udp=17,
+ ProtocolType_Idp=22,
+ ProtocolType_IPv6=41,
+ ProtocolType_ND=77,
+ ProtocolType_Raw=255,
+ ProtocolType_Unspecified=0,
+ ProtocolType_Ipx=1000,
+ ProtocolType_Spx=1256,
+ ProtocolType_SpxII=1257,
+ ProtocolType_Unknown=-1
+} MonoProtocolType;
+
+/* This is a copy of System.Net.Sockets.SocketOptionLevel */
+typedef enum {
+ SocketOptionLevel_Socket=65535,
+ SocketOptionLevel_IP=0,
+ SocketOptionLevel_IPv6=41,
+ SocketOptionLevel_Tcp=6,
+ SocketOptionLevel_Udp=17
+} MonoSocketOptionLevel;
+
+/* This is a copy of System.Net.Sockets.SocketOptionName */
+typedef enum {
+ SocketOptionName_Debug=1,
+ SocketOptionName_AcceptConnection=2,
+ SocketOptionName_ReuseAddress=4,
+ SocketOptionName_KeepAlive=8,
+ SocketOptionName_DontRoute=16,
+ SocketOptionName_IPProtectionLevel = 23,
+ SocketOptionName_IPv6Only = 27,
+ SocketOptionName_Broadcast=32,
+ SocketOptionName_UseLoopback=64,
+ SocketOptionName_Linger=128,
+ SocketOptionName_OutOfBandInline=256,
+ SocketOptionName_DontLinger= -129,
+ SocketOptionName_ExclusiveAddressUse= -5,
+ SocketOptionName_SendBuffer= 4097,
+ SocketOptionName_ReceiveBuffer=4098,
+ SocketOptionName_SendLowWater=4099,
+ SocketOptionName_ReceiveLowWater=4100,
+ SocketOptionName_SendTimeout=4101,
+ SocketOptionName_ReceiveTimeout=4102,
+ SocketOptionName_Error=4103,
+ SocketOptionName_Type=4104,
+ SocketOptionName_MaxConnections=2147483647,
+ SocketOptionName_IPOptions=1,
+ SocketOptionName_HeaderIncluded=2,
+ SocketOptionName_TypeOfService=3,
+ SocketOptionName_IpTimeToLive=4,
+ SocketOptionName_MulticastInterface=9,
+ SocketOptionName_MulticastTimeToLive=10,
+ SocketOptionName_MulticastLoopback=11,
+ SocketOptionName_AddMembership=12,
+ SocketOptionName_DropMembership=13,
+ SocketOptionName_DontFragment=14,
+ SocketOptionName_AddSourceMembership=15,
+ SocketOptionName_DropSourceMembership=16,
+ SocketOptionName_BlockSource=17,
+ SocketOptionName_UnblockSource=18,
+ SocketOptionName_PacketInformation=19,
+ SocketOptionName_NoDelay=1,
+ SocketOptionName_BsdUrgent=2,
+ SocketOptionName_Expedited=2,
+ SocketOptionName_NoChecksum=1,
+ SocketOptionName_ChecksumCoverage=20,
+ SocketOptionName_HopLimit=21,
+
+ /* This is Mono-specific, keep it in sync with
+ * Mono.Posix/PeerCred.cs
+ */
+ SocketOptionName_PeerCred=10001
+} MonoSocketOptionName;
+
+/* This is a copy of System.Net.Sockets.SocketFlags */
+typedef enum {
+ SocketFlags_None = 0x0000,
+ SocketFlags_OutOfBand = 0x0001,
+ SocketFlags_MaxIOVectorLength = 0x0010,
+ SocketFlags_Peek = 0x0002,
+ SocketFlags_DontRoute = 0x0004,
+ SocketFlags_Partial = 0x8000
+} MonoSocketFlags;
+
+typedef struct
+{
+ MonoObject obj;
+ gint pid;
+ gint uid;
+ gint gid;
+} MonoPeerCredData;
+
+gpointer
+ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObject *this_obj, gint32 family, gint32 type, gint32 proto,
+ gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_Close_internal (gsize sock, gint32 *error);
+
+gint32
+ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal (void);
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Available_internal (gsize sock, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_Blocking_internal (gsize sock, gboolean block, gint32 *error);
+
+gpointer
+ves_icall_System_Net_Sockets_Socket_Accept_internal (gsize sock, gint32 *error, gboolean blocking);
+
+void
+ves_icall_System_Net_Sockets_Socket_Listen_internal (gsize sock, guint32 backlog, gint32 *error);
+
+MonoObject*
+ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal (gsize sock, gint32 af, gint32 *error);
+
+MonoObject*
+ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (gsize sock, gint32 af, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_Bind_internal (gsize sock, MonoObject *sockaddr, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_Connect_internal (gsize sock, MonoObject *sockaddr, gint32 *error, gboolean blocking);
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Receive_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count,
+ gint32 flags, gint32 *error, gboolean blocking);
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Receive_array_internal (gsize sock, MonoArray *buffers, gint32 flags, gint32 *error,
+ gboolean blocking);
+
+gint32
+ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count,
+ gint32 flags, MonoObject **sockaddr, gint32 *error, gboolean blocking);
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Send_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count,
+ gint32 flags, gint32 *error, gboolean blocking);
+
+gint32
+ves_icall_System_Net_Sockets_Socket_Send_array_internal (gsize sock, MonoArray *buffers, gint32 flags, gint32 *error,
+ gboolean blocking);
+
+gint32
+ves_icall_System_Net_Sockets_Socket_SendTo_internal (gsize sock, MonoArray *buffer, gint32 offset, gint32 count,
+ gint32 flags, MonoObject *sockaddr, gint32 *error, gboolean blocking);
+
+void
+ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32 timeout, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_Shutdown_internal (gsize sock, gint32 how, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (gsize sock, gint32 level, gint32 name,
+ MonoObject **obj_val, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (gsize sock, gint32 level, gint32 name,
+ MonoArray **byte_val, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal (gsize sock, gint32 level, gint32 name,
+ MonoObject *obj_val, MonoArray *byte_val, gint32 int_val, gint32 *error);
+
+int
+ves_icall_System_Net_Sockets_Socket_IOControl_internal (gsize sock, gint32 code, MonoArray *input, MonoArray *output,
+ gint32 *error);
+
+MonoBoolean
+ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases,
+ MonoArray **h_addr_list, gint32 hint);
+
+MonoBoolean
+ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **h_name, MonoArray **h_aliases,
+ MonoArray **h_addr_list, gint32 hint);
+
+MonoBoolean
+ves_icall_System_Net_Dns_GetHostName_internal (MonoString **h_name);
+
+MonoBoolean
+ves_icall_System_Net_Sockets_Socket_Poll_internal (gsize sock, gint mode, gint timeout, gint32 *error);
+
+void
+ves_icall_System_Net_Sockets_Socket_Disconnect_internal (gsize sock, MonoBoolean reuse, gint32 *error);
+
+gboolean
+ves_icall_System_Net_Sockets_Socket_SendFile_internal (gsize sock, MonoString *filename, MonoArray *pre_buffer,
+ MonoArray *post_buffer, gint flags, gint32 *error, gboolean blocking);
+
+void
+icall_cancel_blocking_socket_operation (MonoThread *thread);
+
+gboolean
+ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto);
+
+void
+mono_network_init(void);
+
+void
+mono_network_cleanup(void);
+
+#endif /* _MONO_METADATA_W32SOCKET_H_ */
#include <mono/metadata/environment.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/threadpool.h>
-#include <mono/metadata/socket-io.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/runtime.h>
#include <mono/metadata/verify-internals.h>
#include <mono/metadata/reflection-internals.h>
+#include <mono/metadata/w32socket.h>
#include <mono/utils/mono-coop-mutex.h>
#include <mono/utils/mono-coop-semaphore.h>
#include <mono/utils/mono-error-internals.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/marshal.h>
-#include <mono/metadata/socket-io.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/io-layer/io-layer.h>
<ClCompile Include="..\mono\metadata\cominterop.c" />\r
<ClCompile Include="..\mono\metadata\console-win32.c" />\r
<ClCompile Include="..\mono\metadata\property-bag.c" />\r
- <ClCompile Include="..\mono\metadata\socket-io-windows.c" />\r
+ <ClCompile Include="..\mono\metadata\w32socket-win32.c" />\r
<ClCompile Include="..\mono\metadata\file-io-windows.c" />\r
<ClCompile Include="..\mono\metadata\icall-windows.c" />\r
<ClCompile Include="..\mono\metadata\marshal-windows.c" />\r
<ClCompile Include="..\mono\metadata\sgen-tarjan-bridge.c" />\r
<ClCompile Include="..\mono\metadata\sgen-toggleref.c" />\r
<ClCompile Include="..\mono\metadata\sgen-stw.c" />\r
- <ClCompile Include="..\mono\metadata\socket-io.c" />\r
+ <ClCompile Include="..\mono\metadata\w32socket.c" />\r
<ClCompile Include="..\mono\metadata\sre.c" />\r
<ClCompile Include="..\mono\metadata\sre-encode.c" />\r
<ClCompile Include="..\mono\metadata\sre-save.c" />\r
<ClInclude Include="..\mono\metadata\seq-points-data.h" />\r
<ClInclude Include="..\mono\metadata\sgen-bridge-internals.h" />\r
<ClInclude Include="..\mono\metadata\sgen-client-mono.h" />\r
- <ClInclude Include="..\mono\metadata\socket-io-windows-internals.h" />\r
+ <ClInclude Include="..\mono\metadata\w32socket-internals.h" />\r
<ClInclude Include="..\mono\metadata\threadpool-io.h" />\r
<ClInclude Include="..\mono\metadata\threadpool.h" />\r
<ClInclude Include="..\mono\metadata\threadpool-worker.h" />\r
<ClInclude Include="..\mono\metadata\security.h" />\r
<ClInclude Include="..\mono\metadata\sgen-bridge.h" />\r
<ClInclude Include="..\mono\metadata\sgen-toggleref.h" />\r
- <ClInclude Include="..\mono\metadata\socket-io.h" />\r
+ <ClInclude Include="..\mono\metadata\w32socket.h" />\r
<ClInclude Include="..\mono\metadata\sre-internals.h" />\r
<ClInclude Include="..\mono\metadata\string-icalls.h" />\r
<ClInclude Include="..\mono\metadata\sysmath.h" />\r
<ClCompile Include="..\mono\metadata\seq-points-data.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\mono\metadata\socket-io.c">\r
+ <ClCompile Include="..\mono\metadata\w32socket.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\mono\metadata\string-icalls.c">\r
<ClCompile Include="..\mono\metadata\sre-save.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\mono\metadata\socket-io-windows.c">\r
+ <ClCompile Include="..\mono\metadata\w32socket-win32.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\mono\metadata\file-io-windows.c">\r
<ClInclude Include="..\mono\metadata\seq-points-data.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\mono\metadata\socket-io.h">\r
+ <ClInclude Include="..\mono\metadata\w32socket.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
<ClInclude Include="..\mono\metadata\string-icalls.h">\r
<ClInclude Include="..\mono\metadata\sre-internals.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
- <ClInclude Include="..\mono\metadata\socket-io-windows-internals.h">\r
+ <ClInclude Include="..\mono\metadata\w32socket-internals.h">\r
<Filter>Header Files</Filter>\r
</ClInclude>\r
<ClInclude Include="..\mono\metadata\coree-internals.h">\r
<ClCompile Include="..\mono\metadata\rand.c" />\r
<ClCompile Include="..\mono\metadata\reflection.c" />\r
<ClCompile Include="..\mono\metadata\security-manager.c" />\r
- <ClCompile Include="..\mono\metadata\socket-io.c" />\r
+ <ClCompile Include="..\mono\metadata\w32socket.c" />\r
<ClCompile Include="..\mono\metadata\string-icalls.c" />\r
<ClCompile Include="..\mono\metadata\sysmath.c" />\r
<ClCompile Include="..\mono\metadata\threads.c" />\r
<ClCompile Include="..\mono\metadata\security-manager.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
- <ClCompile Include="..\mono\metadata\socket-io.c">\r
+ <ClCompile Include="..\mono\metadata\w32socket.c">\r
<Filter>Source Files</Filter>\r
</ClCompile>\r
<ClCompile Include="..\mono\metadata\string-icalls.c">\r