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