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