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