2 * w32socket-unix.c: Unix specific socket code.
4 * Copyright 2016 Microsoft
5 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include <sys/socket.h>
15 #ifdef HAVE_SYS_IOCTL_H
16 #include <sys/ioctl.h>
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
23 #include <arpa/inet.h>
29 #include <sys/types.h>
33 #ifdef HAVE_SYS_IOCTL_H
34 #include <sys/ioctl.h>
36 #ifdef HAVE_SYS_FILIO_H
37 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
39 #ifdef HAVE_SYS_SOCKIO_H
40 #include <sys/sockio.h> /* defines SIOCATMARK */
42 #ifndef HAVE_MSG_NOSIGNAL
45 #ifdef HAVE_SYS_SENDFILE_H
46 #include <sys/sendfile.h>
49 #include "w32socket.h"
50 #include "w32socket-internals.h"
51 #include "w32handle.h"
52 #include "utils/mono-logger-internals.h"
53 #include "utils/mono-poll.h"
61 } MonoW32HandleSocket;
63 static guint32 in_cleanup = 0;
66 socket_close (gpointer handle, gpointer data)
69 MonoW32HandleSocket *socket_handle = (MonoW32HandleSocket *)data;
70 MonoThreadInfo *info = mono_thread_info_current ();
72 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle);
74 /* Shutdown the socket for reading, to interrupt any potential
75 * receives that may be blocking for data. See bug 75705. */
76 shutdown (GPOINTER_TO_UINT (handle), SHUT_RD);
79 ret = close (GPOINTER_TO_UINT(handle));
80 } while (ret == -1 && errno == EINTR &&
81 !mono_thread_info_is_interrupt_state (info));
85 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: close error: %s", __func__, g_strerror (errno));
87 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
91 socket_handle->saved_error = 0;
95 socket_details (gpointer data)
97 /* FIXME: do something */
101 socket_typename (void)
107 socket_typesize (void)
109 return sizeof (MonoW32HandleSocket);
112 static MonoW32HandleOps ops = {
113 socket_close, /* close */
117 NULL, /* special_wait */
119 socket_details, /* details */
120 socket_typename, /* typename */
121 socket_typesize, /* typesize */
125 mono_w32socket_initialize (void)
127 mono_w32handle_register_ops (MONO_W32HANDLE_SOCKET, &ops);
131 cleanup_close (gpointer handle, gpointer data, gpointer user_data)
133 if (mono_w32handle_get_type (handle) == MONO_W32HANDLE_SOCKET)
134 mono_w32handle_force_close (handle, data);
140 mono_w32socket_cleanup (void)
142 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: cleaning up", __func__);
145 mono_w32handle_foreach (cleanup_close, NULL);
150 mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking)
154 MonoW32HandleSocket *socket_handle;
155 MonoW32HandleSocket new_socket_handle;
157 MonoThreadInfo *info;
159 if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
160 mono_w32socket_set_last_error (WSAEFAULT);
161 return INVALID_SOCKET;
164 handle = GUINT_TO_POINTER (sock);
165 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
166 mono_w32socket_set_last_error (WSAENOTSOCK);
167 return INVALID_SOCKET;
170 info = mono_thread_info_current ();
173 new_fd = accept (sock, addr, addrlen);
174 } while (new_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
178 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, g_strerror(errno));
179 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
180 return INVALID_SOCKET;
183 if (new_fd >= mono_w32handle_fd_reserve) {
184 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
186 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
190 return INVALID_SOCKET;
193 new_socket_handle.domain = socket_handle->domain;
194 new_socket_handle.type = socket_handle->type;
195 new_socket_handle.protocol = socket_handle->protocol;
196 new_socket_handle.still_readable = 1;
198 new_handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, new_fd,
200 if(new_handle == INVALID_HANDLE_VALUE) {
201 g_warning ("%s: error creating socket handle", __func__);
202 mono_w32socket_set_last_error (ERROR_GEN_FAILURE);
203 return INVALID_SOCKET;
206 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with",
207 __func__, new_handle);
213 mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking)
216 MonoW32HandleSocket *socket_handle;
218 handle = GUINT_TO_POINTER (sock);
219 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
220 mono_w32socket_set_last_error (WSAENOTSOCK);
224 if (connect (sock, addr, addrlen) == -1) {
225 MonoThreadInfo *info;
227 gint errnum, so_error;
232 if (errno != EINTR) {
233 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__,
234 g_strerror (errnum));
236 errnum = mono_w32socket_convert_error (errnum);
237 if (errnum == WSAEINPROGRESS)
238 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
240 mono_w32socket_set_last_error (errnum);
243 * On solaris x86 getsockopt (SO_ERROR) is not set after
244 * connect () fails so we need to save this error.
246 * But don't do this for EWOULDBLOCK (bug 317315)
248 if (errnum != WSAEWOULDBLOCK) {
249 /* ECONNRESET means the socket was closed by another thread */
250 /* Async close on mac raises ECONNABORTED. */
251 socket_handle->saved_error = errnum;
256 info = mono_thread_info_current ();
259 fds.events = MONO_POLLOUT;
260 while (mono_poll (&fds, 1, -1) == -1 && !mono_thread_info_is_interrupt_state (info)) {
261 if (errno != EINTR) {
263 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s", __func__, g_strerror (errno));
264 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
269 len = sizeof(so_error);
270 if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
272 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s", __func__, g_strerror (errno));
273 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
278 gint errnum = mono_w32socket_convert_error (so_error);
280 /* Need to save this socket error */
281 socket_handle->saved_error = errnum;
283 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s",
284 __func__, g_strerror (so_error));
286 mono_w32socket_set_last_error (errnum);
295 mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
297 return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking);
301 mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking)
304 MonoW32HandleSocket *socket_handle;
306 MonoThreadInfo *info;
308 handle = GUINT_TO_POINTER (sock);
309 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
310 mono_w32socket_set_last_error (WSAENOTSOCK);
314 info = mono_thread_info_current ();
317 ret = recvfrom (sock, buf, len, flags, from, fromlen);
318 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
320 if (ret == 0 && len > 0) {
321 /* According to the Linux man page, recvfrom only
322 * returns 0 when the socket has been shut down
323 * cleanly. Turn this into an EINTR to simulate win32
324 * behaviour of returning EINTR when a socket is
325 * closed while the recvfrom is blocking (we use a
326 * shutdown() in socket_close() to trigger this.) See
329 /* Distinguish between the socket being shut down at
330 * the local or remote ends, and reads that request 0
334 /* If this returns FALSE, it means the socket has been
335 * closed locally. If it returns TRUE, but
336 * still_readable != 1 then shutdown
337 * (SHUT_RD|SHUT_RDWR) has been called locally.
339 if (socket_handle->still_readable != 1) {
347 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, g_strerror(errno));
348 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
355 wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr)
359 memset (hdr, 0, sizeof (struct msghdr));
360 hdr->msg_iovlen = count;
361 hdr->msg_iov = g_new0 (struct iovec, count);
362 for (i = 0; i < count; i++) {
363 hdr->msg_iov [i].iov_base = buffers [i].buf;
364 hdr->msg_iov [i].iov_len = buffers [i].len;
369 msghdr_iov_free (struct msghdr *hdr)
371 g_free (hdr->msg_iov);
375 mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking)
377 MonoW32HandleSocket *socket_handle;
378 MonoThreadInfo *info;
383 g_assert (overlapped == NULL);
384 g_assert (complete == NULL);
386 handle = GUINT_TO_POINTER (sock);
387 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
388 mono_w32socket_set_last_error (WSAENOTSOCK);
392 info = mono_thread_info_current ();
394 wsabuf_to_msghdr (buffers, count, &hdr);
397 ret = recvmsg (sock, &hdr, *flags);
398 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
400 msghdr_iov_free (&hdr);
403 /* see mono_w32socket_recvfrom */
404 if (socket_handle->still_readable != 1) {
412 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, g_strerror(errno));
413 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
418 *flags = hdr.msg_flags;
424 mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
428 MonoThreadInfo *info;
430 handle = GUINT_TO_POINTER (sock);
431 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
432 mono_w32socket_set_last_error (WSAENOTSOCK);
436 info = mono_thread_info_current ();
439 ret = send (sock, buf, len, flags);
440 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
444 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno));
447 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
448 * a blocking socket. See bug #599488 */
449 if (errnum == EAGAIN) {
450 ret = fcntl (sock, F_GETFL, 0);
451 if (ret != -1 && (ret & O_NONBLOCK) == 0)
454 #endif /* O_NONBLOCK */
455 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
462 mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
466 MonoThreadInfo *info;
468 handle = GUINT_TO_POINTER (sock);
469 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
470 mono_w32socket_set_last_error (WSAENOTSOCK);
474 info = mono_thread_info_current ();
477 ret = sendto (sock, buf, len, flags, to, tolen);
478 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
482 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno));
483 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
490 mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking)
493 MonoThreadInfo *info;
497 g_assert (overlapped == NULL);
498 g_assert (complete == NULL);
500 handle = GUINT_TO_POINTER (sock);
501 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
502 mono_w32socket_set_last_error (WSAENOTSOCK);
506 info = mono_thread_info_current ();
508 wsabuf_to_msghdr (buffers, count, &hdr);
511 ret = sendmsg (sock, &hdr, flags);
512 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
514 msghdr_iov_free (&hdr);
518 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, g_strerror (errno));
519 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
527 #define SF_BUFFER_SIZE 16384
530 mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking)
532 MonoThreadInfo *info;
536 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
542 handle = GUINT_TO_POINTER (sock);
543 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
544 mono_w32socket_set_last_error (WSAENOTSOCK);
548 /* Write the header */
549 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
550 ret = mono_w32socket_send (sock, buffers->Head, buffers->HeadLength, 0, FALSE);
551 if (ret == SOCKET_ERROR)
555 info = mono_thread_info_current ();
557 file = GPOINTER_TO_INT (file_handle);
559 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
560 ret = fstat (file, &statbuf);
563 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
569 ret = sendfile (sock, file, NULL, statbuf.st_size);
570 #elif defined(DARWIN)
571 /* TODO: header/tail could be sent in the 5th argument */
572 /* TODO: Might not send the entire file for non-blocking sockets */
573 ret = sendfile (file, sock, 0, &statbuf.st_size, NULL, 0);
575 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
577 buffer = g_malloc (SF_BUFFER_SIZE);
581 ret = read (file, buffer, SF_BUFFER_SIZE);
582 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
584 if (ret == -1 || ret == 0)
588 ret = send (sock, buffer, ret, 0); /* short sends? enclose this in a loop? */
589 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
590 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
597 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
602 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
603 ret = mono_w32socket_send (sock, buffers->Tail, buffers->TailLength, 0, FALSE);
604 if (ret == SOCKET_ERROR)
608 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
609 CloseHandle (handle);
615 mono_w32socket_socket (int domain, int type, int protocol)
617 MonoW32HandleSocket socket_handle = {0};
621 socket_handle.domain = domain;
622 socket_handle.type = type;
623 socket_handle.protocol = protocol;
624 socket_handle.still_readable = 1;
626 sock = socket (domain, type, protocol);
627 if (sock == -1 && domain == AF_INET && type == SOCK_RAW &&
629 /* Retry with protocol == 4 (see bug #54565) */
630 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
631 socket_handle.protocol = 4;
632 sock = socket (AF_INET, SOCK_RAW, 4);
637 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errno));
638 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
639 return INVALID_SOCKET;
642 if (sock >= mono_w32handle_fd_reserve) {
643 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big (%d >= %d)",
644 __func__, sock, mono_w32handle_fd_reserve);
646 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
649 return INVALID_SOCKET;
652 /* .net seems to set this by default for SOCK_STREAM, not for
653 * SOCK_DGRAM (see bug #36322)
654 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
656 * It seems winsock has a rather different idea of what
657 * SO_REUSEADDR means. If it's set, then a new socket can be
658 * bound over an existing listening socket. There's a new
659 * windows-specific option called SO_EXCLUSIVEADDRUSE but
660 * using that means the socket MUST be closed properly, or a
661 * denial of service can occur. Luckily for us, winsock
662 * behaves as though any other system would when SO_REUSEADDR
663 * is true, so we don't need to do anything else here. See
665 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
670 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
674 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__);
675 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
676 return INVALID_SOCKET;
681 handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, sock, &socket_handle);
682 if (handle == INVALID_HANDLE_VALUE) {
683 g_warning ("%s: error creating socket handle", __func__);
684 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
686 return INVALID_SOCKET;
689 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, handle);
695 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
700 handle = GUINT_TO_POINTER (sock);
701 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
702 mono_w32socket_set_last_error (WSAENOTSOCK);
706 ret = bind (sock, addr, addrlen);
709 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, g_strerror(errno));
710 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
718 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
723 handle = GUINT_TO_POINTER (sock);
724 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
725 mono_w32socket_set_last_error (WSAENOTSOCK);
729 ret = getpeername (sock, name, namelen);
732 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__, g_strerror (errno));
733 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
741 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
746 handle = GUINT_TO_POINTER (sock);
747 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
748 mono_w32socket_set_last_error (WSAENOTSOCK);
752 ret = getsockname (sock, name, namelen);
755 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__, g_strerror (errno));
756 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
764 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
770 MonoW32HandleSocket *socket_handle;
772 handle = GUINT_TO_POINTER (sock);
773 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
774 mono_w32socket_set_last_error (WSAENOTSOCK);
779 if (level == SOL_SOCKET &&
780 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
782 *optlen = sizeof (tv);
785 ret = getsockopt (sock, level, optname, tmp_val, optlen);
788 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__, g_strerror (errno));
789 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
793 if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
794 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
795 *optlen = sizeof (int);
798 if (optname == SO_ERROR) {
799 if (*((int *)optval) != 0) {
800 *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
801 socket_handle->saved_error = *((int *)optval);
803 *((int *)optval) = socket_handle->saved_error;
811 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen)
816 #if defined (__linux__)
817 /* This has its address taken so it cannot be moved to the if block which uses it */
822 handle = GUINT_TO_POINTER (sock);
823 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
824 mono_w32socket_set_last_error (WSAENOTSOCK);
829 if (level == SOL_SOCKET &&
830 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
831 int ms = *((int *) optval);
832 tv.tv_sec = ms / 1000;
833 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
835 optlen = sizeof (tv);
837 #if defined (__linux__)
838 else if (level == SOL_SOCKET &&
839 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
840 /* According to socket(7) the Linux kernel doubles the
841 * buffer sizes "to allow space for bookkeeping
844 bufsize = *((int *) optval);
851 ret = setsockopt (sock, level, optname, tmp_val, optlen);
854 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__, g_strerror (errno));
855 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
859 #if defined (SO_REUSEPORT)
860 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
861 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
863 socklen_t type_len = sizeof (type);
865 if (!getsockopt (sock, level, SO_TYPE, &type, &type_len)) {
866 if (type == SOCK_DGRAM || type == SOCK_STREAM)
867 setsockopt (sock, level, SO_REUSEPORT, tmp_val, optlen);
876 mono_w32socket_listen (SOCKET sock, gint backlog)
881 handle = GUINT_TO_POINTER (sock);
882 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
883 mono_w32socket_set_last_error (WSAENOTSOCK);
887 ret = listen (sock, backlog);
890 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, g_strerror (errno));
891 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
899 mono_w32socket_shutdown (SOCKET sock, gint how)
901 MonoW32HandleSocket *socket_handle;
905 handle = GUINT_TO_POINTER (sock);
906 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
907 mono_w32socket_set_last_error (WSAENOTSOCK);
911 if (how == SHUT_RD || how == SHUT_RDWR)
912 socket_handle->still_readable = 0;
914 ret = shutdown (sock, how);
917 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__, g_strerror (errno));
918 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
926 mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
928 MonoW32HandleSocket *socket_handle;
933 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, sock);
935 /* We could check the socket type here and fail unless its
936 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
937 * if we really wanted to */
939 handle = GUINT_TO_POINTER (sock);
940 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
941 mono_w32socket_set_last_error (WSAENOTSOCK);
945 newsock = socket (socket_handle->domain, socket_handle->type, socket_handle->protocol);
948 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errnum));
949 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
953 /* According to Stevens "Advanced Programming in the UNIX
954 * Environment: UNIX File I/O" dup2() is atomic so there
955 * should not be a race condition between the old fd being
956 * closed and the new socket fd being copied over */
958 ret = dup2 (newsock, sock);
959 } while (ret == -1 && errno == EAGAIN);
963 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dup2 error: %s", __func__, g_strerror (errnum));
964 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
974 extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
976 return mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
980 extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send,
981 OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags)
983 return mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE);
989 } extension_functions[] = {
990 { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, extension_disconect },
991 { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, extension_transmit_file },
996 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
1002 handle = GUINT_TO_POINTER (sock);
1003 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1004 mono_w32socket_set_last_error (WSAENOTSOCK);
1005 return SOCKET_ERROR;
1008 if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1012 if (inputlen < sizeof(GUID)) {
1013 /* As far as I can tell, windows doesn't
1014 * actually set an error here...
1016 mono_w32socket_set_last_error (WSAEINVAL);
1017 return SOCKET_ERROR;
1020 if (outputlen < sizeof(gpointer)) {
1022 mono_w32socket_set_last_error (WSAEINVAL);
1023 return SOCKET_ERROR;
1026 if (output == NULL) {
1028 mono_w32socket_set_last_error (WSAEINVAL);
1029 return SOCKET_ERROR;
1032 guid = (GUID*) input;
1033 for (i = 0; extension_functions[i].func; i++) {
1034 if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
1035 memcpy (output, &extension_functions[i].func, sizeof(gpointer));
1036 *written = sizeof(gpointer);
1041 mono_w32socket_set_last_error (WSAEINVAL);
1042 return SOCKET_ERROR;
1045 if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1048 if (inputlen < 3 * sizeof (guint32)) {
1049 mono_w32socket_set_last_error (WSAEINVAL);
1050 return SOCKET_ERROR;
1053 onoff = *((guint32*) input);
1055 ret = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
1057 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1058 return SOCKET_ERROR;
1061 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1063 /* Values are in ms, but we need s */
1064 guint32 keepalivetime, keepaliveinterval, rem;
1066 keepalivetime = *(((guint32*) input) + 1);
1067 keepaliveinterval = *(((guint32*) input) + 2);
1069 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1070 rem = keepalivetime % 1000;
1071 keepalivetime /= 1000;
1072 if (keepalivetime == 0 || rem >= 500)
1074 ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
1076 rem = keepaliveinterval % 1000;
1077 keepaliveinterval /= 1000;
1078 if (keepaliveinterval == 0 || rem >= 500)
1079 keepaliveinterval++;
1080 ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
1083 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1084 return SOCKET_ERROR;
1094 buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
1096 ret = ioctl (sock, command, buffer);
1100 gint errnum = errno;
1101 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__, g_strerror (errno));
1102 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1103 return SOCKET_ERROR;
1111 /* We just copy the buffer to the output. Some ioctls
1112 * don't even output any data, but, well...
1114 * NB windows returns WSAEFAULT if outputlen is too small */
1115 inputlen = (inputlen > outputlen) ? outputlen : inputlen;
1117 if (inputlen > 0 && output != NULL)
1118 memcpy (output, buffer, inputlen);
1121 *written = inputlen;
1127 mono_w32socket_set_blocking (SOCKET socket, gboolean blocking)
1132 handle = GINT_TO_POINTER (socket);
1133 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1134 mono_w32socket_set_last_error (WSAENOTSOCK);
1135 return SOCKET_ERROR;
1139 /* This works better than ioctl(...FIONBIO...)
1140 * on Linux (it causes connect to return
1141 * EINPROGRESS, but the ioctl doesn't seem to) */
1142 ret = fcntl (socket, F_GETFL, 0);
1144 ret = fcntl (socket, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK)));
1145 #endif /* O_NONBLOCK */
1148 gint errnum = errno;
1149 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno));
1150 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1151 return SOCKET_ERROR;
1158 mono_w32socket_get_available (SOCKET socket, guint64 *amount)
1163 handle = GINT_TO_POINTER (socket);
1164 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1165 mono_w32socket_set_last_error (WSAENOTSOCK);
1166 return SOCKET_ERROR;
1169 #if defined (PLATFORM_MACOSX)
1170 // ioctl (socket, FIONREAD, XXX) returns the size of
1171 // the UDP header as well on Darwin.
1173 // Use getsockopt SO_NREAD instead to get the
1174 // right values for TCP and UDP.
1176 // ai_canonname can be null in some cases on darwin,
1177 // where the runtime assumes it will be the value of
1180 socklen_t optlen = sizeof (int);
1181 ret = getsockopt (socket, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
1183 ret = ioctl (socket, FIONREAD, (gulong*) amount);
1187 gint errnum = errno;
1188 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno));
1189 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1190 return SOCKET_ERROR;
1197 mono_w32socket_set_last_error (gint32 error)
1199 SetLastError (error);
1203 mono_w32socket_get_last_error (void)
1205 return GetLastError ();
1209 mono_w32socket_convert_error (gint error)
1212 case 0: return ERROR_SUCCESS;
1213 case EACCES: return WSAEACCES;
1215 case EADDRINUSE: return WSAEADDRINUSE;
1218 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
1220 #if EAGAIN != EWOULDBLOCK
1221 case EAGAIN: return WSAEWOULDBLOCK;
1224 case EALREADY: return WSAEALREADY;
1226 case EBADF: return WSAENOTSOCK;
1228 case ECONNABORTED: return WSAENETDOWN;
1231 case ECONNREFUSED: return WSAECONNREFUSED;
1234 case ECONNRESET: return WSAECONNRESET;
1236 case EFAULT: return WSAEFAULT;
1238 case EHOSTUNREACH: return WSAEHOSTUNREACH;
1241 case EINPROGRESS: return WSAEINPROGRESS;
1243 case EINTR: return WSAEINTR;
1244 case EINVAL: return WSAEINVAL;
1245 /*FIXME: case EIO: return WSAE????; */
1247 case EISCONN: return WSAEISCONN;
1249 /* FIXME: case ELOOP: return WSA????; */
1250 case EMFILE: return WSAEMFILE;
1252 case EMSGSIZE: return WSAEMSGSIZE;
1254 /* FIXME: case ENAMETOOLONG: return WSAEACCES; */
1256 case ENETUNREACH: return WSAENETUNREACH;
1259 case ENOBUFS: return WSAENOBUFS; /* not documented */
1261 /* case ENOENT: return WSAE????; */
1262 case ENOMEM: return WSAENOBUFS;
1264 case ENOPROTOOPT: return WSAENOPROTOOPT;
1267 case ENOSR: return WSAENETDOWN;
1270 case ENOTCONN: return WSAENOTCONN;
1272 /*FIXME: case ENOTDIR: return WSAE????; */
1274 case ENOTSOCK: return WSAENOTSOCK;
1276 case ENOTTY: return WSAENOTSOCK;
1278 case EOPNOTSUPP: return WSAEOPNOTSUPP;
1280 case EPERM: return WSAEACCES;
1281 case EPIPE: return WSAESHUTDOWN;
1282 #ifdef EPROTONOSUPPORT
1283 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
1286 case ERESTARTSYS: return WSAENETDOWN;
1288 /*FIXME: case EROFS: return WSAE????; */
1289 #ifdef ESOCKTNOSUPPORT
1290 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
1293 case ETIMEDOUT: return WSAETIMEDOUT;
1296 case EWOULDBLOCK: return WSAEWOULDBLOCK;
1298 #ifdef EADDRNOTAVAIL
1299 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
1301 /* This might happen with unix sockets */
1302 case ENOENT: return WSAECONNREFUSED;
1304 case EDESTADDRREQ: return WSAEDESTADDRREQ;
1307 case EHOSTDOWN: return WSAEHOSTDOWN;
1310 case ENETDOWN: return WSAENETDOWN;
1312 case ENODEV: return WSAENETDOWN;
1314 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
1319 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
1321 #if defined (SO_REUSEPORT)
1325 /* Linux always supports double binding for UDP, even on older kernels. */
1326 if (proto == ProtocolType_Udp)