3 * Unix specific socket code.
5 * Copyright 2016 Microsoft
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #ifdef HAVE_SYS_IOCTL_H
18 #include <sys/ioctl.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
25 #include <arpa/inet.h>
34 #ifdef HAVE_SYS_IOCTL_H
35 #include <sys/ioctl.h>
37 #ifdef HAVE_SYS_FILIO_H
38 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
40 #ifdef HAVE_SYS_SOCKIO_H
41 #include <sys/sockio.h> /* defines SIOCATMARK */
43 #ifndef HAVE_MSG_NOSIGNAL
46 #ifdef HAVE_SYS_SENDFILE_H
47 #include <sys/sendfile.h>
51 #include "w32socket.h"
52 #include "w32socket-internals.h"
54 #include "w32handle.h"
55 #include "utils/mono-logger-internals.h"
56 #include "utils/mono-poll.h"
64 } MonoW32HandleSocket;
66 static guint32 in_cleanup = 0;
69 socket_close (gpointer handle, gpointer data)
72 MonoW32HandleSocket *socket_handle = (MonoW32HandleSocket *)data;
73 MonoThreadInfo *info = mono_thread_info_current ();
75 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle);
77 /* Shutdown the socket for reading, to interrupt any potential
78 * receives that may be blocking for data. See bug 75705. */
79 shutdown (GPOINTER_TO_UINT (handle), SHUT_RD);
82 ret = close (GPOINTER_TO_UINT(handle));
83 } while (ret == -1 && errno == EINTR &&
84 !mono_thread_info_is_interrupt_state (info));
88 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: close error: %s", __func__, g_strerror (errno));
90 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
94 socket_handle->saved_error = 0;
98 socket_details (gpointer data)
100 /* FIXME: do something */
104 socket_typename (void)
110 socket_typesize (void)
112 return sizeof (MonoW32HandleSocket);
115 static MonoW32HandleOps ops = {
116 socket_close, /* close */
120 NULL, /* special_wait */
122 socket_details, /* details */
123 socket_typename, /* typename */
124 socket_typesize, /* typesize */
128 mono_w32socket_initialize (void)
130 mono_w32handle_register_ops (MONO_W32HANDLE_SOCKET, &ops);
134 cleanup_close (gpointer handle, gpointer data, gpointer user_data)
136 if (mono_w32handle_get_type (handle) == MONO_W32HANDLE_SOCKET)
137 mono_w32handle_force_close (handle, data);
143 mono_w32socket_cleanup (void)
145 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: cleaning up", __func__);
148 mono_w32handle_foreach (cleanup_close, NULL);
153 mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking)
157 MonoW32HandleSocket *socket_handle;
158 MonoW32HandleSocket new_socket_handle;
160 MonoThreadInfo *info;
162 if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
163 mono_w32socket_set_last_error (WSAEFAULT);
164 return INVALID_SOCKET;
167 handle = GUINT_TO_POINTER (sock);
168 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
169 mono_w32socket_set_last_error (WSAENOTSOCK);
170 return INVALID_SOCKET;
173 info = mono_thread_info_current ();
176 new_fd = accept (sock, addr, addrlen);
177 } while (new_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
181 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, g_strerror(errno));
182 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
183 return INVALID_SOCKET;
186 if (new_fd >= mono_w32handle_fd_reserve) {
187 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
189 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
193 return INVALID_SOCKET;
196 new_socket_handle.domain = socket_handle->domain;
197 new_socket_handle.type = socket_handle->type;
198 new_socket_handle.protocol = socket_handle->protocol;
199 new_socket_handle.still_readable = 1;
201 new_handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, new_fd,
203 if(new_handle == INVALID_HANDLE_VALUE) {
204 g_warning ("%s: error creating socket handle", __func__);
205 mono_w32socket_set_last_error (ERROR_GEN_FAILURE);
206 return INVALID_SOCKET;
209 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with",
210 __func__, new_handle);
216 mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking)
219 MonoW32HandleSocket *socket_handle;
221 handle = GUINT_TO_POINTER (sock);
222 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
223 mono_w32socket_set_last_error (WSAENOTSOCK);
227 if (connect (sock, addr, addrlen) == -1) {
228 MonoThreadInfo *info;
230 gint errnum, so_error;
235 if (errno != EINTR) {
236 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__,
237 g_strerror (errnum));
239 errnum = mono_w32socket_convert_error (errnum);
240 if (errnum == WSAEINPROGRESS)
241 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
243 mono_w32socket_set_last_error (errnum);
246 * On solaris x86 getsockopt (SO_ERROR) is not set after
247 * connect () fails so we need to save this error.
249 * But don't do this for EWOULDBLOCK (bug 317315)
251 if (errnum != WSAEWOULDBLOCK) {
252 /* ECONNRESET means the socket was closed by another thread */
253 /* Async close on mac raises ECONNABORTED. */
254 socket_handle->saved_error = errnum;
259 info = mono_thread_info_current ();
262 fds.events = MONO_POLLOUT;
263 while (mono_poll (&fds, 1, -1) == -1 && !mono_thread_info_is_interrupt_state (info)) {
264 if (errno != EINTR) {
266 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s", __func__, g_strerror (errno));
267 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
272 len = sizeof(so_error);
273 if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
275 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s", __func__, g_strerror (errno));
276 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
281 gint errnum = mono_w32socket_convert_error (so_error);
283 /* Need to save this socket error */
284 socket_handle->saved_error = errnum;
286 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s",
287 __func__, g_strerror (so_error));
289 mono_w32socket_set_last_error (errnum);
298 mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
300 return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking);
304 mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking)
307 MonoW32HandleSocket *socket_handle;
309 MonoThreadInfo *info;
311 handle = GUINT_TO_POINTER (sock);
312 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
313 mono_w32socket_set_last_error (WSAENOTSOCK);
317 info = mono_thread_info_current ();
320 ret = recvfrom (sock, buf, len, flags, from, fromlen);
321 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
323 if (ret == 0 && len > 0) {
324 /* According to the Linux man page, recvfrom only
325 * returns 0 when the socket has been shut down
326 * cleanly. Turn this into an EINTR to simulate win32
327 * behaviour of returning EINTR when a socket is
328 * closed while the recvfrom is blocking (we use a
329 * shutdown() in socket_close() to trigger this.) See
332 /* Distinguish between the socket being shut down at
333 * the local or remote ends, and reads that request 0
337 /* If this returns FALSE, it means the socket has been
338 * closed locally. If it returns TRUE, but
339 * still_readable != 1 then shutdown
340 * (SHUT_RD|SHUT_RDWR) has been called locally.
342 if (socket_handle->still_readable != 1) {
350 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, g_strerror(errno));
351 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
358 wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr)
362 memset (hdr, 0, sizeof (struct msghdr));
363 hdr->msg_iovlen = count;
364 hdr->msg_iov = g_new0 (struct iovec, count);
365 for (i = 0; i < count; i++) {
366 hdr->msg_iov [i].iov_base = buffers [i].buf;
367 hdr->msg_iov [i].iov_len = buffers [i].len;
372 msghdr_iov_free (struct msghdr *hdr)
374 g_free (hdr->msg_iov);
378 mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking)
380 MonoW32HandleSocket *socket_handle;
381 MonoThreadInfo *info;
386 g_assert (overlapped == NULL);
387 g_assert (complete == NULL);
389 handle = GUINT_TO_POINTER (sock);
390 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
391 mono_w32socket_set_last_error (WSAENOTSOCK);
395 info = mono_thread_info_current ();
397 wsabuf_to_msghdr (buffers, count, &hdr);
400 ret = recvmsg (sock, &hdr, *flags);
401 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
403 msghdr_iov_free (&hdr);
406 /* see mono_w32socket_recvfrom */
407 if (socket_handle->still_readable != 1) {
415 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, g_strerror(errno));
416 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
421 *flags = hdr.msg_flags;
427 mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
431 MonoThreadInfo *info;
433 handle = GUINT_TO_POINTER (sock);
434 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
435 mono_w32socket_set_last_error (WSAENOTSOCK);
439 info = mono_thread_info_current ();
442 ret = send (sock, buf, len, flags);
443 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
447 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno));
450 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
451 * a blocking socket. See bug #599488 */
452 if (errnum == EAGAIN) {
453 ret = fcntl (sock, F_GETFL, 0);
454 if (ret != -1 && (ret & O_NONBLOCK) == 0)
457 #endif /* O_NONBLOCK */
458 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
465 mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
469 MonoThreadInfo *info;
471 handle = GUINT_TO_POINTER (sock);
472 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
473 mono_w32socket_set_last_error (WSAENOTSOCK);
477 info = mono_thread_info_current ();
480 ret = sendto (sock, buf, len, flags, to, tolen);
481 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
485 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno));
486 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
493 mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking)
496 MonoThreadInfo *info;
500 g_assert (overlapped == NULL);
501 g_assert (complete == NULL);
503 handle = GUINT_TO_POINTER (sock);
504 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
505 mono_w32socket_set_last_error (WSAENOTSOCK);
509 info = mono_thread_info_current ();
511 wsabuf_to_msghdr (buffers, count, &hdr);
514 ret = sendmsg (sock, &hdr, flags);
515 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
517 msghdr_iov_free (&hdr);
521 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, g_strerror (errno));
522 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
530 #define SF_BUFFER_SIZE 16384
533 mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking)
535 MonoThreadInfo *info;
539 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
545 handle = GUINT_TO_POINTER (sock);
546 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
547 mono_w32socket_set_last_error (WSAENOTSOCK);
551 /* Write the header */
552 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
553 ret = mono_w32socket_send (sock, buffers->Head, buffers->HeadLength, 0, FALSE);
554 if (ret == SOCKET_ERROR)
558 info = mono_thread_info_current ();
560 file = GPOINTER_TO_INT (file_handle);
562 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
563 ret = fstat (file, &statbuf);
566 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
572 ret = sendfile (sock, file, NULL, statbuf.st_size);
573 #elif defined(DARWIN)
574 /* TODO: header/tail could be sent in the 5th argument */
575 /* TODO: Might not send the entire file for non-blocking sockets */
576 ret = sendfile (file, sock, 0, &statbuf.st_size, NULL, 0);
578 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
580 buffer = g_malloc (SF_BUFFER_SIZE);
584 ret = read (file, buffer, SF_BUFFER_SIZE);
585 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
587 if (ret == -1 || ret == 0)
591 ret = send (sock, buffer, ret, 0); /* short sends? enclose this in a loop? */
592 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
593 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
600 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
605 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
606 ret = mono_w32socket_send (sock, buffers->Tail, buffers->TailLength, 0, FALSE);
607 if (ret == SOCKET_ERROR)
611 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
612 mono_w32handle_close (handle);
618 mono_w32socket_socket (int domain, int type, int protocol)
620 MonoW32HandleSocket socket_handle = {0};
624 socket_handle.domain = domain;
625 socket_handle.type = type;
626 socket_handle.protocol = protocol;
627 socket_handle.still_readable = 1;
629 sock = socket (domain, type, protocol);
630 if (sock == -1 && domain == AF_INET && type == SOCK_RAW &&
632 /* Retry with protocol == 4 (see bug #54565) */
633 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
634 socket_handle.protocol = 4;
635 sock = socket (AF_INET, SOCK_RAW, 4);
640 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errno));
641 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
642 return INVALID_SOCKET;
645 if (sock >= mono_w32handle_fd_reserve) {
646 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big (%d >= %d)",
647 __func__, sock, mono_w32handle_fd_reserve);
649 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
652 return INVALID_SOCKET;
655 /* .net seems to set this by default for SOCK_STREAM, not for
656 * SOCK_DGRAM (see bug #36322)
657 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
659 * It seems winsock has a rather different idea of what
660 * SO_REUSEADDR means. If it's set, then a new socket can be
661 * bound over an existing listening socket. There's a new
662 * windows-specific option called SO_EXCLUSIVEADDRUSE but
663 * using that means the socket MUST be closed properly, or a
664 * denial of service can occur. Luckily for us, winsock
665 * behaves as though any other system would when SO_REUSEADDR
666 * is true, so we don't need to do anything else here. See
668 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
673 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
677 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__);
678 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
679 return INVALID_SOCKET;
684 handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, sock, &socket_handle);
685 if (handle == INVALID_HANDLE_VALUE) {
686 g_warning ("%s: error creating socket handle", __func__);
687 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
689 return INVALID_SOCKET;
692 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, handle);
698 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
703 handle = GUINT_TO_POINTER (sock);
704 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
705 mono_w32socket_set_last_error (WSAENOTSOCK);
709 ret = bind (sock, addr, addrlen);
712 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, g_strerror(errno));
713 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
721 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
726 handle = GUINT_TO_POINTER (sock);
727 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
728 mono_w32socket_set_last_error (WSAENOTSOCK);
732 ret = getpeername (sock, name, namelen);
735 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__, g_strerror (errno));
736 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
744 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
749 handle = GUINT_TO_POINTER (sock);
750 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
751 mono_w32socket_set_last_error (WSAENOTSOCK);
755 ret = getsockname (sock, name, namelen);
758 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__, g_strerror (errno));
759 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
767 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
773 MonoW32HandleSocket *socket_handle;
775 handle = GUINT_TO_POINTER (sock);
776 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
777 mono_w32socket_set_last_error (WSAENOTSOCK);
782 if (level == SOL_SOCKET &&
783 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
785 *optlen = sizeof (tv);
788 ret = getsockopt (sock, level, optname, tmp_val, optlen);
791 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__, g_strerror (errno));
792 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
796 if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
797 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
798 *optlen = sizeof (int);
801 if (optname == SO_ERROR) {
802 if (*((int *)optval) != 0) {
803 *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
804 socket_handle->saved_error = *((int *)optval);
806 *((int *)optval) = socket_handle->saved_error;
814 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen)
819 #if defined (__linux__)
820 /* This has its address taken so it cannot be moved to the if block which uses it */
825 handle = GUINT_TO_POINTER (sock);
826 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
827 mono_w32socket_set_last_error (WSAENOTSOCK);
832 if (level == SOL_SOCKET &&
833 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
834 int ms = *((int *) optval);
835 tv.tv_sec = ms / 1000;
836 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
838 optlen = sizeof (tv);
840 #if defined (__linux__)
841 else if (level == SOL_SOCKET &&
842 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
843 /* According to socket(7) the Linux kernel doubles the
844 * buffer sizes "to allow space for bookkeeping
847 bufsize = *((int *) optval);
854 ret = setsockopt (sock, level, optname, tmp_val, optlen);
857 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__, g_strerror (errno));
858 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
862 #if defined (SO_REUSEPORT)
863 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
864 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
866 socklen_t type_len = sizeof (type);
868 if (!getsockopt (sock, level, SO_TYPE, &type, &type_len)) {
869 if (type == SOCK_DGRAM || type == SOCK_STREAM)
870 setsockopt (sock, level, SO_REUSEPORT, tmp_val, optlen);
879 mono_w32socket_listen (SOCKET sock, gint backlog)
884 handle = GUINT_TO_POINTER (sock);
885 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
886 mono_w32socket_set_last_error (WSAENOTSOCK);
890 ret = listen (sock, backlog);
893 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, g_strerror (errno));
894 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
902 mono_w32socket_shutdown (SOCKET sock, gint how)
904 MonoW32HandleSocket *socket_handle;
908 handle = GUINT_TO_POINTER (sock);
909 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
910 mono_w32socket_set_last_error (WSAENOTSOCK);
914 if (how == SHUT_RD || how == SHUT_RDWR)
915 socket_handle->still_readable = 0;
917 ret = shutdown (sock, how);
920 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__, g_strerror (errno));
921 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
929 mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
931 MonoW32HandleSocket *socket_handle;
936 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, sock);
938 /* We could check the socket type here and fail unless its
939 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
940 * if we really wanted to */
942 handle = GUINT_TO_POINTER (sock);
943 if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
944 mono_w32socket_set_last_error (WSAENOTSOCK);
948 newsock = socket (socket_handle->domain, socket_handle->type, socket_handle->protocol);
951 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errnum));
952 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
956 /* According to Stevens "Advanced Programming in the UNIX
957 * Environment: UNIX File I/O" dup2() is atomic so there
958 * should not be a race condition between the old fd being
959 * closed and the new socket fd being copied over */
961 ret = dup2 (newsock, sock);
962 } while (ret == -1 && errno == EAGAIN);
966 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dup2 error: %s", __func__, g_strerror (errnum));
967 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
977 extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
979 return mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
983 extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send,
984 OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags)
986 return mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE);
992 } extension_functions[] = {
993 { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, extension_disconect },
994 { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, extension_transmit_file },
999 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
1005 handle = GUINT_TO_POINTER (sock);
1006 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1007 mono_w32socket_set_last_error (WSAENOTSOCK);
1008 return SOCKET_ERROR;
1011 if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1015 if (inputlen < sizeof(GUID)) {
1016 /* As far as I can tell, windows doesn't
1017 * actually set an error here...
1019 mono_w32socket_set_last_error (WSAEINVAL);
1020 return SOCKET_ERROR;
1023 if (outputlen < sizeof(gpointer)) {
1025 mono_w32socket_set_last_error (WSAEINVAL);
1026 return SOCKET_ERROR;
1029 if (output == NULL) {
1031 mono_w32socket_set_last_error (WSAEINVAL);
1032 return SOCKET_ERROR;
1035 guid = (GUID*) input;
1036 for (i = 0; extension_functions[i].func; i++) {
1037 if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
1038 memcpy (output, &extension_functions[i].func, sizeof(gpointer));
1039 *written = sizeof(gpointer);
1044 mono_w32socket_set_last_error (WSAEINVAL);
1045 return SOCKET_ERROR;
1048 if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1051 if (inputlen < 3 * sizeof (guint32)) {
1052 mono_w32socket_set_last_error (WSAEINVAL);
1053 return SOCKET_ERROR;
1056 onoff = *((guint32*) input);
1058 ret = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
1060 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1061 return SOCKET_ERROR;
1064 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1066 /* Values are in ms, but we need s */
1067 guint32 keepalivetime, keepaliveinterval, rem;
1069 keepalivetime = *(((guint32*) input) + 1);
1070 keepaliveinterval = *(((guint32*) input) + 2);
1072 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1073 rem = keepalivetime % 1000;
1074 keepalivetime /= 1000;
1075 if (keepalivetime == 0 || rem >= 500)
1077 ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
1079 rem = keepaliveinterval % 1000;
1080 keepaliveinterval /= 1000;
1081 if (keepaliveinterval == 0 || rem >= 500)
1082 keepaliveinterval++;
1083 ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
1086 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1087 return SOCKET_ERROR;
1097 buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
1099 ret = ioctl (sock, command, buffer);
1103 gint errnum = errno;
1104 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__, g_strerror (errno));
1105 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1106 return SOCKET_ERROR;
1114 /* We just copy the buffer to the output. Some ioctls
1115 * don't even output any data, but, well...
1117 * NB windows returns WSAEFAULT if outputlen is too small */
1118 inputlen = (inputlen > outputlen) ? outputlen : inputlen;
1120 if (inputlen > 0 && output != NULL)
1121 memcpy (output, buffer, inputlen);
1124 *written = inputlen;
1130 mono_w32socket_close (SOCKET sock)
1132 return mono_w32handle_close (GINT_TO_POINTER (sock));
1136 mono_w32socket_set_blocking (SOCKET socket, gboolean blocking)
1142 handle = GINT_TO_POINTER (socket);
1143 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1144 mono_w32socket_set_last_error (WSAENOTSOCK);
1145 return SOCKET_ERROR;
1148 /* This works better than ioctl(...FIONBIO...)
1149 * on Linux (it causes connect to return
1150 * EINPROGRESS, but the ioctl doesn't seem to) */
1151 ret = fcntl (socket, F_GETFL, 0);
1153 ret = fcntl (socket, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK)));
1156 gint errnum = errno;
1157 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno));
1158 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1159 return SOCKET_ERROR;
1164 mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED);
1165 return SOCKET_ERROR;
1166 #endif /* O_NONBLOCK */
1170 mono_w32socket_get_available (SOCKET socket, guint64 *amount)
1175 handle = GINT_TO_POINTER (socket);
1176 if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1177 mono_w32socket_set_last_error (WSAENOTSOCK);
1178 return SOCKET_ERROR;
1181 #if defined (PLATFORM_MACOSX)
1182 // ioctl (socket, FIONREAD, XXX) returns the size of
1183 // the UDP header as well on Darwin.
1185 // Use getsockopt SO_NREAD instead to get the
1186 // right values for TCP and UDP.
1188 // ai_canonname can be null in some cases on darwin,
1189 // where the runtime assumes it will be the value of
1192 socklen_t optlen = sizeof (int);
1193 ret = getsockopt (socket, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
1195 ret = ioctl (socket, FIONREAD, (gulong*) amount);
1199 gint errnum = errno;
1200 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno));
1201 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1202 return SOCKET_ERROR;
1209 mono_w32socket_set_last_error (gint32 error)
1211 mono_w32error_set_last (error);
1215 mono_w32socket_get_last_error (void)
1217 return mono_w32error_get_last ();
1221 mono_w32socket_convert_error (gint error)
1224 case 0: return ERROR_SUCCESS;
1225 case EACCES: return WSAEACCES;
1227 case EADDRINUSE: return WSAEADDRINUSE;
1230 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
1232 #if EAGAIN != EWOULDBLOCK
1233 case EAGAIN: return WSAEWOULDBLOCK;
1236 case EALREADY: return WSAEALREADY;
1238 case EBADF: return WSAENOTSOCK;
1240 case ECONNABORTED: return WSAENETDOWN;
1243 case ECONNREFUSED: return WSAECONNREFUSED;
1246 case ECONNRESET: return WSAECONNRESET;
1248 case EFAULT: return WSAEFAULT;
1250 case EHOSTUNREACH: return WSAEHOSTUNREACH;
1253 case EINPROGRESS: return WSAEINPROGRESS;
1255 case EINTR: return WSAEINTR;
1256 case EINVAL: return WSAEINVAL;
1257 /*FIXME: case EIO: return WSAE????; */
1259 case EISCONN: return WSAEISCONN;
1261 /* FIXME: case ELOOP: return WSA????; */
1262 case EMFILE: return WSAEMFILE;
1264 case EMSGSIZE: return WSAEMSGSIZE;
1266 /* FIXME: case ENAMETOOLONG: return WSAEACCES; */
1268 case ENETUNREACH: return WSAENETUNREACH;
1271 case ENOBUFS: return WSAENOBUFS; /* not documented */
1273 /* case ENOENT: return WSAE????; */
1274 case ENOMEM: return WSAENOBUFS;
1276 case ENOPROTOOPT: return WSAENOPROTOOPT;
1279 case ENOSR: return WSAENETDOWN;
1282 case ENOTCONN: return WSAENOTCONN;
1284 /*FIXME: case ENOTDIR: return WSAE????; */
1286 case ENOTSOCK: return WSAENOTSOCK;
1288 case ENOTTY: return WSAENOTSOCK;
1290 case EOPNOTSUPP: return WSAEOPNOTSUPP;
1292 case EPERM: return WSAEACCES;
1293 case EPIPE: return WSAESHUTDOWN;
1294 #ifdef EPROTONOSUPPORT
1295 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
1298 case ERESTARTSYS: return WSAENETDOWN;
1300 /*FIXME: case EROFS: return WSAE????; */
1301 #ifdef ESOCKTNOSUPPORT
1302 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
1305 case ETIMEDOUT: return WSAETIMEDOUT;
1308 case EWOULDBLOCK: return WSAEWOULDBLOCK;
1310 #ifdef EADDRNOTAVAIL
1311 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
1313 /* This might happen with unix sockets */
1314 case ENOENT: return WSAECONNREFUSED;
1316 case EDESTADDRREQ: return WSAEDESTADDRREQ;
1319 case EHOSTDOWN: return WSAEHOSTDOWN;
1322 case ENETDOWN: return WSAENETDOWN;
1324 case ENODEV: return WSAENETDOWN;
1326 case EPROTOTYPE: return WSAEPROTOTYPE;
1329 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
1334 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
1336 #if defined (SO_REUSEPORT)
1340 /* Linux always supports double binding for UDP, even on older kernels. */
1341 if (proto == ProtocolType_Udp)