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