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