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