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