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