2005-05-13 Zoltan Varga <vargaz@freemail.hu>
[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         return(ret);
434 }
435
436 int _wapi_listen(guint32 fd, int backlog)
437 {
438         gpointer handle = GUINT_TO_POINTER (fd);
439         int ret;
440         
441         if (startup_count == 0) {
442                 WSASetLastError (WSANOTINITIALISED);
443                 return(SOCKET_ERROR);
444         }
445         
446         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
447                 WSASetLastError (WSAENOTSOCK);
448                 return(SOCKET_ERROR);
449         }
450         
451         ret = listen (fd, backlog);
452         if (ret == -1) {
453                 gint errnum = errno;
454 #ifdef DEBUG
455                 g_message ("%s: listen error: %s", __func__, strerror (errno));
456 #endif
457
458                 errnum = errno_to_WSA (errnum, __func__);
459                 WSASetLastError (errnum);
460
461                 return(SOCKET_ERROR);
462         }
463
464         return(0);
465 }
466
467 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
468 {
469         return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
470 }
471
472 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
473                    struct sockaddr *from, socklen_t *fromlen)
474 {
475 #ifndef HAVE_MSG_NOSIGNAL
476         void (*old_sigpipe)(int);       // old SIGPIPE handler
477 #endif
478         gpointer handle = GUINT_TO_POINTER (fd);
479         int ret;
480         
481         if (startup_count == 0) {
482                 WSASetLastError (WSANOTINITIALISED);
483                 return(SOCKET_ERROR);
484         }
485         
486         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
487                 WSASetLastError (WSAENOTSOCK);
488                 return(SOCKET_ERROR);
489         }
490         
491 #ifdef HAVE_MSG_NOSIGNAL
492         do {
493                 ret = recvfrom (fd, buf, len, recv_flags | MSG_NOSIGNAL, from,
494                                 fromlen);
495         } while (ret == -1 && errno == EINTR &&
496                  !_wapi_thread_cur_apc_pending ());
497 #else
498         old_sigpipe = signal (SIGPIPE, SIG_IGN);
499         do {
500                 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
501         } while (ret == -1 && errno == EINTR &&
502                  !_wapi_thread_cur_apc_pending ());
503         signal (SIGPIPE, old_sigpipe);
504 #endif
505
506         if (ret == -1) {
507                 gint errnum = errno;
508 #ifdef DEBUG
509                 g_message ("%s: recv error: %s", __func__, strerror(errno));
510 #endif
511
512                 errnum = errno_to_WSA (errnum, __func__);
513                 WSASetLastError (errnum);
514                 
515                 return(SOCKET_ERROR);
516         }
517         return(ret);
518 }
519
520 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
521 {
522 #ifndef HAVE_MSG_NOSIGNAL
523         void (*old_sigpipe)(int);       // old SIGPIPE handler
524 #endif
525         gpointer handle = GUINT_TO_POINTER (fd);
526         int ret;
527         
528         if (startup_count == 0) {
529                 WSASetLastError (WSANOTINITIALISED);
530                 return(SOCKET_ERROR);
531         }
532         
533         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
534                 WSASetLastError (WSAENOTSOCK);
535                 return(SOCKET_ERROR);
536         }
537
538 #ifdef HAVE_MSG_NOSIGNAL
539         do {
540                 ret = send (fd, msg, len, send_flags | MSG_NOSIGNAL);
541         } while (ret == -1 && errno == EINTR &&
542                  !_wapi_thread_cur_apc_pending ());
543 #else
544         old_sigpipe = signal (SIGPIPE, SIG_IGN);
545         do {
546                 ret = send (fd, msg, len, send_flags);
547         } while (ret == -1 && errno == EINTR &&
548                  !_wapi_thread_cur_apc_pending ());
549         signal (SIGPIPE, old_sigpipe);
550 #endif
551         if (ret == -1) {
552                 gint errnum = errno;
553 #ifdef DEBUG
554                 g_message ("%s: send error: %s", __func__, strerror (errno));
555 #endif
556
557                 errnum = errno_to_WSA (errnum, __func__);
558                 WSASetLastError (errnum);
559                 
560                 return(SOCKET_ERROR);
561         }
562         return(ret);
563 }
564
565 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
566                  const struct sockaddr *to, socklen_t tolen)
567 {
568 #ifndef HAVE_MSG_NOSIGNAL
569         void (*old_sigpipe)(int);       // old SIGPIPE handler
570 #endif
571         gpointer handle = GUINT_TO_POINTER (fd);
572         int ret;
573         
574         if (startup_count == 0) {
575                 WSASetLastError (WSANOTINITIALISED);
576                 return(SOCKET_ERROR);
577         }
578         
579         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
580                 WSASetLastError (WSAENOTSOCK);
581                 return(SOCKET_ERROR);
582         }
583         
584 #ifdef HAVE_MSG_NOSIGNAL
585         do {
586                 ret = sendto (fd, msg, len, send_flags | MSG_NOSIGNAL, to,
587                               tolen);
588         } while (ret == -1 && errno == EINTR &&
589                  !_wapi_thread_cur_apc_pending ());
590 #else
591         old_sigpipe = signal (SIGPIPE, SIG_IGN);
592         do {
593                 ret = sendto (fd, msg, len, send_flags, to, tolen);
594         } while (ret == -1 && errno == EINTR &&
595                  !_wapi_thread_cur_apc_pending ());
596         signal (SIGPIPE, old_sigpipe);
597 #endif
598         if (ret == -1) {
599                 gint errnum = errno;
600 #ifdef DEBUG
601                 g_message ("%s: send error: %s", __func__, strerror (errno));
602 #endif
603
604                 errnum = errno_to_WSA (errnum, __func__);
605                 WSASetLastError (errnum);
606                 
607                 return(SOCKET_ERROR);
608         }
609         return(ret);
610 }
611
612 int _wapi_setsockopt(guint32 fd, int level, int optname,
613                      const void *optval, socklen_t optlen)
614 {
615         gpointer handle = GUINT_TO_POINTER (fd);
616         int ret;
617         const void *tmp_val;
618         struct timeval tv;
619         
620         if (startup_count == 0) {
621                 WSASetLastError (WSANOTINITIALISED);
622                 return(SOCKET_ERROR);
623         }
624         
625         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
626                 WSASetLastError (WSAENOTSOCK);
627                 return(SOCKET_ERROR);
628         }
629
630         tmp_val = optval;
631         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
632                 int ms = *((int *) optval);
633                 tv.tv_sec = ms / 1000;
634                 tv.tv_usec = ms % 1000;
635                 tmp_val = &tv;
636                 optlen = sizeof (tv);
637         }
638                 
639         ret = setsockopt (fd, level, optname, tmp_val, optlen);
640         if (ret == -1) {
641                 gint errnum = errno;
642 #ifdef DEBUG
643                 g_message ("%s: setsockopt error: %s", __func__,
644                            strerror (errno));
645 #endif
646
647                 errnum = errno_to_WSA (errnum, __func__);
648                 WSASetLastError (errnum);
649                 
650                 return(SOCKET_ERROR);
651         }
652         
653         return(ret);
654 }
655
656 int _wapi_shutdown(guint32 fd, int how)
657 {
658         gpointer handle = GUINT_TO_POINTER (fd);
659         int ret;
660         
661         if (startup_count == 0) {
662                 WSASetLastError (WSANOTINITIALISED);
663                 return(SOCKET_ERROR);
664         }
665         
666         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
667                 WSASetLastError (WSAENOTSOCK);
668                 return(SOCKET_ERROR);
669         }
670         
671         ret = shutdown (fd, how);
672         if (ret == -1) {
673                 gint errnum = errno;
674 #ifdef DEBUG
675                 g_message ("%s: shutdown error: %s", __func__,
676                            strerror (errno));
677 #endif
678
679                 errnum = errno_to_WSA (errnum, __func__);
680                 WSASetLastError (errnum);
681                 
682                 return(SOCKET_ERROR);
683         }
684         
685         return(ret);
686 }
687
688 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
689                      guint32 unused2, guint32 unused3)
690 {
691         gpointer handle;
692         int fd;
693         
694         fd = socket (domain, type, protocol);
695         if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
696             protocol == 0) {
697                 /* Retry with protocol == 4 (see bug #54565) */
698                 fd = socket (AF_INET, SOCK_RAW, 4);
699         }
700         
701         if (fd == -1) {
702                 gint errnum = errno;
703 #ifdef DEBUG
704                 g_message ("%s: socket error: %s", __func__, strerror (errno));
705 #endif
706                 errnum = errno_to_WSA (errnum, __func__);
707                 WSASetLastError (errnum);
708
709                 return(INVALID_SOCKET);
710         }
711
712         if (fd >= _wapi_fd_reserve) {
713 #ifdef DEBUG
714                 g_message ("%s: File descriptor is too big", __func__);
715 #endif
716
717                 WSASetLastError (WSASYSCALLFAILURE);
718                 close (fd);
719                 
720                 return(INVALID_SOCKET);
721         }
722         
723         
724         mono_once (&socket_ops_once, socket_ops_init);
725         
726         handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, NULL);
727         if (handle == _WAPI_HANDLE_INVALID) {
728                 g_warning ("%s: error creating socket handle", __func__);
729                 return(INVALID_SOCKET);
730         }
731
732 #ifdef DEBUG
733         g_message ("%s: returning socket handle %p", __func__, handle);
734 #endif
735
736         return(fd);
737 }
738
739 struct hostent *_wapi_gethostbyname(const char *hostname)
740 {
741         struct hostent *he;
742         
743         if (startup_count == 0) {
744                 WSASetLastError (WSANOTINITIALISED);
745                 return(NULL);
746         }
747
748         he = gethostbyname (hostname);
749         if (he == NULL) {
750 #ifdef DEBUG
751                 g_message ("%s: gethostbyname error: %s", __func__,
752                            strerror (h_errno));
753 #endif
754
755                 switch(h_errno) {
756                 case HOST_NOT_FOUND:
757                         WSASetLastError (WSAHOST_NOT_FOUND);
758                         break;
759 #if NO_ADDRESS != NO_DATA
760                 case NO_ADDRESS:
761 #endif
762                 case NO_DATA:
763                         WSASetLastError (WSANO_DATA);
764                         break;
765                 case NO_RECOVERY:
766                         WSASetLastError (WSANO_RECOVERY);
767                         break;
768                 case TRY_AGAIN:
769                         WSASetLastError (WSATRY_AGAIN);
770                         break;
771                 default:
772                         g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno);
773                         break;
774                 }
775         }
776         
777         return(he);
778 }
779
780 int
781 WSAIoctl (guint32 fd, gint32 command,
782           gchar *input, gint i_len,
783           gchar *output, gint o_len, glong *written,
784           void *unused1, void *unused2)
785 {
786         gpointer handle = GUINT_TO_POINTER (fd);
787         int ret;
788         gchar *buffer = NULL;
789
790         if (startup_count == 0) {
791                 WSASetLastError (WSANOTINITIALISED);
792                 return(SOCKET_ERROR);
793         }
794
795         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
796                 WSASetLastError (WSAENOTSOCK);
797                 return SOCKET_ERROR;
798         }
799
800         if (i_len > 0) {
801                 buffer = g_memdup (input, i_len);
802         }
803
804         ret = ioctl (fd, command, buffer);
805         if (ret == -1) {
806                 gint errnum = errno;
807 #ifdef DEBUG
808                 g_message("%s: WSAIoctl error: %s", __func__,
809                           strerror (errno));
810 #endif
811
812                 errnum = errno_to_WSA (errnum, __func__);
813                 WSASetLastError (errnum);
814                 g_free (buffer);
815                 
816                 return(SOCKET_ERROR);
817         }
818
819         if (buffer == NULL) {
820                 *written = 0;
821         } else {
822                 /* We just copy the buffer to the output. Some ioctls
823                  * don't even output any data, but, well...
824                  */
825                 i_len = (i_len > o_len) ? o_len : i_len;
826                 memcpy (output, buffer, i_len);
827                 g_free (buffer);
828                 *written = i_len;
829         }
830
831         return(0);
832 }
833
834 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
835 {
836         gpointer handle = GUINT_TO_POINTER (fd);
837         int ret;
838         
839         if (startup_count == 0) {
840                 WSASetLastError (WSANOTINITIALISED);
841                 return(SOCKET_ERROR);
842         }
843         
844         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
845                 WSASetLastError (WSAENOTSOCK);
846                 return(SOCKET_ERROR);
847         }
848
849         if (command != FIONBIO &&
850             command != FIONREAD &&
851             command != SIOCATMARK) {
852                 /* Not listed in the MSDN specs, but ioctl(2) returns
853                  * this if command is invalid
854                  */
855                 WSASetLastError (WSAEINVAL);
856                 return(SOCKET_ERROR);
857         }
858
859 #ifdef O_NONBLOCK
860         /* This works better than ioctl(...FIONBIO...) on Linux (it causes
861          * connect to return EINPROGRESS, but the ioctl doesn't seem to)
862          */
863         if (command == FIONBIO) {
864                 ret = fcntl (fd, F_GETFL, 0);
865                 if (ret != -1) {
866                         if (*(gboolean *)arg) {
867                                 ret |= O_NONBLOCK;
868                         } else {
869                                 ret &= ~O_NONBLOCK;
870                         }
871                         ret = fcntl (fd, F_SETFL, ret);
872                 }
873         } else
874 #endif /* O_NONBLOCK */
875         {
876                 ret = ioctl (fd, command, arg);
877         }
878         if (ret == -1) {
879                 gint errnum = errno;
880 #ifdef DEBUG
881                 g_message ("%s: ioctl error: %s", __func__, strerror (errno));
882 #endif
883
884                 errnum = errno_to_WSA (errnum, __func__);
885                 WSASetLastError (errnum);
886                 
887                 return(SOCKET_ERROR);
888         }
889         
890         return(0);
891 }
892
893 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
894                  fd_set *exceptfds, struct timeval *timeout)
895 {
896         int ret;
897         
898         if (startup_count == 0) {
899                 WSASetLastError (WSANOTINITIALISED);
900                 return(SOCKET_ERROR);
901         }
902
903         do {
904                 ret = select(getdtablesize (), readfds, writefds, exceptfds,
905                              timeout);
906         } while (ret == -1 && errno == EINTR &&
907                  !_wapi_thread_cur_apc_pending ());
908
909         if (ret == -1) {
910                 gint errnum = errno;
911 #ifdef DEBUG
912                 g_message ("%s: select error: %s", __func__, strerror (errno));
913 #endif
914                 errnum = errno_to_WSA (errnum, __func__);
915                 WSASetLastError (errnum);
916                 
917                 return(SOCKET_ERROR);
918         }
919
920         return(ret);
921 }
922
923 void _wapi_FD_CLR(guint32 fd, fd_set *set)
924 {
925         gpointer handle = GUINT_TO_POINTER (fd);
926         
927         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
928                 WSASetLastError (WSAENOTSOCK);
929                 return;
930         }
931
932         FD_CLR (fd, set);
933 }
934
935 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
936 {
937         gpointer handle = GUINT_TO_POINTER (fd);
938         
939         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
940                 WSASetLastError (WSAENOTSOCK);
941                 return(0);
942         }
943
944         return(FD_ISSET (fd, set));
945 }
946
947 void _wapi_FD_SET(guint32 fd, fd_set *set)
948 {
949         gpointer handle = GUINT_TO_POINTER (fd);
950         
951         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
952                 WSASetLastError (WSAENOTSOCK);
953                 return;
954         }
955
956         FD_SET (fd, set);
957 }
958