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