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