2 * sockets.c: Socket handles
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
12 #ifndef DISABLE_SOCKETS
18 #include <sys/types.h>
19 #include <sys/socket.h>
23 #ifdef HAVE_SYS_IOCTL_H
24 # include <sys/ioctl.h>
26 #ifdef HAVE_SYS_FILIO_H
27 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
29 #ifdef HAVE_SYS_SOCKIO_H
30 #include <sys/sockio.h> /* defines SIOCATMARK */
35 #ifndef HAVE_MSG_NOSIGNAL
39 #include <mono/io-layer/wapi.h>
40 #include <mono/io-layer/wapi-private.h>
41 #include <mono/io-layer/socket-private.h>
42 #include <mono/io-layer/socket-wrappers.h>
43 #include <mono/io-layer/io-trace.h>
44 #include <mono/utils/mono-poll.h>
45 #include <mono/utils/mono-once.h>
46 #include <mono/utils/mono-logger-internals.h>
47 #include <mono/metadata/w32handle.h>
49 #include <netinet/in.h>
50 #include <netinet/tcp.h>
51 #include <arpa/inet.h>
52 #ifdef HAVE_SYS_SENDFILE_H
53 #include <sys/sendfile.h>
59 static guint32 in_cleanup
= 0;
61 static void socket_close (gpointer handle
, gpointer data
);
62 static void socket_details (gpointer data
);
63 static const gchar
* socket_typename (void);
64 static gsize
socket_typesize (void);
66 static MonoW32HandleOps _wapi_socket_ops
= {
67 socket_close
, /* close */
71 NULL
, /* special_wait */
73 socket_details
, /* details */
74 socket_typename
, /* typename */
75 socket_typesize
, /* typesize */
79 _wapi_socket_init (void)
81 mono_w32handle_register_ops (MONO_W32HANDLE_SOCKET
, &_wapi_socket_ops
);
84 static void socket_close (gpointer handle
, gpointer data
)
87 struct _WapiHandle_socket
*socket_handle
= (struct _WapiHandle_socket
*)data
;
88 MonoThreadInfo
*info
= mono_thread_info_current ();
90 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: closing socket handle %p", __func__
, handle
);
92 /* Shutdown the socket for reading, to interrupt any potential
93 * receives that may be blocking for data. See bug 75705.
95 shutdown (GPOINTER_TO_UINT (handle
), SHUT_RD
);
98 ret
= close (GPOINTER_TO_UINT(handle
));
99 } while (ret
== -1 && errno
== EINTR
&&
100 !mono_thread_info_is_interrupt_state (info
));
104 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: close error: %s", __func__
, strerror (errno
));
105 errnum
= errno_to_WSA (errnum
, __func__
);
107 WSASetLastError (errnum
);
111 socket_handle
->saved_error
= 0;
114 static void socket_details (gpointer data
)
116 /* FIXME: do something */
119 static const gchar
* socket_typename (void)
124 static gsize
socket_typesize (void)
126 return sizeof (struct _WapiHandle_socket
);
130 cleanup_close (gpointer handle
, gpointer data
, gpointer user_data
)
132 if (mono_w32handle_get_type (handle
) == MONO_W32HANDLE_SOCKET
)
133 mono_w32handle_force_close (handle
, data
);
138 void _wapi_cleanup_networking(void)
140 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: cleaning up", __func__
);
143 mono_w32handle_foreach (cleanup_close
, NULL
);
147 void WSASetLastError(int error
)
149 SetLastError (error
);
152 int WSAGetLastError(void)
154 return(GetLastError ());
157 int closesocket(guint32 fd
)
159 gpointer handle
= GUINT_TO_POINTER (fd
);
161 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
162 WSASetLastError (WSAENOTSOCK
);
166 mono_w32handle_unref (handle
);
170 guint32
_wapi_accept(guint32 fd
, struct sockaddr
*addr
, socklen_t
*addrlen
)
172 gpointer handle
= GUINT_TO_POINTER (fd
);
174 struct _WapiHandle_socket
*socket_handle
;
175 struct _WapiHandle_socket new_socket_handle
= {0};
178 MonoThreadInfo
*info
= mono_thread_info_current ();
180 if (addr
!= NULL
&& *addrlen
< sizeof(struct sockaddr
)) {
181 WSASetLastError (WSAEFAULT
);
182 return(INVALID_SOCKET
);
185 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
186 WSASetLastError (WSAENOTSOCK
);
187 return(INVALID_SOCKET
);
190 ok
= mono_w32handle_lookup (handle
, MONO_W32HANDLE_SOCKET
,
191 (gpointer
*)&socket_handle
);
193 g_warning ("%s: error looking up socket handle %p",
195 WSASetLastError (WSAENOTSOCK
);
196 return(INVALID_SOCKET
);
200 new_fd
= accept (fd
, addr
, addrlen
);
201 } while (new_fd
== -1 && errno
== EINTR
&&
202 !mono_thread_info_is_interrupt_state (info
));
206 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: accept error: %s", __func__
, strerror(errno
));
208 errnum
= errno_to_WSA (errnum
, __func__
);
209 WSASetLastError (errnum
);
211 return(INVALID_SOCKET
);
214 if (new_fd
>= mono_w32handle_fd_reserve
) {
215 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: File descriptor is too big", __func__
);
217 WSASetLastError (WSASYSCALLFAILURE
);
221 return(INVALID_SOCKET
);
224 new_socket_handle
.domain
= socket_handle
->domain
;
225 new_socket_handle
.type
= socket_handle
->type
;
226 new_socket_handle
.protocol
= socket_handle
->protocol
;
227 new_socket_handle
.still_readable
= 1;
229 new_handle
= mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET
, new_fd
,
231 if(new_handle
== INVALID_HANDLE_VALUE
) {
232 g_warning ("%s: error creating socket handle", __func__
);
233 WSASetLastError (ERROR_GEN_FAILURE
);
234 return(INVALID_SOCKET
);
237 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: returning newly accepted socket handle %p with",
238 __func__
, new_handle
);
243 int _wapi_bind(guint32 fd
, struct sockaddr
*my_addr
, socklen_t addrlen
)
245 gpointer handle
= GUINT_TO_POINTER (fd
);
248 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
249 WSASetLastError (WSAENOTSOCK
);
250 return(SOCKET_ERROR
);
253 ret
= bind (fd
, my_addr
, addrlen
);
256 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: bind error: %s", __func__
, strerror(errno
));
257 errnum
= errno_to_WSA (errnum
, __func__
);
258 WSASetLastError (errnum
);
260 return(SOCKET_ERROR
);
265 int _wapi_connect(guint32 fd
, const struct sockaddr
*serv_addr
,
268 gpointer handle
= GUINT_TO_POINTER (fd
);
269 struct _WapiHandle_socket
*socket_handle
;
272 MonoThreadInfo
*info
= mono_thread_info_current ();
274 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
275 WSASetLastError (WSAENOTSOCK
);
276 return(SOCKET_ERROR
);
279 if (connect (fd
, serv_addr
, addrlen
) == -1) {
286 if (errno
!= EINTR
) {
287 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: connect error: %s", __func__
,
290 errnum
= errno_to_WSA (errnum
, __func__
);
291 if (errnum
== WSAEINPROGRESS
)
292 errnum
= WSAEWOULDBLOCK
; /* see bug #73053 */
294 WSASetLastError (errnum
);
297 * On solaris x86 getsockopt (SO_ERROR) is not set after
298 * connect () fails so we need to save this error.
300 * But don't do this for EWOULDBLOCK (bug 317315)
302 if (errnum
!= WSAEWOULDBLOCK
) {
303 ok
= mono_w32handle_lookup (handle
,
304 MONO_W32HANDLE_SOCKET
,
305 (gpointer
*)&socket_handle
);
307 /* ECONNRESET means the socket was closed by another thread */
308 /* Async close on mac raises ECONNABORTED. */
309 if (errnum
!= WSAECONNRESET
&& errnum
!= WSAENETDOWN
)
310 g_warning ("%s: error looking up socket handle %p (error %d)", __func__
, handle
, errnum
);
312 socket_handle
->saved_error
= errnum
;
315 return(SOCKET_ERROR
);
319 fds
.events
= MONO_POLLOUT
;
320 while (mono_poll (&fds
, 1, -1) == -1 &&
321 !mono_thread_info_is_interrupt_state (info
)) {
322 if (errno
!= EINTR
) {
323 errnum
= errno_to_WSA (errno
, __func__
);
325 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: connect poll error: %s",
326 __func__
, strerror (errno
));
328 WSASetLastError (errnum
);
329 return(SOCKET_ERROR
);
333 len
= sizeof(so_error
);
334 if (getsockopt (fd
, SOL_SOCKET
, SO_ERROR
, &so_error
,
336 errnum
= errno_to_WSA (errno
, __func__
);
338 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: connect getsockopt error: %s",
339 __func__
, strerror (errno
));
341 WSASetLastError (errnum
);
342 return(SOCKET_ERROR
);
346 errnum
= errno_to_WSA (so_error
, __func__
);
348 /* Need to save this socket error */
349 ok
= mono_w32handle_lookup (handle
, MONO_W32HANDLE_SOCKET
,
350 (gpointer
*)&socket_handle
);
352 g_warning ("%s: error looking up socket handle %p", __func__
, handle
);
354 socket_handle
->saved_error
= errnum
;
357 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: connect getsockopt returned error: %s",
358 __func__
, strerror (so_error
));
360 WSASetLastError (errnum
);
361 return(SOCKET_ERROR
);
368 int _wapi_getpeername(guint32 fd
, struct sockaddr
*name
, socklen_t
*namelen
)
370 gpointer handle
= GUINT_TO_POINTER (fd
);
373 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
374 WSASetLastError (WSAENOTSOCK
);
375 return(SOCKET_ERROR
);
378 ret
= getpeername (fd
, name
, namelen
);
381 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: getpeername error: %s", __func__
,
384 errnum
= errno_to_WSA (errnum
, __func__
);
385 WSASetLastError (errnum
);
387 return(SOCKET_ERROR
);
393 int _wapi_getsockname(guint32 fd
, struct sockaddr
*name
, socklen_t
*namelen
)
395 gpointer handle
= GUINT_TO_POINTER (fd
);
398 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
399 WSASetLastError (WSAENOTSOCK
);
400 return(SOCKET_ERROR
);
403 ret
= getsockname (fd
, name
, namelen
);
406 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: getsockname error: %s", __func__
,
409 errnum
= errno_to_WSA (errnum
, __func__
);
410 WSASetLastError (errnum
);
412 return(SOCKET_ERROR
);
418 int _wapi_getsockopt(guint32 fd
, int level
, int optname
, void *optval
,
421 gpointer handle
= GUINT_TO_POINTER (fd
);
425 struct _WapiHandle_socket
*socket_handle
;
428 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
429 WSASetLastError (WSAENOTSOCK
);
430 return(SOCKET_ERROR
);
434 if (level
== SOL_SOCKET
&&
435 (optname
== SO_RCVTIMEO
|| optname
== SO_SNDTIMEO
)) {
437 *optlen
= sizeof (tv
);
440 ret
= getsockopt (fd
, level
, optname
, tmp_val
, optlen
);
443 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: getsockopt error: %s", __func__
,
446 errnum
= errno_to_WSA (errnum
, __func__
);
447 WSASetLastError (errnum
);
449 return(SOCKET_ERROR
);
452 if (level
== SOL_SOCKET
&&
453 (optname
== SO_RCVTIMEO
|| optname
== SO_SNDTIMEO
)) {
454 *((int *) optval
) = tv
.tv_sec
* 1000 + (tv
.tv_usec
/ 1000); // milli from micro
455 *optlen
= sizeof (int);
458 if (optname
== SO_ERROR
) {
459 ok
= mono_w32handle_lookup (handle
, MONO_W32HANDLE_SOCKET
,
460 (gpointer
*)&socket_handle
);
462 g_warning ("%s: error looking up socket handle %p",
465 /* can't extract the last error */
466 *((int *) optval
) = errno_to_WSA (*((int *)optval
),
469 if (*((int *)optval
) != 0) {
470 *((int *) optval
) = errno_to_WSA (*((int *)optval
),
472 socket_handle
->saved_error
= *((int *)optval
);
474 *((int *)optval
) = socket_handle
->saved_error
;
482 int _wapi_listen(guint32 fd
, int backlog
)
484 gpointer handle
= GUINT_TO_POINTER (fd
);
487 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
488 WSASetLastError (WSAENOTSOCK
);
489 return(SOCKET_ERROR
);
492 ret
= listen (fd
, backlog
);
495 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: listen error: %s", __func__
, strerror (errno
));
497 errnum
= errno_to_WSA (errnum
, __func__
);
498 WSASetLastError (errnum
);
500 return(SOCKET_ERROR
);
506 int _wapi_recv(guint32 fd
, void *buf
, size_t len
, int recv_flags
)
508 return(_wapi_recvfrom (fd
, buf
, len
, recv_flags
, NULL
, 0));
511 int _wapi_recvfrom(guint32 fd
, void *buf
, size_t len
, int recv_flags
,
512 struct sockaddr
*from
, socklen_t
*fromlen
)
514 gpointer handle
= GUINT_TO_POINTER (fd
);
515 struct _WapiHandle_socket
*socket_handle
;
518 MonoThreadInfo
*info
= mono_thread_info_current ();
520 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
521 WSASetLastError (WSAENOTSOCK
);
522 return(SOCKET_ERROR
);
526 ret
= recvfrom (fd
, buf
, len
, recv_flags
, from
, fromlen
);
527 } while (ret
== -1 && errno
== EINTR
&&
528 !mono_thread_info_is_interrupt_state (info
));
530 if (ret
== 0 && len
> 0) {
531 /* According to the Linux man page, recvfrom only
532 * returns 0 when the socket has been shut down
533 * cleanly. Turn this into an EINTR to simulate win32
534 * behaviour of returning EINTR when a socket is
535 * closed while the recvfrom is blocking (we use a
536 * shutdown() in socket_close() to trigger this.) See
539 /* Distinguish between the socket being shut down at
540 * the local or remote ends, and reads that request 0
544 /* If this returns FALSE, it means the socket has been
545 * closed locally. If it returns TRUE, but
546 * still_readable != 1 then shutdown
547 * (SHUT_RD|SHUT_RDWR) has been called locally.
549 ok
= mono_w32handle_lookup (handle
, MONO_W32HANDLE_SOCKET
,
550 (gpointer
*)&socket_handle
);
551 if (ok
== FALSE
|| socket_handle
->still_readable
!= 1) {
559 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: recv error: %s", __func__
, strerror(errno
));
561 errnum
= errno_to_WSA (errnum
, __func__
);
562 WSASetLastError (errnum
);
564 return(SOCKET_ERROR
);
570 _wapi_recvmsg(guint32 fd
, struct msghdr
*msg
, int recv_flags
)
572 gpointer handle
= GUINT_TO_POINTER (fd
);
573 struct _WapiHandle_socket
*socket_handle
;
576 MonoThreadInfo
*info
= mono_thread_info_current ();
578 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
579 WSASetLastError (WSAENOTSOCK
);
580 return(SOCKET_ERROR
);
584 ret
= recvmsg (fd
, msg
, recv_flags
);
585 } while (ret
== -1 && errno
== EINTR
&&
586 !mono_thread_info_is_interrupt_state (info
));
589 /* see _wapi_recvfrom */
590 ok
= mono_w32handle_lookup (handle
, MONO_W32HANDLE_SOCKET
,
591 (gpointer
*)&socket_handle
);
592 if (ok
== FALSE
|| socket_handle
->still_readable
!= 1) {
600 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: recvmsg error: %s", __func__
, strerror(errno
));
602 errnum
= errno_to_WSA (errnum
, __func__
);
603 WSASetLastError (errnum
);
605 return(SOCKET_ERROR
);
610 int _wapi_send(guint32 fd
, const void *msg
, size_t len
, int send_flags
)
612 gpointer handle
= GUINT_TO_POINTER (fd
);
614 MonoThreadInfo
*info
= mono_thread_info_current ();
616 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
617 WSASetLastError (WSAENOTSOCK
);
618 return(SOCKET_ERROR
);
622 ret
= send (fd
, msg
, len
, send_flags
);
623 } while (ret
== -1 && errno
== EINTR
&&
624 !mono_thread_info_is_interrupt_state (info
));
628 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: send error: %s", __func__
, strerror (errno
));
631 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
632 * a blocking socket. See bug #599488 */
633 if (errnum
== EAGAIN
) {
634 ret
= fcntl (fd
, F_GETFL
, 0);
635 if (ret
!= -1 && (ret
& O_NONBLOCK
) == 0)
638 #endif /* O_NONBLOCK */
639 errnum
= errno_to_WSA (errnum
, __func__
);
640 WSASetLastError (errnum
);
642 return(SOCKET_ERROR
);
647 int _wapi_sendto(guint32 fd
, const void *msg
, size_t len
, int send_flags
,
648 const struct sockaddr
*to
, socklen_t tolen
)
650 gpointer handle
= GUINT_TO_POINTER (fd
);
652 MonoThreadInfo
*info
= mono_thread_info_current ();
654 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
655 WSASetLastError (WSAENOTSOCK
);
656 return(SOCKET_ERROR
);
660 ret
= sendto (fd
, msg
, len
, send_flags
, to
, tolen
);
661 } while (ret
== -1 && errno
== EINTR
&&
662 !mono_thread_info_is_interrupt_state (info
));
666 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: send error: %s", __func__
, strerror (errno
));
668 errnum
= errno_to_WSA (errnum
, __func__
);
669 WSASetLastError (errnum
);
671 return(SOCKET_ERROR
);
677 _wapi_sendmsg(guint32 fd
, const struct msghdr
*msg
, int send_flags
)
679 gpointer handle
= GUINT_TO_POINTER (fd
);
681 MonoThreadInfo
*info
= mono_thread_info_current ();
683 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
684 WSASetLastError (WSAENOTSOCK
);
685 return(SOCKET_ERROR
);
689 ret
= sendmsg (fd
, msg
, send_flags
);
690 } while (ret
== -1 && errno
== EINTR
&&
691 !mono_thread_info_is_interrupt_state (info
));
695 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: sendmsg error: %s", __func__
, strerror (errno
));
697 errnum
= errno_to_WSA (errnum
, __func__
);
698 WSASetLastError (errnum
);
700 return(SOCKET_ERROR
);
705 int _wapi_setsockopt(guint32 fd
, int level
, int optname
,
706 const void *optval
, socklen_t optlen
)
708 gpointer handle
= GUINT_TO_POINTER (fd
);
711 #if defined (__linux__)
712 /* This has its address taken so it cannot be moved to the if block which uses it */
717 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
718 WSASetLastError (WSAENOTSOCK
);
719 return(SOCKET_ERROR
);
723 if (level
== SOL_SOCKET
&&
724 (optname
== SO_RCVTIMEO
|| optname
== SO_SNDTIMEO
)) {
725 int ms
= *((int *) optval
);
726 tv
.tv_sec
= ms
/ 1000;
727 tv
.tv_usec
= (ms
% 1000) * 1000; // micro from milli
729 optlen
= sizeof (tv
);
731 #if defined (__linux__)
732 else if (level
== SOL_SOCKET
&&
733 (optname
== SO_SNDBUF
|| optname
== SO_RCVBUF
)) {
734 /* According to socket(7) the Linux kernel doubles the
735 * buffer sizes "to allow space for bookkeeping
738 bufsize
= *((int *) optval
);
745 ret
= setsockopt (fd
, level
, optname
, tmp_val
, optlen
);
748 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: setsockopt error: %s", __func__
,
751 errnum
= errno_to_WSA (errnum
, __func__
);
752 WSASetLastError (errnum
);
754 return(SOCKET_ERROR
);
757 #if defined (SO_REUSEPORT)
758 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
759 if (level
== SOL_SOCKET
&& optname
== SO_REUSEADDR
) {
761 socklen_t type_len
= sizeof (type
);
763 if (!getsockopt (fd
, level
, SO_TYPE
, &type
, &type_len
)) {
764 if (type
== SOCK_DGRAM
|| type
== SOCK_STREAM
)
765 setsockopt (fd
, level
, SO_REUSEPORT
, tmp_val
, optlen
);
773 int _wapi_shutdown(guint32 fd
, int how
)
775 struct _WapiHandle_socket
*socket_handle
;
777 gpointer handle
= GUINT_TO_POINTER (fd
);
780 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
781 WSASetLastError (WSAENOTSOCK
);
782 return(SOCKET_ERROR
);
785 if (how
== SHUT_RD
||
787 ok
= mono_w32handle_lookup (handle
, MONO_W32HANDLE_SOCKET
,
788 (gpointer
*)&socket_handle
);
790 g_warning ("%s: error looking up socket handle %p",
792 WSASetLastError (WSAENOTSOCK
);
793 return(SOCKET_ERROR
);
796 socket_handle
->still_readable
= 0;
799 ret
= shutdown (fd
, how
);
802 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: shutdown error: %s", __func__
,
805 errnum
= errno_to_WSA (errnum
, __func__
);
806 WSASetLastError (errnum
);
808 return(SOCKET_ERROR
);
814 guint32
_wapi_socket(int domain
, int type
, int protocol
, void *unused
,
815 guint32 unused2
, guint32 unused3
)
817 struct _WapiHandle_socket socket_handle
= {0};
821 socket_handle
.domain
= domain
;
822 socket_handle
.type
= type
;
823 socket_handle
.protocol
= protocol
;
824 socket_handle
.still_readable
= 1;
826 fd
= socket (domain
, type
, protocol
);
827 if (fd
== -1 && domain
== AF_INET
&& type
== SOCK_RAW
&&
829 /* Retry with protocol == 4 (see bug #54565) */
830 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
831 socket_handle
.protocol
= 4;
832 fd
= socket (AF_INET
, SOCK_RAW
, 4);
837 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: socket error: %s", __func__
, strerror (errno
));
838 errnum
= errno_to_WSA (errnum
, __func__
);
839 WSASetLastError (errnum
);
841 return(INVALID_SOCKET
);
844 if (fd
>= mono_w32handle_fd_reserve
) {
845 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: File descriptor is too big (%d >= %d)",
846 __func__
, fd
, mono_w32handle_fd_reserve
);
848 WSASetLastError (WSASYSCALLFAILURE
);
851 return(INVALID_SOCKET
);
854 /* .net seems to set this by default for SOCK_STREAM, not for
855 * SOCK_DGRAM (see bug #36322)
856 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
858 * It seems winsock has a rather different idea of what
859 * SO_REUSEADDR means. If it's set, then a new socket can be
860 * bound over an existing listening socket. There's a new
861 * windows-specific option called SO_EXCLUSIVEADDRUSE but
862 * using that means the socket MUST be closed properly, or a
863 * denial of service can occur. Luckily for us, winsock
864 * behaves as though any other system would when SO_REUSEADDR
865 * is true, so we don't need to do anything else here. See
867 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
872 ret
= setsockopt (fd
, SOL_SOCKET
, SO_REUSEADDR
, &true_
,
877 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: Error setting SO_REUSEADDR", __func__
);
879 errnum
= errno_to_WSA (errnum
, __func__
);
880 WSASetLastError (errnum
);
884 return(INVALID_SOCKET
);
889 handle
= mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET
, fd
, &socket_handle
);
890 if (handle
== INVALID_HANDLE_VALUE
) {
891 g_warning ("%s: error creating socket handle", __func__
);
892 WSASetLastError (WSASYSCALLFAILURE
);
894 return(INVALID_SOCKET
);
897 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: returning socket handle %p", __func__
, handle
);
902 static gboolean
socket_disconnect (guint32 fd
)
904 struct _WapiHandle_socket
*socket_handle
;
906 gpointer handle
= GUINT_TO_POINTER (fd
);
909 ok
= mono_w32handle_lookup (handle
, MONO_W32HANDLE_SOCKET
,
910 (gpointer
*)&socket_handle
);
912 g_warning ("%s: error looking up socket handle %p", __func__
,
914 WSASetLastError (WSAENOTSOCK
);
918 newsock
= socket (socket_handle
->domain
, socket_handle
->type
,
919 socket_handle
->protocol
);
923 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: socket error: %s", __func__
, strerror (errno
));
925 errnum
= errno_to_WSA (errnum
, __func__
);
926 WSASetLastError (errnum
);
931 /* According to Stevens "Advanced Programming in the UNIX
932 * Environment: UNIX File I/O" dup2() is atomic so there
933 * should not be a race condition between the old fd being
934 * closed and the new socket fd being copied over
937 ret
= dup2 (newsock
, fd
);
938 } while (ret
== -1 && errno
== EAGAIN
);
943 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: dup2 error: %s", __func__
, strerror (errno
));
945 errnum
= errno_to_WSA (errnum
, __func__
);
946 WSASetLastError (errnum
);
956 static gboolean
wapi_disconnectex (guint32 fd
, WapiOverlapped
*overlapped
,
957 guint32 flags
, guint32 reserved
)
959 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: called on socket %d!", __func__
, fd
);
962 WSASetLastError (WSAEINVAL
);
966 /* We could check the socket type here and fail unless its
967 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
968 * if we really wanted to
971 return(socket_disconnect (fd
));
974 #define SF_BUFFER_SIZE 16384
976 wapi_sendfile (guint32 socket
, gpointer fd
, guint32 bytes_to_write
, guint32 bytes_per_send
, guint32 flags
)
978 MonoThreadInfo
*info
= mono_thread_info_current ();
979 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
980 gint file
= GPOINTER_TO_INT (fd
);
986 n
= fstat (file
, &statbuf
);
989 errnum
= errno_to_WSA (errnum
, __func__
);
990 WSASetLastError (errnum
);
995 res
= sendfile (socket
, file
, NULL
, statbuf
.st_size
);
996 #elif defined(DARWIN)
997 /* TODO: header/tail could be sent in the 5th argument */
998 /* TODO: Might not send the entire file for non-blocking sockets */
999 res
= sendfile (file
, socket
, 0, &statbuf
.st_size
, NULL
, 0);
1001 } while (res
!= -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
1004 errnum
= errno_to_WSA (errnum
, __func__
);
1005 WSASetLastError (errnum
);
1006 return SOCKET_ERROR
;
1009 /* Default implementation */
1010 gint file
= GPOINTER_TO_INT (fd
);
1014 buffer
= g_malloc (SF_BUFFER_SIZE
);
1017 n
= read (file
, buffer
, SF_BUFFER_SIZE
);
1018 } while (n
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
1023 return 0; /* We're done reading */
1026 n
= send (socket
, buffer
, n
, 0); /* short sends? enclose this in a loop? */
1027 } while (n
== -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
1028 } while (n
!= -1 && errno
== EINTR
&& !mono_thread_info_is_interrupt_state (info
));
1031 gint errnum
= errno
;
1032 errnum
= errno_to_WSA (errnum
, __func__
);
1033 WSASetLastError (errnum
);
1035 return SOCKET_ERROR
;
1043 TransmitFile (guint32 socket
, gpointer file
, guint32 bytes_to_write
, guint32 bytes_per_send
, WapiOverlapped
*ol
,
1044 WapiTransmitFileBuffers
*buffers
, guint32 flags
)
1046 gpointer sock
= GUINT_TO_POINTER (socket
);
1049 if (mono_w32handle_get_type (sock
) != MONO_W32HANDLE_SOCKET
) {
1050 WSASetLastError (WSAENOTSOCK
);
1054 /* Write the header */
1055 if (buffers
!= NULL
&& buffers
->Head
!= NULL
&& buffers
->HeadLength
> 0) {
1056 ret
= _wapi_send (socket
, buffers
->Head
, buffers
->HeadLength
, 0);
1057 if (ret
== SOCKET_ERROR
)
1061 ret
= wapi_sendfile (socket
, file
, bytes_to_write
, bytes_per_send
, flags
);
1062 if (ret
== SOCKET_ERROR
)
1065 /* Write the tail */
1066 if (buffers
!= NULL
&& buffers
->Tail
!= NULL
&& buffers
->TailLength
> 0) {
1067 ret
= _wapi_send (socket
, buffers
->Tail
, buffers
->TailLength
, 0);
1068 if (ret
== SOCKET_ERROR
)
1072 if ((flags
& TF_DISCONNECT
) == TF_DISCONNECT
)
1073 closesocket (socket
);
1082 } extension_functions
[] = {
1083 {WSAID_DISCONNECTEX
, wapi_disconnectex
},
1084 {WSAID_TRANSMITFILE
, TransmitFile
},
1089 WSAIoctl (guint32 fd
, gint32 command
,
1090 gchar
*input
, gint i_len
,
1091 gchar
*output
, gint o_len
, glong
*written
,
1092 void *unused1
, void *unused2
)
1094 gpointer handle
= GUINT_TO_POINTER (fd
);
1096 gchar
*buffer
= NULL
;
1098 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
1099 WSASetLastError (WSAENOTSOCK
);
1100 return SOCKET_ERROR
;
1103 if (command
== SIO_GET_EXTENSION_FUNCTION_POINTER
) {
1105 WapiGuid
*guid
= (WapiGuid
*)input
;
1107 if (i_len
< sizeof(WapiGuid
)) {
1108 /* As far as I can tell, windows doesn't
1109 * actually set an error here...
1111 WSASetLastError (WSAEINVAL
);
1112 return(SOCKET_ERROR
);
1115 if (o_len
< sizeof(gpointer
)) {
1117 WSASetLastError (WSAEINVAL
);
1118 return(SOCKET_ERROR
);
1121 if (output
== NULL
) {
1123 WSASetLastError (WSAEINVAL
);
1124 return(SOCKET_ERROR
);
1127 while(extension_functions
[i
].func
!= NULL
) {
1128 if (!memcmp (guid
, &extension_functions
[i
].guid
,
1129 sizeof(WapiGuid
))) {
1130 memcpy (output
, &extension_functions
[i
].func
,
1132 *written
= sizeof(gpointer
);
1139 WSASetLastError (WSAEINVAL
);
1140 return(SOCKET_ERROR
);
1143 if (command
== SIO_KEEPALIVE_VALS
) {
1145 uint32_t keepalivetime
;
1146 uint32_t keepaliveinterval
;
1148 if (i_len
< (3 * sizeof (uint32_t))) {
1149 WSASetLastError (WSAEINVAL
);
1150 return SOCKET_ERROR
;
1152 memcpy (&onoff
, input
, sizeof (uint32_t));
1153 memcpy (&keepalivetime
, input
+ sizeof (uint32_t), sizeof (uint32_t));
1154 memcpy (&keepaliveinterval
, input
+ 2 * sizeof (uint32_t), sizeof (uint32_t));
1155 ret
= setsockopt (fd
, SOL_SOCKET
, SO_KEEPALIVE
, &onoff
, sizeof (uint32_t));
1157 gint errnum
= errno
;
1158 errnum
= errno_to_WSA (errnum
, __func__
);
1159 WSASetLastError (errnum
);
1160 return SOCKET_ERROR
;
1163 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1164 /* Values are in ms, but we need s */
1167 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1168 rem
= keepalivetime
% 1000;
1169 keepalivetime
/= 1000;
1170 if (keepalivetime
== 0 || rem
>= 500)
1172 ret
= setsockopt (fd
, IPPROTO_TCP
, TCP_KEEPIDLE
, &keepalivetime
, sizeof (uint32_t));
1174 rem
= keepaliveinterval
% 1000;
1175 keepaliveinterval
/= 1000;
1176 if (keepaliveinterval
== 0 || rem
>= 500)
1177 keepaliveinterval
++;
1178 ret
= setsockopt (fd
, IPPROTO_TCP
, TCP_KEEPINTVL
, &keepaliveinterval
, sizeof (uint32_t));
1181 gint errnum
= errno
;
1182 errnum
= errno_to_WSA (errnum
, __func__
);
1183 WSASetLastError (errnum
);
1184 return SOCKET_ERROR
;
1193 buffer
= (char *)g_memdup (input
, i_len
);
1196 ret
= ioctl (fd
, command
, buffer
);
1198 gint errnum
= errno
;
1199 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: WSAIoctl error: %s", __func__
,
1202 errnum
= errno_to_WSA (errnum
, __func__
);
1203 WSASetLastError (errnum
);
1206 return(SOCKET_ERROR
);
1209 if (buffer
== NULL
) {
1212 /* We just copy the buffer to the output. Some ioctls
1213 * don't even output any data, but, well...
1215 * NB windows returns WSAEFAULT if o_len is too small
1217 i_len
= (i_len
> o_len
) ? o_len
: i_len
;
1219 if (i_len
> 0 && output
!= NULL
) {
1220 memcpy (output
, buffer
, i_len
);
1230 #ifndef PLATFORM_PORT_PROVIDES_IOCTLSOCKET
1231 int ioctlsocket(guint32 fd
, unsigned long command
, gpointer arg
)
1233 gpointer handle
= GUINT_TO_POINTER (fd
);
1236 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
1237 WSASetLastError (WSAENOTSOCK
);
1238 return(SOCKET_ERROR
);
1244 /* This works better than ioctl(...FIONBIO...)
1245 * on Linux (it causes connect to return
1246 * EINPROGRESS, but the ioctl doesn't seem to)
1248 ret
= fcntl(fd
, F_GETFL
, 0);
1250 if (*(gboolean
*)arg
) {
1255 ret
= fcntl(fd
, F_SETFL
, ret
);
1258 #endif /* O_NONBLOCK */
1259 /* Unused in Mono */
1261 ret
= ioctl (fd
, command
, arg
);
1266 #if defined (PLATFORM_MACOSX)
1268 // ioctl (fd, FIONREAD, XXX) returns the size of
1269 // the UDP header as well on
1272 // Use getsockopt SO_NREAD instead to get the
1273 // right values for TCP and UDP.
1275 // ai_canonname can be null in some cases on darwin, where the runtime assumes it will
1276 // be the value of the ip buffer.
1278 socklen_t optlen
= sizeof (int);
1279 ret
= getsockopt (fd
, SOL_SOCKET
, SO_NREAD
, arg
, &optlen
);
1281 ret
= ioctl (fd
, command
, arg
);
1286 WSASetLastError (WSAEINVAL
);
1287 return(SOCKET_ERROR
);
1291 gint errnum
= errno
;
1292 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: ioctl error: %s", __func__
, strerror (errno
));
1294 errnum
= errno_to_WSA (errnum
, __func__
);
1295 WSASetLastError (errnum
);
1297 return(SOCKET_ERROR
);
1303 int _wapi_select(int nfds G_GNUC_UNUSED
, fd_set
*readfds
, fd_set
*writefds
,
1304 fd_set
*exceptfds
, struct timeval
*timeout
)
1307 MonoThreadInfo
*info
= mono_thread_info_current ();
1309 for (maxfd
= FD_SETSIZE
-1; maxfd
>= 0; maxfd
--) {
1310 if ((readfds
&& FD_ISSET (maxfd
, readfds
)) ||
1311 (writefds
&& FD_ISSET (maxfd
, writefds
)) ||
1312 (exceptfds
&& FD_ISSET (maxfd
, exceptfds
))) {
1318 WSASetLastError (WSAEINVAL
);
1319 return(SOCKET_ERROR
);
1323 ret
= select(maxfd
+ 1, readfds
, writefds
, exceptfds
,
1325 } while (ret
== -1 && errno
== EINTR
&&
1326 !mono_thread_info_is_interrupt_state (info
));
1329 gint errnum
= errno
;
1330 MONO_TRACE (G_LOG_LEVEL_DEBUG
, MONO_TRACE_IO_LAYER
, "%s: select error: %s", __func__
, strerror (errno
));
1331 errnum
= errno_to_WSA (errnum
, __func__
);
1332 WSASetLastError (errnum
);
1334 return(SOCKET_ERROR
);
1340 void _wapi_FD_CLR(guint32 fd
, fd_set
*set
)
1342 gpointer handle
= GUINT_TO_POINTER (fd
);
1344 if (fd
>= FD_SETSIZE
) {
1345 WSASetLastError (WSAEINVAL
);
1349 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
1350 WSASetLastError (WSAENOTSOCK
);
1357 int _wapi_FD_ISSET(guint32 fd
, fd_set
*set
)
1359 gpointer handle
= GUINT_TO_POINTER (fd
);
1361 if (fd
>= FD_SETSIZE
) {
1362 WSASetLastError (WSAEINVAL
);
1366 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
1367 WSASetLastError (WSAENOTSOCK
);
1371 return(FD_ISSET (fd
, set
));
1374 void _wapi_FD_SET(guint32 fd
, fd_set
*set
)
1376 gpointer handle
= GUINT_TO_POINTER (fd
);
1378 if (fd
>= FD_SETSIZE
) {
1379 WSASetLastError (WSAEINVAL
);
1383 if (mono_w32handle_get_type (handle
) != MONO_W32HANDLE_SOCKET
) {
1384 WSASetLastError (WSAENOTSOCK
);
1393 wsabuf_to_msghdr (WapiWSABuf
*buffers
, guint32 count
, struct msghdr
*hdr
)
1397 memset (hdr
, 0, sizeof (struct msghdr
));
1398 hdr
->msg_iovlen
= count
;
1399 hdr
->msg_iov
= g_new0 (struct iovec
, count
);
1400 for (i
= 0; i
< count
; i
++) {
1401 hdr
->msg_iov
[i
].iov_base
= buffers
[i
].buf
;
1402 hdr
->msg_iov
[i
].iov_len
= buffers
[i
].len
;
1407 msghdr_iov_free (struct msghdr
*hdr
)
1409 g_free (hdr
->msg_iov
);
1412 int WSARecv (guint32 fd
, WapiWSABuf
*buffers
, guint32 count
, guint32
*received
,
1413 guint32
*flags
, WapiOverlapped
*overlapped
,
1414 WapiOverlappedCB
*complete
)
1419 g_assert (overlapped
== NULL
);
1420 g_assert (complete
== NULL
);
1422 wsabuf_to_msghdr (buffers
, count
, &hdr
);
1423 ret
= _wapi_recvmsg (fd
, &hdr
, *flags
);
1424 msghdr_iov_free (&hdr
);
1426 if(ret
== SOCKET_ERROR
) {
1431 *flags
= hdr
.msg_flags
;
1436 int WSASend (guint32 fd
, WapiWSABuf
*buffers
, guint32 count
, guint32
*sent
,
1437 guint32 flags
, WapiOverlapped
*overlapped
,
1438 WapiOverlappedCB
*complete
)
1443 g_assert (overlapped
== NULL
);
1444 g_assert (complete
== NULL
);
1446 wsabuf_to_msghdr (buffers
, count
, &hdr
);
1447 ret
= _wapi_sendmsg (fd
, &hdr
, flags
);
1448 msghdr_iov_free (&hdr
);
1450 if(ret
== SOCKET_ERROR
)
1457 #endif /* ifndef DISABLE_SOCKETS */