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