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