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