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