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