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