Removed mono_debugger_create_notification_function() from here.
[mono.git] / mono / metadata / socket-io.c
1 /*
2  * socket-io.c: Socket IO internal calls
3  *
4  * Authors:
5  *      Dick Porter (dick@ximian.com)
6  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  * Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
10  */
11
12 #include <config.h>
13
14 #include <glib.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <errno.h>
19
20 #include <mono/metadata/object.h>
21 #include <mono/io-layer/io-layer.h>
22 #include <mono/metadata/socket-io.h>
23 #include <mono/metadata/exception.h>
24 #include <mono/metadata/assembly.h>
25 #include <mono/metadata/appdomain.h>
26 #include <mono/metadata/threads.h>
27 #include <mono/metadata/threads-types.h>
28 #include <mono/utils/mono-poll.h>
29 /* FIXME change this code to not mess so much with the internals */
30 #include <mono/metadata/class-internals.h>
31 #include <mono/metadata/threadpool-internals.h>
32 #include <mono/metadata/domain-internals.h>
33
34 #include <sys/time.h> 
35 #ifdef HAVE_SYS_IOCTL_H
36 #include <sys/ioctl.h>
37 #endif
38 #ifdef HAVE_NET_IF_H
39 #include <net/if.h>
40 #endif
41
42 #ifdef HAVE_NETDB_H
43 #include <netdb.h>
44 #endif
45 #ifdef HAVE_SYS_FILIO_H
46 #include <sys/filio.h>     /* defines FIONBIO and FIONREAD */
47 #endif
48 #ifdef HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h>    /* defines SIOCATMARK */
50 #endif
51 #ifdef HAVE_SYS_UN_H
52 #include <sys/un.h>
53 #endif
54
55 #include "mono/io-layer/socket-wrappers.h"
56
57 #ifdef PLATFORM_WIN32
58 /* This is a kludge to make this file build under cygwin:
59  * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
60  * prototypes for some but not all required functions (notably
61  * inet_ntop() is missing), but the libws2_32 library is missing the
62  * actual implementations of these functions.
63  */
64 #undef AF_INET6
65 #endif
66
67 #undef DEBUG
68
69 static gint32 convert_family(MonoAddressFamily mono_family)
70 {
71         gint32 family=-1;
72         
73         switch(mono_family) {
74         case AddressFamily_Unknown:
75         case AddressFamily_ImpLink:
76         case AddressFamily_Pup:
77         case AddressFamily_Chaos:
78         case AddressFamily_Iso:
79         case AddressFamily_Ecma:
80         case AddressFamily_DataKit:
81         case AddressFamily_Ccitt:
82         case AddressFamily_DataLink:
83         case AddressFamily_Lat:
84         case AddressFamily_HyperChannel:
85         case AddressFamily_NetBios:
86         case AddressFamily_VoiceView:
87         case AddressFamily_FireFox:
88         case AddressFamily_Banyan:
89         case AddressFamily_Atm:
90         case AddressFamily_Cluster:
91         case AddressFamily_Ieee12844:
92         case AddressFamily_NetworkDesigners:
93                 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
94                 break;
95                 
96         case AddressFamily_Unspecified:
97                 family=AF_UNSPEC;
98                 break;
99                 
100         case AddressFamily_Unix:
101                 family=AF_UNIX;
102                 break;
103                 
104         case AddressFamily_InterNetwork:
105                 family=AF_INET;
106                 break;
107                 
108         case AddressFamily_Ipx:
109 #ifdef AF_IPX
110                 family=AF_IPX;
111 #endif
112                 break;
113                 
114         case AddressFamily_Sna:
115                 family=AF_SNA;
116                 break;
117                 
118         case AddressFamily_DecNet:
119                 family=AF_DECnet;
120                 break;
121                 
122         case AddressFamily_AppleTalk:
123                 family=AF_APPLETALK;
124                 break;
125                 
126         case AddressFamily_InterNetworkV6:
127 #ifdef AF_INET6
128                 family=AF_INET6;
129 #endif
130                 break;
131         case AddressFamily_Irda:
132 #ifdef AF_IRDA  
133                 family=AF_IRDA;
134 #endif
135                 break;
136         default:
137                 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
138         }
139
140         return(family);
141 }
142
143 static MonoAddressFamily convert_to_mono_family(guint16 af_family)
144 {
145         MonoAddressFamily family=AddressFamily_Unknown;
146         
147         switch(af_family) {
148         case AF_UNSPEC:
149                 family=AddressFamily_Unspecified;
150                 break;
151                 
152         case AF_UNIX:
153                 family=AddressFamily_Unix;
154                 break;
155                 
156         case AF_INET:
157                 family=AddressFamily_InterNetwork;
158                 break;
159                 
160 #ifdef AF_IPX
161         case AF_IPX:
162                 family=AddressFamily_Ipx;
163                 break;
164 #endif
165                 
166         case AF_SNA:
167                 family=AddressFamily_Sna;
168                 break;
169                 
170         case AF_DECnet:
171                 family=AddressFamily_DecNet;
172                 break;
173                 
174         case AF_APPLETALK:
175                 family=AddressFamily_AppleTalk;
176                 break;
177                 
178 #ifdef AF_INET6
179         case AF_INET6:
180                 family=AddressFamily_InterNetworkV6;
181                 break;
182 #endif
183                 
184 #ifdef AF_IRDA  
185         case AF_IRDA:
186                 family=AddressFamily_Irda;
187                 break;
188 #endif
189         default:
190                 g_warning("unknown address family 0x%x", af_family);
191         }
192
193         return(family);
194 }
195
196 static gint32 convert_type(MonoSocketType mono_type)
197 {
198         gint32 type=-1;
199         
200         switch(mono_type) {
201         case SocketType_Stream:
202                 type=SOCK_STREAM;
203                 break;
204
205         case SocketType_Dgram:
206                 type=SOCK_DGRAM;
207                 break;
208                 
209         case SocketType_Raw:
210                 type=SOCK_RAW;
211                 break;
212
213         case SocketType_Rdm:
214                 type=SOCK_RDM;
215                 break;
216
217         case SocketType_Seqpacket:
218                 type=SOCK_SEQPACKET;
219                 break;
220
221         case SocketType_Unknown:
222                 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
223                 break;
224
225         default:
226                 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
227         }
228
229         return(type);
230 }
231
232 static gint32 convert_proto(MonoProtocolType mono_proto)
233 {
234         gint32 proto=-1;
235         
236         switch(mono_proto) {
237         case ProtocolType_IP:
238         case ProtocolType_IPv6:
239         case ProtocolType_Icmp:
240         case ProtocolType_Igmp:
241         case ProtocolType_Ggp:
242         case ProtocolType_Tcp:
243         case ProtocolType_Pup:
244         case ProtocolType_Udp:
245         case ProtocolType_Idp:
246                 /* These protocols are known (on my system at least) */
247                 proto=mono_proto;
248                 break;
249                 
250         case ProtocolType_ND:
251         case ProtocolType_Raw:
252         case ProtocolType_Ipx:
253         case ProtocolType_Spx:
254         case ProtocolType_SpxII:
255         case ProtocolType_Unknown:
256                 /* These protocols arent */
257                 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
258                 break;
259                 
260         default:
261                 break;
262         }
263
264         return(proto);
265 }
266
267 /* Convert MonoSocketFlags */
268 static gint32 convert_socketflags (gint32 sflags)
269 {
270         gint32 flags = 0;
271
272         if (!sflags)
273                 /* SocketFlags.None */
274                 return 0;
275
276         if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek | 
277                         SocketFlags_DontRoute | SocketFlags_Partial))
278                 /* Contains invalid flag values */
279                 return -1;
280
281         if (sflags & SocketFlags_OutOfBand)
282                 flags |= MSG_OOB;
283         if (sflags & SocketFlags_Peek)
284                 flags |= MSG_PEEK;
285         if (sflags & SocketFlags_DontRoute)
286                 flags |= MSG_DONTROUTE;
287         if (sflags & SocketFlags_Partial)
288 #ifdef MSG_MORE
289                 flags |= MSG_MORE;
290 #else
291                 return -1;      
292 #endif
293         if (sflags & SocketFlags_MaxIOVectorLength)
294                 /* FIXME: Don't know what to do for MaxIOVectorLength query */
295                 return -1;      
296         
297         return (flags ? flags : -1);
298 }
299
300 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
301                                              MonoSocketOptionName mono_name,
302                                              int *system_level,
303                                              int *system_name)
304 {
305         switch (mono_level) {
306         case SocketOptionLevel_Socket:
307                 *system_level = SOL_SOCKET;
308                 
309                 switch(mono_name) {
310                 case SocketOptionName_DontLinger:
311                         /* This is SO_LINGER, because the setsockopt
312                          * internal call maps DontLinger to SO_LINGER
313                          * with l_onoff=0
314                          */
315                         *system_name = SO_LINGER;
316                         break;
317                 case SocketOptionName_Debug:
318                         *system_name = SO_DEBUG;
319                         break;
320 #ifdef SO_ACCEPTCONN
321                 case SocketOptionName_AcceptConnection:
322                         *system_name = SO_ACCEPTCONN;
323                         break;
324 #endif
325                 case SocketOptionName_ReuseAddress:
326                         *system_name = SO_REUSEADDR;
327                         break;
328                 case SocketOptionName_KeepAlive:
329                         *system_name = SO_KEEPALIVE;
330                         break;
331                 case SocketOptionName_DontRoute:
332                         *system_name = SO_DONTROUTE;
333                         break;
334                 case SocketOptionName_Broadcast:
335                         *system_name = SO_BROADCAST;
336                         break;
337                 case SocketOptionName_Linger:
338                         *system_name = SO_LINGER;
339                         break;
340                 case SocketOptionName_OutOfBandInline:
341                         *system_name = SO_OOBINLINE;
342                         break;
343                 case SocketOptionName_SendBuffer:
344                         *system_name = SO_SNDBUF;
345                         break;
346                 case SocketOptionName_ReceiveBuffer:
347                         *system_name = SO_RCVBUF;
348                         break;
349                 case SocketOptionName_SendLowWater:
350                         *system_name = SO_SNDLOWAT;
351                         break;
352                 case SocketOptionName_ReceiveLowWater:
353                         *system_name = SO_RCVLOWAT;
354                         break;
355                 case SocketOptionName_SendTimeout:
356                         *system_name = SO_SNDTIMEO;
357                         break;
358                 case SocketOptionName_ReceiveTimeout:
359                         *system_name = SO_RCVTIMEO;
360                         break;
361                 case SocketOptionName_Error:
362                         *system_name = SO_ERROR;
363                         break;
364                 case SocketOptionName_Type:
365                         *system_name = SO_TYPE;
366                         break;
367 #ifdef SO_PEERCRED
368                 case SocketOptionName_PeerCred:
369                         *system_name = SO_PEERCRED;
370                         break;
371 #endif
372                 case SocketOptionName_ExclusiveAddressUse:
373                 case SocketOptionName_UseLoopback:
374                 case SocketOptionName_MaxConnections:
375                         /* Can't figure out how to map these, so fall
376                          * through
377                          */
378                 default:
379                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
380                         return(-1);
381                 }
382                 break;
383                 
384         case SocketOptionLevel_IP:
385 #ifdef HAVE_SOL_IP
386                 *system_level = SOL_IP;
387 #else
388                 if (1) {
389                         static int cached = 0;
390                         static int proto;
391                         
392                         if (!cached) {
393                                 struct protoent *pent;
394                                 
395                                 pent = getprotobyname ("IP");
396                                 proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
397                                 cached = 1;
398                         }
399                         
400                         *system_level = proto;
401                 }
402 #endif /* HAVE_SOL_IP */
403                 
404                 switch(mono_name) {
405                 case SocketOptionName_IPOptions:
406                         *system_name = IP_OPTIONS;
407                         break;
408 #ifdef IP_HDRINCL
409                 case SocketOptionName_HeaderIncluded:
410                         *system_name = IP_HDRINCL;
411                         break;
412 #endif
413 #ifdef IP_TOS
414                 case SocketOptionName_TypeOfService:
415                         *system_name = IP_TOS;
416                         break;
417 #endif
418 #ifdef IP_TTL
419                 case SocketOptionName_IpTimeToLive:
420                         *system_name = IP_TTL;
421                         break;
422 #endif
423                 case SocketOptionName_MulticastInterface:
424                         *system_name = IP_MULTICAST_IF;
425                         break;
426                 case SocketOptionName_MulticastTimeToLive:
427                         *system_name = IP_MULTICAST_TTL;
428                         break;
429                 case SocketOptionName_MulticastLoopback:
430                         *system_name = IP_MULTICAST_LOOP;
431                         break;
432                 case SocketOptionName_AddMembership:
433                         *system_name = IP_ADD_MEMBERSHIP;
434                         break;
435                 case SocketOptionName_DropMembership:
436                         *system_name = IP_DROP_MEMBERSHIP;
437                         break;
438 #ifdef HAVE_IP_PKTINFO
439                 case SocketOptionName_PacketInformation:
440                         *system_name = IP_PKTINFO;
441                         break;
442 #endif /* HAVE_IP_PKTINFO */
443                 case SocketOptionName_DontFragment:
444                 case SocketOptionName_AddSourceMembership:
445                 case SocketOptionName_DropSourceMembership:
446                 case SocketOptionName_BlockSource:
447                 case SocketOptionName_UnblockSource:
448                         /* Can't figure out how to map these, so fall
449                          * through
450                          */
451                 default:
452                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
453                         return(-1);
454                 }
455                 break;
456
457 #ifdef AF_INET6
458         case SocketOptionLevel_IPv6:
459 #ifdef HAVE_SOL_IPV6
460                 *system_level = SOL_IPV6;
461 #else
462                 if (1) {
463                         static int cached = 0;
464                         static int proto;
465
466                         if (!cached) {
467                                 struct protoent *pent;
468
469                                 pent = getprotobyname ("IPV6");
470                                 proto = pent ? pent->p_proto : 41 /* 41 a good default value?? */;
471                                 cached = 1;
472                         }
473
474                         *system_level = proto;
475                 }
476 #endif /* HAVE_SOL_IPV6 */
477
478                 switch(mono_name) {
479                 case SocketOptionName_IpTimeToLive:
480                         *system_name = IPV6_UNICAST_HOPS;
481                         break;
482                 case SocketOptionName_MulticastInterface:
483                         *system_name = IPV6_MULTICAST_IF;
484                         break;
485                 case SocketOptionName_MulticastTimeToLive:
486                         *system_name = IPV6_MULTICAST_HOPS;
487                         break;
488                 case SocketOptionName_MulticastLoopback:
489                         *system_name = IPV6_MULTICAST_LOOP;
490                         break;
491                 case SocketOptionName_AddMembership:
492                         *system_name = IPV6_JOIN_GROUP;
493                         break;
494                 case SocketOptionName_DropMembership:
495                         *system_name = IPV6_LEAVE_GROUP;
496                         break;
497                 case SocketOptionName_PacketInformation:
498 #ifdef HAVE_IPV6_PKTINFO
499                         *system_name = IPV6_PKTINFO;
500 #endif
501                         break;
502                 case SocketOptionName_HeaderIncluded:
503                 case SocketOptionName_IPOptions:
504                 case SocketOptionName_TypeOfService:
505                 case SocketOptionName_DontFragment:
506                 case SocketOptionName_AddSourceMembership:
507                 case SocketOptionName_DropSourceMembership:
508                 case SocketOptionName_BlockSource:
509                 case SocketOptionName_UnblockSource:
510                         /* Can't figure out how to map these, so fall
511                          * through
512                          */
513                 default:
514                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
515                         return(-1);
516                 }
517
518                 break;  /* SocketOptionLevel_IPv6 */
519 #endif
520                 
521         case SocketOptionLevel_Tcp:
522 #ifdef HAVE_SOL_TCP
523                 *system_level = SOL_TCP;
524 #else
525                 if (1) {
526                         static int cached = 0;
527                         static int proto;
528                         
529                         if (!cached) {
530                                 struct protoent *pent;
531                                 
532                                 pent = getprotobyname ("TCP");
533                                 proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
534                                 cached = 1;
535                         }
536                         
537                         *system_level = proto;
538                 }
539 #endif /* HAVE_SOL_TCP */
540                 
541                 switch(mono_name) {
542                 case SocketOptionName_NoDelay:
543                         *system_name = TCP_NODELAY;
544                         break;
545 #if 0
546                         /* The documentation is talking complete
547                          * bollocks here: rfc-1222 is titled
548                          * 'Advancing the NSFNET Routing Architecture'
549                          * and doesn't mention either of the words
550                          * "expedite" or "urgent".
551                          */
552                 case SocketOptionName_BsdUrgent:
553                 case SocketOptionName_Expedited:
554 #endif
555                 default:
556                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
557                         return(-1);
558                 }
559                 break;
560                 
561         case SocketOptionLevel_Udp:
562                 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
563
564                 switch(mono_name) {
565                 case SocketOptionName_NoChecksum:
566                 case SocketOptionName_ChecksumCoverage:
567                 default:
568                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
569                         return(-1);
570                 }
571                 return(-1);
572                 break;
573
574         default:
575                 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
576                 return(-1);
577         }
578
579         return(0);
580 }
581
582 #define STASH_SYS_ASS(this) \
583         if(system_assembly == NULL) { \
584                 system_assembly=mono_image_loaded ("System"); \
585                 if (!system_assembly) { \
586                         MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);     \
587                         if (!sa) g_assert_not_reached ();       \
588                         else {system_assembly = mono_assembly_get_image (sa);}  \
589                 }       \
590         }
591
592 static MonoImage *system_assembly=NULL;
593
594
595 #ifdef AF_INET6
596 static gint32 get_family_hint(void)
597 {
598         MonoClass *socket_class;
599         MonoClassField *ipv6_field, *ipv4_field;
600         gint32 ipv6_enabled = -1, ipv4_enabled = -1;
601         MonoVTable *vtable;
602
603         socket_class = mono_class_from_name (system_assembly,
604                                              "System.Net.Sockets", "Socket");
605         ipv4_field = mono_class_get_field_from_name (socket_class,
606                                                      "ipv4Supported");
607         ipv6_field = mono_class_get_field_from_name (socket_class,
608                                                      "ipv6Supported");
609         vtable = mono_class_vtable (mono_domain_get (), socket_class);
610
611         mono_field_static_get_value(vtable, ipv4_field, &ipv4_enabled);
612         mono_field_static_get_value(vtable, ipv6_field, &ipv6_enabled);
613
614         if(ipv4_enabled == 1 && ipv6_enabled == 1) {
615                 return(PF_UNSPEC);
616         } else if(ipv4_enabled == 1) {
617                 return(PF_INET);
618         } else {
619                 return(PF_INET6);
620         }
621 }
622 #endif
623
624 gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto, gint32 *error)
625 {
626         SOCKET sock;
627         gint32 sock_family;
628         gint32 sock_proto;
629         gint32 sock_type;
630         
631         MONO_ARCH_SAVE_REGS;
632
633         STASH_SYS_ASS(this);
634         
635         *error = 0;
636         
637         sock_family=convert_family(family);
638         if(sock_family==-1) {
639                 *error = WSAEAFNOSUPPORT;
640                 return(NULL);
641         }
642
643         sock_proto=convert_proto(proto);
644         if(sock_proto==-1) {
645                 *error = WSAEPROTONOSUPPORT;
646                 return(NULL);
647         }
648         
649         sock_type=convert_type(type);
650         if(sock_type==-1) {
651                 *error = WSAESOCKTNOSUPPORT;
652                 return(NULL);
653         }
654         
655         sock = _wapi_socket (sock_family, sock_type, sock_proto,
656                              NULL, 0, WSA_FLAG_OVERLAPPED);
657
658         if(sock==INVALID_SOCKET) {
659                 *error = WSAGetLastError ();
660                 return(NULL);
661         }
662
663         if (sock_family == AF_INET && sock_type == SOCK_DGRAM) {
664                 return (GUINT_TO_POINTER (sock));
665         }
666
667 #ifdef AF_INET6
668         if (sock_family == AF_INET6 && sock_type == SOCK_DGRAM) {
669                 return (GUINT_TO_POINTER (sock));
670         }
671 #endif
672
673 #ifndef PLATFORM_WIN32
674         /* .net seems to set this by default for SOCK_STREAM,
675          * not for SOCK_DGRAM (see bug #36322)
676          *
677          * It seems winsock has a rather different idea of what
678          * SO_REUSEADDR means.  If it's set, then a new socket can be
679          * bound over an existing listening socket.  There's a new
680          * windows-specific option called SO_EXCLUSIVEADDRUSE but
681          * using that means the socket MUST be closed properly, or a
682          * denial of service can occur.  Luckily for us, winsock
683          * behaves as though any other system would when SO_REUSEADDR
684          * is true, so we don't need to do anything else here.  See
685          * bug 53992.
686          */
687         {
688         int ret, true = 1;
689         
690         ret = _wapi_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (true));
691         if(ret==SOCKET_ERROR) {
692                 *error = WSAGetLastError ();
693                 
694                 closesocket(sock);
695                 return(NULL);
696         }
697         }
698 #endif
699         
700         return(GUINT_TO_POINTER (sock));
701 }
702
703 /* FIXME: the SOCKET parameter (here and in other functions in this
704  * file) is really an IntPtr which needs to be converted to a guint32.
705  */
706 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock,
707                                                         gint32 *error)
708 {
709         MONO_ARCH_SAVE_REGS;
710
711 #ifdef DEBUG
712         g_message (G_GNUC_PRETTY_FUNCTION ": closing 0x%x", sock);
713 #endif
714
715         *error = 0;
716
717         /* Clear any pending work item from this socket if the underlying
718          * polling system does not notify when the socket is closed */
719         mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock));
720         closesocket(sock);
721 }
722
723 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
724 {
725         MONO_ARCH_SAVE_REGS;
726
727 #ifdef DEBUG
728         g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
729 #endif
730
731         return(WSAGetLastError());
732 }
733
734 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock,
735                                                               gint32 *error)
736 {
737         int ret;
738         gulong amount;
739         
740         MONO_ARCH_SAVE_REGS;
741
742         *error = 0;
743         
744         ret=ioctlsocket(sock, FIONREAD, &amount);
745         if(ret==SOCKET_ERROR) {
746                 *error = WSAGetLastError ();
747                 return(0);
748         }
749         
750         return(amount);
751 }
752
753 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
754                                                            gboolean block,
755                                                            gint32 *error)
756 {
757         int ret;
758         
759         MONO_ARCH_SAVE_REGS;
760
761         *error = 0;
762
763         /*
764          * block == TRUE/FALSE means we will block/not block.
765          * But the ioctlsocket call takes TRUE/FALSE for non-block/block
766          */
767         block = !block;
768         
769         ret = ioctlsocket (sock, FIONBIO, (gulong *) &block);
770         if(ret==SOCKET_ERROR) {
771                 *error = WSAGetLastError ();
772         }
773 }
774
775 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock,
776                                                              gint32 *error)
777 {
778         SOCKET newsock;
779         
780         MONO_ARCH_SAVE_REGS;
781
782         *error = 0;
783         
784         newsock = _wapi_accept (sock, NULL, 0);
785         if(newsock==INVALID_SOCKET) {
786                 *error = WSAGetLastError ();
787                 return(NULL);
788         }
789         
790         return(GUINT_TO_POINTER (newsock));
791 }
792
793 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
794                                                          guint32 backlog,
795                                                          gint32 *error)
796 {
797         int ret;
798         
799         MONO_ARCH_SAVE_REGS;
800
801         *error = 0;
802         
803         ret = _wapi_listen (sock, backlog);
804         if(ret==SOCKET_ERROR) {
805                 *error = WSAGetLastError ();
806         }
807 }
808
809 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
810                                                int sa_size, gint32 *error)
811 {
812         MonoDomain *domain = mono_domain_get ();
813         MonoObject *sockaddr_obj;
814         MonoClass *sockaddr_class;
815         MonoClassField *field;
816         MonoArray *data;
817         MonoAddressFamily family;
818
819         /* Build a System.Net.SocketAddress object instance */
820         sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
821         sockaddr_obj=mono_object_new(domain, sockaddr_class);
822         
823         /* Locate the SocketAddress data buffer in the object */
824         field=mono_class_get_field_from_name(sockaddr_class, "data");
825
826         /* Make sure there is space for the family and size bytes */
827 #ifdef HAVE_SYS_UN_H
828         if (saddr->sa_family == AF_UNIX) {
829                 /* sa_len includes the entire sockaddr size, so we don't need the
830                  * N bytes (sizeof (unsigned short)) of the family. */
831                 data=mono_array_new(domain, mono_get_byte_class (), sa_size);
832         } else
833 #endif
834         {
835                 /* May be the +2 here is too conservative, as sa_len returns
836                  * the length of the entire sockaddr_in/in6, including
837                  * sizeof (unsigned short) of the family */
838                 data=mono_array_new(domain, mono_get_byte_class (), sa_size+2);
839         }
840
841         /* The data buffer is laid out as follows:
842          * bytes 0 and 1 are the address family
843          * bytes 2 and 3 are the port info
844          * the rest is the address info
845          */
846                 
847         family=convert_to_mono_family(saddr->sa_family);
848         if(family==AddressFamily_Unknown) {
849                 *error = WSAEAFNOSUPPORT;
850                 return(NULL);
851         }
852
853         mono_array_set(data, guint8, 0, family & 0x0FF);
854         mono_array_set(data, guint8, 1, (family >> 8) & 0x0FF);
855         
856         if(saddr->sa_family==AF_INET) {
857                 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
858                 guint16 port=ntohs(sa_in->sin_port);
859                 guint32 address=ntohl(sa_in->sin_addr.s_addr);
860                 
861                 if(sa_size<8) {
862                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
863                 }
864                 
865                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
866                 mono_array_set(data, guint8, 3, (port) & 0xff);
867                 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
868                 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
869                 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
870                 mono_array_set(data, guint8, 7, (address) & 0xff);
871         
872                 mono_field_set_value (sockaddr_obj, field, data);
873
874                 return(sockaddr_obj);
875 #ifdef AF_INET6
876         } else if (saddr->sa_family == AF_INET6) {
877                 struct sockaddr_in6 *sa_in=(struct sockaddr_in6 *)saddr;
878                 int i;
879
880                 guint16 port=ntohs(sa_in->sin6_port);
881
882                 if(sa_size<28) {
883                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
884                 }
885
886                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
887                 mono_array_set(data, guint8, 3, (port) & 0xff);
888
889                 for(i=0; i<16; i++) {
890                         mono_array_set(data, guint8, 8+i,
891                                        sa_in->sin6_addr.s6_addr[i]);
892                 }
893
894                 mono_array_set(data, guint8, 24, sa_in->sin6_scope_id & 0xff);
895                 mono_array_set(data, guint8, 25,
896                                (sa_in->sin6_scope_id >> 8) & 0xff);
897                 mono_array_set(data, guint8, 26,
898                                (sa_in->sin6_scope_id >> 16) & 0xff);
899                 mono_array_set(data, guint8, 27,
900                                (sa_in->sin6_scope_id >> 24) & 0xff);
901
902                 mono_field_set_value (sockaddr_obj, field, data);
903
904                 return(sockaddr_obj);
905 #endif
906 #ifdef HAVE_SYS_UN_H
907         } else if (saddr->sa_family == AF_UNIX) {
908                 int i;
909
910                 for (i = 0; i < sa_size; i++) {
911                         mono_array_set (data, guint8, i+2, saddr->sa_data[i]);
912                 }
913                 
914                 mono_field_set_value (sockaddr_obj, field, data);
915
916                 return sockaddr_obj;
917 #endif
918         } else {
919                 *error = WSAEAFNOSUPPORT;
920                 return(NULL);
921         }
922 }
923
924 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 *error)
925 {
926         gchar sa[32];   /* sockaddr in not big enough for sockaddr_in6 */
927         socklen_t salen;
928         int ret;
929         
930         MONO_ARCH_SAVE_REGS;
931
932         *error = 0;
933         
934         salen=sizeof(sa);
935         ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
936         
937         if(ret==SOCKET_ERROR) {
938                 *error = WSAGetLastError ();
939                 return(NULL);
940         }
941         
942 #ifdef DEBUG
943         g_message(G_GNUC_PRETTY_FUNCTION ": bound to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port));
944 #endif
945
946         return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
947                                            error));
948 }
949
950 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 *error)
951 {
952         gchar sa[32];   /* sockaddr in not big enough for sockaddr_in6 */
953         socklen_t salen;
954         int ret;
955         
956         MONO_ARCH_SAVE_REGS;
957
958         *error = 0;
959         
960         salen=sizeof(sa);
961         ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
962         
963         if(ret==SOCKET_ERROR) {
964                 *error = WSAGetLastError ();
965                 return(NULL);
966         }
967         
968 #ifdef DEBUG
969         g_message(G_GNUC_PRETTY_FUNCTION ": connected to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port));
970 #endif
971
972         return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
973                                            error));
974 }
975
976 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
977                                                     socklen_t *sa_size,
978                                                     gint32 *error)
979 {
980         MonoClassField *field;
981         MonoArray *data;
982         gint32 family;
983         int len;
984
985         /* Dig the SocketAddress data buffer out of the object */
986         field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
987         data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
988
989         /* The data buffer is laid out as follows:
990          * byte 0 is the address family low byte
991          * byte 1 is the address family high byte
992          * INET:
993          *      bytes 2 and 3 are the port info
994          *      the rest is the address info
995          * UNIX:
996          *      the rest is the file name
997          */
998         len = mono_array_length (data);
999         if (len < 2) {
1000                 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1001         }
1002         
1003         family = convert_family (mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8));
1004         if (family == AF_INET) {
1005                 struct sockaddr_in *sa;
1006                 guint16 port;
1007                 guint32 address;
1008                 
1009                 if (len < 8) {
1010                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1011                 }
1012
1013                 sa = g_new0 (struct sockaddr_in, 1);
1014                 port = (mono_array_get (data, guint8, 2) << 8) +
1015                         mono_array_get (data, guint8, 3);
1016                 address = (mono_array_get (data, guint8, 4) << 24) +
1017                         (mono_array_get (data, guint8, 5) << 16 ) +
1018                         (mono_array_get (data, guint8, 6) << 8) +
1019                         mono_array_get (data, guint8, 7);
1020
1021                 sa->sin_family = family;
1022                 sa->sin_addr.s_addr = htonl (address);
1023                 sa->sin_port = htons (port);
1024
1025                 *sa_size = sizeof(struct sockaddr_in);
1026                 return((struct sockaddr *)sa);
1027
1028 #ifdef AF_INET6
1029         } else if (family == AF_INET6) {
1030                 struct sockaddr_in6 *sa;
1031                 int i;
1032                 guint16 port;
1033                 guint32 scopeid;
1034                 
1035                 if (len < 28) {
1036                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1037                 }
1038
1039                 sa = g_new0 (struct sockaddr_in6, 1);
1040                 port = mono_array_get (data, guint8, 3) +
1041                         (mono_array_get (data, guint8, 2) << 8);
1042                 scopeid = mono_array_get (data, guint8, 24) + 
1043                         (mono_array_get (data, guint8, 25) << 8) + 
1044                         (mono_array_get (data, guint8, 26) << 16) + 
1045                         (mono_array_get (data, guint8, 27) << 24);
1046
1047                 sa->sin6_family = family;
1048                 sa->sin6_port = htons (port);
1049                 sa->sin6_scope_id = scopeid;
1050
1051                 for(i=0; i<16; i++) {
1052                         sa->sin6_addr.s6_addr[i] = mono_array_get (data, guint8, 8+i);
1053                 }
1054
1055                 *sa_size = sizeof(struct sockaddr_in6);
1056                 return((struct sockaddr *)sa);
1057 #endif
1058 #ifdef HAVE_SYS_UN_H
1059         } else if (family == AF_UNIX) {
1060                 struct sockaddr_un *sock_un;
1061                 int i;
1062
1063                 /* Need a byte for the '\0' terminator/prefix, and the first
1064                  * two bytes hold the SocketAddress family
1065                  */
1066                 if (len - 2 >= MONO_SIZEOF_SUNPATH) {
1067                         mono_raise_exception (mono_get_exception_index_out_of_range ());
1068                 }
1069                 
1070                 sock_un = g_new0 (struct sockaddr_un, 1);
1071
1072                 sock_un->sun_family = family;
1073                 for (i = 0; i < len - 2; i++) {
1074                         sock_un->sun_path [i] = mono_array_get (data, guint8,
1075                                                                 i + 2);
1076                 }
1077                 
1078                 *sa_size = len;
1079
1080                 return (struct sockaddr *)sock_un;
1081 #endif
1082         } else {
1083                 *error = WSAEAFNOSUPPORT;
1084                 return(0);
1085         }
1086 }
1087
1088 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1089 {
1090         struct sockaddr *sa;
1091         socklen_t sa_size;
1092         int ret;
1093         
1094         MONO_ARCH_SAVE_REGS;
1095
1096         *error = 0;
1097         
1098         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1099         if (*error != 0) {
1100                 return;
1101         }
1102
1103 #ifdef DEBUG
1104         g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port));
1105 #endif
1106
1107         ret = _wapi_bind (sock, sa, sa_size);
1108         if(ret==SOCKET_ERROR) {
1109                 *error = WSAGetLastError ();
1110         }
1111
1112         g_free(sa);
1113 }
1114
1115 enum {
1116         SelectModeRead,
1117         SelectModeWrite,
1118         SelectModeError
1119 };
1120
1121 MonoBoolean
1122 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1123                                                    gint timeout, gint32 *error)
1124 {
1125         MonoThread *thread = NULL;
1126         mono_pollfd *pfds;
1127         int ret;
1128         time_t start;
1129         
1130
1131         MONO_ARCH_SAVE_REGS;
1132         
1133         pfds = g_new0 (mono_pollfd, 1);
1134         pfds[0].fd = GPOINTER_TO_INT (sock);
1135         pfds[0].events = (mode == SelectModeRead) ? MONO_POLLIN :
1136                 (mode == SelectModeWrite) ? MONO_POLLOUT :
1137                 (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL);
1138
1139         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1140         start = time (NULL);
1141         do {
1142                 *error = 0;
1143                 
1144                 ret = mono_poll (pfds, 1, timeout);
1145                 if (timeout > 0 && ret < 0) {
1146                         int err = errno;
1147                         int sec = time (NULL) - start;
1148                         
1149                         timeout -= sec * 1000;
1150                         if (timeout < 0) {
1151                                 timeout = 0;
1152                         }
1153                         
1154                         errno = err;
1155                 }
1156                 
1157                 if (ret == -1 && errno == EINTR) {
1158                         int leave = 0;
1159
1160                         if (thread == NULL) {
1161                                 thread = mono_thread_current ();
1162                         }
1163                         
1164                         mono_monitor_enter (thread->synch_lock);
1165                         leave = ((thread->state & ThreadState_AbortRequested) != 0 ||
1166                                  (thread->state & ThreadState_StopRequested) != 0);
1167                         mono_monitor_exit (thread->synch_lock);
1168                         
1169                         if (leave != 0) {
1170                                 g_free (pfds);
1171                                 return(FALSE);
1172                         } else {
1173                                 /* Suspend requested? */
1174                                 mono_thread_interruption_checkpoint ();
1175                         }
1176                         errno = EINTR;
1177                 }
1178         } while (ret == -1 && errno == EINTR);
1179
1180         if (ret == -1) {
1181 #ifdef PLATFORM_WIN32
1182                 *error = WSAGetLastError ();
1183 #else
1184                 *error = errno_to_WSA (errno, __func__);
1185 #endif
1186                 g_free (pfds);
1187                 return(FALSE);
1188         }
1189         
1190         g_free (pfds);
1191
1192         if (ret == 0) {
1193                 return(FALSE);
1194         } else {
1195                 return (TRUE);
1196         }
1197 }
1198
1199 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1200 {
1201         struct sockaddr *sa;
1202         socklen_t sa_size;
1203         int ret;
1204         
1205         MONO_ARCH_SAVE_REGS;
1206
1207         *error = 0;
1208         
1209         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1210         if (*error != 0) {
1211                 return;
1212         }
1213         
1214 #ifdef DEBUG
1215         g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port));
1216 #endif
1217
1218         ret = _wapi_connect (sock, sa, sa_size);
1219         if(ret==SOCKET_ERROR) {
1220                 *error = WSAGetLastError ();
1221         }
1222
1223         g_free(sa);
1224 }
1225
1226 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1227 {
1228         int ret;
1229         guchar *buf;
1230         gint32 alen;
1231         int recvflags=0;
1232         
1233         MONO_ARCH_SAVE_REGS;
1234
1235         *error = 0;
1236         
1237         alen = mono_array_length (buffer);
1238         if (offset > alen - count) {
1239                 return(0);
1240         }
1241         
1242         buf=mono_array_addr(buffer, guchar, offset);
1243         
1244         recvflags = convert_socketflags (flags);
1245         if (recvflags == -1) {
1246                 *error = WSAEOPNOTSUPP;
1247                 return (0);
1248         }
1249                 
1250         ret = _wapi_recv (sock, buf, count, recvflags);
1251         if(ret==SOCKET_ERROR) {
1252                 *error = WSAGetLastError ();
1253                 return(0);
1254         }
1255
1256         return(ret);
1257 }
1258
1259 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
1260 {
1261         int ret;
1262         guchar *buf;
1263         gint32 alen;
1264         int recvflags=0;
1265         struct sockaddr *sa;
1266         socklen_t sa_size;
1267         
1268         MONO_ARCH_SAVE_REGS;
1269
1270         *error = 0;
1271         
1272         alen = mono_array_length (buffer);
1273         if (offset > alen - count) {
1274                 return(0);
1275         }
1276
1277         sa=create_sockaddr_from_object(*sockaddr, &sa_size, error);
1278         if (*error != 0) {
1279                 return(0);
1280         }
1281         
1282         buf=mono_array_addr(buffer, guchar, offset);
1283         
1284         recvflags = convert_socketflags (flags);
1285         if (recvflags == -1) {
1286                 *error = WSAEOPNOTSUPP;
1287                 return (0);
1288         }
1289
1290         ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1291         if(ret==SOCKET_ERROR) {
1292                 g_free(sa);
1293                 *error = WSAGetLastError ();
1294                 return(0);
1295         }
1296
1297         /* If we didn't get a socket size, then we're probably a
1298          * connected connection-oriented socket and the stack hasn't
1299          * returned the remote address. All we can do is return null.
1300          */
1301         if ( sa_size != 0 )
1302                 *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
1303         else
1304                 *sockaddr=NULL;
1305
1306         g_free(sa);
1307         
1308         return(ret);
1309 }
1310
1311 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1312 {
1313         int ret;
1314         guchar *buf;
1315         gint32 alen;
1316         int sendflags=0;
1317         
1318         MONO_ARCH_SAVE_REGS;
1319
1320         *error = 0;
1321         
1322         alen = mono_array_length (buffer);
1323         if (offset > alen - count) {
1324                 return(0);
1325         }
1326
1327 #ifdef DEBUG
1328         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1329 #endif
1330         
1331         buf=mono_array_addr(buffer, guchar, offset);
1332
1333 #ifdef DEBUG
1334         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1335 #endif
1336
1337         sendflags = convert_socketflags (flags);
1338         if (sendflags == -1) {
1339                 *error = WSAEOPNOTSUPP;
1340                 return (0);
1341         }
1342
1343         ret = _wapi_send (sock, buf, count, sendflags);
1344         if(ret==SOCKET_ERROR) {
1345                 *error = WSAGetLastError ();
1346                 return(0);
1347         }
1348
1349         return(ret);
1350 }
1351
1352 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
1353 {
1354         int ret;
1355         guchar *buf;
1356         gint32 alen;
1357         int sendflags=0;
1358         struct sockaddr *sa;
1359         socklen_t sa_size;
1360         
1361         MONO_ARCH_SAVE_REGS;
1362
1363         *error = 0;
1364         
1365         alen = mono_array_length (buffer);
1366         if (offset > alen - count) {
1367                 return(0);
1368         }
1369
1370         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1371         if(*error != 0) {
1372                 return(0);
1373         }
1374         
1375 #ifdef DEBUG
1376         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1377 #endif
1378         
1379         buf=mono_array_addr(buffer, guchar, offset);
1380
1381 #ifdef DEBUG
1382         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1383 #endif
1384
1385         sendflags = convert_socketflags (flags);
1386         if (sendflags == -1) {
1387                 *error = WSAEOPNOTSUPP;
1388                 return (0);
1389         }
1390
1391         ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1392         if(ret==SOCKET_ERROR) {
1393                 *error = WSAGetLastError ();
1394         }
1395
1396         g_free(sa);
1397         
1398         return(ret);
1399 }
1400
1401 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
1402 {
1403         SOCKET sock;
1404         MonoClassField *field;
1405         
1406         field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
1407         sock=*(SOCKET *)(((char *)sockobj)+field->offset);
1408
1409         return(sock);
1410 }
1411
1412 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1413 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error)
1414 {
1415         MonoThread *thread = NULL;
1416         MonoObject *obj;
1417         mono_pollfd *pfds;
1418         int nfds, idx;
1419         int ret;
1420         int i, count;
1421         int mode;
1422         MonoClass *sock_arr_class;
1423         MonoArray *socks;
1424         time_t start;
1425         
1426         MONO_ARCH_SAVE_REGS;
1427
1428         /* *sockets -> READ, null, WRITE, null, ERROR, null */
1429         count = mono_array_length (*sockets);
1430         nfds = count - 3; /* NULL separators */
1431         pfds = g_new0 (mono_pollfd, nfds);
1432         mode = idx = 0;
1433         for (i = 0; i < count; i++) {
1434                 obj = mono_array_get (*sockets, MonoObject *, i);
1435                 if (obj == NULL) {
1436                         mode++;
1437                         continue;
1438                 }
1439
1440                 if (idx >= nfds) {
1441                         /* The socket array was bogus */
1442                         g_free (pfds);
1443                         *error = WSAEFAULT;
1444                         return;
1445                 }
1446
1447                 pfds [idx].fd = GPOINTER_TO_INT (Socket_to_SOCKET (obj));
1448                 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1449                 idx++;
1450         }
1451
1452         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1453         start = time (NULL);
1454         do {
1455                 *error = 0;
1456                 ret = mono_poll (pfds, nfds, timeout);
1457                 if (timeout > 0 && ret < 0) {
1458                         int err = errno;
1459                         int sec = time (NULL) - start;
1460
1461                         timeout -= sec * 1000;
1462                         if (timeout < 0)
1463                                 timeout = 0;
1464                         errno = err;
1465                 }
1466
1467                 if (ret == -1 && errno == EINTR) {
1468                         int leave = 0;
1469                         if (thread == NULL)
1470                                 thread = mono_thread_current ();
1471
1472                         mono_monitor_enter (thread->synch_lock);
1473                         leave = ((thread->state & ThreadState_AbortRequested) != 0 || 
1474                                  (thread->state & ThreadState_StopRequested) != 0);
1475                         mono_monitor_exit (thread->synch_lock);
1476                         if (leave != 0) {
1477                                 g_free (pfds);
1478                                 *sockets = NULL;
1479                                 return;
1480                         } else {
1481                                 /* Suspend requested? */
1482                                 mono_thread_interruption_checkpoint ();
1483                         }
1484                         errno = EINTR;
1485                 }
1486         } while (ret == -1 && errno == EINTR);
1487         
1488         if (ret == -1) {
1489 #ifdef PLATFORM_WIN32
1490                 *error = WSAGetLastError ();
1491 #else
1492                 *error = errno_to_WSA (errno, __func__);
1493 #endif
1494                 g_free (pfds);
1495                 return;
1496         }
1497
1498         if (ret == 0) {
1499                 g_free (pfds);
1500                 *sockets = NULL;
1501                 return;
1502         }
1503
1504         sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
1505         ret += 3; /* space for the NULL delimiters */
1506         socks = mono_array_new_full (mono_domain_get (), sock_arr_class, (guint32*)&ret, NULL);
1507         ret -= 3;
1508         mode = idx = 0;
1509         for (i = 0; i < count && ret > 0; i++) {
1510                 mono_pollfd *pfd;
1511
1512                 obj = mono_array_get (*sockets, MonoObject *, i);
1513                 if (obj == NULL) {
1514                         mode++;
1515                         idx++;
1516                         continue;
1517                 }
1518
1519                 pfd = &pfds [i - mode];
1520                 if (pfd->revents == 0)
1521                         continue;
1522
1523                 ret--;
1524                 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1525                         mono_array_setref (socks, idx++, obj);
1526                 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1527                         mono_array_setref (socks, idx++, obj);
1528                 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1529                         mono_array_setref (socks, idx++, obj);
1530                 }
1531         }
1532
1533         *sockets = socks;
1534         g_free (pfds);
1535 }
1536
1537 static MonoObject* int_to_object (MonoDomain *domain, int val)
1538 {
1539         return mono_value_box (domain, mono_get_int32_class (), &val);
1540 }
1541
1542
1543 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error)
1544 {
1545         int system_level;
1546         int system_name;
1547         int ret;
1548         int val;
1549         socklen_t valsize=sizeof(val);
1550         struct linger linger;
1551         socklen_t lingersize=sizeof(linger);
1552         int time_ms = 0;
1553         socklen_t time_ms_size = sizeof (time_ms);
1554 #ifdef SO_PEERCRED
1555         struct ucred cred;
1556         socklen_t credsize = sizeof(cred);
1557 #endif
1558         MonoDomain *domain=mono_domain_get();
1559         MonoObject *obj;
1560         MonoClass *obj_class;
1561         MonoClassField *field;
1562         
1563         MONO_ARCH_SAVE_REGS;
1564
1565         *error = 0;
1566         
1567         ret=convert_sockopt_level_and_name(level, name, &system_level,
1568                                            &system_name);
1569         if(ret==-1) {
1570                 *error = WSAENOPROTOOPT;
1571                 return;
1572         }
1573         
1574         /* No need to deal with MulticastOption names here, because
1575          * you cant getsockopt AddMembership or DropMembership (the
1576          * int getsockopt will error, causing an exception)
1577          */
1578         switch(name) {
1579         case SocketOptionName_Linger:
1580         case SocketOptionName_DontLinger:
1581                 ret = _wapi_getsockopt(sock, system_level, system_name, &linger,
1582                                &lingersize);
1583                 break;
1584                 
1585         case SocketOptionName_SendTimeout:
1586         case SocketOptionName_ReceiveTimeout:
1587                 ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
1588                 break;
1589
1590 #ifdef SO_PEERCRED
1591         case SocketOptionName_PeerCred: 
1592                 ret = _wapi_getsockopt (sock, system_level, system_name, &cred,
1593                                         &credsize);
1594                 break;
1595 #endif
1596
1597         default:
1598                 ret = _wapi_getsockopt (sock, system_level, system_name, &val,
1599                                &valsize);
1600         }
1601         
1602         if(ret==SOCKET_ERROR) {
1603                 *error = WSAGetLastError ();
1604                 return;
1605         }
1606         
1607         switch(name) {
1608         case SocketOptionName_Linger:
1609                 /* build a System.Net.Sockets.LingerOption */
1610                 obj_class=mono_class_from_name(system_assembly,
1611                                                "System.Net.Sockets",
1612                                                "LingerOption");
1613                 obj=mono_object_new(domain, obj_class);
1614                 
1615                 /* Locate and set the fields "bool enabled" and "int
1616                  * seconds"
1617                  */
1618                 field=mono_class_get_field_from_name(obj_class, "enabled");
1619                 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1620
1621                 field=mono_class_get_field_from_name(obj_class, "seconds");
1622                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1623                 
1624                 break;
1625                 
1626         case SocketOptionName_DontLinger:
1627                 /* construct a bool int in val - true if linger is off */
1628                 obj = int_to_object (domain, !linger.l_onoff);
1629                 break;
1630                 
1631         case SocketOptionName_SendTimeout:
1632         case SocketOptionName_ReceiveTimeout:
1633                 obj = int_to_object (domain, time_ms);
1634                 break;
1635
1636 #ifdef SO_PEERCRED
1637         case SocketOptionName_PeerCred: 
1638         {
1639                 /* build a Mono.Posix.PeerCred+PeerCredData if
1640                  * possible
1641                  */
1642                 static MonoImage *mono_posix_image = NULL;
1643                 MonoPeerCredData *cred_data;
1644                 
1645                 if (mono_posix_image == NULL) {
1646                         mono_posix_image=mono_image_loaded ("Mono.Posix");
1647                         if (!mono_posix_image) {
1648                                 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
1649                                 if (!sa) {
1650                                         *error = WSAENOPROTOOPT;
1651                                         return;
1652                                 } else {
1653                                         mono_posix_image = mono_assembly_get_image (sa);
1654                                 }
1655                         }
1656                 }
1657                 
1658                 obj_class = mono_class_from_name(mono_posix_image,
1659                                                  "Mono.Posix",
1660                                                  "PeerCredData");
1661                 obj = mono_object_new(domain, obj_class);
1662                 cred_data = (MonoPeerCredData *)obj;
1663                 cred_data->pid = cred.pid;
1664                 cred_data->uid = cred.uid;
1665                 cred_data->gid = cred.gid;
1666                 break;
1667         }
1668 #endif
1669
1670         default:
1671                 obj = int_to_object (domain, val);
1672         }
1673
1674         *obj_val=obj;
1675 }
1676
1677 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error)
1678 {
1679         int system_level;
1680         int system_name;
1681         int ret;
1682         guchar *buf;
1683         socklen_t valsize;
1684         
1685         MONO_ARCH_SAVE_REGS;
1686
1687         *error = 0;
1688         
1689         ret=convert_sockopt_level_and_name(level, name, &system_level,
1690                                            &system_name);
1691         if(ret==-1) {
1692                 *error = WSAENOPROTOOPT;
1693                 return;
1694         }
1695
1696         valsize=mono_array_length(*byte_val);
1697         buf=mono_array_addr(*byte_val, guchar, 0);
1698         
1699         ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
1700         if(ret==SOCKET_ERROR) {
1701                 *error = WSAGetLastError ();
1702         }
1703 }
1704
1705 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1706 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1707 {
1708         struct in_addr inaddr;
1709         MonoClassField *field;
1710         
1711         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
1712
1713         /* No idea why .net uses a 64bit type to hold a 32bit value...
1714          *
1715          * Internal value of IPAddess is in Network Order, there is no need
1716          * to call htonl here.
1717          */
1718         inaddr.s_addr=(guint32)*(guint64 *)(((char *)ipaddr)+field->offset);
1719         
1720         return(inaddr);
1721 }
1722 #endif
1723
1724 #ifdef AF_INET6
1725 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
1726 {
1727         struct in6_addr in6addr;
1728         MonoClassField *field;
1729         MonoArray *data;
1730         int i;
1731
1732         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
1733         data=*(MonoArray **)(((char *)ipaddr) + field->offset);
1734
1735 /* Solaris has only the 8 bit version. */
1736 #ifndef s6_addr16
1737         for(i=0; i<8; i++) {
1738                 guint16 s = mono_array_get (data, guint16, i);
1739                 in6addr.s6_addr[2 * i] = (s >> 8) & 0xff;
1740                 in6addr.s6_addr[2 * i + 1] = s & 0xff;
1741         }
1742 #else
1743         for(i=0; i<8; i++)
1744                 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
1745 #endif
1746         return(in6addr);
1747 }
1748 #endif /* AF_INET6 */
1749
1750 void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val, gint32 *error)
1751 {
1752         int system_level;
1753         int system_name;
1754         int ret;
1755 #ifdef AF_INET6
1756         int sol_ip;
1757         int sol_ipv6;
1758
1759         *error = 0;
1760         
1761 #ifdef HAVE_SOL_IPV6
1762         sol_ipv6 = SOL_IPV6;
1763 #else
1764         {
1765                 struct protoent *pent;
1766                 pent = getprotobyname ("ipv6");
1767                 sol_ipv6 = (pent != NULL) ? pent->p_proto : 41;
1768         }
1769 #endif
1770
1771 #ifdef HAVE_SOL_IP
1772         sol_ip = SOL_IP;
1773 #else
1774         {
1775                 struct protoent *pent;
1776                 pent = getprotobyname ("ip");
1777                 sol_ip = (pent != NULL) ? pent->p_proto : 0;
1778         }
1779 #endif
1780 #endif /* AF_INET6 */
1781
1782         MONO_ARCH_SAVE_REGS;
1783
1784         ret=convert_sockopt_level_and_name(level, name, &system_level,
1785                                            &system_name);
1786         if(ret==-1) {
1787                 *error = WSAENOPROTOOPT;
1788                 return;
1789         }
1790
1791         /* Only one of obj_val, byte_val or int_val has data */
1792         if(obj_val!=NULL) {
1793                 MonoClassField *field;
1794                 struct linger linger;
1795                 int valsize;
1796                 
1797                 switch(name) {
1798                 case SocketOptionName_DontLinger:
1799                         linger.l_onoff=0;
1800                         linger.l_linger=0;
1801                         valsize=sizeof(linger);
1802                         ret = _wapi_setsockopt (sock, system_level,
1803                                                 system_name, &linger, valsize);
1804                         break;
1805                         
1806                 case SocketOptionName_Linger:
1807                         /* Dig out "bool enabled" and "int seconds"
1808                          * fields
1809                          */
1810                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1811                         linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1812                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1813                         linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1814                         
1815                         valsize=sizeof(linger);
1816                         ret = _wapi_setsockopt (sock, system_level,
1817                                                 system_name, &linger, valsize);
1818                         break;
1819                 case SocketOptionName_AddMembership:
1820                 case SocketOptionName_DropMembership:
1821 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1822                 {
1823                         MonoObject *address = NULL;
1824
1825 #ifdef AF_INET6
1826                         if(system_level == sol_ipv6) {
1827                                 struct ipv6_mreq mreq6;
1828
1829                                 /*
1830                                  *      Get group address
1831                                  */
1832                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1833                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1834                                 
1835                                 if(address) {
1836                                         mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
1837                                 }
1838
1839                                 field=mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
1840                                 mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
1841
1842                                 ret = _wapi_setsockopt (sock, system_level,
1843                                                         system_name, &mreq6,
1844                                                         sizeof (mreq6));
1845                         } else if(system_level == sol_ip)
1846 #endif /* AF_INET6 */
1847                         {
1848 #ifdef HAVE_STRUCT_IP_MREQN
1849                                 struct ip_mreqn mreq = {{0}};
1850 #else
1851                                 struct ip_mreq mreq = {{0}};
1852 #endif /* HAVE_STRUCT_IP_MREQN */
1853                         
1854                                 /* pain! MulticastOption holds two IPAddress
1855                                  * members, so I have to dig the value out of
1856                                  * those :-(
1857                                  */
1858                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1859                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1860
1861                                 /* address might not be defined and if so, set the address to ADDR_ANY.
1862                                  */
1863                                 if(address) {
1864                                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
1865                                 }
1866
1867                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1868                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1869
1870 #ifdef HAVE_STRUCT_IP_MREQN
1871                                 if(address) {
1872                                         mreq.imr_address = ipaddress_to_struct_in_addr (address);
1873                                 }
1874 #else
1875                                 if(address) {
1876                                         mreq.imr_interface = ipaddress_to_struct_in_addr (address);
1877                                 }
1878 #endif /* HAVE_STRUCT_IP_MREQN */
1879                         
1880                                 ret = _wapi_setsockopt (sock, system_level,
1881                                                         system_name, &mreq,
1882                                                         sizeof (mreq));
1883                         }
1884                         break;
1885                 }
1886 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
1887                 default:
1888                         /* Cause an exception to be thrown */
1889                         *error = WSAEINVAL;
1890                         return;
1891                 }
1892         } else if (byte_val!=NULL) {
1893                 int valsize=mono_array_length(byte_val);
1894                 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1895         
1896                 ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
1897                 if(ret==SOCKET_ERROR) {
1898                         *error = WSAGetLastError ();
1899                         return;
1900                 }
1901         } else {
1902                 /* ReceiveTimeout/SendTimeout get here */
1903                 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
1904         }
1905
1906         if(ret==SOCKET_ERROR) {
1907                 *error = WSAGetLastError ();
1908         }
1909 }
1910
1911 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
1912                                                            gint32 how,
1913                                                            gint32 *error)
1914 {
1915         int ret;
1916         
1917         MONO_ARCH_SAVE_REGS;
1918
1919         *error = 0;
1920         
1921         /* Currently, the values for how (recv=0, send=1, both=2) match
1922          * the BSD API
1923          */
1924         ret = _wapi_shutdown (sock, how);
1925         if(ret==SOCKET_ERROR) {
1926                 *error = WSAGetLastError ();
1927         }
1928 }
1929
1930 gint
1931 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
1932                                               MonoArray *input,
1933                                               MonoArray *output, gint32 *error)
1934 {
1935         glong output_bytes = 0;
1936         gchar *i_buffer, *o_buffer;
1937         gint i_len, o_len;
1938         gint ret;
1939
1940         MONO_ARCH_SAVE_REGS;
1941
1942         *error = 0;
1943         
1944         if (code == FIONBIO) {
1945                 /* Invalid command. Must use Socket.Blocking */
1946                 return -1;
1947         }
1948
1949         if (input == NULL) {
1950                 i_buffer = NULL;
1951                 i_len = 0;
1952         } else {
1953                 i_buffer = mono_array_addr (input, gchar, 0);
1954                 i_len = mono_array_length (input);
1955         }
1956
1957         if (output == NULL) {
1958                 o_buffer = NULL;
1959                 o_len = 0;
1960         } else {
1961                 o_buffer = mono_array_addr (output, gchar, 0);
1962                 o_len = mono_array_length (output);
1963         }
1964
1965         ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
1966         if (ret == SOCKET_ERROR) {
1967                 *error = WSAGetLastError ();
1968                 return(-1);
1969         }
1970
1971         return (gint) output_bytes;
1972 }
1973
1974 #ifdef HAVE_SIOCGIFCONF
1975 static gboolean
1976 is_loopback (int family, void *ad)
1977 {
1978         char *ptr = (char *) ad;
1979
1980         if (family == AF_INET) {
1981                 return (ptr [0] == 127);
1982         }
1983 #ifdef AF_INET6
1984         else {
1985                 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
1986         }
1987 #endif
1988         return FALSE;
1989 }
1990
1991 static void *
1992 get_local_ips (int family, int *nips)
1993 {
1994         int addr_size, offset, fd, i, count;
1995         int max_ifaces = 50; /* 50 interfaces should be enough... */
1996         struct ifconf ifc;
1997         struct ifreq *ifr;
1998         struct ifreq iflags;
1999         char *result, *tmp_ptr;
2000         gboolean ignore_loopback = FALSE;
2001
2002         *nips = 0;
2003         if (family == AF_INET) {
2004                 addr_size = sizeof (struct in_addr);
2005                 offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
2006 #ifdef AF_INET6
2007         } else if (family == AF_INET6) {
2008                 addr_size = sizeof (struct in6_addr);
2009                 offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
2010 #endif
2011         } else {
2012                 return NULL;
2013         }
2014
2015         fd = socket (family, SOCK_STREAM, 0);
2016
2017         ifc.ifc_len = max_ifaces * sizeof (struct ifreq);
2018         ifc.ifc_buf = g_malloc (ifc.ifc_len);
2019         if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
2020                 close (fd);
2021                 g_free (ifc.ifc_buf);
2022                 return NULL;
2023         }
2024
2025         count = ifc.ifc_len / sizeof (struct ifreq);
2026         *nips = count;
2027         if (count == 0) {
2028                 g_free (ifc.ifc_buf);
2029                 close (fd);
2030                 return NULL;
2031         }
2032
2033         for (i = 0, ifr = ifc.ifc_req; i < *nips; i++, ifr++) {
2034                 strcpy (iflags.ifr_name, ifr->ifr_name);
2035                 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
2036                         continue;
2037                 }
2038
2039                 if ((iflags.ifr_flags & IFF_UP) == 0) {
2040                         ifr->ifr_name [0] = '\0';
2041                         continue;
2042                 }
2043
2044                 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
2045                         ignore_loopback = TRUE;
2046                 }
2047         }
2048
2049         close (fd);
2050         result = g_malloc (addr_size * count);
2051         tmp_ptr = result;
2052         for (i = 0, ifr = ifc.ifc_req; i < count; i++, ifr++) {
2053                 if (ifr->ifr_name [0] == '\0') {
2054                         (*nips)--;
2055                         continue;
2056                 }
2057
2058                 if (ignore_loopback && is_loopback (family, ((char *) &ifr->ifr_addr) + offset)) {
2059                         (*nips)--;
2060                         continue;
2061                 }
2062
2063                 memcpy (tmp_ptr, ((char *) &ifr->ifr_addr) + offset, addr_size);
2064                 tmp_ptr += addr_size;
2065         }
2066
2067         g_free (ifc.ifc_buf);
2068         return result;
2069 }
2070 #else
2071 static void *
2072 get_local_ips (int family, int *nips)
2073 {
2074         *nips = 0;
2075         return NULL;
2076 }
2077
2078 #endif /* HAVE_SIOCGIFCONF */
2079
2080 #ifndef AF_INET6
2081 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
2082                                        MonoArray **h_aliases,
2083                                        MonoArray **h_addr_list,
2084                                        gboolean add_local_ips)
2085 {
2086         MonoDomain *domain = mono_domain_get ();
2087         int i;
2088         struct in_addr *local_in = NULL;
2089         int nlocal_in = 0;
2090
2091         if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
2092                 return(FALSE);
2093         }
2094
2095         *h_name=mono_string_new(domain, he->h_name);
2096
2097         i=0;
2098         while(he->h_aliases[i]!=NULL) {
2099                 i++;
2100         }
2101         
2102         *h_aliases=mono_array_new(domain, mono_get_string_class (), i);
2103         i=0;
2104         while(he->h_aliases[i]!=NULL) {
2105                 MonoString *alias;
2106                 
2107                 alias=mono_string_new(domain, he->h_aliases[i]);
2108                 mono_array_setref (*h_aliases, i, alias);
2109                 i++;
2110         }
2111
2112         if (add_local_ips) {
2113                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2114                 if (nlocal_in) {
2115                         *h_addr_list = mono_array_new(domain, mono_get_string_class (), nlocal_in);
2116                         for (i = 0; i < nlocal_in; i++) {
2117                                 MonoString *addr_string;
2118                                 char addr [16], *ptr;
2119                                 
2120                                 ptr = (char *) &local_in [i];
2121                                 g_snprintf(addr, 16, "%u.%u.%u.%u",
2122                                          (unsigned char) ptr [0],
2123                                          (unsigned char) ptr [1],
2124                                          (unsigned char) ptr [2],
2125                                          (unsigned char) ptr [3]);
2126                                 
2127                                 addr_string = mono_string_new (domain, addr);
2128                                 mono_array_setref (*h_addr_list, i, addr_string);
2129                                 i++;
2130                         }
2131
2132                         g_free (local_in);
2133                 }
2134         }
2135         
2136         if (nlocal_in == 0) {
2137                 i = 0;
2138                 while (he->h_addr_list[i]!=NULL) {
2139                         i++;
2140                 }
2141
2142                 *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
2143                 i=0;
2144                 while(he->h_addr_list[i]!=NULL) {
2145                         MonoString *addr_string;
2146                         char addr[16];
2147                         
2148                         g_snprintf(addr, 16, "%u.%u.%u.%u",
2149                                  (unsigned char)he->h_addr_list[i][0],
2150                                  (unsigned char)he->h_addr_list[i][1],
2151                                  (unsigned char)he->h_addr_list[i][2],
2152                                  (unsigned char)he->h_addr_list[i][3]);
2153                         
2154                         addr_string=mono_string_new(domain, addr);
2155                         mono_array_setref (*h_addr_list, i, addr_string);
2156                         i++;
2157                 }
2158         }
2159
2160         return(TRUE);
2161 }
2162
2163 static gboolean ipaddr_to_IPHostEntry(const char *addr, MonoString **h_name,
2164                                       MonoArray **h_aliases,
2165                                       MonoArray **h_addr_list)
2166 {
2167         MonoDomain *domain = mono_domain_get ();
2168
2169         *h_name=mono_string_new(domain, addr);
2170         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2171         *h_addr_list=mono_array_new(domain, mono_get_string_class (), 1);
2172         mono_array_setref (*h_addr_list, 0, *h_name);
2173
2174         return(TRUE);
2175 }
2176 #endif
2177
2178 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2179 static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name,
2180                                 MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
2181 {
2182         MonoDomain *domain = mono_domain_get ();
2183         int i, host_count, host_index, family_hint;
2184         struct in_addr *local_in = NULL;
2185         int nlocal_in = 0;
2186         struct in6_addr *local_in6 = NULL;
2187         int nlocal_in6 = 0;
2188         gboolean from_local = FALSE;
2189
2190         family_hint = get_family_hint ();
2191
2192         if(he1 == NULL && he2 == NULL) {
2193                 return(FALSE);
2194         }
2195
2196         /*
2197          * Check if address length and family are correct
2198          */
2199         if (he1 != NULL && (he1->h_length!=4 || he1->h_addrtype!=AF_INET)) {
2200                 return(FALSE);
2201         }
2202
2203         if (he2 != NULL && (he2->h_length!=16 || he2->h_addrtype!=AF_INET6)) {
2204                 return(FALSE);
2205         }
2206
2207         /*
2208          * Get the aliases and host name from he1 or he2 whichever is
2209          * not null, if he1 is not null then take aliases from he1
2210          */
2211         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2212                             family_hint == PF_INET)) {
2213                 *h_name=mono_string_new (domain, he1->h_name);
2214
2215                 i=0;
2216                 while(he1->h_aliases[i]!=NULL) {
2217                         i++;
2218                 }
2219
2220                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2221                                            i);
2222                 i=0;
2223                 while(he1->h_aliases[i]!=NULL) {
2224                         MonoString *alias;
2225
2226                         alias=mono_string_new (domain, he1->h_aliases[i]);
2227                         mono_array_setref (*h_aliases, i, alias);
2228                         i++;
2229                 }
2230         } else if (he2 != NULL && (family_hint == PF_UNSPEC ||
2231                                    family_hint == PF_INET6)) {
2232                 *h_name=mono_string_new (domain, he2->h_name);
2233
2234                 i=0;
2235                 while(he2->h_aliases [i] != NULL) {
2236                         i++;
2237                 }
2238
2239                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2240                                            i);
2241                 i=0;
2242                 while(he2->h_aliases[i]!=NULL) {
2243                         MonoString *alias;
2244
2245                         alias=mono_string_new (domain, he2->h_aliases[i]);
2246                         mono_array_setref (*h_aliases, i, alias);
2247                         i++;
2248                 }
2249         } else {
2250                 return(FALSE);
2251         }
2252
2253         /*
2254          * Count the number of addresses in he1 + he2
2255          */
2256         host_count = 0;
2257         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2258                             family_hint == PF_INET)) {
2259                 i=0;
2260                 while(he1->h_addr_list[i]!=NULL) {
2261                         i++;
2262                         host_count++;
2263                 }
2264         }
2265
2266         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2267                             family_hint == PF_INET6)) {
2268                 i=0;
2269                 while(he2->h_addr_list[i]!=NULL) {
2270                         i++;
2271                         host_count++;
2272                 }
2273         }
2274
2275         /*
2276          * Fills the array
2277          */
2278         host_index = 0;
2279         if (add_local_ips) {
2280                 if (family_hint == PF_UNSPEC || family_hint == PF_INET)
2281                         local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2282
2283                 if (family_hint == PF_UNSPEC || family_hint == PF_INET6)
2284                         local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2285
2286                 if (nlocal_in || nlocal_in6) {
2287                         from_local = TRUE;
2288                         *h_addr_list = mono_array_new (domain, mono_get_string_class (),
2289                                                              nlocal_in + nlocal_in6);
2290
2291                         if (nlocal_in6) {
2292                                 int n;
2293                                 for (n = 0; n < nlocal_in6; n++) {
2294                                         MonoString *addr_string;
2295                                         const char *ret;
2296                                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2297
2298                                         ret = inet_ntop (AF_INET6, &local_in6 [n], addr, sizeof(addr));
2299
2300                                         if (ret != NULL) {
2301                                                 addr_string = mono_string_new (domain, addr);
2302                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2303                                                 host_index++;
2304                                         }
2305                                 }
2306                         }
2307
2308                         if (nlocal_in) {
2309                                 int n;
2310                                 for (n = 0; n < nlocal_in; n++) {
2311                                         MonoString *addr_string;
2312                                         const char *ret;
2313                                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2314
2315                                         ret = inet_ntop (AF_INET, &local_in [n], addr, sizeof(addr));
2316
2317                                         if (ret != NULL) {
2318                                                 addr_string = mono_string_new (domain, addr);
2319                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2320                                                 host_index++;
2321                                         }
2322                                 }
2323                         }
2324                         g_free (local_in);
2325                         g_free (local_in6);
2326                         return TRUE;
2327                 }
2328
2329                 g_free (local_in);
2330                 g_free (local_in6);
2331         }
2332
2333         *h_addr_list=mono_array_new (domain, mono_get_string_class (), host_count);
2334
2335         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2336                             family_hint == PF_INET6)) {
2337                 i = 0;
2338                 while(he2->h_addr_list[i] != NULL) {
2339                         MonoString *addr_string;
2340                         const char *ret;
2341                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2342
2343                         ret = inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
2344                                          sizeof(addr));
2345
2346                         if (ret != NULL) {
2347                                 addr_string = mono_string_new (domain, addr);
2348                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2349                                 i++;
2350                                 host_index++;
2351                         }
2352                 }
2353         }
2354
2355         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2356                             family_hint == PF_INET)) {
2357                 i=0;
2358                 while(he1->h_addr_list[i] != NULL) {
2359                         MonoString *addr_string;
2360                         const char *ret;
2361                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2362
2363                         ret = inet_ntop (AF_INET, he1->h_addr_list[i], addr,
2364                                          sizeof(addr));
2365
2366                         if (ret != NULL) {
2367                                 addr_string=mono_string_new (domain, addr);
2368                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2369                                 i++;
2370                                 host_index++;
2371                         }
2372                 }
2373         }
2374
2375         return(TRUE);
2376 }
2377 #endif
2378
2379 #if defined(AF_INET6)
2380 static gboolean 
2381 addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
2382                                                 MonoArray **h_aliases,
2383                                                 MonoArray **h_addr_list,
2384                                                 gboolean add_local_ips)
2385 {
2386         gint32 count, i;
2387         struct addrinfo *ai = NULL;
2388         struct in_addr *local_in = NULL;
2389         int nlocal_in = 0;
2390         struct in6_addr *local_in6 = NULL;
2391         int nlocal_in6 = 0;
2392         int addr_index;
2393
2394         MonoDomain *domain = mono_domain_get ();
2395
2396         addr_index = 0;
2397         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2398         if (add_local_ips) {
2399                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2400                 local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2401                 if (nlocal_in || nlocal_in6) {
2402                         *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
2403                         if (nlocal_in) {
2404                                 MonoString *addr_string;
2405                                 char addr [16];
2406                                 int i;
2407
2408                                 for (i = 0; i < nlocal_in; i++) {
2409                                         inet_ntop (AF_INET, &local_in [i], addr, sizeof (addr));
2410                                         addr_string = mono_string_new (domain, addr);
2411                                         mono_array_setref (*h_addr_list, addr_index, addr_string);
2412                                         addr_index++;
2413                                 }
2414                         }
2415
2416                         if (nlocal_in6) {
2417                                 MonoString *addr_string;
2418                                 const char *ret;
2419                                 char addr [48];
2420                                 int i;
2421
2422                                 for (i = 0; i < nlocal_in6; i++) {
2423                                         ret = inet_ntop (AF_INET6, &local_in6 [i], addr, sizeof (addr));
2424                                         if (ret != NULL) {
2425                                                 addr_string = mono_string_new (domain, addr);
2426                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2427                                                 addr_index++;
2428                                         }
2429                                 }
2430                         }
2431
2432                         g_free (local_in);
2433                         g_free (local_in6);
2434                         if (info) {
2435                                 freeaddrinfo (info);
2436                         }
2437                         return TRUE;
2438                 }
2439
2440                 g_free (local_in);
2441                 g_free (local_in6);
2442         }
2443
2444         for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
2445                 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2446                         continue;
2447
2448                 count++;
2449         }
2450
2451         *h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
2452
2453         for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
2454                 MonoString *addr_string;
2455                 const char *ret;
2456                 char buffer [48]; /* Max. size for IPv6 */
2457
2458                 if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
2459                         continue;
2460                 }
2461
2462                 if(ai->ai_family == PF_INET) {
2463                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, 16);
2464                 } else {
2465                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, 48);
2466                 }
2467
2468                 if(ret) {
2469                         addr_string=mono_string_new(domain, buffer);
2470                 } else {
2471                         addr_string=mono_string_new(domain, "");
2472                 }
2473
2474                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2475
2476                 if(!i && ai->ai_canonname != NULL) {
2477                         *h_name=mono_string_new(domain, ai->ai_canonname);
2478                 }
2479
2480                 addr_index++;
2481         }
2482
2483         if(info) {
2484                 freeaddrinfo(info);
2485         }
2486
2487         return(TRUE);
2488 }
2489 #endif
2490
2491 #ifdef AF_INET6
2492 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2493 {
2494         gboolean add_local_ips = FALSE;
2495 #ifdef HAVE_SIOCGIFCONF
2496         gchar this_hostname [256];
2497 #endif
2498 #if !defined(HAVE_GETHOSTBYNAME2_R)
2499         struct addrinfo *info = NULL, hints;
2500         char *hostname;
2501         
2502         MONO_ARCH_SAVE_REGS;
2503         
2504         hostname=mono_string_to_utf8 (host);
2505 #ifdef HAVE_SIOCGIFCONF
2506         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2507                 if (!strcmp (hostname, this_hostname))
2508                         add_local_ips = TRUE;
2509         }
2510 #endif
2511
2512         memset(&hints, 0, sizeof(hints));
2513         hints.ai_family = get_family_hint ();
2514         hints.ai_socktype = SOCK_STREAM;
2515         hints.ai_flags = AI_CANONNAME;
2516
2517         if (getaddrinfo(hostname, NULL, &hints, &info) == -1) {
2518                 return(FALSE);
2519         }
2520         
2521         g_free(hostname);
2522
2523         return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips));
2524 #else
2525         struct hostent he1,*hp1, he2, *hp2;
2526         int buffer_size1, buffer_size2;
2527         char *buffer1, *buffer2;
2528         int herr;
2529         gboolean return_value;
2530         char *hostname;
2531         
2532         MONO_ARCH_SAVE_REGS;
2533         
2534         hostname=mono_string_to_utf8 (host);
2535
2536 #ifdef HAVE_SIOCGIFCONF
2537         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2538                 if (!strcmp (hostname, this_hostname))
2539                         add_local_ips = TRUE;
2540         }
2541 #endif
2542
2543         buffer_size1 = 512;
2544         buffer_size2 = 512;
2545         buffer1 = g_malloc0(buffer_size1);
2546         buffer2 = g_malloc0(buffer_size2);
2547
2548         while (gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1,
2549                                 &hp1, &herr) == ERANGE) {
2550                 buffer_size1 *= 2;
2551                 buffer1 = g_realloc(buffer1, buffer_size1);
2552         }
2553
2554         if (hp1 == NULL)
2555         {
2556                 while (gethostbyname2_r(hostname, AF_INET6, &he2, buffer2,
2557                                         buffer_size2, &hp2, &herr) == ERANGE) {
2558                         buffer_size2 *= 2;
2559                         buffer2 = g_realloc(buffer2, buffer_size2);
2560                 }
2561         }
2562         else
2563                 hp2 = NULL;
2564
2565         return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
2566                                                h_addr_list, add_local_ips);
2567
2568         g_free(buffer1);
2569         g_free(buffer2);
2570         g_free(hostname);
2571
2572         return(return_value);
2573 #endif /* HAVE_GETHOSTBYNAME2_R */
2574 }
2575 #else /* AF_INET6 */
2576 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2577 {
2578         struct hostent *he;
2579         char *hostname;
2580         gboolean add_local_ips = FALSE;
2581 #ifdef HAVE_SIOCGIFCONF
2582         gchar this_hostname [256];
2583 #endif
2584         
2585         MONO_ARCH_SAVE_REGS;
2586
2587         hostname=mono_string_to_utf8(host);
2588 #ifdef HAVE_SIOCGIFCONF
2589         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2590                 if (!strcmp (hostname, this_hostname))
2591                         add_local_ips = TRUE;
2592         }
2593 #endif
2594
2595         he = _wapi_gethostbyname (hostname);
2596         g_free(hostname);
2597
2598         if(he==NULL) {
2599                 return(FALSE);
2600         }
2601
2602         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips));
2603 }
2604 #endif /* AF_INET6 */
2605
2606 #ifndef HAVE_INET_PTON
2607 static int
2608 inet_pton (int family, const char *address, void *inaddrp)
2609 {
2610         if (family == AF_INET) {
2611 #ifdef HAVE_INET_ATON
2612                 struct in_addr inaddr;
2613                 
2614                 if (!inet_aton (address, &inaddr))
2615                         return 0;
2616                 
2617                 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
2618                 return 1;
2619 #else
2620                 /* assume the system has inet_addr(), if it doesn't
2621                    have that we're pretty much screwed... */
2622                 guint32 inaddr;
2623                 
2624                 if (!strcmp (address, "255.255.255.255")) {
2625                         /* special-case hack */
2626                         inaddr = 0xffffffff;
2627                 } else {
2628                         inaddr = inet_addr (address);
2629 #ifndef INADDR_NONE
2630 #define INADDR_NONE ((in_addr_t) -1)
2631 #endif
2632                         if (inaddr == INADDR_NONE)
2633                                 return 0;
2634                 }
2635                 
2636                 memcpy (inaddrp, &inaddr, sizeof (guint32));
2637                 return 1;
2638 #endif /* HAVE_INET_ATON */
2639         }
2640         
2641         return -1;
2642 }
2643 #endif /* !HAVE_INET_PTON */
2644
2645 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2646 {
2647         char *address;
2648         const char *version;
2649         gboolean v1;
2650         
2651 #ifdef AF_INET6
2652         struct sockaddr_in saddr;
2653         struct sockaddr_in6 saddr6;
2654         struct addrinfo *info = NULL, hints;
2655         gint32 family;
2656         char hostname[1024] = {0};
2657         int flags = 0;
2658 #else
2659         struct in_addr inaddr;
2660         struct hostent *he;
2661         gboolean ret;
2662 #endif
2663
2664         MONO_ARCH_SAVE_REGS;
2665
2666         version = mono_get_runtime_info ()->framework_version;
2667         v1 = (version[0] == '1');
2668
2669         address = mono_string_to_utf8 (addr);
2670
2671 #ifdef AF_INET6
2672         if (inet_pton (AF_INET, address, &saddr.sin_addr ) <= 0) {
2673                 /* Maybe an ipv6 address */
2674                 if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) <= 0) {
2675                         g_free (address);
2676                         return FALSE;
2677                 }
2678                 else {
2679                         family = AF_INET6;
2680                         saddr6.sin6_family = AF_INET6;
2681                 }
2682         }
2683         else {
2684                 family = AF_INET;
2685                 saddr.sin_family = AF_INET;
2686         }
2687         g_free(address);
2688
2689         if (v1) {
2690                 flags = NI_NAMEREQD;
2691         }
2692         
2693         if(family == AF_INET) {
2694                 if(getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr),
2695                                 hostname, sizeof(hostname), NULL, 0,
2696                                 flags) != 0) {
2697                         return(FALSE);
2698                 }
2699         } else if(family == AF_INET6) {
2700                 if(getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6),
2701                                 hostname, sizeof(hostname), NULL, 0,
2702                                 flags) != 0) {
2703                         return(FALSE);
2704                 }
2705         }
2706
2707         memset (&hints, 0, sizeof(hints));
2708         hints.ai_family = get_family_hint ();
2709         hints.ai_socktype = SOCK_STREAM;
2710         hints.ai_flags = AI_CANONNAME;
2711
2712         if( getaddrinfo (hostname, NULL, &hints, &info) == -1 ) {
2713                 return(FALSE);
2714         }
2715
2716         return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE));
2717 #else
2718         if (inet_pton (AF_INET, address, &inaddr) <= 0) {
2719                 g_free (address);
2720                 return(FALSE);
2721         }
2722
2723         if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) {
2724                 if (v1) {
2725                         ret = FALSE;
2726                 } else {
2727                         ret = ipaddr_to_IPHostEntry (address, h_name,
2728                                                      h_aliases, h_addr_list);
2729                 }
2730         } else {
2731                 ret = hostent_to_IPHostEntry (he, h_name, h_aliases,
2732                                               h_addr_list, FALSE);
2733         }
2734
2735         g_free (address);
2736         return(ret);
2737 #endif
2738 }
2739
2740 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
2741 {
2742         gchar hostname[256];
2743         int ret;
2744         
2745         MONO_ARCH_SAVE_REGS;
2746
2747         ret = gethostname (hostname, sizeof (hostname));
2748         if(ret==-1) {
2749                 return(FALSE);
2750         }
2751         
2752         *h_name=mono_string_new(mono_domain_get (), hostname);
2753
2754         return(TRUE);
2755 }
2756
2757 void mono_network_init(void)
2758 {
2759         WSADATA wsadata;
2760         int err;
2761         
2762         err=WSAStartup(MAKEWORD(2,0), &wsadata);
2763         if(err!=0) {
2764                 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
2765                 exit(-1);
2766         }
2767
2768 #ifdef DEBUG
2769         g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
2770         g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
2771 #endif
2772 }
2773
2774 void mono_network_cleanup(void)
2775 {
2776         WSACleanup();
2777 }
2778