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