Update dependencies from https://github.com/dotnet/arcade build 20190725.3 (#15836)
[mono-project.git] / mono / metadata / w32socket-unix.c
blob6afe95813e6fe72ebf84d5d2306efbb678ebc17c
1 /**
2 * \file
3 * Unix specific socket code.
5 * Copyright 2016 Microsoft
6 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7 */
9 #include <config.h>
10 #include <glib.h>
12 #include <pthread.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #ifdef HAVE_SYS_IOCTL_H
18 #include <sys/ioctl.h>
19 #endif
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
22 #ifdef HAVE_NETDB_H
23 #include <netdb.h>
24 #endif
25 #ifdef HAVE_NETINET_TCP_H
26 #include <arpa/inet.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <errno.h>
32 #include <fcntl.h>
33 #ifdef HAVE_SYS_UIO_H
34 #include <sys/uio.h>
35 #endif
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_SYS_FILIO_H
40 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
41 #endif
42 #ifdef HAVE_SYS_SOCKIO_H
43 #include <sys/sockio.h> /* defines SIOCATMARK */
44 #endif
45 #ifndef HAVE_MSG_NOSIGNAL
46 #include <signal.h>
47 #endif
48 #ifdef HAVE_SYS_SENDFILE_H
49 #include <sys/sendfile.h>
50 #endif
51 #include <sys/stat.h>
53 #include "w32socket.h"
54 #include "w32socket-internals.h"
55 #include "w32error.h"
56 #include "fdhandle.h"
57 #include "utils/mono-logger-internals.h"
58 #include "utils/mono-poll.h"
59 #include "utils/mono-compiler.h"
60 #include "icall-decl.h"
61 #include "utils/mono-errno.h"
63 typedef struct {
64 MonoFDHandle fdhandle;
65 gint domain;
66 gint type;
67 gint protocol;
68 gint saved_error;
69 gint still_readable;
70 } SocketHandle;
72 static SocketHandle*
73 socket_data_create (MonoFDType type, gint fd)
75 SocketHandle *sockethandle;
77 sockethandle = g_new0 (SocketHandle, 1);
78 mono_fdhandle_init ((MonoFDHandle*) sockethandle, type, fd);
80 return sockethandle;
83 static void
84 socket_data_close (MonoFDHandle *fdhandle)
86 MonoThreadInfo *info;
87 SocketHandle* sockethandle;
88 gint ret;
90 sockethandle = (SocketHandle*) fdhandle;
91 g_assert (sockethandle);
93 info = mono_thread_info_current ();
95 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: closing fd %d", __func__, ((MonoFDHandle*) sockethandle)->fd);
97 /* Shutdown the socket for reading, to interrupt any potential
98 * receives that may be blocking for data. See bug 75705. */
99 MONO_ENTER_GC_SAFE;
100 shutdown (((MonoFDHandle*) sockethandle)->fd, SHUT_RD);
101 MONO_EXIT_GC_SAFE;
103 retry_close:
104 MONO_ENTER_GC_SAFE;
105 ret = close (((MonoFDHandle*) sockethandle)->fd);
106 MONO_EXIT_GC_SAFE;
107 if (ret == -1) {
108 if (errno == EINTR && !mono_thread_info_is_interrupt_state (info))
109 goto retry_close;
112 sockethandle->saved_error = 0;
115 static void
116 socket_data_destroy (MonoFDHandle *fdhandle)
118 SocketHandle *sockethandle;
120 sockethandle = (SocketHandle*) fdhandle;
121 g_assert (sockethandle);
123 g_free (sockethandle);
126 void
127 mono_w32socket_initialize (void)
129 MonoFDHandleCallback socket_data_callbacks;
130 memset (&socket_data_callbacks, 0, sizeof (socket_data_callbacks));
131 socket_data_callbacks.close = socket_data_close;
132 socket_data_callbacks.destroy = socket_data_destroy;
134 mono_fdhandle_register (MONO_FDTYPE_SOCKET, &socket_data_callbacks);
137 void
138 mono_w32socket_cleanup (void)
142 SOCKET
143 mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking)
145 SocketHandle *sockethandle, *accepted_socket_data;
146 MonoThreadInfo *info;
147 gint accepted_fd;
149 if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
150 mono_w32socket_set_last_error (WSAEFAULT);
151 return INVALID_SOCKET;
154 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
155 mono_w32error_set_last (WSAENOTSOCK);
156 return INVALID_SOCKET;
159 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
160 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
161 mono_w32error_set_last (WSAENOTSOCK);
162 return INVALID_SOCKET;
165 info = mono_thread_info_current ();
167 do {
168 MONO_ENTER_GC_SAFE;
169 accepted_fd = accept (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
170 MONO_EXIT_GC_SAFE;
171 } while (accepted_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
173 if (accepted_fd == -1) {
174 gint error = mono_w32socket_convert_error (errno);
175 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: accept error: %s", __func__, g_strerror(errno));
176 mono_w32socket_set_last_error (error);
177 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
178 return INVALID_SOCKET;
181 accepted_socket_data = socket_data_create (MONO_FDTYPE_SOCKET, accepted_fd);
182 accepted_socket_data->domain = sockethandle->domain;
183 accepted_socket_data->type = sockethandle->type;
184 accepted_socket_data->protocol = sockethandle->protocol;
185 accepted_socket_data->still_readable = 1;
187 mono_fdhandle_insert ((MonoFDHandle*) accepted_socket_data);
189 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning accepted handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) accepted_socket_data)->fd));
191 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
192 return ((MonoFDHandle*) accepted_socket_data)->fd;
196 mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking)
198 SocketHandle *sockethandle;
199 gint ret;
201 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
202 mono_w32error_set_last (WSAENOTSOCK);
203 return SOCKET_ERROR;
206 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
207 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
208 mono_w32error_set_last (WSAENOTSOCK);
209 return SOCKET_ERROR;
212 MONO_ENTER_GC_SAFE;
213 ret = connect (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
214 MONO_EXIT_GC_SAFE;
215 if (ret == -1) {
216 MonoThreadInfo *info;
217 mono_pollfd fds;
218 gint errnum, so_error;
219 socklen_t len;
221 errnum = errno;
223 if (errno != EINTR) {
224 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect error: %s", __func__,
225 g_strerror (errnum));
227 errnum = mono_w32socket_convert_error (errnum);
228 if (errnum == WSAEINPROGRESS)
229 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
231 mono_w32socket_set_last_error (errnum);
234 * On solaris x86 getsockopt (SO_ERROR) is not set after
235 * connect () fails so we need to save this error.
237 * But don't do this for EWOULDBLOCK (bug 317315)
239 if (errnum != WSAEWOULDBLOCK) {
240 /* ECONNRESET means the socket was closed by another thread */
241 /* Async close on mac raises ECONNABORTED. */
242 sockethandle->saved_error = errnum;
244 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
245 return SOCKET_ERROR;
248 info = mono_thread_info_current ();
250 fds.fd = ((MonoFDHandle*) sockethandle)->fd;
251 fds.events = MONO_POLLOUT;
252 for (;;) {
253 MONO_ENTER_GC_SAFE;
254 ret = mono_poll (&fds, 1, -1);
255 MONO_EXIT_GC_SAFE;
256 if (ret != -1 || mono_thread_info_is_interrupt_state (info))
257 break;
259 if (errno != EINTR) {
260 gint errnum = errno;
261 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect poll error: %s", __func__, g_strerror (errno));
262 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
263 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
264 return SOCKET_ERROR;
268 len = sizeof(so_error);
269 MONO_ENTER_GC_SAFE;
270 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
271 MONO_EXIT_GC_SAFE;
272 if (ret == -1) {
273 gint errnum = errno;
274 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt error: %s", __func__, g_strerror (errno));
275 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
276 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
277 return SOCKET_ERROR;
280 if (so_error != 0) {
281 gint errnum = mono_w32socket_convert_error (so_error);
283 /* Need to save this socket error */
284 sockethandle->saved_error = errnum;
286 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: connect getsockopt returned error: %s",
287 __func__, g_strerror (so_error));
289 mono_w32socket_set_last_error (errnum);
290 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
291 return SOCKET_ERROR;
295 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
296 return 0;
300 mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
302 return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking);
306 mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking)
308 SocketHandle *sockethandle;
309 int ret;
310 MonoThreadInfo *info;
312 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
313 mono_w32error_set_last (WSAENOTSOCK);
314 return SOCKET_ERROR;
317 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
318 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
319 mono_w32error_set_last (WSAENOTSOCK);
320 return SOCKET_ERROR;
323 info = mono_thread_info_current ();
325 do {
326 MONO_ENTER_GC_SAFE;
327 ret = recvfrom (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, from, fromlen);
328 MONO_EXIT_GC_SAFE;
329 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
331 if (ret == 0 && len > 0) {
332 /* According to the Linux man page, recvfrom only
333 * returns 0 when the socket has been shut down
334 * cleanly. Turn this into an EINTR to simulate win32
335 * behaviour of returning EINTR when a socket is
336 * closed while the recvfrom is blocking (we use a
337 * shutdown() in socket_close() to trigger this.) See
338 * bug 75705.
340 /* Distinguish between the socket being shut down at
341 * the local or remote ends, and reads that request 0
342 * bytes to be read
345 /* If this returns FALSE, it means the socket has been
346 * closed locally. If it returns TRUE, but
347 * still_readable != 1 then shutdown
348 * (SHUT_RD|SHUT_RDWR) has been called locally.
350 if (sockethandle->still_readable != 1) {
351 ret = -1;
352 mono_set_errno (EINTR);
356 if (ret == -1) {
357 gint errnum = errno;
358 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recv error: %s", __func__, g_strerror(errno));
359 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
360 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
361 return SOCKET_ERROR;
363 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
364 return ret;
367 static void
368 wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr)
370 guint32 i;
372 memset (hdr, 0, sizeof (struct msghdr));
373 hdr->msg_iovlen = count;
374 hdr->msg_iov = g_new0 (struct iovec, count);
375 for (i = 0; i < count; i++) {
376 hdr->msg_iov [i].iov_base = buffers [i].buf;
377 hdr->msg_iov [i].iov_len = buffers [i].len;
381 static void
382 msghdr_iov_free (struct msghdr *hdr)
384 g_free (hdr->msg_iov);
388 mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking)
390 SocketHandle *sockethandle;
391 MonoThreadInfo *info;
392 gint ret;
393 struct msghdr hdr;
395 g_assert (overlapped == NULL);
396 g_assert (complete == NULL);
398 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
399 mono_w32error_set_last (WSAENOTSOCK);
400 return SOCKET_ERROR;
403 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
404 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
405 mono_w32error_set_last (WSAENOTSOCK);
406 return SOCKET_ERROR;
409 info = mono_thread_info_current ();
411 wsabuf_to_msghdr (buffers, count, &hdr);
413 do {
414 MONO_ENTER_GC_SAFE;
415 ret = recvmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, *flags);
416 MONO_EXIT_GC_SAFE;
417 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
419 msghdr_iov_free (&hdr);
421 if (ret == 0) {
422 /* see mono_w32socket_recvfrom */
423 if (sockethandle->still_readable != 1) {
424 ret = -1;
425 mono_set_errno (EINTR);
429 if (ret == -1) {
430 gint errnum = errno;
431 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: recvmsg error: %s", __func__, g_strerror(errno));
432 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
433 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
434 return SOCKET_ERROR;
437 *received = ret;
438 *flags = hdr.msg_flags;
440 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
441 return 0;
445 mono_w32socket_send (SOCKET sock, void *buf, int len, int flags, gboolean blocking)
447 SocketHandle *sockethandle;
448 int ret;
449 MonoThreadInfo *info;
451 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
452 mono_w32error_set_last (WSAENOTSOCK);
453 return SOCKET_ERROR;
456 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
457 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
458 mono_w32error_set_last (WSAENOTSOCK);
459 return SOCKET_ERROR;
462 info = mono_thread_info_current ();
464 do {
465 MONO_ENTER_GC_SAFE;
466 ret = send (((MonoFDHandle*) sockethandle)->fd, buf, len, flags);
467 MONO_EXIT_GC_SAFE;
468 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
470 if (ret == -1) {
471 gint errnum = errno;
472 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno));
474 #ifdef O_NONBLOCK
475 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
476 * a blocking socket. See bug #599488 */
477 if (errnum == EAGAIN) {
478 MONO_ENTER_GC_SAFE;
479 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0);
480 MONO_EXIT_GC_SAFE;
481 if (ret != -1 && (ret & O_NONBLOCK) == 0)
482 errnum = ETIMEDOUT;
484 #endif /* O_NONBLOCK */
485 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
486 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
487 return SOCKET_ERROR;
489 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
490 return ret;
494 mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
496 SocketHandle *sockethandle;
497 int ret;
498 MonoThreadInfo *info;
500 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
501 mono_w32error_set_last (WSAENOTSOCK);
502 return SOCKET_ERROR;
505 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
506 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
507 mono_w32error_set_last (WSAENOTSOCK);
508 return SOCKET_ERROR;
511 info = mono_thread_info_current ();
513 do {
514 MONO_ENTER_GC_SAFE;
515 ret = sendto (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, to, tolen);
516 MONO_EXIT_GC_SAFE;
517 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
519 if (ret == -1) {
520 gint errnum = errno;
521 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: send error: %s", __func__, g_strerror (errno));
522 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
523 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
524 return SOCKET_ERROR;
526 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
527 return ret;
531 mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking)
533 struct msghdr hdr;
534 MonoThreadInfo *info;
535 SocketHandle *sockethandle;
536 gint ret;
538 g_assert (overlapped == NULL);
539 g_assert (complete == NULL);
541 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
542 mono_w32error_set_last (WSAENOTSOCK);
543 return SOCKET_ERROR;
546 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
547 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
548 mono_w32error_set_last (WSAENOTSOCK);
549 return SOCKET_ERROR;
552 info = mono_thread_info_current ();
554 wsabuf_to_msghdr (buffers, count, &hdr);
556 do {
557 MONO_ENTER_GC_SAFE;
558 ret = sendmsg (((MonoFDHandle*) sockethandle)->fd, &hdr, flags);
559 MONO_EXIT_GC_SAFE;
560 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
562 msghdr_iov_free (&hdr);
564 if (ret == -1) {
565 gint errnum = errno;
566 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: sendmsg error: %s", __func__, g_strerror (errno));
567 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
568 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
569 return SOCKET_ERROR;
572 *sent = ret;
573 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
574 return 0;
577 #define SF_BUFFER_SIZE 16384
579 BOOL
580 mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking)
582 MonoThreadInfo *info;
583 SocketHandle *sockethandle;
584 gint file;
585 gssize ret;
586 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
587 struct stat statbuf;
588 #else
589 gpointer buffer;
590 #endif
592 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
593 mono_w32error_set_last (WSAENOTSOCK);
594 return FALSE;
597 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
598 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
599 mono_w32error_set_last (WSAENOTSOCK);
600 return FALSE;
603 /* Write the header */
604 if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
605 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Head, buffers->HeadLength, 0, FALSE);
606 if (ret == SOCKET_ERROR) {
607 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
608 return FALSE;
612 info = mono_thread_info_current ();
614 file = GPOINTER_TO_INT (file_handle);
616 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
617 MONO_ENTER_GC_SAFE;
618 ret = fstat (file, &statbuf);
619 MONO_EXIT_GC_SAFE;
620 if (ret == -1) {
621 gint errnum = errno;
622 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
623 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
624 return FALSE;
627 do {
628 MONO_ENTER_GC_SAFE;
629 #ifdef __linux__
630 ret = sendfile (((MonoFDHandle*) sockethandle)->fd, file, NULL, statbuf.st_size);
631 #elif defined(DARWIN)
632 /* TODO: header/tail could be sent in the 5th argument */
633 /* TODO: Might not send the entire file for non-blocking sockets */
634 ret = sendfile (file, ((MonoFDHandle*) sockethandle)->fd, 0, &statbuf.st_size, NULL, 0);
635 #endif
636 MONO_EXIT_GC_SAFE;
637 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
638 #else
639 buffer = g_malloc (SF_BUFFER_SIZE);
641 do {
642 do {
643 MONO_ENTER_GC_SAFE;
644 ret = read (file, buffer, SF_BUFFER_SIZE);
645 MONO_EXIT_GC_SAFE;
646 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
648 if (ret == -1 || ret == 0)
649 break;
651 do {
652 MONO_ENTER_GC_SAFE;
653 ret = send (((MonoFDHandle*) sockethandle)->fd, buffer, ret, 0); /* short sends? enclose this in a loop? */
654 MONO_EXIT_GC_SAFE;
655 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
656 } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
658 g_free (buffer);
659 #endif
661 if (ret == -1) {
662 gint errnum = errno;
663 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
664 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
665 return FALSE;
668 /* Write the tail */
669 if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
670 ret = mono_w32socket_send (((MonoFDHandle*) sockethandle)->fd, buffers->Tail, buffers->TailLength, 0, FALSE);
671 if (ret == SOCKET_ERROR) {
672 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
673 return FALSE;
677 if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
678 mono_w32socket_close (((MonoFDHandle*) sockethandle)->fd);
680 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
681 return TRUE;
684 SOCKET
685 mono_w32socket_socket (int domain, int type, int protocol)
687 SocketHandle *sockethandle;
688 gint fd;
690 retry_socket:
691 MONO_ENTER_GC_SAFE;
692 fd = socket (domain, type, protocol);
693 MONO_EXIT_GC_SAFE;
694 if (fd == -1) {
695 if (domain == AF_INET && type == SOCK_RAW && protocol == 0) {
696 /* Retry with protocol == 4 (see bug #54565) */
697 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
698 protocol = 4;
699 goto retry_socket;
702 gint errnum = errno;
703 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errno));
704 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
705 return INVALID_SOCKET;
708 sockethandle = socket_data_create(MONO_FDTYPE_SOCKET, fd);
709 sockethandle->domain = domain;
710 sockethandle->type = type;
711 sockethandle->protocol = protocol;
712 sockethandle->still_readable = 1;
714 /* .net seems to set this by default for SOCK_STREAM, not for
715 * SOCK_DGRAM (see bug #36322)
716 * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
718 * It seems winsock has a rather different idea of what
719 * SO_REUSEADDR means. If it's set, then a new socket can be
720 * bound over an existing listening socket. There's a new
721 * windows-specific option called SO_EXCLUSIVEADDRUSE but
722 * using that means the socket MUST be closed properly, or a
723 * denial of service can occur. Luckily for us, winsock
724 * behaves as though any other system would when SO_REUSEADDR
725 * is true, so we don't need to do anything else here. See
726 * bug 53992.
727 * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
730 int ret;
731 const int true_ = 1;
733 MONO_ENTER_GC_SAFE;
734 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
735 MONO_EXIT_GC_SAFE;
736 if (ret == -1) {
737 gint errnum = errno;
738 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: Error setting SO_REUSEADDR", __func__);
739 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
741 MONO_ENTER_GC_SAFE;
742 close (((MonoFDHandle*) sockethandle)->fd);
743 MONO_EXIT_GC_SAFE;
745 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
746 return INVALID_SOCKET;
750 mono_fdhandle_insert ((MonoFDHandle*) sockethandle);
752 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: returning socket handle %p", __func__, GINT_TO_POINTER(((MonoFDHandle*) sockethandle)->fd));
754 return ((MonoFDHandle*) sockethandle)->fd;
757 gint
758 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
760 SocketHandle *sockethandle;
761 int ret;
763 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
764 mono_w32error_set_last (WSAENOTSOCK);
765 return SOCKET_ERROR;
768 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
769 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
770 mono_w32error_set_last (WSAENOTSOCK);
771 return SOCKET_ERROR;
774 MONO_ENTER_GC_SAFE;
775 ret = bind (((MonoFDHandle*) sockethandle)->fd, addr, addrlen);
776 MONO_EXIT_GC_SAFE;
777 if (ret == -1) {
778 gint errnum = errno;
779 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: bind error: %s", __func__, g_strerror(errno));
780 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
781 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
782 return SOCKET_ERROR;
785 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
786 return 0;
789 gint
790 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
792 SocketHandle *sockethandle;
793 gint ret;
795 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
796 mono_w32error_set_last (WSAENOTSOCK);
797 return SOCKET_ERROR;
800 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
801 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
802 mono_w32error_set_last (WSAENOTSOCK);
803 return SOCKET_ERROR;
806 #ifdef HAVE_GETPEERNAME
807 MONO_ENTER_GC_SAFE;
808 ret = getpeername (((MonoFDHandle*) sockethandle)->fd, name, namelen);
809 MONO_EXIT_GC_SAFE;
810 #else
811 ret = -1;
812 #endif
813 if (ret == -1) {
814 gint errnum = errno;
815 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getpeername error: %s", __func__, g_strerror (errno));
816 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
817 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
818 return SOCKET_ERROR;
821 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
822 return 0;
825 gint
826 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
828 SocketHandle *sockethandle;
829 gint ret;
831 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
832 mono_w32error_set_last (WSAENOTSOCK);
833 return SOCKET_ERROR;
836 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
837 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
838 mono_w32error_set_last (WSAENOTSOCK);
839 return SOCKET_ERROR;
842 MONO_ENTER_GC_SAFE;
843 ret = getsockname (((MonoFDHandle*) sockethandle)->fd, name, namelen);
844 MONO_EXIT_GC_SAFE;
845 if (ret == -1) {
846 gint errnum = errno;
847 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockname error: %s", __func__, g_strerror (errno));
848 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
849 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
850 return SOCKET_ERROR;
853 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
854 return 0;
857 gint
858 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
860 SocketHandle *sockethandle;
861 gint ret;
862 struct timeval tv;
863 gpointer tmp_val;
865 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
866 mono_w32error_set_last (WSAENOTSOCK);
867 return SOCKET_ERROR;
870 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
871 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
872 mono_w32error_set_last (WSAENOTSOCK);
873 return SOCKET_ERROR;
876 tmp_val = optval;
877 if (level == SOL_SOCKET &&
878 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
879 tmp_val = &tv;
880 *optlen = sizeof (tv);
883 MONO_ENTER_GC_SAFE;
884 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
885 MONO_EXIT_GC_SAFE;
886 if (ret == -1) {
887 gint errnum = errno;
888 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
889 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
890 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
891 return SOCKET_ERROR;
894 if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
895 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro
896 *optlen = sizeof (int);
899 if (optname == SO_ERROR) {
900 if (*((int *)optval) != 0) {
901 *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
902 sockethandle->saved_error = *((int *)optval);
903 } else {
904 *((int *)optval) = sockethandle->saved_error;
908 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
909 return 0;
912 gint
913 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen)
915 SocketHandle *sockethandle;
916 gint ret;
917 gconstpointer tmp_val;
918 #if defined (__linux__)
919 /* This has its address taken so it cannot be moved to the if block which uses it */
920 gint bufsize = 0;
921 #endif
922 struct timeval tv;
924 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
925 mono_w32error_set_last (WSAENOTSOCK);
926 return SOCKET_ERROR;
929 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
930 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
931 mono_w32error_set_last (WSAENOTSOCK);
932 return SOCKET_ERROR;
935 tmp_val = optval;
936 if (level == SOL_SOCKET &&
937 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
938 int ms = *((int *) optval);
939 tv.tv_sec = ms / 1000;
940 tv.tv_usec = (ms % 1000) * 1000; // micro from milli
941 tmp_val = &tv;
942 optlen = sizeof (tv);
944 #if defined (__linux__)
945 else if (level == SOL_SOCKET &&
946 (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
947 /* According to socket(7) the Linux kernel doubles the
948 * buffer sizes "to allow space for bookkeeping
949 * overhead."
951 bufsize = *((int *) optval);
953 bufsize /= 2;
954 tmp_val = &bufsize;
956 #endif
958 MONO_ENTER_GC_SAFE;
959 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, level, optname, tmp_val, optlen);
960 MONO_EXIT_GC_SAFE;
961 if (ret == -1) {
962 gint errnum = errno;
963 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: setsockopt error: %s", __func__, g_strerror (errno));
964 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
965 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
966 return SOCKET_ERROR;
969 #if defined (SO_REUSEPORT)
970 /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */
971 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
972 int type;
973 socklen_t type_len = sizeof (type);
975 MONO_ENTER_GC_SAFE;
976 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_TYPE, &type, &type_len);
977 MONO_EXIT_GC_SAFE;
978 if (!ret) {
979 if (type == SOCK_DGRAM || type == SOCK_STREAM) {
980 MONO_ENTER_GC_SAFE;
981 setsockopt (((MonoFDHandle*) sockethandle)->fd, level, SO_REUSEPORT, tmp_val, optlen);
982 MONO_EXIT_GC_SAFE;
986 #endif
988 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
989 return ret;
992 gint
993 mono_w32socket_listen (SOCKET sock, gint backlog)
995 SocketHandle *sockethandle;
996 gint ret;
998 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
999 mono_w32error_set_last (WSAENOTSOCK);
1000 return SOCKET_ERROR;
1003 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1004 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1005 mono_w32error_set_last (WSAENOTSOCK);
1006 return SOCKET_ERROR;
1009 MONO_ENTER_GC_SAFE;
1010 ret = listen (((MonoFDHandle*) sockethandle)->fd, backlog);
1011 MONO_EXIT_GC_SAFE;
1012 if (ret == -1) {
1013 gint errnum = errno;
1014 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: listen error: %s", __func__, g_strerror (errno));
1015 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1016 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1017 return SOCKET_ERROR;
1020 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1021 return 0;
1024 gint
1025 mono_w32socket_shutdown (SOCKET sock, gint how)
1027 SocketHandle *sockethandle;
1028 gint ret;
1030 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1031 mono_w32error_set_last (WSAENOTSOCK);
1032 return SOCKET_ERROR;
1035 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1036 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1037 mono_w32error_set_last (WSAENOTSOCK);
1038 return SOCKET_ERROR;
1041 if (how == SHUT_RD || how == SHUT_RDWR)
1042 sockethandle->still_readable = 0;
1044 MONO_ENTER_GC_SAFE;
1045 ret = shutdown (((MonoFDHandle*) sockethandle)->fd, how);
1046 MONO_EXIT_GC_SAFE;
1047 if (ret == -1) {
1048 gint errnum = errno;
1049 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: shutdown error: %s", __func__, g_strerror (errno));
1050 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1051 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1052 return SOCKET_ERROR;
1055 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1056 return ret;
1059 gint
1060 mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
1062 SocketHandle *sockethandle;
1063 SOCKET newsock;
1064 gint ret;
1066 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: called on socket %d!", __func__, sock);
1068 /* We could check the socket type here and fail unless its
1069 * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
1070 * if we really wanted to */
1072 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1073 mono_w32error_set_last (WSAENOTSOCK);
1074 return SOCKET_ERROR;
1077 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1078 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1079 mono_w32error_set_last (WSAENOTSOCK);
1080 return SOCKET_ERROR;
1083 MONO_ENTER_GC_SAFE;
1084 newsock = socket (sockethandle->domain, sockethandle->type, sockethandle->protocol);
1085 MONO_EXIT_GC_SAFE;
1086 if (newsock == -1) {
1087 gint errnum = errno;
1088 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: socket error: %s", __func__, g_strerror (errnum));
1089 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1090 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1091 return SOCKET_ERROR;
1094 /* According to Stevens "Advanced Programming in the UNIX
1095 * Environment: UNIX File I/O" dup2() is atomic so there
1096 * should not be a race condition between the old fd being
1097 * closed and the new socket fd being copied over */
1098 do {
1099 MONO_ENTER_GC_SAFE;
1100 ret = dup2 (newsock, ((MonoFDHandle*) sockethandle)->fd);
1101 MONO_EXIT_GC_SAFE;
1102 } while (ret == -1 && errno == EAGAIN);
1104 if (ret == -1) {
1105 gint errnum = errno;
1106 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: dup2 error: %s", __func__, g_strerror (errnum));
1107 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1108 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1109 return SOCKET_ERROR;
1112 MONO_ENTER_GC_SAFE;
1113 close (newsock);
1114 MONO_EXIT_GC_SAFE;
1116 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1117 return 0;
1120 static gboolean
1121 extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
1123 gboolean ret;
1124 MONO_ENTER_GC_UNSAFE;
1125 ret = mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
1126 MONO_EXIT_GC_UNSAFE;
1127 return ret;
1130 static gboolean
1131 extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send,
1132 OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags)
1134 gboolean ret;
1135 MONO_ENTER_GC_UNSAFE;
1136 ret = mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE);
1137 MONO_EXIT_GC_UNSAFE;
1138 return ret;
1141 const
1142 static struct {
1143 GUID guid;
1144 gpointer func;
1145 } extension_functions[] = {
1146 { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, (gpointer)extension_disconect },
1147 { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, (gpointer)extension_transmit_file },
1148 { {0} , NULL },
1151 gint
1152 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
1154 SocketHandle *sockethandle;
1155 gint ret;
1156 gpointer buffer;
1158 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1159 mono_w32error_set_last (WSAENOTSOCK);
1160 return SOCKET_ERROR;
1163 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1164 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1165 mono_w32error_set_last (WSAENOTSOCK);
1166 return SOCKET_ERROR;
1169 if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1170 gint i;
1171 GUID *guid;
1173 if (inputlen < sizeof(GUID)) {
1174 /* As far as I can tell, windows doesn't
1175 * actually set an error here...
1177 mono_w32socket_set_last_error (WSAEINVAL);
1178 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1179 return SOCKET_ERROR;
1182 if (outputlen < sizeof(gpointer)) {
1183 /* Or here... */
1184 mono_w32socket_set_last_error (WSAEINVAL);
1185 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1186 return SOCKET_ERROR;
1189 if (output == NULL) {
1190 /* Or here */
1191 mono_w32socket_set_last_error (WSAEINVAL);
1192 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1193 return SOCKET_ERROR;
1196 guid = (GUID*) input;
1197 for (i = 0; extension_functions[i].func; i++) {
1198 if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
1199 memcpy (output, &extension_functions[i].func, sizeof(gpointer));
1200 *written = sizeof(gpointer);
1201 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1202 return 0;
1206 mono_w32socket_set_last_error (WSAEINVAL);
1207 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1208 return SOCKET_ERROR;
1211 if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1212 guint32 onoff;
1214 if (inputlen < 3 * sizeof (guint32)) {
1215 mono_w32socket_set_last_error (WSAEINVAL);
1216 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1217 return SOCKET_ERROR;
1220 onoff = *((guint32*) input);
1222 MONO_ENTER_GC_SAFE;
1223 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
1224 MONO_EXIT_GC_SAFE;
1225 if (ret < 0) {
1226 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1227 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1228 return SOCKET_ERROR;
1231 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1232 if (onoff != 0) {
1233 /* Values are in ms, but we need s */
1234 guint32 keepalivetime, keepaliveinterval, rem;
1236 keepalivetime = *(((guint32*) input) + 1);
1237 keepaliveinterval = *(((guint32*) input) + 2);
1239 /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1240 rem = keepalivetime % 1000;
1241 keepalivetime /= 1000;
1242 if (keepalivetime == 0 || rem >= 500)
1243 keepalivetime++;
1244 MONO_ENTER_GC_SAFE;
1245 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
1246 MONO_EXIT_GC_SAFE;
1247 if (ret == 0) {
1248 rem = keepaliveinterval % 1000;
1249 keepaliveinterval /= 1000;
1250 if (keepaliveinterval == 0 || rem >= 500)
1251 keepaliveinterval++;
1252 MONO_ENTER_GC_SAFE;
1253 ret = setsockopt (((MonoFDHandle*) sockethandle)->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
1254 MONO_EXIT_GC_SAFE;
1256 if (ret != 0) {
1257 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1258 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1259 return SOCKET_ERROR;
1262 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1263 return 0;
1265 #endif
1267 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1268 return 0;
1271 buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
1273 MONO_ENTER_GC_SAFE;
1274 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, command, buffer);
1275 MONO_EXIT_GC_SAFE;
1276 if (ret == -1) {
1277 g_free (buffer);
1279 gint errnum = errno;
1280 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: WSAIoctl error: %s", __func__, g_strerror (errno));
1281 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1282 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1283 return SOCKET_ERROR;
1286 if (!buffer) {
1287 *written = 0;
1288 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1289 return 0;
1292 /* We just copy the buffer to the output. Some ioctls
1293 * don't even output any data, but, well...
1295 * NB windows returns WSAEFAULT if outputlen is too small */
1296 inputlen = (inputlen > outputlen) ? outputlen : inputlen;
1298 if (inputlen > 0 && output != NULL)
1299 memcpy (output, buffer, inputlen);
1301 g_free (buffer);
1302 *written = inputlen;
1304 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1305 return 0;
1308 gboolean
1309 mono_w32socket_close (SOCKET sock)
1311 if (!mono_fdhandle_close (sock)) {
1312 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1313 return FALSE;
1316 return TRUE;
1319 gint
1320 mono_w32socket_set_blocking (SOCKET sock, gboolean blocking)
1322 #ifdef O_NONBLOCK
1323 SocketHandle *sockethandle;
1324 gint ret;
1326 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1327 mono_w32error_set_last (WSAENOTSOCK);
1328 return SOCKET_ERROR;
1331 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1332 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1333 mono_w32error_set_last (WSAENOTSOCK);
1334 return SOCKET_ERROR;
1337 /* This works better than ioctl(...FIONBIO...)
1338 * on Linux (it causes connect to return
1339 * EINPROGRESS, but the ioctl doesn't seem to) */
1340 MONO_ENTER_GC_SAFE;
1341 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_GETFL, 0);
1342 MONO_EXIT_GC_SAFE;
1343 if (ret == -1) {
1344 gint errnum = mono_w32socket_convert_error (errno);
1345 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_GETFL) error: %s", __func__, g_strerror (errno));
1346 mono_w32socket_set_last_error (errnum);
1347 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1348 return SOCKET_ERROR;
1351 MONO_ENTER_GC_SAFE;
1352 ret = fcntl (((MonoFDHandle*) sockethandle)->fd, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK)));
1353 MONO_EXIT_GC_SAFE;
1354 if (ret == -1) {
1355 gint errnum = mono_w32socket_convert_error (errno);
1356 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: fcntl(F_SETFL) error: %s", __func__, g_strerror (errno));
1357 mono_w32socket_set_last_error (errnum);
1358 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1359 return SOCKET_ERROR;
1362 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1363 return 0;
1364 #else
1365 mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED);
1366 return SOCKET_ERROR;
1367 #endif /* O_NONBLOCK */
1370 gint
1371 mono_w32socket_get_available (SOCKET sock, guint64 *amount)
1373 SocketHandle *sockethandle;
1374 gint ret;
1376 if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
1377 mono_w32error_set_last (WSAENOTSOCK);
1378 return SOCKET_ERROR;
1381 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1382 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1383 mono_w32error_set_last (WSAENOTSOCK);
1384 return SOCKET_ERROR;
1387 #if defined (HOST_DARWIN)
1388 // ioctl (socket, FIONREAD, XXX) returns the size of
1389 // the UDP header as well on Darwin.
1391 // Use getsockopt SO_NREAD instead to get the
1392 // right values for TCP and UDP.
1394 // ai_canonname can be null in some cases on darwin,
1395 // where the runtime assumes it will be the value of
1396 // the ip buffer.
1398 socklen_t optlen = sizeof (int);
1399 MONO_ENTER_GC_SAFE;
1400 ret = getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
1401 MONO_EXIT_GC_SAFE;
1402 if (ret == -1) {
1403 gint errnum = mono_w32socket_convert_error (errno);
1404 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: getsockopt error: %s", __func__, g_strerror (errno));
1405 mono_w32socket_set_last_error (errnum);
1406 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1407 return SOCKET_ERROR;
1409 #else
1410 MONO_ENTER_GC_SAFE;
1411 ret = ioctl (((MonoFDHandle*) sockethandle)->fd, FIONREAD, (gulong*) amount);
1412 MONO_EXIT_GC_SAFE;
1413 if (ret == -1) {
1414 gint errnum = mono_w32socket_convert_error (errno);
1415 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER_SOCKET, "%s: ioctl error: %s", __func__, g_strerror (errno));
1416 mono_w32socket_set_last_error (errnum);
1417 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1418 return SOCKET_ERROR;
1420 #endif
1422 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1423 return 0;
1426 void
1427 mono_w32socket_set_last_error (gint32 error)
1429 mono_w32error_set_last (error);
1432 gint32
1433 mono_w32socket_get_last_error (void)
1435 return mono_w32error_get_last ();
1438 gint32
1439 mono_w32socket_convert_error (gint error)
1441 switch (error) {
1442 case 0: return ERROR_SUCCESS;
1443 case EACCES: return WSAEACCES;
1444 #ifdef EADDRINUSE
1445 case EADDRINUSE: return WSAEADDRINUSE;
1446 #endif
1447 #ifdef EAFNOSUPPORT
1448 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
1449 #endif
1450 #if EAGAIN != EWOULDBLOCK
1451 case EAGAIN: return WSAEWOULDBLOCK;
1452 #endif
1453 #ifdef EALREADY
1454 case EALREADY: return WSAEALREADY;
1455 #endif
1456 case EBADF: return WSAENOTSOCK;
1457 #ifdef ECONNABORTED
1458 case ECONNABORTED: return WSAENETDOWN;
1459 #endif
1460 #ifdef ECONNREFUSED
1461 case ECONNREFUSED: return WSAECONNREFUSED;
1462 #endif
1463 #ifdef ECONNRESET
1464 case ECONNRESET: return WSAECONNRESET;
1465 #endif
1466 case EFAULT: return WSAEFAULT;
1467 #ifdef EHOSTUNREACH
1468 case EHOSTUNREACH: return WSAEHOSTUNREACH;
1469 #endif
1470 #ifdef EINPROGRESS
1471 case EINPROGRESS: return WSAEINPROGRESS;
1472 #endif
1473 case EINTR: return WSAEINTR;
1474 case EINVAL: return WSAEINVAL;
1475 /*FIXME: case EIO: return WSAE????; */
1476 #ifdef EISCONN
1477 case EISCONN: return WSAEISCONN;
1478 #endif
1479 /* FIXME: case ELOOP: return WSA????; */
1480 case EMFILE: return WSAEMFILE;
1481 #ifdef EMSGSIZE
1482 case EMSGSIZE: return WSAEMSGSIZE;
1483 #endif
1484 /* FIXME: case ENAMETOOLONG: return WSAEACCES; */
1485 #ifdef ENETUNREACH
1486 case ENETUNREACH: return WSAENETUNREACH;
1487 #endif
1488 #ifdef ENOBUFS
1489 case ENOBUFS: return WSAENOBUFS; /* not documented */
1490 #endif
1491 /* case ENOENT: return WSAE????; */
1492 case ENOMEM: return WSAENOBUFS;
1493 #ifdef ENOPROTOOPT
1494 case ENOPROTOOPT: return WSAENOPROTOOPT;
1495 #endif
1496 #ifdef ENOSR
1497 case ENOSR: return WSAENETDOWN;
1498 #endif
1499 #ifdef ENOTCONN
1500 case ENOTCONN: return WSAENOTCONN;
1501 #endif
1502 /*FIXME: case ENOTDIR: return WSAE????; */
1503 #ifdef ENOTSOCK
1504 case ENOTSOCK: return WSAENOTSOCK;
1505 #endif
1506 case ENOTTY: return WSAENOTSOCK;
1507 #ifdef EOPNOTSUPP
1508 case EOPNOTSUPP: return WSAEOPNOTSUPP;
1509 #endif
1510 case EPERM: return WSAEACCES;
1511 case EPIPE: return WSAESHUTDOWN;
1512 #ifdef EPROTONOSUPPORT
1513 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
1514 #endif
1515 #if ERESTARTSYS
1516 case ERESTARTSYS: return WSAENETDOWN;
1517 #endif
1518 /*FIXME: case EROFS: return WSAE????; */
1519 #ifdef ESOCKTNOSUPPORT
1520 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
1521 #endif
1522 #ifdef ETIMEDOUT
1523 case ETIMEDOUT: return WSAETIMEDOUT;
1524 #endif
1525 #ifdef EWOULDBLOCK
1526 case EWOULDBLOCK: return WSAEWOULDBLOCK;
1527 #endif
1528 #ifdef EADDRNOTAVAIL
1529 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
1530 #endif
1531 /* This might happen with unix sockets */
1532 case ENOENT: return WSAECONNREFUSED;
1533 #ifdef EDESTADDRREQ
1534 case EDESTADDRREQ: return WSAEDESTADDRREQ;
1535 #endif
1536 #ifdef EHOSTDOWN
1537 case EHOSTDOWN: return WSAEHOSTDOWN;
1538 #endif
1539 #ifdef ENETDOWN
1540 case ENETDOWN: return WSAENETDOWN;
1541 #endif
1542 case ENODEV: return WSAENETDOWN;
1543 #ifdef EPROTOTYPE
1544 case EPROTOTYPE: return WSAEPROTOTYPE;
1545 #endif
1546 #ifdef ENXIO
1547 case ENXIO: return WSAENXIO;
1548 #endif
1549 #ifdef ENONET
1550 case ENONET: return WSAENETUNREACH;
1551 #endif
1552 default:
1553 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
1557 MonoBoolean
1558 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto, MonoError *error)
1560 error_init (error);
1561 #if defined (SO_REUSEPORT)
1562 return TRUE;
1563 #else
1564 #ifdef __linux__
1565 /* Linux always supports double binding for UDP, even on older kernels. */
1566 if (proto == ProtocolType_Udp)
1567 return TRUE;
1568 #endif
1569 return FALSE;
1570 #endif
1573 gboolean
1574 mono_w32socket_duplicate (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle)
1576 SocketHandle *sockethandle;
1578 if (!mono_fdhandle_lookup_and_ref (GPOINTER_TO_INT(handle), (MonoFDHandle**) &sockethandle)) {
1579 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1580 return FALSE;
1583 if (((MonoFDHandle*) sockethandle)->type != MONO_FDTYPE_SOCKET) {
1584 mono_fdhandle_unref ((MonoFDHandle*) sockethandle);
1585 mono_w32error_set_last (ERROR_INVALID_HANDLE);
1586 return FALSE;
1589 *duplicate_handle = handle;
1590 return TRUE;