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