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