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