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