merge -r 60814:60815
[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 #include <glib.h>
12 #include <pthread.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/ioctl.h>
18 #ifdef HAVE_SYS_FILIO_H
19 #include <sys/filio.h>     /* defines FIONBIO and FIONREAD */
20 #endif
21 #ifdef HAVE_SYS_SOCKIO_H
22 #include <sys/sockio.h>    /* defines SIOCATMARK */
23 #endif
24 #include <unistd.h>
25 #include <fcntl.h>
26
27 #ifndef HAVE_MSG_NOSIGNAL
28 #include <signal.h>
29 #endif
30
31 #include <mono/io-layer/wapi.h>
32 #include <mono/io-layer/wapi-private.h>
33 #include <mono/io-layer/socket-private.h>
34 #include <mono/io-layer/handles-private.h>
35 #include <mono/io-layer/socket-wrappers.h>
36
37 #undef DEBUG
38
39 static guint32 startup_count=0;
40 static pthread_key_t error_key;
41 static mono_once_t error_key_once=MONO_ONCE_INIT;
42
43 static void socket_close (gpointer handle, gpointer data);
44
45 struct _WapiHandleOps _wapi_socket_ops = {
46         socket_close,           /* close */
47         NULL,                   /* signal */
48         NULL,                   /* own */
49         NULL,                   /* is_owned */
50         NULL,                   /* special_wait */
51         NULL                    /* prewait */
52 };
53
54 static mono_once_t socket_ops_once=MONO_ONCE_INIT;
55
56 static void socket_ops_init (void)
57 {
58         /* No capabilities to register */
59 }
60
61 static void socket_close (gpointer handle, gpointer data G_GNUC_UNUSED)
62 {
63         int ret;
64
65 #ifdef DEBUG
66         g_message ("%s: closing socket handle %p", __func__, handle);
67 #endif
68
69         if (startup_count == 0) {
70                 WSASetLastError (WSANOTINITIALISED);
71                 return;
72         }
73
74         do {
75                 ret = close (GPOINTER_TO_UINT(handle));
76         } while (ret == -1 && errno == EINTR &&
77                  !_wapi_thread_cur_apc_pending ());
78         
79         if (ret == -1) {
80                 gint errnum = errno;
81 #ifdef DEBUG
82                 g_message ("%s: close error: %s", __func__, strerror (errno));
83 #endif
84                 errnum = errno_to_WSA (errnum, __func__);
85                 WSASetLastError (errnum);
86         }
87 }
88
89 int WSAStartup(guint32 requested, WapiWSAData *data)
90 {
91         if (data == NULL) {
92                 return(WSAEFAULT);
93         }
94
95         /* Insist on v2.0+ */
96         if (requested < MAKEWORD(2,0)) {
97                 return(WSAVERNOTSUPPORTED);
98         }
99
100         startup_count++;
101
102         /* I've no idea what is the minor version of the spec I read */
103         data->wHighVersion = MAKEWORD(2,0);
104         
105         data->wVersion = requested < data->wHighVersion? requested:
106                 data->wHighVersion;
107
108 #ifdef DEBUG
109         g_message ("%s: high version 0x%x", __func__, data->wHighVersion);
110 #endif
111         
112         strncpy (data->szDescription, "WAPI", WSADESCRIPTION_LEN);
113         strncpy (data->szSystemStatus, "groovy", WSASYS_STATUS_LEN);
114         
115         return(0);
116 }
117
118 static gboolean
119 cleanup_close (gpointer handle, gpointer data)
120 {
121         _wapi_handle_ops_close (handle, NULL);
122         return TRUE;
123 }
124
125 int WSACleanup(void)
126 {
127 #ifdef DEBUG
128         g_message ("%s: cleaning up", __func__);
129 #endif
130
131         if (--startup_count) {
132                 /* Do nothing */
133                 return(0);
134         }
135
136         _wapi_handle_foreach (WAPI_HANDLE_SOCKET, cleanup_close, NULL);
137         return(0);
138 }
139
140 static void error_init(void)
141 {
142         int ret;
143         
144         ret = pthread_key_create (&error_key, NULL);
145         g_assert (ret == 0);
146 }
147
148 void WSASetLastError(int error)
149 {
150         int ret;
151         
152         mono_once (&error_key_once, error_init);
153         ret = pthread_setspecific (error_key, GINT_TO_POINTER(error));
154         g_assert (ret == 0);
155 }
156
157 int WSAGetLastError(void)
158 {
159         int err;
160         void *errptr;
161         
162         mono_once (&error_key_once, error_init);
163         errptr = pthread_getspecific (error_key);
164         err = GPOINTER_TO_INT(errptr);
165         
166         return(err);
167 }
168
169 int closesocket(guint32 fd)
170 {
171         gpointer handle = GUINT_TO_POINTER (fd);
172         
173         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
174                 WSASetLastError (WSAENOTSOCK);
175                 return(0);
176         }
177         
178         _wapi_handle_unref (handle);
179         return(0);
180 }
181
182 guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen)
183 {
184         gpointer handle = GUINT_TO_POINTER (fd);
185         gpointer new_handle;
186         int new_fd;
187         
188         if (startup_count == 0) {
189                 WSASetLastError (WSANOTINITIALISED);
190                 return(INVALID_SOCKET);
191         }
192         
193         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
194                 WSASetLastError (WSAENOTSOCK);
195                 return(INVALID_SOCKET);
196         }
197         
198         do {
199                 new_fd = accept (fd, addr, addrlen);
200         } while (new_fd == -1 && errno == EINTR &&
201                  !_wapi_thread_cur_apc_pending());
202
203         if (new_fd == -1) {
204                 gint errnum = errno;
205 #ifdef DEBUG
206                 g_message ("%s: accept error: %s", __func__, strerror(errno));
207 #endif
208
209                 errnum = errno_to_WSA (errnum, __func__);
210                 WSASetLastError (errnum);
211                 
212                 return(INVALID_SOCKET);
213         }
214
215         if (new_fd >= _wapi_fd_reserve) {
216 #ifdef DEBUG
217                 g_message ("%s: File descriptor is too big", __func__);
218 #endif
219
220                 WSASetLastError (WSASYSCALLFAILURE);
221                 
222                 close (new_fd);
223                 
224                 return(INVALID_SOCKET);
225         }
226
227         new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd, NULL);
228         if(new_handle == _WAPI_HANDLE_INVALID) {
229                 g_warning ("%s: error creating socket handle", __func__);
230                 WSASetLastError (ERROR_GEN_FAILURE);
231                 return(INVALID_SOCKET);
232         }
233
234 #ifdef DEBUG
235         g_message ("%s: returning newly accepted socket handle %p with",
236                    __func__, new_handle);
237 #endif
238         
239         return(new_fd);
240 }
241
242 int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
243 {
244         gpointer handle = GUINT_TO_POINTER (fd);
245         int ret;
246         
247         if (startup_count == 0) {
248                 WSASetLastError (WSANOTINITIALISED);
249                 return(SOCKET_ERROR);
250         }
251
252         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
253                 WSASetLastError (WSAENOTSOCK);
254                 return(SOCKET_ERROR);
255         }
256         
257         ret = bind (fd, my_addr, addrlen);
258         if (ret == -1) {
259                 gint errnum = errno;
260 #ifdef DEBUG
261                 g_message ("%s: bind error: %s", __func__, strerror(errno));
262 #endif
263                 errnum = errno_to_WSA (errnum, __func__);
264                 WSASetLastError (errnum);
265                 
266                 return(SOCKET_ERROR);
267         }
268         return(ret);
269 }
270
271 int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
272                   socklen_t addrlen)
273 {
274         gpointer handle = GUINT_TO_POINTER (fd);
275         int ret;
276         gint errnum;
277         
278         if (startup_count == 0) {
279                 WSASetLastError (WSANOTINITIALISED);
280                 return(SOCKET_ERROR);
281         }
282         
283         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
284                 WSASetLastError (WSAENOTSOCK);
285                 return(SOCKET_ERROR);
286         }
287         
288         do {
289                 ret = connect (fd, serv_addr, addrlen);
290         } while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending());
291
292         if (ret == -1 && errno == EACCES) {
293                 /* Try setting SO_BROADCAST and connecting again, but
294                  * keep the original errno
295                  */
296                 int true=1;
297                 
298                 errnum = errno;
299
300                 ret = setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &true,
301                                   sizeof(true));
302                 if (ret == 0) {
303                         do {
304                                 ret = connect (fd, serv_addr, addrlen);
305                         } while (ret==-1 && errno==EINTR &&
306                                  !_wapi_thread_cur_apc_pending());
307                 }
308         } else if (ret == -1) {
309                 errnum = errno;
310         }
311         
312         if (ret == -1) {
313 #ifdef DEBUG
314                 g_message ("%s: connect error: %s", __func__,
315                            strerror (errnum));
316 #endif
317                 errnum = errno_to_WSA (errnum, __func__);
318                 if (errnum == WSAEINPROGRESS)
319                         errnum = WSAEWOULDBLOCK; /* see bug #73053 */
320
321                 WSASetLastError (errnum);
322                 
323                 return(SOCKET_ERROR);
324         }
325         return(ret);
326 }
327
328 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
329 {
330         gpointer handle = GUINT_TO_POINTER (fd);
331         int ret;
332         
333         if (startup_count == 0) {
334                 WSASetLastError (WSANOTINITIALISED);
335                 return(SOCKET_ERROR);
336         }
337         
338         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
339                 WSASetLastError (WSAENOTSOCK);
340                 return(SOCKET_ERROR);
341         }
342
343         ret = getpeername (fd, name, namelen);
344         if (ret == -1) {
345                 gint errnum = errno;
346 #ifdef DEBUG
347                 g_message ("%s: getpeername error: %s", __func__,
348                            strerror (errno));
349 #endif
350
351                 errnum = errno_to_WSA (errnum, __func__);
352                 WSASetLastError (errnum);
353
354                 return(SOCKET_ERROR);
355         }
356         
357         return(ret);
358 }
359
360 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
361 {
362         gpointer handle = GUINT_TO_POINTER (fd);
363         int ret;
364         
365         if (startup_count == 0) {
366                 WSASetLastError (WSANOTINITIALISED);
367                 return(SOCKET_ERROR);
368         }
369         
370         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
371                 WSASetLastError (WSAENOTSOCK);
372                 return(SOCKET_ERROR);
373         }
374
375         ret = getsockname (fd, name, namelen);
376         if (ret == -1) {
377                 gint errnum = errno;
378 #ifdef DEBUG
379                 g_message ("%s: getsockname error: %s", __func__,
380                            strerror (errno));
381 #endif
382
383                 errnum = errno_to_WSA (errnum, __func__);
384                 WSASetLastError (errnum);
385
386                 return(SOCKET_ERROR);
387         }
388         
389         return(ret);
390 }
391
392 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
393                      socklen_t *optlen)
394 {
395         gpointer handle = GUINT_TO_POINTER (fd);
396         int ret;
397         struct timeval tv;
398         void *tmp_val;
399
400         if (startup_count == 0) {
401                 WSASetLastError (WSANOTINITIALISED);
402                 return(SOCKET_ERROR);
403         }
404         
405         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
406                 WSASetLastError (WSAENOTSOCK);
407                 return(SOCKET_ERROR);
408         }
409
410         tmp_val = optval;
411         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
412                 tmp_val = &tv;
413                 *optlen = sizeof (tv);
414         }
415
416         ret = getsockopt (fd, level, optname, tmp_val, optlen);
417         if (ret == -1) {
418                 gint errnum = errno;
419 #ifdef DEBUG
420                 g_message ("%s: getsockopt error: %s", __func__,
421                            strerror (errno));
422 #endif
423
424                 errnum = errno_to_WSA (errnum, __func__);
425                 WSASetLastError (errnum);
426                 
427                 return(SOCKET_ERROR);
428         }
429
430         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
431                 *((int *) optval)  = tv.tv_sec * 1000 + tv.tv_usec;
432                 *optlen = sizeof (int);
433         }
434
435         if (optname == SO_ERROR) {
436                 if (*((int *)optval) != 0) {
437                         *((int *) optval) = errno_to_WSA (*((int *)optval),
438                                                           __func__);
439                 }
440         }
441         
442         return(ret);
443 }
444
445 int _wapi_listen(guint32 fd, int backlog)
446 {
447         gpointer handle = GUINT_TO_POINTER (fd);
448         int ret;
449         
450         if (startup_count == 0) {
451                 WSASetLastError (WSANOTINITIALISED);
452                 return(SOCKET_ERROR);
453         }
454         
455         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
456                 WSASetLastError (WSAENOTSOCK);
457                 return(SOCKET_ERROR);
458         }
459         
460         ret = listen (fd, backlog);
461         if (ret == -1) {
462                 gint errnum = errno;
463 #ifdef DEBUG
464                 g_message ("%s: listen error: %s", __func__, strerror (errno));
465 #endif
466
467                 errnum = errno_to_WSA (errnum, __func__);
468                 WSASetLastError (errnum);
469
470                 return(SOCKET_ERROR);
471         }
472
473         return(0);
474 }
475
476 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
477 {
478         return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
479 }
480
481 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
482                    struct sockaddr *from, socklen_t *fromlen)
483 {
484         gpointer handle = GUINT_TO_POINTER (fd);
485         int ret;
486         
487         if (startup_count == 0) {
488                 WSASetLastError (WSANOTINITIALISED);
489                 return(SOCKET_ERROR);
490         }
491         
492         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
493                 WSASetLastError (WSAENOTSOCK);
494                 return(SOCKET_ERROR);
495         }
496         
497         do {
498                 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
499         } while (ret == -1 && errno == EINTR &&
500                  !_wapi_thread_cur_apc_pending ());
501
502         if (ret == -1) {
503                 gint errnum = errno;
504 #ifdef DEBUG
505                 g_message ("%s: recv error: %s", __func__, strerror(errno));
506 #endif
507
508                 errnum = errno_to_WSA (errnum, __func__);
509                 WSASetLastError (errnum);
510                 
511                 return(SOCKET_ERROR);
512         }
513         return(ret);
514 }
515
516 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
517 {
518         gpointer handle = GUINT_TO_POINTER (fd);
519         int ret;
520         
521         if (startup_count == 0) {
522                 WSASetLastError (WSANOTINITIALISED);
523                 return(SOCKET_ERROR);
524         }
525         
526         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
527                 WSASetLastError (WSAENOTSOCK);
528                 return(SOCKET_ERROR);
529         }
530
531         do {
532                 ret = send (fd, msg, len, send_flags);
533         } while (ret == -1 && errno == EINTR &&
534                  !_wapi_thread_cur_apc_pending ());
535
536         if (ret == -1) {
537                 gint errnum = errno;
538 #ifdef DEBUG
539                 g_message ("%s: send error: %s", __func__, strerror (errno));
540 #endif
541
542                 errnum = errno_to_WSA (errnum, __func__);
543                 WSASetLastError (errnum);
544                 
545                 return(SOCKET_ERROR);
546         }
547         return(ret);
548 }
549
550 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
551                  const struct sockaddr *to, socklen_t tolen)
552 {
553         gpointer handle = GUINT_TO_POINTER (fd);
554         int ret;
555         
556         if (startup_count == 0) {
557                 WSASetLastError (WSANOTINITIALISED);
558                 return(SOCKET_ERROR);
559         }
560         
561         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
562                 WSASetLastError (WSAENOTSOCK);
563                 return(SOCKET_ERROR);
564         }
565         
566         do {
567                 ret = sendto (fd, msg, len, send_flags, to, tolen);
568         } while (ret == -1 && errno == EINTR &&
569                  !_wapi_thread_cur_apc_pending ());
570
571         if (ret == -1) {
572                 gint errnum = errno;
573 #ifdef DEBUG
574                 g_message ("%s: send error: %s", __func__, strerror (errno));
575 #endif
576
577                 errnum = errno_to_WSA (errnum, __func__);
578                 WSASetLastError (errnum);
579                 
580                 return(SOCKET_ERROR);
581         }
582         return(ret);
583 }
584
585 int _wapi_setsockopt(guint32 fd, int level, int optname,
586                      const void *optval, socklen_t optlen)
587 {
588         gpointer handle = GUINT_TO_POINTER (fd);
589         int ret;
590         const void *tmp_val;
591         struct timeval tv;
592         
593         if (startup_count == 0) {
594                 WSASetLastError (WSANOTINITIALISED);
595                 return(SOCKET_ERROR);
596         }
597         
598         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
599                 WSASetLastError (WSAENOTSOCK);
600                 return(SOCKET_ERROR);
601         }
602
603         tmp_val = optval;
604         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
605                 int ms = *((int *) optval);
606                 tv.tv_sec = ms / 1000;
607                 tv.tv_usec = ms % 1000;
608                 tmp_val = &tv;
609                 optlen = sizeof (tv);
610         }
611                 
612         ret = setsockopt (fd, level, optname, tmp_val, optlen);
613         if (ret == -1) {
614                 gint errnum = errno;
615 #ifdef DEBUG
616                 g_message ("%s: setsockopt error: %s", __func__,
617                            strerror (errno));
618 #endif
619
620                 errnum = errno_to_WSA (errnum, __func__);
621                 WSASetLastError (errnum);
622                 
623                 return(SOCKET_ERROR);
624         }
625         
626         return(ret);
627 }
628
629 int _wapi_shutdown(guint32 fd, int how)
630 {
631         gpointer handle = GUINT_TO_POINTER (fd);
632         int ret;
633         
634         if (startup_count == 0) {
635                 WSASetLastError (WSANOTINITIALISED);
636                 return(SOCKET_ERROR);
637         }
638         
639         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
640                 WSASetLastError (WSAENOTSOCK);
641                 return(SOCKET_ERROR);
642         }
643         
644         ret = shutdown (fd, how);
645         if (ret == -1) {
646                 gint errnum = errno;
647 #ifdef DEBUG
648                 g_message ("%s: shutdown error: %s", __func__,
649                            strerror (errno));
650 #endif
651
652                 errnum = errno_to_WSA (errnum, __func__);
653                 WSASetLastError (errnum);
654                 
655                 return(SOCKET_ERROR);
656         }
657         
658         return(ret);
659 }
660
661 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
662                      guint32 unused2, guint32 unused3)
663 {
664         gpointer handle;
665         int fd;
666         
667         fd = socket (domain, type, protocol);
668         if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
669             protocol == 0) {
670                 /* Retry with protocol == 4 (see bug #54565) */
671                 fd = socket (AF_INET, SOCK_RAW, 4);
672         }
673         
674         if (fd == -1) {
675                 gint errnum = errno;
676 #ifdef DEBUG
677                 g_message ("%s: socket error: %s", __func__, strerror (errno));
678 #endif
679                 errnum = errno_to_WSA (errnum, __func__);
680                 WSASetLastError (errnum);
681
682                 return(INVALID_SOCKET);
683         }
684
685         if (fd >= _wapi_fd_reserve) {
686 #ifdef DEBUG
687                 g_message ("%s: File descriptor is too big", __func__);
688 #endif
689
690                 WSASetLastError (WSASYSCALLFAILURE);
691                 close (fd);
692                 
693                 return(INVALID_SOCKET);
694         }
695         
696         
697         mono_once (&socket_ops_once, socket_ops_init);
698         
699         handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, NULL);
700         if (handle == _WAPI_HANDLE_INVALID) {
701                 g_warning ("%s: error creating socket handle", __func__);
702                 return(INVALID_SOCKET);
703         }
704
705 #ifdef DEBUG
706         g_message ("%s: returning socket handle %p", __func__, handle);
707 #endif
708
709         return(fd);
710 }
711
712 struct hostent *_wapi_gethostbyname(const char *hostname)
713 {
714         struct hostent *he;
715         
716         if (startup_count == 0) {
717                 WSASetLastError (WSANOTINITIALISED);
718                 return(NULL);
719         }
720
721         he = gethostbyname (hostname);
722         if (he == NULL) {
723 #ifdef DEBUG
724                 g_message ("%s: gethostbyname error: %s", __func__,
725                            strerror (h_errno));
726 #endif
727
728                 switch(h_errno) {
729                 case HOST_NOT_FOUND:
730                         WSASetLastError (WSAHOST_NOT_FOUND);
731                         break;
732 #if NO_ADDRESS != NO_DATA
733                 case NO_ADDRESS:
734 #endif
735                 case NO_DATA:
736                         WSASetLastError (WSANO_DATA);
737                         break;
738                 case NO_RECOVERY:
739                         WSASetLastError (WSANO_RECOVERY);
740                         break;
741                 case TRY_AGAIN:
742                         WSASetLastError (WSATRY_AGAIN);
743                         break;
744                 default:
745                         g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno);
746                         break;
747                 }
748         }
749         
750         return(he);
751 }
752
753 int
754 WSAIoctl (guint32 fd, gint32 command,
755           gchar *input, gint i_len,
756           gchar *output, gint o_len, glong *written,
757           void *unused1, void *unused2)
758 {
759         gpointer handle = GUINT_TO_POINTER (fd);
760         int ret;
761         gchar *buffer = NULL;
762
763         if (startup_count == 0) {
764                 WSASetLastError (WSANOTINITIALISED);
765                 return(SOCKET_ERROR);
766         }
767
768         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
769                 WSASetLastError (WSAENOTSOCK);
770                 return SOCKET_ERROR;
771         }
772
773         if (i_len > 0) {
774                 buffer = g_memdup (input, i_len);
775         }
776
777         ret = ioctl (fd, command, buffer);
778         if (ret == -1) {
779                 gint errnum = errno;
780 #ifdef DEBUG
781                 g_message("%s: WSAIoctl error: %s", __func__,
782                           strerror (errno));
783 #endif
784
785                 errnum = errno_to_WSA (errnum, __func__);
786                 WSASetLastError (errnum);
787                 g_free (buffer);
788                 
789                 return(SOCKET_ERROR);
790         }
791
792         if (buffer == NULL) {
793                 *written = 0;
794         } else {
795                 /* We just copy the buffer to the output. Some ioctls
796                  * don't even output any data, but, well...
797                  *
798                  * NB windows returns WSAEFAULT if o_len is too small
799                  */
800                 i_len = (i_len > o_len) ? o_len : i_len;
801
802                 if (i_len > 0 && output != NULL) {
803                         memcpy (output, buffer, i_len);
804                 }
805                 
806                 g_free (buffer);
807                 *written = i_len;
808         }
809
810         return(0);
811 }
812
813 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
814 {
815         gpointer handle = GUINT_TO_POINTER (fd);
816         int ret;
817         
818         if (startup_count == 0) {
819                 WSASetLastError (WSANOTINITIALISED);
820                 return(SOCKET_ERROR);
821         }
822         
823         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
824                 WSASetLastError (WSAENOTSOCK);
825                 return(SOCKET_ERROR);
826         }
827
828         switch(command){
829                 case FIONBIO:
830 #ifdef O_NONBLOCK
831                         /* This works better than ioctl(...FIONBIO...) 
832                          * on Linux (it causes connect to return
833                          * EINPROGRESS, but the ioctl doesn't seem to)
834                          */
835                         ret = fcntl(fd, F_GETFL, 0);
836                         if (ret != -1) {
837                                 if (*(gboolean *)arg) {
838                                         ret |= O_NONBLOCK;
839                                 } else {
840                                         ret &= ~O_NONBLOCK;
841                                 }
842                                 ret = fcntl(fd, F_SETFL, ret);
843                         }
844                         break;
845 #endif /* O_NONBLOCK */
846                 case FIONREAD:
847                 case SIOCATMARK:
848                         ret = ioctl (fd, command, arg);
849                         break;
850                 default:
851                         WSASetLastError (WSAEINVAL);
852                         return(SOCKET_ERROR);
853         }
854
855         if (ret == -1) {
856                 gint errnum = errno;
857 #ifdef DEBUG
858                 g_message ("%s: ioctl error: %s", __func__, strerror (errno));
859 #endif
860
861                 errnum = errno_to_WSA (errnum, __func__);
862                 WSASetLastError (errnum);
863                 
864                 return(SOCKET_ERROR);
865         }
866         
867         return(0);
868 }
869
870 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
871                  fd_set *exceptfds, struct timeval *timeout)
872 {
873         int ret;
874         
875         if (startup_count == 0) {
876                 WSASetLastError (WSANOTINITIALISED);
877                 return(SOCKET_ERROR);
878         }
879
880         do {
881                 ret = select(getdtablesize (), readfds, writefds, exceptfds,
882                              timeout);
883         } while (ret == -1 && errno == EINTR &&
884                  !_wapi_thread_cur_apc_pending ());
885
886         if (ret == -1) {
887                 gint errnum = errno;
888 #ifdef DEBUG
889                 g_message ("%s: select error: %s", __func__, strerror (errno));
890 #endif
891                 errnum = errno_to_WSA (errnum, __func__);
892                 WSASetLastError (errnum);
893                 
894                 return(SOCKET_ERROR);
895         }
896
897         return(ret);
898 }
899
900 void _wapi_FD_CLR(guint32 fd, fd_set *set)
901 {
902         gpointer handle = GUINT_TO_POINTER (fd);
903         
904         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
905                 WSASetLastError (WSAENOTSOCK);
906                 return;
907         }
908
909         FD_CLR (fd, set);
910 }
911
912 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
913 {
914         gpointer handle = GUINT_TO_POINTER (fd);
915         
916         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
917                 WSASetLastError (WSAENOTSOCK);
918                 return(0);
919         }
920
921         return(FD_ISSET (fd, set));
922 }
923
924 void _wapi_FD_SET(guint32 fd, fd_set *set)
925 {
926         gpointer handle = GUINT_TO_POINTER (fd);
927         
928         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
929                 WSASetLastError (WSAENOTSOCK);
930                 return;
931         }
932
933         FD_SET (fd, set);
934 }
935