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