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