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