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