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