Merge pull request #5714 from alexischr/update_bockbuild
[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 = closesocket (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, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, gboolean blocking, MonoError *error)
1433 {
1434         int ret;
1435         int recvflags = 0;
1436         gboolean interrupted;
1437         
1438         error_init (error);
1439         *werror = 0;
1440         
1441         recvflags = convert_socketflags (flags);
1442         if (recvflags == -1) {
1443                 *werror = WSAEOPNOTSUPP;
1444                 return 0;
1445         }
1446
1447         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1448         if (interrupted)
1449                 return 0;
1450
1451         ret = mono_w32socket_recv (sock, buffer, count, recvflags, blocking);
1452         
1453         if (ret == SOCKET_ERROR)
1454                 *werror = mono_w32socket_get_last_error ();
1455
1456         mono_thread_info_uninstall_interrupt (&interrupted);
1457         if (interrupted)
1458                 *werror = WSAEINTR;
1459
1460         if (*werror)
1461                 return 0;
1462
1463         return ret;
1464 }
1465
1466 gint32
1467 ves_icall_System_Net_Sockets_Socket_Receive_array_internal (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, gboolean blocking, MonoError *error)
1468 {
1469         int ret;
1470         gboolean interrupted;
1471         guint32 recv;
1472         guint32 recvflags = 0;
1473         
1474         error_init (error);
1475         *werror = 0;
1476         
1477         recvflags = convert_socketflags (flags);
1478         if (recvflags == -1) {
1479                 *werror = WSAEOPNOTSUPP;
1480                 return 0;
1481         }
1482
1483         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1484         if (interrupted) {
1485                 *werror = WSAEINTR;
1486                 return 0;
1487         }
1488
1489         ret = mono_w32socket_recvbuffers (sock, buffers, count, &recv, &recvflags, NULL, NULL, blocking);
1490
1491         if (ret == SOCKET_ERROR)
1492                 *werror = mono_w32socket_get_last_error ();
1493
1494         mono_thread_info_uninstall_interrupt (&interrupted);
1495         if (interrupted)
1496                 *werror = WSAEINTR;
1497
1498         if (*werror)
1499                 return 0;
1500
1501         return recv;
1502 }
1503
1504 gint32
1505 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandle sockaddr, gint32 *werror, gboolean blocking, MonoError *error)
1506 {
1507         int ret;
1508         int recvflags = 0;
1509         struct sockaddr *sa;
1510         socklen_t sa_size;
1511         gboolean interrupted;
1512         
1513         error_init (error);
1514         *werror = 0;
1515
1516         sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1517         if (*werror != 0)
1518                 return 0;
1519         if (!is_ok (error))
1520                 return 0;
1521         
1522         recvflags = convert_socketflags (flags);
1523         if (recvflags == -1) {
1524                 *werror = WSAEOPNOTSUPP;
1525                 return 0;
1526         }
1527
1528         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1529         if (interrupted) {
1530                 g_free (sa);
1531                 *werror = WSAEINTR;
1532                 return 0;
1533         }
1534
1535         ret = mono_w32socket_recvfrom (sock, buffer, count, recvflags, sa, &sa_size, blocking);
1536
1537         if (ret == SOCKET_ERROR)
1538                 *werror = mono_w32socket_get_last_error ();
1539
1540         mono_thread_info_uninstall_interrupt (&interrupted);
1541
1542         if (interrupted)
1543                 *werror = WSAEINTR;
1544
1545         if (*werror) {
1546                 g_free(sa);
1547                 return 0;
1548         }
1549
1550         /* If we didn't get a socket size, then we're probably a
1551          * connected connection-oriented socket and the stack hasn't
1552          * returned the remote address. All we can do is return null.
1553          */
1554         if (sa_size) {
1555                 MONO_HANDLE_ASSIGN (sockaddr, create_object_handle_from_sockaddr (sa, sa_size, werror, error));
1556                 if (!is_ok (error)) {
1557                         g_free (sa);
1558                         return 0;
1559                 }
1560         } else {
1561                 MONO_HANDLE_ASSIGN (sockaddr, MONO_HANDLE_NEW (MonoObject, NULL));
1562         }
1563
1564         g_free (sa);
1565         
1566         return ret;
1567 }
1568
1569 gint32
1570 ves_icall_System_Net_Sockets_Socket_Send_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, gboolean blocking, MonoError *error)
1571 {
1572         int ret;
1573         int sendflags = 0;
1574         gboolean interrupted;
1575         
1576         error_init (error);
1577         *werror = 0;
1578         
1579         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1580
1581         sendflags = convert_socketflags (flags);
1582         if (sendflags == -1) {
1583                 *werror = WSAEOPNOTSUPP;
1584                 return 0;
1585         }
1586
1587         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1588         if (interrupted) {
1589                 *werror = WSAEINTR;
1590                 return 0;
1591         }
1592
1593         ret = mono_w32socket_send (sock, buffer, count, sendflags, blocking);
1594
1595         if (ret == SOCKET_ERROR)
1596                 *werror = mono_w32socket_get_last_error ();
1597
1598         mono_thread_info_uninstall_interrupt (&interrupted);
1599         if (interrupted)
1600                 *werror = WSAEINTR;
1601
1602         if (*werror)
1603                 return 0;
1604
1605         return ret;
1606 }
1607
1608 gint32
1609 ves_icall_System_Net_Sockets_Socket_Send_array_internal (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, gboolean blocking, MonoError *error)
1610 {
1611         int ret;
1612         guint32 sent;
1613         guint32 sendflags = 0;
1614         gboolean interrupted;
1615         
1616         error_init (error);
1617         *werror = 0;
1618         
1619         sendflags = convert_socketflags (flags);
1620         if (sendflags == -1) {
1621                 *werror = WSAEOPNOTSUPP;
1622                 return 0;
1623         }
1624
1625         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1626         if (interrupted) {
1627                 *werror = WSAEINTR;
1628                 return 0;
1629         }
1630
1631         ret = mono_w32socket_sendbuffers (sock, buffers, count, &sent, sendflags, NULL, NULL, blocking);
1632
1633         if (ret == SOCKET_ERROR)
1634                 *werror = mono_w32socket_get_last_error ();
1635
1636         mono_thread_info_uninstall_interrupt (&interrupted);
1637         if (interrupted)
1638                 *werror = WSAEINTR;
1639
1640         if (*werror)
1641                 return 0;
1642
1643         return sent;
1644 }
1645
1646 gint32
1647 ves_icall_System_Net_Sockets_Socket_SendTo_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandle sockaddr, gint32 *werror, gboolean blocking, MonoError *error)
1648 {
1649         int ret;
1650         int sendflags = 0;
1651         struct sockaddr *sa;
1652         socklen_t sa_size;
1653         gboolean interrupted;
1654         
1655         *werror = 0;
1656
1657         sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1658         if (*werror != 0)
1659                 return 0;
1660         return_val_if_nok (error, 0);
1661         
1662         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1663
1664         sendflags = convert_socketflags (flags);
1665         if (sendflags == -1) {
1666                 g_free (sa);
1667                 *werror = WSAEOPNOTSUPP;
1668                 return 0;
1669         }
1670
1671         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1672         if (interrupted) {
1673                 g_free (sa);
1674                 *werror = WSAEINTR;
1675                 return 0;
1676         }
1677
1678         ret = mono_w32socket_sendto (sock, buffer, count, sendflags, sa, sa_size, blocking);
1679
1680         if (ret == SOCKET_ERROR)
1681                 *werror = mono_w32socket_get_last_error ();
1682
1683         mono_thread_info_uninstall_interrupt (&interrupted);
1684         if (interrupted)
1685                 *werror = WSAEINTR;
1686
1687         g_free(sa);
1688
1689         if (*werror)
1690                 return 0;
1691
1692         return ret;
1693 }
1694
1695 static SOCKET
1696 Socket_to_SOCKET (MonoObjectHandle sockobj)
1697 {
1698         MonoClassField *field;
1699         
1700         field = mono_class_get_field_from_name (mono_handle_class (sockobj), "m_Handle");
1701         MonoSafeHandleHandle safe_handle = MONO_HANDLE_NEW_GET_FIELD(sockobj, MonoSafeHandle, field);
1702
1703         if (MONO_HANDLE_IS_NULL (safe_handle))
1704                 return -1;
1705
1706         return (SOCKET)MONO_HANDLE_GETVAL (safe_handle, handle);
1707 }
1708
1709 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1710
1711 static gboolean
1712 collect_pollfds_from_array (MonoArrayHandle sockets, int i, int nfds, mono_pollfd *pfds, int *idx, int *mode)
1713 {
1714         HANDLE_FUNCTION_ENTER ();
1715         gboolean result = TRUE;
1716         MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1717         MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1718         if (MONO_HANDLE_IS_NULL (obj)) {
1719                 (*mode)++;
1720                 goto leave;
1721         }
1722
1723         if (*idx >= nfds) {
1724                 result = FALSE;
1725                 goto leave;
1726         }
1727
1728         pfds [*idx].fd = Socket_to_SOCKET (obj);
1729         pfds [*idx].events = (*mode == 0) ? MONO_POLLIN : (*mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1730         (*idx)++;
1731 leave:
1732         HANDLE_FUNCTION_RETURN_VAL (result);
1733 }
1734
1735 static void
1736 set_socks_array_from_pollfds (MonoArrayHandle sockets, int i, mono_pollfd *pfds, int *ret, int *mode, MonoArrayHandle socks, int *idx)
1737 {
1738         HANDLE_FUNCTION_ENTER ();
1739         mono_pollfd *pfd;
1740
1741         MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1742         MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1743         if (MONO_HANDLE_IS_NULL (obj)) {
1744                 (*mode)++;
1745                 (*idx)++;
1746                 goto leave;
1747         }
1748
1749         pfd = &pfds [i - *mode];
1750         if (pfd->revents == 0)
1751                 goto leave;
1752
1753         (*ret)--;
1754         if (((*mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0)) ||
1755             ((*mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0)) ||
1756             ((pfd->revents & POLL_ERRORS) != 0)) {
1757                 MONO_HANDLE_ARRAY_SETREF (socks, *idx, obj);
1758                 (*idx)++;
1759         }
1760 leave:
1761         HANDLE_FUNCTION_RETURN ();
1762 }
1763
1764 void
1765 ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArrayHandle sockets, gint32 timeout, gint32 *werror, MonoError *error)
1766 {
1767         MonoInternalThread *thread = mono_thread_internal_current ();
1768         mono_pollfd *pfds;
1769         int nfds, idx;
1770         int ret;
1771         int i, count;
1772         int mode;
1773         MonoClass *sock_arr_class;
1774         time_t start;
1775         uintptr_t socks_size;
1776         gboolean interrupted;
1777
1778         error_init (error);
1779         *werror = 0;
1780
1781         /* *sockets -> READ, null, WRITE, null, ERROR, null */
1782         count = mono_array_handle_length (sockets);
1783         nfds = count - 3; /* NULL separators */
1784         pfds = g_new0 (mono_pollfd, nfds);
1785         mode = idx = 0;
1786         for (i = 0; i < count; i++) {
1787                 if (!collect_pollfds_from_array (sockets, i, nfds, pfds, &idx, &mode)) {
1788                         /* The socket array was bogus */
1789                         g_free (pfds);
1790                         *werror = WSAEFAULT;
1791                         return;
1792                 }
1793         }
1794
1795         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1796         start = time (NULL);
1797         do {
1798                 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1799                 if (interrupted) {
1800                         g_free (pfds);
1801                         *werror = WSAEINTR;
1802                         return;
1803                 }
1804
1805                 MONO_ENTER_GC_SAFE;
1806
1807                 ret = mono_poll (pfds, nfds, timeout);
1808
1809                 MONO_EXIT_GC_SAFE;
1810
1811                 mono_thread_info_uninstall_interrupt (&interrupted);
1812                 if (interrupted) {
1813                         g_free (pfds);
1814                         *werror = WSAEINTR;
1815                         return;
1816                 }
1817
1818                 if (timeout > 0 && ret < 0) {
1819                         int err = errno;
1820                         int sec = time (NULL) - start;
1821
1822                         timeout -= sec * 1000;
1823                         if (timeout < 0)
1824                                 timeout = 0;
1825                         errno = err;
1826                 }
1827
1828                 if (ret == -1 && errno == EINTR) {
1829                         if (mono_thread_test_state (thread, ThreadState_AbortRequested)) {
1830                                 g_free (pfds);
1831                                 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1832                                 return;
1833                         }
1834
1835                         /* Suspend requested? */
1836                         mono_thread_interruption_checkpoint ();
1837
1838                         errno = EINTR;
1839                 }
1840         } while (ret == -1 && errno == EINTR);
1841         
1842         if (ret == -1) {
1843                 *werror = mono_w32socket_convert_error (errno);
1844                 g_free (pfds);
1845                 return;
1846         }
1847
1848         if (ret == 0) {
1849                 g_free (pfds);
1850                 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1851                 return;
1852         }
1853
1854         sock_arr_class = mono_handle_class (sockets);
1855         socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1856         MonoArrayHandle socks = MONO_HANDLE_NEW (MonoArray, mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, error));
1857         if (!is_ok (error)) {
1858                 g_free (pfds);
1859                 return;
1860         }
1861
1862         mode = idx = 0;
1863         for (i = 0; i < count && ret > 0; i++) {
1864                 set_socks_array_from_pollfds (sockets, i, pfds, &ret, &mode, socks, &idx);
1865         }
1866
1867         MONO_HANDLE_ASSIGN (sockets, socks);
1868         g_free (pfds);
1869 }
1870
1871 static MonoObjectHandle
1872 int_to_object_handle (MonoDomain *domain, int val, MonoError *error)
1873 {
1874         return MONO_HANDLE_NEW (MonoObject, mono_value_box_checked (domain, mono_get_int32_class (), &val, error));
1875 }
1876
1877 void
1878 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (gsize sock, gint32 level, gint32 name, MonoObjectHandle obj_val, gint32 *werror, MonoError *error)
1879 {
1880         int system_level = 0;
1881         int system_name = 0;
1882         int ret;
1883         int val = 0;
1884         socklen_t valsize = sizeof (val);
1885         struct linger linger;
1886         socklen_t lingersize = sizeof (linger);
1887         int time_ms = 0;
1888         socklen_t time_ms_size = sizeof (time_ms);
1889 #ifdef SO_PEERCRED
1890 #  if defined(__OpenBSD__)
1891         struct sockpeercred cred;
1892 #  else
1893         struct ucred cred;
1894 #  endif
1895         socklen_t credsize = sizeof (cred);
1896 #endif
1897         MonoDomain *domain = mono_domain_get ();
1898         MonoClass *obj_class;
1899         MonoClassField *field;
1900         
1901         error_init (error);
1902         *werror = 0;
1903         
1904 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1905         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1906                 system_level = SOL_SOCKET;
1907                 system_name = SO_REUSEADDR;
1908                 ret = 0;
1909         } else
1910 #endif
1911         {
1912                 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1913         }
1914
1915         if (ret == -1) {
1916                 *werror = WSAENOPROTOOPT;
1917                 return;
1918         }
1919         if (ret == -2) {
1920                 MONO_HANDLE_ASSIGN (obj_val, int_to_object_handle (domain, 0, error));
1921                 return;
1922         }
1923
1924         /* No need to deal with MulticastOption names here, because
1925          * you cant getsockopt AddMembership or DropMembership (the
1926          * int getsockopt will error, causing an exception)
1927          */
1928         switch (name) {
1929         case SocketOptionName_Linger:
1930         case SocketOptionName_DontLinger:
1931                 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &linger, &lingersize);
1932                 break;
1933                 
1934         case SocketOptionName_SendTimeout:
1935         case SocketOptionName_ReceiveTimeout:
1936                 ret = mono_w32socket_getsockopt (sock, system_level, system_name, (char *)&time_ms, &time_ms_size);
1937                 break;
1938
1939 #ifdef SO_PEERCRED
1940         case SocketOptionName_PeerCred: 
1941                 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &cred, &credsize);
1942                 break;
1943 #endif
1944
1945         default:
1946                 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &val, &valsize);
1947         }
1948
1949         if (ret == SOCKET_ERROR) {
1950                 *werror = mono_w32socket_get_last_error ();
1951                 return;
1952         }
1953         
1954         switch (name) {
1955         case SocketOptionName_Linger: {
1956                 /* build a System.Net.Sockets.LingerOption */
1957                 obj_class = mono_class_load_from_name (get_socket_assembly (),
1958                                                                                            "System.Net.Sockets",
1959                                                                                            "LingerOption");
1960                 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_object_new_checked (domain, obj_class, error));
1961                 return_if_nok (error);
1962
1963                 /* Locate and set the fields "bool enabled" and "int
1964                  * lingerTime"
1965                  */
1966                 field = mono_class_get_field_from_name(obj_class, "enabled");
1967                 MONO_HANDLE_SET_FIELD_VAL (obj, guint8, field, linger.l_onoff);
1968
1969                 field = mono_class_get_field_from_name(obj_class, "lingerTime");
1970                 MONO_HANDLE_SET_FIELD_VAL (obj, guint32, field, linger.l_linger);
1971
1972                 MONO_HANDLE_ASSIGN (obj_val, obj);
1973                 break;
1974         }
1975         case SocketOptionName_DontLinger: {
1976                 /* construct a bool int in val - true if linger is off */
1977                 MonoObjectHandle obj = int_to_object_handle (domain, !linger.l_onoff, error);
1978                 return_if_nok (error);
1979
1980                 MONO_HANDLE_ASSIGN (obj_val, obj);
1981                 break;
1982         }
1983         case SocketOptionName_SendTimeout:
1984         case SocketOptionName_ReceiveTimeout: {
1985                 MonoObjectHandle obj = int_to_object_handle (domain, time_ms, error);
1986                 return_if_nok (error);
1987
1988                 MONO_HANDLE_ASSIGN (obj_val, obj);
1989                 break;
1990         }
1991
1992 #ifdef SO_PEERCRED
1993         case SocketOptionName_PeerCred:  {
1994                 /* 
1995                  * build a Mono.Posix.PeerCred+PeerCredData if
1996                  * possible
1997                  */
1998                 static MonoImage *mono_posix_image = NULL;
1999                 
2000                 if (mono_posix_image == NULL) {
2001                         mono_posix_image = mono_image_loaded ("Mono.Posix");
2002                         if (!mono_posix_image) {
2003                                 MonoAssembly *sa = mono_assembly_open_predicate ("Mono.Posix.dll", FALSE, FALSE, NULL, NULL, NULL);
2004                                 if (!sa) {
2005                                         *werror = WSAENOPROTOOPT;
2006                                         return;
2007                                 } else {
2008                                         mono_posix_image = mono_assembly_get_image (sa);
2009                                 }
2010                         }
2011                 }
2012                 
2013                 obj_class = mono_class_load_from_name (mono_posix_image,
2014                                                  "Mono.Posix",
2015                                                  "PeerCredData");
2016                 MonoPeerCredDataHandle cred_data = MONO_HANDLE_NEW (MonoPeerCredData, mono_object_new_checked (domain, obj_class, error));
2017                 return_if_nok (error);
2018
2019                 MONO_HANDLE_SETVAL (cred_data, pid, gint, cred.pid);
2020                 MONO_HANDLE_SETVAL (cred_data, uid, gint, cred.uid);
2021                 MONO_HANDLE_SETVAL (cred_data, gid, gint, cred.gid);
2022
2023                 MONO_HANDLE_ASSIGN (obj_val, cred_data);
2024                 break;
2025         }
2026 #endif
2027
2028         default: {
2029 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2030                 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
2031                         val = val ? 0 : 1;
2032 #endif
2033                 MonoObjectHandle obj = int_to_object_handle (domain, val, error);
2034                 return_if_nok (error);
2035
2036                 MONO_HANDLE_ASSIGN (obj_val, obj);
2037         }
2038         }
2039 }
2040
2041 void
2042 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (gsize sock, gint32 level, gint32 name, MonoArrayHandle byte_val, gint32 *werror, MonoError *error)
2043 {
2044         int system_level = 0;
2045         int system_name = 0;
2046         int ret;
2047         socklen_t valsize;
2048         
2049         error_init (error);
2050         *werror = 0;
2051         
2052         ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2053                                                                                  &system_name);
2054         if (ret == -1) {
2055                 *werror = WSAENOPROTOOPT;
2056                 return;
2057         }
2058         if (ret == -2)
2059                 return;
2060
2061         valsize = mono_array_handle_length (byte_val);
2062
2063         uint32_t gchandle;
2064         guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
2065
2066         ret = mono_w32socket_getsockopt (sock, system_level, system_name, buf, &valsize);
2067
2068         mono_gchandle_free (gchandle);
2069
2070         if (ret == SOCKET_ERROR)
2071                 *werror = mono_w32socket_get_last_error ();
2072 }
2073
2074 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2075 static struct in_addr
2076 ipaddress_handle_to_struct_in_addr (MonoObjectHandle ipaddr)
2077 {
2078         struct in_addr inaddr;
2079         MonoClassField *field;
2080         
2081         field = mono_class_get_field_from_name (mono_handle_class (ipaddr), "m_Address");
2082         g_assert (field);
2083
2084         /* No idea why .net uses a 64bit type to hold a 32bit value...
2085          *
2086          * Internal value of IPAddess is in little-endian order
2087          */
2088         inaddr.s_addr = GUINT_FROM_LE ((guint32)MONO_HANDLE_GET_FIELD_VAL (ipaddr, guint64, field));
2089         
2090         return inaddr;
2091 }
2092
2093 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2094 static struct in6_addr
2095 ipaddress_handle_to_struct_in6_addr (MonoObjectHandle ipaddr)
2096 {
2097         struct in6_addr in6addr;
2098         MonoClassField *field;
2099         int i;
2100
2101         field = mono_class_get_field_from_name (mono_handle_class (ipaddr), "m_Numbers");
2102         g_assert (field);
2103         MonoArrayHandle data = MONO_HANDLE_NEW_GET_FIELD (ipaddr, MonoArray, field);
2104
2105         for (i = 0; i < 8; i++) {
2106                 guint16 v;
2107                 MONO_HANDLE_ARRAY_GETVAL (v, data, guint16, i);
2108                 const guint16 s = GUINT16_TO_BE (v);
2109
2110 /* Solaris/MacOS have only the 8 bit version. */
2111 #ifndef s6_addr16
2112                 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
2113                 in6addr.s6_addr[2 * i] = s & 0xff;
2114 #else
2115                 in6addr.s6_addr16[i] = s;
2116 #endif
2117         }
2118         return in6addr;
2119 }
2120 #endif
2121 #endif
2122
2123 #if defined(__APPLE__) || defined(__FreeBSD__)
2124
2125 static int
2126 get_local_interface_id (int family)
2127 {
2128 #if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
2129         return 0;
2130 #else
2131         struct ifaddrs *ifap = NULL, *ptr;
2132         int idx = 0;
2133         
2134         if (getifaddrs (&ifap))
2135                 return 0;
2136         
2137         for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
2138                 if (!ptr->ifa_addr || !ptr->ifa_name)
2139                         continue;
2140                 if (ptr->ifa_addr->sa_family != family)
2141                         continue;
2142                 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
2143                         continue;
2144                 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
2145                         continue;
2146                         
2147                 idx = if_nametoindex (ptr->ifa_name);
2148                 break;
2149         }
2150         
2151         freeifaddrs (ifap);
2152         return idx;
2153 #endif
2154 }
2155
2156 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
2157
2158 void
2159 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)
2160 {
2161         struct linger linger;
2162         int system_level = 0;
2163         int system_name = 0;
2164         int ret;
2165         int sol_ip;
2166         int sol_ipv6;
2167
2168         error_init (error);
2169         *werror = 0;
2170
2171         sol_ipv6 = mono_networking_get_ipv6_protocol ();
2172         sol_ip = mono_networking_get_ip_protocol ();
2173
2174         ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2175                                                                                   &system_name);
2176
2177 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2178         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2179                 system_name = SO_REUSEADDR;
2180                 int_val = int_val ? 0 : 1;
2181                 ret = 0;
2182         }
2183 #endif
2184
2185         if (ret == -1) {
2186                 *werror = WSAENOPROTOOPT;
2187                 return;
2188         }
2189         if (ret == -2)
2190                 return;
2191
2192         /* Only one of obj_val, byte_val or int_val has data */
2193         if (!MONO_HANDLE_IS_NULL (obj_val)) {
2194                 MonoClass *obj_class = mono_handle_class (obj_val);
2195                 MonoClassField *field;
2196                 int valsize;
2197                 
2198                 switch (name) {
2199                 case SocketOptionName_Linger:
2200                         /* Dig out "bool enabled" and "int lingerTime"
2201                          * fields
2202                          */
2203                         field = mono_class_get_field_from_name (obj_class, "enabled");
2204                         linger.l_onoff = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint8, field);
2205                         field = mono_class_get_field_from_name (obj_class, "lingerTime");
2206                         linger.l_linger = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint32, field);
2207                         
2208                         valsize = sizeof (linger);
2209                         ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, valsize);
2210                         break;
2211                 case SocketOptionName_AddMembership:
2212                 case SocketOptionName_DropMembership:
2213 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2214                 {
2215                         MonoObjectHandle address = MONO_HANDLE_NEW (MonoObject, NULL);
2216 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2217                         if (system_level == sol_ipv6) {
2218                                 struct ipv6_mreq mreq6;
2219
2220                                 /*
2221                                  *      Get group address
2222                                  */
2223                                 field = mono_class_get_field_from_name (obj_class, "m_Group");
2224                                 g_assert (field);
2225                                 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2226                                 
2227                                 if (!MONO_HANDLE_IS_NULL (address))
2228                                         mreq6.ipv6mr_multiaddr = ipaddress_handle_to_struct_in6_addr (address);
2229
2230                                 field = mono_class_get_field_from_name (obj_class, "m_Interface");
2231                                 mreq6.ipv6mr_interface = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint64, field);
2232                                 
2233 #if defined(__APPLE__) || defined(__FreeBSD__)
2234                                 /*
2235                                 * Bug #5504:
2236                                 *
2237                                 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2238                                 *
2239                                 * Tests on Windows and Linux show that the multicast group is only
2240                                 * joined on one NIC when interface = 0, so we simply use the interface
2241                                 * id from the first non-loopback interface (this is also what
2242                                 * Dns.GetHostName (string.Empty) would return).
2243                                 */
2244                                 if (!mreq6.ipv6mr_interface)
2245                                         mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2246 #endif
2247                                         
2248                                 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq6, sizeof (mreq6));
2249
2250                                 break; // Don't check sol_ip
2251                         }
2252 #endif
2253                         if (system_level == sol_ip) {
2254 #ifdef HAVE_STRUCT_IP_MREQN
2255                                 struct ip_mreqn mreq = {{0}};
2256 #else
2257                                 struct ip_mreq mreq = {{0}};
2258 #endif /* HAVE_STRUCT_IP_MREQN */
2259                         
2260                                 /*
2261                                  * pain! MulticastOption holds two IPAddress
2262                                  * members, so I have to dig the value out of
2263                                  * those :-(
2264                                  */
2265                                 field = mono_class_get_field_from_name (obj_class, "group");
2266                                 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2267
2268                                 /* address might not be defined and if so, set the address to ADDR_ANY.
2269                                  */
2270                                 if (!MONO_HANDLE_IS_NULL (address))
2271                                         mreq.imr_multiaddr = ipaddress_handle_to_struct_in_addr (address);
2272
2273                                 field = mono_class_get_field_from_name (obj_class, "localAddress");
2274                                 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2275
2276 #ifdef HAVE_STRUCT_IP_MREQN
2277                                 if (!MONO_HANDLE_IS_NULL (address))
2278                                         mreq.imr_address = ipaddress_handle_to_struct_in_addr (address);
2279
2280                                 field = mono_class_get_field_from_name (obj_class, "ifIndex");
2281                                 mreq.imr_ifindex = MONO_HANDLE_GET_FIELD_VAL (obj_val, gint32, field);
2282 #else
2283                                 if (!MONO_HANDLE_IS_NULL (address))
2284                                         mreq.imr_interface = ipaddress_handle_to_struct_in_addr (address);
2285 #endif /* HAVE_STRUCT_IP_MREQN */
2286
2287                                 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
2288                         }
2289                         break;
2290                 }
2291 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2292                 default:
2293                         /* Cause an exception to be thrown */
2294                         *werror = WSAEINVAL;
2295                         return;
2296                 }
2297         } else if (!MONO_HANDLE_IS_NULL (byte_val)) {
2298                 int valsize = mono_array_handle_length (byte_val);
2299                 uint32_t gchandle;
2300                 guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
2301                 
2302                 switch(name) {
2303                 case SocketOptionName_DontLinger:
2304                         if (valsize == 1) {
2305                                 linger.l_onoff = (*buf) ? 0 : 1;
2306                                 linger.l_linger = 0;
2307                                 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2308                         } else {
2309                                 *werror = WSAEINVAL;
2310                         }
2311                         break;
2312                 default:
2313                         ret = mono_w32socket_setsockopt (sock, system_level, system_name, buf, valsize);
2314                         break;
2315                 }
2316                 mono_gchandle_free (gchandle);
2317         } else {
2318                 /* ReceiveTimeout/SendTimeout get here */
2319                 switch (name) {
2320                 case SocketOptionName_DontLinger:
2321                         linger.l_onoff = !int_val;
2322                         linger.l_linger = 0;
2323                         ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2324                         break;
2325                 case SocketOptionName_MulticastInterface:
2326 #ifndef HOST_WIN32
2327 #ifdef HAVE_STRUCT_IP_MREQN
2328                         int_val = GUINT32_FROM_BE (int_val);
2329                         if ((int_val & 0xff000000) == 0) {
2330                                 /* int_val is interface index */
2331                                 struct ip_mreqn mreq = {{0}};
2332                                 mreq.imr_ifindex = int_val;
2333                                 ret = mono_w32socket_setsockopt (sock, system_level, system_name, (char *) &mreq, sizeof (mreq));
2334                                 break;
2335                         }
2336                         int_val = GUINT32_TO_BE (int_val);
2337 #endif /* HAVE_STRUCT_IP_MREQN */
2338 #endif /* HOST_WIN32 */
2339                         /* int_val is in_addr */
2340                         ret = mono_w32socket_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2341                         break;
2342                 case SocketOptionName_DontFragment:
2343 #ifdef HAVE_IP_MTU_DISCOVER
2344                         /* Fiddle with the value slightly if we're
2345                          * turning DF on
2346                          */
2347                         if (int_val == 1)
2348                                 int_val = IP_PMTUDISC_DO;
2349                         /* Fall through */
2350 #endif
2351                         
2352                 default:
2353                         ret = mono_w32socket_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2354                 }
2355         }
2356
2357         if (ret == SOCKET_ERROR)
2358                 *werror = mono_w32socket_get_last_error ();
2359 }
2360
2361 void
2362 ves_icall_System_Net_Sockets_Socket_Shutdown_internal (gsize sock, gint32 how, gint32 *werror, MonoError *error)
2363 {
2364         int ret;
2365         gboolean interrupted;
2366
2367         error_init (error);
2368         *werror = 0;
2369
2370         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2371         if (interrupted) {
2372                 *werror = WSAEINTR;
2373                 return;
2374         }
2375
2376         /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2377         ret = mono_w32socket_shutdown (sock, how);
2378         if (ret == SOCKET_ERROR)
2379                 *werror = mono_w32socket_get_last_error ();
2380
2381         mono_thread_info_uninstall_interrupt (&interrupted);
2382         if (interrupted) {
2383                 *werror = WSAEINTR;
2384         }
2385
2386 }
2387
2388 gint
2389 ves_icall_System_Net_Sockets_Socket_IOControl_internal (gsize sock, gint32 code, MonoArrayHandle input, MonoArrayHandle output, gint32 *werror, MonoError *error)
2390 {
2391         glong output_bytes = 0;
2392         gchar *i_buffer, *o_buffer;
2393         gint i_len, o_len;
2394         uint32_t i_gchandle, o_gchandle;
2395         gint ret;
2396
2397         error_init (error);
2398         *werror = 0;
2399         
2400         if ((guint32)code == FIONBIO)
2401                 /* Invalid command. Must use Socket.Blocking */
2402                 return -1;
2403
2404         if (MONO_HANDLE_IS_NULL (input)) {
2405                 i_buffer = NULL;
2406                 i_len = 0;
2407                 i_gchandle = 0;
2408         } else {
2409                 i_len = mono_array_handle_length (input);
2410                 i_buffer = MONO_ARRAY_HANDLE_PIN (input, gchar, 0, &i_gchandle);
2411         }
2412
2413         if (MONO_HANDLE_IS_NULL (output)) {
2414                 o_buffer = NULL;
2415                 o_len = 0;
2416                 o_gchandle = 0;
2417         } else {
2418                 o_len = mono_array_handle_length (output);
2419                 o_buffer = MONO_ARRAY_HANDLE_PIN (output, gchar, 0, &o_gchandle);
2420         }
2421
2422         ret = mono_w32socket_ioctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes);
2423
2424         if (i_gchandle)
2425                 mono_gchandle_free (i_gchandle);
2426         if (o_gchandle)
2427                 mono_gchandle_free (o_gchandle);
2428
2429         if (ret == SOCKET_ERROR) {
2430                 *werror = mono_w32socket_get_last_error ();
2431                 return -1;
2432         }
2433
2434         return (gint)output_bytes;
2435 }
2436
2437 static gboolean
2438 addrinfo_add_string (MonoDomain *domain, const char *s, MonoArrayHandle arr, int index, MonoError *error)
2439 {
2440         HANDLE_FUNCTION_ENTER ();
2441         error_init (error);
2442         MonoStringHandle str = mono_string_new_handle (domain, s, error);
2443         if (!is_ok (error))
2444                 goto leave;
2445         MONO_HANDLE_ARRAY_SETREF (arr, index, str);
2446 leave:
2447         HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2448
2449 }
2450
2451 static int
2452 addrinfo_add_local_ips (MonoDomain *domain, MonoArrayHandleOut h_addr_list, MonoError *error)
2453 {
2454         HANDLE_FUNCTION_ENTER ();
2455         struct in_addr *local_in = NULL;
2456         int nlocal_in = 0;
2457         struct in6_addr *local_in6 = NULL;
2458         int nlocal_in6 = 0;
2459         int addr_index = 0;
2460
2461         error_init (error);
2462         local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2463         local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2464         if (nlocal_in || nlocal_in6) {
2465                 char addr [INET6_ADDRSTRLEN];
2466                 MONO_HANDLE_ASSIGN (h_addr_list,  mono_array_new_handle (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error));
2467                 if (!is_ok (error))
2468                         goto leave;
2469                         
2470                 if (nlocal_in) {
2471                         int i;
2472
2473                         for (i = 0; i < nlocal_in; i++) {
2474                                 MonoAddress maddr;
2475                                 mono_address_init (&maddr, AF_INET, &local_in [i]);
2476                                 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2477                                         if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2478                                                 goto leave;
2479                                         addr_index++;
2480                                 }
2481                         }
2482                 }
2483 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2484                 if (nlocal_in6) {
2485                         int i;
2486
2487                         for (i = 0; i < nlocal_in6; i++) {
2488                                 MonoAddress maddr;
2489                                 mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2490                                 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2491                                         if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2492                                                 goto leave;
2493                                         addr_index++;
2494                                 }
2495                         }
2496                 }
2497 #endif
2498         }
2499
2500 leave:
2501         g_free (local_in);
2502         g_free (local_in6);
2503         HANDLE_FUNCTION_RETURN_VAL (addr_index);
2504 }
2505
2506 static gboolean 
2507 addrinfo_to_IPHostEntry_handles (MonoAddressInfo *info, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gboolean add_local_ips, MonoError *error)
2508 {
2509         HANDLE_FUNCTION_ENTER ();
2510         MonoAddressEntry *ai = NULL;
2511         MonoDomain *domain = mono_domain_get ();
2512
2513         error_init (error);
2514         MONO_HANDLE_ASSIGN (h_aliases, mono_array_new_handle (domain, mono_get_string_class (), 0, error));
2515         if (!is_ok (error))
2516                 goto leave;
2517         if (add_local_ips) {
2518                 int addr_index = addrinfo_add_local_ips (domain, h_addr_list, error);
2519                 if (!is_ok (error))
2520                         goto leave;
2521                 if (addr_index > 0)
2522                         goto leave;
2523         }
2524
2525         gint32 count = 0;
2526         for (ai = info->entries; ai != NULL; ai = ai->next) {
2527                 if (ai->family != AF_INET && ai->family != AF_INET6)
2528                         continue;
2529                 count++;
2530         }
2531
2532         int addr_index = 0;
2533         MONO_HANDLE_ASSIGN (h_addr_list, mono_array_new_handle (domain, mono_get_string_class (), count, error));
2534         if (!is_ok (error))
2535                 goto leave;
2536
2537         gboolean name_assigned = FALSE;
2538         for (ai = info->entries; ai != NULL; ai = ai->next) {
2539                 MonoAddress maddr;
2540                 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2541
2542                 if ((ai->family != PF_INET) && (ai->family != PF_INET6))
2543                         continue;
2544
2545                 mono_address_init (&maddr, ai->family, &ai->address);
2546                 const char *addr = NULL;
2547                 if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
2548                         addr = buffer;
2549                 else
2550                         addr = "";
2551                 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2552                         goto leave;
2553
2554                 if (!name_assigned) {
2555                         name_assigned = TRUE;
2556                         const char *name = ai->canonical_name != NULL ? ai->canonical_name : buffer;
2557                         MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (domain, name, error));
2558                         if (!is_ok (error))
2559                                 goto leave;
2560                 }
2561
2562                 addr_index++;
2563         }
2564
2565 leave:
2566         if (info)
2567                 mono_free_address_info (info);
2568
2569         HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2570 }
2571
2572 MonoBoolean
2573 ves_icall_System_Net_Dns_GetHostByName_internal (MonoStringHandle host, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2574 {
2575         gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2576         gchar this_hostname [256];
2577         MonoAddressInfo *info = NULL;
2578
2579         error_init (error);
2580
2581         char *hostname = mono_string_handle_to_utf8 (host, error);
2582         return_val_if_nok (error, FALSE);
2583
2584         if (*hostname == '\0') {
2585                 add_local_ips = TRUE;
2586                 MONO_HANDLE_ASSIGN (h_name, host);
2587         }
2588
2589         if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2590                 if (!strcmp (hostname, this_hostname)) {
2591                         add_local_ips = TRUE;
2592                         MONO_HANDLE_ASSIGN (h_name, host);
2593                 }
2594         }
2595
2596 #ifdef HOST_WIN32
2597         // Win32 APIs already returns local interface addresses for empty hostname ("")
2598         // so we never want to add them manually.
2599         add_local_ips = FALSE;
2600         if (mono_get_address_info(hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2601                 add_info_ok = FALSE;
2602 #else
2603         if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2604                 add_info_ok = FALSE;
2605 #endif
2606
2607         g_free(hostname);
2608
2609         if (add_info_ok) {
2610                 MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, add_local_ips, error);
2611                 return result;
2612         }
2613         return FALSE;
2614 }
2615
2616 MonoBoolean
2617 ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoStringHandle addr, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2618 {
2619         char *address;
2620         struct sockaddr_in saddr;
2621 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2622         struct sockaddr_in6 saddr6;
2623 #endif
2624         MonoAddressInfo *info = NULL;
2625         gint32 family;
2626         gchar hostname [NI_MAXHOST] = { 0 };
2627         gboolean ret;
2628
2629         error_init (error);
2630
2631         address = mono_string_handle_to_utf8 (addr, error);
2632         return_val_if_nok (error, FALSE);
2633
2634         if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2635                 family = AF_INET;
2636                 saddr.sin_family = AF_INET;
2637         }
2638 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2639         else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2640                 family = AF_INET6;
2641                 saddr6.sin6_family = AF_INET6;
2642         }
2643 #endif
2644         else {
2645                 g_free (address);
2646                 return FALSE;
2647         }
2648
2649         g_free (address);
2650
2651         switch (family) {
2652         case AF_INET: {
2653 #if HAVE_SOCKADDR_IN_SIN_LEN
2654                 saddr.sin_len = sizeof (saddr);
2655 #endif
2656                 MONO_ENTER_GC_SAFE;
2657                 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2658                 MONO_EXIT_GC_SAFE;
2659                 break;
2660         }
2661 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2662         case AF_INET6: {
2663 #if HAVE_SOCKADDR_IN6_SIN_LEN
2664                 saddr6.sin6_len = sizeof (saddr6);
2665 #endif
2666                 MONO_ENTER_GC_SAFE;
2667                 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2668                 MONO_EXIT_GC_SAFE;
2669                 break;
2670         }
2671 #endif
2672         default:
2673                 g_assert_not_reached ();
2674         }
2675
2676         if (!ret)
2677                 return FALSE;
2678
2679         if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2680                 return FALSE;
2681
2682         MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, FALSE, error);
2683         return result;
2684 }
2685
2686 MonoBoolean
2687 ves_icall_System_Net_Dns_GetHostName_internal (MonoStringHandleOut h_name, MonoError *error)
2688 {
2689         gchar hostname [NI_MAXHOST] = { 0 };
2690         int ret;
2691
2692         error_init (error);
2693         MONO_ENTER_GC_SAFE;
2694         ret = gethostname (hostname, sizeof (hostname));
2695         MONO_EXIT_GC_SAFE;
2696         if (ret == -1)
2697                 return FALSE;
2698
2699         MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (mono_domain_get (), hostname, error));
2700         return TRUE;
2701 }
2702
2703 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
2704 gboolean
2705 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)
2706 {
2707         HANDLE file;
2708         gboolean ret;
2709         gboolean interrupted;
2710         TRANSMIT_FILE_BUFFERS buffers;
2711         uint32_t pre_buffer_gchandle = 0;
2712         uint32_t post_buffer_gchandle = 0;
2713
2714         error_init (error);
2715         *werror = 0;
2716
2717         if (MONO_HANDLE_IS_NULL (filename))
2718                 return FALSE;
2719
2720         /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2721
2722         uint32_t filename_gchandle;
2723         gunichar2 *filename_chars = mono_string_handle_pin_chars (filename, &filename_gchandle);
2724         file = mono_w32file_create (filename_chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0);
2725         mono_gchandle_free (filename_gchandle);
2726         if (file == INVALID_HANDLE_VALUE) {
2727                 *werror = mono_w32error_get_last ();
2728                 return FALSE;
2729         }
2730
2731         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2732         if (interrupted) {
2733                 mono_w32file_close (file);
2734                 mono_w32error_set_last (WSAEINTR);
2735                 return FALSE;
2736         }
2737
2738
2739         memset (&buffers, 0, sizeof (buffers));
2740         if (!MONO_HANDLE_IS_NULL (pre_buffer)) {
2741                 buffers.Head = MONO_ARRAY_HANDLE_PIN (pre_buffer, guchar, 0, &pre_buffer_gchandle);
2742                 buffers.HeadLength = mono_array_handle_length (pre_buffer);
2743         }
2744         if (!MONO_HANDLE_IS_NULL (post_buffer)) {
2745                 buffers.Tail = MONO_ARRAY_HANDLE_PIN (post_buffer, guchar, 0, &post_buffer_gchandle);
2746                 buffers.TailLength = mono_array_handle_length (post_buffer);
2747         }
2748
2749         ret = mono_w32socket_transmit_file (sock, file, &buffers, flags, blocking);
2750
2751         if (pre_buffer_gchandle)
2752                 mono_gchandle_free (pre_buffer_gchandle);
2753         if (post_buffer_gchandle)
2754                 mono_gchandle_free (post_buffer_gchandle);
2755
2756         if (!ret)
2757                 *werror = mono_w32socket_get_last_error ();
2758
2759         mono_thread_info_uninstall_interrupt (&interrupted);
2760         if (interrupted) {
2761                 mono_w32file_close (file);
2762                 *werror = WSAEINTR;
2763                 return FALSE;
2764         }
2765
2766         mono_w32file_close (file);
2767
2768         if (*werror)
2769                 return FALSE;
2770
2771         return ret;
2772 }
2773 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
2774
2775 void
2776 mono_network_init (void)
2777 {
2778         mono_networking_init ();
2779         mono_w32socket_initialize ();
2780 }
2781
2782 void
2783 mono_network_cleanup (void)
2784 {
2785         mono_w32socket_cleanup ();
2786         mono_networking_shutdown ();
2787 }
2788
2789 void
2790 icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error)
2791 {
2792         error_init (error);
2793         MonoInternalThreadHandle internal = MONO_HANDLE_NEW_GET (MonoInternalThread, thread, internal_thread);
2794         g_assert (!MONO_HANDLE_IS_NULL (internal));
2795
2796         guint64 tid = mono_internal_thread_handle_ptr (internal)->tid;
2797         mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (tid));
2798 }
2799
2800 #endif /* #ifndef DISABLE_SOCKETS */