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