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