2004-01-29 Zoltan Varga <vargaz@freemail.hu>
[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         pthread_key_create(&error_key, NULL);
166 }
167
168 void WSASetLastError(int error)
169 {
170         mono_once(&error_key_once, error_init);
171         pthread_setspecific(error_key, GINT_TO_POINTER(error));
172 }
173
174 int WSAGetLastError(void)
175 {
176         int err;
177         void *errptr;
178         
179         mono_once(&error_key_once, error_init);
180         errptr=pthread_getspecific(error_key);
181         err=GPOINTER_TO_INT(errptr);
182         
183         return(err);
184 }
185
186 int closesocket(guint32 handle)
187 {
188         _wapi_handle_unref (GUINT_TO_POINTER (handle));
189         return(0);
190 }
191
192 guint32 _wapi_accept(guint32 handle, struct sockaddr *addr,
193                      socklen_t *addrlen)
194 {
195         struct _WapiHandlePrivate_socket *socket_private_handle;
196         struct _WapiHandlePrivate_socket *new_socket_private_handle;
197         gpointer new_handle;
198         gboolean ok;
199         int fd;
200         
201         if(startup_count==0) {
202                 WSASetLastError(WSANOTINITIALISED);
203                 return(INVALID_SOCKET);
204         }
205         
206         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
207                                 NULL, (gpointer *)&socket_private_handle);
208         if(ok==FALSE) {
209                 g_warning (G_GNUC_PRETTY_FUNCTION
210                            ": error looking up socket handle 0x%x", handle);
211                 WSASetLastError(WSAENOTSOCK);
212                 return(INVALID_SOCKET);
213         }
214         
215         fd=accept(socket_private_handle->fd, addr, addrlen);
216         if(fd==-1) {
217                 gint errnum = errno;
218 #ifdef DEBUG
219                 g_message(G_GNUC_PRETTY_FUNCTION ": accept error: %s",
220                           strerror(errno));
221 #endif
222
223                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
224                 WSASetLastError (errnum);
225                 
226                 return(INVALID_SOCKET);
227         }
228
229         new_handle=_wapi_handle_new (WAPI_HANDLE_SOCKET);
230         if(new_handle==_WAPI_HANDLE_INVALID) {
231                 g_warning (G_GNUC_PRETTY_FUNCTION
232                            ": error creating socket handle");
233                 return(INVALID_SOCKET);
234         }
235
236         _wapi_handle_lock_handle (new_handle);
237         
238         ok=_wapi_lookup_handle (new_handle, WAPI_HANDLE_SOCKET, NULL,
239                                 (gpointer *)&new_socket_private_handle);
240         if(ok==FALSE) {
241                 g_warning (G_GNUC_PRETTY_FUNCTION
242                            ": error looking up socket handle 0x%x", handle);
243                 _wapi_handle_unlock_handle (new_handle);
244                 return(INVALID_SOCKET);
245         }
246         
247         new_socket_private_handle->fd=fd;
248         
249 #ifdef DEBUG
250         g_message(G_GNUC_PRETTY_FUNCTION
251                   ": returning newly accepted socket handle %p with fd %d",
252                   new_handle, new_socket_private_handle->fd);
253 #endif
254
255         _wapi_handle_unlock_handle (new_handle);
256
257         return(GPOINTER_TO_UINT (new_handle));
258 }
259
260 int _wapi_bind(guint32 handle, struct sockaddr *my_addr, socklen_t addrlen)
261 {
262         struct _WapiHandlePrivate_socket *socket_private_handle;
263         gboolean ok;
264         int ret;
265         
266         if(startup_count==0) {
267                 WSASetLastError(WSANOTINITIALISED);
268                 return(SOCKET_ERROR);
269         }
270         
271         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
272                                 NULL, (gpointer *)&socket_private_handle);
273         if(ok==FALSE) {
274                 g_warning (G_GNUC_PRETTY_FUNCTION
275                            ": error looking up socket handle 0x%x", handle);
276                 WSASetLastError(WSAENOTSOCK);
277                 return(SOCKET_ERROR);
278         }
279         
280         ret=bind(socket_private_handle->fd, my_addr, addrlen);
281         if(ret==-1) {
282                 gint errnum = errno;
283 #ifdef DEBUG
284                 g_message(G_GNUC_PRETTY_FUNCTION ": bind error: %s",
285                           strerror(errno));
286 #endif
287                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
288                 WSASetLastError (errnum);
289                 
290                 return(SOCKET_ERROR);
291         }
292         return(ret);
293 }
294
295 int _wapi_connect(guint32 handle, const struct sockaddr *serv_addr,
296                   socklen_t addrlen)
297 {
298         struct _WapiHandlePrivate_socket *socket_private_handle;
299         gboolean ok;
300         int ret;
301         gint errnum;
302         
303         if(startup_count==0) {
304                 WSASetLastError(WSANOTINITIALISED);
305                 return(SOCKET_ERROR);
306         }
307         
308         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
309                                 NULL, (gpointer *)&socket_private_handle);
310         if(ok==FALSE) {
311                 g_warning (G_GNUC_PRETTY_FUNCTION
312                            ": error looking up socket handle 0x%x", handle);
313                 WSASetLastError(WSAENOTSOCK);
314                 return(SOCKET_ERROR);
315         }
316         
317         ret=connect(socket_private_handle->fd, serv_addr, addrlen);
318         if(ret==-1 && errno==EACCES) {
319                 /* Try setting SO_BROADCAST and connecting again, but
320                  * keep the original errno
321                  */
322                 int true=1;
323                 
324                 errnum = errno;
325
326                 ret=setsockopt (socket_private_handle->fd, SOL_SOCKET,
327                                 SO_BROADCAST, &true, sizeof(true));
328                 if(ret==0) {
329                         ret=connect (socket_private_handle->fd, serv_addr,
330                                      addrlen);
331                 }
332         } else if (ret==-1) {
333                 errnum = errno;
334         }
335         
336         if(ret==-1) {
337 #ifdef DEBUG
338                 g_message(G_GNUC_PRETTY_FUNCTION ": connect error: %s",
339                           strerror(errnum));
340 #endif
341                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
342                 WSASetLastError (errnum);
343                 
344                 return(SOCKET_ERROR);
345         }
346         return(ret);
347 }
348
349 int _wapi_getpeername(guint32 handle, struct sockaddr *name,
350                       socklen_t *namelen)
351 {
352         struct _WapiHandlePrivate_socket *socket_private_handle;
353         gboolean ok;
354         int ret;
355         
356         if(startup_count==0) {
357                 WSASetLastError(WSANOTINITIALISED);
358                 return(SOCKET_ERROR);
359         }
360         
361         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
362                                 NULL, (gpointer *)&socket_private_handle);
363         if(ok==FALSE) {
364                 g_warning (G_GNUC_PRETTY_FUNCTION
365                            ": error looking up socket handle 0x%x", handle);
366                 WSASetLastError(WSAENOTSOCK);
367                 return(SOCKET_ERROR);
368         }
369
370         ret=getpeername(socket_private_handle->fd, name, namelen);
371         if(ret==-1) {
372                 gint errnum = errno;
373 #ifdef DEBUG
374                 g_message(G_GNUC_PRETTY_FUNCTION ": getpeername error: %s",
375                           strerror(errno));
376 #endif
377
378                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
379                 WSASetLastError (errnum);
380
381                 return(SOCKET_ERROR);
382         }
383         
384         return(ret);
385 }
386
387 int _wapi_getsockname(guint32 handle, struct sockaddr *name,
388                       socklen_t *namelen)
389 {
390         struct _WapiHandlePrivate_socket *socket_private_handle;
391         gboolean ok;
392         int ret;
393         
394         if(startup_count==0) {
395                 WSASetLastError(WSANOTINITIALISED);
396                 return(SOCKET_ERROR);
397         }
398         
399         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
400                                 NULL, (gpointer *)&socket_private_handle);
401         if(ok==FALSE) {
402                 g_warning (G_GNUC_PRETTY_FUNCTION
403                            ": error looking up socket handle 0x%x", handle);
404                 WSASetLastError(WSAENOTSOCK);
405                 return(SOCKET_ERROR);
406         }
407
408         ret=getsockname(socket_private_handle->fd, name, namelen);
409         if(ret==-1) {
410                 gint errnum = errno;
411 #ifdef DEBUG
412                 g_message(G_GNUC_PRETTY_FUNCTION ": getsockname error: %s",
413                           strerror(errno));
414 #endif
415
416                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
417                 WSASetLastError (errnum);
418
419                 return(SOCKET_ERROR);
420         }
421         
422         return(ret);
423 }
424
425 int _wapi_getsockopt(guint32 handle, int level, int optname, void *optval,
426                      socklen_t *optlen)
427 {
428         struct _WapiHandlePrivate_socket *socket_private_handle;
429         gboolean ok;
430         int ret;
431         
432         if(startup_count==0) {
433                 WSASetLastError(WSANOTINITIALISED);
434                 return(SOCKET_ERROR);
435         }
436         
437         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
438                                 NULL, (gpointer *)&socket_private_handle);
439         if(ok==FALSE) {
440                 g_warning (G_GNUC_PRETTY_FUNCTION
441                            ": error looking up socket handle 0x%x", handle);
442                 WSASetLastError(WSAENOTSOCK);
443                 return(SOCKET_ERROR);
444         }
445         
446         ret=getsockopt(socket_private_handle->fd, level, optname, optval,
447                        optlen);
448         if(ret==-1) {
449                 gint errnum = errno;
450 #ifdef DEBUG
451                 g_message(G_GNUC_PRETTY_FUNCTION ": getsockopt error: %s",
452                           strerror(errno));
453 #endif
454
455                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
456                 WSASetLastError (errnum);
457                 
458                 return(SOCKET_ERROR);
459         }
460         
461         return(ret);
462 }
463
464 int _wapi_listen(guint32 handle, int backlog)
465 {
466         struct _WapiHandlePrivate_socket *socket_private_handle;
467         gboolean ok;
468         int ret;
469         
470         if(startup_count==0) {
471                 WSASetLastError(WSANOTINITIALISED);
472                 return(SOCKET_ERROR);
473         }
474         
475         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
476                                 NULL, (gpointer *)&socket_private_handle);
477         if(ok==FALSE) {
478                 g_warning (G_GNUC_PRETTY_FUNCTION
479                            ": error looking up socket handle 0x%x", handle);
480                 WSASetLastError(WSAENOTSOCK);
481                 return(SOCKET_ERROR);
482         }
483         
484         ret=listen(socket_private_handle->fd, backlog);
485         if(ret==-1) {
486                 gint errnum = errno;
487 #ifdef DEBUG
488                 g_message(G_GNUC_PRETTY_FUNCTION ": listen error: %s",
489                           strerror(errno));
490 #endif
491
492                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
493                 WSASetLastError (errnum);
494
495                 return(SOCKET_ERROR);
496         }
497
498         return(0);
499 }
500
501 int _wapi_recv(guint32 handle, void *buf, size_t len, int recv_flags)
502 {
503         return(_wapi_recvfrom(handle, buf, len, recv_flags, NULL, 0));
504 }
505
506 int _wapi_recvfrom(guint32 handle, void *buf, size_t len, int recv_flags,
507                    struct sockaddr *from, socklen_t *fromlen)
508 {
509 #ifndef HAVE_MSG_NOSIGNAL
510         void (*old_sigpipe)(int);       // old SIGPIPE handler
511 #endif
512         struct _WapiHandlePrivate_socket *socket_private_handle;
513         gboolean ok;
514         int ret;
515         
516         if(startup_count==0) {
517                 WSASetLastError(WSANOTINITIALISED);
518                 return(SOCKET_ERROR);
519         }
520         
521         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
522                                 NULL, (gpointer *)&socket_private_handle);
523         if(ok==FALSE) {
524                 g_warning (G_GNUC_PRETTY_FUNCTION
525                            ": error looking up socket handle 0x%x", handle);
526                 WSASetLastError(WSAENOTSOCK);
527                 return(SOCKET_ERROR);
528         }
529         
530 #ifdef HAVE_MSG_NOSIGNAL
531         ret=recvfrom(socket_private_handle->fd, buf, len, recv_flags | MSG_NOSIGNAL, from,
532                      fromlen);
533 #else
534         old_sigpipe = signal(SIGPIPE, SIG_IGN);
535         ret=recvfrom(socket_private_handle->fd, buf, len, recv_flags, from,
536                      fromlen);
537         signal(SIGPIPE, old_sigpipe);
538 #endif
539
540         if(ret==-1) {
541                 gint errnum = errno;
542 #ifdef DEBUG
543                 g_message(G_GNUC_PRETTY_FUNCTION ": recv error: %s",
544                           strerror(errno));
545 #endif
546
547                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
548                 WSASetLastError (errnum);
549                 
550                 return(SOCKET_ERROR);
551         }
552         return(ret);
553 }
554
555 int _wapi_send(guint32 handle, const void *msg, size_t len, int send_flags)
556 {
557 #ifndef HAVE_MSG_NOSIGNAL
558         void (*old_sigpipe)(int);       // old SIGPIPE handler
559 #endif
560         struct _WapiHandlePrivate_socket *socket_private_handle;
561         gboolean ok;
562         int ret;
563         
564         if(startup_count==0) {
565                 WSASetLastError(WSANOTINITIALISED);
566                 return(SOCKET_ERROR);
567         }
568         
569         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
570                                 NULL, (gpointer *)&socket_private_handle);
571         if(ok==FALSE) {
572                 g_warning (G_GNUC_PRETTY_FUNCTION
573                            ": error looking up socket handle 0x%x", handle);
574                 WSASetLastError(WSAENOTSOCK);
575                 return(SOCKET_ERROR);
576         }
577
578 #ifdef HAVE_MSG_NOSIGNAL
579         ret=send(socket_private_handle->fd, msg, len, send_flags | MSG_NOSIGNAL);
580 #else
581         old_sigpipe = signal(SIGPIPE, SIG_IGN);
582         ret=send(socket_private_handle->fd, msg, len, send_flags);
583         signal(SIGPIPE, old_sigpipe);
584 #endif
585         if(ret==-1) {
586                 gint errnum = errno;
587 #ifdef DEBUG
588                 g_message(G_GNUC_PRETTY_FUNCTION ": send error: %s",
589                           strerror(errno));
590 #endif
591
592                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
593                 WSASetLastError (errnum);
594                 
595                 return(SOCKET_ERROR);
596         }
597         return(ret);
598 }
599
600 int _wapi_sendto(guint32 handle, const void *msg, size_t len, int send_flags,
601                  const struct sockaddr *to, socklen_t tolen)
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         ret=sendto(socket_private_handle->fd, msg, len, send_flags | MSG_NOSIGNAL, to, tolen);
626 #else
627         old_sigpipe = signal(SIGPIPE, SIG_IGN);
628         ret=sendto(socket_private_handle->fd, msg, len, send_flags, to, tolen);
629         signal(SIGPIPE, old_sigpipe);
630 #endif
631         if(ret==-1) {
632                 gint errnum = errno;
633 #ifdef DEBUG
634                 g_message(G_GNUC_PRETTY_FUNCTION ": send error: %s",
635                           strerror(errno));
636 #endif
637
638                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
639                 WSASetLastError (errnum);
640                 
641                 return(SOCKET_ERROR);
642         }
643         return(ret);
644 }
645
646 int _wapi_setsockopt(guint32 handle, int level, int optname,
647                      const void *optval, socklen_t optlen)
648 {
649         struct _WapiHandlePrivate_socket *socket_private_handle;
650         gboolean ok;
651         int ret;
652         
653         if(startup_count==0) {
654                 WSASetLastError(WSANOTINITIALISED);
655                 return(SOCKET_ERROR);
656         }
657         
658         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
659                                 NULL, (gpointer *)&socket_private_handle);
660         if(ok==FALSE) {
661                 g_warning (G_GNUC_PRETTY_FUNCTION
662                            ": error looking up socket handle 0x%x", handle);
663                 WSASetLastError(WSAENOTSOCK);
664                 return(SOCKET_ERROR);
665         }
666         
667         ret=setsockopt(socket_private_handle->fd, level, optname, optval,
668                        optlen);
669         if(ret==-1) {
670                 gint errnum = errno;
671 #ifdef DEBUG
672                 g_message(G_GNUC_PRETTY_FUNCTION ": setsockopt error: %s",
673                           strerror(errno));
674 #endif
675
676                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
677                 WSASetLastError (errnum);
678                 
679                 return(SOCKET_ERROR);
680         }
681         
682         return(ret);
683 }
684
685 int _wapi_shutdown(guint32 handle, int how)
686 {
687         struct _WapiHandlePrivate_socket *socket_private_handle;
688         gboolean ok;
689         int ret;
690         
691         if(startup_count==0) {
692                 WSASetLastError(WSANOTINITIALISED);
693                 return(SOCKET_ERROR);
694         }
695         
696         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
697                                 NULL, (gpointer *)&socket_private_handle);
698         if(ok==FALSE) {
699                 g_warning (G_GNUC_PRETTY_FUNCTION
700                            ": error looking up socket handle 0x%x", handle);
701                 WSASetLastError(WSAENOTSOCK);
702                 return(SOCKET_ERROR);
703         }
704         
705         ret=shutdown(socket_private_handle->fd, how);
706         if(ret==-1) {
707                 gint errnum = errno;
708 #ifdef DEBUG
709                 g_message(G_GNUC_PRETTY_FUNCTION ": shutdown error: %s",
710                           strerror(errno));
711 #endif
712
713                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
714                 WSASetLastError (errnum);
715                 
716                 return(SOCKET_ERROR);
717         }
718         
719         return(ret);
720 }
721
722 guint32 _wapi_socket(int domain, int type, int protocol)
723 {
724         struct _WapiHandlePrivate_socket *socket_private_handle;
725         gpointer handle;
726         gboolean ok;
727         int fd;
728         
729         fd=socket(domain, type, protocol);
730         if(fd==-1) {
731                 gint errnum = errno;
732 #ifdef DEBUG
733                 g_message(G_GNUC_PRETTY_FUNCTION ": socket error: %s", strerror(errno));
734 #endif
735                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
736                 WSASetLastError (errnum);
737
738                 return(INVALID_SOCKET);
739         }
740         
741         mono_once (&socket_ops_once, socket_ops_init);
742         
743         handle=_wapi_handle_new (WAPI_HANDLE_SOCKET);
744         if(handle==_WAPI_HANDLE_INVALID) {
745                 g_warning (G_GNUC_PRETTY_FUNCTION
746                            ": error creating socket handle");
747                 return(INVALID_SOCKET);
748         }
749
750         _wapi_handle_lock_handle (handle);
751         
752         ok=_wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, NULL,
753                                 (gpointer *)&socket_private_handle);
754         if(ok==FALSE) {
755                 g_warning (G_GNUC_PRETTY_FUNCTION
756                            ": error looking up socket handle %p", handle);
757                 _wapi_handle_unlock_handle (handle);
758                 return(INVALID_SOCKET);
759         }
760         
761         socket_private_handle->fd=fd;
762         
763 #ifdef DEBUG
764         g_message(G_GNUC_PRETTY_FUNCTION
765                   ": returning socket handle %p with fd %d", handle,
766                   socket_private_handle->fd);
767 #endif
768
769         _wapi_handle_unlock_handle (handle);
770
771         return(GPOINTER_TO_UINT (handle));
772 }
773
774 struct hostent *_wapi_gethostbyname(const char *hostname)
775 {
776         struct hostent *he;
777         
778         if(startup_count==0) {
779                 WSASetLastError(WSANOTINITIALISED);
780                 return(NULL);
781         }
782
783         he=gethostbyname(hostname);
784         if(he==NULL) {
785 #ifdef DEBUG
786                 g_message(G_GNUC_PRETTY_FUNCTION ": gethostbyname error: %s",
787                           strerror(h_errno));
788 #endif
789
790                 switch(h_errno) {
791                 case HOST_NOT_FOUND:
792                         WSASetLastError(WSAHOST_NOT_FOUND);
793                         break;
794 #if NO_ADDRESS != NO_DATA
795                 case NO_ADDRESS:
796 #endif
797                 case NO_DATA:
798                         WSASetLastError(WSANO_DATA);
799                         break;
800                 case NO_RECOVERY:
801                         WSASetLastError(WSANO_RECOVERY);
802                         break;
803                 case TRY_AGAIN:
804                         WSASetLastError(WSATRY_AGAIN);
805                         break;
806                 default:
807                         g_warning (G_GNUC_PRETTY_FUNCTION ": Need to translate %d into winsock error", h_errno);
808                         break;
809                 }
810         }
811         
812         return(he);
813 }
814
815 int ioctlsocket(guint32 handle, gint32 command, gpointer arg)
816 {
817         struct _WapiHandlePrivate_socket *socket_private_handle;
818         gboolean ok;
819         int ret;
820         
821         if(startup_count==0) {
822                 WSASetLastError(WSANOTINITIALISED);
823                 return(SOCKET_ERROR);
824         }
825         
826         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
827                                 NULL, (gpointer *)&socket_private_handle);
828         if(ok==FALSE) {
829                 g_warning (G_GNUC_PRETTY_FUNCTION
830                            ": error looking up socket handle 0x%x", handle);
831                 WSASetLastError(WSAENOTSOCK);
832                 return(SOCKET_ERROR);
833         }
834
835         if(command!=FIONBIO &&
836            command!=FIONREAD &&
837            command!=SIOCATMARK) {
838                 /* Not listed in the MSDN specs, but ioctl(2) returns
839                  * this if command is invalid
840                  */
841                 WSASetLastError(WSAEINVAL);
842                 return(SOCKET_ERROR);
843         }
844
845 #ifdef O_NONBLOCK
846         /* This works better than ioctl(...FIONBIO...) on Linux (it causes
847          * connect to return EINPROGRESS, but the ioctl doesn't seem to)
848          */
849         if(command==FIONBIO) {
850                 ret=fcntl(socket_private_handle->fd, F_GETFL, 0);
851                 if(ret!=-1) {
852                         if(*(gboolean *)arg) {
853                                 ret &= ~O_NONBLOCK;
854                         } else {
855                                 ret |= O_NONBLOCK;
856                         }
857                         ret=fcntl(socket_private_handle->fd, F_SETFL, ret);
858                 }
859         } else
860 #endif /* O_NONBLOCK */
861         {
862                 ret=ioctl(socket_private_handle->fd, command, arg);
863         }
864         if(ret==-1) {
865                 gint errnum = errno;
866 #ifdef DEBUG
867                 g_message(G_GNUC_PRETTY_FUNCTION ": ioctl error: %s",
868                           strerror(errno));
869 #endif
870
871                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
872                 WSASetLastError (errnum);
873                 
874                 return(SOCKET_ERROR);
875         }
876         
877         return(0);
878 }
879
880 int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds,
881                  fd_set *exceptfds, struct timeval *timeout)
882 {
883         int ret;
884         
885         if(startup_count==0) {
886                 WSASetLastError(WSANOTINITIALISED);
887                 return(SOCKET_ERROR);
888         }
889
890         ret=select(getdtablesize(), readfds, writefds, exceptfds, timeout);
891         if(ret==-1) {
892                 gint errnum = errno;
893 #ifdef DEBUG
894                 g_message(G_GNUC_PRETTY_FUNCTION ": select error: %s",
895                           strerror(errno));
896 #endif
897                 errnum = errno_to_WSA (errnum, G_GNUC_PRETTY_FUNCTION);
898                 WSASetLastError (errnum);
899                 
900                 return(SOCKET_ERROR);
901         }
902
903         return(ret);
904 }
905
906 void _wapi_FD_CLR(guint32 handle, fd_set *set)
907 {
908         struct _WapiHandlePrivate_socket *socket_private_handle;
909         gboolean ok;
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;
918         }
919
920         FD_CLR(socket_private_handle->fd, set);
921 }
922
923 int _wapi_FD_ISSET(guint32 handle, fd_set *set)
924 {
925         struct _WapiHandlePrivate_socket *socket_private_handle;
926         gboolean ok;
927         
928         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
929                                 NULL, (gpointer *)&socket_private_handle);
930         if(ok==FALSE) {
931                 g_warning (G_GNUC_PRETTY_FUNCTION
932                            ": error looking up socket handle 0x%x", handle);
933                 WSASetLastError(WSAENOTSOCK);
934                 return(0);
935         }
936
937         return(FD_ISSET(socket_private_handle->fd, set));
938 }
939
940 void _wapi_FD_SET(guint32 handle, fd_set *set)
941 {
942         struct _WapiHandlePrivate_socket *socket_private_handle;
943         gboolean ok;
944         
945         ok=_wapi_lookup_handle (GUINT_TO_POINTER (handle), WAPI_HANDLE_SOCKET,
946                                 NULL, (gpointer *)&socket_private_handle);
947         if(ok==FALSE) {
948                 g_warning (G_GNUC_PRETTY_FUNCTION
949                            ": error looking up socket handle 0x%x", handle);
950                 WSASetLastError(WSAENOTSOCK);
951                 return;
952         }
953
954         FD_SET(socket_private_handle->fd, set);
955 }
956