Merge pull request #2869 from BrzVlad/feature-mod-union-opt
[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, error);
851         return_val_if_nok (error, NULL);
852
853         /* The data buffer is laid out as follows:
854          * bytes 0 and 1 are the address family
855          * bytes 2 and 3 are the port info
856          * the rest is the address info
857          */
858                 
859         family = convert_to_mono_family (saddr->sa_family);
860         if (family == AddressFamily_Unknown) {
861                 *werror = WSAEAFNOSUPPORT;
862                 return NULL;
863         }
864
865         mono_array_set (data, guint8, 0, family & 0x0FF);
866         mono_array_set (data, guint8, 1, (family >> 8) & 0x0FF);
867         
868         if (saddr->sa_family == AF_INET) {
869                 struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr;
870                 guint16 port = ntohs (sa_in->sin_port);
871                 guint32 address = ntohl (sa_in->sin_addr.s_addr);
872                 
873                 if (sa_size < 8) {
874                         mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
875                         return NULL;
876                 }
877                 
878                 mono_array_set (data, guint8, 2, (port>>8) & 0xff);
879                 mono_array_set (data, guint8, 3, (port) & 0xff);
880                 mono_array_set (data, guint8, 4, (address>>24) & 0xff);
881                 mono_array_set (data, guint8, 5, (address>>16) & 0xff);
882                 mono_array_set (data, guint8, 6, (address>>8) & 0xff);
883                 mono_array_set (data, guint8, 7, (address) & 0xff);
884         
885                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
886
887                 return sockaddr_obj;
888         } else if (saddr->sa_family == AF_INET6) {
889                 struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)saddr;
890                 int i;
891
892                 guint16 port = ntohs (sa_in->sin6_port);
893
894                 if (sa_size < 28) {
895                         mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
896                         return NULL;
897                 }
898
899                 mono_array_set (data, guint8, 2, (port>>8) & 0xff);
900                 mono_array_set (data, guint8, 3, (port) & 0xff);
901                 
902                 if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
903                         // Map ::ffff:0:0 to :: (bug #5502)
904                         for (i = 0; i < 16; i++)
905                                 mono_array_set (data, guint8, 8 + i, 0);
906                 } else {
907                         for (i = 0; i < 16; i++) {
908                                 mono_array_set (data, guint8, 8 + i,
909                                                                 sa_in->sin6_addr.s6_addr [i]);
910                         }
911                 }
912
913                 mono_array_set (data, guint8, 24, sa_in->sin6_scope_id & 0xff);
914                 mono_array_set (data, guint8, 25,
915                                                 (sa_in->sin6_scope_id >> 8) & 0xff);
916                 mono_array_set (data, guint8, 26,
917                                                 (sa_in->sin6_scope_id >> 16) & 0xff);
918                 mono_array_set (data, guint8, 27,
919                                                 (sa_in->sin6_scope_id >> 24) & 0xff);
920
921                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
922
923                 return sockaddr_obj;
924         }
925 #ifdef HAVE_SYS_UN_H
926         else if (saddr->sa_family == AF_UNIX) {
927                 int i;
928
929                 for (i = 0; i < sa_size; i++)
930                         mono_array_set (data, guint8, i + 2, saddr->sa_data [i]);
931                 
932                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
933
934                 return sockaddr_obj;
935         }
936 #endif
937         else {
938                 *werror = WSAEAFNOSUPPORT;
939                 return NULL;
940         }
941 }
942
943 static int
944 get_sockaddr_size (int family)
945 {
946         int size;
947
948         size = 0;
949         if (family == AF_INET) {
950                 size = sizeof (struct sockaddr_in);
951         } else if (family == AF_INET6) {
952                 size = sizeof (struct sockaddr_in6);
953         }
954 #ifdef HAVE_SYS_UN_H
955         else if (family == AF_UNIX) {
956                 size = sizeof (struct sockaddr_un);
957         }
958 #endif
959         return size;
960 }
961
962 MonoObject*
963 ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal (SOCKET sock, gint32 af, gint32 *werror)
964 {
965         gchar *sa;
966         socklen_t salen;
967         int ret;
968         MonoObject *result;
969         MonoError error;
970         
971         *werror = 0;
972         
973         salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
974         if (salen == 0) {
975                 *werror = WSAEAFNOSUPPORT;
976                 return NULL;
977         }
978         sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
979
980         MONO_PREPARE_BLOCKING;
981
982         ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
983
984         MONO_FINISH_BLOCKING;
985         
986         if (ret == SOCKET_ERROR) {
987                 *werror = WSAGetLastError ();
988                 if (salen > 128)
989                         g_free (sa);
990                 return NULL;
991         }
992         
993         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)));
994
995         result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
996         if (salen > 128)
997                 g_free (sa);
998         if (!mono_error_ok (&error))
999                 mono_error_set_pending_exception (&error);
1000         return result;
1001 }
1002
1003 MonoObject*
1004 ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (SOCKET sock, gint32 af, gint32 *werror)
1005 {
1006         gchar *sa;
1007         socklen_t salen;
1008         int ret;
1009         MonoObject *result;
1010         MonoError error;
1011         
1012         *werror = 0;
1013         
1014         salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
1015         if (salen == 0) {
1016                 *werror = WSAEAFNOSUPPORT;
1017                 return NULL;
1018         }
1019         sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
1020         /* Note: linux returns just 2 for AF_UNIX. Always. */
1021
1022         MONO_PREPARE_BLOCKING;
1023
1024         ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
1025
1026         MONO_FINISH_BLOCKING;
1027
1028         if (ret == SOCKET_ERROR) {
1029                 *werror = WSAGetLastError ();
1030                 if (salen > 128)
1031                         g_free (sa);
1032                 return NULL;
1033         }
1034         
1035         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)));
1036
1037         result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
1038         if (salen > 128)
1039                 g_free (sa);
1040         if (!mono_error_ok (&error))
1041                 mono_error_set_pending_exception (&error);
1042         return result;
1043 }
1044
1045 static struct sockaddr*
1046 create_sockaddr_from_object (MonoObject *saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
1047 {
1048         MonoClassField *field;
1049         MonoArray *data;
1050         gint32 family;
1051         int len;
1052
1053         mono_error_init (error);
1054
1055         /* Dig the SocketAddress data buffer out of the object */
1056         field = mono_class_get_field_from_name (saddr_obj->vtable->klass, "data");
1057         data = *(MonoArray **)(((char *)saddr_obj) + field->offset);
1058
1059         /* The data buffer is laid out as follows:
1060          * byte 0 is the address family low byte
1061          * byte 1 is the address family high byte
1062          * INET:
1063          *      bytes 2 and 3 are the port info
1064          *      the rest is the address info
1065          * UNIX:
1066          *      the rest is the file name
1067          */
1068         len = mono_array_length (data);
1069         if (len < 2) {
1070                 mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1071                 return NULL;
1072         }
1073         
1074         family = convert_family ((MonoAddressFamily)(mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8)));
1075         if (family == AF_INET) {
1076                 struct sockaddr_in *sa;
1077                 guint16 port;
1078                 guint32 address;
1079                 
1080                 if (len < 8) {
1081                         mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1082                         return NULL;
1083                 }
1084
1085                 sa = g_new0 (struct sockaddr_in, 1);
1086                 port = (mono_array_get (data, guint8, 2) << 8) +
1087                         mono_array_get (data, guint8, 3);
1088                 address = (mono_array_get (data, guint8, 4) << 24) +
1089                         (mono_array_get (data, guint8, 5) << 16 ) +
1090                         (mono_array_get (data, guint8, 6) << 8) +
1091                         mono_array_get (data, guint8, 7);
1092
1093                 sa->sin_family = family;
1094                 sa->sin_addr.s_addr = htonl (address);
1095                 sa->sin_port = htons (port);
1096
1097                 *sa_size = sizeof (struct sockaddr_in);
1098                 return (struct sockaddr *)sa;
1099         } else if (family == AF_INET6) {
1100                 struct sockaddr_in6 *sa;
1101                 int i;
1102                 guint16 port;
1103                 guint32 scopeid;
1104                 
1105                 if (len < 28) {
1106                         mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1107                         return NULL;
1108                 }
1109
1110                 sa = g_new0 (struct sockaddr_in6, 1);
1111                 port = mono_array_get (data, guint8, 3) +
1112                         (mono_array_get (data, guint8, 2) << 8);
1113                 scopeid = mono_array_get (data, guint8, 24) + 
1114                         (mono_array_get (data, guint8, 25) << 8) + 
1115                         (mono_array_get (data, guint8, 26) << 16) + 
1116                         (mono_array_get (data, guint8, 27) << 24);
1117
1118                 sa->sin6_family = family;
1119                 sa->sin6_port = htons (port);
1120                 sa->sin6_scope_id = scopeid;
1121
1122                 for (i = 0; i < 16; i++)
1123                         sa->sin6_addr.s6_addr [i] = mono_array_get (data, guint8, 8 + i);
1124
1125                 *sa_size = sizeof (struct sockaddr_in6);
1126                 return (struct sockaddr *)sa;
1127         }
1128 #ifdef HAVE_SYS_UN_H
1129         else if (family == AF_UNIX) {
1130                 struct sockaddr_un *sock_un;
1131                 int i;
1132
1133                 /* Need a byte for the '\0' terminator/prefix, and the first
1134                  * two bytes hold the SocketAddress family
1135                  */
1136                 if (len - 2 >= sizeof (sock_un->sun_path)) {
1137                         mono_error_set_exception_instance (error, mono_get_exception_index_out_of_range ());
1138                         return NULL;
1139                 }
1140                 
1141                 sock_un = g_new0 (struct sockaddr_un, 1);
1142
1143                 sock_un->sun_family = family;
1144                 for (i = 0; i < len - 2; i++)
1145                         sock_un->sun_path [i] = mono_array_get (data, guint8, i + 2);
1146                 
1147                 *sa_size = len;
1148                 return (struct sockaddr *)sock_un;
1149         }
1150 #endif
1151         else {
1152                 *werror = WSAEAFNOSUPPORT;
1153                 return 0;
1154         }
1155 }
1156
1157 void
1158 ves_icall_System_Net_Sockets_Socket_Bind_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror)
1159 {
1160         MonoError error;
1161         struct sockaddr *sa;
1162         socklen_t sa_size;
1163         int ret;
1164         
1165         *werror = 0;
1166         
1167         sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
1168         if (*werror != 0)
1169                 return;
1170         if (!mono_error_ok (&error)) {
1171                 mono_error_set_pending_exception (&error);
1172                 return;
1173         }
1174
1175         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)));
1176
1177         ret = _wapi_bind (sock, sa, sa_size);
1178
1179         if (ret == SOCKET_ERROR)
1180                 *werror = WSAGetLastError ();
1181
1182         g_free (sa);
1183 }
1184
1185 enum {
1186         SelectModeRead,
1187         SelectModeWrite,
1188         SelectModeError
1189 };
1190
1191 MonoBoolean
1192 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1193                                                                                                    gint timeout, gint32 *werror)
1194 {
1195         MonoInternalThread *thread = mono_thread_internal_current ();
1196         mono_pollfd *pfds;
1197         int ret;
1198         gboolean interrupted;
1199         time_t start;
1200
1201         *werror = 0;
1202
1203         pfds = g_new0 (mono_pollfd, 1);
1204         pfds->fd = GPOINTER_TO_INT (sock);
1205
1206         switch (mode) {
1207         case SelectModeRead:
1208                 pfds->events = MONO_POLLIN;
1209                 break;
1210         case SelectModeWrite:
1211                 pfds->events = MONO_POLLOUT;
1212                 break;
1213         default:
1214                 pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL;
1215                 break;
1216         }
1217
1218         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1219         start = time (NULL);
1220
1221         do {
1222                 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1223                 if (interrupted) {
1224                         g_free (pfds);
1225                         *werror = WSAEINTR;
1226                         return FALSE;
1227                 }
1228
1229                 MONO_PREPARE_BLOCKING;
1230
1231                 ret = mono_poll (pfds, 1, timeout);
1232
1233                 MONO_FINISH_BLOCKING;
1234
1235                 mono_thread_info_uninstall_interrupt (&interrupted);
1236                 if (interrupted) {
1237                         g_free (pfds);
1238                         *werror = WSAEINTR;
1239                         return FALSE;
1240                 }
1241
1242                 if (timeout > 0 && ret < 0) {
1243                         int err = errno;
1244                         int sec = time (NULL) - start;
1245                         
1246                         timeout -= sec * 1000;
1247                         if (timeout < 0) {
1248                                 timeout = 0;
1249                         }
1250                         
1251                         errno = err;
1252                 }
1253
1254                 if (ret == -1 && errno == EINTR) {
1255                         if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
1256                                 g_free (pfds);
1257                                 return FALSE;
1258                         }
1259
1260                         /* Suspend requested? */
1261                         mono_thread_interruption_checkpoint ();
1262
1263                         errno = EINTR;
1264                 }
1265         } while (ret == -1 && errno == EINTR);
1266
1267         if (ret == -1) {
1268 #ifdef HOST_WIN32
1269                 *werror = WSAGetLastError ();
1270 #else
1271                 *werror = errno_to_WSA (errno, __func__);
1272 #endif
1273                 g_free (pfds);
1274                 return FALSE;
1275         }
1276
1277         g_free (pfds);
1278         return ret != 0;
1279 }
1280
1281 void
1282 ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror)
1283 {
1284         MonoError error;
1285         struct sockaddr *sa;
1286         socklen_t sa_size;
1287         int ret;
1288         gboolean interrupted;
1289
1290         *werror = 0;
1291
1292         sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
1293         if (*werror != 0)
1294                 return;
1295         if (!mono_error_ok (&error)) {
1296                 mono_error_set_pending_exception (&error);
1297                 return;
1298         }
1299
1300         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)));
1301
1302         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1303         if (interrupted) {
1304                 *werror = WSAEINTR;
1305                 return;
1306         }
1307
1308         MONO_PREPARE_BLOCKING;
1309
1310         ret = _wapi_connect (sock, sa, sa_size);
1311
1312         MONO_FINISH_BLOCKING;
1313
1314         mono_thread_info_uninstall_interrupt (&interrupted);
1315         if (interrupted) {
1316                 *werror = WSAEINTR;
1317                 return;
1318         }
1319
1320         if (ret == SOCKET_ERROR)
1321                 *werror = WSAGetLastError ();
1322
1323         g_free (sa);
1324 }
1325
1326 /* These #defines from mswsock.h from wine.  Defining them here allows
1327  * us to build this file on a mingw box that doesn't know the magic
1328  * numbers, but still run on a newer windows box that does.
1329  */
1330 #ifndef WSAID_DISCONNECTEX
1331 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1332 typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
1333 #endif
1334
1335 #ifndef WSAID_TRANSMITFILE
1336 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1337 typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
1338 #endif
1339
1340 void
1341 ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolean reuse, gint32 *werror)
1342 {
1343         int ret;
1344         glong output_bytes = 0;
1345         GUID disco_guid = WSAID_DISCONNECTEX;
1346         GUID trans_guid = WSAID_TRANSMITFILE;
1347         LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
1348         LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
1349         gboolean interrupted;
1350
1351         *werror = 0;
1352
1353         LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
1354
1355         MONO_PREPARE_BLOCKING;
1356
1357         /* I _think_ the extension function pointers need to be looked
1358          * up for each socket.  FIXME: check the best way to store
1359          * pointers to functions in managed objects that still works
1360          * on 64bit platforms.
1361          */
1362         ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&disco_guid, sizeof (GUID),
1363                                         (gchar *)&_wapi_disconnectex, sizeof (void *), &output_bytes, NULL, NULL);
1364
1365         MONO_FINISH_BLOCKING;
1366
1367         if (ret != 0) {
1368                 /* make sure that WSAIoctl didn't put crap in the
1369                  * output pointer
1370                  */
1371                 _wapi_disconnectex = NULL;
1372
1373                 MONO_PREPARE_BLOCKING;
1374
1375                 /*
1376                  * Use the SIO_GET_EXTENSION_FUNCTION_POINTER to
1377                  * determine the address of the disconnect method without
1378                  * taking a hard dependency on a single provider
1379                  * 
1380                  * For an explanation of why this is done, you can read
1381                  * the article at http://www.codeproject.com/internet/jbsocketserver3.asp
1382                  */
1383                 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&trans_guid, sizeof(GUID),
1384                                 (gchar *)&_wapi_transmitfile, sizeof(void *), &output_bytes, NULL, NULL);
1385
1386                 MONO_FINISH_BLOCKING;
1387
1388                 if (ret != 0)
1389                         _wapi_transmitfile = NULL;
1390         }
1391
1392         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1393         if (interrupted) {
1394                 *werror = WSAEINTR;
1395                 return;
1396         }
1397
1398         MONO_PREPARE_BLOCKING;
1399
1400         if (_wapi_disconnectex != NULL) {
1401                 if (!_wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0))
1402                         *werror = WSAGetLastError ();
1403         } else if (_wapi_transmitfile != NULL) {
1404                 if (!_wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET))
1405                         *werror = WSAGetLastError ();
1406         } else {
1407                 *werror = ERROR_NOT_SUPPORTED;
1408         }
1409
1410         MONO_FINISH_BLOCKING;
1411
1412         mono_thread_info_uninstall_interrupt (&interrupted);
1413         if (interrupted)
1414                 *werror = WSAEINTR;
1415 }
1416
1417 gint32
1418 ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror)
1419 {
1420         int ret;
1421         guchar *buf;
1422         gint32 alen;
1423         int recvflags = 0;
1424         gboolean interrupted;
1425         MonoInternalThread* curthread G_GNUC_UNUSED = mono_thread_internal_current ();
1426         
1427         *werror = 0;
1428         
1429         alen = mono_array_length (buffer);
1430         if (offset > alen - count)
1431                 return 0;
1432         
1433         buf = mono_array_addr (buffer, guchar, offset);
1434         
1435         recvflags = convert_socketflags (flags);
1436         if (recvflags == -1) {
1437                 *werror = WSAEOPNOTSUPP;
1438                 return 0;
1439         }
1440
1441         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1442         if (interrupted)
1443                 return 0;
1444
1445         MONO_PREPARE_BLOCKING;
1446
1447 #ifdef HOST_WIN32
1448         {
1449                 curthread->interrupt_on_stop = (gpointer)TRUE;
1450                 ret = _wapi_recv (sock, buf, count, recvflags);
1451                 curthread->interrupt_on_stop = (gpointer)FALSE;
1452         }
1453 #else
1454         ret = _wapi_recv (sock, buf, count, recvflags);
1455 #endif
1456
1457         MONO_FINISH_BLOCKING;
1458
1459         mono_thread_info_uninstall_interrupt (&interrupted);
1460         if (interrupted) {
1461                 *werror = WSAEINTR;
1462                 return 0;
1463         }
1464
1465         if (ret == SOCKET_ERROR) {
1466                 *werror = WSAGetLastError ();
1467                 return 0;
1468         }
1469
1470         return ret;
1471 }
1472
1473 gint32
1474 ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror)
1475 {
1476         int ret, count;
1477         gboolean interrupted;
1478         DWORD recv;
1479         WSABUF *wsabufs;
1480         DWORD recvflags = 0;
1481         
1482         *werror = 0;
1483         
1484         wsabufs = mono_array_addr (buffers, WSABUF, 0);
1485         count = mono_array_length (buffers);
1486         
1487         recvflags = convert_socketflags (flags);
1488         if (recvflags == -1) {
1489                 *werror = WSAEOPNOTSUPP;
1490                 return 0;
1491         }
1492
1493         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1494         if (interrupted) {
1495                 *werror = WSAEINTR;
1496                 return 0;
1497         }
1498
1499         MONO_PREPARE_BLOCKING;
1500
1501         ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL);
1502
1503         MONO_FINISH_BLOCKING;
1504
1505         mono_thread_info_uninstall_interrupt (&interrupted);
1506         if (interrupted) {
1507                 *werror = WSAEINTR;
1508                 return 0;
1509         }
1510
1511         if (ret == SOCKET_ERROR) {
1512                 *werror = WSAGetLastError ();
1513                 return 0;
1514         }
1515
1516         return recv;
1517 }
1518
1519 gint32
1520 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *werror)
1521 {
1522         MonoError error;
1523         int ret;
1524         guchar *buf;
1525         gint32 alen;
1526         int recvflags = 0;
1527         struct sockaddr *sa;
1528         socklen_t sa_size;
1529         gboolean interrupted;
1530         
1531         *werror = 0;
1532         
1533         alen = mono_array_length (buffer);
1534         if (offset > alen - count)
1535                 return 0;
1536
1537         sa = create_sockaddr_from_object (*sockaddr, &sa_size, werror, &error);
1538         if (*werror != 0)
1539                 return 0;
1540         if (!mono_error_ok (&error)) {
1541                 mono_error_set_pending_exception (&error);
1542                 return 0;
1543         }
1544         
1545         buf = mono_array_addr (buffer, guchar, offset);
1546         
1547         recvflags = convert_socketflags (flags);
1548         if (recvflags == -1) {
1549                 *werror = WSAEOPNOTSUPP;
1550                 return 0;
1551         }
1552
1553         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1554         if (interrupted) {
1555                 g_free (sa);
1556                 *werror = WSAEINTR;
1557                 return 0;
1558         }
1559
1560         MONO_PREPARE_BLOCKING;
1561
1562         ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1563
1564         MONO_FINISH_BLOCKING;
1565
1566         mono_thread_info_uninstall_interrupt (&interrupted);
1567         if (interrupted) {
1568                 g_free (sa);
1569                 *werror = WSAEINTR;
1570                 return 0;
1571         }
1572
1573         if (ret==SOCKET_ERROR) {
1574                 g_free (sa);
1575                 *werror = WSAGetLastError ();
1576                 return 0;
1577         }
1578
1579         /* If we didn't get a socket size, then we're probably a
1580          * connected connection-oriented socket and the stack hasn't
1581          * returned the remote address. All we can do is return null.
1582          */
1583         if (sa_size) {
1584                 *sockaddr = create_object_from_sockaddr (sa, sa_size, werror, &error);
1585                 if (!mono_error_ok (&error)) {
1586                         mono_error_set_pending_exception (&error);
1587                         g_free (sa);
1588                         return 0;
1589                 }
1590         } else {
1591                 *sockaddr = NULL;
1592         }
1593
1594         g_free (sa);
1595         
1596         return ret;
1597 }
1598
1599 gint32
1600 ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror)
1601 {
1602         int ret;
1603         guchar *buf;
1604         gint32 alen;
1605         int sendflags = 0;
1606         gboolean interrupted;
1607         
1608         *werror = 0;
1609         
1610         alen = mono_array_length (buffer);
1611         if (offset > alen - count)
1612                 return 0;
1613
1614         LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
1615         
1616         buf = mono_array_addr (buffer, guchar, offset);
1617
1618         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1619
1620         sendflags = convert_socketflags (flags);
1621         if (sendflags == -1) {
1622                 *werror = WSAEOPNOTSUPP;
1623                 return 0;
1624         }
1625
1626         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1627         if (interrupted) {
1628                 *werror = WSAEINTR;
1629                 return 0;
1630         }
1631
1632         MONO_PREPARE_BLOCKING;
1633
1634         ret = _wapi_send (sock, buf, count, sendflags);
1635
1636         MONO_FINISH_BLOCKING;
1637
1638         mono_thread_info_uninstall_interrupt (&interrupted);
1639         if (interrupted) {
1640                 *werror = WSAEINTR;
1641                 return 0;
1642         }
1643
1644         if (ret == SOCKET_ERROR) {
1645                 *werror = WSAGetLastError ();
1646                 return 0;
1647         }
1648
1649         return ret;
1650 }
1651
1652 gint32
1653 ves_icall_System_Net_Sockets_Socket_Send_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror)
1654 {
1655         int ret, count;
1656         DWORD sent;
1657         WSABUF *wsabufs;
1658         DWORD sendflags = 0;
1659         gboolean interrupted;
1660         
1661         *werror = 0;
1662         
1663         wsabufs = mono_array_addr (buffers, WSABUF, 0);
1664         count = mono_array_length (buffers);
1665         
1666         sendflags = convert_socketflags (flags);
1667         if (sendflags == -1) {
1668                 *werror = WSAEOPNOTSUPP;
1669                 return 0;
1670         }
1671
1672         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1673         if (interrupted) {
1674                 *werror = WSAEINTR;
1675                 return 0;
1676         }
1677
1678         MONO_PREPARE_BLOCKING;
1679
1680         ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL);
1681
1682         MONO_FINISH_BLOCKING;
1683
1684         mono_thread_info_uninstall_interrupt (&interrupted);
1685         if (interrupted) {
1686                 *werror = WSAEINTR;
1687                 return 0;
1688         }
1689
1690         if (ret == SOCKET_ERROR) {
1691                 *werror = WSAGetLastError ();
1692                 return 0;
1693         }
1694         
1695         return sent;
1696 }
1697
1698 gint32
1699 ves_icall_System_Net_Sockets_Socket_SendTo_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *werror)
1700 {
1701         MonoError error;
1702         int ret;
1703         guchar *buf;
1704         gint32 alen;
1705         int sendflags = 0;
1706         struct sockaddr *sa;
1707         socklen_t sa_size;
1708         gboolean interrupted;
1709         
1710         *werror = 0;
1711         
1712         alen = mono_array_length (buffer);
1713         if (offset > alen - count) {
1714                 return 0;
1715         }
1716
1717         sa = create_sockaddr_from_object(sockaddr, &sa_size, werror, &error);
1718         if (*werror != 0)
1719                 return 0;
1720         if (!mono_error_ok (&error)) {
1721                 mono_error_set_pending_exception (&error);
1722                 return 0;
1723         }
1724         
1725         LOGDEBUG (g_message ("%s: alen: %d", __func__, alen));
1726         
1727         buf = mono_array_addr (buffer, guchar, offset);
1728
1729         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1730
1731         sendflags = convert_socketflags (flags);
1732         if (sendflags == -1) {
1733                 g_free (sa);
1734                 *werror = WSAEOPNOTSUPP;
1735                 return 0;
1736         }
1737
1738         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1739         if (interrupted) {
1740                 g_free (sa);
1741                 *werror = WSAEINTR;
1742                 return 0;
1743         }
1744
1745         MONO_PREPARE_BLOCKING;
1746
1747         ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1748
1749         MONO_FINISH_BLOCKING;
1750
1751         mono_thread_info_uninstall_interrupt (&interrupted);
1752         if (interrupted) {
1753                 g_free (sa);
1754                 *werror = WSAEINTR;
1755                 return 0;
1756         }
1757
1758         if (ret == SOCKET_ERROR)
1759                 *werror = WSAGetLastError ();
1760
1761         g_free (sa);
1762         
1763         return ret;
1764 }
1765
1766 static SOCKET
1767 Socket_to_SOCKET (MonoObject *sockobj)
1768 {
1769         MonoSafeHandle *safe_handle;
1770         MonoClassField *field;
1771         
1772         field = mono_class_get_field_from_name (sockobj->vtable->klass, "safe_handle");
1773         safe_handle = ((MonoSafeHandle *)(*(gpointer *)(((char *)sockobj) + field->offset)));
1774
1775         if (safe_handle == NULL)
1776                 return -1;
1777
1778         return (SOCKET)safe_handle->handle;
1779 }
1780
1781 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1782
1783 void
1784 ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32 timeout, gint32 *werror)
1785 {
1786         MonoError error;
1787         MonoInternalThread *thread = mono_thread_internal_current ();
1788         MonoObject *obj;
1789         mono_pollfd *pfds;
1790         int nfds, idx;
1791         int ret;
1792         int i, count;
1793         int mode;
1794         MonoClass *sock_arr_class;
1795         MonoArray *socks;
1796         time_t start;
1797         uintptr_t socks_size;
1798         gboolean interrupted;
1799
1800         *werror = 0;
1801
1802         /* *sockets -> READ, null, WRITE, null, ERROR, null */
1803         count = mono_array_length (*sockets);
1804         nfds = count - 3; /* NULL separators */
1805         pfds = g_new0 (mono_pollfd, nfds);
1806         mode = idx = 0;
1807         for (i = 0; i < count; i++) {
1808                 obj = mono_array_get (*sockets, MonoObject *, i);
1809                 if (obj == NULL) {
1810                         mode++;
1811                         continue;
1812                 }
1813
1814                 if (idx >= nfds) {
1815                         /* The socket array was bogus */
1816                         g_free (pfds);
1817                         *werror = WSAEFAULT;
1818                         return;
1819                 }
1820
1821                 pfds [idx].fd = Socket_to_SOCKET (obj);
1822                 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1823                 idx++;
1824         }
1825
1826         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1827         start = time (NULL);
1828         do {
1829                 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1830                 if (interrupted) {
1831                         g_free (pfds);
1832                         *werror = WSAEINTR;
1833                         return;
1834                 }
1835
1836                 MONO_PREPARE_BLOCKING;
1837
1838                 ret = mono_poll (pfds, nfds, timeout);
1839
1840                 MONO_FINISH_BLOCKING;
1841
1842                 mono_thread_info_uninstall_interrupt (&interrupted);
1843                 if (interrupted) {
1844                         g_free (pfds);
1845                         *werror = WSAEINTR;
1846                         return;
1847                 }
1848
1849                 if (timeout > 0 && ret < 0) {
1850                         int err = errno;
1851                         int sec = time (NULL) - start;
1852
1853                         timeout -= sec * 1000;
1854                         if (timeout < 0)
1855                                 timeout = 0;
1856                         errno = err;
1857                 }
1858
1859                 if (ret == -1 && errno == EINTR) {
1860                         if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
1861                                 g_free (pfds);
1862                                 *sockets = NULL;
1863                                 return;
1864                         }
1865
1866                         /* Suspend requested? */
1867                         mono_thread_interruption_checkpoint ();
1868
1869                         errno = EINTR;
1870                 }
1871         } while (ret == -1 && errno == EINTR);
1872         
1873         if (ret == -1) {
1874 #ifdef HOST_WIN32
1875                 *werror = WSAGetLastError ();
1876 #else
1877                 *werror = errno_to_WSA (errno, __func__);
1878 #endif
1879                 g_free (pfds);
1880                 return;
1881         }
1882
1883         if (ret == 0) {
1884                 g_free (pfds);
1885                 *sockets = NULL;
1886                 return;
1887         }
1888
1889         sock_arr_class = ((MonoObject *)*sockets)->vtable->klass;
1890         socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1891         socks = mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, &error);
1892         if (!mono_error_ok (&error)) {
1893                 mono_error_set_pending_exception (&error);
1894                 g_free (pfds);
1895                 return;
1896         }
1897
1898         mode = idx = 0;
1899         for (i = 0; i < count && ret > 0; i++) {
1900                 mono_pollfd *pfd;
1901
1902                 obj = mono_array_get (*sockets, MonoObject *, i);
1903                 if (obj == NULL) {
1904                         mode++;
1905                         idx++;
1906                         continue;
1907                 }
1908
1909                 pfd = &pfds [i - mode];
1910                 if (pfd->revents == 0)
1911                         continue;
1912
1913                 ret--;
1914                 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1915                         mono_array_setref (socks, idx++, obj);
1916                 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1917                         mono_array_setref (socks, idx++, obj);
1918                 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1919                         mono_array_setref (socks, idx++, obj);
1920                 }
1921         }
1922
1923         *sockets = socks;
1924         g_free (pfds);
1925 }
1926
1927 static MonoObject*
1928 int_to_object (MonoDomain *domain, int val, MonoError *error)
1929 {
1930         return mono_value_box_checked (domain, mono_get_int32_class (), &val, error);
1931 }
1932
1933 void
1934 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *werror)
1935 {
1936         int system_level = 0;
1937         int system_name = 0;
1938         int ret;
1939         int val;
1940         socklen_t valsize = sizeof (val);
1941         struct linger linger;
1942         socklen_t lingersize = sizeof (linger);
1943         int time_ms = 0;
1944         socklen_t time_ms_size = sizeof (time_ms);
1945 #ifdef SO_PEERCRED
1946 #  if defined(__OpenBSD__)
1947         struct sockpeercred cred;
1948 #  else
1949         struct ucred cred;
1950 #  endif
1951         socklen_t credsize = sizeof (cred);
1952 #endif
1953         MonoError error;
1954         MonoDomain *domain = mono_domain_get ();
1955         MonoObject *obj;
1956         MonoClass *obj_class;
1957         MonoClassField *field;
1958         
1959         *werror = 0;
1960         
1961 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1962         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1963                 system_level = SOL_SOCKET;
1964                 system_name = SO_REUSEADDR;
1965                 ret = 0;
1966         } else
1967 #endif
1968         {
1969                 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1970         }
1971
1972         if (ret == -1) {
1973                 *werror = WSAENOPROTOOPT;
1974                 return;
1975         }
1976         if (ret == -2) {
1977                 *obj_val = int_to_object (domain, 0, &error);
1978                 mono_error_set_pending_exception (&error);
1979                 return;
1980         }
1981
1982         MONO_PREPARE_BLOCKING;
1983
1984         /* No need to deal with MulticastOption names here, because
1985          * you cant getsockopt AddMembership or DropMembership (the
1986          * int getsockopt will error, causing an exception)
1987          */
1988         switch (name) {
1989         case SocketOptionName_Linger:
1990         case SocketOptionName_DontLinger:
1991                 ret = _wapi_getsockopt (sock, system_level, system_name, &linger, &lingersize);
1992                 break;
1993                 
1994         case SocketOptionName_SendTimeout:
1995         case SocketOptionName_ReceiveTimeout:
1996                 ret = _wapi_getsockopt (sock, system_level, system_name, (char *)&time_ms, &time_ms_size);
1997                 break;
1998
1999 #ifdef SO_PEERCRED
2000         case SocketOptionName_PeerCred: 
2001                 ret = _wapi_getsockopt (sock, system_level, system_name, &cred, &credsize);
2002                 break;
2003 #endif
2004
2005         default:
2006                 ret = _wapi_getsockopt (sock, system_level, system_name, &val, &valsize);
2007         }
2008
2009         MONO_FINISH_BLOCKING;
2010
2011         if (ret == SOCKET_ERROR) {
2012                 *werror = WSAGetLastError ();
2013                 return;
2014         }
2015         
2016         switch (name) {
2017         case SocketOptionName_Linger:
2018                 /* build a System.Net.Sockets.LingerOption */
2019                 obj_class = mono_class_load_from_name (get_socket_assembly (),
2020                                                                                            "System.Net.Sockets",
2021                                                                                            "LingerOption");
2022                 obj = mono_object_new_checked (domain, obj_class, &error);
2023                 if (!mono_error_ok (&error)) {
2024                         mono_error_set_pending_exception (&error);
2025                         return;
2026                 }
2027
2028                 /* Locate and set the fields "bool enabled" and "int
2029                  * lingerTime"
2030                  */
2031                 field = mono_class_get_field_from_name(obj_class, "enabled");
2032                 *(guint8 *)(((char *)obj)+field->offset) = linger.l_onoff;
2033
2034                 field = mono_class_get_field_from_name(obj_class, "lingerTime");
2035                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
2036                 break;
2037         case SocketOptionName_DontLinger:
2038                 /* construct a bool int in val - true if linger is off */
2039                 obj = int_to_object (domain, !linger.l_onoff, &error);
2040                 mono_error_set_pending_exception (&error);
2041                 break;
2042         case SocketOptionName_SendTimeout:
2043         case SocketOptionName_ReceiveTimeout:
2044                 obj = int_to_object (domain, time_ms, &error);
2045                 mono_error_set_pending_exception (&error);
2046                 break;
2047
2048 #ifdef SO_PEERCRED
2049         case SocketOptionName_PeerCred:  {
2050                 /* 
2051                  * build a Mono.Posix.PeerCred+PeerCredData if
2052                  * possible
2053                  */
2054                 static MonoImage *mono_posix_image = NULL;
2055                 MonoPeerCredData *cred_data;
2056                 
2057                 if (mono_posix_image == NULL) {
2058                         mono_posix_image = mono_image_loaded ("Mono.Posix");
2059                         if (!mono_posix_image) {
2060                                 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
2061                                 if (!sa) {
2062                                         *werror = WSAENOPROTOOPT;
2063                                         return;
2064                                 } else {
2065                                         mono_posix_image = mono_assembly_get_image (sa);
2066                                 }
2067                         }
2068                 }
2069                 
2070                 obj_class = mono_class_load_from_name (mono_posix_image,
2071                                                  "Mono.Posix",
2072                                                  "PeerCredData");
2073                 obj = mono_object_new_checked (domain, obj_class, &error);
2074                 if (!mono_error_ok (&error)) {
2075                         mono_error_set_pending_exception (&error);
2076                         return;
2077                 }
2078                 cred_data = (MonoPeerCredData *)obj;
2079                 cred_data->pid = cred.pid;
2080                 cred_data->uid = cred.uid;
2081                 cred_data->gid = cred.gid;
2082                 break;
2083         }
2084 #endif
2085
2086         default:
2087 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2088                 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
2089                         val = val ? 0 : 1;
2090 #endif
2091                 obj = int_to_object (domain, val, &error);
2092                 mono_error_set_pending_exception (&error);
2093         }
2094
2095         *obj_val = obj;
2096 }
2097
2098 void
2099 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *werror)
2100 {
2101         int system_level = 0;
2102         int system_name = 0;
2103         int ret;
2104         guchar *buf;
2105         socklen_t valsize;
2106         
2107         *werror = 0;
2108         
2109         ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2110                                                                                  &system_name);
2111         if (ret == -1) {
2112                 *werror = WSAENOPROTOOPT;
2113                 return;
2114         }
2115         if (ret == -2)
2116                 return;
2117
2118         valsize = mono_array_length (*byte_val);
2119         buf = mono_array_addr (*byte_val, guchar, 0);
2120
2121         MONO_PREPARE_BLOCKING;
2122
2123         ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
2124
2125         MONO_FINISH_BLOCKING;
2126
2127         if (ret == SOCKET_ERROR)
2128                 *werror = WSAGetLastError ();
2129 }
2130
2131 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2132 static struct in_addr
2133 ipaddress_to_struct_in_addr (MonoObject *ipaddr)
2134 {
2135         struct in_addr inaddr;
2136         MonoClassField *field;
2137         
2138         field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Address");
2139
2140         /* No idea why .net uses a 64bit type to hold a 32bit value...
2141          *
2142          * Internal value of IPAddess is in little-endian order
2143          */
2144         inaddr.s_addr = GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr) + field->offset));
2145         
2146         return inaddr;
2147 }
2148
2149 static struct in6_addr
2150 ipaddress_to_struct_in6_addr (MonoObject *ipaddr)
2151 {
2152         struct in6_addr in6addr;
2153         MonoClassField *field;
2154         MonoArray *data;
2155         int i;
2156
2157         field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Numbers");
2158         data = *(MonoArray **)(((char *)ipaddr) + field->offset);
2159
2160 /* Solaris has only the 8 bit version. */
2161 #ifndef s6_addr16
2162         for (i = 0; i < 8; i++) {
2163                 guint16 s = mono_array_get (data, guint16, i);
2164                 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
2165                 in6addr.s6_addr[2 * i] = s & 0xff;
2166         }
2167 #else
2168         for (i = 0; i < 8; i++)
2169                 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
2170 #endif
2171         return in6addr;
2172 }
2173 #endif
2174
2175 #if defined(__APPLE__) || defined(__FreeBSD__)
2176
2177 static int
2178 get_local_interface_id (int family)
2179 {
2180 #if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
2181         return 0;
2182 #else
2183         struct ifaddrs *ifap = NULL, *ptr;
2184         int idx = 0;
2185         
2186         if (getifaddrs (&ifap))
2187                 return 0;
2188         
2189         for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
2190                 if (!ptr->ifa_addr || !ptr->ifa_name)
2191                         continue;
2192                 if (ptr->ifa_addr->sa_family != family)
2193                         continue;
2194                 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
2195                         continue;
2196                 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
2197                         continue;
2198                         
2199                 idx = if_nametoindex (ptr->ifa_name);
2200                 break;
2201         }
2202         
2203         freeifaddrs (ifap);
2204         return idx;
2205 #endif
2206 }
2207
2208 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
2209
2210 void
2211 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)
2212 {
2213         struct linger linger;
2214         int system_level = 0;
2215         int system_name = 0;
2216         int ret;
2217         int sol_ip;
2218         int sol_ipv6;
2219
2220         *werror = 0;
2221
2222         sol_ipv6 = mono_networking_get_ipv6_protocol ();
2223         sol_ip = mono_networking_get_ip_protocol ();
2224
2225         ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2226                                                                                   &system_name);
2227
2228 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2229         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2230                 system_name = SO_REUSEADDR;
2231                 int_val = int_val ? 0 : 1;
2232                 ret = 0;
2233         }
2234 #endif
2235
2236         if (ret == -1) {
2237                 *werror = WSAENOPROTOOPT;
2238                 return;
2239         }
2240         if (ret == -2)
2241                 return;
2242
2243         /* Only one of obj_val, byte_val or int_val has data */
2244         if (obj_val) {
2245                 MonoClassField *field;
2246                 int valsize;
2247                 
2248                 switch (name) {
2249                 case SocketOptionName_Linger:
2250                         /* Dig out "bool enabled" and "int lingerTime"
2251                          * fields
2252                          */
2253                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "enabled");
2254                         linger.l_onoff = *(guint8 *)(((char *)obj_val) + field->offset);
2255                         field = mono_class_get_field_from_name (obj_val->vtable->klass, "lingerTime");
2256                         linger.l_linger = *(guint32 *)(((char *)obj_val) + field->offset);
2257                         
2258                         valsize = sizeof (linger);
2259                         ret = _wapi_setsockopt (sock, system_level,
2260                                                                         system_name, &linger, valsize);
2261                         break;
2262                 case SocketOptionName_AddMembership:
2263                 case SocketOptionName_DropMembership:
2264 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2265                 {
2266                         MonoObject *address = NULL;
2267
2268                         if (system_level == sol_ipv6) {
2269                                 struct ipv6_mreq mreq6;
2270
2271                                 /*
2272                                  *      Get group address
2273                                  */
2274                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Group");
2275                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2276                                 
2277                                 if (address)
2278                                         mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
2279
2280                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Interface");
2281                                 mreq6.ipv6mr_interface = *(guint64 *)(((char *)obj_val) + field->offset);
2282                                 
2283 #if defined(__APPLE__) || defined(__FreeBSD__)
2284                                 /*
2285                                 * Bug #5504:
2286                                 *
2287                                 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2288                                 *
2289                                 * Tests on Windows and Linux show that the multicast group is only
2290                                 * joined on one NIC when interface = 0, so we simply use the interface
2291                                 * id from the first non-loopback interface (this is also what
2292                                 * Dns.GetHostName (string.Empty) would return).
2293                                 */
2294                                 if (!mreq6.ipv6mr_interface)
2295                                         mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2296 #endif
2297                                         
2298                                 ret = _wapi_setsockopt (sock, system_level,
2299                                                                                 system_name, &mreq6,
2300                                                                                 sizeof (mreq6));
2301                         } else if (system_level == sol_ip) {
2302 #ifdef HAVE_STRUCT_IP_MREQN
2303                                 struct ip_mreqn mreq = {{0}};
2304 #else
2305                                 struct ip_mreq mreq = {{0}};
2306 #endif /* HAVE_STRUCT_IP_MREQN */
2307                         
2308                                 /*
2309                                  * pain! MulticastOption holds two IPAddress
2310                                  * members, so I have to dig the value out of
2311                                  * those :-(
2312                                  */
2313                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
2314                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2315
2316                                 /* address might not be defined and if so, set the address to ADDR_ANY.
2317                                  */
2318                                 if (address)
2319                                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
2320
2321                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "localAddress");
2322                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2323
2324 #ifdef HAVE_STRUCT_IP_MREQN
2325                                 if (address)
2326                                         mreq.imr_address = ipaddress_to_struct_in_addr (address);
2327
2328                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "ifIndex");
2329                                 mreq.imr_ifindex = *(gint32 *)(((char *)obj_val) + field->offset);
2330 #else
2331                                 if (address)
2332                                         mreq.imr_interface = ipaddress_to_struct_in_addr (address);
2333 #endif /* HAVE_STRUCT_IP_MREQN */
2334
2335                                 ret = _wapi_setsockopt (sock, system_level,
2336                                                                                 system_name, &mreq,
2337                                                                                 sizeof (mreq));
2338                         }
2339                         break;
2340                 }
2341 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2342                 default:
2343                         /* Cause an exception to be thrown */
2344                         *werror = WSAEINVAL;
2345                         return;
2346                 }
2347         } else if (byte_val!=NULL) {
2348                 int valsize = mono_array_length (byte_val);
2349                 guchar *buf = mono_array_addr (byte_val, guchar, 0);
2350                 
2351                 switch(name) {
2352                 case SocketOptionName_DontLinger:
2353                         if (valsize == 1) {
2354                                 linger.l_onoff = (*buf) ? 0 : 1;
2355                                 linger.l_linger = 0;
2356                                 ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2357                         } else {
2358                                 *werror = WSAEINVAL;
2359                         }
2360                         break;
2361                 default:
2362                         ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
2363                         break;
2364                 }
2365         } else {
2366                 /* ReceiveTimeout/SendTimeout get here */
2367                 switch (name) {
2368                 case SocketOptionName_DontLinger:
2369                         linger.l_onoff = !int_val;
2370                         linger.l_linger = 0;
2371                         ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2372                         break;
2373                 case SocketOptionName_MulticastInterface:
2374 #ifndef HOST_WIN32
2375 #ifdef HAVE_STRUCT_IP_MREQN
2376                         int_val = GUINT32_FROM_BE (int_val);
2377                         if ((int_val & 0xff000000) == 0) {
2378                                 /* int_val is interface index */
2379                                 struct ip_mreqn mreq = {{0}};
2380                                 mreq.imr_ifindex = int_val;
2381                                 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &mreq, sizeof (mreq));
2382                                 break;
2383                         }
2384                         int_val = GUINT32_TO_BE (int_val);
2385 #endif /* HAVE_STRUCT_IP_MREQN */
2386 #endif /* HOST_WIN32 */
2387                         /* int_val is in_addr */
2388                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2389                         break;
2390                 case SocketOptionName_DontFragment:
2391 #ifdef HAVE_IP_MTU_DISCOVER
2392                         /* Fiddle with the value slightly if we're
2393                          * turning DF on
2394                          */
2395                         if (int_val == 1)
2396                                 int_val = IP_PMTUDISC_DO;
2397                         /* Fall through */
2398 #endif
2399                         
2400                 default:
2401                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2402                 }
2403         }
2404
2405         if (ret == SOCKET_ERROR)
2406                 *werror = WSAGetLastError ();
2407 }
2408
2409 void
2410 ves_icall_System_Net_Sockets_Socket_Shutdown_internal (SOCKET sock, gint32 how, gint32 *werror)
2411 {
2412         int ret;
2413         gboolean interrupted;
2414
2415         *werror = 0;
2416
2417         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2418         if (interrupted) {
2419                 *werror = WSAEINTR;
2420                 return;
2421         }
2422
2423         MONO_PREPARE_BLOCKING;
2424
2425         /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2426         ret = _wapi_shutdown (sock, how);
2427
2428         MONO_FINISH_BLOCKING;
2429
2430         mono_thread_info_uninstall_interrupt (&interrupted);
2431         if (interrupted) {
2432                 *werror = WSAEINTR;
2433                 return;
2434         }
2435
2436         if (ret == SOCKET_ERROR)
2437                 *werror = WSAGetLastError ();
2438 }
2439
2440 gint
2441 ves_icall_System_Net_Sockets_Socket_IOControl_internal (SOCKET sock, gint32 code, MonoArray *input, MonoArray *output, gint32 *werror)
2442 {
2443         glong output_bytes = 0;
2444         gchar *i_buffer, *o_buffer;
2445         gint i_len, o_len;
2446         gint ret;
2447
2448         *werror = 0;
2449         
2450         if ((guint32)code == FIONBIO)
2451                 /* Invalid command. Must use Socket.Blocking */
2452                 return -1;
2453
2454         if (input == NULL) {
2455                 i_buffer = NULL;
2456                 i_len = 0;
2457         } else {
2458                 i_buffer = mono_array_addr (input, gchar, 0);
2459                 i_len = mono_array_length (input);
2460         }
2461
2462         if (output == NULL) {
2463                 o_buffer = NULL;
2464                 o_len = 0;
2465         } else {
2466                 o_buffer = mono_array_addr (output, gchar, 0);
2467                 o_len = mono_array_length (output);
2468         }
2469
2470         MONO_PREPARE_BLOCKING;
2471
2472         ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2473
2474         MONO_FINISH_BLOCKING;
2475
2476         if (ret == SOCKET_ERROR) {
2477                 *werror = WSAGetLastError ();
2478                 return -1;
2479         }
2480
2481         return (gint)output_bytes;
2482 }
2483
2484 static gboolean 
2485 addrinfo_to_IPHostEntry (MonoAddressInfo *info, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips, MonoError *error)
2486 {
2487         gint32 count, i;
2488         MonoAddressEntry *ai = NULL;
2489         struct in_addr *local_in = NULL;
2490         int nlocal_in = 0;
2491         struct in6_addr *local_in6 = NULL;
2492         int nlocal_in6 = 0;
2493         int addr_index;
2494         MonoDomain *domain = mono_domain_get ();
2495
2496         mono_error_init (error);
2497         addr_index = 0;
2498         *h_aliases = mono_array_new_checked (domain, mono_get_string_class (), 0, error);
2499         return_val_if_nok (error, FALSE);
2500         if (add_local_ips) {
2501                 local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2502                 local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2503                 if (nlocal_in || nlocal_in6) {
2504                         char addr [INET6_ADDRSTRLEN];
2505                         *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error);
2506                         if (!is_ok (error))
2507                                 goto leave;
2508                         
2509                         if (nlocal_in) {
2510                                 MonoString *addr_string;
2511                                 int i;
2512
2513                                 for (i = 0; i < nlocal_in; i++) {
2514                                         MonoAddress maddr;
2515                                         mono_address_init (&maddr, AF_INET, &local_in [i]);
2516                                         if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2517                                                 addr_string = mono_string_new (domain, addr);
2518                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2519                                                 addr_index++;
2520                                         }
2521                                 }
2522                         }
2523
2524                         if (nlocal_in6) {
2525                                 MonoString *addr_string;
2526                                 int i;
2527
2528                                 for (i = 0; i < nlocal_in6; i++) {
2529                                         MonoAddress maddr;
2530                                         mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2531                                         if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2532                                                 addr_string = mono_string_new (domain, addr);
2533                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2534                                                 addr_index++;
2535                                         }
2536                                 }
2537                         }
2538
2539                 leave:
2540                         g_free (local_in);
2541                         g_free (local_in6);
2542                         if (info)
2543                                 mono_free_address_info (info);
2544                         return is_ok (error);;
2545                 }
2546
2547                 g_free (local_in);
2548                 g_free (local_in6);
2549         }
2550
2551         for (count = 0, ai = info->entries; ai != NULL; ai = ai->next) {
2552                 if (ai->family != AF_INET && ai->family != AF_INET6)
2553                         continue;
2554                 count++;
2555         }
2556
2557         *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), count, error);
2558         if (!is_ok (error))
2559                 goto leave2;
2560
2561         for (ai = info->entries, i = 0; ai != NULL; ai = ai->next) {
2562                 MonoAddress maddr;
2563                 MonoString *addr_string;
2564                 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2565
2566                 if ((ai->family != PF_INET) && (ai->family != PF_INET6))
2567                         continue;
2568
2569                 mono_address_init (&maddr, ai->family, &ai->address);
2570                 if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
2571                         addr_string = mono_string_new (domain, buffer);
2572                 else
2573                         addr_string = mono_string_new (domain, "");
2574
2575                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2576
2577                 if (!i) {
2578                         i++;
2579                         if (ai->canonical_name != NULL) {
2580                                 *h_name = mono_string_new (domain, ai->canonical_name);
2581                         } else {
2582                                 *h_name = mono_string_new (domain, buffer);
2583                         }
2584                 }
2585
2586                 addr_index++;
2587         }
2588
2589 leave2:
2590         if (info)
2591                 mono_free_address_info (info);
2592
2593         return is_ok (error);
2594 }
2595
2596 static int
2597 get_addrinfo_family_hint (MonoError *error)
2598 {
2599         int hint;
2600
2601         mono_error_init (error);
2602
2603         hint = get_family_hint (error);
2604         return_val_if_nok (error, 0);
2605
2606         switch (hint) {
2607         case PF_UNSPEC:
2608                 return MONO_HINT_UNSPECIFIED;
2609         case PF_INET:
2610                 return MONO_HINT_IPV4;
2611 #ifdef PF_INET6
2612         case PF_INET6:
2613                 return MONO_HINT_IPV6;
2614 #endif
2615         default:
2616                 g_error ("invalid hint");
2617                 return 0;
2618         }
2619 }
2620
2621 MonoBoolean
2622 ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2623 {
2624         gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2625         gchar this_hostname [256];
2626         MonoAddressInfo *info = NULL;
2627         char *hostname = mono_string_to_utf8 (host);
2628         MonoError error;
2629         int hint;
2630
2631         hint = get_addrinfo_family_hint (&error);
2632         if (!mono_error_ok (&error)) {
2633                 mono_error_set_pending_exception (&error);
2634                 return FALSE;
2635         }
2636
2637         if (*hostname == '\0') {
2638                 add_local_ips = TRUE;
2639                 *h_name = host;
2640         }
2641
2642         if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2643                 if (!strcmp (hostname, this_hostname)) {
2644                         add_local_ips = TRUE;
2645                         *h_name = host;
2646                 }
2647         }
2648
2649         if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2650                 add_info_ok = FALSE;
2651
2652         g_free(hostname);
2653
2654         if (add_info_ok) {
2655                 MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, add_local_ips, &error);
2656                 mono_error_set_pending_exception (&error);
2657                 return result;
2658         }
2659         return FALSE;
2660 }
2661
2662 MonoBoolean
2663 ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2664 {
2665         char *address;
2666         struct sockaddr_in saddr;
2667         struct sockaddr_in6 saddr6;
2668         MonoAddressInfo *info = NULL;
2669         MonoError error;
2670         gint32 family, hint;
2671         gchar hostname [NI_MAXHOST] = { 0 };
2672         gboolean ret;
2673
2674         address = mono_string_to_utf8 (addr);
2675
2676         if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2677                 family = AF_INET;
2678                 saddr.sin_family = AF_INET;
2679         } else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2680                 family = AF_INET6;
2681                 saddr6.sin6_family = AF_INET6;
2682         } else {
2683                 g_free (address);
2684                 return FALSE;
2685         }
2686
2687         g_free (address);
2688
2689         MONO_PREPARE_BLOCKING;
2690
2691         switch (family) {
2692         case AF_INET: {
2693 #if HAVE_SOCKADDR_IN_SIN_LEN
2694                 saddr.sin_len = sizeof (saddr);
2695 #endif
2696                 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2697                 break;
2698         }
2699         case AF_INET6: {
2700 #if HAVE_SOCKADDR_IN6_SIN_LEN
2701                 saddr6.sin6_len = sizeof (saddr6);
2702 #endif
2703                 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2704                 break;
2705         }
2706         default:
2707                 g_assert_not_reached ();
2708         }
2709
2710         MONO_FINISH_BLOCKING;
2711
2712         if (!ret)
2713                 return FALSE;
2714
2715         hint = get_addrinfo_family_hint (&error);
2716         if (!mono_error_ok (&error)) {
2717                 mono_error_set_pending_exception (&error);
2718                 return FALSE;
2719         }
2720         if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2721                 return FALSE;
2722
2723         MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE, &error);
2724         mono_error_set_pending_exception (&error);
2725         return result;
2726 }
2727
2728 MonoBoolean
2729 ves_icall_System_Net_Dns_GetHostName_internal (MonoString **h_name)
2730 {
2731         gchar hostname [NI_MAXHOST] = { 0 };
2732         int ret;
2733
2734         ret = gethostname (hostname, sizeof (hostname));
2735         if (ret == -1)
2736                 return FALSE;
2737
2738         *h_name = mono_string_new (mono_domain_get (), hostname);
2739
2740         return TRUE;
2741 }
2742
2743 gboolean
2744 ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags)
2745 {
2746         HANDLE file;
2747         gint32 werror;
2748         gboolean ret;
2749         gboolean interrupted;
2750         TRANSMIT_FILE_BUFFERS buffers;
2751
2752         if (filename == NULL)
2753                 return FALSE;
2754
2755         /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2756
2757         file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, &werror);
2758
2759         if (file == INVALID_HANDLE_VALUE) {
2760                 SetLastError (werror);
2761                 return FALSE;
2762         }
2763
2764         memset (&buffers, 0, sizeof (buffers));
2765         if (pre_buffer != NULL) {
2766                 buffers.Head = mono_array_addr (pre_buffer, guchar, 0);
2767                 buffers.HeadLength = mono_array_length (pre_buffer);
2768         }
2769         if (post_buffer != NULL) {
2770                 buffers.Tail = mono_array_addr (post_buffer, guchar, 0);
2771                 buffers.TailLength = mono_array_length (post_buffer);
2772         }
2773
2774         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2775         if (interrupted) {
2776                 CloseHandle (file);
2777                 SetLastError (WSAEINTR);
2778                 return FALSE;
2779         }
2780
2781         MONO_PREPARE_BLOCKING;
2782
2783         ret = TransmitFile (sock, file, 0, 0, NULL, &buffers, flags);
2784
2785         MONO_FINISH_BLOCKING;
2786
2787         mono_thread_info_uninstall_interrupt (&interrupted);
2788         if (interrupted) {
2789                 CloseHandle (file);
2790                 SetLastError (WSAEINTR);
2791                 return FALSE;
2792         }
2793
2794         MONO_PREPARE_BLOCKING;
2795
2796         CloseHandle (file);
2797
2798         MONO_FINISH_BLOCKING;
2799
2800         return ret;
2801 }
2802
2803 gboolean
2804 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (void)
2805 {
2806 #if defined (SO_REUSEPORT) || defined (HOST_WIN32)
2807     return TRUE;
2808 #else
2809     return FALSE;
2810 #endif
2811 }
2812
2813 void
2814 mono_network_init (void)
2815 {
2816         mono_networking_init ();
2817 }
2818
2819 void
2820 mono_network_cleanup (void)
2821 {
2822         _wapi_cleanup_networking ();
2823         mono_networking_shutdown ();
2824 }
2825
2826 void
2827 icall_cancel_blocking_socket_operation (MonoThread *thread)
2828 {
2829         MonoInternalThread *internal;
2830
2831         internal = thread->internal_thread;
2832         g_assert (internal);
2833
2834         mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
2835 }
2836
2837 #endif /* #ifndef DISABLE_SOCKETS */