6071a0cab1b91798f58cc0bb7f52bcb02f1801fe
[mono.git] / mono / metadata / socket-io.c
1 /*
2  * socket-io.c: Socket IO internal calls
3  *
4  * Authors:
5  *      Dick Porter (dick@ximian.com)
6  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7  *
8  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  */
11
12 #include <config.h>
13
14 #ifndef DISABLE_SOCKETS
15
16 #ifdef __APPLE__
17 #define __APPLE_USE_RFC_3542
18 #endif
19
20 #include <glib.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #include <errno.h>
27
28 #include <sys/types.h>
29 #ifndef HOST_WIN32 
30 #include <sys/socket.h>
31 #include <sys/ioctl.h>
32 #include <netinet/in.h>
33 #include <netinet/tcp.h>
34 #include <netdb.h>
35 #include <arpa/inet.h>
36 #endif
37
38 #include <mono/metadata/object.h>
39 #include <mono/io-layer/io-layer.h>
40 #include <mono/metadata/socket-io.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/assembly.h>
43 #include <mono/metadata/appdomain.h>
44 #include <mono/metadata/file-io.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threads-types.h>
47 #include <mono/utils/mono-poll.h>
48 /* FIXME change this code to not mess so much with the internals */
49 #include <mono/metadata/class-internals.h>
50 #include <mono/metadata/threadpool-internals.h>
51 #include <mono/metadata/domain-internals.h>
52 #include <mono/utils/mono-threads.h>
53
54 #include <time.h>
55 #ifdef HAVE_SYS_TIME_H
56 #include <sys/time.h>
57 #endif
58 #ifdef HAVE_SYS_IOCTL_H
59 #include <sys/ioctl.h>
60 #endif
61 #ifdef HAVE_NET_IF_H
62 #include <net/if.h>
63 #endif
64
65 #ifdef HAVE_NETDB_H
66 #include <netdb.h>
67 #endif
68 #ifdef HAVE_SYS_FILIO_H
69 #include <sys/filio.h>     /* defines FIONBIO and FIONREAD */
70 #endif
71 #ifdef HAVE_SYS_SOCKIO_H
72 #include <sys/sockio.h>    /* defines SIOCATMARK */
73 #endif
74 #ifdef HAVE_SYS_UN_H
75 #include <sys/un.h>
76 #endif
77
78 #ifdef HAVE_GETIFADDRS
79 // <net/if.h> must be included before <ifaddrs.h>
80 #include <ifaddrs.h>
81 #endif
82
83 #include "mono/io-layer/socket-wrappers.h"
84
85 #if defined(HOST_WIN32)
86 /* This is a kludge to make this file build under cygwin:
87  * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
88  * prototypes for some but not all required functions (notably
89  * inet_ntop() is missing), but the libws2_32 library is missing the
90  * actual implementations of these functions.
91  */
92 #undef AF_INET6
93 #endif
94
95 #ifdef PLATFORM_ANDROID
96 // not yet actually implemented...
97 #undef AF_INET6
98 #endif
99
100 #define LOGDEBUG(...)  
101 /* define LOGDEBUG(...) g_message(__VA_ARGS__)  */
102
103 /* 
104  * Some older versions of libc provide IPV6 support without defining the AI_ADDRCONFIG
105  * flag for getaddrinfo.
106  */
107 #ifndef AI_ADDRCONFIG
108 #define AI_ADDRCONFIG 0
109 #endif
110
111 static gint32 convert_family(MonoAddressFamily mono_family)
112 {
113         gint32 family=-1;
114         
115         switch(mono_family) {
116         case AddressFamily_Unknown:
117         case AddressFamily_ImpLink:
118         case AddressFamily_Pup:
119         case AddressFamily_Chaos:
120         case AddressFamily_Iso:
121         case AddressFamily_Ecma:
122         case AddressFamily_DataKit:
123         case AddressFamily_Ccitt:
124         case AddressFamily_DataLink:
125         case AddressFamily_Lat:
126         case AddressFamily_HyperChannel:
127         case AddressFamily_NetBios:
128         case AddressFamily_VoiceView:
129         case AddressFamily_FireFox:
130         case AddressFamily_Banyan:
131         case AddressFamily_Atm:
132         case AddressFamily_Cluster:
133         case AddressFamily_Ieee12844:
134         case AddressFamily_NetworkDesigners:
135                 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
136                 break;
137                 
138         case AddressFamily_Unspecified:
139                 family=AF_UNSPEC;
140                 break;
141                 
142         case AddressFamily_Unix:
143                 family=AF_UNIX;
144                 break;
145                 
146         case AddressFamily_InterNetwork:
147                 family=AF_INET;
148                 break;
149                 
150         case AddressFamily_Ipx:
151 #ifdef AF_IPX
152                 family=AF_IPX;
153 #endif
154                 break;
155                 
156         case AddressFamily_Sna:
157 #ifdef AF_SNA
158                 family=AF_SNA;
159 #endif
160                 break;
161                 
162         case AddressFamily_DecNet:
163 #ifdef AF_DECnet
164                 family=AF_DECnet;
165 #endif
166                 break;
167                 
168         case AddressFamily_AppleTalk:
169                 family=AF_APPLETALK;
170                 break;
171                 
172         case AddressFamily_InterNetworkV6:
173 #ifdef AF_INET6
174                 family=AF_INET6;
175 #endif
176                 break;
177         case AddressFamily_Irda:
178 #ifdef AF_IRDA  
179                 family=AF_IRDA;
180 #endif
181                 break;
182         default:
183                 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
184         }
185
186         return(family);
187 }
188
189 static MonoAddressFamily convert_to_mono_family(guint16 af_family)
190 {
191         MonoAddressFamily family=AddressFamily_Unknown;
192         
193         switch(af_family) {
194         case AF_UNSPEC:
195                 family=AddressFamily_Unspecified;
196                 break;
197                 
198         case AF_UNIX:
199                 family=AddressFamily_Unix;
200                 break;
201                 
202         case AF_INET:
203                 family=AddressFamily_InterNetwork;
204                 break;
205                 
206 #ifdef AF_IPX
207         case AF_IPX:
208                 family=AddressFamily_Ipx;
209                 break;
210 #endif
211                 
212 #ifdef AF_SNA
213         case AF_SNA:
214                 family=AddressFamily_Sna;
215                 break;
216 #endif
217                 
218 #ifdef AF_DECnet
219         case AF_DECnet:
220                 family=AddressFamily_DecNet;
221                 break;
222 #endif
223                 
224         case AF_APPLETALK:
225                 family=AddressFamily_AppleTalk;
226                 break;
227                 
228 #ifdef AF_INET6
229         case AF_INET6:
230                 family=AddressFamily_InterNetworkV6;
231                 break;
232 #endif
233                 
234 #ifdef AF_IRDA  
235         case AF_IRDA:
236                 family=AddressFamily_Irda;
237                 break;
238 #endif
239         default:
240                 g_warning("unknown address family 0x%x", af_family);
241         }
242
243         return(family);
244 }
245
246 static gint32 convert_type(MonoSocketType mono_type)
247 {
248         gint32 type=-1;
249         
250         switch(mono_type) {
251         case SocketType_Stream:
252                 type=SOCK_STREAM;
253                 break;
254
255         case SocketType_Dgram:
256                 type=SOCK_DGRAM;
257                 break;
258                 
259         case SocketType_Raw:
260                 type=SOCK_RAW;
261                 break;
262
263         case SocketType_Rdm:
264 #ifdef SOCK_RDM
265                 type=SOCK_RDM;
266 #endif
267                 break;
268
269         case SocketType_Seqpacket:
270                 type=SOCK_SEQPACKET;
271                 break;
272
273         case SocketType_Unknown:
274                 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
275                 break;
276
277         default:
278                 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
279         }
280
281         return(type);
282 }
283
284 static gint32 convert_proto(MonoProtocolType mono_proto)
285 {
286         gint32 proto=-1;
287         
288         switch(mono_proto) {
289         case ProtocolType_IP:
290         case ProtocolType_IPv6:
291         case ProtocolType_Icmp:
292         case ProtocolType_Igmp:
293         case ProtocolType_Ggp:
294         case ProtocolType_Tcp:
295         case ProtocolType_Pup:
296         case ProtocolType_Udp:
297         case ProtocolType_Idp:
298                 /* These protocols are known (on my system at least) */
299                 proto=mono_proto;
300                 break;
301                 
302         case ProtocolType_ND:
303         case ProtocolType_Raw:
304         case ProtocolType_Ipx:
305         case ProtocolType_Spx:
306         case ProtocolType_SpxII:
307         case ProtocolType_Unknown:
308                 /* These protocols arent */
309                 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
310                 break;
311                 
312         default:
313                 break;
314         }
315
316         return(proto);
317 }
318
319 /* Convert MonoSocketFlags */
320 static gint32 convert_socketflags (gint32 sflags)
321 {
322         gint32 flags = 0;
323
324         if (!sflags)
325                 /* SocketFlags.None */
326                 return 0;
327
328         if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek | 
329                         SocketFlags_DontRoute | SocketFlags_Partial))
330                 /* Contains invalid flag values */
331                 return -1;
332
333         if (sflags & SocketFlags_OutOfBand)
334                 flags |= MSG_OOB;
335         if (sflags & SocketFlags_Peek)
336                 flags |= MSG_PEEK;
337         if (sflags & SocketFlags_DontRoute)
338                 flags |= MSG_DONTROUTE;
339
340         /* Ignore Partial - see bug 349688.  Don't return -1, because
341          * according to the comment in that bug ms runtime doesn't for
342          * UDP sockets (this means we will silently ignore it for TCP
343          * too)
344          */
345 #ifdef MSG_MORE
346         if (sflags & SocketFlags_Partial)
347                 flags |= MSG_MORE;
348 #endif
349 #if 0
350         /* Don't do anything for MaxIOVectorLength */
351         if (sflags & SocketFlags_MaxIOVectorLength)
352                 return -1;      
353 #endif
354         return flags;
355 }
356
357 /*
358  * Returns:
359  *    0 on success (mapped mono_level and mono_name to system_level and system_name
360  *   -1 on error
361  *   -2 on non-fatal error (ie, must ignore)
362  */
363 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
364                                              MonoSocketOptionName mono_name,
365                                              int *system_level,
366                                              int *system_name)
367 {
368         switch (mono_level) {
369         case SocketOptionLevel_Socket:
370                 *system_level = SOL_SOCKET;
371                 
372                 switch(mono_name) {
373                 case SocketOptionName_DontLinger:
374                         /* This is SO_LINGER, because the setsockopt
375                          * internal call maps DontLinger to SO_LINGER
376                          * with l_onoff=0
377                          */
378                         *system_name = SO_LINGER;
379                         break;
380                 case SocketOptionName_Debug:
381                         *system_name = SO_DEBUG;
382                         break;
383 #ifdef SO_ACCEPTCONN
384                 case SocketOptionName_AcceptConnection:
385                         *system_name = SO_ACCEPTCONN;
386                         break;
387 #endif
388                 case SocketOptionName_ReuseAddress:
389                         *system_name = SO_REUSEADDR;
390                         break;
391                 case SocketOptionName_KeepAlive:
392                         *system_name = SO_KEEPALIVE;
393                         break;
394                 case SocketOptionName_DontRoute:
395                         *system_name = SO_DONTROUTE;
396                         break;
397                 case SocketOptionName_Broadcast:
398                         *system_name = SO_BROADCAST;
399                         break;
400                 case SocketOptionName_Linger:
401                         *system_name = SO_LINGER;
402                         break;
403                 case SocketOptionName_OutOfBandInline:
404                         *system_name = SO_OOBINLINE;
405                         break;
406                 case SocketOptionName_SendBuffer:
407                         *system_name = SO_SNDBUF;
408                         break;
409                 case SocketOptionName_ReceiveBuffer:
410                         *system_name = SO_RCVBUF;
411                         break;
412                 case SocketOptionName_SendLowWater:
413                         *system_name = SO_SNDLOWAT;
414                         break;
415                 case SocketOptionName_ReceiveLowWater:
416                         *system_name = SO_RCVLOWAT;
417                         break;
418                 case SocketOptionName_SendTimeout:
419                         *system_name = SO_SNDTIMEO;
420                         break;
421                 case SocketOptionName_ReceiveTimeout:
422                         *system_name = SO_RCVTIMEO;
423                         break;
424                 case SocketOptionName_Error:
425                         *system_name = SO_ERROR;
426                         break;
427                 case SocketOptionName_Type:
428                         *system_name = SO_TYPE;
429                         break;
430 #ifdef SO_PEERCRED
431                 case SocketOptionName_PeerCred:
432                         *system_name = SO_PEERCRED;
433                         break;
434 #endif
435                 case SocketOptionName_ExclusiveAddressUse:
436 #ifdef SO_EXCLUSIVEADDRUSE
437                         *system_name = SO_EXCLUSIVEADDRUSE;
438                         break;
439 #endif
440                 case SocketOptionName_UseLoopback:
441 #ifdef SO_USELOOPBACK
442                         *system_name = SO_USELOOPBACK;
443                         break;
444 #endif
445                 case SocketOptionName_MaxConnections:
446 #ifdef SO_MAXCONN
447                         *system_name = SO_MAXCONN;
448                         break;
449 #elif defined(SOMAXCONN)
450                         *system_name = SOMAXCONN;
451                         break;
452 #endif
453                 default:
454                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
455                         return(-1);
456                 }
457                 break;
458                 
459         case SocketOptionLevel_IP:
460 #ifdef HAVE_SOL_IP
461                 *system_level = SOL_IP;
462 #else
463                 if (1) {
464                         static int cached = 0;
465                         static int proto;
466                         
467                         if (!cached) {
468                                 struct protoent *pent;
469                                 
470                                 pent = getprotobyname ("IP");
471                                 proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
472                                 cached = 1;
473                         }
474                         
475                         *system_level = proto;
476                 }
477 #endif /* HAVE_SOL_IP */
478                 
479                 switch(mono_name) {
480                 case SocketOptionName_IPOptions:
481                         *system_name = IP_OPTIONS;
482                         break;
483 #ifdef IP_HDRINCL
484                 case SocketOptionName_HeaderIncluded:
485                         *system_name = IP_HDRINCL;
486                         break;
487 #endif
488 #ifdef IP_TOS
489                 case SocketOptionName_TypeOfService:
490                         *system_name = IP_TOS;
491                         break;
492 #endif
493 #ifdef IP_TTL
494                 case SocketOptionName_IpTimeToLive:
495                         *system_name = IP_TTL;
496                         break;
497 #endif
498                 case SocketOptionName_MulticastInterface:
499                         *system_name = IP_MULTICAST_IF;
500                         break;
501                 case SocketOptionName_MulticastTimeToLive:
502                         *system_name = IP_MULTICAST_TTL;
503                         break;
504                 case SocketOptionName_MulticastLoopback:
505                         *system_name = IP_MULTICAST_LOOP;
506                         break;
507                 case SocketOptionName_AddMembership:
508                         *system_name = IP_ADD_MEMBERSHIP;
509                         break;
510                 case SocketOptionName_DropMembership:
511                         *system_name = IP_DROP_MEMBERSHIP;
512                         break;
513 #ifdef HAVE_IP_PKTINFO
514                 case SocketOptionName_PacketInformation:
515                         *system_name = IP_PKTINFO;
516                         break;
517 #endif /* HAVE_IP_PKTINFO */
518
519                 case SocketOptionName_DontFragment:
520 #ifdef HAVE_IP_DONTFRAGMENT
521                         *system_name = IP_DONTFRAGMENT;
522                         break;
523 #elif defined HAVE_IP_MTU_DISCOVER
524                         /* Not quite the same */
525                         *system_name = IP_MTU_DISCOVER;
526                         break;
527 #else
528                         /* If the flag is not available on this system, we can ignore this error */
529                         return (-2);
530 #endif /* HAVE_IP_DONTFRAGMENT */
531                 case SocketOptionName_AddSourceMembership:
532                 case SocketOptionName_DropSourceMembership:
533                 case SocketOptionName_BlockSource:
534                 case SocketOptionName_UnblockSource:
535                         /* Can't figure out how to map these, so fall
536                          * through
537                          */
538                 default:
539                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
540                         return(-1);
541                 }
542                 break;
543
544 #ifdef AF_INET6
545         case SocketOptionLevel_IPv6:
546 #ifdef HAVE_SOL_IPV6
547                 *system_level = SOL_IPV6;
548 #else
549                 if (1) {
550                         static int cached = 0;
551                         static int proto;
552
553                         if (!cached) {
554                                 struct protoent *pent;
555
556                                 pent = getprotobyname ("IPV6");
557                                 proto = pent ? pent->p_proto : 41 /* 41 a good default value?? */;
558                                 cached = 1;
559                         }
560
561                         *system_level = proto;
562                 }
563 #endif /* HAVE_SOL_IPV6 */
564
565                 switch(mono_name) {
566                 case SocketOptionName_IpTimeToLive:
567                 case SocketOptionName_HopLimit:
568                         *system_name = IPV6_UNICAST_HOPS;
569                         break;
570                 case SocketOptionName_MulticastInterface:
571                         *system_name = IPV6_MULTICAST_IF;
572                         break;
573                 case SocketOptionName_MulticastTimeToLive:
574                         *system_name = IPV6_MULTICAST_HOPS;
575                         break;
576                 case SocketOptionName_MulticastLoopback:
577                         *system_name = IPV6_MULTICAST_LOOP;
578                         break;
579                 case SocketOptionName_AddMembership:
580                         *system_name = IPV6_JOIN_GROUP;
581                         break;
582                 case SocketOptionName_DropMembership:
583                         *system_name = IPV6_LEAVE_GROUP;
584                         break;
585                 case SocketOptionName_PacketInformation:
586 #ifdef HAVE_IPV6_PKTINFO
587                         *system_name = IPV6_PKTINFO;
588 #endif
589                         break;
590                 case SocketOptionName_HeaderIncluded:
591                 case SocketOptionName_IPOptions:
592                 case SocketOptionName_TypeOfService:
593                 case SocketOptionName_DontFragment:
594                 case SocketOptionName_AddSourceMembership:
595                 case SocketOptionName_DropSourceMembership:
596                 case SocketOptionName_BlockSource:
597                 case SocketOptionName_UnblockSource:
598                         /* Can't figure out how to map these, so fall
599                          * through
600                          */
601                 default:
602                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
603                         return(-1);
604                 }
605
606                 break;  /* SocketOptionLevel_IPv6 */
607 #endif
608                 
609         case SocketOptionLevel_Tcp:
610 #ifdef HAVE_SOL_TCP
611                 *system_level = SOL_TCP;
612 #else
613                 if (1) {
614                         static int cached = 0;
615                         static int proto;
616                         
617                         if (!cached) {
618                                 struct protoent *pent;
619                                 
620                                 pent = getprotobyname ("TCP");
621                                 proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
622                                 cached = 1;
623                         }
624                         
625                         *system_level = proto;
626                 }
627 #endif /* HAVE_SOL_TCP */
628                 
629                 switch(mono_name) {
630                 case SocketOptionName_NoDelay:
631                         *system_name = TCP_NODELAY;
632                         break;
633 #if 0
634                         /* The documentation is talking complete
635                          * bollocks here: rfc-1222 is titled
636                          * 'Advancing the NSFNET Routing Architecture'
637                          * and doesn't mention either of the words
638                          * "expedite" or "urgent".
639                          */
640                 case SocketOptionName_BsdUrgent:
641                 case SocketOptionName_Expedited:
642 #endif
643                 default:
644                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
645                         return(-1);
646                 }
647                 break;
648                 
649         case SocketOptionLevel_Udp:
650                 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
651
652                 switch(mono_name) {
653                 case SocketOptionName_NoChecksum:
654                 case SocketOptionName_ChecksumCoverage:
655                 default:
656                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
657                         return(-1);
658                 }
659                 return(-1);
660                 break;
661
662         default:
663                 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
664                 return(-1);
665         }
666
667         return(0);
668 }
669
670 static MonoImage *get_socket_assembly (void)
671 {
672         static const char *version = NULL;
673         static gboolean moonlight;
674         MonoDomain *domain = mono_domain_get ();
675         
676         if (version == NULL) {
677                 version = mono_get_runtime_info ()->framework_version;
678                 moonlight = !strcmp (version, "2.1");
679         }
680         
681         if (domain->socket_assembly == NULL) {
682                 MonoImage *socket_assembly;
683
684                 if (moonlight) {
685                         socket_assembly = mono_image_loaded ("System.Net");
686                         if (!socket_assembly) {
687                                 MonoAssembly *sa = mono_assembly_open ("System.Net.dll", NULL);
688                         
689                                 if (!sa) {
690                                         g_assert_not_reached ();
691                                 } else {
692                                         socket_assembly = mono_assembly_get_image (sa);
693                                 }
694                         }
695                 } else {
696                         socket_assembly = mono_image_loaded ("System");
697                         if (!socket_assembly) {
698                                 MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);
699                         
700                                 if (!sa) {
701                                         g_assert_not_reached ();
702                                 } else {
703                                         socket_assembly = mono_assembly_get_image (sa);
704                                 }
705                         }
706                 }
707
708                 domain->socket_assembly = socket_assembly;
709         }
710         
711         return domain->socket_assembly;
712 }
713
714 #ifdef AF_INET6
715 static gint32 get_family_hint(void)
716 {
717         MonoDomain *domain = mono_domain_get ();
718
719         if (!domain->inet_family_hint) {
720                 MonoClass *socket_class;
721                 MonoClassField *ipv6_field, *ipv4_field;
722                 gint32 ipv6_enabled = -1, ipv4_enabled = -1;
723                 MonoVTable *vtable;
724
725                 socket_class = mono_class_from_name (get_socket_assembly (), "System.Net.Sockets", "Socket");
726                 ipv4_field = mono_class_get_field_from_name (socket_class, "ipv4Supported");
727                 ipv6_field = mono_class_get_field_from_name (socket_class, "ipv6Supported");
728                 vtable = mono_class_vtable (mono_domain_get (), socket_class);
729                 g_assert (vtable);
730                 mono_runtime_class_init (vtable);
731
732                 mono_field_static_get_value (vtable, ipv4_field, &ipv4_enabled);
733                 mono_field_static_get_value (vtable, ipv6_field, &ipv6_enabled);
734
735                 mono_domain_lock (domain);
736                 if (ipv4_enabled == 1 && ipv6_enabled == 1) {
737                         domain->inet_family_hint = 1;
738                 } else if (ipv4_enabled == 1) {
739                         domain->inet_family_hint = 2;
740                 } else {
741                         domain->inet_family_hint = 3;
742                 }
743                 mono_domain_unlock (domain);
744         }
745         switch (domain->inet_family_hint) {
746         case 1: return PF_UNSPEC;
747         case 2: return PF_INET;
748         case 3: return PF_INET6;
749         default:
750                 return PF_UNSPEC;
751         }
752 }
753 #endif
754
755 gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto, gint32 *error)
756 {
757         SOCKET sock;
758         gint32 sock_family;
759         gint32 sock_proto;
760         gint32 sock_type;
761         
762         MONO_ARCH_SAVE_REGS;
763
764         *error = 0;
765         
766         sock_family=convert_family(family);
767         if(sock_family==-1) {
768                 *error = WSAEAFNOSUPPORT;
769                 return(NULL);
770         }
771
772         sock_proto=convert_proto(proto);
773         if(sock_proto==-1) {
774                 *error = WSAEPROTONOSUPPORT;
775                 return(NULL);
776         }
777         
778         sock_type=convert_type(type);
779         if(sock_type==-1) {
780                 *error = WSAESOCKTNOSUPPORT;
781                 return(NULL);
782         }
783         
784         sock = _wapi_socket (sock_family, sock_type, sock_proto,
785                              NULL, 0, WSA_FLAG_OVERLAPPED);
786
787         if(sock==INVALID_SOCKET) {
788                 *error = WSAGetLastError ();
789                 return(NULL);
790         }
791
792         if (sock_family == AF_INET && sock_type == SOCK_DGRAM) {
793                 return (GUINT_TO_POINTER (sock));
794         }
795
796 #ifdef AF_INET6
797         if (sock_family == AF_INET6 && sock_type == SOCK_DGRAM) {
798                 return (GUINT_TO_POINTER (sock));
799         }
800 #endif
801
802         return(GUINT_TO_POINTER (sock));
803 }
804
805 /* FIXME: the SOCKET parameter (here and in other functions in this
806  * file) is really an IntPtr which needs to be converted to a guint32.
807  */
808 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock,
809                                                         gint32 *error)
810 {
811         MONO_ARCH_SAVE_REGS;
812
813         LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
814
815         *error = 0;
816
817         /* Clear any pending work item from this socket if the underlying
818          * polling system does not notify when the socket is closed */
819         mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock));
820         closesocket(sock);
821 }
822
823 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
824 {
825         MONO_ARCH_SAVE_REGS;
826
827         LOGDEBUG (g_message("%s: returning %d", __func__, WSAGetLastError()));
828
829         return(WSAGetLastError());
830 }
831
832 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock,
833                                                               gint32 *error)
834 {
835         int ret;
836         int amount;
837         
838         MONO_ARCH_SAVE_REGS;
839
840         *error = 0;
841         
842         ret=ioctlsocket(sock, FIONREAD, &amount);
843         if(ret==SOCKET_ERROR) {
844                 *error = WSAGetLastError ();
845                 return(0);
846         }
847         
848         return(amount);
849 }
850
851 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
852                                                            gboolean block,
853                                                            gint32 *error)
854 {
855         int ret;
856         
857         MONO_ARCH_SAVE_REGS;
858
859         *error = 0;
860
861         /*
862          * block == TRUE/FALSE means we will block/not block.
863          * But the ioctlsocket call takes TRUE/FALSE for non-block/block
864          */
865         block = !block;
866         
867         ret = ioctlsocket (sock, FIONBIO, (gulong *) &block);
868         if(ret==SOCKET_ERROR) {
869                 *error = WSAGetLastError ();
870         }
871 }
872
873 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock,
874                                                              gint32 *error,
875                                                              gboolean blocking)
876 {
877         SOCKET newsock;
878         
879         MONO_ARCH_SAVE_REGS;
880
881         *error = 0;
882 #ifdef HOST_WIN32
883         {
884                 MonoInternalThread* curthread = mono_thread_internal_current ();
885                 curthread->interrupt_on_stop = (gpointer)TRUE;
886                 newsock = _wapi_accept (sock, NULL, 0);
887                 curthread->interrupt_on_stop = (gpointer)FALSE;
888         }
889 #else
890         newsock = _wapi_accept (sock, NULL, 0);
891 #endif
892         if(newsock==INVALID_SOCKET) {
893                 *error = WSAGetLastError ();
894                 return(NULL);
895         }
896         
897         return(GUINT_TO_POINTER (newsock));
898 }
899
900 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
901                                                          guint32 backlog,
902                                                          gint32 *error)
903 {
904         int ret;
905         
906         MONO_ARCH_SAVE_REGS;
907
908         *error = 0;
909         
910         ret = _wapi_listen (sock, backlog);
911         if(ret==SOCKET_ERROR) {
912                 *error = WSAGetLastError ();
913         }
914 }
915
916 #ifdef AF_INET6
917 // Check whether it's ::ffff::0:0.
918 static gboolean
919 is_ipv4_mapped_any (const struct in6_addr *addr)
920 {
921         int i;
922         
923         for (i = 0; i < 10; i++) {
924                 if (addr->s6_addr [i])
925                         return FALSE;
926         }
927         if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
928                 return FALSE;
929         for (i = 12; i < 16; i++) {
930                 if (addr->s6_addr [i])
931                         return FALSE;
932         }
933         return TRUE;
934 }
935 #endif
936
937 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
938                                                int sa_size, gint32 *error)
939 {
940         MonoDomain *domain = mono_domain_get ();
941         MonoObject *sockaddr_obj;
942         MonoArray *data;
943         MonoAddressFamily family;
944
945         /* Build a System.Net.SocketAddress object instance */
946         if (!domain->sockaddr_class) {
947                 domain->sockaddr_class=mono_class_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
948                 g_assert (domain->sockaddr_class);
949         }
950         sockaddr_obj=mono_object_new(domain, domain->sockaddr_class);
951         
952         /* Locate the SocketAddress data buffer in the object */
953         if (!domain->sockaddr_data_field) {
954                 domain->sockaddr_data_field=mono_class_get_field_from_name (domain->sockaddr_class, "data");
955                 g_assert (domain->sockaddr_data_field);
956         }
957
958         /* Make sure there is space for the family and size bytes */
959 #ifdef HAVE_SYS_UN_H
960         if (saddr->sa_family == AF_UNIX) {
961                 /* sa_len includes the entire sockaddr size, so we don't need the
962                  * N bytes (sizeof (unsigned short)) of the family. */
963                 data=mono_array_new_cached(domain, mono_get_byte_class (), sa_size);
964         } else
965 #endif
966         {
967                 /* May be the +2 here is too conservative, as sa_len returns
968                  * the length of the entire sockaddr_in/in6, including
969                  * sizeof (unsigned short) of the family */
970                 data=mono_array_new_cached(domain, mono_get_byte_class (), sa_size+2);
971         }
972
973         /* The data buffer is laid out as follows:
974          * bytes 0 and 1 are the address family
975          * bytes 2 and 3 are the port info
976          * the rest is the address info
977          */
978                 
979         family=convert_to_mono_family(saddr->sa_family);
980         if(family==AddressFamily_Unknown) {
981                 *error = WSAEAFNOSUPPORT;
982                 return(NULL);
983         }
984
985         mono_array_set(data, guint8, 0, family & 0x0FF);
986         mono_array_set(data, guint8, 1, (family >> 8) & 0x0FF);
987         
988         if(saddr->sa_family==AF_INET) {
989                 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
990                 guint16 port=ntohs(sa_in->sin_port);
991                 guint32 address=ntohl(sa_in->sin_addr.s_addr);
992                 
993                 if(sa_size<8) {
994                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
995                 }
996                 
997                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
998                 mono_array_set(data, guint8, 3, (port) & 0xff);
999                 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
1000                 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
1001                 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
1002                 mono_array_set(data, guint8, 7, (address) & 0xff);
1003         
1004                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
1005
1006                 return(sockaddr_obj);
1007 #ifdef AF_INET6
1008         } else if (saddr->sa_family == AF_INET6) {
1009                 struct sockaddr_in6 *sa_in=(struct sockaddr_in6 *)saddr;
1010                 int i;
1011
1012                 guint16 port=ntohs(sa_in->sin6_port);
1013
1014                 if(sa_size<28) {
1015                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1016                 }
1017
1018                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
1019                 mono_array_set(data, guint8, 3, (port) & 0xff);
1020                 
1021                 if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
1022                         // Map ::ffff:0:0 to :: (bug #5502)
1023                         for(i=0; i<16; i++) {
1024                                 mono_array_set(data, guint8, 8+i, 0);
1025                         }
1026                 } else {
1027                         for(i=0; i<16; i++) {
1028                                 mono_array_set(data, guint8, 8+i,
1029                                                sa_in->sin6_addr.s6_addr[i]);
1030                         }
1031                 }
1032
1033                 mono_array_set(data, guint8, 24, sa_in->sin6_scope_id & 0xff);
1034                 mono_array_set(data, guint8, 25,
1035                                (sa_in->sin6_scope_id >> 8) & 0xff);
1036                 mono_array_set(data, guint8, 26,
1037                                (sa_in->sin6_scope_id >> 16) & 0xff);
1038                 mono_array_set(data, guint8, 27,
1039                                (sa_in->sin6_scope_id >> 24) & 0xff);
1040
1041                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
1042
1043                 return(sockaddr_obj);
1044 #endif
1045 #ifdef HAVE_SYS_UN_H
1046         } else if (saddr->sa_family == AF_UNIX) {
1047                 int i;
1048
1049                 for (i = 0; i < sa_size; i++) {
1050                         mono_array_set (data, guint8, i+2, saddr->sa_data[i]);
1051                 }
1052                 
1053                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
1054
1055                 return sockaddr_obj;
1056 #endif
1057         } else {
1058                 *error = WSAEAFNOSUPPORT;
1059                 return(NULL);
1060         }
1061 }
1062
1063 static int
1064 get_sockaddr_size (int family)
1065 {
1066         int size;
1067
1068         size = 0;
1069         if (family == AF_INET) {
1070                 size = sizeof (struct sockaddr_in);
1071 #ifdef AF_INET6
1072         } else if (family == AF_INET6) {
1073                 size = sizeof (struct sockaddr_in6);
1074 #endif
1075 #ifdef HAVE_SYS_UN_H
1076         } else if (family == AF_UNIX) {
1077                 size = sizeof (struct sockaddr_un);
1078 #endif
1079         }
1080         return size;
1081 }
1082
1083 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 af, gint32 *error)
1084 {
1085         gchar *sa;
1086         socklen_t salen;
1087         int ret;
1088         MonoObject *result;
1089         
1090         MONO_ARCH_SAVE_REGS;
1091
1092         *error = 0;
1093         
1094         salen = get_sockaddr_size (convert_family (af));
1095         if (salen == 0) {
1096                 *error = WSAEAFNOSUPPORT;
1097                 return NULL;
1098         }
1099         sa = (salen <= 128) ? alloca (salen) : g_malloc0 (salen);
1100         ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
1101         
1102         if(ret==SOCKET_ERROR) {
1103                 *error = WSAGetLastError ();
1104                 if (salen > 128)
1105                         g_free (sa);
1106                 return(NULL);
1107         }
1108         
1109         LOGDEBUG (g_message("%s: bound to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port)));
1110
1111         result = create_object_from_sockaddr((struct sockaddr *)sa, salen, error);
1112         if (salen > 128)
1113                 g_free (sa);
1114         return result;
1115 }
1116
1117 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 af, gint32 *error)
1118 {
1119         gchar *sa;
1120         socklen_t salen;
1121         int ret;
1122         MonoObject *result;
1123         
1124         MONO_ARCH_SAVE_REGS;
1125
1126         *error = 0;
1127         
1128         salen = get_sockaddr_size (convert_family (af));
1129         if (salen == 0) {
1130                 *error = WSAEAFNOSUPPORT;
1131                 return NULL;
1132         }
1133         sa = (salen <= 128) ? alloca (salen) : g_malloc0 (salen);
1134         /* Note: linux returns just 2 for AF_UNIX. Always. */
1135         ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
1136         if(ret==SOCKET_ERROR) {
1137                 *error = WSAGetLastError ();
1138                 if (salen > 128)
1139                         g_free (sa);
1140                 return(NULL);
1141         }
1142         
1143         LOGDEBUG (g_message("%s: connected to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port)));
1144
1145         result = create_object_from_sockaddr((struct sockaddr *)sa, salen, error);
1146         if (salen > 128)
1147                 g_free (sa);
1148         return result;
1149 }
1150
1151 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
1152                                                     socklen_t *sa_size,
1153                                                     gint32 *error)
1154 {
1155         MonoClassField *field;
1156         MonoArray *data;
1157         gint32 family;
1158         int len;
1159
1160         /* Dig the SocketAddress data buffer out of the object */
1161         field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
1162         data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
1163
1164         /* The data buffer is laid out as follows:
1165          * byte 0 is the address family low byte
1166          * byte 1 is the address family high byte
1167          * INET:
1168          *      bytes 2 and 3 are the port info
1169          *      the rest is the address info
1170          * UNIX:
1171          *      the rest is the file name
1172          */
1173         len = mono_array_length (data);
1174         if (len < 2) {
1175                 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1176         }
1177         
1178         family = convert_family (mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8));
1179         if (family == AF_INET) {
1180                 struct sockaddr_in *sa;
1181                 guint16 port;
1182                 guint32 address;
1183                 
1184                 if (len < 8) {
1185                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1186                 }
1187
1188                 sa = g_new0 (struct sockaddr_in, 1);
1189                 port = (mono_array_get (data, guint8, 2) << 8) +
1190                         mono_array_get (data, guint8, 3);
1191                 address = (mono_array_get (data, guint8, 4) << 24) +
1192                         (mono_array_get (data, guint8, 5) << 16 ) +
1193                         (mono_array_get (data, guint8, 6) << 8) +
1194                         mono_array_get (data, guint8, 7);
1195
1196                 sa->sin_family = family;
1197                 sa->sin_addr.s_addr = htonl (address);
1198                 sa->sin_port = htons (port);
1199
1200                 *sa_size = sizeof(struct sockaddr_in);
1201                 return((struct sockaddr *)sa);
1202
1203 #ifdef AF_INET6
1204         } else if (family == AF_INET6) {
1205                 struct sockaddr_in6 *sa;
1206                 int i;
1207                 guint16 port;
1208                 guint32 scopeid;
1209                 
1210                 if (len < 28) {
1211                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1212                 }
1213
1214                 sa = g_new0 (struct sockaddr_in6, 1);
1215                 port = mono_array_get (data, guint8, 3) +
1216                         (mono_array_get (data, guint8, 2) << 8);
1217                 scopeid = mono_array_get (data, guint8, 24) + 
1218                         (mono_array_get (data, guint8, 25) << 8) + 
1219                         (mono_array_get (data, guint8, 26) << 16) + 
1220                         (mono_array_get (data, guint8, 27) << 24);
1221
1222                 sa->sin6_family = family;
1223                 sa->sin6_port = htons (port);
1224                 sa->sin6_scope_id = scopeid;
1225
1226                 for(i=0; i<16; i++) {
1227                         sa->sin6_addr.s6_addr[i] = mono_array_get (data, guint8, 8+i);
1228                 }
1229
1230                 *sa_size = sizeof(struct sockaddr_in6);
1231                 return((struct sockaddr *)sa);
1232 #endif
1233 #ifdef HAVE_SYS_UN_H
1234         } else if (family == AF_UNIX) {
1235                 struct sockaddr_un *sock_un;
1236                 int i;
1237
1238                 /* Need a byte for the '\0' terminator/prefix, and the first
1239                  * two bytes hold the SocketAddress family
1240                  */
1241                 if (len - 2 >= MONO_SIZEOF_SUNPATH) {
1242                         mono_raise_exception (mono_get_exception_index_out_of_range ());
1243                 }
1244                 
1245                 sock_un = g_new0 (struct sockaddr_un, 1);
1246
1247                 sock_un->sun_family = family;
1248                 for (i = 0; i < len - 2; i++) {
1249                         sock_un->sun_path [i] = mono_array_get (data, guint8,
1250                                                                 i + 2);
1251                 }
1252                 
1253                 *sa_size = len;
1254
1255                 return (struct sockaddr *)sock_un;
1256 #endif
1257         } else {
1258                 *error = WSAEAFNOSUPPORT;
1259                 return(0);
1260         }
1261 }
1262
1263 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1264 {
1265         struct sockaddr *sa;
1266         socklen_t sa_size;
1267         int ret;
1268         
1269         MONO_ARCH_SAVE_REGS;
1270
1271         *error = 0;
1272         
1273         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1274         if (*error != 0) {
1275                 return;
1276         }
1277
1278         LOGDEBUG (g_message("%s: binding to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)));
1279
1280         ret = _wapi_bind (sock, sa, sa_size);
1281         if(ret==SOCKET_ERROR) {
1282                 *error = WSAGetLastError ();
1283         }
1284
1285         g_free(sa);
1286 }
1287
1288 enum {
1289         SelectModeRead,
1290         SelectModeWrite,
1291         SelectModeError
1292 };
1293
1294 MonoBoolean
1295 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1296                                                    gint timeout, gint32 *error)
1297 {
1298         MonoInternalThread *thread = NULL;
1299         mono_pollfd *pfds;
1300         int ret;
1301         time_t start;
1302         
1303
1304         MONO_ARCH_SAVE_REGS;
1305         
1306         pfds = g_new0 (mono_pollfd, 1);
1307         pfds[0].fd = GPOINTER_TO_INT (sock);
1308         pfds[0].events = (mode == SelectModeRead) ? MONO_POLLIN :
1309                 (mode == SelectModeWrite) ? MONO_POLLOUT :
1310                 (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL);
1311
1312         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1313         start = time (NULL);
1314         do {
1315                 *error = 0;
1316                 
1317                 ret = mono_poll (pfds, 1, timeout);
1318                 if (timeout > 0 && ret < 0) {
1319                         int err = errno;
1320                         int sec = time (NULL) - start;
1321                         
1322                         timeout -= sec * 1000;
1323                         if (timeout < 0) {
1324                                 timeout = 0;
1325                         }
1326                         
1327                         errno = err;
1328                 }
1329                 
1330                 if (ret == -1 && errno == EINTR) {
1331                         int leave = 0;
1332
1333                         if (thread == NULL) {
1334                                 thread = mono_thread_internal_current ();
1335                         }
1336                         
1337                         leave = mono_thread_test_state (thread, ThreadState_AbortRequested | ThreadState_StopRequested);
1338                         
1339                         if (leave != 0) {
1340                                 g_free (pfds);
1341                                 return(FALSE);
1342                         } else {
1343                                 /* Suspend requested? */
1344                                 mono_thread_interruption_checkpoint ();
1345                         }
1346                         errno = EINTR;
1347                 }
1348         } while (ret == -1 && errno == EINTR);
1349
1350         if (ret == -1) {
1351 #ifdef HOST_WIN32
1352                 *error = WSAGetLastError ();
1353 #else
1354                 *error = errno_to_WSA (errno, __func__);
1355 #endif
1356                 g_free (pfds);
1357                 return(FALSE);
1358         }
1359         
1360         g_free (pfds);
1361
1362         if (ret == 0) {
1363                 return(FALSE);
1364         } else {
1365                 return (TRUE);
1366         }
1367 }
1368
1369 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1370 {
1371         struct sockaddr *sa;
1372         socklen_t sa_size;
1373         int ret;
1374         
1375         MONO_ARCH_SAVE_REGS;
1376
1377         *error = 0;
1378         
1379         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1380         if (*error != 0) {
1381                 return;
1382         }
1383         
1384         LOGDEBUG (g_message("%s: connecting to %s port %d", __func__, inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)));
1385
1386         ret = _wapi_connect (sock, sa, sa_size);
1387         if(ret==SOCKET_ERROR) {
1388                 *error = WSAGetLastError ();
1389         }
1390
1391         g_free(sa);
1392 }
1393
1394 /* These #defines from mswsock.h from wine.  Defining them here allows
1395  * us to build this file on a mingw box that doesn't know the magic
1396  * numbers, but still run on a newer windows box that does.
1397  */
1398 #ifndef WSAID_DISCONNECTEX
1399 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1400 typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
1401 #endif
1402
1403 #ifndef WSAID_TRANSMITFILE
1404 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1405 typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
1406 #endif
1407
1408 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, MonoBoolean reuse, gint32 *error)
1409 {
1410         int ret;
1411         glong output_bytes = 0;
1412         GUID disco_guid = WSAID_DISCONNECTEX;
1413         GUID trans_guid = WSAID_TRANSMITFILE;
1414         LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
1415         LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
1416         gboolean bret;
1417         
1418         MONO_ARCH_SAVE_REGS;
1419
1420         *error = 0;
1421         
1422         LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
1423
1424         /* I _think_ the extension function pointers need to be looked
1425          * up for each socket.  FIXME: check the best way to store
1426          * pointers to functions in managed objects that still works
1427          * on 64bit platforms.
1428          */
1429         ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1430                         (void *)&disco_guid, sizeof(GUID),
1431                         (void *)&_wapi_disconnectex, sizeof(void *),
1432                         &output_bytes, NULL, NULL);
1433         if (ret != 0) {
1434                 /* make sure that WSAIoctl didn't put crap in the
1435                  * output pointer
1436                  */
1437                 _wapi_disconnectex = NULL;
1438
1439                 /* Look up the TransmitFile extension function pointer
1440                  * instead of calling TransmitFile() directly, because
1441                  * apparently "Several of the extension functions have
1442                  * been available since WinSock 1.1 and are exported
1443                  * from MSWsock.dll, however it's not advisable to
1444                  * link directly to this dll as this ties you to the
1445                  * Microsoft WinSock provider. A provider neutral way
1446                  * of accessing these extension functions is to load
1447                  * them dynamically via WSAIoctl using the
1448                  * SIO_GET_EXTENSION_FUNCTION_POINTER op code. This
1449                  * should, theoretically, allow you to access these
1450                  * functions from any provider that supports them..." 
1451                  * (http://www.codeproject.com/internet/jbsocketserver3.asp)
1452                  */
1453                 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1454                                 (void *)&trans_guid, sizeof(GUID),
1455                                 (void *)&_wapi_transmitfile, sizeof(void *),
1456                                 &output_bytes, NULL, NULL);
1457                 if (ret != 0) {
1458                         _wapi_transmitfile = NULL;
1459                 }
1460         }
1461
1462         if (_wapi_disconnectex != NULL) {
1463                 bret = _wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0);
1464         } else if (_wapi_transmitfile != NULL) {
1465                 bret = _wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL,
1466                                            TF_DISCONNECT | TF_REUSE_SOCKET);
1467         } else {
1468                 *error = ERROR_NOT_SUPPORTED;
1469                 return;
1470         }
1471
1472         if (bret == FALSE) {
1473                 *error = WSAGetLastError ();
1474         }
1475 }
1476
1477 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1478 {
1479         int ret;
1480         guchar *buf;
1481         gint32 alen;
1482         int recvflags=0;
1483         
1484         MONO_ARCH_SAVE_REGS;
1485
1486         *error = 0;
1487         
1488         alen = mono_array_length (buffer);
1489         if (offset > alen - count) {
1490                 return(0);
1491         }
1492         
1493         buf=mono_array_addr(buffer, guchar, offset);
1494         
1495         recvflags = convert_socketflags (flags);
1496         if (recvflags == -1) {
1497                 *error = WSAEOPNOTSUPP;
1498                 return (0);
1499         }
1500
1501 #ifdef HOST_WIN32
1502         {
1503                 MonoInternalThread* curthread = mono_thread_internal_current ();
1504                 curthread->interrupt_on_stop = (gpointer)TRUE;
1505                 ret = _wapi_recv (sock, buf, count, recvflags);
1506                 curthread->interrupt_on_stop = (gpointer)FALSE;
1507         }
1508 #else
1509         ret = _wapi_recv (sock, buf, count, recvflags);
1510 #endif
1511
1512         if(ret==SOCKET_ERROR) {
1513                 *error = WSAGetLastError ();
1514                 return(0);
1515         }
1516
1517         return(ret);
1518 }
1519
1520 gint32 ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error)
1521 {
1522         int ret, count;
1523         DWORD recv;
1524         WSABUF *wsabufs;
1525         DWORD recvflags = 0;
1526         
1527         MONO_ARCH_SAVE_REGS;
1528
1529         *error = 0;
1530         
1531         wsabufs = mono_array_addr (buffers, WSABUF, 0);
1532         count = mono_array_length (buffers);
1533         
1534         recvflags = convert_socketflags (flags);
1535         if (recvflags == -1) {
1536                 *error = WSAEOPNOTSUPP;
1537                 return(0);
1538         }
1539         
1540         ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL);
1541         if (ret == SOCKET_ERROR) {
1542                 *error = WSAGetLastError ();
1543                 return(0);
1544         }
1545         
1546         return(recv);
1547 }
1548
1549 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
1550 {
1551         int ret;
1552         guchar *buf;
1553         gint32 alen;
1554         int recvflags=0;
1555         struct sockaddr *sa;
1556         socklen_t sa_size;
1557         
1558         MONO_ARCH_SAVE_REGS;
1559
1560         *error = 0;
1561         
1562         alen = mono_array_length (buffer);
1563         if (offset > alen - count) {
1564                 return(0);
1565         }
1566
1567         sa=create_sockaddr_from_object(*sockaddr, &sa_size, error);
1568         if (*error != 0) {
1569                 return(0);
1570         }
1571         
1572         buf=mono_array_addr(buffer, guchar, offset);
1573         
1574         recvflags = convert_socketflags (flags);
1575         if (recvflags == -1) {
1576                 *error = WSAEOPNOTSUPP;
1577                 return (0);
1578         }
1579
1580         ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1581         if(ret==SOCKET_ERROR) {
1582                 g_free(sa);
1583                 *error = WSAGetLastError ();
1584                 return(0);
1585         }
1586
1587         /* If we didn't get a socket size, then we're probably a
1588          * connected connection-oriented socket and the stack hasn't
1589          * returned the remote address. All we can do is return null.
1590          */
1591         if ( sa_size != 0 )
1592                 *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
1593         else
1594                 *sockaddr=NULL;
1595
1596         g_free(sa);
1597         
1598         return(ret);
1599 }
1600
1601 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1602 {
1603         int ret;
1604         guchar *buf;
1605         gint32 alen;
1606         int sendflags=0;
1607         
1608         MONO_ARCH_SAVE_REGS;
1609
1610         *error = 0;
1611         
1612         alen = mono_array_length (buffer);
1613         if (offset > alen - count) {
1614                 return(0);
1615         }
1616
1617         LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
1618         
1619         buf=mono_array_addr(buffer, guchar, offset);
1620
1621         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1622
1623         sendflags = convert_socketflags (flags);
1624         if (sendflags == -1) {
1625                 *error = WSAEOPNOTSUPP;
1626                 return (0);
1627         }
1628
1629         ret = _wapi_send (sock, buf, count, sendflags);
1630         if(ret==SOCKET_ERROR) {
1631                 *error = WSAGetLastError ();
1632                 return(0);
1633         }
1634
1635         return(ret);
1636 }
1637
1638 gint32 ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error)
1639 {
1640         int ret, count;
1641         DWORD sent;
1642         WSABUF *wsabufs;
1643         DWORD sendflags = 0;
1644         
1645         MONO_ARCH_SAVE_REGS;
1646
1647         *error = 0;
1648         
1649         wsabufs = mono_array_addr (buffers, WSABUF, 0);
1650         count = mono_array_length (buffers);
1651         
1652         sendflags = convert_socketflags (flags);
1653         if (sendflags == -1) {
1654                 *error = WSAEOPNOTSUPP;
1655                 return(0);
1656         }
1657         
1658         ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL);
1659         if (ret == SOCKET_ERROR) {
1660                 *error = WSAGetLastError ();
1661                 return(0);
1662         }
1663         
1664         return(sent);
1665 }
1666
1667 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
1668 {
1669         int ret;
1670         guchar *buf;
1671         gint32 alen;
1672         int sendflags=0;
1673         struct sockaddr *sa;
1674         socklen_t sa_size;
1675         
1676         MONO_ARCH_SAVE_REGS;
1677
1678         *error = 0;
1679         
1680         alen = mono_array_length (buffer);
1681         if (offset > alen - count) {
1682                 return(0);
1683         }
1684
1685         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1686         if(*error != 0) {
1687                 return(0);
1688         }
1689         
1690         LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
1691         
1692         buf=mono_array_addr(buffer, guchar, offset);
1693
1694         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1695
1696         sendflags = convert_socketflags (flags);
1697         if (sendflags == -1) {
1698                 *error = WSAEOPNOTSUPP;
1699                 return (0);
1700         }
1701
1702         ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1703         if(ret==SOCKET_ERROR) {
1704                 *error = WSAGetLastError ();
1705         }
1706
1707         g_free(sa);
1708         
1709         return(ret);
1710 }
1711
1712 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
1713 {
1714         SOCKET sock;
1715         MonoClassField *field;
1716         
1717         field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
1718         sock=GPOINTER_TO_INT (*(gpointer *)(((char *)sockobj)+field->offset));
1719
1720         return(sock);
1721 }
1722
1723 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1724 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error)
1725 {
1726         MonoInternalThread *thread = NULL;
1727         MonoObject *obj;
1728         mono_pollfd *pfds;
1729         int nfds, idx;
1730         int ret;
1731         int i, count;
1732         int mode;
1733         MonoClass *sock_arr_class;
1734         MonoArray *socks;
1735         time_t start;
1736         uintptr_t socks_size;
1737         
1738         MONO_ARCH_SAVE_REGS;
1739
1740         /* *sockets -> READ, null, WRITE, null, ERROR, null */
1741         count = mono_array_length (*sockets);
1742         nfds = count - 3; /* NULL separators */
1743         pfds = g_new0 (mono_pollfd, nfds);
1744         mode = idx = 0;
1745         for (i = 0; i < count; i++) {
1746                 obj = mono_array_get (*sockets, MonoObject *, i);
1747                 if (obj == NULL) {
1748                         mode++;
1749                         continue;
1750                 }
1751
1752                 if (idx >= nfds) {
1753                         /* The socket array was bogus */
1754                         g_free (pfds);
1755                         *error = WSAEFAULT;
1756                         return;
1757                 }
1758
1759                 pfds [idx].fd = Socket_to_SOCKET (obj);
1760                 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1761                 idx++;
1762         }
1763
1764         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1765         start = time (NULL);
1766         do {
1767                 *error = 0;
1768                 ret = mono_poll (pfds, nfds, timeout);
1769                 if (timeout > 0 && ret < 0) {
1770                         int err = errno;
1771                         int sec = time (NULL) - start;
1772
1773                         timeout -= sec * 1000;
1774                         if (timeout < 0)
1775                                 timeout = 0;
1776                         errno = err;
1777                 }
1778
1779                 if (ret == -1 && errno == EINTR) {
1780                         int leave = 0;
1781                         if (thread == NULL)
1782                                 thread = mono_thread_internal_current ();
1783
1784                         leave = mono_thread_test_state (thread, ThreadState_AbortRequested | ThreadState_StopRequested);
1785                         
1786                         if (leave != 0) {
1787                                 g_free (pfds);
1788                                 *sockets = NULL;
1789                                 return;
1790                         } else {
1791                                 /* Suspend requested? */
1792                                 mono_thread_interruption_checkpoint ();
1793                         }
1794                         errno = EINTR;
1795                 }
1796         } while (ret == -1 && errno == EINTR);
1797         
1798         if (ret == -1) {
1799 #ifdef HOST_WIN32
1800                 *error = WSAGetLastError ();
1801 #else
1802                 *error = errno_to_WSA (errno, __func__);
1803 #endif
1804                 g_free (pfds);
1805                 return;
1806         }
1807
1808         if (ret == 0) {
1809                 g_free (pfds);
1810                 *sockets = NULL;
1811                 return;
1812         }
1813
1814         sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
1815         socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1816         socks = mono_array_new_full (mono_domain_get (), sock_arr_class, &socks_size, NULL);
1817
1818         mode = idx = 0;
1819         for (i = 0; i < count && ret > 0; i++) {
1820                 mono_pollfd *pfd;
1821
1822                 obj = mono_array_get (*sockets, MonoObject *, i);
1823                 if (obj == NULL) {
1824                         mode++;
1825                         idx++;
1826                         continue;
1827                 }
1828
1829                 pfd = &pfds [i - mode];
1830                 if (pfd->revents == 0)
1831                         continue;
1832
1833                 ret--;
1834                 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1835                         mono_array_setref (socks, idx++, obj);
1836                 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1837                         mono_array_setref (socks, idx++, obj);
1838                 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1839                         mono_array_setref (socks, idx++, obj);
1840                 }
1841         }
1842
1843         *sockets = socks;
1844         g_free (pfds);
1845 }
1846
1847 static MonoObject* int_to_object (MonoDomain *domain, int val)
1848 {
1849         return mono_value_box (domain, mono_get_int32_class (), &val);
1850 }
1851
1852
1853 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error)
1854 {
1855         int system_level;
1856         int system_name;
1857         int ret;
1858         int val;
1859         socklen_t valsize=sizeof(val);
1860         struct linger linger;
1861         socklen_t lingersize=sizeof(linger);
1862         int time_ms = 0;
1863         socklen_t time_ms_size = sizeof (time_ms);
1864 #ifdef SO_PEERCRED
1865 #  if defined(__OpenBSD__)
1866         struct sockpeercred cred;
1867 #  else
1868         struct ucred cred;
1869 #  endif
1870         socklen_t credsize = sizeof(cred);
1871 #endif
1872         MonoDomain *domain=mono_domain_get();
1873         MonoObject *obj;
1874         MonoClass *obj_class;
1875         MonoClassField *field;
1876         
1877         MONO_ARCH_SAVE_REGS;
1878
1879         *error = 0;
1880         
1881 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1882         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1883                 system_level = SOL_SOCKET;
1884                 system_name = SO_REUSEADDR;
1885                 ret = 0;
1886         } else
1887 #endif
1888         {
1889
1890                 ret = convert_sockopt_level_and_name (level, name, &system_level, &system_name);
1891         }
1892
1893         if(ret==-1) {
1894                 *error = WSAENOPROTOOPT;
1895                 return;
1896         }
1897         if (ret == -2) {
1898                 *obj_val = int_to_object (domain, 0);
1899                 return;
1900         }
1901         
1902         /* No need to deal with MulticastOption names here, because
1903          * you cant getsockopt AddMembership or DropMembership (the
1904          * int getsockopt will error, causing an exception)
1905          */
1906         switch(name) {
1907         case SocketOptionName_Linger:
1908         case SocketOptionName_DontLinger:
1909                 ret = _wapi_getsockopt(sock, system_level, system_name, &linger,
1910                                &lingersize);
1911                 break;
1912                 
1913         case SocketOptionName_SendTimeout:
1914         case SocketOptionName_ReceiveTimeout:
1915                 ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
1916                 break;
1917
1918 #ifdef SO_PEERCRED
1919         case SocketOptionName_PeerCred: 
1920                 ret = _wapi_getsockopt (sock, system_level, system_name, &cred,
1921                                         &credsize);
1922                 break;
1923 #endif
1924
1925         default:
1926                 ret = _wapi_getsockopt (sock, system_level, system_name, &val,
1927                                &valsize);
1928         }
1929         
1930         if(ret==SOCKET_ERROR) {
1931                 *error = WSAGetLastError ();
1932                 return;
1933         }
1934         
1935         switch(name) {
1936         case SocketOptionName_Linger:
1937                 /* build a System.Net.Sockets.LingerOption */
1938                 obj_class=mono_class_from_name(get_socket_assembly (),
1939                                                "System.Net.Sockets",
1940                                                "LingerOption");
1941                 obj=mono_object_new(domain, obj_class);
1942                 
1943                 /* Locate and set the fields "bool enabled" and "int
1944                  * seconds"
1945                  */
1946                 field=mono_class_get_field_from_name(obj_class, "enabled");
1947                 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1948
1949                 field=mono_class_get_field_from_name(obj_class, "seconds");
1950                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1951                 
1952                 break;
1953                 
1954         case SocketOptionName_DontLinger:
1955                 /* construct a bool int in val - true if linger is off */
1956                 obj = int_to_object (domain, !linger.l_onoff);
1957                 break;
1958                 
1959         case SocketOptionName_SendTimeout:
1960         case SocketOptionName_ReceiveTimeout:
1961                 obj = int_to_object (domain, time_ms);
1962                 break;
1963
1964 #ifdef SO_PEERCRED
1965         case SocketOptionName_PeerCred: 
1966         {
1967                 /* build a Mono.Posix.PeerCred+PeerCredData if
1968                  * possible
1969                  */
1970                 static MonoImage *mono_posix_image = NULL;
1971                 MonoPeerCredData *cred_data;
1972                 
1973                 if (mono_posix_image == NULL) {
1974                         mono_posix_image=mono_image_loaded ("Mono.Posix");
1975                         if (!mono_posix_image) {
1976                                 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
1977                                 if (!sa) {
1978                                         *error = WSAENOPROTOOPT;
1979                                         return;
1980                                 } else {
1981                                         mono_posix_image = mono_assembly_get_image (sa);
1982                                 }
1983                         }
1984                 }
1985                 
1986                 obj_class = mono_class_from_name(mono_posix_image,
1987                                                  "Mono.Posix",
1988                                                  "PeerCredData");
1989                 obj = mono_object_new(domain, obj_class);
1990                 cred_data = (MonoPeerCredData *)obj;
1991                 cred_data->pid = cred.pid;
1992                 cred_data->uid = cred.uid;
1993                 cred_data->gid = cred.gid;
1994                 break;
1995         }
1996 #endif
1997
1998         default:
1999 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2000                 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
2001                         val = val ? 0 : 1;
2002 #endif
2003                 obj = int_to_object (domain, val);
2004         }
2005         *obj_val=obj;
2006 }
2007
2008 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error)
2009 {
2010         int system_level;
2011         int system_name;
2012         int ret;
2013         guchar *buf;
2014         socklen_t valsize;
2015         
2016         MONO_ARCH_SAVE_REGS;
2017
2018         *error = 0;
2019         
2020         ret=convert_sockopt_level_and_name(level, name, &system_level,
2021                                            &system_name);
2022         if(ret==-1) {
2023                 *error = WSAENOPROTOOPT;
2024                 return;
2025         }
2026         if(ret==-2)
2027                 return;
2028
2029         valsize=mono_array_length(*byte_val);
2030         buf=mono_array_addr(*byte_val, guchar, 0);
2031         
2032         ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
2033         if(ret==SOCKET_ERROR) {
2034                 *error = WSAGetLastError ();
2035         }
2036 }
2037
2038 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2039 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
2040 {
2041         struct in_addr inaddr;
2042         MonoClassField *field;
2043         
2044         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
2045
2046         /* No idea why .net uses a 64bit type to hold a 32bit value...
2047          *
2048          * Internal value of IPAddess is in little-endian order
2049          */
2050         inaddr.s_addr=GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr)+field->offset));
2051         
2052         return(inaddr);
2053 }
2054
2055 #ifdef AF_INET6
2056 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
2057 {
2058         struct in6_addr in6addr;
2059         MonoClassField *field;
2060         MonoArray *data;
2061         int i;
2062
2063         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
2064         data=*(MonoArray **)(((char *)ipaddr) + field->offset);
2065
2066 /* Solaris has only the 8 bit version. */
2067 #ifndef s6_addr16
2068         for(i=0; i<8; i++) {
2069                 guint16 s = mono_array_get (data, guint16, i);
2070                 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
2071                 in6addr.s6_addr[2 * i] = s & 0xff;
2072         }
2073 #else
2074         for(i=0; i<8; i++)
2075                 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
2076 #endif
2077         return(in6addr);
2078 }
2079 #endif /* AF_INET6 */
2080 #endif
2081
2082 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)
2083 {
2084         struct linger linger;
2085         int system_level;
2086         int system_name;
2087         int ret;
2088 #ifdef AF_INET6
2089         int sol_ip;
2090         int sol_ipv6;
2091
2092         *error = 0;
2093         
2094 #ifdef HAVE_SOL_IPV6
2095         sol_ipv6 = SOL_IPV6;
2096 #else
2097         {
2098                 struct protoent *pent;
2099                 pent = getprotobyname ("ipv6");
2100                 sol_ipv6 = (pent != NULL) ? pent->p_proto : 41;
2101         }
2102 #endif
2103
2104 #ifdef HAVE_SOL_IP
2105         sol_ip = SOL_IP;
2106 #else
2107         {
2108                 struct protoent *pent;
2109                 pent = getprotobyname ("ip");
2110                 sol_ip = (pent != NULL) ? pent->p_proto : 0;
2111         }
2112 #endif
2113 #endif /* AF_INET6 */
2114
2115         MONO_ARCH_SAVE_REGS;
2116
2117         ret=convert_sockopt_level_and_name(level, name, &system_level,
2118                                            &system_name);
2119
2120 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2121         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2122                 system_name = SO_REUSEADDR;
2123                 int_val = int_val ? 0 : 1;
2124                 ret = 0;
2125         }
2126 #endif
2127
2128         if(ret==-1) {
2129                 *error = WSAENOPROTOOPT;
2130                 return;
2131         }
2132         if(ret==-2){
2133                 return;
2134         }
2135
2136         /* Only one of obj_val, byte_val or int_val has data */
2137         if(obj_val!=NULL) {
2138                 MonoClassField *field;
2139                 int valsize;
2140                 
2141                 switch(name) {
2142                 case SocketOptionName_Linger:
2143                         /* Dig out "bool enabled" and "int seconds"
2144                          * fields
2145                          */
2146                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
2147                         linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
2148                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
2149                         linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
2150                         
2151                         valsize=sizeof(linger);
2152                         ret = _wapi_setsockopt (sock, system_level,
2153                                                 system_name, &linger, valsize);
2154                         break;
2155                 case SocketOptionName_AddMembership:
2156                 case SocketOptionName_DropMembership:
2157 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2158                 {
2159                         MonoObject *address = NULL;
2160
2161 #ifdef AF_INET6
2162                         if(system_level == sol_ipv6) {
2163                                 struct ipv6_mreq mreq6;
2164
2165                                 /*
2166                                  *      Get group address
2167                                  */
2168                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
2169                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
2170                                 
2171                                 if(address) {
2172                                         mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
2173                                 }
2174
2175                                 field=mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
2176                                 mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
2177
2178                                 ret = _wapi_setsockopt (sock, system_level,
2179                                                         system_name, &mreq6,
2180                                                         sizeof (mreq6));
2181                         } else if(system_level == sol_ip)
2182 #endif /* AF_INET6 */
2183                         {
2184 #ifdef HAVE_STRUCT_IP_MREQN
2185                                 struct ip_mreqn mreq = {{0}};
2186 #else
2187                                 struct ip_mreq mreq = {{0}};
2188 #endif /* HAVE_STRUCT_IP_MREQN */
2189                         
2190                                 /* pain! MulticastOption holds two IPAddress
2191                                  * members, so I have to dig the value out of
2192                                  * those :-(
2193                                  */
2194                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
2195                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
2196
2197                                 /* address might not be defined and if so, set the address to ADDR_ANY.
2198                                  */
2199                                 if(address) {
2200                                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
2201                                 }
2202
2203                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
2204                                 address = *(gpointer *)(((char *)obj_val) + field->offset);
2205
2206 #ifdef HAVE_STRUCT_IP_MREQN
2207                                 if(address) {
2208                                         mreq.imr_address = ipaddress_to_struct_in_addr (address);
2209                                 }
2210 #else
2211                                 if(address) {
2212                                         mreq.imr_interface = ipaddress_to_struct_in_addr (address);
2213                                 }
2214 #endif /* HAVE_STRUCT_IP_MREQN */
2215                         
2216                                 ret = _wapi_setsockopt (sock, system_level,
2217                                                         system_name, &mreq,
2218                                                         sizeof (mreq));
2219                         }
2220                         break;
2221                 }
2222 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2223                 default:
2224                         /* Cause an exception to be thrown */
2225                         *error = WSAEINVAL;
2226                         return;
2227                 }
2228         } else if (byte_val!=NULL) {
2229                 int valsize = mono_array_length (byte_val);
2230                 guchar *buf = mono_array_addr (byte_val, guchar, 0);
2231                 
2232                 switch(name) {
2233                 case SocketOptionName_DontLinger:
2234                         if (valsize == 1) {
2235                                 linger.l_onoff = (*buf) ? 0 : 1;
2236                                 linger.l_linger = 0;
2237                                 ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2238                         } else {
2239                                 *error = WSAEINVAL;
2240                         }
2241                         break;
2242                 default:
2243                         ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
2244                         break;
2245                 }
2246         } else {
2247                 /* ReceiveTimeout/SendTimeout get here */
2248                 switch(name) {
2249                 case SocketOptionName_DontLinger:
2250                         linger.l_onoff = !int_val;
2251                         linger.l_linger = 0;
2252                         ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2253                         break;
2254                 case SocketOptionName_DontFragment:
2255 #ifdef HAVE_IP_MTU_DISCOVER
2256                         /* Fiddle with the value slightly if we're
2257                          * turning DF on
2258                          */
2259                         if (int_val == 1) {
2260                                 int_val = IP_PMTUDISC_DO;
2261                         }
2262                         /* Fall through */
2263 #endif
2264                         
2265                 default:
2266                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2267                 }
2268         }
2269
2270         if(ret==SOCKET_ERROR) {
2271                 *error = WSAGetLastError ();
2272         }
2273 }
2274
2275 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
2276                                                            gint32 how,
2277                                                            gint32 *error)
2278 {
2279         int ret;
2280         
2281         MONO_ARCH_SAVE_REGS;
2282
2283         *error = 0;
2284         
2285         /* Currently, the values for how (recv=0, send=1, both=2) match
2286          * the BSD API
2287          */
2288         ret = _wapi_shutdown (sock, how);
2289         if(ret==SOCKET_ERROR) {
2290                 *error = WSAGetLastError ();
2291         }
2292 }
2293
2294 gint
2295 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
2296                                               MonoArray *input,
2297                                               MonoArray *output, gint32 *error)
2298 {
2299         glong output_bytes = 0;
2300         gchar *i_buffer, *o_buffer;
2301         gint i_len, o_len;
2302         gint ret;
2303
2304         MONO_ARCH_SAVE_REGS;
2305
2306         *error = 0;
2307         
2308         if (code == FIONBIO) {
2309                 /* Invalid command. Must use Socket.Blocking */
2310                 return -1;
2311         }
2312
2313         if (input == NULL) {
2314                 i_buffer = NULL;
2315                 i_len = 0;
2316         } else {
2317                 i_buffer = mono_array_addr (input, gchar, 0);
2318                 i_len = mono_array_length (input);
2319         }
2320
2321         if (output == NULL) {
2322                 o_buffer = NULL;
2323                 o_len = 0;
2324         } else {
2325                 o_buffer = mono_array_addr (output, gchar, 0);
2326                 o_len = mono_array_length (output);
2327         }
2328
2329         ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2330         if (ret == SOCKET_ERROR) {
2331                 *error = WSAGetLastError ();
2332                 return(-1);
2333         }
2334
2335         return (gint) output_bytes;
2336 }
2337
2338 #ifdef HAVE_SIOCGIFCONF
2339 static gboolean
2340 is_loopback (int family, void *ad)
2341 {
2342         char *ptr = (char *) ad;
2343
2344         if (family == AF_INET) {
2345                 return (ptr [0] == 127);
2346         }
2347 #ifdef AF_INET6
2348         else {
2349                 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
2350         }
2351 #endif
2352         return FALSE;
2353 }
2354
2355 static void *
2356 get_local_ips (int family, int *nips)
2357 {
2358         int addr_size, offset, fd, i, count;
2359         int max_ifaces = 50; /* 50 interfaces should be enough... */
2360         struct ifconf ifc;
2361         struct ifreq *ifr;
2362         struct ifreq iflags;
2363         char *result, *tmp_ptr;
2364         gboolean ignore_loopback = FALSE;
2365
2366         *nips = 0;
2367         if (family == AF_INET) {
2368                 addr_size = sizeof (struct in_addr);
2369                 offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
2370 #ifdef AF_INET6
2371         } else if (family == AF_INET6) {
2372                 addr_size = sizeof (struct in6_addr);
2373                 offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
2374 #endif
2375         } else {
2376                 return NULL;
2377         }
2378
2379         fd = socket (family, SOCK_STREAM, 0);
2380
2381         ifc.ifc_len = max_ifaces * sizeof (struct ifreq);
2382         ifc.ifc_buf = g_malloc (ifc.ifc_len);
2383         if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
2384                 close (fd);
2385                 g_free (ifc.ifc_buf);
2386                 return NULL;
2387         }
2388
2389         count = ifc.ifc_len / sizeof (struct ifreq);
2390         *nips = count;
2391         if (count == 0) {
2392                 g_free (ifc.ifc_buf);
2393                 close (fd);
2394                 return NULL;
2395         }
2396
2397         for (i = 0, ifr = ifc.ifc_req; i < *nips; i++, ifr++) {
2398                 strcpy (iflags.ifr_name, ifr->ifr_name);
2399                 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
2400                         continue;
2401                 }
2402
2403                 if ((iflags.ifr_flags & IFF_UP) == 0) {
2404                         ifr->ifr_name [0] = '\0';
2405                         continue;
2406                 }
2407
2408                 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
2409                         ignore_loopback = TRUE;
2410                 }
2411         }
2412
2413         close (fd);
2414         result = g_malloc (addr_size * count);
2415         tmp_ptr = result;
2416         for (i = 0, ifr = ifc.ifc_req; i < count; i++, ifr++) {
2417                 if (ifr->ifr_name [0] == '\0') {
2418                         (*nips)--;
2419                         continue;
2420                 }
2421
2422                 if (ignore_loopback && is_loopback (family, ((char *) &ifr->ifr_addr) + offset)) {
2423                         (*nips)--;
2424                         continue;
2425                 }
2426
2427                 memcpy (tmp_ptr, ((char *) &ifr->ifr_addr) + offset, addr_size);
2428                 tmp_ptr += addr_size;
2429         }
2430
2431         g_free (ifc.ifc_buf);
2432         return result;
2433 }
2434 #elif defined(HAVE_GETIFADDRS)
2435 static gboolean
2436 is_loopback (int family, void *ad)
2437 {
2438         char *ptr = (char *) ad;
2439
2440         if (family == AF_INET) {
2441                 return (ptr [0] == 127);
2442         }
2443 #ifdef AF_INET6
2444         else {
2445                 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
2446         }
2447 #endif
2448         return FALSE;
2449 }
2450
2451 static void *
2452 get_local_ips (int family, int *nips)
2453 {
2454         struct ifaddrs *ifap = NULL, *ptr;
2455         int addr_size, offset, count, i;
2456         char *result, *tmp_ptr;
2457
2458         *nips = 0;
2459         if (family == AF_INET) {
2460                 addr_size = sizeof (struct in_addr);
2461                 offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
2462 #ifdef AF_INET6
2463         } else if (family == AF_INET6) {
2464                 addr_size = sizeof (struct in6_addr);
2465                 offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
2466 #endif
2467         } else {
2468                 return NULL;
2469         }
2470         
2471         if (getifaddrs (&ifap)) {
2472                 fprintf(stderr, "get_local_ips() error: %s\n", strerror (errno));
2473                 return NULL;
2474         }
2475         
2476         count = 0;
2477         for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
2478                 if (!ptr->ifa_addr)
2479                         continue;
2480                 if (ptr->ifa_addr->sa_family != family)
2481                         continue;
2482                 if (is_loopback (family, ((char *) ptr->ifa_addr) + offset))
2483                         continue;
2484                 count++;
2485         }
2486                 
2487         result = g_malloc (addr_size * count);
2488         tmp_ptr = result;
2489         for (i = 0, ptr = ifap; ptr; ptr = ptr->ifa_next) {
2490                 if (!ptr->ifa_addr)
2491                         continue;
2492                 if (ptr->ifa_addr->sa_family != family)
2493                         continue;
2494                 if (is_loopback (family, ((char *) ptr->ifa_addr) + offset))
2495                         continue;
2496                         
2497                 memcpy (tmp_ptr, ((char *) ptr->ifa_addr) + offset, addr_size);
2498                 tmp_ptr += addr_size;
2499         }
2500         
2501         freeifaddrs (ifap);
2502         *nips = count;
2503         return result;
2504 }
2505 #else
2506 static void *
2507 get_local_ips (int family, int *nips)
2508 {
2509         *nips = 0;
2510         return NULL;
2511 }
2512
2513 #endif /* HAVE_SIOCGIFCONF */
2514
2515 #ifndef AF_INET6
2516 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
2517                                        MonoArray **h_aliases,
2518                                        MonoArray **h_addr_list,
2519                                        gboolean add_local_ips)
2520 {
2521         MonoDomain *domain = mono_domain_get ();
2522         int i = 0;
2523         struct in_addr *local_in = NULL;
2524         int nlocal_in = 0;
2525
2526         if (he != NULL) {
2527                 if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
2528                         return(FALSE);
2529                 }
2530
2531                 *h_name=mono_string_new(domain, he->h_name);
2532
2533                 while(he->h_aliases[i]!=NULL) {
2534                         i++;
2535                 }
2536                 
2537                 *h_aliases=mono_array_new(domain, mono_get_string_class (), i);
2538                 i=0;
2539                 while(he->h_aliases[i]!=NULL) {
2540                         MonoString *alias;
2541                         
2542                         alias=mono_string_new(domain, he->h_aliases[i]);
2543                         mono_array_setref (*h_aliases, i, alias);
2544                         i++;
2545                 }
2546         } else if (!add_local_ips) {
2547                 return FALSE;
2548         }
2549
2550         if (add_local_ips) {
2551                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2552                 if (nlocal_in) {
2553                         *h_addr_list = mono_array_new(domain, mono_get_string_class (), nlocal_in);
2554                         for (i = 0; i < nlocal_in; i++) {
2555                                 MonoString *addr_string;
2556                                 char addr [16], *ptr;
2557                                 
2558                                 ptr = (char *) &local_in [i];
2559                                 g_snprintf(addr, 16, "%u.%u.%u.%u",
2560                                          (unsigned char) ptr [0],
2561                                          (unsigned char) ptr [1],
2562                                          (unsigned char) ptr [2],
2563                                          (unsigned char) ptr [3]);
2564                                 
2565                                 addr_string = mono_string_new (domain, addr);
2566                                 mono_array_setref (*h_addr_list, i, addr_string);
2567                                 i++;
2568                         }
2569
2570                         g_free (local_in);
2571                 } else if (he == NULL) {
2572                         /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */
2573                         *h_addr_list = mono_array_new(domain, mono_get_string_class (), 1);
2574                         mono_array_setref (*h_addr_list, 0, mono_string_new (domain, "127.0.0.1"));
2575                         return TRUE;
2576                 }
2577         }
2578         
2579         if (nlocal_in == 0 && he != NULL) {
2580                 i = 0;
2581                 while (he->h_addr_list[i]!=NULL) {
2582                         i++;
2583                 }
2584
2585                 *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
2586                 i=0;
2587                 while(he->h_addr_list[i]!=NULL) {
2588                         MonoString *addr_string;
2589                         char addr[16];
2590                         
2591                         g_snprintf(addr, 16, "%u.%u.%u.%u",
2592                                  (unsigned char)he->h_addr_list[i][0],
2593                                  (unsigned char)he->h_addr_list[i][1],
2594                                  (unsigned char)he->h_addr_list[i][2],
2595                                  (unsigned char)he->h_addr_list[i][3]);
2596                         
2597                         addr_string=mono_string_new(domain, addr);
2598                         mono_array_setref (*h_addr_list, i, addr_string);
2599                         i++;
2600                 }
2601         }
2602
2603         return(TRUE);
2604 }
2605
2606 static gboolean ipaddr_to_IPHostEntry(const char *addr, MonoString **h_name,
2607                                       MonoArray **h_aliases,
2608                                       MonoArray **h_addr_list)
2609 {
2610         MonoDomain *domain = mono_domain_get ();
2611
2612         *h_name=mono_string_new(domain, addr);
2613         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2614         *h_addr_list=mono_array_new(domain, mono_get_string_class (), 1);
2615         mono_array_setref (*h_addr_list, 0, *h_name);
2616
2617         return(TRUE);
2618 }
2619 #endif
2620
2621 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2622 static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name,
2623                                 MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
2624 {
2625         MonoDomain *domain = mono_domain_get ();
2626         int i, host_count, host_index, family_hint;
2627         struct in_addr *local_in = NULL;
2628         int nlocal_in = 0;
2629         struct in6_addr *local_in6 = NULL;
2630         int nlocal_in6 = 0;
2631         gboolean from_local = FALSE;
2632
2633         family_hint = get_family_hint ();
2634
2635         /*
2636          * Check if address length and family are correct
2637          */
2638         if (he1 != NULL && (he1->h_length!=4 || he1->h_addrtype!=AF_INET)) {
2639                 return(FALSE);
2640         }
2641
2642         if (he2 != NULL && (he2->h_length!=16 || he2->h_addrtype!=AF_INET6)) {
2643                 return(FALSE);
2644         }
2645
2646         /*
2647          * Get the aliases and host name from he1 or he2 whichever is
2648          * not null, if he1 is not null then take aliases from he1
2649          */
2650         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2651                             family_hint == PF_INET)) {
2652                 *h_name=mono_string_new (domain, he1->h_name);
2653
2654                 i=0;
2655                 while(he1->h_aliases[i]!=NULL) {
2656                         i++;
2657                 }
2658
2659                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2660                                            i);
2661                 i=0;
2662                 while(he1->h_aliases[i]!=NULL) {
2663                         MonoString *alias;
2664
2665                         alias=mono_string_new (domain, he1->h_aliases[i]);
2666                         mono_array_setref (*h_aliases, i, alias);
2667                         i++;
2668                 }
2669         } else if (he2 != NULL && (family_hint == PF_UNSPEC ||
2670                                    family_hint == PF_INET6)) {
2671                 *h_name=mono_string_new (domain, he2->h_name);
2672
2673                 i=0;
2674                 while(he2->h_aliases [i] != NULL) {
2675                         i++;
2676                 }
2677
2678                 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2679                                            i);
2680                 i=0;
2681                 while(he2->h_aliases[i]!=NULL) {
2682                         MonoString *alias;
2683
2684                         alias=mono_string_new (domain, he2->h_aliases[i]);
2685                         mono_array_setref (*h_aliases, i, alias);
2686                         i++;
2687                 }
2688         } else if (!add_local_ips) {
2689                 return(FALSE);
2690         }
2691
2692         /*
2693          * Count the number of addresses in he1 + he2
2694          */
2695         host_count = 0;
2696         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2697                             family_hint == PF_INET)) {
2698                 i=0;
2699                 while(he1->h_addr_list[i]!=NULL) {
2700                         i++;
2701                         host_count++;
2702                 }
2703         }
2704
2705         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2706                             family_hint == PF_INET6)) {
2707                 i=0;
2708                 while(he2->h_addr_list[i]!=NULL) {
2709                         i++;
2710                         host_count++;
2711                 }
2712         }
2713
2714         /*
2715          * Fills the array
2716          */
2717         host_index = 0;
2718         if (add_local_ips) {
2719                 if (family_hint == PF_UNSPEC || family_hint == PF_INET)
2720                         local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2721
2722                 if (family_hint == PF_UNSPEC || family_hint == PF_INET6)
2723                         local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2724
2725                 if (nlocal_in || nlocal_in6) {
2726                         from_local = TRUE;
2727                         *h_addr_list = mono_array_new (domain, mono_get_string_class (),
2728                                                              nlocal_in + nlocal_in6);
2729
2730                         if (nlocal_in6) {
2731                                 int n;
2732                                 for (n = 0; n < nlocal_in6; n++) {
2733                                         MonoString *addr_string;
2734                                         const char *ret;
2735                                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2736
2737                                         ret = inet_ntop (AF_INET6, &local_in6 [n], addr, sizeof(addr));
2738
2739                                         if (ret != NULL) {
2740                                                 addr_string = mono_string_new (domain, addr);
2741                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2742                                                 host_index++;
2743                                         }
2744                                 }
2745                         }
2746
2747                         if (nlocal_in) {
2748                                 int n;
2749                                 for (n = 0; n < nlocal_in; n++) {
2750                                         MonoString *addr_string;
2751                                         const char *ret;
2752                                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2753
2754                                         ret = inet_ntop (AF_INET, &local_in [n], addr, sizeof(addr));
2755
2756                                         if (ret != NULL) {
2757                                                 addr_string = mono_string_new (domain, addr);
2758                                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2759                                                 host_index++;
2760                                         }
2761                                 }
2762                         }
2763                         g_free (local_in);
2764                         g_free (local_in6);
2765                         return TRUE;
2766                 } else if (he1 == NULL && he2 == NULL) {
2767                         /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */
2768                         *h_addr_list = mono_array_new(domain, mono_get_string_class (), 1);
2769                         mono_array_setref (*h_addr_list, 0, mono_string_new (domain, "127.0.0.1"));
2770                         g_free (local_in);
2771                         g_free (local_in6);
2772                         return TRUE;
2773                 }
2774
2775                 g_free (local_in);
2776                 g_free (local_in6);
2777         }
2778
2779         *h_addr_list=mono_array_new (domain, mono_get_string_class (), host_count);
2780
2781         if (he2 != NULL && (family_hint == PF_UNSPEC ||
2782                             family_hint == PF_INET6)) {
2783                 i = 0;
2784                 while(he2->h_addr_list[i] != NULL) {
2785                         MonoString *addr_string;
2786                         const char *ret;
2787                         char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2788
2789                         ret = inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
2790                                          sizeof(addr));
2791
2792                         if (ret != NULL) {
2793                                 addr_string = mono_string_new (domain, addr);
2794                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2795                                 i++;
2796                                 host_index++;
2797                         }
2798                 }
2799         }
2800
2801         if (he1 != NULL && (family_hint == PF_UNSPEC ||
2802                             family_hint == PF_INET)) {
2803                 i=0;
2804                 while(he1->h_addr_list[i] != NULL) {
2805                         MonoString *addr_string;
2806                         const char *ret;
2807                         char addr[16]; /* INET_ADDRSTRLEN == 16 */
2808
2809                         ret = inet_ntop (AF_INET, he1->h_addr_list[i], addr,
2810                                          sizeof(addr));
2811
2812                         if (ret != NULL) {
2813                                 addr_string=mono_string_new (domain, addr);
2814                                 mono_array_setref (*h_addr_list, host_index, addr_string);
2815                                 i++;
2816                                 host_index++;
2817                         }
2818                 }
2819         }
2820
2821         return(TRUE);
2822 }
2823 #endif
2824
2825 #if defined(AF_INET6)
2826 static gboolean 
2827 addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
2828                                                 MonoArray **h_aliases,
2829                                                 MonoArray **h_addr_list,
2830                                                 gboolean add_local_ips)
2831 {
2832         gint32 count, i;
2833         struct addrinfo *ai = NULL;
2834         struct in_addr *local_in = NULL;
2835         int nlocal_in = 0;
2836         struct in6_addr *local_in6 = NULL;
2837         int nlocal_in6 = 0;
2838         int addr_index;
2839
2840         MonoDomain *domain = mono_domain_get ();
2841
2842         addr_index = 0;
2843         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2844         if (add_local_ips) {
2845                 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2846                 local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2847                 if (nlocal_in || nlocal_in6) {
2848                         *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
2849                         if (nlocal_in) {
2850                                 MonoString *addr_string;
2851                                 char addr [16];
2852                                 int i;
2853
2854                                 for (i = 0; i < nlocal_in; i++) {
2855                                         inet_ntop (AF_INET, &local_in [i], addr, sizeof (addr));
2856                                         addr_string = mono_string_new (domain, addr);
2857                                         mono_array_setref (*h_addr_list, addr_index, addr_string);
2858                                         addr_index++;
2859                                 }
2860                         }
2861
2862                         if (nlocal_in6) {
2863                                 MonoString *addr_string;
2864                                 const char *ret;
2865                                 char addr [48];
2866                                 int i;
2867
2868                                 for (i = 0; i < nlocal_in6; i++) {
2869                                         ret = inet_ntop (AF_INET6, &local_in6 [i], addr, sizeof (addr));
2870                                         if (ret != NULL) {
2871                                                 addr_string = mono_string_new (domain, addr);
2872                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2873                                                 addr_index++;
2874                                         }
2875                                 }
2876                         }
2877
2878                         g_free (local_in);
2879                         g_free (local_in6);
2880                         if (info) {
2881                                 freeaddrinfo (info);
2882                         }
2883                         return TRUE;
2884                 }
2885
2886                 g_free (local_in);
2887                 g_free (local_in6);
2888         }
2889
2890         for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
2891                 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2892                         continue;
2893
2894                 count++;
2895         }
2896
2897         *h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
2898
2899         for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
2900                 MonoString *addr_string;
2901                 const char *ret;
2902                 char buffer [48]; /* Max. size for IPv6 */
2903
2904                 if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
2905                         continue;
2906                 }
2907
2908                 if(ai->ai_family == PF_INET) {
2909                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, 16);
2910                 } else {
2911                         ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, 48);
2912                 }
2913
2914                 if(ret) {
2915                         addr_string=mono_string_new(domain, buffer);
2916                 } else {
2917                         addr_string=mono_string_new(domain, "");
2918                 }
2919
2920                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2921
2922                 if(!i) {
2923                         i++;
2924                         if (ai->ai_canonname != NULL) {
2925                                 *h_name=mono_string_new(domain, ai->ai_canonname);
2926                         } else {
2927                                 *h_name=mono_string_new(domain, buffer);
2928                         }
2929                 }
2930
2931                 addr_index++;
2932         }
2933
2934         if(info) {
2935                 freeaddrinfo(info);
2936         }
2937
2938         return(TRUE);
2939 }
2940 #endif
2941
2942 #ifdef AF_INET6
2943 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2944 {
2945         gboolean add_local_ips = FALSE;
2946 #ifdef HAVE_SIOCGIFCONF
2947         gchar this_hostname [256];
2948 #endif
2949 #if !defined(HAVE_GETHOSTBYNAME2_R)
2950         struct addrinfo *info = NULL, hints;
2951         char *hostname;
2952         
2953         MONO_ARCH_SAVE_REGS;
2954         
2955         hostname=mono_string_to_utf8 (host);
2956         if (*hostname == '\0') {
2957                 add_local_ips = TRUE;
2958                 *h_name = host;
2959         }
2960 #ifdef HAVE_SIOCGIFCONF
2961         if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2962                 if (!strcmp (hostname, this_hostname)) {
2963                         add_local_ips = TRUE;
2964                         *h_name = host;
2965                 }
2966         }
2967 #endif
2968
2969         memset(&hints, 0, sizeof(hints));
2970         hints.ai_family = get_family_hint ();
2971         hints.ai_socktype = SOCK_STREAM;
2972         hints.ai_flags = AI_CANONNAME;
2973
2974         if (*hostname && getaddrinfo(hostname, NULL, &hints, &info) == -1) {
2975                 return(FALSE);
2976         }
2977         
2978         g_free(hostname);
2979
2980         return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips));
2981 #else
2982         struct hostent he1,*hp1, he2, *hp2;
2983         int buffer_size1, buffer_size2;
2984         char *buffer1, *buffer2;
2985         int herr;
2986         gboolean return_value;
2987         char *hostname;
2988         
2989         MONO_ARCH_SAVE_REGS;
2990         
2991         hostname=mono_string_to_utf8 (host);
2992         if (*hostname == '\0')
2993                 add_local_ips = TRUE;
2994
2995 #ifdef HAVE_SIOCGIFCONF
2996         if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2997                 if (!strcmp (hostname, this_hostname))
2998                         add_local_ips = TRUE;
2999         }
3000 #endif
3001
3002         buffer_size1 = 512;
3003         buffer_size2 = 512;
3004         buffer1 = g_malloc0(buffer_size1);
3005         buffer2 = g_malloc0(buffer_size2);
3006
3007         hp1 = NULL;
3008         hp2 = NULL;
3009         while (*hostname && gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1,
3010                                 &hp1, &herr) == ERANGE) {
3011                 buffer_size1 *= 2;
3012                 buffer1 = g_realloc(buffer1, buffer_size1);
3013         }
3014
3015         if (*hostname && hp1 == NULL)
3016         {
3017                 while (gethostbyname2_r(hostname, AF_INET6, &he2, buffer2,
3018                                         buffer_size2, &hp2, &herr) == ERANGE) {
3019                         buffer_size2 *= 2;
3020                         buffer2 = g_realloc(buffer2, buffer_size2);
3021                 }
3022         }
3023
3024         return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
3025                                                h_addr_list, add_local_ips);
3026
3027         g_free(buffer1);
3028         g_free(buffer2);
3029         g_free(hostname);
3030
3031         return(return_value);
3032 #endif /* HAVE_GETHOSTBYNAME2_R */
3033 }
3034 #else /* AF_INET6 */
3035 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
3036 {
3037         struct hostent *he;
3038         char *hostname;
3039         gboolean add_local_ips = FALSE;
3040 #ifdef HAVE_SIOCGIFCONF
3041         gchar this_hostname [256];
3042 #endif
3043         
3044         MONO_ARCH_SAVE_REGS;
3045
3046         hostname=mono_string_to_utf8(host);
3047         if (*hostname == '\0')
3048                 add_local_ips = TRUE;
3049 #ifdef HAVE_SIOCGIFCONF
3050         if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
3051                 if (!strcmp (hostname, this_hostname))
3052                         add_local_ips = TRUE;
3053         }
3054 #endif
3055
3056 #ifndef HOST_WIN32
3057         he = NULL;
3058         if (*hostname)
3059                 he = _wapi_gethostbyname (hostname);
3060 #else
3061         he = _wapi_gethostbyname (hostname);
3062 #endif
3063         g_free(hostname);
3064
3065         if (*hostname && he==NULL)
3066                 return(FALSE);
3067
3068         return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips));
3069 }
3070 #endif /* AF_INET6 */
3071
3072 #ifndef HAVE_INET_PTON
3073 static int
3074 inet_pton (int family, const char *address, void *inaddrp)
3075 {
3076         if (family == AF_INET) {
3077 #ifdef HAVE_INET_ATON
3078                 struct in_addr inaddr;
3079                 
3080                 if (!inet_aton (address, &inaddr))
3081                         return 0;
3082                 
3083                 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
3084                 return 1;
3085 #else
3086                 /* assume the system has inet_addr(), if it doesn't
3087                    have that we're pretty much screwed... */
3088                 guint32 inaddr;
3089                 
3090                 if (!strcmp (address, "255.255.255.255")) {
3091                         /* special-case hack */
3092                         inaddr = 0xffffffff;
3093                 } else {
3094                         inaddr = inet_addr (address);
3095 #ifndef INADDR_NONE
3096 #define INADDR_NONE ((in_addr_t) -1)
3097 #endif
3098                         if (inaddr == INADDR_NONE)
3099                                 return 0;
3100                 }
3101                 
3102                 memcpy (inaddrp, &inaddr, sizeof (guint32));
3103                 return 1;
3104 #endif /* HAVE_INET_ATON */
3105         }
3106         
3107         return -1;
3108 }
3109 #endif /* !HAVE_INET_PTON */
3110
3111 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
3112 {
3113         char *address;
3114         
3115 #ifdef AF_INET6
3116         struct sockaddr_in saddr;
3117         struct sockaddr_in6 saddr6;
3118         struct addrinfo *info = NULL, hints;
3119         gint32 family;
3120         char hostname[1024] = {0};
3121         int flags = 0;
3122 #else
3123         struct in_addr inaddr;
3124         struct hostent *he;
3125         gboolean ret;
3126 #endif
3127
3128         address = mono_string_to_utf8 (addr);
3129
3130 #ifdef AF_INET6
3131         if (inet_pton (AF_INET, address, &saddr.sin_addr ) <= 0) {
3132                 /* Maybe an ipv6 address */
3133                 if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) <= 0) {
3134                         g_free (address);
3135                         return FALSE;
3136                 }
3137                 else {
3138                         family = AF_INET6;
3139                         saddr6.sin6_family = AF_INET6;
3140                 }
3141         }
3142         else {
3143                 family = AF_INET;
3144                 saddr.sin_family = AF_INET;
3145         }
3146         g_free(address);
3147
3148         if(family == AF_INET) {
3149 #if HAVE_SOCKADDR_IN_SIN_LEN
3150                 saddr.sin_len = sizeof (saddr);
3151 #endif
3152                 if(getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr),
3153                                 hostname, sizeof(hostname), NULL, 0,
3154                                 flags) != 0) {
3155                         return(FALSE);
3156                 }
3157         } else if(family == AF_INET6) {
3158 #if HAVE_SOCKADDR_IN6_SIN_LEN
3159                 saddr6.sin6_len = sizeof (saddr6);
3160 #endif
3161                 if(getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6),
3162                                 hostname, sizeof(hostname), NULL, 0,
3163                                 flags) != 0) {
3164                         return(FALSE);
3165                 }
3166         }
3167
3168         memset (&hints, 0, sizeof(hints));
3169         hints.ai_family = get_family_hint ();
3170         hints.ai_socktype = SOCK_STREAM;
3171         hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
3172
3173         if( getaddrinfo (hostname, NULL, &hints, &info) == -1 ) {
3174                 return(FALSE);
3175         }
3176
3177         return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE));
3178 #else
3179         if (inet_pton (AF_INET, address, &inaddr) <= 0) {
3180                 g_free (address);
3181                 return(FALSE);
3182         }
3183
3184         if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) {
3185                 ret = ipaddr_to_IPHostEntry (address, h_name, h_aliases, h_addr_list);
3186         } else {
3187                 ret = hostent_to_IPHostEntry (he, h_name, h_aliases,
3188                                               h_addr_list, FALSE);
3189         }
3190
3191         g_free (address);
3192         return(ret);
3193 #endif
3194 }
3195
3196 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
3197 {
3198         gchar hostname[256];
3199         int ret;
3200         
3201         MONO_ARCH_SAVE_REGS;
3202
3203         ret = gethostname (hostname, sizeof (hostname));
3204         if(ret==-1) {
3205                 return(FALSE);
3206         }
3207         
3208         *h_name=mono_string_new(mono_domain_get (), hostname);
3209
3210         return(TRUE);
3211 }
3212
3213 gboolean
3214 ves_icall_System_Net_Sockets_Socket_SendFile (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags)
3215 {
3216         HANDLE file;
3217         gint32 error;
3218         TRANSMIT_FILE_BUFFERS buffers;
3219
3220         MONO_ARCH_SAVE_REGS;
3221
3222         if (filename == NULL)
3223                 return FALSE;
3224
3225         file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, &error);
3226         if (file == INVALID_HANDLE_VALUE) {
3227                 SetLastError (error);
3228                 return FALSE;
3229         }
3230
3231         memset (&buffers, 0, sizeof (buffers));
3232         if (pre_buffer != NULL) {
3233                 buffers.Head = mono_array_addr (pre_buffer, guchar, 0);
3234                 buffers.HeadLength = mono_array_length (pre_buffer);
3235         }
3236         if (post_buffer != NULL) {
3237                 buffers.Tail = mono_array_addr (post_buffer, guchar, 0);
3238                 buffers.TailLength = mono_array_length (post_buffer);
3239         }
3240
3241         if (!TransmitFile (sock, file, 0, 0, NULL, &buffers, flags)) {
3242                 CloseHandle (file);
3243                 return FALSE;
3244         }
3245
3246         CloseHandle (file);
3247         return TRUE;
3248 }
3249
3250 void mono_network_init(void)
3251 {
3252         WSADATA wsadata;
3253         int err;
3254         
3255         err=WSAStartup(MAKEWORD(2,0), &wsadata);
3256         if(err!=0) {
3257                 g_error("%s: Couldn't initialise networking", __func__);
3258                 exit(-1);
3259         }
3260
3261         LOGDEBUG (g_message("%s: Using socket library: %s", __func__, wsadata.szDescription));
3262         LOGDEBUG (g_message("%s: Socket system status: %s", __func__, wsadata.szSystemStatus));
3263 }
3264
3265 void mono_network_cleanup(void)
3266 {
3267         WSACleanup();
3268 }
3269
3270 void
3271 icall_cancel_blocking_socket_operation (MonoThread *thread)
3272 {
3273         MonoInternalThread *internal = thread->internal_thread;
3274         
3275         if (mono_thread_info_new_interrupt_enabled ()) {
3276                 mono_thread_info_abort_socket_syscall_for_close ((MonoNativeThreadId)(gsize)internal->tid);
3277         } else {
3278 #ifndef HOST_WIN32
3279                 internal->ignore_next_signal = TRUE;
3280                 mono_thread_kill (internal, mono_thread_get_abort_signal ());           
3281 #endif
3282         }
3283 }
3284
3285 #endif /* #ifndef DISABLE_SOCKETS */