2007-01-11 Dick Porter <dick@ximian.com>
[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) {
293                 errnum = errno;
294                 
295 #ifdef DEBUG
296                 g_message ("%s: connect error: %s", __func__,
297                            strerror (errnum));
298 #endif
299                 errnum = errno_to_WSA (errnum, __func__);
300                 if (errnum == WSAEINPROGRESS)
301                         errnum = WSAEWOULDBLOCK; /* see bug #73053 */
302
303                 WSASetLastError (errnum);
304                 
305                 return(SOCKET_ERROR);
306         }
307         return(ret);
308 }
309
310 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
311 {
312         gpointer handle = GUINT_TO_POINTER (fd);
313         int ret;
314         
315         if (startup_count == 0) {
316                 WSASetLastError (WSANOTINITIALISED);
317                 return(SOCKET_ERROR);
318         }
319         
320         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
321                 WSASetLastError (WSAENOTSOCK);
322                 return(SOCKET_ERROR);
323         }
324
325         ret = getpeername (fd, name, namelen);
326         if (ret == -1) {
327                 gint errnum = errno;
328 #ifdef DEBUG
329                 g_message ("%s: getpeername error: %s", __func__,
330                            strerror (errno));
331 #endif
332
333                 errnum = errno_to_WSA (errnum, __func__);
334                 WSASetLastError (errnum);
335
336                 return(SOCKET_ERROR);
337         }
338         
339         return(ret);
340 }
341
342 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
343 {
344         gpointer handle = GUINT_TO_POINTER (fd);
345         int ret;
346         
347         if (startup_count == 0) {
348                 WSASetLastError (WSANOTINITIALISED);
349                 return(SOCKET_ERROR);
350         }
351         
352         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
353                 WSASetLastError (WSAENOTSOCK);
354                 return(SOCKET_ERROR);
355         }
356
357         ret = getsockname (fd, name, namelen);
358         if (ret == -1) {
359                 gint errnum = errno;
360 #ifdef DEBUG
361                 g_message ("%s: getsockname error: %s", __func__,
362                            strerror (errno));
363 #endif
364
365                 errnum = errno_to_WSA (errnum, __func__);
366                 WSASetLastError (errnum);
367
368                 return(SOCKET_ERROR);
369         }
370         
371         return(ret);
372 }
373
374 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
375                      socklen_t *optlen)
376 {
377         gpointer handle = GUINT_TO_POINTER (fd);
378         int ret;
379         struct timeval tv;
380         void *tmp_val;
381
382         if (startup_count == 0) {
383                 WSASetLastError (WSANOTINITIALISED);
384                 return(SOCKET_ERROR);
385         }
386         
387         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
388                 WSASetLastError (WSAENOTSOCK);
389                 return(SOCKET_ERROR);
390         }
391
392         tmp_val = optval;
393         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
394                 tmp_val = &tv;
395                 *optlen = sizeof (tv);
396         }
397
398         ret = getsockopt (fd, level, optname, tmp_val, optlen);
399         if (ret == -1) {
400                 gint errnum = errno;
401 #ifdef DEBUG
402                 g_message ("%s: getsockopt error: %s", __func__,
403                            strerror (errno));
404 #endif
405
406                 errnum = errno_to_WSA (errnum, __func__);
407                 WSASetLastError (errnum);
408                 
409                 return(SOCKET_ERROR);
410         }
411
412         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
413                 *((int *) optval)  = tv.tv_sec * 1000 + (tv.tv_usec / 1000);    // milli from micro
414                 *optlen = sizeof (int);
415         }
416
417         if (optname == SO_ERROR) {
418                 if (*((int *)optval) != 0) {
419                         *((int *) optval) = errno_to_WSA (*((int *)optval),
420                                                           __func__);
421                 }
422         }
423         
424         return(ret);
425 }
426
427 int _wapi_listen(guint32 fd, int backlog)
428 {
429         gpointer handle = GUINT_TO_POINTER (fd);
430         int ret;
431         
432         if (startup_count == 0) {
433                 WSASetLastError (WSANOTINITIALISED);
434                 return(SOCKET_ERROR);
435         }
436         
437         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
438                 WSASetLastError (WSAENOTSOCK);
439                 return(SOCKET_ERROR);
440         }
441         
442         ret = listen (fd, backlog);
443         if (ret == -1) {
444                 gint errnum = errno;
445 #ifdef DEBUG
446                 g_message ("%s: listen error: %s", __func__, strerror (errno));
447 #endif
448
449                 errnum = errno_to_WSA (errnum, __func__);
450                 WSASetLastError (errnum);
451
452                 return(SOCKET_ERROR);
453         }
454
455         return(0);
456 }
457
458 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
459 {
460         return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
461 }
462
463 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
464                    struct sockaddr *from, socklen_t *fromlen)
465 {
466         gpointer handle = GUINT_TO_POINTER (fd);
467         int ret;
468         
469         if (startup_count == 0) {
470                 WSASetLastError (WSANOTINITIALISED);
471                 return(SOCKET_ERROR);
472         }
473         
474         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
475                 WSASetLastError (WSAENOTSOCK);
476                 return(SOCKET_ERROR);
477         }
478         
479         do {
480                 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
481         } while (ret == -1 && errno == EINTR &&
482                  !_wapi_thread_cur_apc_pending ());
483
484         if (ret == -1) {
485                 gint errnum = errno;
486 #ifdef DEBUG
487                 g_message ("%s: recv error: %s", __func__, strerror(errno));
488 #endif
489
490                 errnum = errno_to_WSA (errnum, __func__);
491                 WSASetLastError (errnum);
492                 
493                 return(SOCKET_ERROR);
494         }
495         return(ret);
496 }
497
498 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
499 {
500         gpointer handle = GUINT_TO_POINTER (fd);
501         int ret;
502         
503         if (startup_count == 0) {
504                 WSASetLastError (WSANOTINITIALISED);
505                 return(SOCKET_ERROR);
506         }
507         
508         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
509                 WSASetLastError (WSAENOTSOCK);
510                 return(SOCKET_ERROR);
511         }
512
513         do {
514                 ret = send (fd, msg, len, send_flags);
515         } while (ret == -1 && errno == EINTR &&
516                  !_wapi_thread_cur_apc_pending ());
517
518         if (ret == -1) {
519                 gint errnum = errno;
520 #ifdef DEBUG
521                 g_message ("%s: send error: %s", __func__, strerror (errno));
522 #endif
523
524                 errnum = errno_to_WSA (errnum, __func__);
525                 WSASetLastError (errnum);
526                 
527                 return(SOCKET_ERROR);
528         }
529         return(ret);
530 }
531
532 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
533                  const struct sockaddr *to, socklen_t tolen)
534 {
535         gpointer handle = GUINT_TO_POINTER (fd);
536         int ret;
537         
538         if (startup_count == 0) {
539                 WSASetLastError (WSANOTINITIALISED);
540                 return(SOCKET_ERROR);
541         }
542         
543         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
544                 WSASetLastError (WSAENOTSOCK);
545                 return(SOCKET_ERROR);
546         }
547         
548         do {
549                 ret = sendto (fd, msg, len, send_flags, to, tolen);
550         } while (ret == -1 && errno == EINTR &&
551                  !_wapi_thread_cur_apc_pending ());
552
553         if (ret == -1) {
554                 gint errnum = errno;
555 #ifdef DEBUG
556                 g_message ("%s: send error: %s", __func__, strerror (errno));
557 #endif
558
559                 errnum = errno_to_WSA (errnum, __func__);
560                 WSASetLastError (errnum);
561                 
562                 return(SOCKET_ERROR);
563         }
564         return(ret);
565 }
566
567 int _wapi_setsockopt(guint32 fd, int level, int optname,
568                      const void *optval, socklen_t optlen)
569 {
570         gpointer handle = GUINT_TO_POINTER (fd);
571         int ret;
572         const void *tmp_val;
573         struct timeval tv;
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         tmp_val = optval;
586         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
587                 int ms = *((int *) optval);
588                 tv.tv_sec = ms / 1000;
589                 tv.tv_usec = (ms % 1000) * 1000;        // micro from milli
590                 tmp_val = &tv;
591                 optlen = sizeof (tv);
592 #if defined (__linux__)
593         } else if (optname == SO_SNDBUF || optname == SO_RCVBUF) {
594                 /* According to socket(7) the Linux kernel doubles the
595                  * buffer sizes "to allow space for bookkeeping
596                  * overhead."
597                  */
598                 int bufsize = *((int *) optval);
599
600                 bufsize /= 2;
601                 tmp_val = &bufsize;
602 #endif
603         }
604                 
605         ret = setsockopt (fd, level, optname, tmp_val, optlen);
606         if (ret == -1) {
607                 gint errnum = errno;
608 #ifdef DEBUG
609                 g_message ("%s: setsockopt error: %s", __func__,
610                            strerror (errno));
611 #endif
612
613                 errnum = errno_to_WSA (errnum, __func__);
614                 WSASetLastError (errnum);
615                 
616                 return(SOCKET_ERROR);
617         }
618         
619         return(ret);
620 }
621
622 int _wapi_shutdown(guint32 fd, int how)
623 {
624         gpointer handle = GUINT_TO_POINTER (fd);
625         int ret;
626         
627         if (startup_count == 0) {
628                 WSASetLastError (WSANOTINITIALISED);
629                 return(SOCKET_ERROR);
630         }
631         
632         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
633                 WSASetLastError (WSAENOTSOCK);
634                 return(SOCKET_ERROR);
635         }
636         
637         ret = shutdown (fd, how);
638         if (ret == -1) {
639                 gint errnum = errno;
640 #ifdef DEBUG
641                 g_message ("%s: shutdown error: %s", __func__,
642                            strerror (errno));
643 #endif
644
645                 errnum = errno_to_WSA (errnum, __func__);
646                 WSASetLastError (errnum);
647                 
648                 return(SOCKET_ERROR);
649         }
650         
651         return(ret);
652 }
653
654 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
655                      guint32 unused2, guint32 unused3)
656 {
657         struct _WapiHandle_socket socket_handle = {0};
658         gpointer handle;
659         int fd;
660         
661         socket_handle.domain = domain;
662         socket_handle.type = type;
663         socket_handle.protocol = protocol;
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                 socket_handle.protocol = 4;
670                 fd = socket (AF_INET, SOCK_RAW, 4);
671         }
672         
673         if (fd == -1) {
674                 gint errnum = errno;
675 #ifdef DEBUG
676                 g_message ("%s: socket error: %s", __func__, strerror (errno));
677 #endif
678                 errnum = errno_to_WSA (errnum, __func__);
679                 WSASetLastError (errnum);
680
681                 return(INVALID_SOCKET);
682         }
683
684         if (fd >= _wapi_fd_reserve) {
685 #ifdef DEBUG
686                 g_message ("%s: File descriptor is too big (%d >= %d)",
687                            __func__, fd, _wapi_fd_reserve);
688 #endif
689
690                 WSASetLastError (WSASYSCALLFAILURE);
691                 close (fd);
692                 
693                 return(INVALID_SOCKET);
694         }
695         
696         
697         mono_once (&socket_ops_once, socket_ops_init);
698         
699         handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, &socket_handle);
700         if (handle == _WAPI_HANDLE_INVALID) {
701                 g_warning ("%s: error creating socket handle", __func__);
702                 return(INVALID_SOCKET);
703         }
704
705 #ifdef DEBUG
706         g_message ("%s: returning socket handle %p", __func__, handle);
707 #endif
708
709         return(fd);
710 }
711
712 struct hostent *_wapi_gethostbyname(const char *hostname)
713 {
714         struct hostent *he;
715         
716         if (startup_count == 0) {
717                 WSASetLastError (WSANOTINITIALISED);
718                 return(NULL);
719         }
720
721         he = gethostbyname (hostname);
722         if (he == NULL) {
723 #ifdef DEBUG
724                 g_message ("%s: gethostbyname error: %s", __func__,
725                            strerror (h_errno));
726 #endif
727
728                 switch(h_errno) {
729                 case HOST_NOT_FOUND:
730                         WSASetLastError (WSAHOST_NOT_FOUND);
731                         break;
732 #if NO_ADDRESS != NO_DATA
733                 case NO_ADDRESS:
734 #endif
735                 case NO_DATA:
736                         WSASetLastError (WSANO_DATA);
737                         break;
738                 case NO_RECOVERY:
739                         WSASetLastError (WSANO_RECOVERY);
740                         break;
741                 case TRY_AGAIN:
742                         WSASetLastError (WSATRY_AGAIN);
743                         break;
744                 default:
745                         g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno);
746                         break;
747                 }
748         }
749         
750         return(he);
751 }
752
753 static gboolean socket_disconnect (guint32 fd)
754 {
755         struct _WapiHandle_socket *socket_handle;
756         gboolean ok;
757         gpointer handle = GUINT_TO_POINTER (fd);
758         int newsock, ret;
759         
760         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
761                                   (gpointer *)&socket_handle);
762         if (ok == FALSE) {
763                 g_warning ("%s: error looking up socket handle %p", __func__,
764                            handle);
765                 WSASetLastError (WSAENOTSOCK);
766                 return(FALSE);
767         }
768         
769         newsock = socket (socket_handle->domain, socket_handle->type,
770                           socket_handle->protocol);
771         if (newsock == -1) {
772                 gint errnum = errno;
773
774 #ifdef DEBUG
775                 g_message ("%s: socket error: %s", __func__, strerror (errno));
776 #endif
777
778                 errnum = errno_to_WSA (errnum, __func__);
779                 WSASetLastError (errnum);
780                 
781                 return(FALSE);
782         }
783
784         /* According to Stevens "Advanced Programming in the UNIX
785          * Environment: UNIX File I/O" dup2() is atomic so there
786          * should not be a race condition between the old fd being
787          * closed and the new socket fd being copied over
788          */
789         do {
790                 ret = dup2 (newsock, fd);
791         } while (ret == -1 && errno == EAGAIN);
792         
793         if (ret == -1) {
794                 gint errnum = errno;
795                 
796 #ifdef DEBUG
797                 g_message ("%s: dup2 error: %s", __func__, strerror (errno));
798 #endif
799
800                 errnum = errno_to_WSA (errnum, __func__);
801                 WSASetLastError (errnum);
802                 
803                 return(FALSE);
804         }
805
806         close (newsock);
807         
808         return(TRUE);
809 }
810
811 static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped,
812                                    guint32 flags, guint32 reserved)
813 {
814 #ifdef DEBUG
815         g_message ("%s: called on socket %d!", __func__, fd);
816 #endif
817         
818         if (reserved != 0) {
819                 WSASetLastError (WSAEINVAL);
820                 return(FALSE);
821         }
822
823         /* We could check the socket type here and fail unless its
824          * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
825          * if we really wanted to
826          */
827
828         return(socket_disconnect (fd));
829 }
830
831 /* NB only supports NULL file handle, NULL buffers and
832  * TF_DISCONNECT|TF_REUSE_SOCKET flags to disconnect the socket fd.
833  * Shouldn't actually ever need to be called anyway though, because we
834  * have DisconnectEx ().
835  */
836 static gboolean wapi_transmitfile (guint32 fd, gpointer file,
837                                    guint32 num_write, guint32 num_per_send,
838                                    WapiOverlapped *overlapped,
839                                    WapiTransmitFileBuffers *buffers,
840                                    WapiTransmitFileFlags flags)
841 {
842 #ifdef DEBUG
843         g_message ("%s: called on socket %d!", __func__, fd);
844 #endif
845         
846         g_assert (file == NULL);
847         g_assert (overlapped == NULL);
848         g_assert (buffers == NULL);
849         g_assert (num_write == 0);
850         g_assert (num_per_send == 0);
851         g_assert (flags == (TF_DISCONNECT | TF_REUSE_SOCKET));
852
853         return(socket_disconnect (fd));
854 }
855
856 static struct 
857 {
858         WapiGuid guid;
859         gpointer func;
860 } extension_functions[] = {
861         {WSAID_DISCONNECTEX, wapi_disconnectex},
862         {WSAID_TRANSMITFILE, wapi_transmitfile},
863         {{0}, NULL},
864 };
865
866 int
867 WSAIoctl (guint32 fd, gint32 command,
868           gchar *input, gint i_len,
869           gchar *output, gint o_len, glong *written,
870           void *unused1, void *unused2)
871 {
872         gpointer handle = GUINT_TO_POINTER (fd);
873         int ret;
874         gchar *buffer = NULL;
875
876         if (startup_count == 0) {
877                 WSASetLastError (WSANOTINITIALISED);
878                 return(SOCKET_ERROR);
879         }
880
881         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
882                 WSASetLastError (WSAENOTSOCK);
883                 return SOCKET_ERROR;
884         }
885
886         if (command == SIO_GET_EXTENSION_FUNCTION_POINTER) {
887                 int i = 0;
888                 WapiGuid *guid = (WapiGuid *)input;
889                 
890                 if (i_len < sizeof(WapiGuid)) {
891                         /* As far as I can tell, windows doesn't
892                          * actually set an error here...
893                          */
894                         WSASetLastError (WSAEINVAL);
895                         return(SOCKET_ERROR);
896                 }
897
898                 if (o_len < sizeof(gpointer)) {
899                         /* Or here... */
900                         WSASetLastError (WSAEINVAL);
901                         return(SOCKET_ERROR);
902                 }
903
904                 if (output == NULL) {
905                         /* Or here */
906                         WSASetLastError (WSAEINVAL);
907                         return(SOCKET_ERROR);
908                 }
909                 
910                 while(extension_functions[i].func != NULL) {
911                         if (!memcmp (guid, &extension_functions[i].guid,
912                                      sizeof(WapiGuid))) {
913                                 memcpy (output, &extension_functions[i].func,
914                                         sizeof(gpointer));
915                                 *written = sizeof(gpointer);
916                                 return(0);
917                         }
918
919                         i++;
920                 }
921                 
922                 WSASetLastError (WSAEINVAL);
923                 return(SOCKET_ERROR);
924         }
925
926         if (i_len > 0) {
927                 buffer = g_memdup (input, i_len);
928         }
929
930         ret = ioctl (fd, command, buffer);
931         if (ret == -1) {
932                 gint errnum = errno;
933 #ifdef DEBUG
934                 g_message("%s: WSAIoctl error: %s", __func__,
935                           strerror (errno));
936 #endif
937
938                 errnum = errno_to_WSA (errnum, __func__);
939                 WSASetLastError (errnum);
940                 g_free (buffer);
941                 
942                 return(SOCKET_ERROR);
943         }
944
945         if (buffer == NULL) {
946                 *written = 0;
947         } else {
948                 /* We just copy the buffer to the output. Some ioctls
949                  * don't even output any data, but, well...
950                  *
951                  * NB windows returns WSAEFAULT if o_len is too small
952                  */
953                 i_len = (i_len > o_len) ? o_len : i_len;
954
955                 if (i_len > 0 && output != NULL) {
956                         memcpy (output, buffer, i_len);
957                 }
958                 
959                 g_free (buffer);
960                 *written = i_len;
961         }
962
963         return(0);
964 }
965
966 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
967 {
968         gpointer handle = GUINT_TO_POINTER (fd);
969         int ret;
970         
971         if (startup_count == 0) {
972                 WSASetLastError (WSANOTINITIALISED);
973                 return(SOCKET_ERROR);
974         }
975         
976         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
977                 WSASetLastError (WSAENOTSOCK);
978                 return(SOCKET_ERROR);
979         }
980
981         switch(command){
982                 case FIONBIO:
983 #ifdef O_NONBLOCK
984                         /* This works better than ioctl(...FIONBIO...) 
985                          * on Linux (it causes connect to return
986                          * EINPROGRESS, but the ioctl doesn't seem to)
987                          */
988                         ret = fcntl(fd, F_GETFL, 0);
989                         if (ret != -1) {
990                                 if (*(gboolean *)arg) {
991                                         ret |= O_NONBLOCK;
992                                 } else {
993                                         ret &= ~O_NONBLOCK;
994                                 }
995                                 ret = fcntl(fd, F_SETFL, ret);
996                         }
997                         break;
998 #endif /* O_NONBLOCK */
999                 case FIONREAD:
1000                 case SIOCATMARK:
1001                         ret = ioctl (fd, command, arg);
1002                         break;
1003                 default:
1004                         WSASetLastError (WSAEINVAL);
1005                         return(SOCKET_ERROR);
1006         }
1007
1008         if (ret == -1) {
1009                 gint errnum = errno;
1010 #ifdef DEBUG
1011                 g_message ("%s: ioctl error: %s", __func__, strerror (errno));
1012 #endif
1013
1014                 errnum = errno_to_WSA (errnum, __func__);
1015                 WSASetLastError (errnum);
1016                 
1017                 return(SOCKET_ERROR);
1018         }
1019         
1020         return(0);
1021 }
1022
1023 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
1024                  fd_set *exceptfds, struct timeval *timeout)
1025 {
1026         int ret, maxfd;
1027         
1028         if (startup_count == 0) {
1029                 WSASetLastError (WSANOTINITIALISED);
1030                 return(SOCKET_ERROR);
1031         }
1032
1033         for (maxfd = FD_SETSIZE-1; maxfd >= 0; maxfd--) {
1034                 if ((readfds && FD_ISSET (maxfd, readfds)) ||
1035                     (writefds && FD_ISSET (maxfd, writefds)) ||
1036                     (exceptfds && FD_ISSET (maxfd, exceptfds))) {
1037                         break;
1038                 }
1039         }
1040
1041         if (maxfd == -1) {
1042                 WSASetLastError (WSAEINVAL);
1043                 return(SOCKET_ERROR);
1044         }
1045
1046         do {
1047                 ret = select(maxfd + 1, readfds, writefds, exceptfds,
1048                              timeout);
1049         } while (ret == -1 && errno == EINTR &&
1050                  !_wapi_thread_cur_apc_pending ());
1051
1052         if (ret == -1) {
1053                 gint errnum = errno;
1054 #ifdef DEBUG
1055                 g_message ("%s: select error: %s", __func__, strerror (errno));
1056 #endif
1057                 errnum = errno_to_WSA (errnum, __func__);
1058                 WSASetLastError (errnum);
1059                 
1060                 return(SOCKET_ERROR);
1061         }
1062
1063         return(ret);
1064 }
1065
1066 void _wapi_FD_CLR(guint32 fd, fd_set *set)
1067 {
1068         gpointer handle = GUINT_TO_POINTER (fd);
1069         
1070         if (fd >= FD_SETSIZE) {
1071                 WSASetLastError (WSAEINVAL);
1072                 return;
1073         }
1074         
1075         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1076                 WSASetLastError (WSAENOTSOCK);
1077                 return;
1078         }
1079
1080         FD_CLR (fd, set);
1081 }
1082
1083 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
1084 {
1085         gpointer handle = GUINT_TO_POINTER (fd);
1086         
1087         if (fd >= FD_SETSIZE) {
1088                 WSASetLastError (WSAEINVAL);
1089                 return(0);
1090         }
1091         
1092         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1093                 WSASetLastError (WSAENOTSOCK);
1094                 return(0);
1095         }
1096
1097         return(FD_ISSET (fd, set));
1098 }
1099
1100 void _wapi_FD_SET(guint32 fd, fd_set *set)
1101 {
1102         gpointer handle = GUINT_TO_POINTER (fd);
1103         
1104         if (fd >= FD_SETSIZE) {
1105                 WSASetLastError (WSAEINVAL);
1106                 return;
1107         }
1108
1109         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1110                 WSASetLastError (WSAENOTSOCK);
1111                 return;
1112         }
1113
1114         FD_SET (fd, set);
1115 }
1116