update known-issues
[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 #ifndef PLATFORM_WIN32
696         /* .net seems to set this by default for SOCK_STREAM,
697          * not for SOCK_DGRAM (see bug #36322)
698          *
699          * It seems winsock has a rather different idea of what
700          * SO_REUSEADDR means.  If it's set, then a new socket can be
701          * bound over an existing listening socket.  There's a new
702          * windows-specific option called SO_EXCLUSIVEADDRUSE but
703          * using that means the socket MUST be closed properly, or a
704          * denial of service can occur.  Luckily for us, winsock
705          * behaves as though any other system would when SO_REUSEADDR
706          * is true, so we don't need to do anything else here.  See
707          * bug 53992.
708          */
709         {
710         int ret, true = 1;
711         
712         ret = _wapi_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (true));
713         if(ret==SOCKET_ERROR) {
714                 *error = WSAGetLastError ();
715                 
716                 closesocket(sock);
717                 return(NULL);
718         }
719         }
720 #endif
721         
722         return(GUINT_TO_POINTER (sock));
723 }
724
725 /* FIXME: the SOCKET parameter (here and in other functions in this
726  * file) is really an IntPtr which needs to be converted to a guint32.
727  */
728 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock,
729                                                         gint32 *error)
730 {
731         MONO_ARCH_SAVE_REGS;
732
733 #ifdef DEBUG
734         g_message (G_GNUC_PRETTY_FUNCTION ": closing 0x%x", sock);
735 #endif
736
737         *error = 0;
738
739         /* Clear any pending work item from this socket if the underlying
740          * polling system does not notify when the socket is closed */
741         mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock));
742         closesocket(sock);
743 }
744
745 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
746 {
747         MONO_ARCH_SAVE_REGS;
748
749 #ifdef DEBUG
750         g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
751 #endif
752
753         return(WSAGetLastError());
754 }
755
756 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock,
757                                                               gint32 *error)
758 {
759         int ret;
760         gulong amount;
761         
762         MONO_ARCH_SAVE_REGS;
763
764         *error = 0;
765         
766         ret=ioctlsocket(sock, FIONREAD, &amount);
767         if(ret==SOCKET_ERROR) {
768                 *error = WSAGetLastError ();
769                 return(0);
770         }
771         
772         return(amount);
773 }
774
775 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
776                                                            gboolean block,
777                                                            gint32 *error)
778 {
779         int ret;
780         
781         MONO_ARCH_SAVE_REGS;
782
783         *error = 0;
784
785         /*
786          * block == TRUE/FALSE means we will block/not block.
787          * But the ioctlsocket call takes TRUE/FALSE for non-block/block
788          */
789         block = !block;
790         
791         ret = ioctlsocket (sock, FIONBIO, (gulong *) &block);
792         if(ret==SOCKET_ERROR) {
793                 *error = WSAGetLastError ();
794         }
795 }
796
797 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock,
798                                                              gint32 *error)
799 {
800         SOCKET newsock;
801         
802         MONO_ARCH_SAVE_REGS;
803
804         *error = 0;
805         
806         newsock = _wapi_accept (sock, NULL, 0);
807         if(newsock==INVALID_SOCKET) {
808                 *error = WSAGetLastError ();
809                 return(NULL);
810         }
811         
812         return(GUINT_TO_POINTER (newsock));
813 }
814
815 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
816                                                          guint32 backlog,
817                                                          gint32 *error)
818 {
819         int ret;
820         
821         MONO_ARCH_SAVE_REGS;
822
823         *error = 0;
824         
825         ret = _wapi_listen (sock, backlog);
826         if(ret==SOCKET_ERROR) {
827                 *error = WSAGetLastError ();
828         }
829 }
830
831 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
832                                                int sa_size, gint32 *error)
833 {
834         MonoDomain *domain = mono_domain_get ();
835         MonoObject *sockaddr_obj;
836         MonoClass *sockaddr_class;
837         MonoClassField *field;
838         MonoArray *data;
839         MonoAddressFamily family;
840
841         /* Build a System.Net.SocketAddress object instance */
842         sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
843         sockaddr_obj=mono_object_new(domain, sockaddr_class);
844         
845         /* Locate the SocketAddress data buffer in the object */
846         field=mono_class_get_field_from_name(sockaddr_class, "data");
847
848         /* Make sure there is space for the family and size bytes */
849 #ifdef HAVE_SYS_UN_H
850         if (saddr->sa_family == AF_UNIX) {
851                 /* sa_len includes the entire sockaddr size, so we don't need the
852                  * N bytes (sizeof (unsigned short)) of the family. */
853                 data=mono_array_new(domain, mono_get_byte_class (), sa_size);
854         } else
855 #endif
856         {
857                 /* May be the +2 here is too conservative, as sa_len returns
858                  * the length of the entire sockaddr_in/in6, including
859                  * sizeof (unsigned short) of the family */
860                 data=mono_array_new(domain, mono_get_byte_class (), sa_size+2);
861         }
862
863         /* The data buffer is laid out as follows:
864          * bytes 0 and 1 are the address family
865          * bytes 2 and 3 are the port info
866          * the rest is the address info
867          */
868                 
869         family=convert_to_mono_family(saddr->sa_family);
870         if(family==AddressFamily_Unknown) {
871                 *error = WSAEAFNOSUPPORT;
872                 return(NULL);
873         }
874
875         mono_array_set(data, guint8, 0, family & 0x0FF);
876         mono_array_set(data, guint8, 1, (family >> 8) & 0x0FF);
877         
878         if(saddr->sa_family==AF_INET) {
879                 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
880                 guint16 port=ntohs(sa_in->sin_port);
881                 guint32 address=ntohl(sa_in->sin_addr.s_addr);
882                 
883                 if(sa_size<8) {
884                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
885                 }
886                 
887                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
888                 mono_array_set(data, guint8, 3, (port) & 0xff);
889                 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
890                 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
891                 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
892                 mono_array_set(data, guint8, 7, (address) & 0xff);
893         
894                 mono_field_set_value (sockaddr_obj, field, data);
895
896                 return(sockaddr_obj);
897 #ifdef AF_INET6
898         } else if (saddr->sa_family == AF_INET6) {
899                 struct sockaddr_in6 *sa_in=(struct sockaddr_in6 *)saddr;
900                 int i;
901
902                 guint16 port=ntohs(sa_in->sin6_port);
903
904                 if(sa_size<28) {
905                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
906                 }
907
908                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
909                 mono_array_set(data, guint8, 3, (port) & 0xff);
910
911                 for(i=0; i<16; i++) {
912                         mono_array_set(data, guint8, 8+i,
913                                        sa_in->sin6_addr.s6_addr[i]);
914                 }
915
916                 mono_array_set(data, guint8, 24, sa_in->sin6_scope_id & 0xff);
917                 mono_array_set(data, guint8, 25,
918                                (sa_in->sin6_scope_id >> 8) & 0xff);
919                 mono_array_set(data, guint8, 26,
920                                (sa_in->sin6_scope_id >> 16) & 0xff);
921                 mono_array_set(data, guint8, 27,
922                                (sa_in->sin6_scope_id >> 24) & 0xff);
923
924                 mono_field_set_value (sockaddr_obj, field, data);
925
926                 return(sockaddr_obj);
927 #endif
928 #ifdef HAVE_SYS_UN_H
929         } else if (saddr->sa_family == AF_UNIX) {
930                 int i;
931
932                 for (i = 0; i < sa_size; i++) {
933                         mono_array_set (data, guint8, i+2, saddr->sa_data[i]);
934                 }
935                 
936                 mono_field_set_value (sockaddr_obj, field, data);
937
938                 return sockaddr_obj;
939 #endif
940         } else {
941                 *error = WSAEAFNOSUPPORT;
942                 return(NULL);
943         }
944 }
945
946 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 *error)
947 {
948         gchar sa[32];   /* sockaddr in not big enough for sockaddr_in6 */
949         socklen_t salen;
950         int ret;
951         
952         MONO_ARCH_SAVE_REGS;
953
954         *error = 0;
955         
956         salen=sizeof(sa);
957         ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
958         
959         if(ret==SOCKET_ERROR) {
960                 *error = WSAGetLastError ();
961                 return(NULL);
962         }
963         
964 #ifdef DEBUG
965         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));
966 #endif
967
968         return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
969                                            error));
970 }
971
972 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 *error)
973 {
974         gchar sa[32];   /* sockaddr in not big enough for sockaddr_in6 */
975         socklen_t salen;
976         int ret;
977         
978         MONO_ARCH_SAVE_REGS;
979
980         *error = 0;
981         
982         salen=sizeof(sa);
983         ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
984         
985         if(ret==SOCKET_ERROR) {
986                 *error = WSAGetLastError ();
987                 return(NULL);
988         }
989         
990 #ifdef DEBUG
991         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));
992 #endif
993
994         return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
995                                            error));
996 }
997
998 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
999                                                     socklen_t *sa_size,
1000                                                     gint32 *error)
1001 {
1002         MonoClassField *field;
1003         MonoArray *data;
1004         gint32 family;
1005         int len;
1006
1007         /* Dig the SocketAddress data buffer out of the object */
1008         field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
1009         data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
1010
1011         /* The data buffer is laid out as follows:
1012          * byte 0 is the address family low byte
1013          * byte 1 is the address family high byte
1014          * INET:
1015          *      bytes 2 and 3 are the port info
1016          *      the rest is the address info
1017          * UNIX:
1018          *      the rest is the file name
1019          */
1020         len = mono_array_length (data);
1021         if (len < 2) {
1022                 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1023         }
1024         
1025         family = convert_family (mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8));
1026         if (family == AF_INET) {
1027                 struct sockaddr_in *sa;
1028                 guint16 port;
1029                 guint32 address;
1030                 
1031                 if (len < 8) {
1032                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1033                 }
1034
1035                 sa = g_new0 (struct sockaddr_in, 1);
1036                 port = (mono_array_get (data, guint8, 2) << 8) +
1037                         mono_array_get (data, guint8, 3);
1038                 address = (mono_array_get (data, guint8, 4) << 24) +
1039                         (mono_array_get (data, guint8, 5) << 16 ) +
1040                         (mono_array_get (data, guint8, 6) << 8) +
1041                         mono_array_get (data, guint8, 7);
1042
1043                 sa->sin_family = family;
1044                 sa->sin_addr.s_addr = htonl (address);
1045                 sa->sin_port = htons (port);
1046
1047                 *sa_size = sizeof(struct sockaddr_in);
1048                 return((struct sockaddr *)sa);
1049
1050 #ifdef AF_INET6
1051         } else if (family == AF_INET6) {
1052                 struct sockaddr_in6 *sa;
1053                 int i;
1054                 guint16 port;
1055                 guint32 scopeid;
1056                 
1057                 if (len < 28) {
1058                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1059                 }
1060
1061                 sa = g_new0 (struct sockaddr_in6, 1);
1062                 port = mono_array_get (data, guint8, 3) +
1063                         (mono_array_get (data, guint8, 2) << 8);
1064                 scopeid = mono_array_get (data, guint8, 24) + 
1065                         (mono_array_get (data, guint8, 25) << 8) + 
1066                         (mono_array_get (data, guint8, 26) << 16) + 
1067                         (mono_array_get (data, guint8, 27) << 24);
1068
1069                 sa->sin6_family = family;
1070                 sa->sin6_port = htons (port);
1071                 sa->sin6_scope_id = scopeid;
1072
1073                 for(i=0; i<16; i++) {
1074                         sa->sin6_addr.s6_addr[i] = mono_array_get (data, guint8, 8+i);
1075                 }
1076
1077                 *sa_size = sizeof(struct sockaddr_in6);
1078                 return((struct sockaddr *)sa);
1079 #endif
1080 #ifdef HAVE_SYS_UN_H
1081         } else if (family == AF_UNIX) {
1082                 struct sockaddr_un *sock_un;
1083                 int i;
1084
1085                 /* Need a byte for the '\0' terminator/prefix, and the first
1086                  * two bytes hold the SocketAddress family
1087                  */
1088                 if (len - 2 >= MONO_SIZEOF_SUNPATH) {
1089                         mono_raise_exception (mono_get_exception_index_out_of_range ());
1090                 }
1091                 
1092                 sock_un = g_new0 (struct sockaddr_un, 1);
1093
1094                 sock_un->sun_family = family;
1095                 for (i = 0; i < len - 2; i++) {
1096                         sock_un->sun_path [i] = mono_array_get (data, guint8,
1097                                                                 i + 2);
1098                 }
1099                 
1100                 *sa_size = len;
1101
1102                 return (struct sockaddr *)sock_un;
1103 #endif
1104         } else {
1105                 *error = WSAEAFNOSUPPORT;
1106                 return(0);
1107         }
1108 }
1109
1110 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1111 {
1112         struct sockaddr *sa;
1113         socklen_t sa_size;
1114         int ret;
1115         
1116         MONO_ARCH_SAVE_REGS;
1117
1118         *error = 0;
1119         
1120         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1121         if (*error != 0) {
1122                 return;
1123         }
1124
1125 #ifdef DEBUG
1126         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));
1127 #endif
1128
1129         ret = _wapi_bind (sock, sa, sa_size);
1130         if(ret==SOCKET_ERROR) {
1131                 *error = WSAGetLastError ();
1132         }
1133
1134         g_free(sa);
1135 }
1136
1137 enum {
1138         SelectModeRead,
1139         SelectModeWrite,
1140         SelectModeError
1141 };
1142
1143 MonoBoolean
1144 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1145                                                    gint timeout, gint32 *error)
1146 {
1147         MonoThread *thread = NULL;
1148         mono_pollfd *pfds;
1149         int ret;
1150         time_t start;
1151         
1152
1153         MONO_ARCH_SAVE_REGS;
1154         
1155         pfds = g_new0 (mono_pollfd, 1);
1156         pfds[0].fd = GPOINTER_TO_INT (sock);
1157         pfds[0].events = (mode == SelectModeRead) ? MONO_POLLIN :
1158                 (mode == SelectModeWrite) ? MONO_POLLOUT :
1159                 (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL);
1160
1161         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1162         start = time (NULL);
1163         do {
1164                 *error = 0;
1165                 
1166                 ret = mono_poll (pfds, 1, timeout);
1167                 if (timeout > 0 && ret < 0) {
1168                         int err = errno;
1169                         int sec = time (NULL) - start;
1170                         
1171                         timeout -= sec * 1000;
1172                         if (timeout < 0) {
1173                                 timeout = 0;
1174                         }
1175                         
1176                         errno = err;
1177                 }
1178                 
1179                 if (ret == -1 && errno == EINTR) {
1180                         int leave = 0;
1181
1182                         if (thread == NULL) {
1183                                 thread = mono_thread_current ();
1184                         }
1185                         
1186                         mono_monitor_enter (thread->synch_lock);
1187                         leave = ((thread->state & ThreadState_AbortRequested) != 0 ||
1188                                  (thread->state & ThreadState_StopRequested) != 0);
1189                         mono_monitor_exit (thread->synch_lock);
1190                         
1191                         if (leave != 0) {
1192                                 g_free (pfds);
1193                                 return(FALSE);
1194                         } else {
1195                                 /* Suspend requested? */
1196                                 mono_thread_interruption_checkpoint ();
1197                         }
1198                         errno = EINTR;
1199                 }
1200         } while (ret == -1 && errno == EINTR);
1201
1202         if (ret == -1) {
1203 #ifdef PLATFORM_WIN32
1204                 *error = WSAGetLastError ();
1205 #else
1206                 *error = errno_to_WSA (errno, __func__);
1207 #endif
1208                 g_free (pfds);
1209                 return(FALSE);
1210         }
1211         
1212         g_free (pfds);
1213
1214         if (ret == 0) {
1215                 return(FALSE);
1216         } else {
1217                 return (TRUE);
1218         }
1219 }
1220
1221 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1222 {
1223         struct sockaddr *sa;
1224         socklen_t sa_size;
1225         int ret;
1226         
1227         MONO_ARCH_SAVE_REGS;
1228
1229         *error = 0;
1230         
1231         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1232         if (*error != 0) {
1233                 return;
1234         }
1235         
1236 #ifdef DEBUG
1237         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));
1238 #endif
1239
1240         ret = _wapi_connect (sock, sa, sa_size);
1241         if(ret==SOCKET_ERROR) {
1242                 *error = WSAGetLastError ();
1243         }
1244
1245         g_free(sa);
1246 }
1247
1248 /* These #defines from mswsock.h from wine.  Defining them here allows
1249  * us to build this file on a mingw box that doesn't know the magic
1250  * numbers, but still run on a newer windows box that does.
1251  */
1252 #ifndef WSAID_DISCONNECTEX
1253 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1254 typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
1255 #endif
1256
1257 #ifndef WSAID_TRANSMITFILE
1258 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1259 typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
1260 #endif
1261
1262 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, MonoBoolean reuse, gint32 *error)
1263 {
1264         int ret;
1265         glong output_bytes = 0;
1266         GUID disco_guid = WSAID_DISCONNECTEX;
1267         GUID trans_guid = WSAID_TRANSMITFILE;
1268         LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
1269         LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
1270         gboolean bret;
1271         
1272         MONO_ARCH_SAVE_REGS;
1273
1274         *error = 0;
1275         
1276 #ifdef DEBUG
1277         g_message("%s: disconnecting from socket %p (reuse %d)", __func__,
1278                   sock, reuse);
1279 #endif
1280
1281         /* I _think_ the extension function pointers need to be looked
1282          * up for each socket.  FIXME: check the best way to store
1283          * pointers to functions in managed objects that still works
1284          * on 64bit platforms.
1285          */
1286         ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1287                         (void *)&disco_guid, sizeof(GUID),
1288                         (void *)&_wapi_disconnectex, sizeof(void *),
1289                         &output_bytes, NULL, NULL);
1290         if (ret != 0) {
1291                 /* make sure that WSAIoctl didn't put crap in the
1292                  * output pointer
1293                  */
1294                 _wapi_disconnectex = NULL;
1295
1296                 /* Look up the TransmitFile extension function pointer
1297                  * instead of calling TransmitFile() directly, because
1298                  * apparently "Several of the extension functions have
1299                  * been available since WinSock 1.1 and are exported
1300                  * from MSWsock.dll, however it's not advisable to
1301                  * link directly to this dll as this ties you to the
1302                  * Microsoft WinSock provider. A provider neutral way
1303                  * of accessing these extension functions is to load
1304                  * them dynamically via WSAIoctl using the
1305                  * SIO_GET_EXTENSION_FUNCTION_POINTER op code. This
1306                  * should, theoretically, allow you to access these
1307                  * functions from any provider that supports them..." 
1308                  * (http://www.codeproject.com/internet/jbsocketserver3.asp)
1309                  */
1310                 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1311                                 (void *)&trans_guid, sizeof(GUID),
1312                                 (void *)&_wapi_transmitfile, sizeof(void *),
1313                                 &output_bytes, NULL, NULL);
1314                 if (ret != 0) {
1315                         _wapi_transmitfile = NULL;
1316                 }
1317         }
1318
1319         if (_wapi_disconnectex != NULL) {
1320                 bret = _wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0);
1321         } else if (_wapi_transmitfile != NULL) {
1322                 bret = _wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL,
1323                                            TF_DISCONNECT | TF_REUSE_SOCKET);
1324         } else {
1325                 *error = ERROR_NOT_SUPPORTED;
1326                 return;
1327         }
1328
1329         if (bret == FALSE) {
1330                 *error = WSAGetLastError ();
1331         }
1332 }
1333
1334 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1335 {
1336         int ret;
1337         guchar *buf;
1338         gint32 alen;
1339         int recvflags=0;
1340         
1341         MONO_ARCH_SAVE_REGS;
1342
1343         *error = 0;
1344         
1345         alen = mono_array_length (buffer);
1346         if (offset > alen - count) {
1347                 return(0);
1348         }
1349         
1350         buf=mono_array_addr(buffer, guchar, offset);
1351         
1352         recvflags = convert_socketflags (flags);
1353         if (recvflags == -1) {
1354                 *error = WSAEOPNOTSUPP;
1355                 return (0);
1356         }
1357                 
1358         ret = _wapi_recv (sock, buf, count, recvflags);
1359         if(ret==SOCKET_ERROR) {
1360                 *error = WSAGetLastError ();
1361                 return(0);
1362         }
1363
1364         return(ret);
1365 }
1366
1367 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
1368 {
1369         int ret;
1370         guchar *buf;
1371         gint32 alen;
1372         int recvflags=0;
1373         struct sockaddr *sa;
1374         socklen_t sa_size;
1375         
1376         MONO_ARCH_SAVE_REGS;
1377
1378         *error = 0;
1379         
1380         alen = mono_array_length (buffer);
1381         if (offset > alen - count) {
1382                 return(0);
1383         }
1384
1385         sa=create_sockaddr_from_object(*sockaddr, &sa_size, error);
1386         if (*error != 0) {
1387                 return(0);
1388         }
1389         
1390         buf=mono_array_addr(buffer, guchar, offset);
1391         
1392         recvflags = convert_socketflags (flags);
1393         if (recvflags == -1) {
1394                 *error = WSAEOPNOTSUPP;
1395                 return (0);
1396         }
1397
1398         ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1399         if(ret==SOCKET_ERROR) {
1400                 g_free(sa);
1401                 *error = WSAGetLastError ();
1402                 return(0);
1403         }
1404
1405         /* If we didn't get a socket size, then we're probably a
1406          * connected connection-oriented socket and the stack hasn't
1407          * returned the remote address. All we can do is return null.
1408          */
1409         if ( sa_size != 0 )
1410                 *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
1411         else
1412                 *sockaddr=NULL;
1413
1414         g_free(sa);
1415         
1416         return(ret);
1417 }
1418
1419 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1420 {
1421         int ret;
1422         guchar *buf;
1423         gint32 alen;
1424         int sendflags=0;
1425         
1426         MONO_ARCH_SAVE_REGS;
1427
1428         *error = 0;
1429         
1430         alen = mono_array_length (buffer);
1431         if (offset > alen - count) {
1432                 return(0);
1433         }
1434
1435 #ifdef DEBUG
1436         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1437 #endif
1438         
1439         buf=mono_array_addr(buffer, guchar, offset);
1440
1441 #ifdef DEBUG
1442         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1443 #endif
1444
1445         sendflags = convert_socketflags (flags);
1446         if (sendflags == -1) {
1447                 *error = WSAEOPNOTSUPP;
1448                 return (0);
1449         }
1450
1451         ret = _wapi_send (sock, buf, count, sendflags);
1452         if(ret==SOCKET_ERROR) {
1453                 *error = WSAGetLastError ();
1454                 return(0);
1455         }
1456
1457         return(ret);
1458 }
1459
1460 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
1461 {
1462         int ret;
1463         guchar *buf;
1464         gint32 alen;
1465         int sendflags=0;
1466         struct sockaddr *sa;
1467         socklen_t sa_size;
1468         
1469         MONO_ARCH_SAVE_REGS;
1470
1471         *error = 0;
1472         
1473         alen = mono_array_length (buffer);
1474         if (offset > alen - count) {
1475                 return(0);
1476         }
1477
1478         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1479         if(*error != 0) {
1480                 return(0);
1481         }
1482         
1483 #ifdef DEBUG
1484         g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1485 #endif
1486         
1487         buf=mono_array_addr(buffer, guchar, offset);
1488
1489 #ifdef DEBUG
1490         g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1491 #endif
1492
1493         sendflags = convert_socketflags (flags);
1494         if (sendflags == -1) {
1495                 *error = WSAEOPNOTSUPP;
1496                 return (0);
1497         }
1498
1499         ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1500         if(ret==SOCKET_ERROR) {
1501                 *error = WSAGetLastError ();
1502         }
1503
1504         g_free(sa);
1505         
1506         return(ret);
1507 }
1508
1509 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
1510 {
1511         SOCKET sock;
1512         MonoClassField *field;
1513         
1514         field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
1515         sock=*(SOCKET *)(((char *)sockobj)+field->offset);
1516
1517         return(sock);
1518 }
1519
1520 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1521 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error)
1522 {
1523         MonoThread *thread = NULL;
1524         MonoObject *obj;
1525         mono_pollfd *pfds;
1526         int nfds, idx;
1527         int ret;
1528         int i, count;
1529         int mode;
1530         MonoClass *sock_arr_class;
1531         MonoArray *socks;
1532         time_t start;
1533         
1534         MONO_ARCH_SAVE_REGS;
1535
1536         /* *sockets -> READ, null, WRITE, null, ERROR, null */
1537         count = mono_array_length (*sockets);
1538         nfds = count - 3; /* NULL separators */
1539         pfds = g_new0 (mono_pollfd, nfds);
1540         mode = idx = 0;
1541         for (i = 0; i < count; i++) {
1542                 obj = mono_array_get (*sockets, MonoObject *, i);
1543                 if (obj == NULL) {
1544                         mode++;
1545                         continue;
1546                 }
1547
1548                 if (idx >= nfds) {
1549                         /* The socket array was bogus */
1550                         g_free (pfds);
1551                         *error = WSAEFAULT;
1552                         return;
1553                 }
1554
1555                 pfds [idx].fd = GPOINTER_TO_INT (Socket_to_SOCKET (obj));
1556                 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1557                 idx++;
1558         }
1559
1560         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1561         start = time (NULL);
1562         do {
1563                 *error = 0;
1564                 ret = mono_poll (pfds, nfds, timeout);
1565                 if (timeout > 0 && ret < 0) {
1566                         int err = errno;
1567                         int sec = time (NULL) - start;
1568
1569                         timeout -= sec * 1000;
1570                         if (timeout < 0)
1571                                 timeout = 0;
1572                         errno = err;
1573                 }
1574
1575                 if (ret == -1 && errno == EINTR) {
1576                         int leave = 0;
1577                         if (thread == NULL)
1578                                 thread = mono_thread_current ();
1579
1580                         mono_monitor_enter (thread->synch_lock);
1581                         leave = ((thread->state & ThreadState_AbortRequested) != 0 || 
1582                                  (thread->state & ThreadState_StopRequested) != 0);
1583                         mono_monitor_exit (thread->synch_lock);
1584                         if (leave != 0) {
1585                                 g_free (pfds);
1586                                 *sockets = NULL;
1587                                 return;
1588                         } else {
1589                                 /* Suspend requested? */
1590                                 mono_thread_interruption_checkpoint ();
1591                         }
1592                         errno = EINTR;
1593                 }
1594         } while (ret == -1 && errno == EINTR);
1595         
1596         if (ret == -1) {
1597 #ifdef PLATFORM_WIN32
1598                 *error = WSAGetLastError ();
1599 #else
1600                 *error = errno_to_WSA (errno, __func__);
1601 #endif
1602                 g_free (pfds);
1603                 return;
1604         }
1605
1606         if (ret == 0) {
1607                 g_free (pfds);
1608                 *sockets = NULL;
1609                 return;
1610         }
1611
1612         sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
1613         ret += 3; /* space for the NULL delimiters */
1614         socks = mono_array_new_full (mono_domain_get (), sock_arr_class, (guint32*)&ret, NULL);
1615         ret -= 3;
1616         mode = idx = 0;
1617         for (i = 0; i < count && ret > 0; i++) {
1618                 mono_pollfd *pfd;
1619
1620                 obj = mono_array_get (*sockets, MonoObject *, i);
1621                 if (obj == NULL) {
1622                         mode++;
1623                         idx++;
1624                         continue;
1625                 }
1626
1627                 pfd = &pfds [i - mode];
1628                 if (pfd->revents == 0)
1629                         continue;
1630
1631                 ret--;
1632                 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1633                         mono_array_setref (socks, idx++, obj);
1634                 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1635                         mono_array_setref (socks, idx++, obj);
1636                 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1637                         mono_array_setref (socks, idx++, obj);
1638                 }
1639         }
1640
1641         *sockets = socks;
1642         g_free (pfds);
1643 }
1644
1645 static MonoObject* int_to_object (MonoDomain *domain, int val)
1646 {
1647         return mono_value_box (domain, mono_get_int32_class (), &val);
1648 }
1649
1650
1651 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error)
1652 {
1653         int system_level;
1654         int system_name;
1655         int ret;
1656         int val;
1657         socklen_t valsize=sizeof(val);
1658         struct linger linger;
1659         socklen_t lingersize=sizeof(linger);
1660         int time_ms = 0;
1661         socklen_t time_ms_size = sizeof (time_ms);
1662 #ifdef SO_PEERCRED
1663         struct ucred cred;
1664         socklen_t credsize = sizeof(cred);
1665 #endif
1666         MonoDomain *domain=mono_domain_get();
1667         MonoObject *obj;
1668         MonoClass *obj_class;
1669         MonoClassField *field;
1670         
1671         MONO_ARCH_SAVE_REGS;
1672
1673         *error = 0;
1674         
1675         ret=convert_sockopt_level_and_name(level, name, &system_level,
1676                                            &system_name);
1677         if(ret==-1) {
1678                 *error = WSAENOPROTOOPT;
1679                 return;
1680         }
1681         if (ret == -2) {
1682                 *obj_val = int_to_object (domain, 0);
1683                 return;
1684         }
1685         
1686         /* No need to deal with MulticastOption names here, because
1687          * you cant getsockopt AddMembership or DropMembership (the
1688          * int getsockopt will error, causing an exception)
1689          */
1690         switch(name) {
1691         case SocketOptionName_Linger:
1692         case SocketOptionName_DontLinger:
1693                 ret = _wapi_getsockopt(sock, system_level, system_name, &linger,
1694                                &lingersize);
1695                 break;
1696                 
1697         case SocketOptionName_SendTimeout:
1698         case SocketOptionName_ReceiveTimeout:
1699                 ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
1700                 break;
1701
1702 #ifdef SO_PEERCRED
1703         case SocketOptionName_PeerCred: 
1704                 ret = _wapi_getsockopt (sock, system_level, system_name, &cred,
1705                                         &credsize);
1706                 break;
1707 #endif
1708
1709         default:
1710                 ret = _wapi_getsockopt (sock, system_level, system_name, &val,
1711                                &valsize);
1712         }
1713         
1714         if(ret==SOCKET_ERROR) {
1715                 *error = WSAGetLastError ();
1716                 return;
1717         }
1718         
1719         switch(name) {
1720         case SocketOptionName_Linger:
1721                 /* build a System.Net.Sockets.LingerOption */
1722                 obj_class=mono_class_from_name(system_assembly,
1723                                                "System.Net.Sockets",
1724                                                "LingerOption");
1725                 obj=mono_object_new(domain, obj_class);
1726                 
1727                 /* Locate and set the fields "bool enabled" and "int
1728                  * seconds"
1729                  */
1730                 field=mono_class_get_field_from_name(obj_class, "enabled");
1731                 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1732
1733                 field=mono_class_get_field_from_name(obj_class, "seconds");
1734                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1735                 
1736                 break;
1737                 
1738         case SocketOptionName_DontLinger:
1739                 /* construct a bool int in val - true if linger is off */
1740                 obj = int_to_object (domain, !linger.l_onoff);
1741                 break;
1742                 
1743         case SocketOptionName_SendTimeout:
1744         case SocketOptionName_ReceiveTimeout:
1745                 obj = int_to_object (domain, time_ms);
1746                 break;
1747
1748 #ifdef SO_PEERCRED
1749         case SocketOptionName_PeerCred: 
1750         {
1751                 /* build a Mono.Posix.PeerCred+PeerCredData if
1752                  * possible
1753                  */
1754                 static MonoImage *mono_posix_image = NULL;
1755                 MonoPeerCredData *cred_data;
1756                 
1757                 if (mono_posix_image == NULL) {
1758                         mono_posix_image=mono_image_loaded ("Mono.Posix");
1759                         if (!mono_posix_image) {
1760                                 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
1761                                 if (!sa) {
1762                                         *error = WSAENOPROTOOPT;
1763                                         return;
1764                                 } else {
1765                                         mono_posix_image = mono_assembly_get_image (sa);
1766                                 }
1767                         }
1768                 }
1769                 
1770                 obj_class = mono_class_from_name(mono_posix_image,
1771                                                  "Mono.Posix",
1772                                                  "PeerCredData");
1773                 obj = mono_object_new(domain, obj_class);
1774                 cred_data = (MonoPeerCredData *)obj;
1775                 cred_data->pid = cred.pid;
1776                 cred_data->uid = cred.uid;
1777                 cred_data->gid = cred.gid;
1778                 break;
1779         }
1780 #endif
1781
1782         default:
1783                 obj = int_to_object (domain, val);
1784         }
1785
1786         *obj_val=obj;
1787 }
1788
1789 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error)
1790 {
1791         int system_level;
1792         int system_name;
1793         int ret;
1794         guchar *buf;
1795         socklen_t valsize;
1796         
1797         MONO_ARCH_SAVE_REGS;
1798
1799         *error = 0;
1800         
1801         ret=convert_sockopt_level_and_name(level, name, &system_level,
1802                                            &system_name);
1803         if(ret==-1) {
1804                 *error = WSAENOPROTOOPT;
1805                 return;
1806         }
1807         if(ret==-2)
1808                 return;
1809
1810         valsize=mono_array_length(*byte_val);
1811         buf=mono_array_addr(*byte_val, guchar, 0);
1812         
1813         ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
1814         if(ret==SOCKET_ERROR) {
1815                 *error = WSAGetLastError ();
1816         }
1817 }
1818
1819 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1820 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1821 {
1822         struct in_addr inaddr;
1823         MonoClassField *field;
1824         
1825         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
1826
1827         /* No idea why .net uses a 64bit type to hold a 32bit value...
1828          *
1829          * Internal value of IPAddess is in little-endian order
1830          */
1831         inaddr.s_addr=GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr)+field->offset));
1832         
1833         return(inaddr);
1834 }
1835 #endif
1836
1837 #ifdef AF_INET6
1838 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
1839 {
1840         struct in6_addr in6addr;
1841         MonoClassField *field;
1842         MonoArray *data;
1843         int i;
1844
1845         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
1846         data=*(MonoArray **)(((char *)ipaddr) + field->offset);
1847
1848 /* Solaris has only the 8 bit version. */
1849 #ifndef s6_addr16
1850         for(i=0; i<8; i++) {
1851                 guint16 s = mono_array_get (data, guint16, i);
1852                 in6addr.s6_addr[2 * i] = (s >> 8) & 0xff;
1853                 in6addr.s6_addr[2 * i + 1] = s & 0xff;
1854         }
1855 #else
1856         for(i=0; i<8; i++)
1857                 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
1858 #endif
1859         return(in6addr);
1860 }
1861 #endif /* AF_INET6 */
1862
1863 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)
1864 {
1865         int system_level;
1866         int system_name;
1867         int ret;
1868 #ifdef AF_INET6
1869         int sol_ip;
1870         int sol_ipv6;
1871
1872         *error = 0;
1873         
1874 #ifdef HAVE_SOL_IPV6
1875         sol_ipv6 = SOL_IPV6;
1876 #else
1877         {
1878                 struct protoent *pent;
1879                 pent = getprotobyname ("ipv6");
1880                 sol_ipv6 = (pent != NULL) ? pent->p_proto : 41;
1881         }
1882 #endif
1883
1884 #ifdef HAVE_SOL_IP
1885         sol_ip = SOL_IP;
1886 #else
1887         {
1888                 struct protoent *pent;
1889                 pent = getprotobyname ("ip");
1890                 sol_ip = (pent != NULL) ? pent->p_proto : 0;
1891         }
1892 #endif
1893 #endif /* AF_INET6 */
1894
1895         MONO_ARCH_SAVE_REGS;
1896
1897         ret=convert_sockopt_level_and_name(level, name, &system_level,
1898                                            &system_name);
1899         if(ret==-1) {
1900                 *error = WSAENOPROTOOPT;
1901                 return;
1902         }
1903         if(ret==-2){
1904                 return;
1905         }
1906
1907         /* Only one of obj_val, byte_val or int_val has data */
1908         if(obj_val!=NULL) {
1909                 MonoClassField *field;
1910                 struct linger linger;
1911                 int valsize;
1912                 
1913                 switch(name) {
1914                 case SocketOptionName_DontLinger:
1915                         linger.l_onoff=0;
1916                         linger.l_linger=0;
1917                         valsize=sizeof(linger);
1918                         ret = _wapi_setsockopt (sock, system_level,
1919                                                 system_name, &linger, valsize);
1920                         break;
1921                         
1922                 case SocketOptionName_Linger:
1923                         /* Dig out "bool enabled" and "int seconds"
1924                          * fields
1925                          */
1926                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1927                         linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1928                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1929                         linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1930                         
1931                         valsize=sizeof(linger);
1932                         ret = _wapi_setsockopt (sock, system_level,
1933                                                 system_name, &linger, valsize);
1934                         break;
1935                 case SocketOptionName_AddMembership:
1936                 case SocketOptionName_DropMembership:
1937 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1938                 {
1939                         MonoObject *address = NULL;
1940
1941 #ifdef AF_INET6
1942                         if(system_level == sol_ipv6) {
1943                                 struct ipv6_mreq mreq6;
1944
1945                                 /*
1946                                  *      Get group address
1947                                  */
1948                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1949                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1950                                 
1951                                 if(address) {
1952                                         mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
1953                                 }
1954
1955                                 field=mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
1956                                 mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
1957
1958                                 ret = _wapi_setsockopt (sock, system_level,
1959                                                         system_name, &mreq6,
1960                                                         sizeof (mreq6));
1961                         } else if(system_level == sol_ip)
1962 #endif /* AF_INET6 */
1963                         {
1964 #ifdef HAVE_STRUCT_IP_MREQN
1965                                 struct ip_mreqn mreq = {{0}};
1966 #else
1967                                 struct ip_mreq mreq = {{0}};
1968 #endif /* HAVE_STRUCT_IP_MREQN */
1969                         
1970                                 /* pain! MulticastOption holds two IPAddress
1971                                  * members, so I have to dig the value out of
1972                                  * those :-(
1973                                  */
1974                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1975                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1976
1977                                 /* address might not be defined and if so, set the address to ADDR_ANY.
1978                                  */
1979                                 if(address) {
1980                                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
1981                                 }
1982
1983                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1984                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
1985
1986 #ifdef HAVE_STRUCT_IP_MREQN
1987                                 if(address) {
1988                                         mreq.imr_address = ipaddress_to_struct_in_addr (address);
1989                                 }
1990 #else
1991                                 if(address) {
1992                                         mreq.imr_interface = ipaddress_to_struct_in_addr (address);
1993                                 }
1994 #endif /* HAVE_STRUCT_IP_MREQN */
1995                         
1996                                 ret = _wapi_setsockopt (sock, system_level,
1997                                                         system_name, &mreq,
1998                                                         sizeof (mreq));
1999                         }
2000                         break;
2001                 }
2002 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2003                 default:
2004                         /* Cause an exception to be thrown */
2005                         *error = WSAEINVAL;
2006                         return;
2007                 }
2008         } else if (byte_val!=NULL) {
2009                 int valsize=mono_array_length(byte_val);
2010                 guchar *buf=mono_array_addr(byte_val, guchar, 0);
2011         
2012                 ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
2013                 if(ret==SOCKET_ERROR) {
2014                         *error = WSAGetLastError ();
2015                         return;
2016                 }
2017         } else {
2018                 /* ReceiveTimeout/SendTimeout get here */
2019                 switch(name) {
2020                 case SocketOptionName_DontFragment:
2021 #ifdef HAVE_IP_MTU_DISCOVER
2022                         /* Fiddle with the value slightly if we're
2023                          * turning DF on
2024                          */
2025                         if (int_val == 1) {
2026                                 int_val = IP_PMTUDISC_DO;
2027                         }
2028                         /* Fall through */
2029 #endif
2030                         
2031                 default:
2032                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2033                 }
2034         }
2035
2036         if(ret==SOCKET_ERROR) {
2037                 *error = WSAGetLastError ();
2038         }
2039 }
2040
2041 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
2042                                                            gint32 how,
2043                                                            gint32 *error)
2044 {
2045         int ret;
2046         
2047         MONO_ARCH_SAVE_REGS;
2048
2049         *error = 0;
2050         
2051         /* Currently, the values for how (recv=0, send=1, both=2) match
2052          * the BSD API
2053          */
2054         ret = _wapi_shutdown (sock, how);
2055         if(ret==SOCKET_ERROR) {
2056                 *error = WSAGetLastError ();
2057         }
2058 }
2059
2060 gint
2061 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
2062                                               MonoArray *input,
2063                                               MonoArray *output, gint32 *error)
2064 {
2065         glong output_bytes = 0;
2066         gchar *i_buffer, *o_buffer;
2067         gint i_len, o_len;
2068         gint ret;
2069
2070         MONO_ARCH_SAVE_REGS;
2071
2072         *error = 0;
2073         
2074         if (code == FIONBIO) {
2075                 /* Invalid command. Must use Socket.Blocking */
2076                 return -1;
2077         }
2078
2079         if (input == NULL) {
2080                 i_buffer = NULL;
2081                 i_len = 0;
2082         } else {
2083                 i_buffer = mono_array_addr (input, gchar, 0);
2084                 i_len = mono_array_length (input);
2085         }
2086
2087         if (output == NULL) {
2088                 o_buffer = NULL;
2089                 o_len = 0;
2090         } else {
2091                 o_buffer = mono_array_addr (output, gchar, 0);
2092                 o_len = mono_array_length (output);
2093         }
2094
2095         ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2096         if (ret == SOCKET_ERROR) {
2097                 *error = WSAGetLastError ();
2098                 return(-1);
2099         }
2100
2101         return (gint) output_bytes;
2102 }
2103
2104 #ifdef HAVE_SIOCGIFCONF
2105 static gboolean
2106 is_loopback (int family, void *ad)
2107 {
2108         char *ptr = (char *) ad;
2109
2110         if (family == AF_INET) {
2111                 return (ptr [0] == 127);
2112         }
2113 #ifdef AF_INET6
2114         else {
2115                 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
2116         }
2117 #endif
2118         return FALSE;
2119 }
2120
2121 static void *
2122 get_local_ips (int family, int *nips)
2123 {
2124         int addr_size, offset, fd, i, count;
2125         int max_ifaces = 50; /* 50 interfaces should be enough... */
2126         struct ifconf ifc;
2127         struct ifreq *ifr;
2128         struct ifreq iflags;
2129         char *result, *tmp_ptr;
2130         gboolean ignore_loopback = FALSE;
2131
2132         *nips = 0;
2133         if (family == AF_INET) {
2134                 addr_size = sizeof (struct in_addr);
2135                 offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
2136 #ifdef AF_INET6
2137         } else if (family == AF_INET6) {
2138                 addr_size = sizeof (struct in6_addr);
2139                 offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
2140 #endif
2141         } else {
2142                 return NULL;
2143         }
2144
2145         fd = socket (family, SOCK_STREAM, 0);
2146
2147         ifc.ifc_len = max_ifaces * sizeof (struct ifreq);
2148         ifc.ifc_buf = g_malloc (ifc.ifc_len);
2149         if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
2150                 close (fd);
2151                 g_free (ifc.ifc_buf);
2152                 return NULL;
2153         }
2154
2155         count = ifc.ifc_len / sizeof (struct ifreq);
2156         *nips = count;
2157         if (count == 0) {
2158                 g_free (ifc.ifc_buf);
2159                 close (fd);
2160                 return NULL;
2161         }
2162
2163         for (i = 0, ifr = ifc.ifc_req; i < *nips; i++, ifr++) {
2164                 strcpy (iflags.ifr_name, ifr->ifr_name);
2165                 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
2166                         continue;
2167                 }
2168
2169                 if ((iflags.ifr_flags & IFF_UP) == 0) {
2170                         ifr->ifr_name [0] = '\0';
2171                         continue;
2172                 }
2173
2174                 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
2175                         ignore_loopback = TRUE;
2176                 }
2177         }
2178
2179         close (fd);
2180         result = g_malloc (addr_size * count);
2181         tmp_ptr = result;
2182         for (i = 0, ifr = ifc.ifc_req; i < count; i++, ifr++) {
2183                 if (ifr->ifr_name [0] == '\0') {
2184                         (*nips)--;
2185                         continue;
2186                 }
2187
2188                 if (ignore_loopback && is_loopback (family, ((char *) &ifr->ifr_addr) + offset)) {
2189                         (*nips)--;
2190                         continue;
2191                 }
2192
2193                 memcpy (tmp_ptr, ((char *) &ifr->ifr_addr) + offset, addr_size);
2194                 tmp_ptr += addr_size;
2195         }
2196
2197         g_free (ifc.ifc_buf);
2198         return result;
2199 }
2200 #else
2201 static void *
2202 get_local_ips (int family, int *nips)
2203 {
2204         *nips = 0;
2205         return NULL;
2206 }
2207
2208 #endif /* HAVE_SIOCGIFCONF */
2209
2210 #ifndef AF_INET6
2211 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
2212                                        MonoArray **h_aliases,
2213                                        MonoArray **h_addr_list,
2214                                        gboolean add_local_ips)
2215 {
2216         MonoDomain *domain = mono_domain_get ();
2217         int i;
2218         struct in_addr *local_in = NULL;
2219         int nlocal_in = 0;
2220
2221         if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
2222                 return(FALSE);
2223         }
2224
2225         *h_name=mono_string_new(domain, he->h_name);
2226
2227         i=0;
2228         while(he->h_aliases[i]!=NULL) {
2229                 i++;
2230         }
2231         
2232         *h_aliases=mono_array_new(domain, mono_get_string_class (), i);
2233         i=0;
2234         while(he->h_aliases[i]!=NULL) {
2235                 MonoString *alias;
2236                 
2237                 alias=mono_string_new(domain, he->h_aliases[i]);
2238                 mono_array_setref (*h_aliases, i, alias);
2239                 i++;
2240         }
2241
2242         if (add_local_ips) {
2243                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2244                 if (nlocal_in) {
2245                         *h_addr_list = mono_array_new(domain, mono_get_string_class (), nlocal_in);
2246                         for (i = 0; i < nlocal_in; i++) {
2247                                 MonoString *addr_string;
2248                                 char addr [16], *ptr;
2249                                 
2250                                 ptr = (char *) &local_in [i];
2251                                 g_snprintf(addr, 16, "%u.%u.%u.%u",
2252                                          (unsigned char) ptr [0],
2253                                          (unsigned char) ptr [1],
2254                                          (unsigned char) ptr [2],
2255                                          (unsigned char) ptr [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                         g_free (local_in);
2263                 }
2264         }
2265         
2266         if (nlocal_in == 0) {
2267                 i = 0;
2268                 while (he->h_addr_list[i]!=NULL) {
2269                         i++;
2270                 }
2271
2272                 *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
2273                 i=0;
2274                 while(he->h_addr_list[i]!=NULL) {
2275                         MonoString *addr_string;
2276                         char addr[16];
2277                         
2278                         g_snprintf(addr, 16, "%u.%u.%u.%u",
2279                                  (unsigned char)he->h_addr_list[i][0],
2280                                  (unsigned char)he->h_addr_list[i][1],
2281                                  (unsigned char)he->h_addr_list[i][2],
2282                                  (unsigned char)he->h_addr_list[i][3]);
2283                         
2284                         addr_string=mono_string_new(domain, addr);
2285                         mono_array_setref (*h_addr_list, i, addr_string);
2286                         i++;
2287                 }
2288         }
2289
2290         return(TRUE);
2291 }
2292
2293 static gboolean ipaddr_to_IPHostEntry(const char *addr, MonoString **h_name,
2294                                       MonoArray **h_aliases,
2295                                       MonoArray **h_addr_list)
2296 {
2297         MonoDomain *domain = mono_domain_get ();
2298
2299         *h_name=mono_string_new(domain, addr);
2300         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2301         *h_addr_list=mono_array_new(domain, mono_get_string_class (), 1);
2302         mono_array_setref (*h_addr_list, 0, *h_name);
2303
2304         return(TRUE);
2305 }
2306 #endif
2307
2308 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2309 static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name,
2310                                 MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
2311 {
2312         MonoDomain *domain = mono_domain_get ();
2313         int i, host_count, host_index, family_hint;
2314         struct in_addr *local_in = NULL;
2315         int nlocal_in = 0;
2316         struct in6_addr *local_in6 = NULL;
2317         int nlocal_in6 = 0;
2318         gboolean from_local = FALSE;
2319
2320         family_hint = get_family_hint ();
2321
2322         if(he1 == NULL && he2 == NULL) {
2323                 return(FALSE);
2324         }
2325
2326         /*
2327          * Check if address length and family are correct
2328          */
2329         if (he1 != NULL && (he1->h_length!=4 || he1->h_addrtype!=AF_INET)) {
2330                 return(FALSE);
2331         }
2332
2333         if (he2 != NULL && (he2->h_length!=16 || he2->h_addrtype!=AF_INET6)) {
2334                 return(FALSE);
2335         }
2336
2337         /*
2338          * Get the aliases and host name from he1 or he2 whichever is
2339          * not null, if he1 is not null then take aliases from he1
2340          */
2341         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2342                             family_hint == PF_INET)) {
2343                 *h_name=mono_string_new (domain, he1->h_name);
2344
2345                 i=0;
2346                 while(he1->h_aliases[i]!=NULL) {
2347                         i++;
2348                 }
2349
2350                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2351                                            i);
2352                 i=0;
2353                 while(he1->h_aliases[i]!=NULL) {
2354                         MonoString *alias;
2355
2356                         alias=mono_string_new (domain, he1->h_aliases[i]);
2357                         mono_array_setref (*h_aliases, i, alias);
2358                         i++;
2359                 }
2360         } else if (he2 != NULL && (family_hint == PF_UNSPEC ||
2361                                    family_hint == PF_INET6)) {
2362                 *h_name=mono_string_new (domain, he2->h_name);
2363
2364                 i=0;
2365                 while(he2->h_aliases [i] != NULL) {
2366                         i++;
2367                 }
2368
2369                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2370                                            i);
2371                 i=0;
2372                 while(he2->h_aliases[i]!=NULL) {
2373                         MonoString *alias;
2374
2375                         alias=mono_string_new (domain, he2->h_aliases[i]);
2376                         mono_array_setref (*h_aliases, i, alias);
2377                         i++;
2378                 }
2379         } else {
2380                 return(FALSE);
2381         }
2382
2383         /*
2384          * Count the number of addresses in he1 + he2
2385          */
2386         host_count = 0;
2387         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2388                             family_hint == PF_INET)) {
2389                 i=0;
2390                 while(he1->h_addr_list[i]!=NULL) {
2391                         i++;
2392                         host_count++;
2393                 }
2394         }
2395
2396         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2397                             family_hint == PF_INET6)) {
2398                 i=0;
2399                 while(he2->h_addr_list[i]!=NULL) {
2400                         i++;
2401                         host_count++;
2402                 }
2403         }
2404
2405         /*
2406          * Fills the array
2407          */
2408         host_index = 0;
2409         if (add_local_ips) {
2410                 if (family_hint == PF_UNSPEC || family_hint == PF_INET)
2411                         local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2412
2413                 if (family_hint == PF_UNSPEC || family_hint == PF_INET6)
2414                         local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2415
2416                 if (nlocal_in || nlocal_in6) {
2417                         from_local = TRUE;
2418                         *h_addr_list = mono_array_new (domain, mono_get_string_class (),
2419                                                              nlocal_in + nlocal_in6);
2420
2421                         if (nlocal_in6) {
2422                                 int n;
2423                                 for (n = 0; n < nlocal_in6; n++) {
2424                                         MonoString *addr_string;
2425                                         const char *ret;
2426                                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2427
2428                                         ret = inet_ntop (AF_INET6, &local_in6 [n], addr, sizeof(addr));
2429
2430                                         if (ret != NULL) {
2431                                                 addr_string = mono_string_new (domain, addr);
2432                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2433                                                 host_index++;
2434                                         }
2435                                 }
2436                         }
2437
2438                         if (nlocal_in) {
2439                                 int n;
2440                                 for (n = 0; n < nlocal_in; n++) {
2441                                         MonoString *addr_string;
2442                                         const char *ret;
2443                                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2444
2445                                         ret = inet_ntop (AF_INET, &local_in [n], addr, sizeof(addr));
2446
2447                                         if (ret != NULL) {
2448                                                 addr_string = mono_string_new (domain, addr);
2449                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2450                                                 host_index++;
2451                                         }
2452                                 }
2453                         }
2454                         g_free (local_in);
2455                         g_free (local_in6);
2456                         return TRUE;
2457                 }
2458
2459                 g_free (local_in);
2460                 g_free (local_in6);
2461         }
2462
2463         *h_addr_list=mono_array_new (domain, mono_get_string_class (), host_count);
2464
2465         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2466                             family_hint == PF_INET6)) {
2467                 i = 0;
2468                 while(he2->h_addr_list[i] != NULL) {
2469                         MonoString *addr_string;
2470                         const char *ret;
2471                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2472
2473                         ret = inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
2474                                          sizeof(addr));
2475
2476                         if (ret != NULL) {
2477                                 addr_string = mono_string_new (domain, addr);
2478                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2479                                 i++;
2480                                 host_index++;
2481                         }
2482                 }
2483         }
2484
2485         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2486                             family_hint == PF_INET)) {
2487                 i=0;
2488                 while(he1->h_addr_list[i] != NULL) {
2489                         MonoString *addr_string;
2490                         const char *ret;
2491                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2492
2493                         ret = inet_ntop (AF_INET, he1->h_addr_list[i], addr,
2494                                          sizeof(addr));
2495
2496                         if (ret != NULL) {
2497                                 addr_string=mono_string_new (domain, addr);
2498                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2499                                 i++;
2500                                 host_index++;
2501                         }
2502                 }
2503         }
2504
2505         return(TRUE);
2506 }
2507 #endif
2508
2509 #if defined(AF_INET6)
2510 static gboolean 
2511 addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
2512                                                 MonoArray **h_aliases,
2513                                                 MonoArray **h_addr_list,
2514                                                 gboolean add_local_ips)
2515 {
2516         gint32 count, i;
2517         struct addrinfo *ai = NULL;
2518         struct in_addr *local_in = NULL;
2519         int nlocal_in = 0;
2520         struct in6_addr *local_in6 = NULL;
2521         int nlocal_in6 = 0;
2522         int addr_index;
2523
2524         MonoDomain *domain = mono_domain_get ();
2525
2526         addr_index = 0;
2527         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2528         if (add_local_ips) {
2529                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2530                 local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2531                 if (nlocal_in || nlocal_in6) {
2532                         *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
2533                         if (nlocal_in) {
2534                                 MonoString *addr_string;
2535                                 char addr [16];
2536                                 int i;
2537
2538                                 for (i = 0; i < nlocal_in; i++) {
2539                                         inet_ntop (AF_INET, &local_in [i], addr, sizeof (addr));
2540                                         addr_string = mono_string_new (domain, addr);
2541                                         mono_array_setref (*h_addr_list, addr_index, addr_string);
2542                                         addr_index++;
2543                                 }
2544                         }
2545
2546                         if (nlocal_in6) {
2547                                 MonoString *addr_string;
2548                                 const char *ret;
2549                                 char addr [48];
2550                                 int i;
2551
2552                                 for (i = 0; i < nlocal_in6; i++) {
2553                                         ret = inet_ntop (AF_INET6, &local_in6 [i], addr, sizeof (addr));
2554                                         if (ret != NULL) {
2555                                                 addr_string = mono_string_new (domain, addr);
2556                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2557                                                 addr_index++;
2558                                         }
2559                                 }
2560                         }
2561
2562                         g_free (local_in);
2563                         g_free (local_in6);
2564                         if (info) {
2565                                 freeaddrinfo (info);
2566                         }
2567                         return TRUE;
2568                 }
2569
2570                 g_free (local_in);
2571                 g_free (local_in6);
2572         }
2573
2574         for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
2575                 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2576                         continue;
2577
2578                 count++;
2579         }
2580
2581         *h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
2582
2583         for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
2584                 MonoString *addr_string;
2585                 const char *ret;
2586                 char buffer [48]; /* Max. size for IPv6 */
2587
2588                 if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
2589                         continue;
2590                 }
2591
2592                 if(ai->ai_family == PF_INET) {
2593                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, 16);
2594                 } else {
2595                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, 48);
2596                 }
2597
2598                 if(ret) {
2599                         addr_string=mono_string_new(domain, buffer);
2600                 } else {
2601                         addr_string=mono_string_new(domain, "");
2602                 }
2603
2604                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2605
2606                 if(!i && ai->ai_canonname != NULL) {
2607                         *h_name=mono_string_new(domain, ai->ai_canonname);
2608                 }
2609
2610                 addr_index++;
2611         }
2612
2613         if(info) {
2614                 freeaddrinfo(info);
2615         }
2616
2617         return(TRUE);
2618 }
2619 #endif
2620
2621 #ifdef AF_INET6
2622 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2623 {
2624         gboolean add_local_ips = FALSE;
2625 #ifdef HAVE_SIOCGIFCONF
2626         gchar this_hostname [256];
2627 #endif
2628 #if !defined(HAVE_GETHOSTBYNAME2_R)
2629         struct addrinfo *info = NULL, hints;
2630         char *hostname;
2631         
2632         MONO_ARCH_SAVE_REGS;
2633         
2634         hostname=mono_string_to_utf8 (host);
2635 #ifdef HAVE_SIOCGIFCONF
2636         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2637                 if (!strcmp (hostname, this_hostname))
2638                         add_local_ips = TRUE;
2639         }
2640 #endif
2641
2642         memset(&hints, 0, sizeof(hints));
2643         hints.ai_family = get_family_hint ();
2644         hints.ai_socktype = SOCK_STREAM;
2645         hints.ai_flags = AI_CANONNAME;
2646
2647         if (getaddrinfo(hostname, NULL, &hints, &info) == -1) {
2648                 return(FALSE);
2649         }
2650         
2651         g_free(hostname);
2652
2653         return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips));
2654 #else
2655         struct hostent he1,*hp1, he2, *hp2;
2656         int buffer_size1, buffer_size2;
2657         char *buffer1, *buffer2;
2658         int herr;
2659         gboolean return_value;
2660         char *hostname;
2661         
2662         MONO_ARCH_SAVE_REGS;
2663         
2664         hostname=mono_string_to_utf8 (host);
2665
2666 #ifdef HAVE_SIOCGIFCONF
2667         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2668                 if (!strcmp (hostname, this_hostname))
2669                         add_local_ips = TRUE;
2670         }
2671 #endif
2672
2673         buffer_size1 = 512;
2674         buffer_size2 = 512;
2675         buffer1 = g_malloc0(buffer_size1);
2676         buffer2 = g_malloc0(buffer_size2);
2677
2678         while (gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1,
2679                                 &hp1, &herr) == ERANGE) {
2680                 buffer_size1 *= 2;
2681                 buffer1 = g_realloc(buffer1, buffer_size1);
2682         }
2683
2684         if (hp1 == NULL)
2685         {
2686                 while (gethostbyname2_r(hostname, AF_INET6, &he2, buffer2,
2687                                         buffer_size2, &hp2, &herr) == ERANGE) {
2688                         buffer_size2 *= 2;
2689                         buffer2 = g_realloc(buffer2, buffer_size2);
2690                 }
2691         }
2692         else
2693                 hp2 = NULL;
2694
2695         return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
2696                                                h_addr_list, add_local_ips);
2697
2698         g_free(buffer1);
2699         g_free(buffer2);
2700         g_free(hostname);
2701
2702         return(return_value);
2703 #endif /* HAVE_GETHOSTBYNAME2_R */
2704 }
2705 #else /* AF_INET6 */
2706 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2707 {
2708         struct hostent *he;
2709         char *hostname;
2710         gboolean add_local_ips = FALSE;
2711 #ifdef HAVE_SIOCGIFCONF
2712         gchar this_hostname [256];
2713 #endif
2714         
2715         MONO_ARCH_SAVE_REGS;
2716
2717         hostname=mono_string_to_utf8(host);
2718 #ifdef HAVE_SIOCGIFCONF
2719         if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2720                 if (!strcmp (hostname, this_hostname))
2721                         add_local_ips = TRUE;
2722         }
2723 #endif
2724
2725         he = _wapi_gethostbyname (hostname);
2726         g_free(hostname);
2727
2728         if(he==NULL) {
2729                 return(FALSE);
2730         }
2731
2732         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips));
2733 }
2734 #endif /* AF_INET6 */
2735
2736 #ifndef HAVE_INET_PTON
2737 static int
2738 inet_pton (int family, const char *address, void *inaddrp)
2739 {
2740         if (family == AF_INET) {
2741 #ifdef HAVE_INET_ATON
2742                 struct in_addr inaddr;
2743                 
2744                 if (!inet_aton (address, &inaddr))
2745                         return 0;
2746                 
2747                 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
2748                 return 1;
2749 #else
2750                 /* assume the system has inet_addr(), if it doesn't
2751                    have that we're pretty much screwed... */
2752                 guint32 inaddr;
2753                 
2754                 if (!strcmp (address, "255.255.255.255")) {
2755                         /* special-case hack */
2756                         inaddr = 0xffffffff;
2757                 } else {
2758                         inaddr = inet_addr (address);
2759 #ifndef INADDR_NONE
2760 #define INADDR_NONE ((in_addr_t) -1)
2761 #endif
2762                         if (inaddr == INADDR_NONE)
2763                                 return 0;
2764                 }
2765                 
2766                 memcpy (inaddrp, &inaddr, sizeof (guint32));
2767                 return 1;
2768 #endif /* HAVE_INET_ATON */
2769         }
2770         
2771         return -1;
2772 }
2773 #endif /* !HAVE_INET_PTON */
2774
2775 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2776 {
2777         char *address;
2778         const char *version;
2779         gboolean v1;
2780         
2781 #ifdef AF_INET6
2782         struct sockaddr_in saddr;
2783         struct sockaddr_in6 saddr6;
2784         struct addrinfo *info = NULL, hints;
2785         gint32 family;
2786         char hostname[1024] = {0};
2787         int flags = 0;
2788 #else
2789         struct in_addr inaddr;
2790         struct hostent *he;
2791         gboolean ret;
2792 #endif
2793
2794         MONO_ARCH_SAVE_REGS;
2795
2796         version = mono_get_runtime_info ()->framework_version;
2797         v1 = (version[0] == '1');
2798
2799         address = mono_string_to_utf8 (addr);
2800
2801 #ifdef AF_INET6
2802         if (inet_pton (AF_INET, address, &saddr.sin_addr ) <= 0) {
2803                 /* Maybe an ipv6 address */
2804                 if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) <= 0) {
2805                         g_free (address);
2806                         return FALSE;
2807                 }
2808                 else {
2809                         family = AF_INET6;
2810                         saddr6.sin6_family = AF_INET6;
2811                 }
2812         }
2813         else {
2814                 family = AF_INET;
2815                 saddr.sin_family = AF_INET;
2816         }
2817         g_free(address);
2818
2819         if (v1) {
2820                 flags = NI_NAMEREQD;
2821         }
2822         
2823         if(family == AF_INET) {
2824                 if(getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr),
2825                                 hostname, sizeof(hostname), NULL, 0,
2826                                 flags) != 0) {
2827                         return(FALSE);
2828                 }
2829         } else if(family == AF_INET6) {
2830                 if(getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6),
2831                                 hostname, sizeof(hostname), NULL, 0,
2832                                 flags) != 0) {
2833                         return(FALSE);
2834                 }
2835         }
2836
2837         memset (&hints, 0, sizeof(hints));
2838         hints.ai_family = get_family_hint ();
2839         hints.ai_socktype = SOCK_STREAM;
2840         hints.ai_flags = AI_CANONNAME;
2841
2842         if( getaddrinfo (hostname, NULL, &hints, &info) == -1 ) {
2843                 return(FALSE);
2844         }
2845
2846         return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE));
2847 #else
2848         if (inet_pton (AF_INET, address, &inaddr) <= 0) {
2849                 g_free (address);
2850                 return(FALSE);
2851         }
2852
2853         if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) {
2854                 if (v1) {
2855                         ret = FALSE;
2856                 } else {
2857                         ret = ipaddr_to_IPHostEntry (address, h_name,
2858                                                      h_aliases, h_addr_list);
2859                 }
2860         } else {
2861                 ret = hostent_to_IPHostEntry (he, h_name, h_aliases,
2862                                               h_addr_list, FALSE);
2863         }
2864
2865         g_free (address);
2866         return(ret);
2867 #endif
2868 }
2869
2870 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
2871 {
2872         gchar hostname[256];
2873         int ret;
2874         
2875         MONO_ARCH_SAVE_REGS;
2876
2877         ret = gethostname (hostname, sizeof (hostname));
2878         if(ret==-1) {
2879                 return(FALSE);
2880         }
2881         
2882         *h_name=mono_string_new(mono_domain_get (), hostname);
2883
2884         return(TRUE);
2885 }
2886
2887 void mono_network_init(void)
2888 {
2889         WSADATA wsadata;
2890         int err;
2891         
2892         err=WSAStartup(MAKEWORD(2,0), &wsadata);
2893         if(err!=0) {
2894                 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
2895                 exit(-1);
2896         }
2897
2898 #ifdef DEBUG
2899         g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
2900         g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
2901 #endif
2902 }
2903
2904 void mono_network_cleanup(void)
2905 {
2906         WSACleanup();
2907 }
2908