* roottypes.cs: Rename from tree.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         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,2);
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 (%d >= %d)",
688                            __func__, fd, _wapi_fd_offset_table_size);
689 #endif
690
691                 WSASetLastError (WSASYSCALLFAILURE);
692                 close (fd);
693                 
694                 return(INVALID_SOCKET);
695         }
696         
697         
698         mono_once (&socket_ops_once, socket_ops_init);
699         
700         handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, NULL);
701         if (handle == _WAPI_HANDLE_INVALID) {
702                 g_warning ("%s: error creating socket handle", __func__);
703                 return(INVALID_SOCKET);
704         }
705
706 #ifdef DEBUG
707         g_message ("%s: returning socket handle %p", __func__, handle);
708 #endif
709
710         return(fd);
711 }
712
713 struct hostent *_wapi_gethostbyname(const char *hostname)
714 {
715         struct hostent *he;
716         
717         if (startup_count == 0) {
718                 WSASetLastError (WSANOTINITIALISED);
719                 return(NULL);
720         }
721
722         he = gethostbyname (hostname);
723         if (he == NULL) {
724 #ifdef DEBUG
725                 g_message ("%s: gethostbyname error: %s", __func__,
726                            strerror (h_errno));
727 #endif
728
729                 switch(h_errno) {
730                 case HOST_NOT_FOUND:
731                         WSASetLastError (WSAHOST_NOT_FOUND);
732                         break;
733 #if NO_ADDRESS != NO_DATA
734                 case NO_ADDRESS:
735 #endif
736                 case NO_DATA:
737                         WSASetLastError (WSANO_DATA);
738                         break;
739                 case NO_RECOVERY:
740                         WSASetLastError (WSANO_RECOVERY);
741                         break;
742                 case TRY_AGAIN:
743                         WSASetLastError (WSATRY_AGAIN);
744                         break;
745                 default:
746                         g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno);
747                         break;
748                 }
749         }
750         
751         return(he);
752 }
753
754 int
755 WSAIoctl (guint32 fd, gint32 command,
756           gchar *input, gint i_len,
757           gchar *output, gint o_len, glong *written,
758           void *unused1, void *unused2)
759 {
760         gpointer handle = GUINT_TO_POINTER (fd);
761         int ret;
762         gchar *buffer = NULL;
763
764         if (startup_count == 0) {
765                 WSASetLastError (WSANOTINITIALISED);
766                 return(SOCKET_ERROR);
767         }
768
769         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
770                 WSASetLastError (WSAENOTSOCK);
771                 return SOCKET_ERROR;
772         }
773
774         if (i_len > 0) {
775                 buffer = g_memdup (input, i_len);
776         }
777
778         ret = ioctl (fd, command, buffer);
779         if (ret == -1) {
780                 gint errnum = errno;
781 #ifdef DEBUG
782                 g_message("%s: WSAIoctl error: %s", __func__,
783                           strerror (errno));
784 #endif
785
786                 errnum = errno_to_WSA (errnum, __func__);
787                 WSASetLastError (errnum);
788                 g_free (buffer);
789                 
790                 return(SOCKET_ERROR);
791         }
792
793         if (buffer == NULL) {
794                 *written = 0;
795         } else {
796                 /* We just copy the buffer to the output. Some ioctls
797                  * don't even output any data, but, well...
798                  *
799                  * NB windows returns WSAEFAULT if o_len is too small
800                  */
801                 i_len = (i_len > o_len) ? o_len : i_len;
802
803                 if (i_len > 0 && output != NULL) {
804                         memcpy (output, buffer, i_len);
805                 }
806                 
807                 g_free (buffer);
808                 *written = i_len;
809         }
810
811         return(0);
812 }
813
814 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
815 {
816         gpointer handle = GUINT_TO_POINTER (fd);
817         int ret;
818         
819         if (startup_count == 0) {
820                 WSASetLastError (WSANOTINITIALISED);
821                 return(SOCKET_ERROR);
822         }
823         
824         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
825                 WSASetLastError (WSAENOTSOCK);
826                 return(SOCKET_ERROR);
827         }
828
829         switch(command){
830                 case FIONBIO:
831 #ifdef O_NONBLOCK
832                         /* This works better than ioctl(...FIONBIO...) 
833                          * on Linux (it causes connect to return
834                          * EINPROGRESS, but the ioctl doesn't seem to)
835                          */
836                         ret = fcntl(fd, F_GETFL, 0);
837                         if (ret != -1) {
838                                 if (*(gboolean *)arg) {
839                                         ret |= O_NONBLOCK;
840                                 } else {
841                                         ret &= ~O_NONBLOCK;
842                                 }
843                                 ret = fcntl(fd, F_SETFL, ret);
844                         }
845                         break;
846 #endif /* O_NONBLOCK */
847                 case FIONREAD:
848                 case SIOCATMARK:
849                         ret = ioctl (fd, command, arg);
850                         break;
851                 default:
852                         WSASetLastError (WSAEINVAL);
853                         return(SOCKET_ERROR);
854         }
855
856         if (ret == -1) {
857                 gint errnum = errno;
858 #ifdef DEBUG
859                 g_message ("%s: ioctl error: %s", __func__, strerror (errno));
860 #endif
861
862                 errnum = errno_to_WSA (errnum, __func__);
863                 WSASetLastError (errnum);
864                 
865                 return(SOCKET_ERROR);
866         }
867         
868         return(0);
869 }
870
871 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
872                  fd_set *exceptfds, struct timeval *timeout)
873 {
874         int ret;
875         
876         if (startup_count == 0) {
877                 WSASetLastError (WSANOTINITIALISED);
878                 return(SOCKET_ERROR);
879         }
880
881         do {
882                 ret = select(getdtablesize (), readfds, writefds, exceptfds,
883                              timeout);
884         } while (ret == -1 && errno == EINTR &&
885                  !_wapi_thread_cur_apc_pending ());
886
887         if (ret == -1) {
888                 gint errnum = errno;
889 #ifdef DEBUG
890                 g_message ("%s: select error: %s", __func__, strerror (errno));
891 #endif
892                 errnum = errno_to_WSA (errnum, __func__);
893                 WSASetLastError (errnum);
894                 
895                 return(SOCKET_ERROR);
896         }
897
898         return(ret);
899 }
900
901 void _wapi_FD_CLR(guint32 fd, fd_set *set)
902 {
903         gpointer handle = GUINT_TO_POINTER (fd);
904         
905         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
906                 WSASetLastError (WSAENOTSOCK);
907                 return;
908         }
909
910         FD_CLR (fd, set);
911 }
912
913 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
914 {
915         gpointer handle = GUINT_TO_POINTER (fd);
916         
917         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
918                 WSASetLastError (WSAENOTSOCK);
919                 return(0);
920         }
921
922         return(FD_ISSET (fd, set));
923 }
924
925 void _wapi_FD_SET(guint32 fd, fd_set *set)
926 {
927         gpointer handle = GUINT_TO_POINTER (fd);
928         
929         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
930                 WSASetLastError (WSAENOTSOCK);
931                 return;
932         }
933
934         FD_SET (fd, set);
935 }
936