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