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