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