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