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