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