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