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