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