Merge pull request #2810 from kumpera/fix_hazard_free
[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)
1928 {
1929         MonoError error;
1930         MonoObject *result = mono_value_box_checked (domain, mono_get_int32_class (), &val, &error);
1931         mono_error_raise_exception (&error); /* FIXME don't raise here */
1932         return result;
1933 }
1934
1935 void
1936 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *werror)
1937 {
1938         int system_level = 0;
1939         int system_name = 0;
1940         int ret;
1941         int val;
1942         socklen_t valsize = sizeof (val);
1943         struct linger linger;
1944         socklen_t lingersize = sizeof (linger);
1945         int time_ms = 0;
1946         socklen_t time_ms_size = sizeof (time_ms);
1947 #ifdef SO_PEERCRED
1948 #  if defined(__OpenBSD__)
1949         struct sockpeercred cred;
1950 #  else
1951         struct ucred cred;
1952 #  endif
1953         socklen_t credsize = sizeof (cred);
1954 #endif
1955         MonoError error;
1956         MonoDomain *domain = mono_domain_get ();
1957         MonoObject *obj;
1958         MonoClass *obj_class;
1959         MonoClassField *field;
1960         
1961         *werror = 0;
1962         
1963 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1964         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1965                 system_level = SOL_SOCKET;
1966                 system_name = SO_REUSEADDR;
1967                 ret = 0;
1968         } else
1969 #endif
1970         {
1971                 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1972         }
1973
1974         if (ret == -1) {
1975                 *werror = WSAENOPROTOOPT;
1976                 return;
1977         }
1978         if (ret == -2) {
1979                 *obj_val = int_to_object (domain, 0);
1980                 return;
1981         }
1982
1983         MONO_PREPARE_BLOCKING;
1984
1985         /* No need to deal with MulticastOption names here, because
1986          * you cant getsockopt AddMembership or DropMembership (the
1987          * int getsockopt will error, causing an exception)
1988          */
1989         switch (name) {
1990         case SocketOptionName_Linger:
1991         case SocketOptionName_DontLinger:
1992                 ret = _wapi_getsockopt (sock, system_level, system_name, &linger, &lingersize);
1993                 break;
1994                 
1995         case SocketOptionName_SendTimeout:
1996         case SocketOptionName_ReceiveTimeout:
1997                 ret = _wapi_getsockopt (sock, system_level, system_name, (char *)&time_ms, &time_ms_size);
1998                 break;
1999
2000 #ifdef SO_PEERCRED
2001         case SocketOptionName_PeerCred: 
2002                 ret = _wapi_getsockopt (sock, system_level, system_name, &cred, &credsize);
2003                 break;
2004 #endif
2005
2006         default:
2007                 ret = _wapi_getsockopt (sock, system_level, system_name, &val, &valsize);
2008         }
2009
2010         MONO_FINISH_BLOCKING;
2011
2012         if (ret == SOCKET_ERROR) {
2013                 *werror = WSAGetLastError ();
2014                 return;
2015         }
2016         
2017         switch (name) {
2018         case SocketOptionName_Linger:
2019                 /* build a System.Net.Sockets.LingerOption */
2020                 obj_class = mono_class_load_from_name (get_socket_assembly (),
2021                                                                                            "System.Net.Sockets",
2022                                                                                            "LingerOption");
2023                 obj = mono_object_new_checked (domain, obj_class, &error);
2024                 if (!mono_error_ok (&error)) {
2025                         mono_error_set_pending_exception (&error);
2026                         return;
2027                 }
2028
2029                 /* Locate and set the fields "bool enabled" and "int
2030                  * lingerTime"
2031                  */
2032                 field = mono_class_get_field_from_name(obj_class, "enabled");
2033                 *(guint8 *)(((char *)obj)+field->offset) = linger.l_onoff;
2034
2035                 field = mono_class_get_field_from_name(obj_class, "lingerTime");
2036                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
2037                 break;
2038         case SocketOptionName_DontLinger:
2039                 /* construct a bool int in val - true if linger is off */
2040                 obj = int_to_object (domain, !linger.l_onoff);
2041                 break;
2042         case SocketOptionName_SendTimeout:
2043         case SocketOptionName_ReceiveTimeout:
2044                 obj = int_to_object (domain, time_ms);
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);
2091         }
2092
2093         *obj_val = obj;
2094 }
2095
2096 void
2097 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *werror)
2098 {
2099         int system_level = 0;
2100         int system_name = 0;
2101         int ret;
2102         guchar *buf;
2103         socklen_t valsize;
2104         
2105         *werror = 0;
2106         
2107         ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2108                                                                                  &system_name);
2109         if (ret == -1) {
2110                 *werror = WSAENOPROTOOPT;
2111                 return;
2112         }
2113         if (ret == -2)
2114                 return;
2115
2116         valsize = mono_array_length (*byte_val);
2117         buf = mono_array_addr (*byte_val, guchar, 0);
2118
2119         MONO_PREPARE_BLOCKING;
2120
2121         ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
2122
2123         MONO_FINISH_BLOCKING;
2124
2125         if (ret == SOCKET_ERROR)
2126                 *werror = WSAGetLastError ();
2127 }
2128
2129 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2130 static struct in_addr
2131 ipaddress_to_struct_in_addr (MonoObject *ipaddr)
2132 {
2133         struct in_addr inaddr;
2134         MonoClassField *field;
2135         
2136         field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Address");
2137
2138         /* No idea why .net uses a 64bit type to hold a 32bit value...
2139          *
2140          * Internal value of IPAddess is in little-endian order
2141          */
2142         inaddr.s_addr = GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr) + field->offset));
2143         
2144         return inaddr;
2145 }
2146
2147 static struct in6_addr
2148 ipaddress_to_struct_in6_addr (MonoObject *ipaddr)
2149 {
2150         struct in6_addr in6addr;
2151         MonoClassField *field;
2152         MonoArray *data;
2153         int i;
2154
2155         field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Numbers");
2156         data = *(MonoArray **)(((char *)ipaddr) + field->offset);
2157
2158 /* Solaris has only the 8 bit version. */
2159 #ifndef s6_addr16
2160         for (i = 0; i < 8; i++) {
2161                 guint16 s = mono_array_get (data, guint16, i);
2162                 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
2163                 in6addr.s6_addr[2 * i] = s & 0xff;
2164         }
2165 #else
2166         for (i = 0; i < 8; i++)
2167                 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
2168 #endif
2169         return in6addr;
2170 }
2171 #endif
2172
2173 #if defined(__APPLE__) || defined(__FreeBSD__)
2174
2175 static int
2176 get_local_interface_id (int family)
2177 {
2178 #if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
2179         return 0;
2180 #else
2181         struct ifaddrs *ifap = NULL, *ptr;
2182         int idx = 0;
2183         
2184         if (getifaddrs (&ifap))
2185                 return 0;
2186         
2187         for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
2188                 if (!ptr->ifa_addr || !ptr->ifa_name)
2189                         continue;
2190                 if (ptr->ifa_addr->sa_family != family)
2191                         continue;
2192                 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
2193                         continue;
2194                 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
2195                         continue;
2196                         
2197                 idx = if_nametoindex (ptr->ifa_name);
2198                 break;
2199         }
2200         
2201         freeifaddrs (ifap);
2202         return idx;
2203 #endif
2204 }
2205
2206 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
2207
2208 void
2209 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)
2210 {
2211         struct linger linger;
2212         int system_level = 0;
2213         int system_name = 0;
2214         int ret;
2215         int sol_ip;
2216         int sol_ipv6;
2217
2218         *werror = 0;
2219
2220         sol_ipv6 = mono_networking_get_ipv6_protocol ();
2221         sol_ip = mono_networking_get_ip_protocol ();
2222
2223         ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2224                                                                                   &system_name);
2225
2226 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2227         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2228                 system_name = SO_REUSEADDR;
2229                 int_val = int_val ? 0 : 1;
2230                 ret = 0;
2231         }
2232 #endif
2233
2234         if (ret == -1) {
2235                 *werror = WSAENOPROTOOPT;
2236                 return;
2237         }
2238         if (ret == -2)
2239                 return;
2240
2241         /* Only one of obj_val, byte_val or int_val has data */
2242         if (obj_val) {
2243                 MonoClassField *field;
2244                 int valsize;
2245                 
2246                 switch (name) {
2247                 case SocketOptionName_Linger:
2248                         /* Dig out "bool enabled" and "int lingerTime"
2249                          * fields
2250                          */
2251                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "enabled");
2252                         linger.l_onoff = *(guint8 *)(((char *)obj_val) + field->offset);
2253                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "lingerTime");
2254                         linger.l_linger = *(guint32 *)(((char *)obj_val) + field->offset);
2255                         
2256                         valsize = sizeof (linger);
2257                         ret = _wapi_setsockopt (sock, system_level,
2258                                                                         system_name, &linger, valsize);
2259                         break;
2260                 case SocketOptionName_AddMembership:
2261                 case SocketOptionName_DropMembership:
2262 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2263                 {
2264                         MonoObject *address = NULL;
2265
2266                         if (system_level == sol_ipv6) {
2267                                 struct ipv6_mreq mreq6;
2268
2269                                 /*
2270                                  *      Get group address
2271                                  */
2272                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Group");
2273                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2274                                 
2275                                 if (address)
2276                                         mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
2277
2278                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Interface");
2279                                 mreq6.ipv6mr_interface = *(guint64 *)(((char *)obj_val) + field->offset);
2280                                 
2281 #if defined(__APPLE__) || defined(__FreeBSD__)
2282                                 /*
2283                                 * Bug #5504:
2284                                 *
2285                                 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2286                                 *
2287                                 * Tests on Windows and Linux show that the multicast group is only
2288                                 * joined on one NIC when interface = 0, so we simply use the interface
2289                                 * id from the first non-loopback interface (this is also what
2290                                 * Dns.GetHostName (string.Empty) would return).
2291                                 */
2292                                 if (!mreq6.ipv6mr_interface)
2293                                         mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2294 #endif
2295                                         
2296                                 ret = _wapi_setsockopt (sock, system_level,
2297                                                                                 system_name, &mreq6,
2298                                                                                 sizeof (mreq6));
2299                         } else if (system_level == sol_ip) {
2300 #ifdef HAVE_STRUCT_IP_MREQN
2301                                 struct ip_mreqn mreq = {{0}};
2302 #else
2303                                 struct ip_mreq mreq = {{0}};
2304 #endif /* HAVE_STRUCT_IP_MREQN */
2305                         
2306                                 /*
2307                                  * pain! MulticastOption holds two IPAddress
2308                                  * members, so I have to dig the value out of
2309                                  * those :-(
2310                                  */
2311                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
2312                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2313
2314                                 /* address might not be defined and if so, set the address to ADDR_ANY.
2315                                  */
2316                                 if (address)
2317                                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
2318
2319                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "localAddress");
2320                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2321
2322 #ifdef HAVE_STRUCT_IP_MREQN
2323                                 if (address)
2324                                         mreq.imr_address = ipaddress_to_struct_in_addr (address);
2325
2326                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "ifIndex");
2327                                 mreq.imr_ifindex = *(gint32 *)(((char *)obj_val) + field->offset);
2328 #else
2329                                 if (address)
2330                                         mreq.imr_interface = ipaddress_to_struct_in_addr (address);
2331 #endif /* HAVE_STRUCT_IP_MREQN */
2332
2333                                 ret = _wapi_setsockopt (sock, system_level,
2334                                                                                 system_name, &mreq,
2335                                                                                 sizeof (mreq));
2336                         }
2337                         break;
2338                 }
2339 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2340                 default:
2341                         /* Cause an exception to be thrown */
2342                         *werror = WSAEINVAL;
2343                         return;
2344                 }
2345         } else if (byte_val!=NULL) {
2346                 int valsize = mono_array_length (byte_val);
2347                 guchar *buf = mono_array_addr (byte_val, guchar, 0);
2348                 
2349                 switch(name) {
2350                 case SocketOptionName_DontLinger:
2351                         if (valsize == 1) {
2352                                 linger.l_onoff = (*buf) ? 0 : 1;
2353                                 linger.l_linger = 0;
2354                                 ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2355                         } else {
2356                                 *werror = WSAEINVAL;
2357                         }
2358                         break;
2359                 default:
2360                         ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
2361                         break;
2362                 }
2363         } else {
2364                 /* ReceiveTimeout/SendTimeout get here */
2365                 switch (name) {
2366                 case SocketOptionName_DontLinger:
2367                         linger.l_onoff = !int_val;
2368                         linger.l_linger = 0;
2369                         ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2370                         break;
2371                 case SocketOptionName_MulticastInterface:
2372 #ifndef HOST_WIN32
2373 #ifdef HAVE_STRUCT_IP_MREQN
2374                         int_val = GUINT32_FROM_BE (int_val);
2375                         if ((int_val & 0xff000000) == 0) {
2376                                 /* int_val is interface index */
2377                                 struct ip_mreqn mreq = {{0}};
2378                                 mreq.imr_ifindex = int_val;
2379                                 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &mreq, sizeof (mreq));
2380                                 break;
2381                         }
2382                         int_val = GUINT32_TO_BE (int_val);
2383 #endif /* HAVE_STRUCT_IP_MREQN */
2384 #endif /* HOST_WIN32 */
2385                         /* int_val is in_addr */
2386                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2387                         break;
2388                 case SocketOptionName_DontFragment:
2389 #ifdef HAVE_IP_MTU_DISCOVER
2390                         /* Fiddle with the value slightly if we're
2391                          * turning DF on
2392                          */
2393                         if (int_val == 1)
2394                                 int_val = IP_PMTUDISC_DO;
2395                         /* Fall through */
2396 #endif
2397                         
2398                 default:
2399                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2400                 }
2401         }
2402
2403         if (ret == SOCKET_ERROR)
2404                 *werror = WSAGetLastError ();
2405 }
2406
2407 void
2408 ves_icall_System_Net_Sockets_Socket_Shutdown_internal (SOCKET sock, gint32 how, gint32 *werror)
2409 {
2410         int ret;
2411         gboolean interrupted;
2412
2413         *werror = 0;
2414
2415         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2416         if (interrupted) {
2417                 *werror = WSAEINTR;
2418                 return;
2419         }
2420
2421         MONO_PREPARE_BLOCKING;
2422
2423         /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2424         ret = _wapi_shutdown (sock, how);
2425
2426         MONO_FINISH_BLOCKING;
2427
2428         mono_thread_info_uninstall_interrupt (&interrupted);
2429         if (interrupted) {
2430                 *werror = WSAEINTR;
2431                 return;
2432         }
2433
2434         if (ret == SOCKET_ERROR)
2435                 *werror = WSAGetLastError ();
2436 }
2437
2438 gint
2439 ves_icall_System_Net_Sockets_Socket_IOControl_internal (SOCKET sock, gint32 code, MonoArray *input, MonoArray *output, gint32 *werror)
2440 {
2441         glong output_bytes = 0;
2442         gchar *i_buffer, *o_buffer;
2443         gint i_len, o_len;
2444         gint ret;
2445
2446         *werror = 0;
2447         
2448         if ((guint32)code == FIONBIO)
2449                 /* Invalid command. Must use Socket.Blocking */
2450                 return -1;
2451
2452         if (input == NULL) {
2453                 i_buffer = NULL;
2454                 i_len = 0;
2455         } else {
2456                 i_buffer = mono_array_addr (input, gchar, 0);
2457                 i_len = mono_array_length (input);
2458         }
2459
2460         if (output == NULL) {
2461                 o_buffer = NULL;
2462                 o_len = 0;
2463         } else {
2464                 o_buffer = mono_array_addr (output, gchar, 0);
2465                 o_len = mono_array_length (output);
2466         }
2467
2468         MONO_PREPARE_BLOCKING;
2469
2470         ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2471
2472         MONO_FINISH_BLOCKING;
2473
2474         if (ret == SOCKET_ERROR) {
2475                 *werror = WSAGetLastError ();
2476                 return -1;
2477         }
2478
2479         return (gint)output_bytes;
2480 }
2481
2482 static gboolean 
2483 addrinfo_to_IPHostEntry(MonoAddressInfo *info, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
2484 {
2485         gint32 count, i;
2486         MonoAddressEntry *ai = NULL;
2487         struct in_addr *local_in = NULL;
2488         int nlocal_in = 0;
2489         struct in6_addr *local_in6 = NULL;
2490         int nlocal_in6 = 0;
2491         int addr_index;
2492         MonoDomain *domain = mono_domain_get ();
2493
2494         addr_index = 0;
2495         *h_aliases = mono_array_new (domain, mono_get_string_class (), 0);
2496         if (add_local_ips) {
2497                 local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2498                 local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2499                 if (nlocal_in || nlocal_in6) {
2500                         char addr [INET6_ADDRSTRLEN];
2501                         *h_addr_list = mono_array_new (domain, mono_get_string_class (), nlocal_in + nlocal_in6);
2502                         if (nlocal_in) {
2503                                 MonoString *addr_string;
2504                                 int i;
2505
2506                                 for (i = 0; i < nlocal_in; i++) {
2507                                         MonoAddress maddr;
2508                                         mono_address_init (&maddr, AF_INET, &local_in [i]);
2509                                         if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2510                                                 addr_string = mono_string_new (domain, addr);
2511                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2512                                                 addr_index++;
2513                                         }
2514                                 }
2515                         }
2516
2517                         if (nlocal_in6) {
2518                                 MonoString *addr_string;
2519                                 int i;
2520
2521                                 for (i = 0; i < nlocal_in6; i++) {
2522                                         MonoAddress maddr;
2523                                         mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2524                                         if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2525                                                 addr_string = mono_string_new (domain, addr);
2526                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2527                                                 addr_index++;
2528                                         }
2529                                 }
2530                         }
2531
2532                         g_free (local_in);
2533                         g_free (local_in6);
2534                         if (info)
2535                                 mono_free_address_info (info);
2536                         return TRUE;
2537                 }
2538
2539                 g_free (local_in);
2540                 g_free (local_in6);
2541         }
2542
2543         for (count = 0, ai = info->entries; ai != NULL; ai = ai->next) {
2544                 if (ai->family != AF_INET && ai->family != AF_INET6)
2545                         continue;
2546                 count++;
2547         }
2548
2549         *h_addr_list = mono_array_new (domain, mono_get_string_class (), count);
2550
2551         for (ai = info->entries, i = 0; ai != NULL; ai = ai->next) {
2552                 MonoAddress maddr;
2553                 MonoString *addr_string;
2554                 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2555
2556                 if ((ai->family != PF_INET) && (ai->family != PF_INET6))
2557                         continue;
2558
2559                 mono_address_init (&maddr, ai->family, &ai->address);
2560                 if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
2561                         addr_string = mono_string_new (domain, buffer);
2562                 else
2563                         addr_string = mono_string_new (domain, "");
2564
2565                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2566
2567                 if (!i) {
2568                         i++;
2569                         if (ai->canonical_name != NULL) {
2570                                 *h_name = mono_string_new (domain, ai->canonical_name);
2571                         } else {
2572                                 *h_name = mono_string_new (domain, buffer);
2573                         }
2574                 }
2575
2576                 addr_index++;
2577         }
2578
2579         if (info)
2580                 mono_free_address_info (info);
2581
2582         return TRUE;
2583 }
2584
2585 static int
2586 get_addrinfo_family_hint (MonoError *error)
2587 {
2588         int hint;
2589
2590         mono_error_init (error);
2591
2592         hint = get_family_hint (error);
2593         return_val_if_nok (error, 0);
2594
2595         switch (hint) {
2596         case PF_UNSPEC:
2597                 return MONO_HINT_UNSPECIFIED;
2598         case PF_INET:
2599                 return MONO_HINT_IPV4;
2600 #ifdef PF_INET6
2601         case PF_INET6:
2602                 return MONO_HINT_IPV6;
2603 #endif
2604         default:
2605                 g_error ("invalid hint");
2606                 return 0;
2607         }
2608 }
2609
2610 MonoBoolean
2611 ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2612 {
2613         gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2614         gchar this_hostname [256];
2615         MonoAddressInfo *info = NULL;
2616         char *hostname = mono_string_to_utf8 (host);
2617         MonoError error;
2618         int hint;
2619
2620         hint = get_addrinfo_family_hint (&error);
2621         if (!mono_error_ok (&error)) {
2622                 mono_error_set_pending_exception (&error);
2623                 return FALSE;
2624         }
2625
2626         if (*hostname == '\0') {
2627                 add_local_ips = TRUE;
2628                 *h_name = host;
2629         }
2630
2631         if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2632                 if (!strcmp (hostname, this_hostname)) {
2633                         add_local_ips = TRUE;
2634                         *h_name = host;
2635                 }
2636         }
2637
2638         if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2639                 add_info_ok = FALSE;
2640
2641         g_free(hostname);
2642
2643         if (add_info_ok)
2644                 return addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, add_local_ips);
2645         return FALSE;
2646 }
2647
2648 MonoBoolean
2649 ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2650 {
2651         char *address;
2652         struct sockaddr_in saddr;
2653         struct sockaddr_in6 saddr6;
2654         MonoAddressInfo *info = NULL;
2655         MonoError error;
2656         gint32 family, hint;
2657         gchar hostname [NI_MAXHOST] = { 0 };
2658         gboolean ret;
2659
2660         address = mono_string_to_utf8 (addr);
2661
2662         if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2663                 family = AF_INET;
2664                 saddr.sin_family = AF_INET;
2665         } else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2666                 family = AF_INET6;
2667                 saddr6.sin6_family = AF_INET6;
2668         } else {
2669                 g_free (address);
2670                 return FALSE;
2671         }
2672
2673         g_free (address);
2674
2675         MONO_PREPARE_BLOCKING;
2676
2677         switch (family) {
2678         case AF_INET: {
2679 #if HAVE_SOCKADDR_IN_SIN_LEN
2680                 saddr.sin_len = sizeof (saddr);
2681 #endif
2682                 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2683                 break;
2684         }
2685         case AF_INET6: {
2686 #if HAVE_SOCKADDR_IN6_SIN_LEN
2687                 saddr6.sin6_len = sizeof (saddr6);
2688 #endif
2689                 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2690                 break;
2691         }
2692         default:
2693                 g_assert_not_reached ();
2694         }
2695
2696         MONO_FINISH_BLOCKING;
2697
2698         if (!ret)
2699                 return FALSE;
2700
2701         hint = get_addrinfo_family_hint (&error);
2702         if (!mono_error_ok (&error)) {
2703                 mono_error_set_pending_exception (&error);
2704                 return FALSE;
2705         }
2706         if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2707                 return FALSE;
2708
2709         return addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE);
2710 }
2711
2712 MonoBoolean
2713 ves_icall_System_Net_Dns_GetHostName_internal (MonoString **h_name)
2714 {
2715         gchar hostname [NI_MAXHOST] = { 0 };
2716         int ret;
2717
2718         ret = gethostname (hostname, sizeof (hostname));
2719         if (ret == -1)
2720                 return FALSE;
2721
2722         *h_name = mono_string_new (mono_domain_get (), hostname);
2723
2724         return TRUE;
2725 }
2726
2727 gboolean
2728 ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags)
2729 {
2730         HANDLE file;
2731         gint32 werror;
2732         gboolean ret;
2733         gboolean interrupted;
2734         TRANSMIT_FILE_BUFFERS buffers;
2735
2736         if (filename == NULL)
2737                 return FALSE;
2738
2739         /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2740
2741         file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, &werror);
2742
2743         if (file == INVALID_HANDLE_VALUE) {
2744                 SetLastError (werror);
2745                 return FALSE;
2746         }
2747
2748         memset (&buffers, 0, sizeof (buffers));
2749         if (pre_buffer != NULL) {
2750                 buffers.Head = mono_array_addr (pre_buffer, guchar, 0);
2751                 buffers.HeadLength = mono_array_length (pre_buffer);
2752         }
2753         if (post_buffer != NULL) {
2754                 buffers.Tail = mono_array_addr (post_buffer, guchar, 0);
2755                 buffers.TailLength = mono_array_length (post_buffer);
2756         }
2757
2758         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2759         if (interrupted) {
2760                 CloseHandle (file);
2761                 SetLastError (WSAEINTR);
2762                 return FALSE;
2763         }
2764
2765         MONO_PREPARE_BLOCKING;
2766
2767         ret = TransmitFile (sock, file, 0, 0, NULL, &buffers, flags);
2768
2769         MONO_FINISH_BLOCKING;
2770
2771         mono_thread_info_uninstall_interrupt (&interrupted);
2772         if (interrupted) {
2773                 CloseHandle (file);
2774                 SetLastError (WSAEINTR);
2775                 return FALSE;
2776         }
2777
2778         MONO_PREPARE_BLOCKING;
2779
2780         CloseHandle (file);
2781
2782         MONO_FINISH_BLOCKING;
2783
2784         return ret;
2785 }
2786
2787 gboolean
2788 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (void)
2789 {
2790 #if defined (SO_REUSEPORT) || defined (HOST_WIN32)
2791     return TRUE;
2792 #else
2793     return FALSE;
2794 #endif
2795 }
2796
2797 void
2798 mono_network_init (void)
2799 {
2800         mono_networking_init ();
2801 }
2802
2803 void
2804 mono_network_cleanup (void)
2805 {
2806         _wapi_cleanup_networking ();
2807         mono_networking_shutdown ();
2808 }
2809
2810 void
2811 icall_cancel_blocking_socket_operation (MonoThread *thread)
2812 {
2813         MonoInternalThread *internal;
2814
2815         internal = thread->internal_thread;
2816         g_assert (internal);
2817
2818         mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
2819 }
2820
2821 #endif /* #ifndef DISABLE_SOCKETS */