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