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