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