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