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);
64 struct _WapiHandleOps _wapi_socket_ops = {
65 socket_close, /* close */
69 NULL, /* special_wait */
71 socket_details /* details */
74 static mono_once_t socket_ops_once=MONO_ONCE_INIT;
76 static void socket_ops_init (void)
78 /* No capabilities to register */
81 static void socket_close (gpointer handle, gpointer data)
84 struct _WapiHandle_socket *socket_handle = (struct _WapiHandle_socket *)data;
86 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle);
88 /* Shutdown the socket for reading, to interrupt any potential
89 * receives that may be blocking for data. See bug 75705.
91 shutdown (GPOINTER_TO_UINT (handle), SHUT_RD);
94 ret = close (GPOINTER_TO_UINT(handle));
95 } while (ret == -1 && errno == EINTR &&
96 !_wapi_thread_cur_apc_pending ());
100 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: close error: %s", __func__, strerror (errno));
101 errnum = errno_to_WSA (errnum, __func__);
103 WSASetLastError (errnum);
107 socket_handle->saved_error = 0;
110 static void socket_details (gpointer data)
112 /* FIXME: do something */
116 cleanup_close (gpointer handle, gpointer data)
118 _wapi_handle_ops_close (handle, NULL);
122 void _wapi_cleanup_networking(void)
124 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: cleaning up", __func__);
127 _wapi_handle_foreach (WAPI_HANDLE_SOCKET, cleanup_close, NULL);
131 void WSASetLastError(int error)
133 SetLastError (error);
136 int WSAGetLastError(void)
138 return(GetLastError ());
141 int closesocket(guint32 fd)
143 gpointer handle = GUINT_TO_POINTER (fd);
145 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
146 WSASetLastError (WSAENOTSOCK);
150 _wapi_handle_unref (handle);
154 guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen)
156 gpointer handle = GUINT_TO_POINTER (fd);
158 struct _WapiHandle_socket *socket_handle;
159 struct _WapiHandle_socket new_socket_handle = {0};
163 if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
164 WSASetLastError (WSAEFAULT);
165 return(INVALID_SOCKET);
168 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
169 WSASetLastError (WSAENOTSOCK);
170 return(INVALID_SOCKET);
173 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
174 (gpointer *)&socket_handle);
176 g_warning ("%s: error looking up socket handle %p",
178 WSASetLastError (WSAENOTSOCK);
179 return(INVALID_SOCKET);
183 new_fd = accept (fd, addr, addrlen);
184 } while (new_fd == -1 && errno == EINTR &&
185 !_wapi_thread_cur_apc_pending());
189 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, strerror(errno));
191 errnum = errno_to_WSA (errnum, __func__);
192 WSASetLastError (errnum);
194 return(INVALID_SOCKET);
197 if (new_fd >= _wapi_fd_reserve) {
198 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
200 WSASetLastError (WSASYSCALLFAILURE);
204 return(INVALID_SOCKET);
207 new_socket_handle.domain = socket_handle->domain;
208 new_socket_handle.type = socket_handle->type;
209 new_socket_handle.protocol = socket_handle->protocol;
210 new_socket_handle.still_readable = 1;
212 new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd,
214 if(new_handle == _WAPI_HANDLE_INVALID) {
215 g_warning ("%s: error creating socket handle", __func__);
216 WSASetLastError (ERROR_GEN_FAILURE);
217 return(INVALID_SOCKET);
220 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with",
221 __func__, new_handle);
226 int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
228 gpointer handle = GUINT_TO_POINTER (fd);
231 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
232 WSASetLastError (WSAENOTSOCK);
233 return(SOCKET_ERROR);
236 ret = bind (fd, my_addr, addrlen);
239 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, strerror(errno));
240 errnum = errno_to_WSA (errnum, __func__);
241 WSASetLastError (errnum);
243 return(SOCKET_ERROR);
248 int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
251 gpointer handle = GUINT_TO_POINTER (fd);
252 struct _WapiHandle_socket *socket_handle;
256 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
257 WSASetLastError (WSAENOTSOCK);
258 return(SOCKET_ERROR);
261 if (connect (fd, serv_addr, addrlen) == -1) {
268 if (errno != EINTR) {
269 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__,
272 errnum = errno_to_WSA (errnum, __func__);
273 if (errnum == WSAEINPROGRESS)
274 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
276 WSASetLastError (errnum);
279 * On solaris x86 getsockopt (SO_ERROR) is not set after
280 * connect () fails so we need to save this error.
282 * But don't do this for EWOULDBLOCK (bug 317315)
284 if (errnum != WSAEWOULDBLOCK) {
285 ok = _wapi_lookup_handle (handle,
287 (gpointer *)&socket_handle);
289 /* ECONNRESET means the socket was closed by another thread */
290 /* Async close on mac raises ECONNABORTED. */
291 if (errnum != WSAECONNRESET && errnum != WSAENETDOWN)
292 g_warning ("%s: error looking up socket handle %p (error %d)", __func__, handle, errnum);
294 socket_handle->saved_error = errnum;
297 return(SOCKET_ERROR);
301 fds.events = MONO_POLLOUT;
302 while (mono_poll (&fds, 1, -1) == -1 &&
303 !_wapi_thread_cur_apc_pending ()) {
304 if (errno != EINTR) {
305 errnum = errno_to_WSA (errno, __func__);
307 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s",
308 __func__, strerror (errno));
310 WSASetLastError (errnum);
311 return(SOCKET_ERROR);
315 len = sizeof(so_error);
316 if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &so_error,
318 errnum = errno_to_WSA (errno, __func__);
320 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s",
321 __func__, strerror (errno));
323 WSASetLastError (errnum);
324 return(SOCKET_ERROR);
328 errnum = errno_to_WSA (so_error, __func__);
330 /* Need to save this socket error */
331 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
332 (gpointer *)&socket_handle);
334 g_warning ("%s: error looking up socket handle %p", __func__, handle);
336 socket_handle->saved_error = errnum;
339 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s",
340 __func__, strerror (so_error));
342 WSASetLastError (errnum);
343 return(SOCKET_ERROR);
350 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
352 gpointer handle = GUINT_TO_POINTER (fd);
355 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
356 WSASetLastError (WSAENOTSOCK);
357 return(SOCKET_ERROR);
360 ret = getpeername (fd, name, namelen);
363 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__,
366 errnum = errno_to_WSA (errnum, __func__);
367 WSASetLastError (errnum);
369 return(SOCKET_ERROR);
375 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
377 gpointer handle = GUINT_TO_POINTER (fd);
380 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
381 WSASetLastError (WSAENOTSOCK);
382 return(SOCKET_ERROR);
385 ret = getsockname (fd, name, namelen);
388 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__,
391 errnum = errno_to_WSA (errnum, __func__);
392 WSASetLastError (errnum);
394 return(SOCKET_ERROR);
400 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
403 gpointer handle = GUINT_TO_POINTER (fd);
407 struct _WapiHandle_socket *socket_handle;
410 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
411 WSASetLastError (WSAENOTSOCK);
412 return(SOCKET_ERROR);
416 if (level == SOL_SOCKET &&
417 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
419 *optlen = sizeof (tv);
422 ret = getsockopt (fd, level, optname, tmp_val, optlen);
425 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__,
428 errnum = errno_to_WSA (errnum, __func__);
429 WSASetLastError (errnum);
431 return(SOCKET_ERROR);
434 if (level == SOL_SOCKET &&
435 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
436 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
437 *optlen = sizeof (int);
440 if (optname == SO_ERROR) {
441 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
442 (gpointer *)&socket_handle);
444 g_warning ("%s: error looking up socket handle %p",
447 /* can't extract the last error */
448 *((int *) optval) = errno_to_WSA (*((int *)optval),
451 if (*((int *)optval) != 0) {
452 *((int *) optval) = errno_to_WSA (*((int *)optval),
454 socket_handle->saved_error = *((int *)optval);
456 *((int *)optval) = socket_handle->saved_error;
464 int _wapi_listen(guint32 fd, int backlog)
466 gpointer handle = GUINT_TO_POINTER (fd);
469 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
470 WSASetLastError (WSAENOTSOCK);
471 return(SOCKET_ERROR);
474 ret = listen (fd, backlog);
477 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, strerror (errno));
479 errnum = errno_to_WSA (errnum, __func__);
480 WSASetLastError (errnum);
482 return(SOCKET_ERROR);
488 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
490 return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
493 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
494 struct sockaddr *from, socklen_t *fromlen)
496 gpointer handle = GUINT_TO_POINTER (fd);
497 struct _WapiHandle_socket *socket_handle;
501 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
502 WSASetLastError (WSAENOTSOCK);
503 return(SOCKET_ERROR);
507 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
508 } while (ret == -1 && errno == EINTR &&
509 !_wapi_thread_cur_apc_pending ());
511 if (ret == 0 && len > 0) {
512 /* According to the Linux man page, recvfrom only
513 * returns 0 when the socket has been shut down
514 * cleanly. Turn this into an EINTR to simulate win32
515 * behaviour of returning EINTR when a socket is
516 * closed while the recvfrom is blocking (we use a
517 * shutdown() in socket_close() to trigger this.) See
520 /* Distinguish between the socket being shut down at
521 * the local or remote ends, and reads that request 0
525 /* If this returns FALSE, it means the socket has been
526 * closed locally. If it returns TRUE, but
527 * still_readable != 1 then shutdown
528 * (SHUT_RD|SHUT_RDWR) has been called locally.
530 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
531 (gpointer *)&socket_handle);
532 if (ok == FALSE || socket_handle->still_readable != 1) {
540 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, strerror(errno));
542 errnum = errno_to_WSA (errnum, __func__);
543 WSASetLastError (errnum);
545 return(SOCKET_ERROR);
551 _wapi_recvmsg(guint32 fd, struct msghdr *msg, int recv_flags)
553 gpointer handle = GUINT_TO_POINTER (fd);
554 struct _WapiHandle_socket *socket_handle;
558 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
559 WSASetLastError (WSAENOTSOCK);
560 return(SOCKET_ERROR);
564 ret = recvmsg (fd, msg, recv_flags);
565 } while (ret == -1 && errno == EINTR &&
566 !_wapi_thread_cur_apc_pending ());
569 /* see _wapi_recvfrom */
570 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
571 (gpointer *)&socket_handle);
572 if (ok == FALSE || socket_handle->still_readable != 1) {
580 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, strerror(errno));
582 errnum = errno_to_WSA (errnum, __func__);
583 WSASetLastError (errnum);
585 return(SOCKET_ERROR);
590 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
592 gpointer handle = GUINT_TO_POINTER (fd);
595 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
596 WSASetLastError (WSAENOTSOCK);
597 return(SOCKET_ERROR);
601 ret = send (fd, msg, len, send_flags);
602 } while (ret == -1 && errno == EINTR &&
603 !_wapi_thread_cur_apc_pending ());
607 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, strerror (errno));
610 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
611 * a blocking socket. See bug #599488 */
612 if (errnum == EAGAIN) {
613 ret = fcntl (fd, F_GETFL, 0);
614 if (ret != -1 && (ret & O_NONBLOCK) == 0)
617 #endif /* O_NONBLOCK */
618 errnum = errno_to_WSA (errnum, __func__);
619 WSASetLastError (errnum);
621 return(SOCKET_ERROR);
626 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
627 const struct sockaddr *to, socklen_t tolen)
629 gpointer handle = GUINT_TO_POINTER (fd);
632 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
633 WSASetLastError (WSAENOTSOCK);
634 return(SOCKET_ERROR);
638 ret = sendto (fd, msg, len, send_flags, to, tolen);
639 } while (ret == -1 && errno == EINTR &&
640 !_wapi_thread_cur_apc_pending ());
644 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, strerror (errno));
646 errnum = errno_to_WSA (errnum, __func__);
647 WSASetLastError (errnum);
649 return(SOCKET_ERROR);
655 _wapi_sendmsg(guint32 fd, const struct msghdr *msg, int send_flags)
657 gpointer handle = GUINT_TO_POINTER (fd);
660 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
661 WSASetLastError (WSAENOTSOCK);
662 return(SOCKET_ERROR);
666 ret = sendmsg (fd, msg, send_flags);
667 } while (ret == -1 && errno == EINTR &&
668 !_wapi_thread_cur_apc_pending ());
672 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, strerror (errno));
674 errnum = errno_to_WSA (errnum, __func__);
675 WSASetLastError (errnum);
677 return(SOCKET_ERROR);
682 int _wapi_setsockopt(guint32 fd, int level, int optname,
683 const void *optval, socklen_t optlen)
685 gpointer handle = GUINT_TO_POINTER (fd);
688 #if defined (__linux__)
689 /* This has its address taken so it cannot be moved to the if block which uses it */
694 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
695 WSASetLastError (WSAENOTSOCK);
696 return(SOCKET_ERROR);
700 if (level == SOL_SOCKET &&
701 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
702 int ms = *((int *) optval);
703 tv.tv_sec = ms / 1000;
704 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
706 optlen = sizeof (tv);
708 #if defined (__linux__)
709 else if (level == SOL_SOCKET &&
710 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
711 /* According to socket(7) the Linux kernel doubles the
712 * buffer sizes "to allow space for bookkeeping
715 bufsize = *((int *) optval);
722 ret = setsockopt (fd, level, optname, tmp_val, optlen);
725 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__,
728 errnum = errno_to_WSA (errnum, __func__);
729 WSASetLastError (errnum);
731 return(SOCKET_ERROR);
734 #if defined (SO_REUSEPORT)
735 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
736 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
738 socklen_t type_len = sizeof (type);
740 if (!getsockopt (fd, level, SO_TYPE, &type, &type_len)) {
741 if (type == SOCK_DGRAM || type == SOCK_STREAM)
742 setsockopt (fd, level, SO_REUSEPORT, tmp_val, optlen);
750 int _wapi_shutdown(guint32 fd, int how)
752 struct _WapiHandle_socket *socket_handle;
754 gpointer handle = GUINT_TO_POINTER (fd);
757 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
758 WSASetLastError (WSAENOTSOCK);
759 return(SOCKET_ERROR);
762 if (how == SHUT_RD ||
764 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
765 (gpointer *)&socket_handle);
767 g_warning ("%s: error looking up socket handle %p",
769 WSASetLastError (WSAENOTSOCK);
770 return(SOCKET_ERROR);
773 socket_handle->still_readable = 0;
776 ret = shutdown (fd, how);
779 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__,
782 errnum = errno_to_WSA (errnum, __func__);
783 WSASetLastError (errnum);
785 return(SOCKET_ERROR);
791 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
792 guint32 unused2, guint32 unused3)
794 struct _WapiHandle_socket socket_handle = {0};
798 socket_handle.domain = domain;
799 socket_handle.type = type;
800 socket_handle.protocol = protocol;
801 socket_handle.still_readable = 1;
803 fd = socket (domain, type, protocol);
804 if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
806 /* Retry with protocol == 4 (see bug #54565) */
807 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
808 socket_handle.protocol = 4;
809 fd = socket (AF_INET, SOCK_RAW, 4);
814 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, strerror (errno));
815 errnum = errno_to_WSA (errnum, __func__);
816 WSASetLastError (errnum);
818 return(INVALID_SOCKET);
821 if (fd >= _wapi_fd_reserve) {
822 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big (%d >= %d)",
823 __func__, fd, _wapi_fd_reserve);
825 WSASetLastError (WSASYSCALLFAILURE);
828 return(INVALID_SOCKET);
831 /* .net seems to set this by default for SOCK_STREAM, not for
832 * SOCK_DGRAM (see bug #36322)
833 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
835 * It seems winsock has a rather different idea of what
836 * SO_REUSEADDR means. If it's set, then a new socket can be
837 * bound over an existing listening socket. There's a new
838 * windows-specific option called SO_EXCLUSIVEADDRUSE but
839 * using that means the socket MUST be closed properly, or a
840 * denial of service can occur. Luckily for us, winsock
841 * behaves as though any other system would when SO_REUSEADDR
842 * is true, so we don't need to do anything else here. See
844 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
849 ret = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &true_,
854 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__);
856 errnum = errno_to_WSA (errnum, __func__);
857 WSASetLastError (errnum);
861 return(INVALID_SOCKET);
866 mono_once (&socket_ops_once, socket_ops_init);
868 handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, &socket_handle);
869 if (handle == _WAPI_HANDLE_INVALID) {
870 g_warning ("%s: error creating socket handle", __func__);
871 WSASetLastError (WSASYSCALLFAILURE);
873 return(INVALID_SOCKET);
876 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, handle);
881 static gboolean socket_disconnect (guint32 fd)
883 struct _WapiHandle_socket *socket_handle;
885 gpointer handle = GUINT_TO_POINTER (fd);
888 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
889 (gpointer *)&socket_handle);
891 g_warning ("%s: error looking up socket handle %p", __func__,
893 WSASetLastError (WSAENOTSOCK);
897 newsock = socket (socket_handle->domain, socket_handle->type,
898 socket_handle->protocol);
902 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, strerror (errno));
904 errnum = errno_to_WSA (errnum, __func__);
905 WSASetLastError (errnum);
910 /* According to Stevens "Advanced Programming in the UNIX
911 * Environment: UNIX File I/O" dup2() is atomic so there
912 * should not be a race condition between the old fd being
913 * closed and the new socket fd being copied over
916 ret = dup2 (newsock, fd);
917 } while (ret == -1 && errno == EAGAIN);
922 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dup2 error: %s", __func__, strerror (errno));
924 errnum = errno_to_WSA (errnum, __func__);
925 WSASetLastError (errnum);
935 static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped,
936 guint32 flags, guint32 reserved)
938 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, fd);
941 WSASetLastError (WSAEINVAL);
945 /* We could check the socket type here and fail unless its
946 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
947 * if we really wanted to
950 return(socket_disconnect (fd));
953 #define SF_BUFFER_SIZE 16384
955 wapi_sendfile (guint32 socket, gpointer fd, guint32 bytes_to_write, guint32 bytes_per_send, guint32 flags)
957 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
958 gint file = GPOINTER_TO_INT (fd);
964 n = fstat (file, &statbuf);
967 errnum = errno_to_WSA (errnum, __func__);
968 WSASetLastError (errnum);
973 res = sendfile (socket, file, NULL, statbuf.st_size);
974 #elif defined(DARWIN)
975 /* TODO: header/tail could be sent in the 5th argument */
976 /* TODO: Might not send the entire file for non-blocking sockets */
977 res = sendfile (file, socket, 0, &statbuf.st_size, NULL, 0);
979 } while (res != -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
982 errnum = errno_to_WSA (errnum, __func__);
983 WSASetLastError (errnum);
987 /* Default implementation */
988 gint file = GPOINTER_TO_INT (fd);
992 buffer = g_malloc (SF_BUFFER_SIZE);
995 n = read (file, buffer, SF_BUFFER_SIZE);
996 } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
1001 return 0; /* We're done reading */
1004 n = send (socket, buffer, n, 0); /* short sends? enclose this in a loop? */
1005 } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
1006 } while (n != -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ());
1009 gint errnum = errno;
1010 errnum = errno_to_WSA (errnum, __func__);
1011 WSASetLastError (errnum);
1013 return SOCKET_ERROR;
1021 TransmitFile (guint32 socket, gpointer file, guint32 bytes_to_write, guint32 bytes_per_send, WapiOverlapped *ol,
1022 WapiTransmitFileBuffers *buffers, guint32 flags)
1024 gpointer sock = GUINT_TO_POINTER (socket);
1027 if (_wapi_handle_type (sock) != WAPI_HANDLE_SOCKET) {
1028 WSASetLastError (WSAENOTSOCK);
1032 /* Write the header */
1033 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
1034 ret = _wapi_send (socket, buffers->Head, buffers->HeadLength, 0);
1035 if (ret == SOCKET_ERROR)
1039 ret = wapi_sendfile (socket, file, bytes_to_write, bytes_per_send, flags);
1040 if (ret == SOCKET_ERROR)
1043 /* Write the tail */
1044 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
1045 ret = _wapi_send (socket, buffers->Tail, buffers->TailLength, 0);
1046 if (ret == SOCKET_ERROR)
1050 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
1051 closesocket (socket);
1060 } extension_functions[] = {
1061 {WSAID_DISCONNECTEX, wapi_disconnectex},
1062 {WSAID_TRANSMITFILE, TransmitFile},
1067 WSAIoctl (guint32 fd, gint32 command,
1068 gchar *input, gint i_len,
1069 gchar *output, gint o_len, glong *written,
1070 void *unused1, void *unused2)
1072 gpointer handle = GUINT_TO_POINTER (fd);
1074 gchar *buffer = NULL;
1076 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1077 WSASetLastError (WSAENOTSOCK);
1078 return SOCKET_ERROR;
1081 if (command == SIO_GET_EXTENSION_FUNCTION_POINTER) {
1083 WapiGuid *guid = (WapiGuid *)input;
1085 if (i_len < sizeof(WapiGuid)) {
1086 /* As far as I can tell, windows doesn't
1087 * actually set an error here...
1089 WSASetLastError (WSAEINVAL);
1090 return(SOCKET_ERROR);
1093 if (o_len < sizeof(gpointer)) {
1095 WSASetLastError (WSAEINVAL);
1096 return(SOCKET_ERROR);
1099 if (output == NULL) {
1101 WSASetLastError (WSAEINVAL);
1102 return(SOCKET_ERROR);
1105 while(extension_functions[i].func != NULL) {
1106 if (!memcmp (guid, &extension_functions[i].guid,
1107 sizeof(WapiGuid))) {
1108 memcpy (output, &extension_functions[i].func,
1110 *written = sizeof(gpointer);
1117 WSASetLastError (WSAEINVAL);
1118 return(SOCKET_ERROR);
1121 if (command == SIO_KEEPALIVE_VALS) {
1123 uint32_t keepalivetime;
1124 uint32_t keepaliveinterval;
1126 if (i_len < (3 * sizeof (uint32_t))) {
1127 WSASetLastError (WSAEINVAL);
1128 return SOCKET_ERROR;
1130 memcpy (&onoff, input, sizeof (uint32_t));
1131 memcpy (&keepalivetime, input + sizeof (uint32_t), sizeof (uint32_t));
1132 memcpy (&keepaliveinterval, input + 2 * sizeof (uint32_t), sizeof (uint32_t));
1133 ret = setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (uint32_t));
1135 gint errnum = errno;
1136 errnum = errno_to_WSA (errnum, __func__);
1137 WSASetLastError (errnum);
1138 return SOCKET_ERROR;
1141 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1142 /* Values are in ms, but we need s */
1145 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1146 rem = keepalivetime % 1000;
1147 keepalivetime /= 1000;
1148 if (keepalivetime == 0 || rem >= 500)
1150 ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (uint32_t));
1152 rem = keepaliveinterval % 1000;
1153 keepaliveinterval /= 1000;
1154 if (keepaliveinterval == 0 || rem >= 500)
1155 keepaliveinterval++;
1156 ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (uint32_t));
1159 gint errnum = errno;
1160 errnum = errno_to_WSA (errnum, __func__);
1161 WSASetLastError (errnum);
1162 return SOCKET_ERROR;
1171 buffer = (char *)g_memdup (input, i_len);
1174 ret = ioctl (fd, command, buffer);
1176 gint errnum = errno;
1177 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__,
1180 errnum = errno_to_WSA (errnum, __func__);
1181 WSASetLastError (errnum);
1184 return(SOCKET_ERROR);
1187 if (buffer == NULL) {
1190 /* We just copy the buffer to the output. Some ioctls
1191 * don't even output any data, but, well...
1193 * NB windows returns WSAEFAULT if o_len is too small
1195 i_len = (i_len > o_len) ? o_len : i_len;
1197 if (i_len > 0 && output != NULL) {
1198 memcpy (output, buffer, i_len);
1208 #ifndef PLATFORM_PORT_PROVIDES_IOCTLSOCKET
1209 int ioctlsocket(guint32 fd, unsigned long command, gpointer arg)
1211 gpointer handle = GUINT_TO_POINTER (fd);
1214 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1215 WSASetLastError (WSAENOTSOCK);
1216 return(SOCKET_ERROR);
1222 /* This works better than ioctl(...FIONBIO...)
1223 * on Linux (it causes connect to return
1224 * EINPROGRESS, but the ioctl doesn't seem to)
1226 ret = fcntl(fd, F_GETFL, 0);
1228 if (*(gboolean *)arg) {
1233 ret = fcntl(fd, F_SETFL, ret);
1236 #endif /* O_NONBLOCK */
1237 /* Unused in Mono */
1239 ret = ioctl (fd, command, arg);
1244 #if defined (PLATFORM_MACOSX)
1246 // ioctl (fd, FIONREAD, XXX) returns the size of
1247 // the UDP header as well on
1250 // Use getsockopt SO_NREAD instead to get the
1251 // right values for TCP and UDP.
1253 // ai_canonname can be null in some cases on darwin, where the runtime assumes it will
1254 // be the value of the ip buffer.
1256 socklen_t optlen = sizeof (int);
1257 ret = getsockopt (fd, SOL_SOCKET, SO_NREAD, arg, &optlen);
1259 ret = ioctl (fd, command, arg);
1264 WSASetLastError (WSAEINVAL);
1265 return(SOCKET_ERROR);
1269 gint errnum = errno;
1270 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, strerror (errno));
1272 errnum = errno_to_WSA (errnum, __func__);
1273 WSASetLastError (errnum);
1275 return(SOCKET_ERROR);
1281 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
1282 fd_set *exceptfds, struct timeval *timeout)
1286 for (maxfd = FD_SETSIZE-1; maxfd >= 0; maxfd--) {
1287 if ((readfds && FD_ISSET (maxfd, readfds)) ||
1288 (writefds && FD_ISSET (maxfd, writefds)) ||
1289 (exceptfds && FD_ISSET (maxfd, exceptfds))) {
1295 WSASetLastError (WSAEINVAL);
1296 return(SOCKET_ERROR);
1300 ret = select(maxfd + 1, readfds, writefds, exceptfds,
1302 } while (ret == -1 && errno == EINTR &&
1303 !_wapi_thread_cur_apc_pending ());
1306 gint errnum = errno;
1307 MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: select error: %s", __func__, strerror (errno));
1308 errnum = errno_to_WSA (errnum, __func__);
1309 WSASetLastError (errnum);
1311 return(SOCKET_ERROR);
1317 void _wapi_FD_CLR(guint32 fd, fd_set *set)
1319 gpointer handle = GUINT_TO_POINTER (fd);
1321 if (fd >= FD_SETSIZE) {
1322 WSASetLastError (WSAEINVAL);
1326 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1327 WSASetLastError (WSAENOTSOCK);
1334 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
1336 gpointer handle = GUINT_TO_POINTER (fd);
1338 if (fd >= FD_SETSIZE) {
1339 WSASetLastError (WSAEINVAL);
1343 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1344 WSASetLastError (WSAENOTSOCK);
1348 return(FD_ISSET (fd, set));
1351 void _wapi_FD_SET(guint32 fd, fd_set *set)
1353 gpointer handle = GUINT_TO_POINTER (fd);
1355 if (fd >= FD_SETSIZE) {
1356 WSASetLastError (WSAEINVAL);
1360 if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1361 WSASetLastError (WSAENOTSOCK);
1370 wsabuf_to_msghdr (WapiWSABuf *buffers, guint32 count, struct msghdr *hdr)
1374 memset (hdr, 0, sizeof (struct msghdr));
1375 hdr->msg_iovlen = count;
1376 hdr->msg_iov = g_new0 (struct iovec, count);
1377 for (i = 0; i < count; i++) {
1378 hdr->msg_iov [i].iov_base = buffers [i].buf;
1379 hdr->msg_iov [i].iov_len = buffers [i].len;
1384 msghdr_iov_free (struct msghdr *hdr)
1386 g_free (hdr->msg_iov);
1389 int WSARecv (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *received,
1390 guint32 *flags, WapiOverlapped *overlapped,
1391 WapiOverlappedCB *complete)
1396 g_assert (overlapped == NULL);
1397 g_assert (complete == NULL);
1399 wsabuf_to_msghdr (buffers, count, &hdr);
1400 ret = _wapi_recvmsg (fd, &hdr, *flags);
1401 msghdr_iov_free (&hdr);
1403 if(ret == SOCKET_ERROR) {
1408 *flags = hdr.msg_flags;
1413 int WSASend (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *sent,
1414 guint32 flags, WapiOverlapped *overlapped,
1415 WapiOverlappedCB *complete)
1420 g_assert (overlapped == NULL);
1421 g_assert (complete == NULL);
1423 wsabuf_to_msghdr (buffers, count, &hdr);
1424 ret = _wapi_sendmsg (fd, &hdr, flags);
1425 msghdr_iov_free (&hdr);
1427 if(ret == SOCKET_ERROR)
1434 #endif /* ifndef DISABLE_SOCKETS */