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