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