Merge pull request #2274 from esdrubal/udpclientreceive
[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
520                 break;  /* SocketOptionLevel_IPv6 */
521                 
522         case SocketOptionLevel_Tcp:
523                 *system_level = mono_networking_get_tcp_protocol ();
524                 
525                 switch(mono_name) {
526                 case SocketOptionName_NoDelay:
527                         *system_name = TCP_NODELAY;
528                         break;
529 #if 0
530                         /* The documentation is talking complete
531                          * bollocks here: rfc-1222 is titled
532                          * 'Advancing the NSFNET Routing Architecture'
533                          * and doesn't mention either of the words
534                          * "expedite" or "urgent".
535                          */
536                 case SocketOptionName_BsdUrgent:
537                 case SocketOptionName_Expedited:
538 #endif
539                 default:
540                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
541                         return(-1);
542                 }
543                 break;
544                 
545         case SocketOptionLevel_Udp:
546                 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
547
548                 switch(mono_name) {
549                 case SocketOptionName_NoChecksum:
550                 case SocketOptionName_ChecksumCoverage:
551                 default:
552                         g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
553                         return(-1);
554                 }
555                 return(-1);
556                 break;
557
558         default:
559                 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
560                 return(-1);
561         }
562
563         return(0);
564 }
565
566 static MonoImage*
567 get_socket_assembly (void)
568 {
569         MonoDomain *domain = mono_domain_get ();
570         
571         if (domain->socket_assembly == NULL) {
572                 MonoImage *socket_assembly;
573
574                 socket_assembly = mono_image_loaded ("System");
575                 if (!socket_assembly) {
576                         MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);
577                 
578                         if (!sa) {
579                                 g_assert_not_reached ();
580                         } else {
581                                 socket_assembly = mono_assembly_get_image (sa);
582                         }
583                 }
584                 mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
585         }
586         
587         return domain->socket_assembly;
588 }
589
590 static gint32
591 get_family_hint (void)
592 {
593         MonoDomain *domain = mono_domain_get ();
594
595         if (!domain->inet_family_hint) {
596                 MonoImage *socket_assembly;
597                 MonoClass *socket_class;
598                 MonoClassField *ipv6_field, *ipv4_field;
599                 gint32 ipv6_enabled = -1, ipv4_enabled = -1;
600                 MonoVTable *vtable;
601
602                 socket_assembly = get_socket_assembly ();
603                 g_assert (socket_assembly);
604
605                 socket_class = mono_class_from_name (socket_assembly, "System.Net.Sockets", "Socket");
606                 g_assert (socket_class);
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 (vtable);
618
619                 mono_field_static_get_value (vtable, ipv4_field, &ipv4_enabled);
620                 mono_field_static_get_value (vtable, ipv6_field, &ipv6_enabled);
621
622                 mono_domain_lock (domain);
623                 if (ipv4_enabled == 1 && ipv6_enabled == 1) {
624                         domain->inet_family_hint = 1;
625                 } else if (ipv4_enabled == 1) {
626                         domain->inet_family_hint = 2;
627                 } else {
628                         domain->inet_family_hint = 3;
629                 }
630                 mono_domain_unlock (domain);
631         }
632         switch (domain->inet_family_hint) {
633         case 1: return PF_UNSPEC;
634         case 2: return PF_INET;
635         case 3: return PF_INET6;
636         default:
637                 return PF_UNSPEC;
638         }
639 }
640
641 gpointer
642 ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObject *this_obj, gint32 family, gint32 type, gint32 proto, gint32 *error)
643 {
644         SOCKET sock;
645         gint32 sock_family;
646         gint32 sock_proto;
647         gint32 sock_type;
648         
649         *error = 0;
650         
651         sock_family = convert_family ((MonoAddressFamily)family);
652         if(sock_family==-1) {
653                 *error = WSAEAFNOSUPPORT;
654                 return(NULL);
655         }
656
657         sock_proto = convert_proto ((MonoProtocolType)proto);
658         if(sock_proto==-1) {
659                 *error = WSAEPROTONOSUPPORT;
660                 return(NULL);
661         }
662         
663         sock_type = convert_type ((MonoSocketType)type);
664         if(sock_type==-1) {
665                 *error = WSAESOCKTNOSUPPORT;
666                 return(NULL);
667         }
668         
669         sock = _wapi_socket (sock_family, sock_type, sock_proto,
670                              NULL, 0, WSA_FLAG_OVERLAPPED);
671
672         if(sock==INVALID_SOCKET) {
673                 *error = WSAGetLastError ();
674                 return(NULL);
675         }
676
677         return(GUINT_TO_POINTER (sock));
678 }
679
680 /* FIXME: the SOCKET parameter (here and in other functions in this
681  * file) is really an IntPtr which needs to be converted to a guint32.
682  */
683 void
684 ves_icall_System_Net_Sockets_Socket_Close_internal (SOCKET sock, gint32 *error)
685 {
686         LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
687
688         *error = 0;
689
690         /* Clear any pending work item from this socket if the underlying
691          * polling system does not notify when the socket is closed */
692         mono_threadpool_ms_io_remove_socket (GPOINTER_TO_INT (sock));
693
694         MONO_PREPARE_BLOCKING;
695         closesocket(sock);
696         MONO_FINISH_BLOCKING;
697 }
698
699 gint32
700 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
701 {
702         LOGDEBUG (g_message("%s: returning %d", __func__, WSAGetLastError()));
703
704         return(WSAGetLastError());
705 }
706
707 gint32
708 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock, gint32 *error)
709 {
710         int ret;
711         int amount;
712         
713         *error = 0;
714
715         /* FIXME: this might require amount to be unsigned long. */
716         ret=ioctlsocket(sock, FIONREAD, &amount);
717         if(ret==SOCKET_ERROR) {
718                 *error = WSAGetLastError ();
719                 return(0);
720         }
721         
722         return(amount);
723 }
724
725 void
726 ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock, gboolean block, gint32 *error)
727 {
728         int ret;
729         
730         *error = 0;
731
732         /*
733          * block == TRUE/FALSE means we will block/not block.
734          * But the ioctlsocket call takes TRUE/FALSE for non-block/block
735          */
736         block = !block;
737         
738         ret = ioctlsocket (sock, FIONBIO, (gulong *) &block);
739         if(ret==SOCKET_ERROR) {
740                 *error = WSAGetLastError ();
741         }
742 }
743
744 gpointer
745 ves_icall_System_Net_Sockets_Socket_Accept_internal (SOCKET sock, gint32 *error, gboolean blocking)
746 {
747         gboolean interrupted;
748         SOCKET newsock;
749
750         *error = 0;
751
752         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
753         if (interrupted) {
754                 *error = 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                 *error = WSAEINTR;
776                 return NULL;
777         }
778
779         if(newsock==INVALID_SOCKET) {
780                 *error = 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 *error)
789 {
790         int ret;
791         
792         *error = 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                 *error = WSAGetLastError ();
802         }
803 }
804
805 // Check whether it's ::ffff::0:0.
806 static gboolean
807 is_ipv4_mapped_any (const struct in6_addr *addr)
808 {
809         int i;
810         
811         for (i = 0; i < 10; i++) {
812                 if (addr->s6_addr [i])
813                         return FALSE;
814         }
815         if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
816                 return FALSE;
817         for (i = 12; i < 16; i++) {
818                 if (addr->s6_addr [i])
819                         return FALSE;
820         }
821         return TRUE;
822 }
823
824 static MonoObject*
825 create_object_from_sockaddr(struct sockaddr *saddr, int sa_size, gint32 *error)
826 {
827         MonoDomain *domain = mono_domain_get ();
828         MonoObject *sockaddr_obj;
829         MonoArray *data;
830         MonoAddressFamily family;
831
832         /* Build a System.Net.SocketAddress object instance */
833         if (!domain->sockaddr_class) {
834                 domain->sockaddr_class=mono_class_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
835                 g_assert (domain->sockaddr_class);
836         }
837         sockaddr_obj=mono_object_new(domain, domain->sockaddr_class);
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                 *error = 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_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
873                 }
874                 
875                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
876                 mono_array_set(data, guint8, 3, (port) & 0xff);
877                 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
878                 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
879                 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
880                 mono_array_set(data, guint8, 7, (address) & 0xff);
881         
882                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
883
884                 return(sockaddr_obj);
885         } else if (saddr->sa_family == AF_INET6) {
886                 struct sockaddr_in6 *sa_in=(struct sockaddr_in6 *)saddr;
887                 int i;
888
889                 guint16 port=ntohs(sa_in->sin6_port);
890
891                 if(sa_size<28) {
892                         mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
893                 }
894
895                 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
896                 mono_array_set(data, guint8, 3, (port) & 0xff);
897                 
898                 if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
899                         // Map ::ffff:0:0 to :: (bug #5502)
900                         for(i=0; i<16; i++) {
901                                 mono_array_set(data, guint8, 8+i, 0);
902                         }
903                 } else {
904                         for(i=0; i<16; i++) {
905                                 mono_array_set(data, guint8, 8+i,
906                                                sa_in->sin6_addr.s6_addr[i]);
907                         }
908                 }
909
910                 mono_array_set(data, guint8, 24, sa_in->sin6_scope_id & 0xff);
911                 mono_array_set(data, guint8, 25,
912                                (sa_in->sin6_scope_id >> 8) & 0xff);
913                 mono_array_set(data, guint8, 26,
914                                (sa_in->sin6_scope_id >> 16) & 0xff);
915                 mono_array_set(data, guint8, 27,
916                                (sa_in->sin6_scope_id >> 24) & 0xff);
917
918                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
919
920                 return(sockaddr_obj);
921         }
922 #ifdef HAVE_SYS_UN_H
923         else if (saddr->sa_family == AF_UNIX) {
924                 int i;
925
926                 for (i = 0; i < sa_size; i++) {
927                         mono_array_set (data, guint8, i+2, saddr->sa_data[i]);
928                 }
929                 
930                 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
931
932                 return sockaddr_obj;
933         }
934 #endif
935         else {
936                 *error = 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 *error)
962 {
963         gchar *sa;
964         socklen_t salen;
965         int ret;
966         MonoObject *result;
967         
968         *error = 0;
969         
970         salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
971         if (salen == 0) {
972                 *error = WSAEAFNOSUPPORT;
973                 return NULL;
974         }
975         sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
976
977         MONO_PREPARE_BLOCKING;
978
979         ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
980
981         MONO_FINISH_BLOCKING;
982         
983         if(ret==SOCKET_ERROR) {
984                 *error = WSAGetLastError ();
985                 if (salen > 128)
986                         g_free (sa);
987                 return(NULL);
988         }
989         
990         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)));
991
992         result = create_object_from_sockaddr((struct sockaddr *)sa, salen, error);
993         if (salen > 128)
994                 g_free (sa);
995         return result;
996 }
997
998 MonoObject*
999 ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (SOCKET sock, gint32 af, gint32 *error)
1000 {
1001         gchar *sa;
1002         socklen_t salen;
1003         int ret;
1004         MonoObject *result;
1005         
1006         *error = 0;
1007         
1008         salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
1009         if (salen == 0) {
1010                 *error = WSAEAFNOSUPPORT;
1011                 return NULL;
1012         }
1013         sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
1014         /* Note: linux returns just 2 for AF_UNIX. Always. */
1015
1016         MONO_PREPARE_BLOCKING;
1017
1018         ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
1019
1020         MONO_FINISH_BLOCKING;
1021
1022         if(ret==SOCKET_ERROR) {
1023                 *error = WSAGetLastError ();
1024                 if (salen > 128)
1025                         g_free (sa);
1026                 return(NULL);
1027         }
1028         
1029         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)));
1030
1031         result = create_object_from_sockaddr((struct sockaddr *)sa, salen, error);
1032         if (salen > 128)
1033                 g_free (sa);
1034         return result;
1035 }
1036
1037 static struct sockaddr*
1038 create_sockaddr_from_object(MonoObject *saddr_obj, socklen_t *sa_size, gint32 *error)
1039 {
1040         MonoClassField *field;
1041         MonoArray *data;
1042         gint32 family;
1043         int len;
1044
1045         /* Dig the SocketAddress data buffer out of the object */
1046         field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
1047         data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
1048
1049         /* The data buffer is laid out as follows:
1050          * byte 0 is the address family low byte
1051          * byte 1 is the address family high byte
1052          * INET:
1053          *      bytes 2 and 3 are the port info
1054          *      the rest is the address info
1055          * UNIX:
1056          *      the rest is the file name
1057          */
1058         len = mono_array_length (data);
1059         if (len < 2) {
1060                 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1061         }
1062         
1063         family = convert_family ((MonoAddressFamily)(mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8)));
1064         if (family == AF_INET) {
1065                 struct sockaddr_in *sa;
1066                 guint16 port;
1067                 guint32 address;
1068                 
1069                 if (len < 8) {
1070                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1071                 }
1072
1073                 sa = g_new0 (struct sockaddr_in, 1);
1074                 port = (mono_array_get (data, guint8, 2) << 8) +
1075                         mono_array_get (data, guint8, 3);
1076                 address = (mono_array_get (data, guint8, 4) << 24) +
1077                         (mono_array_get (data, guint8, 5) << 16 ) +
1078                         (mono_array_get (data, guint8, 6) << 8) +
1079                         mono_array_get (data, guint8, 7);
1080
1081                 sa->sin_family = family;
1082                 sa->sin_addr.s_addr = htonl (address);
1083                 sa->sin_port = htons (port);
1084
1085                 *sa_size = sizeof(struct sockaddr_in);
1086                 return((struct sockaddr *)sa);
1087         } else if (family == AF_INET6) {
1088                 struct sockaddr_in6 *sa;
1089                 int i;
1090                 guint16 port;
1091                 guint32 scopeid;
1092                 
1093                 if (len < 28) {
1094                         mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1095                 }
1096
1097                 sa = g_new0 (struct sockaddr_in6, 1);
1098                 port = mono_array_get (data, guint8, 3) +
1099                         (mono_array_get (data, guint8, 2) << 8);
1100                 scopeid = mono_array_get (data, guint8, 24) + 
1101                         (mono_array_get (data, guint8, 25) << 8) + 
1102                         (mono_array_get (data, guint8, 26) << 16) + 
1103                         (mono_array_get (data, guint8, 27) << 24);
1104
1105                 sa->sin6_family = family;
1106                 sa->sin6_port = htons (port);
1107                 sa->sin6_scope_id = scopeid;
1108
1109                 for(i=0; i<16; i++) {
1110                         sa->sin6_addr.s6_addr[i] = mono_array_get (data, guint8, 8+i);
1111                 }
1112
1113                 *sa_size = sizeof(struct sockaddr_in6);
1114                 return((struct sockaddr *)sa);
1115         }
1116 #ifdef HAVE_SYS_UN_H
1117         else if (family == AF_UNIX) {
1118                 struct sockaddr_un *sock_un;
1119                 int i;
1120
1121                 /* Need a byte for the '\0' terminator/prefix, and the first
1122                  * two bytes hold the SocketAddress family
1123                  */
1124                 if (len - 2 >= sizeof(sock_un->sun_path)) {
1125                         mono_raise_exception (mono_get_exception_index_out_of_range ());
1126                 }
1127                 
1128                 sock_un = g_new0 (struct sockaddr_un, 1);
1129
1130                 sock_un->sun_family = family;
1131                 for (i = 0; i < len - 2; i++) {
1132                         sock_un->sun_path [i] = mono_array_get (data, guint8,
1133                                                                 i + 2);
1134                 }
1135                 
1136                 *sa_size = len;
1137
1138                 return (struct sockaddr *)sock_un;
1139         }
1140 #endif
1141         else {
1142                 *error = WSAEAFNOSUPPORT;
1143                 return(0);
1144         }
1145 }
1146
1147 void
1148 ves_icall_System_Net_Sockets_Socket_Bind_internal (SOCKET sock, MonoObject *sockaddr, gint32 *error)
1149 {
1150         struct sockaddr *sa;
1151         socklen_t sa_size;
1152         int ret;
1153         
1154         *error = 0;
1155         
1156         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1157         if (*error != 0) {
1158                 return;
1159         }
1160
1161         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)));
1162
1163         ret = _wapi_bind (sock, sa, sa_size);
1164
1165         if(ret==SOCKET_ERROR) {
1166                 *error = WSAGetLastError ();
1167         }
1168
1169         g_free(sa);
1170 }
1171
1172 enum {
1173         SelectModeRead,
1174         SelectModeWrite,
1175         SelectModeError
1176 };
1177
1178 MonoBoolean
1179 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1180                                                    gint timeout, gint32 *error)
1181 {
1182         MonoInternalThread *thread = mono_thread_internal_current ();
1183         mono_pollfd *pfds;
1184         int ret;
1185         gboolean interrupted;
1186         time_t start;
1187
1188         *error = 0;
1189
1190         pfds = g_new0 (mono_pollfd, 1);
1191         pfds->fd = GPOINTER_TO_INT (sock);
1192
1193         switch (mode) {
1194         case SelectModeRead:  pfds->events = MONO_POLLIN; break;
1195         case SelectModeWrite: pfds->events = MONO_POLLOUT; break;
1196         default:              pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL; break;
1197         }
1198
1199         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1200         start = time (NULL);
1201
1202         do {
1203                 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1204                 if (interrupted) {
1205                         g_free (pfds);
1206                         *error = WSAEINTR;
1207                         return FALSE;
1208                 }
1209
1210                 MONO_PREPARE_BLOCKING;
1211
1212                 ret = mono_poll (pfds, 1, timeout);
1213
1214                 MONO_FINISH_BLOCKING;
1215
1216                 mono_thread_info_uninstall_interrupt (&interrupted);
1217                 if (interrupted) {
1218                         g_free (pfds);
1219                         *error = WSAEINTR;
1220                         return FALSE;
1221                 }
1222
1223                 if (timeout > 0 && ret < 0) {
1224                         int err = errno;
1225                         int sec = time (NULL) - start;
1226                         
1227                         timeout -= sec * 1000;
1228                         if (timeout < 0) {
1229                                 timeout = 0;
1230                         }
1231                         
1232                         errno = err;
1233                 }
1234
1235                 if (ret == -1 && errno == EINTR) {
1236                         if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
1237                                 g_free (pfds);
1238                                 return FALSE;
1239                         }
1240
1241                         /* Suspend requested? */
1242                         mono_thread_interruption_checkpoint ();
1243
1244                         errno = EINTR;
1245                 }
1246         } while (ret == -1 && errno == EINTR);
1247
1248         if (ret == -1) {
1249 #ifdef HOST_WIN32
1250                 *error = WSAGetLastError ();
1251 #else
1252                 *error = errno_to_WSA (errno, __func__);
1253 #endif
1254                 g_free (pfds);
1255                 return FALSE;
1256         }
1257
1258         g_free (pfds);
1259         return ret != 0;
1260 }
1261
1262 void
1263 ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *sockaddr, gint32 *error)
1264 {
1265         struct sockaddr *sa;
1266         socklen_t sa_size;
1267         int ret;
1268         gboolean interrupted;
1269
1270         *error = 0;
1271
1272         sa = create_sockaddr_from_object(sockaddr, &sa_size, error);
1273         if (*error != 0)
1274                 return;
1275
1276         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)));
1277
1278         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1279         if (interrupted) {
1280                 *error = WSAEINTR;
1281                 return;
1282         }
1283
1284         MONO_PREPARE_BLOCKING;
1285
1286         ret = _wapi_connect (sock, sa, sa_size);
1287
1288         MONO_FINISH_BLOCKING;
1289
1290         mono_thread_info_uninstall_interrupt (&interrupted);
1291         if (interrupted) {
1292                 *error = WSAEINTR;
1293                 return;
1294         }
1295
1296         if (ret == SOCKET_ERROR)
1297                 *error = WSAGetLastError ();
1298
1299         g_free(sa);
1300 }
1301
1302 /* These #defines from mswsock.h from wine.  Defining them here allows
1303  * us to build this file on a mingw box that doesn't know the magic
1304  * numbers, but still run on a newer windows box that does.
1305  */
1306 #ifndef WSAID_DISCONNECTEX
1307 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1308 typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
1309 #endif
1310
1311 #ifndef WSAID_TRANSMITFILE
1312 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1313 typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
1314 #endif
1315
1316 void
1317 ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolean reuse, gint32 *error)
1318 {
1319         int ret;
1320         glong output_bytes = 0;
1321         GUID disco_guid = WSAID_DISCONNECTEX;
1322         GUID trans_guid = WSAID_TRANSMITFILE;
1323         LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
1324         LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
1325         gboolean interrupted;
1326
1327         *error = 0;
1328
1329         LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
1330
1331         MONO_PREPARE_BLOCKING;
1332
1333         /* I _think_ the extension function pointers need to be looked
1334          * up for each socket.  FIXME: check the best way to store
1335          * pointers to functions in managed objects that still works
1336          * on 64bit platforms.
1337          */
1338         ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&disco_guid, sizeof(GUID),
1339                         (gchar *)&_wapi_disconnectex, sizeof(void *), &output_bytes, NULL, NULL);
1340
1341         MONO_FINISH_BLOCKING;
1342
1343         if (ret != 0) {
1344                 /* make sure that WSAIoctl didn't put crap in the
1345                  * output pointer
1346                  */
1347                 _wapi_disconnectex = NULL;
1348
1349                 MONO_PREPARE_BLOCKING;
1350
1351                 /*
1352                  * Use the SIO_GET_EXTENSION_FUNCTION_POINTER to
1353                  * determine the address of the disconnect method without
1354                  * taking a hard dependency on a single provider
1355                  * 
1356                  * For an explanation of why this is done, you can read
1357                  * the article at http://www.codeproject.com/internet/jbsocketserver3.asp
1358                  */
1359                 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&trans_guid, sizeof(GUID),
1360                                 (gchar *)&_wapi_transmitfile, sizeof(void *), &output_bytes, NULL, NULL);
1361
1362                 MONO_FINISH_BLOCKING;
1363
1364                 if (ret != 0)
1365                         _wapi_transmitfile = NULL;
1366         }
1367
1368         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1369         if (interrupted) {
1370                 *error = WSAEINTR;
1371                 return;
1372         }
1373
1374         MONO_PREPARE_BLOCKING;
1375
1376         if (_wapi_disconnectex != NULL) {
1377                 if (!_wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0))
1378                         *error = WSAGetLastError ();
1379         } else if (_wapi_transmitfile != NULL) {
1380                 if (!_wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET))
1381                         *error = WSAGetLastError ();
1382         } else {
1383                 *error = ERROR_NOT_SUPPORTED;
1384         }
1385
1386         MONO_FINISH_BLOCKING;
1387
1388         mono_thread_info_uninstall_interrupt (&interrupted);
1389         if (interrupted)
1390                 *error = WSAEINTR;
1391 }
1392
1393 gint32
1394 ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1395 {
1396         int ret;
1397         guchar *buf;
1398         gint32 alen;
1399         int recvflags=0;
1400         gboolean interrupted;
1401         MonoInternalThread* curthread G_GNUC_UNUSED = mono_thread_internal_current ();
1402         
1403         *error = 0;
1404         
1405         alen = mono_array_length (buffer);
1406         if (offset > alen - count) {
1407                 return(0);
1408         }
1409         
1410         buf=mono_array_addr(buffer, guchar, offset);
1411         
1412         recvflags = convert_socketflags (flags);
1413         if (recvflags == -1) {
1414                 *error = WSAEOPNOTSUPP;
1415                 return (0);
1416         }
1417
1418         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1419         if (interrupted)
1420                 return 0;
1421
1422         MONO_PREPARE_BLOCKING;
1423
1424 #ifdef HOST_WIN32
1425         {
1426                 curthread->interrupt_on_stop = (gpointer)TRUE;
1427                 ret = _wapi_recv (sock, buf, count, recvflags);
1428                 curthread->interrupt_on_stop = (gpointer)FALSE;
1429         }
1430 #else
1431         ret = _wapi_recv (sock, buf, count, recvflags);
1432 #endif
1433
1434         MONO_FINISH_BLOCKING;
1435
1436         mono_thread_info_uninstall_interrupt (&interrupted);
1437         if (interrupted) {
1438                 *error = WSAEINTR;
1439                 return 0;
1440         }
1441
1442         if(ret==SOCKET_ERROR) {
1443                 *error = WSAGetLastError ();
1444                 return(0);
1445         }
1446
1447         return(ret);
1448 }
1449
1450 gint32
1451 ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error)
1452 {
1453         int ret, count;
1454         gboolean interrupted;
1455         DWORD recv;
1456         WSABUF *wsabufs;
1457         DWORD recvflags = 0;
1458         
1459         *error = 0;
1460         
1461         wsabufs = mono_array_addr (buffers, WSABUF, 0);
1462         count = mono_array_length (buffers);
1463         
1464         recvflags = convert_socketflags (flags);
1465         if (recvflags == -1) {
1466                 *error = WSAEOPNOTSUPP;
1467                 return(0);
1468         }
1469
1470         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1471         if (interrupted) {
1472                 *error = WSAEINTR;
1473                 return 0;
1474         }
1475
1476         MONO_PREPARE_BLOCKING;
1477
1478         ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL);
1479
1480         MONO_FINISH_BLOCKING;
1481
1482         mono_thread_info_uninstall_interrupt (&interrupted);
1483         if (interrupted) {
1484                 *error = WSAEINTR;
1485                 return 0;
1486         }
1487
1488         if (ret == SOCKET_ERROR) {
1489                 *error = WSAGetLastError ();
1490                 return 0;
1491         }
1492
1493         return recv;
1494 }
1495
1496 gint32
1497 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
1498 {
1499         int ret;
1500         guchar *buf;
1501         gint32 alen;
1502         int recvflags=0;
1503         struct sockaddr *sa;
1504         socklen_t sa_size;
1505         gboolean interrupted;
1506         
1507         *error = 0;
1508         
1509         alen = mono_array_length (buffer);
1510         if (offset > alen - count) {
1511                 return(0);
1512         }
1513
1514         sa=create_sockaddr_from_object(*sockaddr, &sa_size, error);
1515         if (*error != 0) {
1516                 return(0);
1517         }
1518         
1519         buf=mono_array_addr(buffer, guchar, offset);
1520         
1521         recvflags = convert_socketflags (flags);
1522         if (recvflags == -1) {
1523                 *error = WSAEOPNOTSUPP;
1524                 return (0);
1525         }
1526
1527         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1528         if (interrupted) {
1529                 g_free(sa);
1530                 *error = WSAEINTR;
1531                 return 0;
1532         }
1533
1534         MONO_PREPARE_BLOCKING;
1535
1536         ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1537
1538         MONO_FINISH_BLOCKING;
1539
1540         mono_thread_info_uninstall_interrupt (&interrupted);
1541         if (interrupted) {
1542                 g_free(sa);
1543                 *error = WSAEINTR;
1544                 return 0;
1545         }
1546
1547         if(ret==SOCKET_ERROR) {
1548                 g_free(sa);
1549                 *error = WSAGetLastError ();
1550                 return(0);
1551         }
1552
1553         /* If we didn't get a socket size, then we're probably a
1554          * connected connection-oriented socket and the stack hasn't
1555          * returned the remote address. All we can do is return null.
1556          */
1557         if ( sa_size != 0 )
1558                 *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
1559         else
1560                 *sockaddr=NULL;
1561
1562         g_free(sa);
1563         
1564         return(ret);
1565 }
1566
1567 gint32
1568 ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1569 {
1570         int ret;
1571         guchar *buf;
1572         gint32 alen;
1573         int sendflags=0;
1574         gboolean interrupted;
1575         
1576         *error = 0;
1577         
1578         alen = mono_array_length (buffer);
1579         if (offset > alen - count) {
1580                 return(0);
1581         }
1582
1583         LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
1584         
1585         buf=mono_array_addr(buffer, guchar, offset);
1586
1587         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1588
1589         sendflags = convert_socketflags (flags);
1590         if (sendflags == -1) {
1591                 *error = WSAEOPNOTSUPP;
1592                 return (0);
1593         }
1594
1595         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1596         if (interrupted) {
1597                 *error = WSAEINTR;
1598                 return 0;
1599         }
1600
1601         MONO_PREPARE_BLOCKING;
1602
1603         ret = _wapi_send (sock, buf, count, sendflags);
1604
1605         MONO_FINISH_BLOCKING;
1606
1607         mono_thread_info_uninstall_interrupt (&interrupted);
1608         if (interrupted) {
1609                 *error = WSAEINTR;
1610                 return 0;
1611         }
1612
1613         if(ret==SOCKET_ERROR) {
1614                 *error = WSAGetLastError ();
1615                 return(0);
1616         }
1617
1618         return(ret);
1619 }
1620
1621 gint32
1622 ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *error)
1623 {
1624         int ret, count;
1625         DWORD sent;
1626         WSABUF *wsabufs;
1627         DWORD sendflags = 0;
1628         gboolean interrupted;
1629         
1630         *error = 0;
1631         
1632         wsabufs = mono_array_addr (buffers, WSABUF, 0);
1633         count = mono_array_length (buffers);
1634         
1635         sendflags = convert_socketflags (flags);
1636         if (sendflags == -1) {
1637                 *error = WSAEOPNOTSUPP;
1638                 return(0);
1639         }
1640
1641         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1642         if (interrupted) {
1643                 *error = WSAEINTR;
1644                 return 0;
1645         }
1646
1647         MONO_PREPARE_BLOCKING;
1648
1649         ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL);
1650
1651         MONO_FINISH_BLOCKING;
1652
1653         mono_thread_info_uninstall_interrupt (&interrupted);
1654         if (interrupted) {
1655                 *error = WSAEINTR;
1656                 return 0;
1657         }
1658
1659         if (ret == SOCKET_ERROR) {
1660                 *error = WSAGetLastError ();
1661                 return(0);
1662         }
1663         
1664         return(sent);
1665 }
1666
1667 gint32
1668 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
1669 {
1670         int ret;
1671         guchar *buf;
1672         gint32 alen;
1673         int sendflags=0;
1674         struct sockaddr *sa;
1675         socklen_t sa_size;
1676         gboolean interrupted;
1677         
1678         *error = 0;
1679         
1680         alen = mono_array_length (buffer);
1681         if (offset > alen - count) {
1682                 return(0);
1683         }
1684
1685         sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1686         if(*error != 0) {
1687                 return(0);
1688         }
1689         
1690         LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
1691         
1692         buf=mono_array_addr(buffer, guchar, offset);
1693
1694         LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1695
1696         sendflags = convert_socketflags (flags);
1697         if (sendflags == -1) {
1698                 g_free (sa);
1699                 *error = WSAEOPNOTSUPP;
1700                 return (0);
1701         }
1702
1703         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1704         if (interrupted) {
1705                 g_free (sa);
1706                 *error = WSAEINTR;
1707                 return 0;
1708         }
1709
1710         MONO_PREPARE_BLOCKING;
1711
1712         ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1713
1714         MONO_FINISH_BLOCKING;
1715
1716         mono_thread_info_uninstall_interrupt (&interrupted);
1717         if (interrupted) {
1718                 g_free (sa);
1719                 *error = WSAEINTR;
1720                 return 0;
1721         }
1722
1723         if(ret==SOCKET_ERROR) {
1724                 *error = WSAGetLastError ();
1725         }
1726
1727         g_free(sa);
1728         
1729         return(ret);
1730 }
1731
1732 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
1733 {
1734         MonoSafeHandle *safe_handle;
1735         MonoClassField *field;
1736         
1737         field = mono_class_get_field_from_name (sockobj->vtable->klass, "safe_handle");
1738         safe_handle = ((MonoSafeHandle*) (*(gpointer *)(((char *)sockobj)+field->offset)));
1739
1740         if (safe_handle == NULL)
1741                 return -1;
1742
1743         return (SOCKET) safe_handle->handle;
1744 }
1745
1746 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1747 void
1748 ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32 timeout, gint32 *error)
1749 {
1750         MonoInternalThread *thread = mono_thread_internal_current ();
1751         MonoObject *obj;
1752         mono_pollfd *pfds;
1753         int nfds, idx;
1754         int ret;
1755         int i, count;
1756         int mode;
1757         MonoClass *sock_arr_class;
1758         MonoArray *socks;
1759         time_t start;
1760         uintptr_t socks_size;
1761         gboolean interrupted;
1762
1763         *error = 0;
1764         
1765         /* *sockets -> READ, null, WRITE, null, ERROR, null */
1766         count = mono_array_length (*sockets);
1767         nfds = count - 3; /* NULL separators */
1768         pfds = g_new0 (mono_pollfd, nfds);
1769         mode = idx = 0;
1770         for (i = 0; i < count; i++) {
1771                 obj = mono_array_get (*sockets, MonoObject *, i);
1772                 if (obj == NULL) {
1773                         mode++;
1774                         continue;
1775                 }
1776
1777                 if (idx >= nfds) {
1778                         /* The socket array was bogus */
1779                         g_free (pfds);
1780                         *error = WSAEFAULT;
1781                         return;
1782                 }
1783
1784                 pfds [idx].fd = Socket_to_SOCKET (obj);
1785                 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1786                 idx++;
1787         }
1788
1789         timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1790         start = time (NULL);
1791         do {
1792                 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1793                 if (interrupted) {
1794                         g_free (pfds);
1795                         *error = WSAEINTR;
1796                         return;
1797                 }
1798
1799                 MONO_PREPARE_BLOCKING;
1800
1801                 ret = mono_poll (pfds, nfds, timeout);
1802
1803                 MONO_FINISH_BLOCKING;
1804
1805                 mono_thread_info_uninstall_interrupt (&interrupted);
1806                 if (interrupted) {
1807                         g_free (pfds);
1808                         *error = WSAEINTR;
1809                         return;
1810                 }
1811
1812                 if (timeout > 0 && ret < 0) {
1813                         int err = errno;
1814                         int sec = time (NULL) - start;
1815
1816                         timeout -= sec * 1000;
1817                         if (timeout < 0)
1818                                 timeout = 0;
1819                         errno = err;
1820                 }
1821
1822                 if (ret == -1 && errno == EINTR) {
1823                         if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
1824                                 g_free (pfds);
1825                                 *sockets = NULL;
1826                                 return;
1827                         }
1828
1829                         /* Suspend requested? */
1830                         mono_thread_interruption_checkpoint ();
1831
1832                         errno = EINTR;
1833                 }
1834         } while (ret == -1 && errno == EINTR);
1835         
1836         if (ret == -1) {
1837 #ifdef HOST_WIN32
1838                 *error = WSAGetLastError ();
1839 #else
1840                 *error = errno_to_WSA (errno, __func__);
1841 #endif
1842                 g_free (pfds);
1843                 return;
1844         }
1845
1846         if (ret == 0) {
1847                 g_free (pfds);
1848                 *sockets = NULL;
1849                 return;
1850         }
1851
1852         sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
1853         socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1854         socks = mono_array_new_full (mono_domain_get (), sock_arr_class, &socks_size, NULL);
1855
1856         mode = idx = 0;
1857         for (i = 0; i < count && ret > 0; i++) {
1858                 mono_pollfd *pfd;
1859
1860                 obj = mono_array_get (*sockets, MonoObject *, i);
1861                 if (obj == NULL) {
1862                         mode++;
1863                         idx++;
1864                         continue;
1865                 }
1866
1867                 pfd = &pfds [i - mode];
1868                 if (pfd->revents == 0)
1869                         continue;
1870
1871                 ret--;
1872                 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1873                         mono_array_setref (socks, idx++, obj);
1874                 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1875                         mono_array_setref (socks, idx++, obj);
1876                 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1877                         mono_array_setref (socks, idx++, obj);
1878                 }
1879         }
1880
1881         *sockets = socks;
1882         g_free (pfds);
1883 }
1884
1885 static MonoObject* int_to_object (MonoDomain *domain, int val)
1886 {
1887         return mono_value_box (domain, mono_get_int32_class (), &val);
1888 }
1889
1890
1891 void
1892 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error)
1893 {
1894         int system_level = 0;
1895         int system_name = 0;
1896         int ret;
1897         int val;
1898         socklen_t valsize=sizeof(val);
1899         struct linger linger;
1900         socklen_t lingersize=sizeof(linger);
1901         int time_ms = 0;
1902         socklen_t time_ms_size = sizeof (time_ms);
1903 #ifdef SO_PEERCRED
1904 #  if defined(__OpenBSD__)
1905         struct sockpeercred cred;
1906 #  else
1907         struct ucred cred;
1908 #  endif
1909         socklen_t credsize = sizeof(cred);
1910 #endif
1911         MonoDomain *domain=mono_domain_get();
1912         MonoObject *obj;
1913         MonoClass *obj_class;
1914         MonoClassField *field;
1915         
1916         *error = 0;
1917         
1918 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1919         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1920                 system_level = SOL_SOCKET;
1921                 system_name = SO_REUSEADDR;
1922                 ret = 0;
1923         } else
1924 #endif
1925         {
1926
1927                 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1928         }
1929
1930         if(ret==-1) {
1931                 *error = WSAENOPROTOOPT;
1932                 return;
1933         }
1934         if (ret == -2) {
1935                 *obj_val = int_to_object (domain, 0);
1936                 return;
1937         }
1938
1939         MONO_PREPARE_BLOCKING;
1940
1941         /* No need to deal with MulticastOption names here, because
1942          * you cant getsockopt AddMembership or DropMembership (the
1943          * int getsockopt will error, causing an exception)
1944          */
1945         switch(name) {
1946         case SocketOptionName_Linger:
1947         case SocketOptionName_DontLinger:
1948                 ret = _wapi_getsockopt(sock, system_level, system_name, &linger, &lingersize);
1949                 break;
1950                 
1951         case SocketOptionName_SendTimeout:
1952         case SocketOptionName_ReceiveTimeout:
1953                 ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
1954                 break;
1955
1956 #ifdef SO_PEERCRED
1957         case SocketOptionName_PeerCred: 
1958                 ret = _wapi_getsockopt (sock, system_level, system_name, &cred, &credsize);
1959                 break;
1960 #endif
1961
1962         default:
1963                 ret = _wapi_getsockopt (sock, system_level, system_name, &val, &valsize);
1964         }
1965
1966         MONO_FINISH_BLOCKING;
1967
1968         if(ret==SOCKET_ERROR) {
1969                 *error = WSAGetLastError ();
1970                 return;
1971         }
1972         
1973         switch(name) {
1974         case SocketOptionName_Linger:
1975                 /* build a System.Net.Sockets.LingerOption */
1976                 obj_class=mono_class_from_name(get_socket_assembly (),
1977                                                "System.Net.Sockets",
1978                                                "LingerOption");
1979                 obj=mono_object_new(domain, obj_class);
1980                 
1981                 /* Locate and set the fields "bool enabled" and "int
1982                  * lingerTime"
1983                  */
1984                 field=mono_class_get_field_from_name(obj_class, "enabled");
1985                 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1986
1987                 field=mono_class_get_field_from_name(obj_class, "lingerTime");
1988                 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1989                 
1990                 break;
1991                 
1992         case SocketOptionName_DontLinger:
1993                 /* construct a bool int in val - true if linger is off */
1994                 obj = int_to_object (domain, !linger.l_onoff);
1995                 break;
1996                 
1997         case SocketOptionName_SendTimeout:
1998         case SocketOptionName_ReceiveTimeout:
1999                 obj = int_to_object (domain, time_ms);
2000                 break;
2001
2002 #ifdef SO_PEERCRED
2003         case SocketOptionName_PeerCred: 
2004         {
2005                 /* build a Mono.Posix.PeerCred+PeerCredData if
2006                  * possible
2007                  */
2008                 static MonoImage *mono_posix_image = NULL;
2009                 MonoPeerCredData *cred_data;
2010                 
2011                 if (mono_posix_image == NULL) {
2012                         mono_posix_image=mono_image_loaded ("Mono.Posix");
2013                         if (!mono_posix_image) {
2014                                 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
2015                                 if (!sa) {
2016                                         *error = WSAENOPROTOOPT;
2017                                         return;
2018                                 } else {
2019                                         mono_posix_image = mono_assembly_get_image (sa);
2020                                 }
2021                         }
2022                 }
2023                 
2024                 obj_class = mono_class_from_name(mono_posix_image,
2025                                                  "Mono.Posix",
2026                                                  "PeerCredData");
2027                 obj = mono_object_new(domain, obj_class);
2028                 cred_data = (MonoPeerCredData *)obj;
2029                 cred_data->pid = cred.pid;
2030                 cred_data->uid = cred.uid;
2031                 cred_data->gid = cred.gid;
2032                 break;
2033         }
2034 #endif
2035
2036         default:
2037 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2038                 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
2039                         val = val ? 0 : 1;
2040 #endif
2041                 obj = int_to_object (domain, val);
2042         }
2043         *obj_val=obj;
2044 }
2045
2046 void
2047 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error)
2048 {
2049         int system_level = 0;
2050         int system_name = 0;
2051         int ret;
2052         guchar *buf;
2053         socklen_t valsize;
2054         
2055         *error = 0;
2056         
2057         ret=convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2058                                            &system_name);
2059         if(ret==-1) {
2060                 *error = WSAENOPROTOOPT;
2061                 return;
2062         }
2063         if(ret==-2)
2064                 return;
2065
2066         valsize=mono_array_length(*byte_val);
2067         buf=mono_array_addr(*byte_val, guchar, 0);
2068
2069         MONO_PREPARE_BLOCKING;
2070
2071         ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
2072
2073         MONO_FINISH_BLOCKING;
2074
2075         if(ret==SOCKET_ERROR) {
2076                 *error = WSAGetLastError ();
2077         }
2078 }
2079
2080 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2081 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
2082 {
2083         struct in_addr inaddr;
2084         MonoClassField *field;
2085         
2086         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
2087
2088         /* No idea why .net uses a 64bit type to hold a 32bit value...
2089          *
2090          * Internal value of IPAddess is in little-endian order
2091          */
2092         inaddr.s_addr=GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr)+field->offset));
2093         
2094         return(inaddr);
2095 }
2096
2097 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
2098 {
2099         struct in6_addr in6addr;
2100         MonoClassField *field;
2101         MonoArray *data;
2102         int i;
2103
2104         field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
2105         data=*(MonoArray **)(((char *)ipaddr) + field->offset);
2106
2107 /* Solaris has only the 8 bit version. */
2108 #ifndef s6_addr16
2109         for(i=0; i<8; i++) {
2110                 guint16 s = mono_array_get (data, guint16, i);
2111                 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
2112                 in6addr.s6_addr[2 * i] = s & 0xff;
2113         }
2114 #else
2115         for(i=0; i<8; i++)
2116                 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
2117 #endif
2118         return(in6addr);
2119 }
2120 #endif
2121
2122 #if defined(__APPLE__) || defined(__FreeBSD__)
2123
2124 static int
2125 get_local_interface_id (int family)
2126 {
2127 #if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
2128         return 0;
2129 #else
2130         struct ifaddrs *ifap = NULL, *ptr;
2131         int idx = 0;
2132         
2133         if (getifaddrs (&ifap)) {
2134                 return 0;
2135         }
2136         
2137         for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
2138                 if (!ptr->ifa_addr || !ptr->ifa_name)
2139                         continue;
2140                 if (ptr->ifa_addr->sa_family != family)
2141                         continue;
2142                 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
2143                         continue;
2144                 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
2145                         continue;
2146                         
2147                 idx = if_nametoindex (ptr->ifa_name);
2148                 break;
2149         }
2150         
2151         freeifaddrs (ifap);
2152         return idx;
2153 #endif
2154 }
2155
2156 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
2157
2158 void
2159 ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal (SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val, gint32 *error)
2160 {
2161         struct linger linger;
2162         int system_level = 0;
2163         int system_name = 0;
2164         int ret;
2165         int sol_ip;
2166         int sol_ipv6;
2167
2168         *error = 0;
2169
2170         sol_ipv6 = mono_networking_get_ipv6_protocol ();
2171         sol_ip = mono_networking_get_ip_protocol ();
2172
2173         ret=convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2174                                            &system_name);
2175
2176 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2177         if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2178                 system_name = SO_REUSEADDR;
2179                 int_val = int_val ? 0 : 1;
2180                 ret = 0;
2181         }
2182 #endif
2183
2184         if(ret==-1) {
2185                 *error = WSAENOPROTOOPT;
2186                 return;
2187         }
2188         if(ret==-2){
2189                 return;
2190         }
2191
2192         /* Only one of obj_val, byte_val or int_val has data */
2193         if(obj_val!=NULL) {
2194                 MonoClassField *field;
2195                 int valsize;
2196                 
2197                 switch(name) {
2198                 case SocketOptionName_Linger:
2199                         /* Dig out "bool enabled" and "int lingerTime"
2200                          * fields
2201                          */
2202                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
2203                         linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
2204                         field=mono_class_get_field_from_name(obj_val->vtable->klass, "lingerTime");
2205                         linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
2206                         
2207                         valsize=sizeof(linger);
2208                         ret = _wapi_setsockopt (sock, system_level,
2209                                                 system_name, &linger, valsize);
2210                         break;
2211                 case SocketOptionName_AddMembership:
2212                 case SocketOptionName_DropMembership:
2213 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2214                 {
2215                         MonoObject *address = NULL;
2216
2217                         if(system_level == sol_ipv6) {
2218                                 struct ipv6_mreq mreq6;
2219
2220                                 /*
2221                                  *      Get group address
2222                                  */
2223                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Group");
2224                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2225                                 
2226                                 if(address) {
2227                                         mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
2228                                 }
2229
2230                                 field=mono_class_get_field_from_name(obj_val->vtable->klass, "m_Interface");
2231                                 mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
2232                                 
2233 #if defined(__APPLE__) || defined(__FreeBSD__)
2234                                 /*
2235                                 * Bug #5504:
2236                                 *
2237                                 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2238                                 *
2239                                 * Tests on Windows and Linux show that the multicast group is only
2240                                 * joined on one NIC when interface = 0, so we simply use the interface
2241                                 * id from the first non-loopback interface (this is also what
2242                                 * Dns.GetHostName (string.Empty) would return).
2243                                 */
2244                                 if (!mreq6.ipv6mr_interface)
2245                                         mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2246 #endif
2247                                         
2248                                 ret = _wapi_setsockopt (sock, system_level,
2249                                                         system_name, &mreq6,
2250                                                         sizeof (mreq6));
2251                         } else if(system_level == sol_ip) {
2252 #ifdef HAVE_STRUCT_IP_MREQN
2253                                 struct ip_mreqn mreq = {{0}};
2254 #else
2255                                 struct ip_mreq mreq = {{0}};
2256 #endif /* HAVE_STRUCT_IP_MREQN */
2257                         
2258                                 /* pain! MulticastOption holds two IPAddress
2259                                  * members, so I have to dig the value out of
2260                                  * those :-(
2261                                  */
2262                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
2263                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2264
2265                                 /* address might not be defined and if so, set the address to ADDR_ANY.
2266                                  */
2267                                 if(address) {
2268                                         mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
2269                                 }
2270
2271                                 field = mono_class_get_field_from_name (obj_val->vtable->klass, "localAddress");
2272                                 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2273
2274 #ifdef HAVE_STRUCT_IP_MREQN
2275                                 if(address) {
2276                                         mreq.imr_address = ipaddress_to_struct_in_addr (address);
2277                                 }
2278
2279                                 field = mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
2280                                 mreq.imr_ifindex = *(gint32 *)(((char *)obj_val)+field->offset);
2281 #else
2282                                 if(address) {
2283                                         mreq.imr_interface = ipaddress_to_struct_in_addr (address);
2284                                 }
2285 #endif /* HAVE_STRUCT_IP_MREQN */
2286
2287                                 ret = _wapi_setsockopt (sock, system_level,
2288                                                         system_name, &mreq,
2289                                                         sizeof (mreq));
2290                         }
2291                         break;
2292                 }
2293 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2294                 default:
2295                         /* Cause an exception to be thrown */
2296                         *error = WSAEINVAL;
2297                         return;
2298                 }
2299         } else if (byte_val!=NULL) {
2300                 int valsize = mono_array_length (byte_val);
2301                 guchar *buf = mono_array_addr (byte_val, guchar, 0);
2302                 
2303                 switch(name) {
2304                 case SocketOptionName_DontLinger:
2305                         if (valsize == 1) {
2306                                 linger.l_onoff = (*buf) ? 0 : 1;
2307                                 linger.l_linger = 0;
2308                                 ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2309                         } else {
2310                                 *error = WSAEINVAL;
2311                         }
2312                         break;
2313                 default:
2314                         ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
2315                         break;
2316                 }
2317         } else {
2318                 /* ReceiveTimeout/SendTimeout get here */
2319                 switch(name) {
2320                 case SocketOptionName_DontLinger:
2321                         linger.l_onoff = !int_val;
2322                         linger.l_linger = 0;
2323                         ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2324                         break;
2325                 case SocketOptionName_MulticastInterface:
2326 #ifndef HOST_WIN32
2327 #ifdef HAVE_STRUCT_IP_MREQN
2328                         int_val = GUINT32_FROM_BE (int_val);
2329                         if ((int_val & 0xff000000) == 0) {
2330                                 /* int_val is interface index */
2331                                 struct ip_mreqn mreq = {{0}};
2332                                 mreq.imr_ifindex = int_val;
2333                                 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &mreq, sizeof (mreq));
2334                                 break;
2335                         }
2336                         int_val = GUINT32_TO_BE (int_val);
2337 #endif /* HAVE_STRUCT_IP_MREQN */
2338 #endif /* HOST_WIN32 */
2339                         /* int_val is in_addr */
2340                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2341                         break;
2342                 case SocketOptionName_DontFragment:
2343 #ifdef HAVE_IP_MTU_DISCOVER
2344                         /* Fiddle with the value slightly if we're
2345                          * turning DF on
2346                          */
2347                         if (int_val == 1) {
2348                                 int_val = IP_PMTUDISC_DO;
2349                         }
2350                         /* Fall through */
2351 #endif
2352                         
2353                 default:
2354                         ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2355                 }
2356         }
2357
2358         if(ret==SOCKET_ERROR) {
2359                 *error = WSAGetLastError ();
2360         }
2361 }
2362
2363 void
2364 ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock, gint32 how, gint32 *error)
2365 {
2366         int ret;
2367         gboolean interrupted;
2368
2369         *error = 0;
2370
2371         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2372         if (interrupted) {
2373                 *error = WSAEINTR;
2374                 return;
2375         }
2376
2377         MONO_PREPARE_BLOCKING;
2378
2379         /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2380         ret = _wapi_shutdown (sock, how);
2381
2382         MONO_FINISH_BLOCKING;
2383
2384         mono_thread_info_uninstall_interrupt (&interrupted);
2385         if (interrupted) {
2386                 *error = WSAEINTR;
2387                 return;
2388         }
2389
2390         if (ret == SOCKET_ERROR)
2391                 *error = WSAGetLastError ();
2392 }
2393
2394 gint
2395 ves_icall_System_Net_Sockets_Socket_IOControl_internal (SOCKET sock, gint32 code, MonoArray *input, MonoArray *output, gint32 *error)
2396 {
2397         glong output_bytes = 0;
2398         gchar *i_buffer, *o_buffer;
2399         gint i_len, o_len;
2400         gint ret;
2401
2402         *error = 0;
2403         
2404         if ((guint32)code == FIONBIO) {
2405                 /* Invalid command. Must use Socket.Blocking */
2406                 return -1;
2407         }
2408
2409         if (input == NULL) {
2410                 i_buffer = NULL;
2411                 i_len = 0;
2412         } else {
2413                 i_buffer = mono_array_addr (input, gchar, 0);
2414                 i_len = mono_array_length (input);
2415         }
2416
2417         if (output == NULL) {
2418                 o_buffer = NULL;
2419                 o_len = 0;
2420         } else {
2421                 o_buffer = mono_array_addr (output, gchar, 0);
2422                 o_len = mono_array_length (output);
2423         }
2424
2425         MONO_PREPARE_BLOCKING;
2426
2427         ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2428
2429         MONO_FINISH_BLOCKING;
2430
2431         if (ret == SOCKET_ERROR) {
2432                 *error = WSAGetLastError ();
2433                 return(-1);
2434         }
2435
2436         return (gint) output_bytes;
2437 }
2438
2439 static gboolean 
2440 addrinfo_to_IPHostEntry(MonoAddressInfo *info, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
2441 {
2442         gint32 count, i;
2443         MonoAddressEntry *ai = NULL;
2444         struct in_addr *local_in = NULL;
2445         int nlocal_in = 0;
2446         struct in6_addr *local_in6 = NULL;
2447         int nlocal_in6 = 0;
2448         int addr_index;
2449
2450         MonoDomain *domain = mono_domain_get ();
2451
2452         addr_index = 0;
2453         *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2454         if (add_local_ips) {
2455                 local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2456                 local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2457                 if (nlocal_in || nlocal_in6) {
2458                         char addr [INET6_ADDRSTRLEN];
2459                         *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
2460                         if (nlocal_in) {
2461                                 MonoString *addr_string;
2462                                 int i;
2463
2464                                 for (i = 0; i < nlocal_in; i++) {
2465                                         MonoAddress maddr;
2466                                         mono_address_init (&maddr, AF_INET, &local_in [i]);
2467                                         if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2468                                                 addr_string = mono_string_new (domain, addr);
2469                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2470                                                 addr_index++;
2471                                         }
2472                                 }
2473                         }
2474
2475                         if (nlocal_in6) {
2476                                 MonoString *addr_string;
2477                                 int i;
2478
2479                                 for (i = 0; i < nlocal_in6; i++) {
2480                                         MonoAddress maddr;
2481                                         mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2482                                         if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2483                                                 addr_string = mono_string_new (domain, addr);
2484                                                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2485                                                 addr_index++;
2486                                         }
2487                                 }
2488                         }
2489
2490                         g_free (local_in);
2491                         g_free (local_in6);
2492                         if (info) {
2493                                 mono_free_address_info (info);
2494                         }
2495                         return TRUE;
2496                 }
2497
2498                 g_free (local_in);
2499                 g_free (local_in6);
2500         }
2501
2502         for (count = 0, ai = info->entries; ai != NULL; ai = ai->next) {
2503                 if (ai->family != AF_INET && ai->family != AF_INET6)
2504                         continue;
2505
2506                 count++;
2507         }
2508
2509         *h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
2510
2511         for (ai = info->entries, i = 0; ai != NULL; ai = ai->next) {
2512                 MonoAddress maddr;
2513                 MonoString *addr_string;
2514                 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2515
2516                 if((ai->family != PF_INET) && (ai->family != PF_INET6)) {
2517                         continue;
2518                 }
2519
2520                 mono_address_init (&maddr, ai->family, &ai->address);
2521                 if(mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer))) {
2522                         addr_string=mono_string_new(domain, buffer);
2523                 } else {
2524                         addr_string=mono_string_new(domain, "");
2525                 }
2526
2527                 mono_array_setref (*h_addr_list, addr_index, addr_string);
2528
2529                 if(!i) {
2530                         i++;
2531                         if (ai->canonical_name != NULL) {
2532                                 *h_name=mono_string_new(domain, ai->canonical_name);
2533                         } else {
2534                                 *h_name=mono_string_new(domain, buffer);
2535                         }
2536                 }
2537
2538                 addr_index++;
2539         }
2540
2541         if(info) {
2542                 mono_free_address_info (info);
2543         }
2544
2545         return(TRUE);
2546 }
2547
2548 static int
2549 get_addrinfo_family_hint (void)
2550 {
2551         switch (get_family_hint ()) {
2552         case PF_UNSPEC: return MONO_HINT_UNSPECIFIED;
2553         case PF_INET: return MONO_HINT_IPV4;
2554 #ifdef PF_INET6
2555         case PF_INET6: return MONO_HINT_IPV6;
2556 #endif
2557         default:
2558                 g_error ("invalid hint");
2559                 return 0;
2560         }
2561 }
2562
2563 MonoBoolean
2564 ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2565 {
2566         gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2567         gchar this_hostname [256];
2568         MonoAddressInfo *info = NULL;
2569         char *hostname = mono_string_to_utf8 (host);
2570         int hint = get_addrinfo_family_hint ();
2571
2572         if (*hostname == '\0') {
2573                 add_local_ips = TRUE;
2574                 *h_name = host;
2575         }
2576
2577         if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2578                 if (!strcmp (hostname, this_hostname)) {
2579                         add_local_ips = TRUE;
2580                         *h_name = host;
2581                 }
2582         }
2583
2584         if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2585                 add_info_ok = FALSE;
2586
2587         g_free(hostname);
2588
2589         if (add_info_ok)
2590                 return addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips);
2591         return FALSE;
2592 }
2593
2594 MonoBoolean
2595 ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2596 {
2597         char *address;
2598         struct sockaddr_in saddr;
2599         struct sockaddr_in6 saddr6;
2600         MonoAddressInfo *info = NULL;
2601         gint32 family;
2602         gchar hostname[NI_MAXHOST] = { 0 };
2603         gboolean ret;
2604
2605         address = mono_string_to_utf8 (addr);
2606
2607         if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2608                 family = AF_INET;
2609                 saddr.sin_family = AF_INET;
2610         } else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2611                 family = AF_INET6;
2612                 saddr6.sin6_family = AF_INET6;
2613         } else {
2614                 g_free (address);
2615                 return FALSE;
2616         }
2617
2618         g_free (address);
2619
2620         MONO_PREPARE_BLOCKING;
2621
2622         switch (family) {
2623         case AF_INET: {
2624 #if HAVE_SOCKADDR_IN_SIN_LEN
2625                 saddr.sin_len = sizeof (saddr);
2626 #endif
2627                 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr), hostname, sizeof(hostname), NULL, 0, 0) == 0;
2628                 break;
2629         }
2630         case AF_INET6: {
2631 #if HAVE_SOCKADDR_IN6_SIN_LEN
2632                 saddr6.sin6_len = sizeof (saddr6);
2633 #endif
2634                 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6), hostname, sizeof(hostname), NULL, 0, 0) == 0;
2635                 break;
2636         }
2637         default:
2638                 g_assert_not_reached ();
2639         }
2640
2641         MONO_FINISH_BLOCKING;
2642
2643         if (!ret)
2644                 return FALSE;
2645
2646         if (mono_get_address_info (hostname, 0, get_addrinfo_family_hint () | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2647                 return FALSE;
2648
2649         return addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE);
2650 }
2651
2652 MonoBoolean
2653 ves_icall_System_Net_Dns_GetHostName_internal (MonoString **h_name)
2654 {
2655         gchar hostname[NI_MAXHOST] = { 0 };
2656         int ret;
2657
2658         ret = gethostname (hostname, sizeof (hostname));
2659         if (ret == -1)
2660                 return FALSE;
2661
2662         *h_name = mono_string_new(mono_domain_get (), hostname);
2663
2664         return TRUE;
2665 }
2666
2667 gboolean
2668 ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags)
2669 {
2670         HANDLE file;
2671         gint32 error;
2672         gboolean ret;
2673         gboolean interrupted;
2674         TRANSMIT_FILE_BUFFERS buffers;
2675
2676         if (filename == NULL)
2677                 return FALSE;
2678
2679         /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2680
2681         file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, &error);
2682
2683         if (file == INVALID_HANDLE_VALUE) {
2684                 SetLastError (error);
2685                 return FALSE;
2686         }
2687
2688         memset (&buffers, 0, sizeof (buffers));
2689         if (pre_buffer != NULL) {
2690                 buffers.Head = mono_array_addr (pre_buffer, guchar, 0);
2691                 buffers.HeadLength = mono_array_length (pre_buffer);
2692         }
2693         if (post_buffer != NULL) {
2694                 buffers.Tail = mono_array_addr (post_buffer, guchar, 0);
2695                 buffers.TailLength = mono_array_length (post_buffer);
2696         }
2697
2698         mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2699         if (interrupted) {
2700                 CloseHandle (file);
2701                 SetLastError (WSAEINTR);
2702                 return FALSE;
2703         }
2704
2705         MONO_PREPARE_BLOCKING;
2706
2707         ret = TransmitFile (sock, file, 0, 0, NULL, &buffers, flags);
2708
2709         MONO_FINISH_BLOCKING;
2710
2711         mono_thread_info_uninstall_interrupt (&interrupted);
2712         if (interrupted) {
2713                 CloseHandle (file);
2714                 SetLastError (WSAEINTR);
2715                 return FALSE;
2716         }
2717
2718         MONO_PREPARE_BLOCKING;
2719
2720         CloseHandle (file);
2721
2722         MONO_FINISH_BLOCKING;
2723
2724         return ret;
2725 }
2726
2727 gboolean
2728 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (void)
2729 {
2730 #if defined (SO_REUSEPORT) || defined (HOST_WIN32)
2731     return TRUE;
2732 #else
2733     return FALSE;
2734 #endif
2735 }
2736
2737 void
2738 mono_network_init(void)
2739 {
2740         mono_networking_init ();
2741 }
2742
2743 void
2744 mono_network_cleanup(void)
2745 {
2746         _wapi_cleanup_networking ();
2747         mono_networking_shutdown ();
2748 }
2749
2750 void
2751 icall_cancel_blocking_socket_operation (MonoThread *thread)
2752 {
2753         MonoInternalThread *internal;
2754
2755         internal = thread->internal_thread;
2756         g_assert (internal);
2757
2758         mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
2759 }
2760
2761 #endif /* #ifndef DISABLE_SOCKETS */