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