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 #ifdef HAVE_NETINET_TCP_H
26 #include <arpa/inet.h>
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
39 #ifdef HAVE_SYS_FILIO_H
40 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
42 #ifdef HAVE_SYS_SOCKIO_H
43 #include <sys/sockio.h> /* defines SIOCATMARK */
45 #ifndef HAVE_MSG_NOSIGNAL
48 #ifdef HAVE_SYS_SENDFILE_H
49 #include <sys/sendfile.h>
53 #include "w32socket.h"
54 #include "w32socket-internals.h"
57 #include "utils/mono-logger-internals.h"
58 #include "utils/mono-poll.h"
59 #include "utils/mono-compiler.h"
60 #include "icall-decl.h"
61 #include "utils/mono-errno.h"
64 MonoFDHandle fdhandle
;
73 socket_data_create (MonoFDType type
, gint fd
)
75 SocketHandle
*sockethandle
;
77 sockethandle
= g_new0 (SocketHandle
, 1);
78 mono_fdhandle_init ((MonoFDHandle
*) sockethandle
, type
, fd
);
84 socket_data_close (MonoFDHandle
*fdhandle
)
87 SocketHandle
* sockethandle
;
90 sockethandle
= (SocketHandle
*) fdhandle
;
91 g_assert (sockethandle
);
93 info
= mono_thread_info_current ();
95 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: closing fd %d", __func__
, ((MonoFDHandle
*) sockethandle
)->fd
);
97 /* Shutdown the socket for reading, to interrupt any potential
98 * receives that may be blocking for data. See bug 75705. */
100 shutdown (((MonoFDHandle
*) sockethandle
)->fd
, SHUT_RD
);
105 ret
= close (((MonoFDHandle
*) sockethandle
)->fd
);
108 if (errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
))
112 sockethandle
->saved_error
= 0;
116 socket_data_destroy (MonoFDHandle
*fdhandle
)
118 SocketHandle
*sockethandle
;
120 sockethandle
= (SocketHandle
*) fdhandle
;
121 g_assert (sockethandle
);
123 g_free (sockethandle
);
127 mono_w32socket_initialize (void)
129 MonoFDHandleCallback socket_data_callbacks
;
130 memset (&socket_data_callbacks
, 0, sizeof (socket_data_callbacks
));
131 socket_data_callbacks
.close
= socket_data_close
;
132 socket_data_callbacks
.destroy
= socket_data_destroy
;
134 mono_fdhandle_register (MONO_FDTYPE_SOCKET
, &socket_data_callbacks
);
138 mono_w32socket_cleanup (void)
143 mono_w32socket_accept (SOCKET sock
, struct sockaddr
*addr
, socklen_t
*addrlen
, gboolean blocking
)
145 SocketHandle
*sockethandle
, *accepted_socket_data
;
146 MonoThreadInfo
*info
;
149 if (addr
!= NULL
&& *addrlen
< sizeof(struct sockaddr
)) {
150 mono_w32socket_set_last_error (WSAEFAULT
);
151 return INVALID_SOCKET
;
154 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
155 mono_w32error_set_last (WSAENOTSOCK
);
156 return INVALID_SOCKET
;
159 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
160 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
161 mono_w32error_set_last (WSAENOTSOCK
);
162 return INVALID_SOCKET
;
165 info
= mono_thread_info_current ();
169 accepted_fd
= accept (((MonoFDHandle
*) sockethandle
)->fd
, addr
, addrlen
);
171 } while (accepted_fd
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
173 if (accepted_fd
== -1) {
174 gint error
= mono_w32socket_convert_error (errno
);
175 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: accept error: %s", __func__
, g_strerror(errno
));
176 mono_w32socket_set_last_error (error
);
177 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
178 return INVALID_SOCKET
;
181 accepted_socket_data
= socket_data_create (MONO_FDTYPE_SOCKET
, accepted_fd
);
182 accepted_socket_data
->domain
= sockethandle
->domain
;
183 accepted_socket_data
->type
= sockethandle
->type
;
184 accepted_socket_data
->protocol
= sockethandle
->protocol
;
185 accepted_socket_data
->still_readable
= 1;
187 mono_fdhandle_insert ((MonoFDHandle
*) accepted_socket_data
);
189 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: returning accepted handle %p", __func__
, GINT_TO_POINTER(((MonoFDHandle
*) accepted_socket_data
)->fd
));
191 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
192 return ((MonoFDHandle
*) accepted_socket_data
)->fd
;
196 mono_w32socket_connect (SOCKET sock
, const struct sockaddr
*addr
, int addrlen
, gboolean blocking
)
198 SocketHandle
*sockethandle
;
201 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
202 mono_w32error_set_last (WSAENOTSOCK
);
206 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
207 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
208 mono_w32error_set_last (WSAENOTSOCK
);
213 ret
= connect (((MonoFDHandle
*) sockethandle
)->fd
, addr
, addrlen
);
216 MonoThreadInfo
*info
;
218 gint errnum
, so_error
;
223 if (errno
!= EINTR
) {
224 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: connect error: %s", __func__
,
225 g_strerror (errnum
));
227 errnum
= mono_w32socket_convert_error (errnum
);
228 if (errnum
== WSAEINPROGRESS
)
229 errnum
= WSAEWOULDBLOCK
; /* see bug #73053 */
231 mono_w32socket_set_last_error (errnum
);
234 * On solaris x86 getsockopt (SO_ERROR) is not set after
235 * connect () fails so we need to save this error.
237 * But don't do this for EWOULDBLOCK (bug 317315)
239 if (errnum
!= WSAEWOULDBLOCK
) {
240 /* ECONNRESET means the socket was closed by another thread */
241 /* Async close on mac raises ECONNABORTED. */
242 sockethandle
->saved_error
= errnum
;
244 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
248 info
= mono_thread_info_current ();
250 fds
.fd
= ((MonoFDHandle
*) sockethandle
)->fd
;
251 fds
.events
= MONO_POLLOUT
;
254 ret
= mono_poll (&fds
, 1, -1);
256 if (ret
!= -1 || mono_thread_info_is_interrupt_state (info
))
259 if (errno
!= EINTR
) {
261 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: connect poll error: %s", __func__
, g_strerror (errno
));
262 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
263 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
268 len
= sizeof(so_error
);
270 ret
= getsockopt (((MonoFDHandle
*) sockethandle
)->fd
, SOL_SOCKET
, SO_ERROR
, &so_error
, &len
);
274 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: connect getsockopt error: %s", __func__
, g_strerror (errno
));
275 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
276 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
281 gint errnum
= mono_w32socket_convert_error (so_error
);
283 /* Need to save this socket error */
284 sockethandle
->saved_error
= errnum
;
286 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: connect getsockopt returned error: %s",
287 __func__
, g_strerror (so_error
));
289 mono_w32socket_set_last_error (errnum
);
290 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
295 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
300 mono_w32socket_recv (SOCKET sock
, char *buf
, int len
, int flags
, gboolean blocking
)
302 return mono_w32socket_recvfrom (sock
, buf
, len
, flags
, NULL
, 0, blocking
);
306 mono_w32socket_recvfrom (SOCKET sock
, char *buf
, int len
, int flags
, struct sockaddr
*from
, socklen_t
*fromlen
, gboolean blocking
)
308 SocketHandle
*sockethandle
;
310 MonoThreadInfo
*info
;
312 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
313 mono_w32error_set_last (WSAENOTSOCK
);
317 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
318 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
319 mono_w32error_set_last (WSAENOTSOCK
);
323 info
= mono_thread_info_current ();
327 ret
= recvfrom (((MonoFDHandle
*) sockethandle
)->fd
, buf
, len
, flags
, from
, fromlen
);
329 } while (ret
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
331 if (ret
== 0 && len
> 0) {
332 /* According to the Linux man page, recvfrom only
333 * returns 0 when the socket has been shut down
334 * cleanly. Turn this into an EINTR to simulate win32
335 * behaviour of returning EINTR when a socket is
336 * closed while the recvfrom is blocking (we use a
337 * shutdown() in socket_close() to trigger this.) See
340 /* Distinguish between the socket being shut down at
341 * the local or remote ends, and reads that request 0
345 /* If this returns FALSE, it means the socket has been
346 * closed locally. If it returns TRUE, but
347 * still_readable != 1 then shutdown
348 * (SHUT_RD|SHUT_RDWR) has been called locally.
350 if (sockethandle
->still_readable
!= 1) {
352 mono_set_errno (EINTR
);
358 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: recv error: %s", __func__
, g_strerror(errno
));
359 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
360 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
363 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
368 wsabuf_to_msghdr (WSABUF
*buffers
, guint32 count
, struct msghdr
*hdr
)
372 memset (hdr
, 0, sizeof (struct msghdr
));
373 hdr
->msg_iovlen
= count
;
374 hdr
->msg_iov
= g_new0 (struct iovec
, count
);
375 for (i
= 0; i
< count
; i
++) {
376 hdr
->msg_iov
[i
].iov_base
= buffers
[i
].buf
;
377 hdr
->msg_iov
[i
].iov_len
= buffers
[i
].len
;
382 msghdr_iov_free (struct msghdr
*hdr
)
384 g_free (hdr
->msg_iov
);
388 mono_w32socket_recvbuffers (SOCKET sock
, WSABUF
*buffers
, guint32 count
, guint32
*received
, guint32
*flags
, gpointer overlapped
, gpointer complete
, gboolean blocking
)
390 SocketHandle
*sockethandle
;
391 MonoThreadInfo
*info
;
395 g_assert (overlapped
== NULL
);
396 g_assert (complete
== NULL
);
398 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
399 mono_w32error_set_last (WSAENOTSOCK
);
403 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
404 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
405 mono_w32error_set_last (WSAENOTSOCK
);
409 info
= mono_thread_info_current ();
411 wsabuf_to_msghdr (buffers
, count
, &hdr
);
415 ret
= recvmsg (((MonoFDHandle
*) sockethandle
)->fd
, &hdr
, *flags
);
417 } while (ret
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
419 msghdr_iov_free (&hdr
);
422 /* see mono_w32socket_recvfrom */
423 if (sockethandle
->still_readable
!= 1) {
425 mono_set_errno (EINTR
);
431 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: recvmsg error: %s", __func__
, g_strerror(errno
));
432 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
433 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
438 *flags
= hdr
.msg_flags
;
440 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
445 mono_w32socket_send (SOCKET sock
, void *buf
, int len
, int flags
, gboolean blocking
)
447 SocketHandle
*sockethandle
;
449 MonoThreadInfo
*info
;
451 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
452 mono_w32error_set_last (WSAENOTSOCK
);
456 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
457 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
458 mono_w32error_set_last (WSAENOTSOCK
);
462 info
= mono_thread_info_current ();
466 ret
= send (((MonoFDHandle
*) sockethandle
)->fd
, buf
, len
, flags
);
468 } while (ret
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
472 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: send error: %s", __func__
, g_strerror (errno
));
475 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
476 * a blocking socket. See bug #599488 */
477 if (errnum
== EAGAIN
) {
479 ret
= fcntl (((MonoFDHandle
*) sockethandle
)->fd
, F_GETFL
, 0);
481 if (ret
!= -1 && (ret
& O_NONBLOCK
) == 0)
484 #endif /* O_NONBLOCK */
485 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
486 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
489 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
494 mono_w32socket_sendto (SOCKET sock
, const char *buf
, int len
, int flags
, const struct sockaddr
*to
, int tolen
, gboolean blocking
)
496 SocketHandle
*sockethandle
;
498 MonoThreadInfo
*info
;
500 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
501 mono_w32error_set_last (WSAENOTSOCK
);
505 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
506 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
507 mono_w32error_set_last (WSAENOTSOCK
);
511 info
= mono_thread_info_current ();
515 ret
= sendto (((MonoFDHandle
*) sockethandle
)->fd
, buf
, len
, flags
, to
, tolen
);
517 } while (ret
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
521 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: send error: %s", __func__
, g_strerror (errno
));
522 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
523 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
526 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
531 mono_w32socket_sendbuffers (SOCKET sock
, WSABUF
*buffers
, guint32 count
, guint32
*sent
, guint32 flags
, gpointer overlapped
, gpointer complete
, gboolean blocking
)
534 MonoThreadInfo
*info
;
535 SocketHandle
*sockethandle
;
538 g_assert (overlapped
== NULL
);
539 g_assert (complete
== NULL
);
541 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
542 mono_w32error_set_last (WSAENOTSOCK
);
546 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
547 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
548 mono_w32error_set_last (WSAENOTSOCK
);
552 info
= mono_thread_info_current ();
554 wsabuf_to_msghdr (buffers
, count
, &hdr
);
558 ret
= sendmsg (((MonoFDHandle
*) sockethandle
)->fd
, &hdr
, flags
);
560 } while (ret
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
562 msghdr_iov_free (&hdr
);
566 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: sendmsg error: %s", __func__
, g_strerror (errno
));
567 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
568 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
573 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
577 #define SF_BUFFER_SIZE 16384
580 mono_w32socket_transmit_file (SOCKET sock
, gpointer file_handle
, TRANSMIT_FILE_BUFFERS
*buffers
, guint32 flags
, gboolean blocking
)
582 MonoThreadInfo
*info
;
583 SocketHandle
*sockethandle
;
586 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
592 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
593 mono_w32error_set_last (WSAENOTSOCK
);
597 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
598 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
599 mono_w32error_set_last (WSAENOTSOCK
);
603 /* Write the header */
604 if (buffers
!= NULL
&& buffers
->Head
!= NULL
&& buffers
->HeadLength
> 0) {
605 ret
= mono_w32socket_send (((MonoFDHandle
*) sockethandle
)->fd
, buffers
->Head
, buffers
->HeadLength
, 0, FALSE
);
606 if (ret
== SOCKET_ERROR
) {
607 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
612 info
= mono_thread_info_current ();
614 file
= GPOINTER_TO_INT (file_handle
);
616 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
618 ret
= fstat (file
, &statbuf
);
622 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
623 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
630 ret
= sendfile (((MonoFDHandle
*) sockethandle
)->fd
, file
, NULL
, statbuf
.st_size
);
631 #elif defined(DARWIN)
632 /* TODO: header/tail could be sent in the 5th argument */
633 /* TODO: Might not send the entire file for non-blocking sockets */
634 ret
= sendfile (file
, ((MonoFDHandle
*) sockethandle
)->fd
, 0, &statbuf
.st_size
, NULL
, 0);
637 } while (ret
!= -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
639 buffer
= g_malloc (SF_BUFFER_SIZE
);
644 ret
= read (file
, buffer
, SF_BUFFER_SIZE
);
646 } while (ret
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
648 if (ret
== -1 || ret
== 0)
653 ret
= send (((MonoFDHandle
*) sockethandle
)->fd
, buffer
, ret
, 0); /* short sends? enclose this in a loop? */
655 } while (ret
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
656 } while (ret
!= -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
663 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
664 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
669 if (buffers
!= NULL
&& buffers
->Tail
!= NULL
&& buffers
->TailLength
> 0) {
670 ret
= mono_w32socket_send (((MonoFDHandle
*) sockethandle
)->fd
, buffers
->Tail
, buffers
->TailLength
, 0, FALSE
);
671 if (ret
== SOCKET_ERROR
) {
672 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
677 if ((flags
& TF_DISCONNECT
) == TF_DISCONNECT
)
678 mono_w32socket_close (((MonoFDHandle
*) sockethandle
)->fd
);
680 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
685 mono_w32socket_socket (int domain
, int type
, int protocol
)
687 SocketHandle
*sockethandle
;
692 fd
= socket (domain
, type
, protocol
);
695 if (domain
== AF_INET
&& type
== SOCK_RAW
&& protocol
== 0) {
696 /* Retry with protocol == 4 (see bug #54565) */
697 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
703 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: socket error: %s", __func__
, g_strerror (errno
));
704 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
705 return INVALID_SOCKET
;
708 sockethandle
= socket_data_create(MONO_FDTYPE_SOCKET
, fd
);
709 sockethandle
->domain
= domain
;
710 sockethandle
->type
= type
;
711 sockethandle
->protocol
= protocol
;
712 sockethandle
->still_readable
= 1;
714 /* .net seems to set this by default for SOCK_STREAM, not for
715 * SOCK_DGRAM (see bug #36322)
716 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
718 * It seems winsock has a rather different idea of what
719 * SO_REUSEADDR means. If it's set, then a new socket can be
720 * bound over an existing listening socket. There's a new
721 * windows-specific option called SO_EXCLUSIVEADDRUSE but
722 * using that means the socket MUST be closed properly, or a
723 * denial of service can occur. Luckily for us, winsock
724 * behaves as though any other system would when SO_REUSEADDR
725 * is true, so we don't need to do anything else here. See
727 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
734 ret
= setsockopt (((MonoFDHandle
*) sockethandle
)->fd
, SOL_SOCKET
, SO_REUSEADDR
, &true_
, sizeof (true_
));
738 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: Error setting SO_REUSEADDR", __func__
);
739 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
742 close (((MonoFDHandle
*) sockethandle
)->fd
);
745 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
746 return INVALID_SOCKET
;
750 mono_fdhandle_insert ((MonoFDHandle
*) sockethandle
);
752 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: returning socket handle %p", __func__
, GINT_TO_POINTER(((MonoFDHandle
*) sockethandle
)->fd
));
754 return ((MonoFDHandle
*) sockethandle
)->fd
;
758 mono_w32socket_bind (SOCKET sock
, struct sockaddr
*addr
, socklen_t addrlen
)
760 SocketHandle
*sockethandle
;
763 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
764 mono_w32error_set_last (WSAENOTSOCK
);
768 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
769 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
770 mono_w32error_set_last (WSAENOTSOCK
);
775 ret
= bind (((MonoFDHandle
*) sockethandle
)->fd
, addr
, addrlen
);
779 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: bind error: %s", __func__
, g_strerror(errno
));
780 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
781 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
785 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
790 mono_w32socket_getpeername (SOCKET sock
, struct sockaddr
*name
, socklen_t
*namelen
)
792 SocketHandle
*sockethandle
;
795 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
796 mono_w32error_set_last (WSAENOTSOCK
);
800 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
801 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
802 mono_w32error_set_last (WSAENOTSOCK
);
806 #ifdef HAVE_GETPEERNAME
808 ret
= getpeername (((MonoFDHandle
*) sockethandle
)->fd
, name
, namelen
);
815 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: getpeername error: %s", __func__
, g_strerror (errno
));
816 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
817 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
821 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
826 mono_w32socket_getsockname (SOCKET sock
, struct sockaddr
*name
, socklen_t
*namelen
)
828 SocketHandle
*sockethandle
;
831 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
832 mono_w32error_set_last (WSAENOTSOCK
);
836 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
837 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
838 mono_w32error_set_last (WSAENOTSOCK
);
843 ret
= getsockname (((MonoFDHandle
*) sockethandle
)->fd
, name
, namelen
);
847 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: getsockname error: %s", __func__
, g_strerror (errno
));
848 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
849 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
853 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
858 mono_w32socket_getsockopt (SOCKET sock
, gint level
, gint optname
, gpointer optval
, socklen_t
*optlen
)
860 SocketHandle
*sockethandle
;
865 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
866 mono_w32error_set_last (WSAENOTSOCK
);
870 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
871 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
872 mono_w32error_set_last (WSAENOTSOCK
);
877 if (level
== SOL_SOCKET
&&
878 (optname
== SO_RCVTIMEO
|| optname
== SO_SNDTIMEO
)) {
880 *optlen
= sizeof (tv
);
884 ret
= getsockopt (((MonoFDHandle
*) sockethandle
)->fd
, level
, optname
, tmp_val
, optlen
);
888 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: getsockopt error: %s", __func__
, g_strerror (errno
));
889 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
890 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
894 if (level
== SOL_SOCKET
&& (optname
== SO_RCVTIMEO
|| optname
== SO_SNDTIMEO
)) {
895 *((int *) optval
) = tv
.tv_sec
* 1000 + (tv
.tv_usec
/ 1000); // milli from micro
896 *optlen
= sizeof (int);
899 if (optname
== SO_ERROR
) {
900 if (*((int *)optval
) != 0) {
901 *((int *) optval
) = mono_w32socket_convert_error (*((int *)optval
));
902 sockethandle
->saved_error
= *((int *)optval
);
904 *((int *)optval
) = sockethandle
->saved_error
;
908 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
913 mono_w32socket_setsockopt (SOCKET sock
, gint level
, gint optname
, gconstpointer optval
, socklen_t optlen
)
915 SocketHandle
*sockethandle
;
917 gconstpointer tmp_val
;
918 #if defined (__linux__)
919 /* This has its address taken so it cannot be moved to the if block which uses it */
924 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
925 mono_w32error_set_last (WSAENOTSOCK
);
929 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
930 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
931 mono_w32error_set_last (WSAENOTSOCK
);
936 if (level
== SOL_SOCKET
&&
937 (optname
== SO_RCVTIMEO
|| optname
== SO_SNDTIMEO
)) {
938 int ms
= *((int *) optval
);
939 tv
.tv_sec
= ms
/ 1000;
940 tv
.tv_usec
= (ms
% 1000) * 1000; // micro from milli
942 optlen
= sizeof (tv
);
944 #if defined (__linux__)
945 else if (level
== SOL_SOCKET
&&
946 (optname
== SO_SNDBUF
|| optname
== SO_RCVBUF
)) {
947 /* According to socket(7) the Linux kernel doubles the
948 * buffer sizes "to allow space for bookkeeping
951 bufsize
= *((int *) optval
);
959 ret
= setsockopt (((MonoFDHandle
*) sockethandle
)->fd
, level
, optname
, tmp_val
, optlen
);
963 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: setsockopt error: %s", __func__
, g_strerror (errno
));
964 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
965 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
969 #if defined (SO_REUSEPORT)
970 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
971 if (level
== SOL_SOCKET
&& optname
== SO_REUSEADDR
) {
973 socklen_t type_len
= sizeof (type
);
976 ret
= getsockopt (((MonoFDHandle
*) sockethandle
)->fd
, level
, SO_TYPE
, &type
, &type_len
);
979 if (type
== SOCK_DGRAM
|| type
== SOCK_STREAM
) {
981 setsockopt (((MonoFDHandle
*) sockethandle
)->fd
, level
, SO_REUSEPORT
, tmp_val
, optlen
);
988 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
993 mono_w32socket_listen (SOCKET sock
, gint backlog
)
995 SocketHandle
*sockethandle
;
998 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
999 mono_w32error_set_last (WSAENOTSOCK
);
1000 return SOCKET_ERROR
;
1003 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
1004 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1005 mono_w32error_set_last (WSAENOTSOCK
);
1006 return SOCKET_ERROR
;
1010 ret
= listen (((MonoFDHandle
*) sockethandle
)->fd
, backlog
);
1013 gint errnum
= errno
;
1014 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: listen error: %s", __func__
, g_strerror (errno
));
1015 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
1016 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1017 return SOCKET_ERROR
;
1020 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1025 mono_w32socket_shutdown (SOCKET sock
, gint how
)
1027 SocketHandle
*sockethandle
;
1030 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
1031 mono_w32error_set_last (WSAENOTSOCK
);
1032 return SOCKET_ERROR
;
1035 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
1036 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1037 mono_w32error_set_last (WSAENOTSOCK
);
1038 return SOCKET_ERROR
;
1041 if (how
== SHUT_RD
|| how
== SHUT_RDWR
)
1042 sockethandle
->still_readable
= 0;
1045 ret
= shutdown (((MonoFDHandle
*) sockethandle
)->fd
, how
);
1048 gint errnum
= errno
;
1049 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: shutdown error: %s", __func__
, g_strerror (errno
));
1050 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
1051 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1052 return SOCKET_ERROR
;
1055 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1060 mono_w32socket_disconnect (SOCKET sock
, gboolean reuse
)
1062 SocketHandle
*sockethandle
;
1066 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: called on socket %d!", __func__
, sock
);
1068 /* We could check the socket type here and fail unless its
1069 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
1070 * if we really wanted to */
1072 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
1073 mono_w32error_set_last (WSAENOTSOCK
);
1074 return SOCKET_ERROR
;
1077 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
1078 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1079 mono_w32error_set_last (WSAENOTSOCK
);
1080 return SOCKET_ERROR
;
1084 newsock
= socket (sockethandle
->domain
, sockethandle
->type
, sockethandle
->protocol
);
1086 if (newsock
== -1) {
1087 gint errnum
= errno
;
1088 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: socket error: %s", __func__
, g_strerror (errnum
));
1089 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
1090 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1091 return SOCKET_ERROR
;
1094 /* According to Stevens "Advanced Programming in the UNIX
1095 * Environment: UNIX File I/O" dup2() is atomic so there
1096 * should not be a race condition between the old fd being
1097 * closed and the new socket fd being copied over */
1100 ret
= dup2 (newsock
, ((MonoFDHandle
*) sockethandle
)->fd
);
1102 } while (ret
== -1 && errno
== EAGAIN
);
1105 gint errnum
= errno
;
1106 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: dup2 error: %s", __func__
, g_strerror (errnum
));
1107 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
1108 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1109 return SOCKET_ERROR
;
1116 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1121 extension_disconect (SOCKET sock
, OVERLAPPED
*overlapped
, guint32 flags
, guint32 reserved
)
1124 MONO_ENTER_GC_UNSAFE
;
1125 ret
= mono_w32socket_disconnect (sock
, flags
& TF_REUSE_SOCKET
) == 0;
1126 MONO_EXIT_GC_UNSAFE
;
1131 extension_transmit_file (SOCKET sock
, gpointer file_handle
, guint32 bytes_to_write
, guint32 bytes_per_send
,
1132 OVERLAPPED
*ol
, TRANSMIT_FILE_BUFFERS
*buffers
, guint32 flags
)
1135 MONO_ENTER_GC_UNSAFE
;
1136 ret
= mono_w32socket_transmit_file (sock
, file_handle
, buffers
, flags
, FALSE
);
1137 MONO_EXIT_GC_UNSAFE
;
1145 } extension_functions
[] = {
1146 { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, (gpointer
)extension_disconect
},
1147 { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, (gpointer
)extension_transmit_file
},
1152 mono_w32socket_ioctl (SOCKET sock
, gint32 command
, gchar
*input
, gint inputlen
, gchar
*output
, gint outputlen
, glong
*written
)
1154 SocketHandle
*sockethandle
;
1158 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
1159 mono_w32error_set_last (WSAENOTSOCK
);
1160 return SOCKET_ERROR
;
1163 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
1164 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1165 mono_w32error_set_last (WSAENOTSOCK
);
1166 return SOCKET_ERROR
;
1169 if (command
== 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1173 if (inputlen
< sizeof(GUID
)) {
1174 /* As far as I can tell, windows doesn't
1175 * actually set an error here...
1177 mono_w32socket_set_last_error (WSAEINVAL
);
1178 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1179 return SOCKET_ERROR
;
1182 if (outputlen
< sizeof(gpointer
)) {
1184 mono_w32socket_set_last_error (WSAEINVAL
);
1185 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1186 return SOCKET_ERROR
;
1189 if (output
== NULL
) {
1191 mono_w32socket_set_last_error (WSAEINVAL
);
1192 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1193 return SOCKET_ERROR
;
1196 guid
= (GUID
*) input
;
1197 for (i
= 0; extension_functions
[i
].func
; i
++) {
1198 if (memcmp (guid
, &extension_functions
[i
].guid
, sizeof(GUID
)) == 0) {
1199 memcpy (output
, &extension_functions
[i
].func
, sizeof(gpointer
));
1200 *written
= sizeof(gpointer
);
1201 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1206 mono_w32socket_set_last_error (WSAEINVAL
);
1207 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1208 return SOCKET_ERROR
;
1211 if (command
== 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1214 if (inputlen
< 3 * sizeof (guint32
)) {
1215 mono_w32socket_set_last_error (WSAEINVAL
);
1216 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1217 return SOCKET_ERROR
;
1220 onoff
= *((guint32
*) input
);
1223 ret
= setsockopt (((MonoFDHandle
*) sockethandle
)->fd
, SOL_SOCKET
, SO_KEEPALIVE
, &onoff
, sizeof (guint32
));
1226 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno
));
1227 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1228 return SOCKET_ERROR
;
1231 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1233 /* Values are in ms, but we need s */
1234 guint32 keepalivetime
, keepaliveinterval
, rem
;
1236 keepalivetime
= *(((guint32
*) input
) + 1);
1237 keepaliveinterval
= *(((guint32
*) input
) + 2);
1239 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1240 rem
= keepalivetime
% 1000;
1241 keepalivetime
/= 1000;
1242 if (keepalivetime
== 0 || rem
>= 500)
1245 ret
= setsockopt (((MonoFDHandle
*) sockethandle
)->fd
, IPPROTO_TCP
, TCP_KEEPIDLE
, &keepalivetime
, sizeof (guint32
));
1248 rem
= keepaliveinterval
% 1000;
1249 keepaliveinterval
/= 1000;
1250 if (keepaliveinterval
== 0 || rem
>= 500)
1251 keepaliveinterval
++;
1253 ret
= setsockopt (((MonoFDHandle
*) sockethandle
)->fd
, IPPROTO_TCP
, TCP_KEEPINTVL
, &keepaliveinterval
, sizeof (guint32
));
1257 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno
));
1258 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1259 return SOCKET_ERROR
;
1262 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1267 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1271 buffer
= inputlen
> 0 ? (gchar
*) g_memdup (input
, inputlen
) : NULL
;
1274 ret
= ioctl (((MonoFDHandle
*) sockethandle
)->fd
, command
, buffer
);
1279 gint errnum
= errno
;
1280 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: WSAIoctl error: %s", __func__
, g_strerror (errno
));
1281 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum
));
1282 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1283 return SOCKET_ERROR
;
1288 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1292 /* We just copy the buffer to the output. Some ioctls
1293 * don't even output any data, but, well...
1295 * NB windows returns WSAEFAULT if outputlen is too small */
1296 inputlen
= (inputlen
> outputlen
) ? outputlen
: inputlen
;
1298 if (inputlen
> 0 && output
!= NULL
)
1299 memcpy (output
, buffer
, inputlen
);
1302 *written
= inputlen
;
1304 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1309 mono_w32socket_close (SOCKET sock
)
1311 if (!mono_fdhandle_close (sock
)) {
1312 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
1320 mono_w32socket_set_blocking (SOCKET sock
, gboolean blocking
)
1323 SocketHandle
*sockethandle
;
1326 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
1327 mono_w32error_set_last (WSAENOTSOCK
);
1328 return SOCKET_ERROR
;
1331 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
1332 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1333 mono_w32error_set_last (WSAENOTSOCK
);
1334 return SOCKET_ERROR
;
1337 /* This works better than ioctl(...FIONBIO...)
1338 * on Linux (it causes connect to return
1339 * EINPROGRESS, but the ioctl doesn't seem to) */
1341 ret
= fcntl (((MonoFDHandle
*) sockethandle
)->fd
, F_GETFL
, 0);
1344 gint errnum
= mono_w32socket_convert_error (errno
);
1345 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: fcntl(F_GETFL) error: %s", __func__
, g_strerror (errno
));
1346 mono_w32socket_set_last_error (errnum
);
1347 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1348 return SOCKET_ERROR
;
1352 ret
= fcntl (((MonoFDHandle
*) sockethandle
)->fd
, F_SETFL
, blocking
? (ret
& (~O_NONBLOCK
)) : (ret
| (O_NONBLOCK
)));
1355 gint errnum
= mono_w32socket_convert_error (errno
);
1356 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: fcntl(F_SETFL) error: %s", __func__
, g_strerror (errno
));
1357 mono_w32socket_set_last_error (errnum
);
1358 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1359 return SOCKET_ERROR
;
1362 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1365 mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED
);
1366 return SOCKET_ERROR
;
1367 #endif /* O_NONBLOCK */
1371 mono_w32socket_get_available (SOCKET sock
, guint64
*amount
)
1373 SocketHandle
*sockethandle
;
1376 if (!mono_fdhandle_lookup_and_ref(sock
, (MonoFDHandle
**) &sockethandle
)) {
1377 mono_w32error_set_last (WSAENOTSOCK
);
1378 return SOCKET_ERROR
;
1381 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
1382 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1383 mono_w32error_set_last (WSAENOTSOCK
);
1384 return SOCKET_ERROR
;
1387 #if defined (HOST_DARWIN)
1388 // ioctl (socket, FIONREAD, XXX) returns the size of
1389 // the UDP header as well on Darwin.
1391 // Use getsockopt SO_NREAD instead to get the
1392 // right values for TCP and UDP.
1394 // ai_canonname can be null in some cases on darwin,
1395 // where the runtime assumes it will be the value of
1398 socklen_t optlen
= sizeof (int);
1400 ret
= getsockopt (((MonoFDHandle
*) sockethandle
)->fd
, SOL_SOCKET
, SO_NREAD
, (gulong
*) amount
, &optlen
);
1403 gint errnum
= mono_w32socket_convert_error (errno
);
1404 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: getsockopt error: %s", __func__
, g_strerror (errno
));
1405 mono_w32socket_set_last_error (errnum
);
1406 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1407 return SOCKET_ERROR
;
1411 ret
= ioctl (((MonoFDHandle
*) sockethandle
)->fd
, FIONREAD
, (gulong
*) amount
);
1414 gint errnum
= mono_w32socket_convert_error (errno
);
1415 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER_SOCKET
, "%s: ioctl error: %s", __func__
, g_strerror (errno
));
1416 mono_w32socket_set_last_error (errnum
);
1417 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1418 return SOCKET_ERROR
;
1422 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1427 mono_w32socket_set_last_error (gint32 error
)
1429 mono_w32error_set_last (error
);
1433 mono_w32socket_get_last_error (void)
1435 return mono_w32error_get_last ();
1439 mono_w32socket_convert_error (gint error
)
1442 case 0: return ERROR_SUCCESS
;
1443 case EACCES
: return WSAEACCES
;
1445 case EADDRINUSE
: return WSAEADDRINUSE
;
1448 case EAFNOSUPPORT
: return WSAEAFNOSUPPORT
;
1450 #if EAGAIN != EWOULDBLOCK
1451 case EAGAIN
: return WSAEWOULDBLOCK
;
1454 case EALREADY
: return WSAEALREADY
;
1456 case EBADF
: return WSAENOTSOCK
;
1458 case ECONNABORTED
: return WSAENETDOWN
;
1461 case ECONNREFUSED
: return WSAECONNREFUSED
;
1464 case ECONNRESET
: return WSAECONNRESET
;
1466 case EFAULT
: return WSAEFAULT
;
1468 case EHOSTUNREACH
: return WSAEHOSTUNREACH
;
1471 case EINPROGRESS
: return WSAEINPROGRESS
;
1473 case EINTR
: return WSAEINTR
;
1474 case EINVAL
: return WSAEINVAL
;
1475 /*FIXME: case EIO: return WSAE????; */
1477 case EISCONN
: return WSAEISCONN
;
1479 /* FIXME: case ELOOP: return WSA????; */
1480 case EMFILE
: return WSAEMFILE
;
1482 case EMSGSIZE
: return WSAEMSGSIZE
;
1484 /* FIXME: case ENAMETOOLONG: return WSAEACCES; */
1486 case ENETUNREACH
: return WSAENETUNREACH
;
1489 case ENOBUFS
: return WSAENOBUFS
; /* not documented */
1491 /* case ENOENT: return WSAE????; */
1492 case ENOMEM
: return WSAENOBUFS
;
1494 case ENOPROTOOPT
: return WSAENOPROTOOPT
;
1497 case ENOSR
: return WSAENETDOWN
;
1500 case ENOTCONN
: return WSAENOTCONN
;
1502 /*FIXME: case ENOTDIR: return WSAE????; */
1504 case ENOTSOCK
: return WSAENOTSOCK
;
1506 case ENOTTY
: return WSAENOTSOCK
;
1508 case EOPNOTSUPP
: return WSAEOPNOTSUPP
;
1510 case EPERM
: return WSAEACCES
;
1511 case EPIPE
: return WSAESHUTDOWN
;
1512 #ifdef EPROTONOSUPPORT
1513 case EPROTONOSUPPORT
: return WSAEPROTONOSUPPORT
;
1516 case ERESTARTSYS
: return WSAENETDOWN
;
1518 /*FIXME: case EROFS: return WSAE????; */
1519 #ifdef ESOCKTNOSUPPORT
1520 case ESOCKTNOSUPPORT
: return WSAESOCKTNOSUPPORT
;
1523 case ETIMEDOUT
: return WSAETIMEDOUT
;
1526 case EWOULDBLOCK
: return WSAEWOULDBLOCK
;
1528 #ifdef EADDRNOTAVAIL
1529 case EADDRNOTAVAIL
: return WSAEADDRNOTAVAIL
;
1531 /* This might happen with unix sockets */
1532 case ENOENT
: return WSAECONNREFUSED
;
1534 case EDESTADDRREQ
: return WSAEDESTADDRREQ
;
1537 case EHOSTDOWN
: return WSAEHOSTDOWN
;
1540 case ENETDOWN
: return WSAENETDOWN
;
1542 case ENODEV
: return WSAENETDOWN
;
1544 case EPROTOTYPE
: return WSAEPROTOTYPE
;
1547 case ENXIO
: return WSAENXIO
;
1550 case ENONET
: return WSAENETUNREACH
;
1553 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__
, error
, g_strerror (error
));
1558 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto
, MonoError
*error
)
1561 #if defined (SO_REUSEPORT)
1565 /* Linux always supports double binding for UDP, even on older kernels. */
1566 if (proto
== ProtocolType_Udp
)
1574 mono_w32socket_duplicate (gpointer handle
, gint32 targetProcessId
, gpointer
*duplicate_handle
)
1576 SocketHandle
*sockethandle
;
1578 if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle
), (MonoFDHandle
**) &sockethandle
)) {
1579 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
1583 if (((MonoFDHandle
*) sockethandle
)->type
!= MONO_FDTYPE_SOCKET
) {
1584 mono_fdhandle_unref ((MonoFDHandle
*) sockethandle
);
1585 mono_w32error_set_last (ERROR_INVALID_HANDLE
);
1589 *duplicate_handle
= handle
;