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