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/handles-private.h>
43 #include <mono/io-layer/socket-wrappers.h>
44 #include <mono/io-layer/io-trace.h>
45 #include <mono/utils/mono-poll.h>
46 #include <mono/utils/mono-once.h>
47 #include <mono/utils/mono-logger-internals.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 WapiHandleOps _wapi_socket_ops = {
67 socket_close, /* close */
71 NULL, /* special_wait */
73 socket_details, /* details */
74 socket_typename, /* typename */
75 socket_typesize, /* typesize */
78 static mono_once_t socket_ops_once=MONO_ONCE_INIT;
80 static void socket_ops_init (void)
82 /* No capabilities to register */
85 static void socket_close (gpointer handle, gpointer data)
88 struct _WapiHandle_socket *socket_handle = (struct _WapiHandle_socket *)data;
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 !_wapi_thread_cur_apc_pending ());
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 (_wapi_handle_type (handle) == WAPI_HANDLE_SOCKET)
133 _wapi_handle_ops_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 _wapi_handle_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 (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
162 WSASetLastError (WSAENOTSOCK);
166 _wapi_handle_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};
179 if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
180 WSASetLastError (WSAEFAULT);
181 return(INVALID_SOCKET);
184 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
185 WSASetLastError (WSAENOTSOCK);
186 return(INVALID_SOCKET);
189 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
190 (gpointer *)&socket_handle);
192 g_warning ("%s: error looking up socket handle %p",
194 WSASetLastError (WSAENOTSOCK);
195 return(INVALID_SOCKET);
199 new_fd = accept (fd, addr, addrlen);
200 } while (new_fd == -1 && errno == EINTR &&
201 !_wapi_thread_cur_apc_pending());
205 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, strerror(errno));
207 errnum = errno_to_WSA (errnum, __func__);
208 WSASetLastError (errnum);
210 return(INVALID_SOCKET);
213 if (new_fd >= _wapi_fd_reserve) {
214 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
216 WSASetLastError (WSASYSCALLFAILURE);
220 return(INVALID_SOCKET);
223 new_socket_handle.domain = socket_handle->domain;
224 new_socket_handle.type = socket_handle->type;
225 new_socket_handle.protocol = socket_handle->protocol;
226 new_socket_handle.still_readable = 1;
228 new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd,
230 if(new_handle == _WAPI_HANDLE_INVALID) {
231 g_warning ("%s: error creating socket handle", __func__);
232 WSASetLastError (ERROR_GEN_FAILURE);
233 return(INVALID_SOCKET);
236 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with",
237 __func__, new_handle);
242 int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
244 gpointer handle = GUINT_TO_POINTER (fd);
247 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
248 WSASetLastError (WSAENOTSOCK);
249 return(SOCKET_ERROR);
252 ret = bind (fd, my_addr, addrlen);
255 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, strerror(errno));
256 errnum = errno_to_WSA (errnum, __func__);
257 WSASetLastError (errnum);
259 return(SOCKET_ERROR);
264 int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
267 gpointer handle = GUINT_TO_POINTER (fd);
268 struct _WapiHandle_socket *socket_handle;
272 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
273 WSASetLastError (WSAENOTSOCK);
274 return(SOCKET_ERROR);
277 if (connect (fd, serv_addr, addrlen) == -1) {
284 if (errno != EINTR) {
285 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__,
288 errnum = errno_to_WSA (errnum, __func__);
289 if (errnum == WSAEINPROGRESS)
290 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
292 WSASetLastError (errnum);
295 * On solaris x86 getsockopt (SO_ERROR) is not set after
296 * connect () fails so we need to save this error.
298 * But don't do this for EWOULDBLOCK (bug 317315)
300 if (errnum != WSAEWOULDBLOCK) {
301 ok = _wapi_lookup_handle (handle,
303 (gpointer *)&socket_handle);
305 /* ECONNRESET means the socket was closed by another thread */
306 /* Async close on mac raises ECONNABORTED. */
307 if (errnum != WSAECONNRESET && errnum != WSAENETDOWN)
308 g_warning ("%s: error looking up socket handle %p (error %d)", __func__, handle, errnum);
310 socket_handle->saved_error = errnum;
313 return(SOCKET_ERROR);
317 fds.events = MONO_POLLOUT;
318 while (mono_poll (&fds, 1, -1) == -1 &&
319 !_wapi_thread_cur_apc_pending ()) {
320 if (errno != EINTR) {
321 errnum = errno_to_WSA (errno, __func__);
323 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s",
324 __func__, strerror (errno));
326 WSASetLastError (errnum);
327 return(SOCKET_ERROR);
331 len = sizeof(so_error);
332 if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &so_error,
334 errnum = errno_to_WSA (errno, __func__);
336 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s",
337 __func__, strerror (errno));
339 WSASetLastError (errnum);
340 return(SOCKET_ERROR);
344 errnum = errno_to_WSA (so_error, __func__);
346 /* Need to save this socket error */
347 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
348 (gpointer *)&socket_handle);
350 g_warning ("%s: error looking up socket handle %p", __func__, handle);
352 socket_handle->saved_error = errnum;
355 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s",
356 __func__, strerror (so_error));
358 WSASetLastError (errnum);
359 return(SOCKET_ERROR);
366 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
368 gpointer handle = GUINT_TO_POINTER (fd);
371 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
372 WSASetLastError (WSAENOTSOCK);
373 return(SOCKET_ERROR);
376 ret = getpeername (fd, name, namelen);
379 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__,
382 errnum = errno_to_WSA (errnum, __func__);
383 WSASetLastError (errnum);
385 return(SOCKET_ERROR);
391 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
393 gpointer handle = GUINT_TO_POINTER (fd);
396 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
397 WSASetLastError (WSAENOTSOCK);
398 return(SOCKET_ERROR);
401 ret = getsockname (fd, name, namelen);
404 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__,
407 errnum = errno_to_WSA (errnum, __func__);
408 WSASetLastError (errnum);
410 return(SOCKET_ERROR);
416 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
419 gpointer handle = GUINT_TO_POINTER (fd);
423 struct _WapiHandle_socket *socket_handle;
426 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
427 WSASetLastError (WSAENOTSOCK);
428 return(SOCKET_ERROR);
432 if (level == SOL_SOCKET &&
433 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
435 *optlen = sizeof (tv);
438 ret = getsockopt (fd, level, optname, tmp_val, optlen);
441 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__,
444 errnum = errno_to_WSA (errnum, __func__);
445 WSASetLastError (errnum);
447 return(SOCKET_ERROR);
450 if (level == SOL_SOCKET &&
451 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
452 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
453 *optlen = sizeof (int);
456 if (optname == SO_ERROR) {
457 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
458 (gpointer *)&socket_handle);
460 g_warning ("%s: error looking up socket handle %p",
463 /* can't extract the last error */
464 *((int *) optval) = errno_to_WSA (*((int *)optval),
467 if (*((int *)optval) != 0) {
468 *((int *) optval) = errno_to_WSA (*((int *)optval),
470 socket_handle->saved_error = *((int *)optval);
472 *((int *)optval) = socket_handle->saved_error;
480 int _wapi_listen(guint32 fd, int backlog)
482 gpointer handle = GUINT_TO_POINTER (fd);
485 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
486 WSASetLastError (WSAENOTSOCK);
487 return(SOCKET_ERROR);
490 ret = listen (fd, backlog);
493 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, strerror (errno));
495 errnum = errno_to_WSA (errnum, __func__);
496 WSASetLastError (errnum);
498 return(SOCKET_ERROR);
504 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
506 return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
509 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
510 struct sockaddr *from, socklen_t *fromlen)
512 gpointer handle = GUINT_TO_POINTER (fd);
513 struct _WapiHandle_socket *socket_handle;
517 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
518 WSASetLastError (WSAENOTSOCK);
519 return(SOCKET_ERROR);
523 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
524 } while (ret == -1 && errno == EINTR &&
525 !_wapi_thread_cur_apc_pending ());
527 if (ret == 0 && len > 0) {
528 /* According to the Linux man page, recvfrom only
529 * returns 0 when the socket has been shut down
530 * cleanly. Turn this into an EINTR to simulate win32
531 * behaviour of returning EINTR when a socket is
532 * closed while the recvfrom is blocking (we use a
533 * shutdown() in socket_close() to trigger this.) See
536 /* Distinguish between the socket being shut down at
537 * the local or remote ends, and reads that request 0
541 /* If this returns FALSE, it means the socket has been
542 * closed locally. If it returns TRUE, but
543 * still_readable != 1 then shutdown
544 * (SHUT_RD|SHUT_RDWR) has been called locally.
546 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
547 (gpointer *)&socket_handle);
548 if (ok == FALSE || socket_handle->still_readable != 1) {
556 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, strerror(errno));
558 errnum = errno_to_WSA (errnum, __func__);
559 WSASetLastError (errnum);
561 return(SOCKET_ERROR);
567 _wapi_recvmsg(guint32 fd, struct msghdr *msg, int recv_flags)
569 gpointer handle = GUINT_TO_POINTER (fd);
570 struct _WapiHandle_socket *socket_handle;
574 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
575 WSASetLastError (WSAENOTSOCK);
576 return(SOCKET_ERROR);
580 ret = recvmsg (fd, msg, recv_flags);
581 } while (ret == -1 && errno == EINTR &&
582 !_wapi_thread_cur_apc_pending ());
585 /* see _wapi_recvfrom */
586 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
587 (gpointer *)&socket_handle);
588 if (ok == FALSE || socket_handle->still_readable != 1) {
596 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, strerror(errno));
598 errnum = errno_to_WSA (errnum, __func__);
599 WSASetLastError (errnum);
601 return(SOCKET_ERROR);
606 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
608 gpointer handle = GUINT_TO_POINTER (fd);
611 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
612 WSASetLastError (WSAENOTSOCK);
613 return(SOCKET_ERROR);
617 ret = send (fd, msg, len, send_flags);
618 } while (ret == -1 && errno == EINTR &&
619 !_wapi_thread_cur_apc_pending ());
623 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, strerror (errno));
626 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
627 * a blocking socket. See bug #599488 */
628 if (errnum == EAGAIN) {
629 ret = fcntl (fd, F_GETFL, 0);
630 if (ret != -1 && (ret & O_NONBLOCK) == 0)
633 #endif /* O_NONBLOCK */
634 errnum = errno_to_WSA (errnum, __func__);
635 WSASetLastError (errnum);
637 return(SOCKET_ERROR);
642 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
643 const struct sockaddr *to, socklen_t tolen)
645 gpointer handle = GUINT_TO_POINTER (fd);
648 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
649 WSASetLastError (WSAENOTSOCK);
650 return(SOCKET_ERROR);
654 ret = sendto (fd, msg, len, send_flags, to, tolen);
655 } while (ret == -1 && errno == EINTR &&
656 !_wapi_thread_cur_apc_pending ());
660 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, strerror (errno));
662 errnum = errno_to_WSA (errnum, __func__);
663 WSASetLastError (errnum);
665 return(SOCKET_ERROR);
671 _wapi_sendmsg(guint32 fd, const struct msghdr *msg, int send_flags)
673 gpointer handle = GUINT_TO_POINTER (fd);
676 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
677 WSASetLastError (WSAENOTSOCK);
678 return(SOCKET_ERROR);
682 ret = sendmsg (fd, msg, send_flags);
683 } while (ret == -1 && errno == EINTR &&
684 !_wapi_thread_cur_apc_pending ());
688 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, strerror (errno));
690 errnum = errno_to_WSA (errnum, __func__);
691 WSASetLastError (errnum);
693 return(SOCKET_ERROR);
698 int _wapi_setsockopt(guint32 fd, int level, int optname,
699 const void *optval, socklen_t optlen)
701 gpointer handle = GUINT_TO_POINTER (fd);
704 #if defined (__linux__)
705 /* This has its address taken so it cannot be moved to the if block which uses it */
710 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
711 WSASetLastError (WSAENOTSOCK);
712 return(SOCKET_ERROR);
716 if (level == SOL_SOCKET &&
717 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
718 int ms = *((int *) optval);
719 tv.tv_sec = ms / 1000;
720 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
722 optlen = sizeof (tv);
724 #if defined (__linux__)
725 else if (level == SOL_SOCKET &&
726 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
727 /* According to socket(7) the Linux kernel doubles the
728 * buffer sizes "to allow space for bookkeeping
731 bufsize = *((int *) optval);
738 ret = setsockopt (fd, level, optname, tmp_val, optlen);
741 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__,
744 errnum = errno_to_WSA (errnum, __func__);
745 WSASetLastError (errnum);
747 return(SOCKET_ERROR);
750 #if defined (SO_REUSEPORT)
751 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
752 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
754 socklen_t type_len = sizeof (type);
756 if (!getsockopt (fd, level, SO_TYPE, &type, &type_len)) {
757 if (type == SOCK_DGRAM || type == SOCK_STREAM)
758 setsockopt (fd, level, SO_REUSEPORT, tmp_val, optlen);
766 int _wapi_shutdown(guint32 fd, int how)
768 struct _WapiHandle_socket *socket_handle;
770 gpointer handle = GUINT_TO_POINTER (fd);
773 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
774 WSASetLastError (WSAENOTSOCK);
775 return(SOCKET_ERROR);
778 if (how == SHUT_RD ||
780 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
781 (gpointer *)&socket_handle);
783 g_warning ("%s: error looking up socket handle %p",
785 WSASetLastError (WSAENOTSOCK);
786 return(SOCKET_ERROR);
789 socket_handle->still_readable = 0;
792 ret = shutdown (fd, how);
795 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__,
798 errnum = errno_to_WSA (errnum, __func__);
799 WSASetLastError (errnum);
801 return(SOCKET_ERROR);
807 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
808 guint32 unused2, guint32 unused3)
810 struct _WapiHandle_socket socket_handle = {0};
814 socket_handle.domain = domain;
815 socket_handle.type = type;
816 socket_handle.protocol = protocol;
817 socket_handle.still_readable = 1;
819 fd = socket (domain, type, protocol);
820 if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
822 /* Retry with protocol == 4 (see bug #54565) */
823 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
824 socket_handle.protocol = 4;
825 fd = socket (AF_INET, SOCK_RAW, 4);
830 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, strerror (errno));
831 errnum = errno_to_WSA (errnum, __func__);
832 WSASetLastError (errnum);
834 return(INVALID_SOCKET);
837 if (fd >= _wapi_fd_reserve) {
838 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big (%d >= %d)",
839 __func__, fd, _wapi_fd_reserve);
841 WSASetLastError (WSASYSCALLFAILURE);
844 return(INVALID_SOCKET);
847 /* .net seems to set this by default for SOCK_STREAM, not for
848 * SOCK_DGRAM (see bug #36322)
849 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
851 * It seems winsock has a rather different idea of what
852 * SO_REUSEADDR means. If it's set, then a new socket can be
853 * bound over an existing listening socket. There's a new
854 * windows-specific option called SO_EXCLUSIVEADDRUSE but
855 * using that means the socket MUST be closed properly, or a
856 * denial of service can occur. Luckily for us, winsock
857 * behaves as though any other system would when SO_REUSEADDR
858 * is true, so we don't need to do anything else here. See
860 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
865 ret = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &true_,
870 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__);
872 errnum = errno_to_WSA (errnum, __func__);
873 WSASetLastError (errnum);
877 return(INVALID_SOCKET);
882 mono_once (&socket_ops_once, socket_ops_init);
884 handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, &socket_handle);
885 if (handle == _WAPI_HANDLE_INVALID) {
886 g_warning ("%s: error creating socket handle", __func__);
887 WSASetLastError (WSASYSCALLFAILURE);
889 return(INVALID_SOCKET);
892 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, handle);
897 static gboolean socket_disconnect (guint32 fd)
899 struct _WapiHandle_socket *socket_handle;
901 gpointer handle = GUINT_TO_POINTER (fd);
904 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
905 (gpointer *)&socket_handle);
907 g_warning ("%s: error looking up socket handle %p", __func__,
909 WSASetLastError (WSAENOTSOCK);
913 newsock = socket (socket_handle->domain, socket_handle->type,
914 socket_handle->protocol);
918 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, strerror (errno));
920 errnum = errno_to_WSA (errnum, __func__);
921 WSASetLastError (errnum);
926 /* According to Stevens "Advanced Programming in the UNIX
927 * Environment: UNIX File I/O" dup2() is atomic so there
928 * should not be a race condition between the old fd being
929 * closed and the new socket fd being copied over
932 ret = dup2 (newsock, fd);
933 } while (ret == -1 && errno == EAGAIN);
938 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dup2 error: %s", __func__, strerror (errno));
940 errnum = errno_to_WSA (errnum, __func__);
941 WSASetLastError (errnum);
951 static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped,
952 guint32 flags, guint32 reserved)
954 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, fd);
957 WSASetLastError (WSAEINVAL);
961 /* We could check the socket type here and fail unless its
962 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
963 * if we really wanted to
966 return(socket_disconnect (fd));
969 #define SF_BUFFER_SIZE 16384
971 wapi_sendfile (guint32 socket, gpointer fd, guint32 bytes_to_write, guint32 bytes_per_send, guint32 flags)
973 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
974 gint file = GPOINTER_TO_INT (fd);
980 n = fstat (file, &statbuf);
983 errnum = errno_to_WSA (errnum, __func__);
984 WSASetLastError (errnum);
989 res = sendfile (socket, file, NULL, statbuf.st_size);
990 #elif defined(DARWIN)
991 /* TODO: header/tail could be sent in the 5th argument */
992 /* TODO: Might not send the entire file for non-blocking sockets */
993 res = sendfile (file, socket, 0, &statbuf.st_size, NULL, 0);
995 } while (res != -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
998 errnum = errno_to_WSA (errnum, __func__);
999 WSASetLastError (errnum);
1000 return SOCKET_ERROR;
1003 /* Default implementation */
1004 gint file = GPOINTER_TO_INT (fd);
1008 buffer = g_malloc (SF_BUFFER_SIZE);
1011 n = read (file, buffer, SF_BUFFER_SIZE);
1012 } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
1017 return 0; /* We're done reading */
1020 n = send (socket, buffer, n, 0); /* short sends? enclose this in a loop? */
1021 } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
1022 } while (n != -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
1025 gint errnum = errno;
1026 errnum = errno_to_WSA (errnum, __func__);
1027 WSASetLastError (errnum);
1029 return SOCKET_ERROR;
1037 TransmitFile (guint32 socket, gpointer file, guint32 bytes_to_write, guint32 bytes_per_send, WapiOverlapped *ol,
1038 WapiTransmitFileBuffers *buffers, guint32 flags)
1040 gpointer sock = GUINT_TO_POINTER (socket);
1043 if (_wapi_handle_type (sock) != WAPI_HANDLE_SOCKET) {
1044 WSASetLastError (WSAENOTSOCK);
1048 /* Write the header */
1049 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
1050 ret = _wapi_send (socket, buffers->Head, buffers->HeadLength, 0);
1051 if (ret == SOCKET_ERROR)
1055 ret = wapi_sendfile (socket, file, bytes_to_write, bytes_per_send, flags);
1056 if (ret == SOCKET_ERROR)
1059 /* Write the tail */
1060 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
1061 ret = _wapi_send (socket, buffers->Tail, buffers->TailLength, 0);
1062 if (ret == SOCKET_ERROR)
1066 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
1067 closesocket (socket);
1076 } extension_functions[] = {
1077 {WSAID_DISCONNECTEX, wapi_disconnectex},
1078 {WSAID_TRANSMITFILE, TransmitFile},
1083 WSAIoctl (guint32 fd, gint32 command,
1084 gchar *input, gint i_len,
1085 gchar *output, gint o_len, glong *written,
1086 void *unused1, void *unused2)
1088 gpointer handle = GUINT_TO_POINTER (fd);
1090 gchar *buffer = NULL;
1092 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1093 WSASetLastError (WSAENOTSOCK);
1094 return SOCKET_ERROR;
1097 if (command == SIO_GET_EXTENSION_FUNCTION_POINTER) {
1099 WapiGuid *guid = (WapiGuid *)input;
1101 if (i_len < sizeof(WapiGuid)) {
1102 /* As far as I can tell, windows doesn't
1103 * actually set an error here...
1105 WSASetLastError (WSAEINVAL);
1106 return(SOCKET_ERROR);
1109 if (o_len < sizeof(gpointer)) {
1111 WSASetLastError (WSAEINVAL);
1112 return(SOCKET_ERROR);
1115 if (output == NULL) {
1117 WSASetLastError (WSAEINVAL);
1118 return(SOCKET_ERROR);
1121 while(extension_functions[i].func != NULL) {
1122 if (!memcmp (guid, &extension_functions[i].guid,
1123 sizeof(WapiGuid))) {
1124 memcpy (output, &extension_functions[i].func,
1126 *written = sizeof(gpointer);
1133 WSASetLastError (WSAEINVAL);
1134 return(SOCKET_ERROR);
1137 if (command == SIO_KEEPALIVE_VALS) {
1139 uint32_t keepalivetime;
1140 uint32_t keepaliveinterval;
1142 if (i_len < (3 * sizeof (uint32_t))) {
1143 WSASetLastError (WSAEINVAL);
1144 return SOCKET_ERROR;
1146 memcpy (&onoff, input, sizeof (uint32_t));
1147 memcpy (&keepalivetime, input + sizeof (uint32_t), sizeof (uint32_t));
1148 memcpy (&keepaliveinterval, input + 2 * sizeof (uint32_t), sizeof (uint32_t));
1149 ret = setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (uint32_t));
1151 gint errnum = errno;
1152 errnum = errno_to_WSA (errnum, __func__);
1153 WSASetLastError (errnum);
1154 return SOCKET_ERROR;
1157 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1158 /* Values are in ms, but we need s */
1161 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1162 rem = keepalivetime % 1000;
1163 keepalivetime /= 1000;
1164 if (keepalivetime == 0 || rem >= 500)
1166 ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (uint32_t));
1168 rem = keepaliveinterval % 1000;
1169 keepaliveinterval /= 1000;
1170 if (keepaliveinterval == 0 || rem >= 500)
1171 keepaliveinterval++;
1172 ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (uint32_t));
1175 gint errnum = errno;
1176 errnum = errno_to_WSA (errnum, __func__);
1177 WSASetLastError (errnum);
1178 return SOCKET_ERROR;
1187 buffer = (char *)g_memdup (input, i_len);
1190 ret = ioctl (fd, command, buffer);
1192 gint errnum = errno;
1193 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__,
1196 errnum = errno_to_WSA (errnum, __func__);
1197 WSASetLastError (errnum);
1200 return(SOCKET_ERROR);
1203 if (buffer == NULL) {
1206 /* We just copy the buffer to the output. Some ioctls
1207 * don't even output any data, but, well...
1209 * NB windows returns WSAEFAULT if o_len is too small
1211 i_len = (i_len > o_len) ? o_len : i_len;
1213 if (i_len > 0 && output != NULL) {
1214 memcpy (output, buffer, i_len);
1224 #ifndef PLATFORM_PORT_PROVIDES_IOCTLSOCKET
1225 int ioctlsocket(guint32 fd, unsigned long command, gpointer arg)
1227 gpointer handle = GUINT_TO_POINTER (fd);
1230 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1231 WSASetLastError (WSAENOTSOCK);
1232 return(SOCKET_ERROR);
1238 /* This works better than ioctl(...FIONBIO...)
1239 * on Linux (it causes connect to return
1240 * EINPROGRESS, but the ioctl doesn't seem to)
1242 ret = fcntl(fd, F_GETFL, 0);
1244 if (*(gboolean *)arg) {
1249 ret = fcntl(fd, F_SETFL, ret);
1252 #endif /* O_NONBLOCK */
1253 /* Unused in Mono */
1255 ret = ioctl (fd, command, arg);
1260 #if defined (PLATFORM_MACOSX)
1262 // ioctl (fd, FIONREAD, XXX) returns the size of
1263 // the UDP header as well on
1266 // Use getsockopt SO_NREAD instead to get the
1267 // right values for TCP and UDP.
1269 // ai_canonname can be null in some cases on darwin, where the runtime assumes it will
1270 // be the value of the ip buffer.
1272 socklen_t optlen = sizeof (int);
1273 ret = getsockopt (fd, SOL_SOCKET, SO_NREAD, arg, &optlen);
1275 ret = ioctl (fd, command, arg);
1280 WSASetLastError (WSAEINVAL);
1281 return(SOCKET_ERROR);
1285 gint errnum = errno;
1286 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, strerror (errno));
1288 errnum = errno_to_WSA (errnum, __func__);
1289 WSASetLastError (errnum);
1291 return(SOCKET_ERROR);
1297 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
1298 fd_set *exceptfds, struct timeval *timeout)
1302 for (maxfd = FD_SETSIZE-1; maxfd >= 0; maxfd--) {
1303 if ((readfds && FD_ISSET (maxfd, readfds)) ||
1304 (writefds && FD_ISSET (maxfd, writefds)) ||
1305 (exceptfds && FD_ISSET (maxfd, exceptfds))) {
1311 WSASetLastError (WSAEINVAL);
1312 return(SOCKET_ERROR);
1316 ret = select(maxfd + 1, readfds, writefds, exceptfds,
1318 } while (ret == -1 && errno == EINTR &&
1319 !_wapi_thread_cur_apc_pending ());
1322 gint errnum = errno;
1323 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: select error: %s", __func__, strerror (errno));
1324 errnum = errno_to_WSA (errnum, __func__);
1325 WSASetLastError (errnum);
1327 return(SOCKET_ERROR);
1333 void _wapi_FD_CLR(guint32 fd, fd_set *set)
1335 gpointer handle = GUINT_TO_POINTER (fd);
1337 if (fd >= FD_SETSIZE) {
1338 WSASetLastError (WSAEINVAL);
1342 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1343 WSASetLastError (WSAENOTSOCK);
1350 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
1352 gpointer handle = GUINT_TO_POINTER (fd);
1354 if (fd >= FD_SETSIZE) {
1355 WSASetLastError (WSAEINVAL);
1359 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1360 WSASetLastError (WSAENOTSOCK);
1364 return(FD_ISSET (fd, set));
1367 void _wapi_FD_SET(guint32 fd, fd_set *set)
1369 gpointer handle = GUINT_TO_POINTER (fd);
1371 if (fd >= FD_SETSIZE) {
1372 WSASetLastError (WSAEINVAL);
1376 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1377 WSASetLastError (WSAENOTSOCK);
1386 wsabuf_to_msghdr (WapiWSABuf *buffers, guint32 count, struct msghdr *hdr)
1390 memset (hdr, 0, sizeof (struct msghdr));
1391 hdr->msg_iovlen = count;
1392 hdr->msg_iov = g_new0 (struct iovec, count);
1393 for (i = 0; i < count; i++) {
1394 hdr->msg_iov [i].iov_base = buffers [i].buf;
1395 hdr->msg_iov [i].iov_len = buffers [i].len;
1400 msghdr_iov_free (struct msghdr *hdr)
1402 g_free (hdr->msg_iov);
1405 int WSARecv (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *received,
1406 guint32 *flags, WapiOverlapped *overlapped,
1407 WapiOverlappedCB *complete)
1412 g_assert (overlapped == NULL);
1413 g_assert (complete == NULL);
1415 wsabuf_to_msghdr (buffers, count, &hdr);
1416 ret = _wapi_recvmsg (fd, &hdr, *flags);
1417 msghdr_iov_free (&hdr);
1419 if(ret == SOCKET_ERROR) {
1424 *flags = hdr.msg_flags;
1429 int WSASend (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *sent,
1430 guint32 flags, WapiOverlapped *overlapped,
1431 WapiOverlappedCB *complete)
1436 g_assert (overlapped == NULL);
1437 g_assert (complete == NULL);
1439 wsabuf_to_msghdr (buffers, count, &hdr);
1440 ret = _wapi_sendmsg (fd, &hdr, flags);
1441 msghdr_iov_free (&hdr);
1443 if(ret == SOCKET_ERROR)
1450 #endif /* ifndef DISABLE_SOCKETS */