cf4c006e430ef0151ffe0c7517ec92bc5114ea73
[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                         mono_monitor_enter (thread->synch_lock);
1160                         leave = ((thread->state & ThreadState_AbortRequested) != 0 ||
1161                                  (thread->state & ThreadState_StopRequested) != 0);
1162                         mono_monitor_exit (thread->synch_lock);
1163                         
1164                         if (leave != 0) {
1165                                 g_free (pfds);
1166                                 return(FALSE);
1167                         } else {
1168                                 /* Suspend requested? */
1169                                 mono_thread_interruption_checkpoint ();
1170                         }
1171                         errno = EINTR;
1172                 }
1173         } while (ret == -1 && errno == EINTR);
1174
1175         if (ret == -1) {
1176 #ifdef PLATFORM_WIN32
1177                 *error = WSAGetLastError ();
1178 #else
1179                 *error = errno_to_WSA (errno, __func__);
1180 #endif
1181                 g_free (pfds);
1182                 return(FALSE);
1183         }
1184         
1185         g_free (pfds);
1186
1187         if (ret == 0) {
1188                 return(FALSE);
1189         } else {
1190                 return (TRUE);
1191         }
1192 }
1193
1194 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1195 {
1196         struct sockaddr *sa;
1197         socklen_t sa_size;
1198         int ret;
1199         
1200         MONO_ARCH_SAVE_REGS;
1201
1202         *error = 0;
1203         
1204         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1205         if (*error != 0) {
1206                 return;
1207         }
1208         
1209 #ifdef DEBUG
1210         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));
1211 #endif
1212
1213         ret = _wapi_connect (sock, sa, sa_size);
1214         if(ret==SOCKET_ERROR) {
1215                 *error = WSAGetLastError ();
1216         }
1217
1218         g_free(sa);
1219 }
1220
1221 /* These #defines from mswsock.h from wine.  Defining them here allows
1222  * us to build this file on a mingw box that doesn't know the magic
1223  * numbers, but still run on a newer windows box that does.
1224  */
1225 #ifndef WSAID_DISCONNECTEX
1226 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1227 typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
1228 #endif
1229
1230 #ifndef WSAID_TRANSMITFILE
1231 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1232 typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
1233 #endif
1234
1235 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, MonoBoolean reuse, gint32 *error)
1236 {
1237         int ret;
1238         glong output_bytes = 0;
1239         GUID disco_guid = WSAID_DISCONNECTEX;
1240         GUID trans_guid = WSAID_TRANSMITFILE;
1241         LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
1242         LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
1243         gboolean bret;
1244         
1245         MONO_ARCH_SAVE_REGS;
1246
1247         *error = 0;
1248         
1249 #ifdef DEBUG
1250         g_message("%s: disconnecting from socket %p (reuse %d)", __func__,
1251                   sock, reuse);
1252 #endif
1253
1254         /* I _think_ the extension function pointers need to be looked
1255          * up for each socket.  FIXME: check the best way to store
1256          * pointers to functions in managed objects that still works
1257          * on 64bit platforms.
1258          */
1259         ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1260                         (void *)&disco_guid, sizeof(GUID),
1261                         (void *)&_wapi_disconnectex, sizeof(void *),
1262                         &output_bytes, NULL, NULL);
1263         if (ret != 0) {
1264                 /* make sure that WSAIoctl didn't put crap in the
1265                  * output pointer
1266                  */
1267                 _wapi_disconnectex = NULL;
1268
1269                 /* Look up the TransmitFile extension function pointer
1270                  * instead of calling TransmitFile() directly, because
1271                  * apparently "Several of the extension functions have
1272                  * been available since WinSock 1.1 and are exported
1273                  * from MSWsock.dll, however it's not advisable to
1274                  * link directly to this dll as this ties you to the
1275                  * Microsoft WinSock provider. A provider neutral way
1276                  * of accessing these extension functions is to load
1277                  * them dynamically via WSAIoctl using the
1278                  * SIO_GET_EXTENSION_FUNCTION_POINTER op code. This
1279                  * should, theoretically, allow you to access these
1280                  * functions from any provider that supports them..." 
1281                  * (http://www.codeproject.com/internet/jbsocketserver3.asp)
1282                  */
1283                 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1284                                 (void *)&trans_guid, sizeof(GUID),
1285                                 (void *)&_wapi_transmitfile, sizeof(void *),
1286                                 &output_bytes, NULL, NULL);
1287                 if (ret != 0) {
1288                         _wapi_transmitfile = NULL;
1289                 }
1290         }
1291
1292         if (_wapi_disconnectex != NULL) {
1293                 bret = _wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0);
1294         } else if (_wapi_transmitfile != NULL) {
1295                 bret = _wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL,
1296                                            TF_DISCONNECT | TF_REUSE_SOCKET);
1297         } else {
1298                 *error = ERROR_NOT_SUPPORTED;
1299                 return;
1300         }
1301
1302         if (bret == FALSE) {
1303                 *error = WSAGetLastError ();
1304         }
1305 }
1306
1307 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1308 {
1309         int ret;
1310         guchar *buf;
1311         gint32 alen;
1312         int recvflags=0;
1313         
1314         MONO_ARCH_SAVE_REGS;
1315
1316         *error = 0;
1317         
1318         alen = mono_array_length (buffer);
1319         if (offset > alen - count) {
1320                 return(0);
1321         }
1322         
1323         buf=mono_array_addr(buffer, guchar, offset);
1324         
1325         recvflags = convert_socketflags (flags);
1326         if (recvflags == -1) {
1327                 *error = WSAEOPNOTSUPP;
1328                 return (0);
1329         }
1330                 
1331         ret = _wapi_recv (sock, buf, count, recvflags);
1332         if(ret==SOCKET_ERROR) {
1333                 *error = WSAGetLastError ();
1334                 return(0);
1335         }
1336
1337         return(ret);
1338 }
1339
1340 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
1341 {
1342         int ret;
1343         guchar *buf;
1344         gint32 alen;
1345         int recvflags=0;
1346         struct sockaddr *sa;
1347         socklen_t sa_size;
1348         
1349         MONO_ARCH_SAVE_REGS;
1350
1351         *error = 0;
1352         
1353         alen = mono_array_length (buffer);
1354         if (offset > alen - count) {
1355                 return(0);
1356         }
1357
1358         sa=create_sockaddr_from_object(*sockaddr, &sa_size, error);
1359         if (*error != 0) {
1360                 return(0);
1361         }
1362         
1363         buf=mono_array_addr(buffer, guchar, offset);
1364         
1365         recvflags = convert_socketflags (flags);
1366         if (recvflags == -1) {
1367                 *error = WSAEOPNOTSUPP;
1368                 return (0);
1369         }
1370
1371         ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1372         if(ret==SOCKET_ERROR) {
1373                 g_free(sa);
1374                 *error = WSAGetLastError ();
1375                 return(0);
1376         }
1377
1378         /* If we didn't get a socket size, then we're probably a
1379          * connected connection-oriented socket and the stack hasn't
1380          * returned the remote address. All we can do is return null.
1381          */
1382         if ( sa_size != 0 )
1383                 *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
1384         else
1385                 *sockaddr=NULL;
1386
1387         g_free(sa);
1388         
1389         return(ret);
1390 }
1391
1392 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1393 {
1394         int ret;
1395         guchar *buf;
1396         gint32 alen;
1397         int sendflags=0;
1398         
1399         MONO_ARCH_SAVE_REGS;
1400
1401         *error = 0;
1402         
1403         alen = mono_array_length (buffer);
1404         if (offset > alen - count) {
1405                 return(0);
1406         }
1407
1408 #ifdef DEBUG
1409         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1410 #endif
1411         
1412         buf=mono_array_addr(buffer, guchar, offset);
1413
1414 #ifdef DEBUG
1415         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1416 #endif
1417
1418         sendflags = convert_socketflags (flags);
1419         if (sendflags == -1) {
1420                 *error = WSAEOPNOTSUPP;
1421                 return (0);
1422         }
1423
1424         ret = _wapi_send (sock, buf, count, sendflags);
1425         if(ret==SOCKET_ERROR) {
1426                 *error = WSAGetLastError ();
1427                 return(0);
1428         }
1429
1430         return(ret);
1431 }
1432
1433 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
1434 {
1435         int ret;
1436         guchar *buf;
1437         gint32 alen;
1438         int sendflags=0;
1439         struct sockaddr *sa;
1440         socklen_t sa_size;
1441         
1442         MONO_ARCH_SAVE_REGS;
1443
1444         *error = 0;
1445         
1446         alen = mono_array_length (buffer);
1447         if (offset > alen - count) {
1448                 return(0);
1449         }
1450
1451         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1452         if(*error != 0) {
1453                 return(0);
1454         }
1455         
1456 #ifdef DEBUG
1457         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1458 #endif
1459         
1460         buf=mono_array_addr(buffer, guchar, offset);
1461
1462 #ifdef DEBUG
1463         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1464 #endif
1465
1466         sendflags = convert_socketflags (flags);
1467         if (sendflags == -1) {
1468                 *error = WSAEOPNOTSUPP;
1469                 return (0);
1470         }
1471
1472         ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1473         if(ret==SOCKET_ERROR) {
1474                 *error = WSAGetLastError ();
1475         }
1476
1477         g_free(sa);
1478         
1479         return(ret);
1480 }
1481
1482 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
1483 {
1484         SOCKET sock;
1485         MonoClassField *field;
1486         
1487         field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
1488         sock=*(SOCKET *)(((char *)sockobj)+field->offset);
1489
1490         return(sock);
1491 }
1492
1493 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1494 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error)
1495 {
1496         MonoThread *thread = NULL;
1497         MonoObject *obj;
1498         mono_pollfd *pfds;
1499         int nfds, idx;
1500         int ret;
1501         int i, count;
1502         int mode;
1503         MonoClass *sock_arr_class;
1504         MonoArray *socks;
1505         time_t start;
1506         
1507         MONO_ARCH_SAVE_REGS;
1508
1509         /* *sockets -> READ, null, WRITE, null, ERROR, null */
1510         count = mono_array_length (*sockets);
1511         nfds = count - 3; /* NULL separators */
1512         pfds = g_new0 (mono_pollfd, nfds);
1513         mode = idx = 0;
1514         for (i = 0; i < count; i++) {
1515                 obj = mono_array_get (*sockets, MonoObject *, i);
1516                 if (obj == NULL) {
1517                         mode++;
1518                         continue;
1519                 }
1520
1521                 if (idx >= nfds) {
1522                         /* The socket array was bogus */
1523                         g_free (pfds);
1524                         *error = WSAEFAULT;
1525                         return;
1526                 }
1527
1528                 pfds [idx].fd = GPOINTER_TO_INT (Socket_to_SOCKET (obj));
1529                 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1530                 idx++;
1531         }
1532
1533         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1534         start = time (NULL);
1535         do {
1536                 *error = 0;
1537                 ret = mono_poll (pfds, nfds, timeout);
1538                 if (timeout > 0 && ret < 0) {
1539                         int err = errno;
1540                         int sec = time (NULL) - start;
1541
1542                         timeout -= sec * 1000;
1543                         if (timeout < 0)
1544                                 timeout = 0;
1545                         errno = err;
1546                 }
1547
1548                 if (ret == -1 && errno == EINTR) {
1549                         int leave = 0;
1550                         if (thread == NULL)
1551                                 thread = mono_thread_current ();
1552
1553                         mono_monitor_enter (thread->synch_lock);
1554                         leave = ((thread->state & ThreadState_AbortRequested) != 0 || 
1555                                  (thread->state & ThreadState_StopRequested) != 0);
1556                         mono_monitor_exit (thread->synch_lock);
1557                         if (leave != 0) {
1558                                 g_free (pfds);
1559                                 *sockets = NULL;
1560                                 return;
1561                         } else {
1562                                 /* Suspend requested? */
1563                                 mono_thread_interruption_checkpoint ();
1564                         }
1565                         errno = EINTR;
1566                 }
1567         } while (ret == -1 && errno == EINTR);
1568         
1569         if (ret == -1) {
1570 #ifdef PLATFORM_WIN32
1571                 *error = WSAGetLastError ();
1572 #else
1573                 *error = errno_to_WSA (errno, __func__);
1574 #endif
1575                 g_free (pfds);
1576                 return;
1577         }
1578
1579         if (ret == 0) {
1580                 g_free (pfds);
1581                 *sockets = NULL;
1582                 return;
1583         }
1584
1585         sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
1586         ret += 3; /* space for the NULL delimiters */
1587         socks = mono_array_new_full (mono_domain_get (), sock_arr_class, (guint32*)&ret, NULL);
1588         ret -= 3;
1589         mode = idx = 0;
1590         for (i = 0; i < count && ret > 0; i++) {
1591                 mono_pollfd *pfd;
1592
1593                 obj = mono_array_get (*sockets, MonoObject *, i);
1594                 if (obj == NULL) {
1595                         mode++;
1596                         idx++;
1597                         continue;
1598                 }
1599
1600                 pfd = &pfds [i - mode];
1601                 if (pfd->revents == 0)
1602                         continue;
1603
1604                 ret--;
1605                 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1606                         mono_array_setref (socks, idx++, obj);
1607                 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1608                         mono_array_setref (socks, idx++, obj);
1609                 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1610                         mono_array_setref (socks, idx++, obj);
1611                 }
1612         }
1613
1614         *sockets = socks;
1615         g_free (pfds);
1616 }
1617
1618 static MonoObject* int_to_object (MonoDomain *domain, int val)
1619 {
1620         return mono_value_box (domain, mono_get_int32_class (), &val);
1621 }
1622
1623
1624 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error)
1625 {
1626         int system_level;
1627         int system_name;
1628         int ret;
1629         int val;
1630         socklen_t valsize=sizeof(val);
1631         struct linger linger;
1632         socklen_t lingersize=sizeof(linger);
1633         int time_ms = 0;
1634         socklen_t time_ms_size = sizeof (time_ms);
1635 #ifdef SO_PEERCRED
1636         struct ucred cred;
1637         socklen_t credsize = sizeof(cred);
1638 #endif
1639         MonoDomain *domain=mono_domain_get();
1640         MonoObject *obj;
1641         MonoClass *obj_class;
1642         MonoClassField *field;
1643         
1644         MONO_ARCH_SAVE_REGS;
1645
1646         *error = 0;
1647         
1648         ret=convert_sockopt_level_and_name(level, name, &system_level,
1649                                            &system_name);
1650         if(ret==-1) {
1651                 *error = WSAENOPROTOOPT;
1652                 return;
1653         }
1654         if (ret == -2) {
1655                 *obj_val = int_to_object (domain, 0);
1656                 return;
1657         }
1658         
1659         /* No need to deal with MulticastOption names here, because
1660          * you cant getsockopt AddMembership or DropMembership (the
1661          * int getsockopt will error, causing an exception)
1662          */
1663         switch(name) {
1664         case SocketOptionName_Linger:
1665         case SocketOptionName_DontLinger:
1666                 ret = _wapi_getsockopt(sock, system_level, system_name, &linger,
1667                                &lingersize);
1668                 break;
1669                 
1670         case SocketOptionName_SendTimeout:
1671         case SocketOptionName_ReceiveTimeout:
1672                 ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
1673                 break;
1674
1675 #ifdef SO_PEERCRED
1676         case SocketOptionName_PeerCred: 
1677                 ret = _wapi_getsockopt (sock, system_level, system_name, &cred,
1678                                         &credsize);
1679                 break;
1680 #endif
1681
1682         default:
1683                 ret = _wapi_getsockopt (sock, system_level, system_name, &val,
1684                                &valsize);
1685         }
1686         
1687         if(ret==SOCKET_ERROR) {
1688                 *error = WSAGetLastError ();
1689                 return;
1690         }
1691         
1692         switch(name) {
1693         case SocketOptionName_Linger:
1694                 /* build a System.Net.Sockets.LingerOption */
1695                 obj_class=mono_class_from_name(system_assembly,
1696                                                "System.Net.Sockets",
1697                                                "LingerOption");
1698                 obj=mono_object_new(domain, obj_class);
1699                 
1700                 /* Locate and set the fields "bool enabled" and "int
1701                  * seconds"
1702                  */
1703                 field=mono_class_get_field_from_name(obj_class, "enabled");
1704                 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1705
1706                 field=mono_class_get_field_from_name(obj_class, "seconds");
1707                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1708                 
1709                 break;
1710                 
1711         case SocketOptionName_DontLinger:
1712                 /* construct a bool int in val - true if linger is off */
1713                 obj = int_to_object (domain, !linger.l_onoff);
1714                 break;
1715                 
1716         case SocketOptionName_SendTimeout:
1717         case SocketOptionName_ReceiveTimeout:
1718                 obj = int_to_object (domain, time_ms);
1719                 break;
1720
1721 #ifdef SO_PEERCRED
1722         case SocketOptionName_PeerCred: 
1723         {
1724                 /* build a Mono.Posix.PeerCred+PeerCredData if
1725                  * possible
1726                  */
1727                 static MonoImage *mono_posix_image = NULL;
1728                 MonoPeerCredData *cred_data;
1729                 
1730                 if (mono_posix_image == NULL) {
1731                         mono_posix_image=mono_image_loaded ("Mono.Posix");
1732                         if (!mono_posix_image) {
1733                                 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
1734                                 if (!sa) {
1735                                         *error = WSAENOPROTOOPT;
1736                                         return;
1737                                 } else {
1738                                         mono_posix_image = mono_assembly_get_image (sa);
1739                                 }
1740                         }
1741                 }
1742                 
1743                 obj_class = mono_class_from_name(mono_posix_image,
1744                                                  "Mono.Posix",
1745                                                  "PeerCredData");
1746                 obj = mono_object_new(domain, obj_class);
1747                 cred_data = (MonoPeerCredData *)obj;
1748                 cred_data->pid = cred.pid;
1749                 cred_data->uid = cred.uid;
1750                 cred_data->gid = cred.gid;
1751                 break;
1752         }
1753 #endif
1754
1755         default:
1756                 obj = int_to_object (domain, val);
1757         }
1758
1759         *obj_val=obj;
1760 }
1761
1762 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error)
1763 {
1764         int system_level;
1765         int system_name;
1766         int ret;
1767         guchar *buf;
1768         socklen_t valsize;
1769         
1770         MONO_ARCH_SAVE_REGS;
1771
1772         *error = 0;
1773         
1774         ret=convert_sockopt_level_and_name(level, name, &system_level,
1775                                            &system_name);
1776         if(ret==-1) {
1777                 *error = WSAENOPROTOOPT;
1778                 return;
1779         }
1780         if(ret==-2)
1781                 return;
1782
1783         valsize=mono_array_length(*byte_val);
1784         buf=mono_array_addr(*byte_val, guchar, 0);
1785         
1786         ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
1787         if(ret==SOCKET_ERROR) {
1788                 *error = WSAGetLastError ();
1789         }
1790 }
1791
1792 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1793 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1794 {
1795         struct in_addr inaddr;
1796         MonoClassField *field;
1797         
1798         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
1799
1800         /* No idea why .net uses a 64bit type to hold a 32bit value...
1801          *
1802          * Internal value of IPAddess is in little-endian order
1803          */
1804         inaddr.s_addr=GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr)+field->offset));
1805         
1806         return(inaddr);
1807 }
1808 #endif
1809
1810 #ifdef AF_INET6
1811 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
1812 {
1813         struct in6_addr in6addr;
1814         MonoClassField *field;
1815         MonoArray *data;
1816         int i;
1817
1818         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
1819         data=*(MonoArray **)(((char *)ipaddr) + field->offset);
1820
1821 /* Solaris has only the 8 bit version. */
1822 #ifndef s6_addr16
1823         for(i=0; i<8; i++) {
1824                 guint16 s = mono_array_get (data, guint16, i);
1825                 in6addr.s6_addr[2 * i] = (s >> 8) & 0xff;
1826                 in6addr.s6_addr[2 * i + 1] = s & 0xff;
1827         }
1828 #else
1829         for(i=0; i<8; i++)
1830                 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
1831 #endif
1832         return(in6addr);
1833 }
1834 #endif /* AF_INET6 */
1835
1836 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)
1837 {
1838         int system_level;
1839         int system_name;
1840         int ret;
1841 #ifdef AF_INET6
1842         int sol_ip;
1843         int sol_ipv6;
1844
1845         *error = 0;
1846         
1847 #ifdef HAVE_SOL_IPV6
1848         sol_ipv6 = SOL_IPV6;
1849 #else
1850         {
1851                 struct protoent *pent;
1852                 pent = getprotobyname ("ipv6");
1853                 sol_ipv6 = (pent != NULL) ? pent->p_proto : 41;
1854         }
1855 #endif
1856
1857 #ifdef HAVE_SOL_IP
1858         sol_ip = SOL_IP;
1859 #else
1860         {
1861                 struct protoent *pent;
1862                 pent = getprotobyname ("ip");
1863                 sol_ip = (pent != NULL) ? pent->p_proto : 0;
1864         }
1865 #endif
1866 #endif /* AF_INET6 */
1867
1868         MONO_ARCH_SAVE_REGS;
1869
1870         ret=convert_sockopt_level_and_name(level, name, &system_level,
1871                                            &system_name);
1872         if(ret==-1) {
1873                 *error = WSAENOPROTOOPT;
1874                 return;
1875         }
1876         if(ret==-2){
1877                 return;
1878         }
1879
1880         /* Only one of obj_val, byte_val or int_val has data */
1881         if(obj_val!=NULL) {
1882                 MonoClassField *field;
1883                 struct linger linger;
1884                 int valsize;
1885                 
1886                 switch(name) {
1887                 case SocketOptionName_DontLinger:
1888                         linger.l_onoff=0;
1889                         linger.l_linger=0;
1890                         valsize=sizeof(linger);
1891                         ret = _wapi_setsockopt (sock, system_level,
1892                                                 system_name, &linger, valsize);
1893                         break;
1894                         
1895                 case SocketOptionName_Linger:
1896                         /* Dig out "bool enabled" and "int seconds"
1897                          * fields
1898                          */
1899                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1900                         linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1901                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1902                         linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1903                         
1904                         valsize=sizeof(linger);
1905                         ret = _wapi_setsockopt (sock, system_level,
1906                                                 system_name, &linger, valsize);
1907                         break;
1908                 case SocketOptionName_AddMembership:
1909                 case SocketOptionName_DropMembership:
1910 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1911                 {
1912                         MonoObject *address = NULL;
1913
1914 #ifdef AF_INET6
1915                         if(system_level == sol_ipv6) {
1916                                 struct ipv6_mreq mreq6;
1917
1918                                 /*
1919                                  *      Get group address
1920                                  */
1921                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1922                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1923                                 
1924                                 if(address) {
1925                                         mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
1926                                 }
1927
1928                                 field=mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
1929                                 mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
1930
1931                                 ret = _wapi_setsockopt (sock, system_level,
1932                                                         system_name, &mreq6,
1933                                                         sizeof (mreq6));
1934                         } else if(system_level == sol_ip)
1935 #endif /* AF_INET6 */
1936                         {
1937 #ifdef HAVE_STRUCT_IP_MREQN
1938                                 struct ip_mreqn mreq = {{0}};
1939 #else
1940                                 struct ip_mreq mreq = {{0}};
1941 #endif /* HAVE_STRUCT_IP_MREQN */
1942                         
1943                                 /* pain! MulticastOption holds two IPAddress
1944                                  * members, so I have to dig the value out of
1945                                  * those :-(
1946                                  */
1947                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1948                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1949
1950                                 /* address might not be defined and if so, set the address to ADDR_ANY.
1951                                  */
1952                                 if(address) {
1953                                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
1954                                 }
1955
1956                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1957                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1958
1959 #ifdef HAVE_STRUCT_IP_MREQN
1960                                 if(address) {
1961                                         mreq.imr_address = ipaddress_to_struct_in_addr (address);
1962                                 }
1963 #else
1964                                 if(address) {
1965                                         mreq.imr_interface = ipaddress_to_struct_in_addr (address);
1966                                 }
1967 #endif /* HAVE_STRUCT_IP_MREQN */
1968                         
1969                                 ret = _wapi_setsockopt (sock, system_level,
1970                                                         system_name, &mreq,
1971                                                         sizeof (mreq));
1972                         }
1973                         break;
1974                 }
1975 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
1976                 default:
1977                         /* Cause an exception to be thrown */
1978                         *error = WSAEINVAL;
1979                         return;
1980                 }
1981         } else if (byte_val!=NULL) {
1982                 int valsize=mono_array_length(byte_val);
1983                 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1984         
1985                 ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
1986                 if(ret==SOCKET_ERROR) {
1987                         *error = WSAGetLastError ();
1988                         return;
1989                 }
1990         } else {
1991                 /* ReceiveTimeout/SendTimeout get here */
1992                 switch(name) {
1993                 case SocketOptionName_DontFragment:
1994 #ifdef HAVE_IP_MTU_DISCOVER
1995                         /* Fiddle with the value slightly if we're
1996                          * turning DF on
1997                          */
1998                         if (int_val == 1) {
1999                                 int_val = IP_PMTUDISC_DO;
2000                         }
2001                         /* Fall through */
2002 #endif
2003                         
2004                 default:
2005                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2006                 }
2007         }
2008
2009         if(ret==SOCKET_ERROR) {
2010                 *error = WSAGetLastError ();
2011         }
2012 }
2013
2014 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
2015                                                            gint32 how,
2016                                                            gint32 *error)
2017 {
2018         int ret;
2019         
2020         MONO_ARCH_SAVE_REGS;
2021
2022         *error = 0;
2023         
2024         /* Currently, the values for how (recv=0, send=1, both=2) match
2025          * the BSD API
2026          */
2027         ret = _wapi_shutdown (sock, how);
2028         if(ret==SOCKET_ERROR) {
2029                 *error = WSAGetLastError ();
2030         }
2031 }
2032
2033 gint
2034 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
2035                                               MonoArray *input,
2036                                               MonoArray *output, gint32 *error)
2037 {
2038         glong output_bytes = 0;
2039         gchar *i_buffer, *o_buffer;
2040         gint i_len, o_len;
2041         gint ret;
2042
2043         MONO_ARCH_SAVE_REGS;
2044
2045         *error = 0;
2046         
2047         if (code == FIONBIO) {
2048                 /* Invalid command. Must use Socket.Blocking */
2049                 return -1;
2050         }
2051
2052         if (input == NULL) {
2053                 i_buffer = NULL;
2054                 i_len = 0;
2055         } else {
2056                 i_buffer = mono_array_addr (input, gchar, 0);
2057                 i_len = mono_array_length (input);
2058         }
2059
2060         if (output == NULL) {
2061                 o_buffer = NULL;
2062                 o_len = 0;
2063         } else {
2064                 o_buffer = mono_array_addr (output, gchar, 0);
2065                 o_len = mono_array_length (output);
2066         }
2067
2068         ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2069         if (ret == SOCKET_ERROR) {
2070                 *error = WSAGetLastError ();
2071                 return(-1);
2072         }
2073
2074         return (gint) output_bytes;
2075 }
2076
2077 #ifdef HAVE_SIOCGIFCONF
2078 static gboolean
2079 is_loopback (int family, void *ad)
2080 {
2081         char *ptr = (char *) ad;
2082
2083         if (family == AF_INET) {
2084                 return (ptr [0] == 127);
2085         }
2086 #ifdef AF_INET6
2087         else {
2088                 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
2089         }
2090 #endif
2091         return FALSE;
2092 }
2093
2094 static void *
2095 get_local_ips (int family, int *nips)
2096 {
2097         int addr_size, offset, fd, i, count;
2098         int max_ifaces = 50; /* 50 interfaces should be enough... */
2099         struct ifconf ifc;
2100         struct ifreq *ifr;
2101         struct ifreq iflags;
2102         char *result, *tmp_ptr;
2103         gboolean ignore_loopback = FALSE;
2104
2105         *nips = 0;
2106         if (family == AF_INET) {
2107                 addr_size = sizeof (struct in_addr);
2108                 offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
2109 #ifdef AF_INET6
2110         } else if (family == AF_INET6) {
2111                 addr_size = sizeof (struct in6_addr);
2112                 offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
2113 #endif
2114         } else {
2115                 return NULL;
2116         }
2117
2118         fd = socket (family, SOCK_STREAM, 0);
2119
2120         ifc.ifc_len = max_ifaces * sizeof (struct ifreq);
2121         ifc.ifc_buf = g_malloc (ifc.ifc_len);
2122         if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
2123                 close (fd);
2124                 g_free (ifc.ifc_buf);
2125                 return NULL;
2126         }
2127
2128         count = ifc.ifc_len / sizeof (struct ifreq);
2129         *nips = count;
2130         if (count == 0) {
2131                 g_free (ifc.ifc_buf);
2132                 close (fd);
2133                 return NULL;
2134         }
2135
2136         for (i = 0, ifr = ifc.ifc_req; i < *nips; i++, ifr++) {
2137                 strcpy (iflags.ifr_name, ifr->ifr_name);
2138                 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
2139                         continue;
2140                 }
2141
2142                 if ((iflags.ifr_flags & IFF_UP) == 0) {
2143                         ifr->ifr_name [0] = '\0';
2144                         continue;
2145                 }
2146
2147                 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
2148                         ignore_loopback = TRUE;
2149                 }
2150         }
2151
2152         close (fd);
2153         result = g_malloc (addr_size * count);
2154         tmp_ptr = result;
2155         for (i = 0, ifr = ifc.ifc_req; i < count; i++, ifr++) {
2156                 if (ifr->ifr_name [0] == '\0') {
2157                         (*nips)--;
2158                         continue;
2159                 }
2160
2161                 if (ignore_loopback && is_loopback (family, ((char *) &ifr->ifr_addr) + offset)) {
2162                         (*nips)--;
2163                         continue;
2164                 }
2165
2166                 memcpy (tmp_ptr, ((char *) &ifr->ifr_addr) + offset, addr_size);
2167                 tmp_ptr += addr_size;
2168         }
2169
2170         g_free (ifc.ifc_buf);
2171         return result;
2172 }
2173 #else
2174 static void *
2175 get_local_ips (int family, int *nips)
2176 {
2177         *nips = 0;
2178         return NULL;
2179 }
2180
2181 #endif /* HAVE_SIOCGIFCONF */
2182
2183 #ifndef AF_INET6
2184 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
2185                                        MonoArray **h_aliases,
2186                                        MonoArray **h_addr_list,
2187                                        gboolean add_local_ips)
2188 {
2189         MonoDomain *domain = mono_domain_get ();
2190         int i;
2191         struct in_addr *local_in = NULL;
2192         int nlocal_in = 0;
2193
2194         if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
2195                 return(FALSE);
2196         }
2197
2198         *h_name=mono_string_new(domain, he->h_name);
2199
2200         i=0;
2201         while(he->h_aliases[i]!=NULL) {
2202                 i++;
2203         }
2204         
2205         *h_aliases=mono_array_new(domain, mono_get_string_class (), i);
2206         i=0;
2207         while(he->h_aliases[i]!=NULL) {
2208                 MonoString *alias;
2209                 
2210                 alias=mono_string_new(domain, he->h_aliases[i]);
2211                 mono_array_setref (*h_aliases, i, alias);
2212                 i++;
2213         }
2214
2215         if (add_local_ips) {
2216                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2217                 if (nlocal_in) {
2218                         *h_addr_list = mono_array_new(domain, mono_get_string_class (), nlocal_in);
2219                         for (i = 0; i < nlocal_in; i++) {
2220                                 MonoString *addr_string;
2221                                 char addr [16], *ptr;
2222                                 
2223                                 ptr = (char *) &local_in [i];
2224                                 g_snprintf(addr, 16, "%u.%u.%u.%u",
2225                                          (unsigned char) ptr [0],
2226                                          (unsigned char) ptr [1],
2227                                          (unsigned char) ptr [2],
2228                                          (unsigned char) ptr [3]);
2229                                 
2230                                 addr_string = mono_string_new (domain, addr);
2231                                 mono_array_setref (*h_addr_list, i, addr_string);
2232                                 i++;
2233                         }
2234
2235                         g_free (local_in);
2236                 }
2237         }
2238         
2239         if (nlocal_in == 0) {
2240                 i = 0;
2241                 while (he->h_addr_list[i]!=NULL) {
2242                         i++;
2243                 }
2244
2245                 *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
2246                 i=0;
2247                 while(he->h_addr_list[i]!=NULL) {
2248                         MonoString *addr_string;
2249                         char addr[16];
2250                         
2251                         g_snprintf(addr, 16, "%u.%u.%u.%u",
2252                                  (unsigned char)he->h_addr_list[i][0],
2253                                  (unsigned char)he->h_addr_list[i][1],
2254                                  (unsigned char)he->h_addr_list[i][2],
2255                                  (unsigned char)he->h_addr_list[i][3]);
2256                         
2257                         addr_string=mono_string_new(domain, addr);
2258                         mono_array_setref (*h_addr_list, i, addr_string);
2259                         i++;
2260                 }
2261         }
2262
2263         return(TRUE);
2264 }
2265
2266 static gboolean ipaddr_to_IPHostEntry(const char *addr, MonoString **h_name,
2267                                       MonoArray **h_aliases,
2268                                       MonoArray **h_addr_list)
2269 {
2270         MonoDomain *domain = mono_domain_get ();
2271
2272         *h_name=mono_string_new(domain, addr);
2273         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2274         *h_addr_list=mono_array_new(domain, mono_get_string_class (), 1);
2275         mono_array_setref (*h_addr_list, 0, *h_name);
2276
2277         return(TRUE);
2278 }
2279 #endif
2280
2281 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2282 static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name,
2283                                 MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
2284 {
2285         MonoDomain *domain = mono_domain_get ();
2286         int i, host_count, host_index, family_hint;
2287         struct in_addr *local_in = NULL;
2288         int nlocal_in = 0;
2289         struct in6_addr *local_in6 = NULL;
2290         int nlocal_in6 = 0;
2291         gboolean from_local = FALSE;
2292
2293         family_hint = get_family_hint ();
2294
2295         if(he1 == NULL && he2 == NULL) {
2296                 return(FALSE);
2297         }
2298
2299         /*
2300          * Check if address length and family are correct
2301          */
2302         if (he1 != NULL && (he1->h_length!=4 || he1->h_addrtype!=AF_INET)) {
2303                 return(FALSE);
2304         }
2305
2306         if (he2 != NULL && (he2->h_length!=16 || he2->h_addrtype!=AF_INET6)) {
2307                 return(FALSE);
2308         }
2309
2310         /*
2311          * Get the aliases and host name from he1 or he2 whichever is
2312          * not null, if he1 is not null then take aliases from he1
2313          */
2314         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2315                             family_hint == PF_INET)) {
2316                 *h_name=mono_string_new (domain, he1->h_name);
2317
2318                 i=0;
2319                 while(he1->h_aliases[i]!=NULL) {
2320                         i++;
2321                 }
2322
2323                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2324                                            i);
2325                 i=0;
2326                 while(he1->h_aliases[i]!=NULL) {
2327                         MonoString *alias;
2328
2329                         alias=mono_string_new (domain, he1->h_aliases[i]);
2330                         mono_array_setref (*h_aliases, i, alias);
2331                         i++;
2332                 }
2333         } else if (he2 != NULL && (family_hint == PF_UNSPEC ||
2334                                    family_hint == PF_INET6)) {
2335                 *h_name=mono_string_new (domain, he2->h_name);
2336
2337                 i=0;
2338                 while(he2->h_aliases [i] != NULL) {
2339                         i++;
2340                 }
2341
2342                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2343                                            i);
2344                 i=0;
2345                 while(he2->h_aliases[i]!=NULL) {
2346                         MonoString *alias;
2347
2348                         alias=mono_string_new (domain, he2->h_aliases[i]);
2349                         mono_array_setref (*h_aliases, i, alias);
2350                         i++;
2351                 }
2352         } else {
2353                 return(FALSE);
2354         }
2355
2356         /*
2357          * Count the number of addresses in he1 + he2
2358          */
2359         host_count = 0;
2360         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2361                             family_hint == PF_INET)) {
2362                 i=0;
2363                 while(he1->h_addr_list[i]!=NULL) {
2364                         i++;
2365                         host_count++;
2366                 }
2367         }
2368
2369         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2370                             family_hint == PF_INET6)) {
2371                 i=0;
2372                 while(he2->h_addr_list[i]!=NULL) {
2373                         i++;
2374                         host_count++;
2375                 }
2376         }
2377
2378         /*
2379          * Fills the array
2380          */
2381         host_index = 0;
2382         if (add_local_ips) {
2383                 if (family_hint == PF_UNSPEC || family_hint == PF_INET)
2384                         local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2385
2386                 if (family_hint == PF_UNSPEC || family_hint == PF_INET6)
2387                         local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2388
2389                 if (nlocal_in || nlocal_in6) {
2390                         from_local = TRUE;
2391                         *h_addr_list = mono_array_new (domain, mono_get_string_class (),
2392                                                              nlocal_in + nlocal_in6);
2393
2394                         if (nlocal_in6) {
2395                                 int n;
2396                                 for (n = 0; n < nlocal_in6; n++) {
2397                                         MonoString *addr_string;
2398                                         const char *ret;
2399                                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2400
2401                                         ret = inet_ntop (AF_INET6, &local_in6 [n], addr, sizeof(addr));
2402
2403                                         if (ret != NULL) {
2404                                                 addr_string = mono_string_new (domain, addr);
2405                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2406                                                 host_index++;
2407                                         }
2408                                 }
2409                         }
2410
2411                         if (nlocal_in) {
2412                                 int n;
2413                                 for (n = 0; n < nlocal_in; n++) {
2414                                         MonoString *addr_string;
2415                                         const char *ret;
2416                                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2417
2418                                         ret = inet_ntop (AF_INET, &local_in [n], addr, sizeof(addr));
2419
2420                                         if (ret != NULL) {
2421                                                 addr_string = mono_string_new (domain, addr);
2422                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2423                                                 host_index++;
2424                                         }
2425                                 }
2426                         }
2427                         g_free (local_in);
2428                         g_free (local_in6);
2429                         return TRUE;
2430                 }
2431
2432                 g_free (local_in);
2433                 g_free (local_in6);
2434         }
2435
2436         *h_addr_list=mono_array_new (domain, mono_get_string_class (), host_count);
2437
2438         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2439                             family_hint == PF_INET6)) {
2440                 i = 0;
2441                 while(he2->h_addr_list[i] != NULL) {
2442                         MonoString *addr_string;
2443                         const char *ret;
2444                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2445
2446                         ret = inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
2447                                          sizeof(addr));
2448
2449                         if (ret != NULL) {
2450                                 addr_string = mono_string_new (domain, addr);
2451                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2452                                 i++;
2453                                 host_index++;
2454                         }
2455                 }
2456         }
2457
2458         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2459                             family_hint == PF_INET)) {
2460                 i=0;
2461                 while(he1->h_addr_list[i] != NULL) {
2462                         MonoString *addr_string;
2463                         const char *ret;
2464                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2465
2466                         ret = inet_ntop (AF_INET, he1->h_addr_list[i], addr,
2467                                          sizeof(addr));
2468
2469                         if (ret != NULL) {
2470                                 addr_string=mono_string_new (domain, addr);
2471                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2472                                 i++;
2473                                 host_index++;
2474                         }
2475                 }
2476         }
2477
2478         return(TRUE);
2479 }
2480 #endif
2481
2482 #if defined(AF_INET6)
2483 static gboolean 
2484 addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
2485                                                 MonoArray **h_aliases,
2486                                                 MonoArray **h_addr_list,
2487                                                 gboolean add_local_ips)
2488 {
2489         gint32 count, i;
2490         struct addrinfo *ai = NULL;
2491         struct in_addr *local_in = NULL;
2492         int nlocal_in = 0;
2493         struct in6_addr *local_in6 = NULL;
2494         int nlocal_in6 = 0;
2495         int addr_index;
2496
2497         MonoDomain *domain = mono_domain_get ();
2498
2499         addr_index = 0;
2500         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2501         if (add_local_ips) {
2502                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2503                 local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2504                 if (nlocal_in || nlocal_in6) {
2505                         *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
2506                         if (nlocal_in) {
2507                                 MonoString *addr_string;
2508                                 char addr [16];
2509                                 int i;
2510
2511                                 for (i = 0; i < nlocal_in; i++) {
2512                                         inet_ntop (AF_INET, &local_in [i], addr, sizeof (addr));
2513                                         addr_string = mono_string_new (domain, addr);
2514                                         mono_array_setref (*h_addr_list, addr_index, addr_string);
2515                                         addr_index++;
2516                                 }
2517                         }
2518
2519                         if (nlocal_in6) {
2520                                 MonoString *addr_string;
2521                                 const char *ret;
2522                                 char addr [48];
2523                                 int i;
2524
2525                                 for (i = 0; i < nlocal_in6; i++) {
2526                                         ret = inet_ntop (AF_INET6, &local_in6 [i], addr, sizeof (addr));
2527                                         if (ret != NULL) {
2528                                                 addr_string = mono_string_new (domain, addr);
2529                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2530                                                 addr_index++;
2531                                         }
2532                                 }
2533                         }
2534
2535                         g_free (local_in);
2536                         g_free (local_in6);
2537                         if (info) {
2538                                 freeaddrinfo (info);
2539                         }
2540                         return TRUE;
2541                 }
2542
2543                 g_free (local_in);
2544                 g_free (local_in6);
2545         }
2546
2547         for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
2548                 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2549                         continue;
2550
2551                 count++;
2552         }
2553
2554         *h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
2555
2556         for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
2557                 MonoString *addr_string;
2558                 const char *ret;
2559                 char buffer [48]; /* Max. size for IPv6 */
2560
2561                 if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
2562                         continue;
2563                 }
2564
2565                 if(ai->ai_family == PF_INET) {
2566                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, 16);
2567                 } else {
2568                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, 48);
2569                 }
2570
2571                 if(ret) {
2572                         addr_string=mono_string_new(domain, buffer);
2573                 } else {
2574                         addr_string=mono_string_new(domain, "");
2575                 }
2576
2577                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2578
2579                 if(!i && ai->ai_canonname != NULL) {
2580                         *h_name=mono_string_new(domain, ai->ai_canonname);
2581                 }
2582
2583                 addr_index++;
2584         }
2585
2586         if(info) {
2587                 freeaddrinfo(info);
2588         }
2589
2590         return(TRUE);
2591 }
2592 #endif
2593
2594 #ifdef AF_INET6
2595 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2596 {
2597         gboolean add_local_ips = FALSE;
2598 #ifdef HAVE_SIOCGIFCONF
2599         gchar this_hostname [256];
2600 #endif
2601 #if !defined(HAVE_GETHOSTBYNAME2_R)
2602         struct addrinfo *info = NULL, hints;
2603         char *hostname;
2604         
2605         MONO_ARCH_SAVE_REGS;
2606         
2607         hostname=mono_string_to_utf8 (host);
2608 #ifdef HAVE_SIOCGIFCONF
2609         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2610                 if (!strcmp (hostname, this_hostname))
2611                         add_local_ips = TRUE;
2612         }
2613 #endif
2614
2615         memset(&hints, 0, sizeof(hints));
2616         hints.ai_family = get_family_hint ();
2617         hints.ai_socktype = SOCK_STREAM;
2618         hints.ai_flags = AI_CANONNAME;
2619
2620         if (getaddrinfo(hostname, NULL, &hints, &info) == -1) {
2621                 return(FALSE);
2622         }
2623         
2624         g_free(hostname);
2625
2626         return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips));
2627 #else
2628         struct hostent he1,*hp1, he2, *hp2;
2629         int buffer_size1, buffer_size2;
2630         char *buffer1, *buffer2;
2631         int herr;
2632         gboolean return_value;
2633         char *hostname;
2634         
2635         MONO_ARCH_SAVE_REGS;
2636         
2637         hostname=mono_string_to_utf8 (host);
2638
2639 #ifdef HAVE_SIOCGIFCONF
2640         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2641                 if (!strcmp (hostname, this_hostname))
2642                         add_local_ips = TRUE;
2643         }
2644 #endif
2645
2646         buffer_size1 = 512;
2647         buffer_size2 = 512;
2648         buffer1 = g_malloc0(buffer_size1);
2649         buffer2 = g_malloc0(buffer_size2);
2650
2651         while (gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1,
2652                                 &hp1, &herr) == ERANGE) {
2653                 buffer_size1 *= 2;
2654                 buffer1 = g_realloc(buffer1, buffer_size1);
2655         }
2656
2657         if (hp1 == NULL)
2658         {
2659                 while (gethostbyname2_r(hostname, AF_INET6, &he2, buffer2,
2660                                         buffer_size2, &hp2, &herr) == ERANGE) {
2661                         buffer_size2 *= 2;
2662                         buffer2 = g_realloc(buffer2, buffer_size2);
2663                 }
2664         }
2665         else
2666                 hp2 = NULL;
2667
2668         return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
2669                                                h_addr_list, add_local_ips);
2670
2671         g_free(buffer1);
2672         g_free(buffer2);
2673         g_free(hostname);
2674
2675         return(return_value);
2676 #endif /* HAVE_GETHOSTBYNAME2_R */
2677 }
2678 #else /* AF_INET6 */
2679 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2680 {
2681         struct hostent *he;
2682         char *hostname;
2683         gboolean add_local_ips = FALSE;
2684 #ifdef HAVE_SIOCGIFCONF
2685         gchar this_hostname [256];
2686 #endif
2687         
2688         MONO_ARCH_SAVE_REGS;
2689
2690         hostname=mono_string_to_utf8(host);
2691 #ifdef HAVE_SIOCGIFCONF
2692         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2693                 if (!strcmp (hostname, this_hostname))
2694                         add_local_ips = TRUE;
2695         }
2696 #endif
2697
2698         he = _wapi_gethostbyname (hostname);
2699         g_free(hostname);
2700
2701         if(he==NULL) {
2702                 return(FALSE);
2703         }
2704
2705         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips));
2706 }
2707 #endif /* AF_INET6 */
2708
2709 #ifndef HAVE_INET_PTON
2710 static int
2711 inet_pton (int family, const char *address, void *inaddrp)
2712 {
2713         if (family == AF_INET) {
2714 #ifdef HAVE_INET_ATON
2715                 struct in_addr inaddr;
2716                 
2717                 if (!inet_aton (address, &inaddr))
2718                         return 0;
2719                 
2720                 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
2721                 return 1;
2722 #else
2723                 /* assume the system has inet_addr(), if it doesn't
2724                    have that we're pretty much screwed... */
2725                 guint32 inaddr;
2726                 
2727                 if (!strcmp (address, "255.255.255.255")) {
2728                         /* special-case hack */
2729                         inaddr = 0xffffffff;
2730                 } else {
2731                         inaddr = inet_addr (address);
2732 #ifndef INADDR_NONE
2733 #define INADDR_NONE ((in_addr_t) -1)
2734 #endif
2735                         if (inaddr == INADDR_NONE)
2736                                 return 0;
2737                 }
2738                 
2739                 memcpy (inaddrp, &inaddr, sizeof (guint32));
2740                 return 1;
2741 #endif /* HAVE_INET_ATON */
2742         }
2743         
2744         return -1;
2745 }
2746 #endif /* !HAVE_INET_PTON */
2747
2748 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2749 {
2750         char *address;
2751         const char *version;
2752         gboolean v1;
2753         
2754 #ifdef AF_INET6
2755         struct sockaddr_in saddr;
2756         struct sockaddr_in6 saddr6;
2757         struct addrinfo *info = NULL, hints;
2758         gint32 family;
2759         char hostname[1024] = {0};
2760         int flags = 0;
2761 #else
2762         struct in_addr inaddr;
2763         struct hostent *he;
2764         gboolean ret;
2765 #endif
2766
2767         MONO_ARCH_SAVE_REGS;
2768
2769         version = mono_get_runtime_info ()->framework_version;
2770         v1 = (version[0] == '1');
2771
2772         address = mono_string_to_utf8 (addr);
2773
2774 #ifdef AF_INET6
2775         if (inet_pton (AF_INET, address, &saddr.sin_addr ) <= 0) {
2776                 /* Maybe an ipv6 address */
2777                 if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) <= 0) {
2778                         g_free (address);
2779                         return FALSE;
2780                 }
2781                 else {
2782                         family = AF_INET6;
2783                         saddr6.sin6_family = AF_INET6;
2784                 }
2785         }
2786         else {
2787                 family = AF_INET;
2788                 saddr.sin_family = AF_INET;
2789         }
2790         g_free(address);
2791
2792         if (v1) {
2793                 flags = NI_NAMEREQD;
2794         }
2795         
2796         if(family == AF_INET) {
2797                 if(getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr),
2798                                 hostname, sizeof(hostname), NULL, 0,
2799                                 flags) != 0) {
2800                         return(FALSE);
2801                 }
2802         } else if(family == AF_INET6) {
2803                 if(getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6),
2804                                 hostname, sizeof(hostname), NULL, 0,
2805                                 flags) != 0) {
2806                         return(FALSE);
2807                 }
2808         }
2809
2810         memset (&hints, 0, sizeof(hints));
2811         hints.ai_family = get_family_hint ();
2812         hints.ai_socktype = SOCK_STREAM;
2813         hints.ai_flags = AI_CANONNAME;
2814
2815         if( getaddrinfo (hostname, NULL, &hints, &info) == -1 ) {
2816                 return(FALSE);
2817         }
2818
2819         return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE));
2820 #else
2821         if (inet_pton (AF_INET, address, &inaddr) <= 0) {
2822                 g_free (address);
2823                 return(FALSE);
2824         }
2825
2826         if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) {
2827                 if (v1) {
2828                         ret = FALSE;
2829                 } else {
2830                         ret = ipaddr_to_IPHostEntry (address, h_name,
2831                                                      h_aliases, h_addr_list);
2832                 }
2833         } else {
2834                 ret = hostent_to_IPHostEntry (he, h_name, h_aliases,
2835                                               h_addr_list, FALSE);
2836         }
2837
2838         g_free (address);
2839         return(ret);
2840 #endif
2841 }
2842
2843 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
2844 {
2845         gchar hostname[256];
2846         int ret;
2847         
2848         MONO_ARCH_SAVE_REGS;
2849
2850         ret = gethostname (hostname, sizeof (hostname));
2851         if(ret==-1) {
2852                 return(FALSE);
2853         }
2854         
2855         *h_name=mono_string_new(mono_domain_get (), hostname);
2856
2857         return(TRUE);
2858 }
2859
2860 void mono_network_init(void)
2861 {
2862         WSADATA wsadata;
2863         int err;
2864         
2865         err=WSAStartup(MAKEWORD(2,0), &wsadata);
2866         if(err!=0) {
2867                 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
2868                 exit(-1);
2869         }
2870
2871 #ifdef DEBUG
2872         g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
2873         g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
2874 #endif
2875 }
2876
2877 void mono_network_cleanup(void)
2878 {
2879         WSACleanup();
2880 }
2881