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