[io-layer] Extract socket (#4241)
[mono.git] / mono / metadata / w32socket-unix.c
1 /*
2  * w32socket-unix.c: Unix specific socket code.
3  *
4  * Copyright 2016 Microsoft
5  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
6  */
7
8 #include <config.h>
9 #include <glib.h>
10
11 #include <pthread.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <sys/socket.h>
15 #ifdef HAVE_SYS_IOCTL_H
16 #include <sys/ioctl.h>
17 #endif
18 #include <netinet/in.h>
19 #include <netinet/tcp.h>
20 #ifdef HAVE_NETDB_H
21 #include <netdb.h>
22 #endif
23 #include <arpa/inet.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_UIO_H
31 #include <sys/uio.h>
32 #endif
33 #ifdef HAVE_SYS_IOCTL_H
34 #include <sys/ioctl.h>
35 #endif
36 #ifdef HAVE_SYS_FILIO_H
37 #include <sys/filio.h>     /* defines FIONBIO and FIONREAD */
38 #endif
39 #ifdef HAVE_SYS_SOCKIO_H
40 #include <sys/sockio.h>    /* defines SIOCATMARK */
41 #endif
42 #ifndef HAVE_MSG_NOSIGNAL
43 #include <signal.h>
44 #endif
45 #ifdef HAVE_SYS_SENDFILE_H
46 #include <sys/sendfile.h>
47 #endif
48
49 #include "w32socket.h"
50 #include "w32socket-internals.h"
51 #include "w32handle.h"
52 #include "utils/mono-logger-internals.h"
53 #include "utils/mono-poll.h"
54
55 typedef struct {
56         int domain;
57         int type;
58         int protocol;
59         int saved_error;
60         int still_readable;
61 } MonoW32HandleSocket;
62
63 static guint32 in_cleanup = 0;
64
65 static void
66 socket_close (gpointer handle, gpointer data)
67 {
68         int ret;
69         MonoW32HandleSocket *socket_handle = (MonoW32HandleSocket *)data;
70         MonoThreadInfo *info = mono_thread_info_current ();
71
72         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: closing socket handle %p", __func__, handle);
73
74         /* Shutdown the socket for reading, to interrupt any potential
75          * receives that may be blocking for data.  See bug 75705. */
76         shutdown (GPOINTER_TO_UINT (handle), SHUT_RD);
77
78         do {
79                 ret = close (GPOINTER_TO_UINT(handle));
80         } while (ret == -1 && errno == EINTR &&
81                  !mono_thread_info_is_interrupt_state (info));
82
83         if (ret == -1) {
84                 gint errnum = errno;
85                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: close error: %s", __func__, g_strerror (errno));
86                 if (!in_cleanup)
87                         mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
88         }
89
90         if (!in_cleanup)
91                 socket_handle->saved_error = 0;
92 }
93
94 static void
95 socket_details (gpointer data)
96 {
97         /* FIXME: do something */
98 }
99
100 static const gchar*
101 socket_typename (void)
102 {
103         return "Socket";
104 }
105
106 static gsize
107 socket_typesize (void)
108 {
109         return sizeof (MonoW32HandleSocket);
110 }
111
112 static MonoW32HandleOps ops = {
113         socket_close,    /* close */
114         NULL,            /* signal */
115         NULL,            /* own */
116         NULL,            /* is_owned */
117         NULL,            /* special_wait */
118         NULL,            /* prewait */
119         socket_details,  /* details */
120         socket_typename, /* typename */
121         socket_typesize, /* typesize */
122 };
123
124 void
125 mono_w32socket_initialize (void)
126 {
127         mono_w32handle_register_ops (MONO_W32HANDLE_SOCKET, &ops);
128 }
129
130 static gboolean
131 cleanup_close (gpointer handle, gpointer data, gpointer user_data)
132 {
133         if (mono_w32handle_get_type (handle) == MONO_W32HANDLE_SOCKET)
134                 mono_w32handle_force_close (handle, data);
135
136         return FALSE;
137 }
138
139 void
140 mono_w32socket_cleanup (void)
141 {
142         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: cleaning up", __func__);
143
144         in_cleanup = 1;
145         mono_w32handle_foreach (cleanup_close, NULL);
146         in_cleanup = 0;
147 }
148
149 SOCKET
150 mono_w32socket_accept (SOCKET sock, struct sockaddr *addr, socklen_t *addrlen, gboolean blocking)
151 {
152         gpointer handle;
153         gpointer new_handle;
154         MonoW32HandleSocket *socket_handle;
155         MonoW32HandleSocket new_socket_handle;
156         SOCKET new_fd;
157         MonoThreadInfo *info;
158
159         if (addr != NULL && *addrlen < sizeof(struct sockaddr)) {
160                 mono_w32socket_set_last_error (WSAEFAULT);
161                 return INVALID_SOCKET;
162         }
163
164         handle = GUINT_TO_POINTER (sock);
165         if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
166                 mono_w32socket_set_last_error (WSAENOTSOCK);
167                 return INVALID_SOCKET;
168         }
169
170         info = mono_thread_info_current ();
171
172         do {
173                 new_fd = accept (sock, addr, addrlen);
174         } while (new_fd == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
175
176         if (new_fd == -1) {
177                 gint errnum = errno;
178                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, g_strerror(errno));
179                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
180                 return INVALID_SOCKET;
181         }
182
183         if (new_fd >= mono_w32handle_fd_reserve) {
184                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big", __func__);
185
186                 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
187
188                 close (new_fd);
189
190                 return INVALID_SOCKET;
191         }
192
193         new_socket_handle.domain = socket_handle->domain;
194         new_socket_handle.type = socket_handle->type;
195         new_socket_handle.protocol = socket_handle->protocol;
196         new_socket_handle.still_readable = 1;
197
198         new_handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, new_fd,
199                                           &new_socket_handle);
200         if(new_handle == INVALID_HANDLE_VALUE) {
201                 g_warning ("%s: error creating socket handle", __func__);
202                 mono_w32socket_set_last_error (ERROR_GEN_FAILURE);
203                 return INVALID_SOCKET;
204         }
205
206         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with",
207                    __func__, new_handle);
208
209         return new_fd;
210 }
211
212 int
213 mono_w32socket_connect (SOCKET sock, const struct sockaddr *addr, int addrlen, gboolean blocking)
214 {
215         gpointer handle;
216         MonoW32HandleSocket *socket_handle;
217
218         handle = GUINT_TO_POINTER (sock);
219         if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
220                 mono_w32socket_set_last_error (WSAENOTSOCK);
221                 return SOCKET_ERROR;
222         }
223
224         if (connect (sock, addr, addrlen) == -1) {
225                 MonoThreadInfo *info;
226                 mono_pollfd fds;
227                 gint errnum, so_error;
228                 socklen_t len;
229
230                 errnum = errno;
231
232                 if (errno != EINTR) {
233                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect error: %s", __func__,
234                                    g_strerror (errnum));
235
236                         errnum = mono_w32socket_convert_error (errnum);
237                         if (errnum == WSAEINPROGRESS)
238                                 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
239
240                         mono_w32socket_set_last_error (errnum);
241
242                         /*
243                          * On solaris x86 getsockopt (SO_ERROR) is not set after
244                          * connect () fails so we need to save this error.
245                          *
246                          * But don't do this for EWOULDBLOCK (bug 317315)
247                          */
248                         if (errnum != WSAEWOULDBLOCK) {
249                                 /* ECONNRESET means the socket was closed by another thread */
250                                 /* Async close on mac raises ECONNABORTED. */
251                                 socket_handle->saved_error = errnum;
252                         }
253                         return SOCKET_ERROR;
254                 }
255
256                 info = mono_thread_info_current ();
257
258                 fds.fd = sock;
259                 fds.events = MONO_POLLOUT;
260                 while (mono_poll (&fds, 1, -1) == -1 && !mono_thread_info_is_interrupt_state (info)) {
261                         if (errno != EINTR) {
262                                 gint errnum = errno;
263                                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect poll error: %s", __func__, g_strerror (errno));
264                                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
265                                 return SOCKET_ERROR;
266                         }
267                 }
268
269                 len = sizeof(so_error);
270                 if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) {
271                         gint errnum = errno;
272                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt error: %s", __func__, g_strerror (errno));
273                         mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
274                         return SOCKET_ERROR;
275                 }
276
277                 if (so_error != 0) {
278                         gint errnum = mono_w32socket_convert_error (so_error);
279
280                         /* Need to save this socket error */
281                         socket_handle->saved_error = errnum;
282
283                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s",
284                                    __func__, g_strerror (so_error));
285
286                         mono_w32socket_set_last_error (errnum);
287                         return SOCKET_ERROR;
288                 }
289         }
290
291         return 0;
292 }
293
294 int
295 mono_w32socket_recv (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
296 {
297         return mono_w32socket_recvfrom (sock, buf, len, flags, NULL, 0, blocking);
298 }
299
300 int
301 mono_w32socket_recvfrom (SOCKET sock, char *buf, int len, int flags, struct sockaddr *from, socklen_t *fromlen, gboolean blocking)
302 {
303         gpointer handle;
304         MonoW32HandleSocket *socket_handle;
305         int ret;
306         MonoThreadInfo *info;
307
308         handle = GUINT_TO_POINTER (sock);
309         if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
310                 mono_w32socket_set_last_error (WSAENOTSOCK);
311                 return SOCKET_ERROR;
312         }
313
314         info = mono_thread_info_current ();
315
316         do {
317                 ret = recvfrom (sock, buf, len, flags, from, fromlen);
318         } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
319
320         if (ret == 0 && len > 0) {
321                 /* According to the Linux man page, recvfrom only
322                  * returns 0 when the socket has been shut down
323                  * cleanly.  Turn this into an EINTR to simulate win32
324                  * behaviour of returning EINTR when a socket is
325                  * closed while the recvfrom is blocking (we use a
326                  * shutdown() in socket_close() to trigger this.) See
327                  * bug 75705.
328                  */
329                 /* Distinguish between the socket being shut down at
330                  * the local or remote ends, and reads that request 0
331                  * bytes to be read
332                  */
333
334                 /* If this returns FALSE, it means the socket has been
335                  * closed locally.  If it returns TRUE, but
336                  * still_readable != 1 then shutdown
337                  * (SHUT_RD|SHUT_RDWR) has been called locally.
338                  */
339                 if (socket_handle->still_readable != 1) {
340                         ret = -1;
341                         errno = EINTR;
342                 }
343         }
344
345         if (ret == -1) {
346                 gint errnum = errno;
347                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, g_strerror(errno));
348                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
349                 return SOCKET_ERROR;
350         }
351         return ret;
352 }
353
354 static void
355 wsabuf_to_msghdr (WSABUF *buffers, guint32 count, struct msghdr *hdr)
356 {
357         guint32 i;
358
359         memset (hdr, 0, sizeof (struct msghdr));
360         hdr->msg_iovlen = count;
361         hdr->msg_iov = g_new0 (struct iovec, count);
362         for (i = 0; i < count; i++) {
363                 hdr->msg_iov [i].iov_base = buffers [i].buf;
364                 hdr->msg_iov [i].iov_len  = buffers [i].len;
365         }
366 }
367
368 static void
369 msghdr_iov_free (struct msghdr *hdr)
370 {
371         g_free (hdr->msg_iov);
372 }
373
374 int
375 mono_w32socket_recvbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *received, guint32 *flags, gpointer overlapped, gpointer complete, gboolean blocking)
376 {
377         MonoW32HandleSocket *socket_handle;
378         MonoThreadInfo *info;
379         gpointer handle;
380         gint ret;
381         struct msghdr hdr;
382
383         g_assert (overlapped == NULL);
384         g_assert (complete == NULL);
385
386         handle = GUINT_TO_POINTER (sock);
387         if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
388                 mono_w32socket_set_last_error (WSAENOTSOCK);
389                 return SOCKET_ERROR;
390         }
391
392         info = mono_thread_info_current ();
393
394         wsabuf_to_msghdr (buffers, count, &hdr);
395
396         do {
397                 ret = recvmsg (sock, &hdr, *flags);
398         } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
399
400         msghdr_iov_free (&hdr);
401
402         if (ret == 0) {
403                 /* see mono_w32socket_recvfrom */
404                 if (socket_handle->still_readable != 1) {
405                         ret = -1;
406                         errno = EINTR;
407                 }
408         }
409
410         if (ret == -1) {
411                 gint errnum = errno;
412                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg error: %s", __func__, g_strerror(errno));
413                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
414                 return SOCKET_ERROR;
415         }
416
417         *received = ret;
418         *flags = hdr.msg_flags;
419
420         return 0;
421 }
422
423 int
424 mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocking)
425 {
426         gpointer handle;
427         int ret;
428         MonoThreadInfo *info;
429
430         handle = GUINT_TO_POINTER (sock);
431         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
432                 mono_w32socket_set_last_error (WSAENOTSOCK);
433                 return SOCKET_ERROR;
434         }
435
436         info = mono_thread_info_current ();
437
438         do {
439                 ret = send (sock, buf, len, flags);
440         } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
441
442         if (ret == -1) {
443                 gint errnum = errno;
444                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno));
445
446 #ifdef O_NONBLOCK
447                 /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on
448                  * a blocking socket. See bug #599488 */
449                 if (errnum == EAGAIN) {
450                         ret = fcntl (sock, F_GETFL, 0);
451                         if (ret != -1 && (ret & O_NONBLOCK) == 0)
452                                 errnum = ETIMEDOUT;
453                 }
454 #endif /* O_NONBLOCK */
455                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
456                 return SOCKET_ERROR;
457         }
458         return ret;
459 }
460
461 int
462 mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
463 {
464         gpointer handle;
465         int ret;
466         MonoThreadInfo *info;
467
468         handle = GUINT_TO_POINTER (sock);
469         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
470                 mono_w32socket_set_last_error (WSAENOTSOCK);
471                 return SOCKET_ERROR;
472         }
473
474         info = mono_thread_info_current ();
475
476         do {
477                 ret = sendto (sock, buf, len, flags, to, tolen);
478         } while (ret == -1 && errno == EINTR &&  !mono_thread_info_is_interrupt_state (info));
479
480         if (ret == -1) {
481                 gint errnum = errno;
482                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno));
483                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
484                 return SOCKET_ERROR;
485         }
486         return ret;
487 }
488
489 int
490 mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking)
491 {
492         struct msghdr hdr;
493         MonoThreadInfo *info;
494         gpointer handle;
495         gint ret;
496
497         g_assert (overlapped == NULL);
498         g_assert (complete == NULL);
499
500         handle = GUINT_TO_POINTER (sock);
501         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
502                 mono_w32socket_set_last_error (WSAENOTSOCK);
503                 return SOCKET_ERROR;
504         }
505
506         info = mono_thread_info_current ();
507
508         wsabuf_to_msghdr (buffers, count, &hdr);
509
510         do {
511                 ret = sendmsg (sock, &hdr, flags);
512         } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
513
514         msghdr_iov_free (&hdr);
515
516         if (ret == -1) {
517                 gint errnum = errno;
518                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, g_strerror (errno));
519                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
520                 return SOCKET_ERROR;
521         }
522
523         *sent = ret;
524         return 0;
525 }
526
527 #define SF_BUFFER_SIZE  16384
528
529 BOOL
530 mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking)
531 {
532         MonoThreadInfo *info;
533         gpointer handle;
534         gint file;
535         gssize ret;
536 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
537         struct stat statbuf;
538 #else
539         gchar *buffer;
540 #endif
541
542         handle = GUINT_TO_POINTER (sock);
543         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
544                 mono_w32socket_set_last_error (WSAENOTSOCK);
545                 return FALSE;
546         }
547
548         /* Write the header */
549         if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) {
550                 ret = mono_w32socket_send (sock, buffers->Head, buffers->HeadLength, 0, FALSE);
551                 if (ret == SOCKET_ERROR)
552                         return FALSE;
553         }
554
555         info = mono_thread_info_current ();
556
557         file = GPOINTER_TO_INT (file_handle);
558
559 #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN))
560         ret = fstat (file, &statbuf);
561         if (ret == -1) {
562                 gint errnum = errno;
563                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
564                 return SOCKET_ERROR;
565         }
566
567         do {
568 #ifdef __linux__
569                 ret = sendfile (sock, file, NULL, statbuf.st_size);
570 #elif defined(DARWIN)
571                 /* TODO: header/tail could be sent in the 5th argument */
572                 /* TODO: Might not send the entire file for non-blocking sockets */
573                 ret = sendfile (file, sock, 0, &statbuf.st_size, NULL, 0);
574 #endif
575         } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
576 #else
577         buffer = g_malloc (SF_BUFFER_SIZE);
578
579         do {
580                 do {
581                         ret = read (file, buffer, SF_BUFFER_SIZE);
582                 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
583
584                 if (ret == -1 || ret == 0)
585                         break;
586
587                 do {
588                         ret = send (sock, buffer, ret, 0); /* short sends? enclose this in a loop? */
589                 } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
590         } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
591
592         g_free (buffer);
593 #endif
594
595         if (ret == -1) {
596                 gint errnum = errno;
597                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
598                 return FALSE;
599         }
600
601         /* Write the tail */
602         if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) {
603                 ret = mono_w32socket_send (sock, buffers->Tail, buffers->TailLength, 0, FALSE);
604                 if (ret == SOCKET_ERROR)
605                         return FALSE;
606         }
607
608         if ((flags & TF_DISCONNECT) == TF_DISCONNECT)
609                 CloseHandle (handle);
610
611         return TRUE;
612 }
613
614 SOCKET
615 mono_w32socket_socket (int domain, int type, int protocol)
616 {
617         MonoW32HandleSocket socket_handle = {0};
618         gpointer handle;
619         SOCKET sock;
620
621         socket_handle.domain = domain;
622         socket_handle.type = type;
623         socket_handle.protocol = protocol;
624         socket_handle.still_readable = 1;
625
626         sock = socket (domain, type, protocol);
627         if (sock == -1 && domain == AF_INET && type == SOCK_RAW &&
628             protocol == 0) {
629                 /* Retry with protocol == 4 (see bug #54565) */
630                 // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565
631                 socket_handle.protocol = 4;
632                 sock = socket (AF_INET, SOCK_RAW, 4);
633         }
634
635         if (sock == -1) {
636                 gint errnum = errno;
637                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errno));
638                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
639                 return INVALID_SOCKET;
640         }
641
642         if (sock >= mono_w32handle_fd_reserve) {
643                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File descriptor is too big (%d >= %d)",
644                            __func__, sock, mono_w32handle_fd_reserve);
645
646                 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
647                 close (sock);
648
649                 return INVALID_SOCKET;
650         }
651
652         /* .net seems to set this by default for SOCK_STREAM, not for
653          * SOCK_DGRAM (see bug #36322)
654          * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322
655          *
656          * It seems winsock has a rather different idea of what
657          * SO_REUSEADDR means.  If it's set, then a new socket can be
658          * bound over an existing listening socket.  There's a new
659          * windows-specific option called SO_EXCLUSIVEADDRUSE but
660          * using that means the socket MUST be closed properly, or a
661          * denial of service can occur.  Luckily for us, winsock
662          * behaves as though any other system would when SO_REUSEADDR
663          * is true, so we don't need to do anything else here.  See
664          * bug 53992.
665          * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992
666          */
667         {
668                 int ret, true_ = 1;
669
670                 ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true_, sizeof (true_));
671                 if (ret == -1) {
672                         close (sock);
673                         gint errnum = errno;
674                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error setting SO_REUSEADDR", __func__);
675                         mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
676                         return INVALID_SOCKET;
677                 }
678         }
679
680
681         handle = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, sock, &socket_handle);
682         if (handle == INVALID_HANDLE_VALUE) {
683                 g_warning ("%s: error creating socket handle", __func__);
684                 mono_w32socket_set_last_error (WSASYSCALLFAILURE);
685                 close (sock);
686                 return INVALID_SOCKET;
687         }
688
689         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning socket handle %p", __func__, handle);
690
691         return sock;
692 }
693
694 gint
695 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
696 {
697         gpointer handle;
698         int ret;
699
700         handle = GUINT_TO_POINTER (sock);
701         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
702                 mono_w32socket_set_last_error (WSAENOTSOCK);
703                 return SOCKET_ERROR;
704         }
705
706         ret = bind (sock, addr, addrlen);
707         if (ret == -1) {
708                 gint errnum = errno;
709                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind error: %s", __func__, g_strerror(errno));
710                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
711                 return SOCKET_ERROR;
712         }
713
714         return 0;
715 }
716
717 gint
718 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
719 {
720         gpointer handle;
721         gint ret;
722
723         handle = GUINT_TO_POINTER (sock);
724         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
725                 mono_w32socket_set_last_error (WSAENOTSOCK);
726                 return SOCKET_ERROR;
727         }
728
729         ret = getpeername (sock, name, namelen);
730         if (ret == -1) {
731                 gint errnum = errno;
732                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getpeername error: %s", __func__, g_strerror (errno));
733                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
734                 return SOCKET_ERROR;
735         }
736
737         return 0;
738 }
739
740 gint
741 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
742 {
743         gpointer handle;
744         gint ret;
745
746         handle = GUINT_TO_POINTER (sock);
747         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
748                 mono_w32socket_set_last_error (WSAENOTSOCK);
749                 return SOCKET_ERROR;
750         }
751
752         ret = getsockname (sock, name, namelen);
753         if (ret == -1) {
754                 gint errnum = errno;
755                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__, g_strerror (errno));
756                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
757                 return SOCKET_ERROR;
758         }
759
760         return 0;
761 }
762
763 gint
764 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
765 {
766         gpointer handle;
767         gint ret;
768         struct timeval tv;
769         gpointer tmp_val;
770         MonoW32HandleSocket *socket_handle;
771
772         handle = GUINT_TO_POINTER (sock);
773         if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
774                 mono_w32socket_set_last_error (WSAENOTSOCK);
775                 return SOCKET_ERROR;
776         }
777
778         tmp_val = optval;
779         if (level == SOL_SOCKET &&
780             (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
781                 tmp_val = &tv;
782                 *optlen = sizeof (tv);
783         }
784
785         ret = getsockopt (sock, level, optname, tmp_val, optlen);
786         if (ret == -1) {
787                 gint errnum = errno;
788                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockopt error: %s", __func__, g_strerror (errno));
789                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
790                 return SOCKET_ERROR;
791         }
792
793         if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
794                 *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000);     // milli from micro
795                 *optlen = sizeof (int);
796         }
797
798         if (optname == SO_ERROR) {
799                 if (*((int *)optval) != 0) {
800                         *((int *) optval) = mono_w32socket_convert_error (*((int *)optval));
801                         socket_handle->saved_error = *((int *)optval);
802                 } else {
803                         *((int *)optval) = socket_handle->saved_error;
804                 }
805         }
806
807         return 0;
808 }
809
810 gint
811 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen)
812 {
813         gpointer handle;
814         gint ret;
815         gpointer tmp_val;
816 #if defined (__linux__)
817         /* This has its address taken so it cannot be moved to the if block which uses it */
818         gint bufsize = 0;
819 #endif
820         struct timeval tv;
821
822         handle = GUINT_TO_POINTER (sock);
823         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
824                 mono_w32socket_set_last_error (WSAENOTSOCK);
825                 return SOCKET_ERROR;
826         }
827
828         tmp_val = optval;
829         if (level == SOL_SOCKET &&
830             (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
831                 int ms = *((int *) optval);
832                 tv.tv_sec = ms / 1000;
833                 tv.tv_usec = (ms % 1000) * 1000;        // micro from milli
834                 tmp_val = &tv;
835                 optlen = sizeof (tv);
836         }
837 #if defined (__linux__)
838         else if (level == SOL_SOCKET &&
839                    (optname == SO_SNDBUF || optname == SO_RCVBUF)) {
840                 /* According to socket(7) the Linux kernel doubles the
841                  * buffer sizes "to allow space for bookkeeping
842                  * overhead."
843                  */
844                 bufsize = *((int *) optval);
845
846                 bufsize /= 2;
847                 tmp_val = &bufsize;
848         }
849 #endif
850
851         ret = setsockopt (sock, level, optname, tmp_val, optlen);
852         if (ret == -1) {
853                 gint errnum = errno;
854                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__, g_strerror (errno));
855                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
856                 return SOCKET_ERROR;
857         }
858
859 #if defined (SO_REUSEPORT)
860         /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested.  */
861         if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
862                 int type;
863                 socklen_t type_len = sizeof (type);
864
865                 if (!getsockopt (sock, level, SO_TYPE, &type, &type_len)) {
866                         if (type == SOCK_DGRAM || type == SOCK_STREAM)
867                                 setsockopt (sock, level, SO_REUSEPORT, tmp_val, optlen);
868                 }
869         }
870 #endif
871
872         return ret;
873 }
874
875 gint
876 mono_w32socket_listen (SOCKET sock, gint backlog)
877 {
878         gpointer handle;
879         gint ret;
880
881         handle = GUINT_TO_POINTER (sock);
882         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
883                 mono_w32socket_set_last_error (WSAENOTSOCK);
884                 return SOCKET_ERROR;
885         }
886
887         ret = listen (sock, backlog);
888         if (ret == -1) {
889                 gint errnum = errno;
890                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, g_strerror (errno));
891                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
892                 return SOCKET_ERROR;
893         }
894
895         return 0;
896 }
897
898 gint
899 mono_w32socket_shutdown (SOCKET sock, gint how)
900 {
901         MonoW32HandleSocket *socket_handle;
902         gpointer handle;
903         gint ret;
904
905         handle = GUINT_TO_POINTER (sock);
906         if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
907                 mono_w32socket_set_last_error (WSAENOTSOCK);
908                 return SOCKET_ERROR;
909         }
910
911         if (how == SHUT_RD || how == SHUT_RDWR)
912                 socket_handle->still_readable = 0;
913
914         ret = shutdown (sock, how);
915         if (ret == -1) {
916                 gint errnum = errno;
917                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__, g_strerror (errno));
918                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
919                 return SOCKET_ERROR;
920         }
921
922         return ret;
923 }
924
925 gint
926 mono_w32socket_disconnect (SOCKET sock, gboolean reuse)
927 {
928         MonoW32HandleSocket *socket_handle;
929         gpointer handle;
930         SOCKET newsock;
931         gint ret;
932
933         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: called on socket %d!", __func__, sock);
934
935         /* We could check the socket type here and fail unless its
936          * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
937          * if we really wanted to */
938
939         handle = GUINT_TO_POINTER (sock);
940         if (!mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle)) {
941                 mono_w32socket_set_last_error (WSAENOTSOCK);
942                 return SOCKET_ERROR;
943         }
944
945         newsock = socket (socket_handle->domain, socket_handle->type, socket_handle->protocol);
946         if (newsock == -1) {
947                 gint errnum = errno;
948                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: socket error: %s", __func__, g_strerror (errnum));
949                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
950                 return SOCKET_ERROR;
951         }
952
953         /* According to Stevens "Advanced Programming in the UNIX
954          * Environment: UNIX File I/O" dup2() is atomic so there
955          * should not be a race condition between the old fd being
956          * closed and the new socket fd being copied over */
957         do {
958                 ret = dup2 (newsock, sock);
959         } while (ret == -1 && errno == EAGAIN);
960
961         if (ret == -1) {
962                 gint errnum = errno;
963                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: dup2 error: %s", __func__, g_strerror (errnum));
964                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
965                 return SOCKET_ERROR;
966         }
967
968         close (newsock);
969
970         return 0;
971 }
972
973 static gboolean
974 extension_disconect (SOCKET sock, OVERLAPPED *overlapped, guint32 flags, guint32 reserved)
975 {
976         return mono_w32socket_disconnect (sock, flags & TF_REUSE_SOCKET) == 0;
977 }
978
979 static gboolean
980 extension_transmit_file (SOCKET sock, gpointer file_handle, guint32 bytes_to_write, guint32 bytes_per_send,
981         OVERLAPPED *ol, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags)
982 {
983         return mono_w32socket_transmit_file (sock, file_handle, buffers, flags, FALSE);
984 }
985
986 static struct {
987         GUID guid;
988         gpointer func;
989 } extension_functions[] = {
990         { {0x7fda2e11,0x8630,0x436f,{0xa0,0x31,0xf5,0x36,0xa6,0xee,0xc1,0x57}} /* WSAID_DISCONNECTEX */, extension_disconect },
991         { {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}} /* WSAID_TRANSMITFILE */, extension_transmit_file },
992         { {0} , NULL },
993 };
994
995 gint
996 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written)
997 {
998         gpointer handle;
999         gint ret;
1000         gchar *buffer;
1001
1002         handle = GUINT_TO_POINTER (sock);
1003         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1004                 mono_w32socket_set_last_error (WSAENOTSOCK);
1005                 return SOCKET_ERROR;
1006         }
1007
1008         if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) {
1009                 gint i;
1010                 GUID *guid;
1011
1012                 if (inputlen < sizeof(GUID)) {
1013                         /* As far as I can tell, windows doesn't
1014                          * actually set an error here...
1015                          */
1016                         mono_w32socket_set_last_error (WSAEINVAL);
1017                         return SOCKET_ERROR;
1018                 }
1019
1020                 if (outputlen < sizeof(gpointer)) {
1021                         /* Or here... */
1022                         mono_w32socket_set_last_error (WSAEINVAL);
1023                         return SOCKET_ERROR;
1024                 }
1025
1026                 if (output == NULL) {
1027                         /* Or here */
1028                         mono_w32socket_set_last_error (WSAEINVAL);
1029                         return SOCKET_ERROR;
1030                 }
1031
1032                 guid = (GUID*) input;
1033                 for (i = 0; extension_functions[i].func; i++) {
1034                         if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) {
1035                                 memcpy (output, &extension_functions[i].func, sizeof(gpointer));
1036                                 *written = sizeof(gpointer);
1037                                 return 0;
1038                         }
1039                 }
1040
1041                 mono_w32socket_set_last_error (WSAEINVAL);
1042                 return SOCKET_ERROR;
1043         }
1044
1045         if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) {
1046                 guint32 onoff;
1047
1048                 if (inputlen < 3 * sizeof (guint32)) {
1049                         mono_w32socket_set_last_error (WSAEINVAL);
1050                         return SOCKET_ERROR;
1051                 }
1052
1053                 onoff = *((guint32*) input);
1054
1055                 ret = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32));
1056                 if (ret < 0) {
1057                         mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1058                         return SOCKET_ERROR;
1059                 }
1060
1061 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL)
1062                 if (onoff != 0) {
1063                         /* Values are in ms, but we need s */
1064                         guint32 keepalivetime, keepaliveinterval, rem;
1065
1066                         keepalivetime = *(((guint32*) input) + 1);
1067                         keepaliveinterval = *(((guint32*) input) + 2);
1068
1069                         /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */
1070                         rem = keepalivetime % 1000;
1071                         keepalivetime /= 1000;
1072                         if (keepalivetime == 0 || rem >= 500)
1073                                 keepalivetime++;
1074                         ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32));
1075                         if (ret == 0) {
1076                                 rem = keepaliveinterval % 1000;
1077                                 keepaliveinterval /= 1000;
1078                                 if (keepaliveinterval == 0 || rem >= 500)
1079                                         keepaliveinterval++;
1080                                 ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32));
1081                         }
1082                         if (ret != 0) {
1083                                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errno));
1084                                 return SOCKET_ERROR;
1085                         }
1086
1087                         return 0;
1088                 }
1089 #endif
1090
1091                 return 0;
1092         }
1093
1094         buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL;
1095
1096         ret = ioctl (sock, command, buffer);
1097         if (ret == -1) {
1098                 g_free (buffer);
1099
1100                 gint errnum = errno;
1101                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__, g_strerror (errno));
1102                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1103                 return SOCKET_ERROR;
1104         }
1105
1106         if (!buffer) {
1107                 *written = 0;
1108                 return 0;
1109         }
1110
1111         /* We just copy the buffer to the output. Some ioctls
1112          * don't even output any data, but, well...
1113          *
1114          * NB windows returns WSAEFAULT if outputlen is too small */
1115         inputlen = (inputlen > outputlen) ? outputlen : inputlen;
1116
1117         if (inputlen > 0 && output != NULL)
1118                 memcpy (output, buffer, inputlen);
1119
1120         g_free (buffer);
1121         *written = inputlen;
1122
1123         return 0;
1124 }
1125
1126 gint
1127 mono_w32socket_set_blocking (SOCKET socket, gboolean blocking)
1128 {
1129         gint ret;
1130         gpointer handle;
1131
1132         handle = GINT_TO_POINTER (socket);
1133         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1134                 mono_w32socket_set_last_error (WSAENOTSOCK);
1135                 return SOCKET_ERROR;
1136         }
1137
1138 #ifdef O_NONBLOCK
1139         /* This works better than ioctl(...FIONBIO...)
1140          * on Linux (it causes connect to return
1141          * EINPROGRESS, but the ioctl doesn't seem to) */
1142         ret = fcntl (socket, F_GETFL, 0);
1143         if (ret != -1)
1144                 ret = fcntl (socket, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK)));
1145 #endif /* O_NONBLOCK */
1146
1147         if (ret == -1) {
1148                 gint errnum = errno;
1149                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno));
1150                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1151                 return SOCKET_ERROR;
1152         }
1153
1154         return 0;
1155 }
1156
1157 gint
1158 mono_w32socket_get_available (SOCKET socket, guint64 *amount)
1159 {
1160         gint ret;
1161         gpointer handle;
1162
1163         handle = GINT_TO_POINTER (socket);
1164         if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) {
1165                 mono_w32socket_set_last_error (WSAENOTSOCK);
1166                 return SOCKET_ERROR;
1167         }
1168
1169 #if defined (PLATFORM_MACOSX)
1170         // ioctl (socket, FIONREAD, XXX) returns the size of
1171         // the UDP header as well on Darwin.
1172         //
1173         // Use getsockopt SO_NREAD instead to get the
1174         // right values for TCP and UDP.
1175         //
1176         // ai_canonname can be null in some cases on darwin,
1177         // where the runtime assumes it will be the value of
1178         // the ip buffer.
1179
1180         socklen_t optlen = sizeof (int);
1181         ret = getsockopt (socket, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen);
1182 #else
1183         ret = ioctl (socket, FIONREAD, (gulong*) amount);
1184 #endif
1185
1186         if (ret == -1) {
1187                 gint errnum = errno;
1188                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno));
1189                 mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum));
1190                 return SOCKET_ERROR;
1191         }
1192
1193         return 0;
1194 }
1195
1196 void
1197 mono_w32socket_set_last_error (gint32 error)
1198 {
1199         SetLastError (error);
1200 }
1201
1202 gint32
1203 mono_w32socket_get_last_error (void)
1204 {
1205         return GetLastError ();
1206 }
1207
1208 gint32
1209 mono_w32socket_convert_error (gint error)
1210 {
1211         switch (error) {
1212         case 0: return ERROR_SUCCESS;
1213         case EACCES: return WSAEACCES;
1214 #ifdef EADDRINUSE
1215         case EADDRINUSE: return WSAEADDRINUSE;
1216 #endif
1217 #ifdef EAFNOSUPPORT
1218         case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
1219 #endif
1220 #if EAGAIN != EWOULDBLOCK
1221         case EAGAIN: return WSAEWOULDBLOCK;
1222 #endif
1223 #ifdef EALREADY
1224         case EALREADY: return WSAEALREADY;
1225 #endif
1226         case EBADF: return WSAENOTSOCK;
1227 #ifdef ECONNABORTED
1228         case ECONNABORTED: return WSAENETDOWN;
1229 #endif
1230 #ifdef ECONNREFUSED
1231         case ECONNREFUSED: return WSAECONNREFUSED;
1232 #endif
1233 #ifdef ECONNRESET
1234         case ECONNRESET: return WSAECONNRESET;
1235 #endif
1236         case EFAULT: return WSAEFAULT;
1237 #ifdef EHOSTUNREACH
1238         case EHOSTUNREACH: return WSAEHOSTUNREACH;
1239 #endif
1240 #ifdef EINPROGRESS
1241         case EINPROGRESS: return WSAEINPROGRESS;
1242 #endif
1243         case EINTR: return WSAEINTR;
1244         case EINVAL: return WSAEINVAL;
1245         /*FIXME: case EIO: return WSAE????; */
1246 #ifdef EISCONN
1247         case EISCONN: return WSAEISCONN;
1248 #endif
1249         /* FIXME: case ELOOP: return WSA????; */
1250         case EMFILE: return WSAEMFILE;
1251 #ifdef EMSGSIZE
1252         case EMSGSIZE: return WSAEMSGSIZE;
1253 #endif
1254         /* FIXME: case ENAMETOOLONG: return WSAEACCES; */
1255 #ifdef ENETUNREACH
1256         case ENETUNREACH: return WSAENETUNREACH;
1257 #endif
1258 #ifdef ENOBUFS
1259         case ENOBUFS: return WSAENOBUFS; /* not documented */
1260 #endif
1261         /* case ENOENT: return WSAE????; */
1262         case ENOMEM: return WSAENOBUFS;
1263 #ifdef ENOPROTOOPT
1264         case ENOPROTOOPT: return WSAENOPROTOOPT;
1265 #endif
1266 #ifdef ENOSR
1267         case ENOSR: return WSAENETDOWN;
1268 #endif
1269 #ifdef ENOTCONN
1270         case ENOTCONN: return WSAENOTCONN;
1271 #endif
1272         /*FIXME: case ENOTDIR: return WSAE????; */
1273 #ifdef ENOTSOCK
1274         case ENOTSOCK: return WSAENOTSOCK;
1275 #endif
1276         case ENOTTY: return WSAENOTSOCK;
1277 #ifdef EOPNOTSUPP
1278         case EOPNOTSUPP: return WSAEOPNOTSUPP;
1279 #endif
1280         case EPERM: return WSAEACCES;
1281         case EPIPE: return WSAESHUTDOWN;
1282 #ifdef EPROTONOSUPPORT
1283         case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
1284 #endif
1285 #if ERESTARTSYS
1286         case ERESTARTSYS: return WSAENETDOWN;
1287 #endif
1288         /*FIXME: case EROFS: return WSAE????; */
1289 #ifdef ESOCKTNOSUPPORT
1290         case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
1291 #endif
1292 #ifdef ETIMEDOUT
1293         case ETIMEDOUT: return WSAETIMEDOUT;
1294 #endif
1295 #ifdef EWOULDBLOCK
1296         case EWOULDBLOCK: return WSAEWOULDBLOCK;
1297 #endif
1298 #ifdef EADDRNOTAVAIL
1299         case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
1300 #endif
1301         /* This might happen with unix sockets */
1302         case ENOENT: return WSAECONNREFUSED;
1303 #ifdef EDESTADDRREQ
1304         case EDESTADDRREQ: return WSAEDESTADDRREQ;
1305 #endif
1306 #ifdef EHOSTDOWN
1307         case EHOSTDOWN: return WSAEHOSTDOWN;
1308 #endif
1309 #ifdef ENETDOWN
1310         case ENETDOWN: return WSAENETDOWN;
1311 #endif
1312         case ENODEV: return WSAENETDOWN;
1313         default:
1314                 g_error ("%s: no translation into winsock error for (%d) \"%s\"", __func__, error, g_strerror (error));
1315         }
1316 }
1317
1318 gboolean
1319 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
1320 {
1321 #if defined (SO_REUSEPORT)
1322         return TRUE;
1323 #else
1324 #ifdef __linux__
1325         /* Linux always supports double binding for UDP, even on older kernels. */
1326         if (proto == ProtocolType_Udp)
1327                 return TRUE;
1328 #endif
1329         return FALSE;
1330 #endif
1331 }