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