2007-03-22 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 #include <sys/poll.h>
19 #ifdef HAVE_SYS_FILIO_H
20 #include <sys/filio.h>     /* defines FIONBIO and FIONREAD */
21 #endif
22 #ifdef HAVE_SYS_SOCKIO_H
23 #include <sys/sockio.h>    /* defines SIOCATMARK */
24 #endif
25 #include <unistd.h>
26 #include <fcntl.h>
27
28 #ifndef HAVE_MSG_NOSIGNAL
29 #include <signal.h>
30 #endif
31
32 #include <mono/io-layer/wapi.h>
33 #include <mono/io-layer/wapi-private.h>
34 #include <mono/io-layer/socket-private.h>
35 #include <mono/io-layer/handles-private.h>
36 #include <mono/io-layer/socket-wrappers.h>
37
38 #undef DEBUG
39
40 static guint32 startup_count=0;
41 static pthread_key_t error_key;
42 static mono_once_t error_key_once=MONO_ONCE_INIT;
43
44 static void socket_close (gpointer handle, gpointer data);
45
46 struct _WapiHandleOps _wapi_socket_ops = {
47         socket_close,           /* close */
48         NULL,                   /* signal */
49         NULL,                   /* own */
50         NULL,                   /* is_owned */
51         NULL,                   /* special_wait */
52         NULL                    /* prewait */
53 };
54
55 static mono_once_t socket_ops_once=MONO_ONCE_INIT;
56
57 static void socket_ops_init (void)
58 {
59         /* No capabilities to register */
60 }
61
62 static void socket_close (gpointer handle, gpointer data G_GNUC_UNUSED)
63 {
64         int ret;
65
66 #ifdef DEBUG
67         g_message ("%s: closing socket handle %p", __func__, handle);
68 #endif
69
70         if (startup_count == 0) {
71                 WSASetLastError (WSANOTINITIALISED);
72                 return;
73         }
74
75         do {
76                 ret = close (GPOINTER_TO_UINT(handle));
77         } while (ret == -1 && errno == EINTR &&
78                  !_wapi_thread_cur_apc_pending ());
79         
80         if (ret == -1) {
81                 gint errnum = errno;
82 #ifdef DEBUG
83                 g_message ("%s: close error: %s", __func__, strerror (errno));
84 #endif
85                 errnum = errno_to_WSA (errnum, __func__);
86                 WSASetLastError (errnum);
87         }
88 }
89
90 int WSAStartup(guint32 requested, WapiWSAData *data)
91 {
92         if (data == NULL) {
93                 return(WSAEFAULT);
94         }
95
96         /* Insist on v2.0+ */
97         if (requested < MAKEWORD(2,0)) {
98                 return(WSAVERNOTSUPPORTED);
99         }
100
101         startup_count++;
102
103         /* I've no idea what is the minor version of the spec I read */
104         data->wHighVersion = MAKEWORD(2,2);
105         
106         data->wVersion = requested < data->wHighVersion? requested:
107                 data->wHighVersion;
108
109 #ifdef DEBUG
110         g_message ("%s: high version 0x%x", __func__, data->wHighVersion);
111 #endif
112         
113         strncpy (data->szDescription, "WAPI", WSADESCRIPTION_LEN);
114         strncpy (data->szSystemStatus, "groovy", WSASYS_STATUS_LEN);
115         
116         return(0);
117 }
118
119 static gboolean
120 cleanup_close (gpointer handle, gpointer data)
121 {
122         _wapi_handle_ops_close (handle, NULL);
123         return TRUE;
124 }
125
126 int WSACleanup(void)
127 {
128 #ifdef DEBUG
129         g_message ("%s: cleaning up", __func__);
130 #endif
131
132         if (--startup_count) {
133                 /* Do nothing */
134                 return(0);
135         }
136
137         _wapi_handle_foreach (WAPI_HANDLE_SOCKET, cleanup_close, NULL);
138         return(0);
139 }
140
141 static void error_init(void)
142 {
143         int ret;
144         
145         ret = pthread_key_create (&error_key, NULL);
146         g_assert (ret == 0);
147 }
148
149 void WSASetLastError(int error)
150 {
151         int ret;
152         
153         mono_once (&error_key_once, error_init);
154         ret = pthread_setspecific (error_key, GINT_TO_POINTER(error));
155         g_assert (ret == 0);
156 }
157
158 int WSAGetLastError(void)
159 {
160         int err;
161         void *errptr;
162         
163         mono_once (&error_key_once, error_init);
164         errptr = pthread_getspecific (error_key);
165         err = GPOINTER_TO_INT(errptr);
166         
167         return(err);
168 }
169
170 int closesocket(guint32 fd)
171 {
172         gpointer handle = GUINT_TO_POINTER (fd);
173         
174         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
175                 WSASetLastError (WSAENOTSOCK);
176                 return(0);
177         }
178         
179         _wapi_handle_unref (handle);
180         return(0);
181 }
182
183 guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen)
184 {
185         gpointer handle = GUINT_TO_POINTER (fd);
186         gpointer new_handle;
187         int new_fd;
188         
189         if (startup_count == 0) {
190                 WSASetLastError (WSANOTINITIALISED);
191                 return(INVALID_SOCKET);
192         }
193         
194         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
195                 WSASetLastError (WSAENOTSOCK);
196                 return(INVALID_SOCKET);
197         }
198         
199         do {
200                 new_fd = accept (fd, addr, addrlen);
201         } while (new_fd == -1 && errno == EINTR &&
202                  !_wapi_thread_cur_apc_pending());
203
204         if (new_fd == -1) {
205                 gint errnum = errno;
206 #ifdef DEBUG
207                 g_message ("%s: accept error: %s", __func__, strerror(errno));
208 #endif
209
210                 errnum = errno_to_WSA (errnum, __func__);
211                 WSASetLastError (errnum);
212                 
213                 return(INVALID_SOCKET);
214         }
215
216         if (new_fd >= _wapi_fd_reserve) {
217 #ifdef DEBUG
218                 g_message ("%s: File descriptor is too big", __func__);
219 #endif
220
221                 WSASetLastError (WSASYSCALLFAILURE);
222                 
223                 close (new_fd);
224                 
225                 return(INVALID_SOCKET);
226         }
227
228         new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd, NULL);
229         if(new_handle == _WAPI_HANDLE_INVALID) {
230                 g_warning ("%s: error creating socket handle", __func__);
231                 WSASetLastError (ERROR_GEN_FAILURE);
232                 return(INVALID_SOCKET);
233         }
234
235 #ifdef DEBUG
236         g_message ("%s: returning newly accepted socket handle %p with",
237                    __func__, new_handle);
238 #endif
239         
240         return(new_fd);
241 }
242
243 int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen)
244 {
245         gpointer handle = GUINT_TO_POINTER (fd);
246         int ret;
247         
248         if (startup_count == 0) {
249                 WSASetLastError (WSANOTINITIALISED);
250                 return(SOCKET_ERROR);
251         }
252
253         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
254                 WSASetLastError (WSAENOTSOCK);
255                 return(SOCKET_ERROR);
256         }
257         
258         ret = bind (fd, my_addr, addrlen);
259         if (ret == -1) {
260                 gint errnum = errno;
261 #ifdef DEBUG
262                 g_message ("%s: bind error: %s", __func__, strerror(errno));
263 #endif
264                 errnum = errno_to_WSA (errnum, __func__);
265                 WSASetLastError (errnum);
266                 
267                 return(SOCKET_ERROR);
268         }
269         return(ret);
270 }
271
272 int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr,
273                   socklen_t addrlen)
274 {
275         gpointer handle = GUINT_TO_POINTER (fd);
276         struct _WapiHandle_socket *socket_handle;
277         gboolean ok;
278         gint errnum;
279         
280         if (startup_count == 0) {
281                 WSASetLastError (WSANOTINITIALISED);
282                 return(SOCKET_ERROR);
283         }
284         
285         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
286                 WSASetLastError (WSAENOTSOCK);
287                 return(SOCKET_ERROR);
288         }
289         
290         if (connect (fd, serv_addr, addrlen) == -1) {
291                 struct pollfd fds;
292                 int so_error;
293                 socklen_t len;
294                 
295                 errnum = errno;
296                 
297                 if (errno != EINTR) {
298 #ifdef DEBUG
299                         g_message ("%s: connect error: %s", __func__,
300                                    strerror (errnum));
301 #endif
302
303                         errnum = errno_to_WSA (errnum, __func__);
304                         if (errnum == WSAEINPROGRESS)
305                                 errnum = WSAEWOULDBLOCK; /* see bug #73053 */
306
307                         WSASetLastError (errnum);
308                 
309                         return(SOCKET_ERROR);
310                 }
311
312                 fds.fd = fd;
313                 fds.events = POLLOUT;
314                 while (poll (&fds, 1, -1) == -1 &&
315                        !_wapi_thread_cur_apc_pending ()) {
316                         if (errno != EINTR) {
317                                 errnum = errno_to_WSA (errno, __func__);
318
319 #ifdef DEBUG
320                                 g_message ("%s: connect poll error: %s",
321                                            __func__, strerror (errno));
322 #endif
323
324                                 WSASetLastError (errnum);
325                                 return(SOCKET_ERROR);
326                         }
327                 }
328
329                 len = sizeof(so_error);
330                 if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &so_error,
331                                 &len) == -1) {
332                         errnum = errno_to_WSA (errno, __func__);
333
334 #ifdef DEBUG
335                         g_message ("%s: connect getsockopt error: %s",
336                                    __func__, strerror (errno));
337 #endif
338
339                         WSASetLastError (errnum);
340                         return(SOCKET_ERROR);
341                 }
342                 
343                 if (so_error != 0) {
344                         errnum = errno_to_WSA (so_error, __func__);
345
346                         /* Need to save this socket error */
347                         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
348                                                   (gpointer *)&socket_handle);
349                         if (ok == FALSE) {
350                                 g_warning ("%s: error looking up socket handle %p", __func__, handle);
351                         } else {
352                                 socket_handle->saved_error = errnum;
353                         }
354                         
355 #ifdef DEBUG
356                         g_message ("%s: connect getsockopt returned error: %s",
357                                    __func__, strerror (so_error));
358 #endif
359
360                         WSASetLastError (errnum);
361                         return(SOCKET_ERROR);
362                 }
363         }
364                 
365         return(0);
366 }
367
368 int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen)
369 {
370         gpointer handle = GUINT_TO_POINTER (fd);
371         int ret;
372         
373         if (startup_count == 0) {
374                 WSASetLastError (WSANOTINITIALISED);
375                 return(SOCKET_ERROR);
376         }
377         
378         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
379                 WSASetLastError (WSAENOTSOCK);
380                 return(SOCKET_ERROR);
381         }
382
383         ret = getpeername (fd, name, namelen);
384         if (ret == -1) {
385                 gint errnum = errno;
386 #ifdef DEBUG
387                 g_message ("%s: getpeername error: %s", __func__,
388                            strerror (errno));
389 #endif
390
391                 errnum = errno_to_WSA (errnum, __func__);
392                 WSASetLastError (errnum);
393
394                 return(SOCKET_ERROR);
395         }
396         
397         return(ret);
398 }
399
400 int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen)
401 {
402         gpointer handle = GUINT_TO_POINTER (fd);
403         int ret;
404         
405         if (startup_count == 0) {
406                 WSASetLastError (WSANOTINITIALISED);
407                 return(SOCKET_ERROR);
408         }
409         
410         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
411                 WSASetLastError (WSAENOTSOCK);
412                 return(SOCKET_ERROR);
413         }
414
415         ret = getsockname (fd, name, namelen);
416         if (ret == -1) {
417                 gint errnum = errno;
418 #ifdef DEBUG
419                 g_message ("%s: getsockname error: %s", __func__,
420                            strerror (errno));
421 #endif
422
423                 errnum = errno_to_WSA (errnum, __func__);
424                 WSASetLastError (errnum);
425
426                 return(SOCKET_ERROR);
427         }
428         
429         return(ret);
430 }
431
432 int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval,
433                      socklen_t *optlen)
434 {
435         gpointer handle = GUINT_TO_POINTER (fd);
436         int ret;
437         struct timeval tv;
438         void *tmp_val;
439         struct _WapiHandle_socket *socket_handle;
440         gboolean ok;
441         
442         if (startup_count == 0) {
443                 WSASetLastError (WSANOTINITIALISED);
444                 return(SOCKET_ERROR);
445         }
446         
447         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
448                 WSASetLastError (WSAENOTSOCK);
449                 return(SOCKET_ERROR);
450         }
451
452         tmp_val = optval;
453         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
454                 tmp_val = &tv;
455                 *optlen = sizeof (tv);
456         }
457
458         ret = getsockopt (fd, level, optname, tmp_val, optlen);
459         if (ret == -1) {
460                 gint errnum = errno;
461 #ifdef DEBUG
462                 g_message ("%s: getsockopt error: %s", __func__,
463                            strerror (errno));
464 #endif
465
466                 errnum = errno_to_WSA (errnum, __func__);
467                 WSASetLastError (errnum);
468                 
469                 return(SOCKET_ERROR);
470         }
471
472         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
473                 *((int *) optval)  = tv.tv_sec * 1000 + (tv.tv_usec / 1000);    // milli from micro
474                 *optlen = sizeof (int);
475         }
476
477         if (optname == SO_ERROR) {
478                 ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
479                                           (gpointer *)&socket_handle);
480                 if (ok == FALSE) {
481                         g_warning ("%s: error looking up socket handle %p",
482                                    __func__, handle);
483
484                         /* can't extract the last error */
485                         *((int *) optval) = errno_to_WSA (*((int *)optval),
486                                                           __func__);
487                 } else {
488                         if (*((int *)optval) != 0) {
489                                 *((int *) optval) = errno_to_WSA (*((int *)optval),
490                                                                   __func__);
491                                 socket_handle->saved_error = *((int *)optval);
492                         } else {
493                                 *((int *)optval) = socket_handle->saved_error;
494                         }
495                 }
496         }
497         
498         return(ret);
499 }
500
501 int _wapi_listen(guint32 fd, int backlog)
502 {
503         gpointer handle = GUINT_TO_POINTER (fd);
504         int ret;
505         
506         if (startup_count == 0) {
507                 WSASetLastError (WSANOTINITIALISED);
508                 return(SOCKET_ERROR);
509         }
510         
511         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
512                 WSASetLastError (WSAENOTSOCK);
513                 return(SOCKET_ERROR);
514         }
515         
516         ret = listen (fd, backlog);
517         if (ret == -1) {
518                 gint errnum = errno;
519 #ifdef DEBUG
520                 g_message ("%s: listen error: %s", __func__, strerror (errno));
521 #endif
522
523                 errnum = errno_to_WSA (errnum, __func__);
524                 WSASetLastError (errnum);
525
526                 return(SOCKET_ERROR);
527         }
528
529         return(0);
530 }
531
532 int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags)
533 {
534         return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0));
535 }
536
537 int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags,
538                    struct sockaddr *from, socklen_t *fromlen)
539 {
540         gpointer handle = GUINT_TO_POINTER (fd);
541         int ret;
542         
543         if (startup_count == 0) {
544                 WSASetLastError (WSANOTINITIALISED);
545                 return(SOCKET_ERROR);
546         }
547         
548         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
549                 WSASetLastError (WSAENOTSOCK);
550                 return(SOCKET_ERROR);
551         }
552         
553         do {
554                 ret = recvfrom (fd, buf, len, recv_flags, from, fromlen);
555         } while (ret == -1 && errno == EINTR &&
556                  !_wapi_thread_cur_apc_pending ());
557
558         if (ret == -1) {
559                 gint errnum = errno;
560 #ifdef DEBUG
561                 g_message ("%s: recv error: %s", __func__, strerror(errno));
562 #endif
563
564                 errnum = errno_to_WSA (errnum, __func__);
565                 WSASetLastError (errnum);
566                 
567                 return(SOCKET_ERROR);
568         }
569         return(ret);
570 }
571
572 int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags)
573 {
574         gpointer handle = GUINT_TO_POINTER (fd);
575         int ret;
576         
577         if (startup_count == 0) {
578                 WSASetLastError (WSANOTINITIALISED);
579                 return(SOCKET_ERROR);
580         }
581         
582         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
583                 WSASetLastError (WSAENOTSOCK);
584                 return(SOCKET_ERROR);
585         }
586
587         do {
588                 ret = send (fd, msg, len, send_flags);
589         } while (ret == -1 && errno == EINTR &&
590                  !_wapi_thread_cur_apc_pending ());
591
592         if (ret == -1) {
593                 gint errnum = errno;
594 #ifdef DEBUG
595                 g_message ("%s: send error: %s", __func__, strerror (errno));
596 #endif
597
598                 errnum = errno_to_WSA (errnum, __func__);
599                 WSASetLastError (errnum);
600                 
601                 return(SOCKET_ERROR);
602         }
603         return(ret);
604 }
605
606 int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags,
607                  const struct sockaddr *to, socklen_t tolen)
608 {
609         gpointer handle = GUINT_TO_POINTER (fd);
610         int ret;
611         
612         if (startup_count == 0) {
613                 WSASetLastError (WSANOTINITIALISED);
614                 return(SOCKET_ERROR);
615         }
616         
617         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
618                 WSASetLastError (WSAENOTSOCK);
619                 return(SOCKET_ERROR);
620         }
621         
622         do {
623                 ret = sendto (fd, msg, len, send_flags, to, tolen);
624         } while (ret == -1 && errno == EINTR &&
625                  !_wapi_thread_cur_apc_pending ());
626
627         if (ret == -1) {
628                 gint errnum = errno;
629 #ifdef DEBUG
630                 g_message ("%s: send error: %s", __func__, strerror (errno));
631 #endif
632
633                 errnum = errno_to_WSA (errnum, __func__);
634                 WSASetLastError (errnum);
635                 
636                 return(SOCKET_ERROR);
637         }
638         return(ret);
639 }
640
641 int _wapi_setsockopt(guint32 fd, int level, int optname,
642                      const void *optval, socklen_t optlen)
643 {
644         gpointer handle = GUINT_TO_POINTER (fd);
645         int ret;
646         const void *tmp_val;
647         struct timeval tv;
648         
649         if (startup_count == 0) {
650                 WSASetLastError (WSANOTINITIALISED);
651                 return(SOCKET_ERROR);
652         }
653         
654         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
655                 WSASetLastError (WSAENOTSOCK);
656                 return(SOCKET_ERROR);
657         }
658
659         tmp_val = optval;
660         if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) {
661                 int ms = *((int *) optval);
662                 tv.tv_sec = ms / 1000;
663                 tv.tv_usec = (ms % 1000) * 1000;        // micro from milli
664                 tmp_val = &tv;
665                 optlen = sizeof (tv);
666 #if defined (__linux__)
667         } else if (optname == SO_SNDBUF || optname == SO_RCVBUF) {
668                 /* According to socket(7) the Linux kernel doubles the
669                  * buffer sizes "to allow space for bookkeeping
670                  * overhead."
671                  */
672                 int bufsize = *((int *) optval);
673
674                 bufsize /= 2;
675                 tmp_val = &bufsize;
676 #endif
677         }
678                 
679         ret = setsockopt (fd, level, optname, tmp_val, optlen);
680         if (ret == -1) {
681                 gint errnum = errno;
682 #ifdef DEBUG
683                 g_message ("%s: setsockopt error: %s", __func__,
684                            strerror (errno));
685 #endif
686
687                 errnum = errno_to_WSA (errnum, __func__);
688                 WSASetLastError (errnum);
689                 
690                 return(SOCKET_ERROR);
691         }
692         
693         return(ret);
694 }
695
696 int _wapi_shutdown(guint32 fd, int how)
697 {
698         gpointer handle = GUINT_TO_POINTER (fd);
699         int ret;
700         
701         if (startup_count == 0) {
702                 WSASetLastError (WSANOTINITIALISED);
703                 return(SOCKET_ERROR);
704         }
705         
706         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
707                 WSASetLastError (WSAENOTSOCK);
708                 return(SOCKET_ERROR);
709         }
710         
711         ret = shutdown (fd, how);
712         if (ret == -1) {
713                 gint errnum = errno;
714 #ifdef DEBUG
715                 g_message ("%s: shutdown error: %s", __func__,
716                            strerror (errno));
717 #endif
718
719                 errnum = errno_to_WSA (errnum, __func__);
720                 WSASetLastError (errnum);
721                 
722                 return(SOCKET_ERROR);
723         }
724         
725         return(ret);
726 }
727
728 guint32 _wapi_socket(int domain, int type, int protocol, void *unused,
729                      guint32 unused2, guint32 unused3)
730 {
731         struct _WapiHandle_socket socket_handle = {0};
732         gpointer handle;
733         int fd;
734         
735         socket_handle.domain = domain;
736         socket_handle.type = type;
737         socket_handle.protocol = protocol;
738         
739         fd = socket (domain, type, protocol);
740         if (fd == -1 && domain == AF_INET && type == SOCK_RAW &&
741             protocol == 0) {
742                 /* Retry with protocol == 4 (see bug #54565) */
743                 socket_handle.protocol = 4;
744                 fd = socket (AF_INET, SOCK_RAW, 4);
745         }
746         
747         if (fd == -1) {
748                 gint errnum = errno;
749 #ifdef DEBUG
750                 g_message ("%s: socket error: %s", __func__, strerror (errno));
751 #endif
752                 errnum = errno_to_WSA (errnum, __func__);
753                 WSASetLastError (errnum);
754
755                 return(INVALID_SOCKET);
756         }
757
758         if (fd >= _wapi_fd_reserve) {
759 #ifdef DEBUG
760                 g_message ("%s: File descriptor is too big (%d >= %d)",
761                            __func__, fd, _wapi_fd_reserve);
762 #endif
763
764                 WSASetLastError (WSASYSCALLFAILURE);
765                 close (fd);
766                 
767                 return(INVALID_SOCKET);
768         }
769         
770         
771         mono_once (&socket_ops_once, socket_ops_init);
772         
773         handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, &socket_handle);
774         if (handle == _WAPI_HANDLE_INVALID) {
775                 g_warning ("%s: error creating socket handle", __func__);
776                 return(INVALID_SOCKET);
777         }
778
779 #ifdef DEBUG
780         g_message ("%s: returning socket handle %p", __func__, handle);
781 #endif
782
783         return(fd);
784 }
785
786 struct hostent *_wapi_gethostbyname(const char *hostname)
787 {
788         struct hostent *he;
789         
790         if (startup_count == 0) {
791                 WSASetLastError (WSANOTINITIALISED);
792                 return(NULL);
793         }
794
795         he = gethostbyname (hostname);
796         if (he == NULL) {
797 #ifdef DEBUG
798                 g_message ("%s: gethostbyname error: %s", __func__,
799                            strerror (h_errno));
800 #endif
801
802                 switch(h_errno) {
803                 case HOST_NOT_FOUND:
804                         WSASetLastError (WSAHOST_NOT_FOUND);
805                         break;
806 #if NO_ADDRESS != NO_DATA
807                 case NO_ADDRESS:
808 #endif
809                 case NO_DATA:
810                         WSASetLastError (WSANO_DATA);
811                         break;
812                 case NO_RECOVERY:
813                         WSASetLastError (WSANO_RECOVERY);
814                         break;
815                 case TRY_AGAIN:
816                         WSASetLastError (WSATRY_AGAIN);
817                         break;
818                 default:
819                         g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno);
820                         break;
821                 }
822         }
823         
824         return(he);
825 }
826
827 static gboolean socket_disconnect (guint32 fd)
828 {
829         struct _WapiHandle_socket *socket_handle;
830         gboolean ok;
831         gpointer handle = GUINT_TO_POINTER (fd);
832         int newsock, ret;
833         
834         ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET,
835                                   (gpointer *)&socket_handle);
836         if (ok == FALSE) {
837                 g_warning ("%s: error looking up socket handle %p", __func__,
838                            handle);
839                 WSASetLastError (WSAENOTSOCK);
840                 return(FALSE);
841         }
842         
843         newsock = socket (socket_handle->domain, socket_handle->type,
844                           socket_handle->protocol);
845         if (newsock == -1) {
846                 gint errnum = errno;
847
848 #ifdef DEBUG
849                 g_message ("%s: socket error: %s", __func__, strerror (errno));
850 #endif
851
852                 errnum = errno_to_WSA (errnum, __func__);
853                 WSASetLastError (errnum);
854                 
855                 return(FALSE);
856         }
857
858         /* According to Stevens "Advanced Programming in the UNIX
859          * Environment: UNIX File I/O" dup2() is atomic so there
860          * should not be a race condition between the old fd being
861          * closed and the new socket fd being copied over
862          */
863         do {
864                 ret = dup2 (newsock, fd);
865         } while (ret == -1 && errno == EAGAIN);
866         
867         if (ret == -1) {
868                 gint errnum = errno;
869                 
870 #ifdef DEBUG
871                 g_message ("%s: dup2 error: %s", __func__, strerror (errno));
872 #endif
873
874                 errnum = errno_to_WSA (errnum, __func__);
875                 WSASetLastError (errnum);
876                 
877                 return(FALSE);
878         }
879
880         close (newsock);
881         
882         return(TRUE);
883 }
884
885 static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped,
886                                    guint32 flags, guint32 reserved)
887 {
888 #ifdef DEBUG
889         g_message ("%s: called on socket %d!", __func__, fd);
890 #endif
891         
892         if (reserved != 0) {
893                 WSASetLastError (WSAEINVAL);
894                 return(FALSE);
895         }
896
897         /* We could check the socket type here and fail unless its
898          * SOCK_STREAM, SOCK_SEQPACKET or SOCK_RDM (according to msdn)
899          * if we really wanted to
900          */
901
902         return(socket_disconnect (fd));
903 }
904
905 /* NB only supports NULL file handle, NULL buffers and
906  * TF_DISCONNECT|TF_REUSE_SOCKET flags to disconnect the socket fd.
907  * Shouldn't actually ever need to be called anyway though, because we
908  * have DisconnectEx ().
909  */
910 static gboolean wapi_transmitfile (guint32 fd, gpointer file,
911                                    guint32 num_write, guint32 num_per_send,
912                                    WapiOverlapped *overlapped,
913                                    WapiTransmitFileBuffers *buffers,
914                                    WapiTransmitFileFlags flags)
915 {
916 #ifdef DEBUG
917         g_message ("%s: called on socket %d!", __func__, fd);
918 #endif
919         
920         g_assert (file == NULL);
921         g_assert (overlapped == NULL);
922         g_assert (buffers == NULL);
923         g_assert (num_write == 0);
924         g_assert (num_per_send == 0);
925         g_assert (flags == (TF_DISCONNECT | TF_REUSE_SOCKET));
926
927         return(socket_disconnect (fd));
928 }
929
930 static struct 
931 {
932         WapiGuid guid;
933         gpointer func;
934 } extension_functions[] = {
935         {WSAID_DISCONNECTEX, wapi_disconnectex},
936         {WSAID_TRANSMITFILE, wapi_transmitfile},
937         {{0}, NULL},
938 };
939
940 int
941 WSAIoctl (guint32 fd, gint32 command,
942           gchar *input, gint i_len,
943           gchar *output, gint o_len, glong *written,
944           void *unused1, void *unused2)
945 {
946         gpointer handle = GUINT_TO_POINTER (fd);
947         int ret;
948         gchar *buffer = NULL;
949
950         if (startup_count == 0) {
951                 WSASetLastError (WSANOTINITIALISED);
952                 return(SOCKET_ERROR);
953         }
954
955         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
956                 WSASetLastError (WSAENOTSOCK);
957                 return SOCKET_ERROR;
958         }
959
960         if (command == SIO_GET_EXTENSION_FUNCTION_POINTER) {
961                 int i = 0;
962                 WapiGuid *guid = (WapiGuid *)input;
963                 
964                 if (i_len < sizeof(WapiGuid)) {
965                         /* As far as I can tell, windows doesn't
966                          * actually set an error here...
967                          */
968                         WSASetLastError (WSAEINVAL);
969                         return(SOCKET_ERROR);
970                 }
971
972                 if (o_len < sizeof(gpointer)) {
973                         /* Or here... */
974                         WSASetLastError (WSAEINVAL);
975                         return(SOCKET_ERROR);
976                 }
977
978                 if (output == NULL) {
979                         /* Or here */
980                         WSASetLastError (WSAEINVAL);
981                         return(SOCKET_ERROR);
982                 }
983                 
984                 while(extension_functions[i].func != NULL) {
985                         if (!memcmp (guid, &extension_functions[i].guid,
986                                      sizeof(WapiGuid))) {
987                                 memcpy (output, &extension_functions[i].func,
988                                         sizeof(gpointer));
989                                 *written = sizeof(gpointer);
990                                 return(0);
991                         }
992
993                         i++;
994                 }
995                 
996                 WSASetLastError (WSAEINVAL);
997                 return(SOCKET_ERROR);
998         }
999
1000         if (i_len > 0) {
1001                 buffer = g_memdup (input, i_len);
1002         }
1003
1004         ret = ioctl (fd, command, buffer);
1005         if (ret == -1) {
1006                 gint errnum = errno;
1007 #ifdef DEBUG
1008                 g_message("%s: WSAIoctl error: %s", __func__,
1009                           strerror (errno));
1010 #endif
1011
1012                 errnum = errno_to_WSA (errnum, __func__);
1013                 WSASetLastError (errnum);
1014                 g_free (buffer);
1015                 
1016                 return(SOCKET_ERROR);
1017         }
1018
1019         if (buffer == NULL) {
1020                 *written = 0;
1021         } else {
1022                 /* We just copy the buffer to the output. Some ioctls
1023                  * don't even output any data, but, well...
1024                  *
1025                  * NB windows returns WSAEFAULT if o_len is too small
1026                  */
1027                 i_len = (i_len > o_len) ? o_len : i_len;
1028
1029                 if (i_len > 0 && output != NULL) {
1030                         memcpy (output, buffer, i_len);
1031                 }
1032                 
1033                 g_free (buffer);
1034                 *written = i_len;
1035         }
1036
1037         return(0);
1038 }
1039
1040 int ioctlsocket(guint32 fd, gint32 command, gpointer arg)
1041 {
1042         gpointer handle = GUINT_TO_POINTER (fd);
1043         int ret;
1044         
1045         if (startup_count == 0) {
1046                 WSASetLastError (WSANOTINITIALISED);
1047                 return(SOCKET_ERROR);
1048         }
1049         
1050         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1051                 WSASetLastError (WSAENOTSOCK);
1052                 return(SOCKET_ERROR);
1053         }
1054
1055         switch(command){
1056                 case FIONBIO:
1057 #ifdef O_NONBLOCK
1058                         /* This works better than ioctl(...FIONBIO...) 
1059                          * on Linux (it causes connect to return
1060                          * EINPROGRESS, but the ioctl doesn't seem to)
1061                          */
1062                         ret = fcntl(fd, F_GETFL, 0);
1063                         if (ret != -1) {
1064                                 if (*(gboolean *)arg) {
1065                                         ret |= O_NONBLOCK;
1066                                 } else {
1067                                         ret &= ~O_NONBLOCK;
1068                                 }
1069                                 ret = fcntl(fd, F_SETFL, ret);
1070                         }
1071                         break;
1072 #endif /* O_NONBLOCK */
1073                 case FIONREAD:
1074                 case SIOCATMARK:
1075                         ret = ioctl (fd, command, arg);
1076                         break;
1077                 default:
1078                         WSASetLastError (WSAEINVAL);
1079                         return(SOCKET_ERROR);
1080         }
1081
1082         if (ret == -1) {
1083                 gint errnum = errno;
1084 #ifdef DEBUG
1085                 g_message ("%s: ioctl error: %s", __func__, strerror (errno));
1086 #endif
1087
1088                 errnum = errno_to_WSA (errnum, __func__);
1089                 WSASetLastError (errnum);
1090                 
1091                 return(SOCKET_ERROR);
1092         }
1093         
1094         return(0);
1095 }
1096
1097 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
1098                  fd_set *exceptfds, struct timeval *timeout)
1099 {
1100         int ret, maxfd;
1101         
1102         if (startup_count == 0) {
1103                 WSASetLastError (WSANOTINITIALISED);
1104                 return(SOCKET_ERROR);
1105         }
1106
1107         for (maxfd = FD_SETSIZE-1; maxfd >= 0; maxfd--) {
1108                 if ((readfds && FD_ISSET (maxfd, readfds)) ||
1109                     (writefds && FD_ISSET (maxfd, writefds)) ||
1110                     (exceptfds && FD_ISSET (maxfd, exceptfds))) {
1111                         break;
1112                 }
1113         }
1114
1115         if (maxfd == -1) {
1116                 WSASetLastError (WSAEINVAL);
1117                 return(SOCKET_ERROR);
1118         }
1119
1120         do {
1121                 ret = select(maxfd + 1, readfds, writefds, exceptfds,
1122                              timeout);
1123         } while (ret == -1 && errno == EINTR &&
1124                  !_wapi_thread_cur_apc_pending ());
1125
1126         if (ret == -1) {
1127                 gint errnum = errno;
1128 #ifdef DEBUG
1129                 g_message ("%s: select error: %s", __func__, strerror (errno));
1130 #endif
1131                 errnum = errno_to_WSA (errnum, __func__);
1132                 WSASetLastError (errnum);
1133                 
1134                 return(SOCKET_ERROR);
1135         }
1136
1137         return(ret);
1138 }
1139
1140 void _wapi_FD_CLR(guint32 fd, fd_set *set)
1141 {
1142         gpointer handle = GUINT_TO_POINTER (fd);
1143         
1144         if (fd >= FD_SETSIZE) {
1145                 WSASetLastError (WSAEINVAL);
1146                 return;
1147         }
1148         
1149         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1150                 WSASetLastError (WSAENOTSOCK);
1151                 return;
1152         }
1153
1154         FD_CLR (fd, set);
1155 }
1156
1157 int _wapi_FD_ISSET(guint32 fd, fd_set *set)
1158 {
1159         gpointer handle = GUINT_TO_POINTER (fd);
1160         
1161         if (fd >= FD_SETSIZE) {
1162                 WSASetLastError (WSAEINVAL);
1163                 return(0);
1164         }
1165         
1166         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1167                 WSASetLastError (WSAENOTSOCK);
1168                 return(0);
1169         }
1170
1171         return(FD_ISSET (fd, set));
1172 }
1173
1174 void _wapi_FD_SET(guint32 fd, fd_set *set)
1175 {
1176         gpointer handle = GUINT_TO_POINTER (fd);
1177         
1178         if (fd >= FD_SETSIZE) {
1179                 WSASetLastError (WSAEINVAL);
1180                 return;
1181         }
1182
1183         if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) {
1184                 WSASetLastError (WSAENOTSOCK);
1185                 return;
1186         }
1187
1188         FD_SET (fd, set);
1189 }
1190