2 * socket-io.c: Socket IO internal calls
5 * Dick Porter (dick@ximian.com)
6 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
14 #ifndef DISABLE_SOCKETS
17 #define __APPLE_USE_RFC_3542
28 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/ioctl.h>
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
37 #include <arpa/inet.h>
40 #include <mono/metadata/object.h>
41 #include <mono/io-layer/io-layer.h>
42 #include <mono/metadata/socket-io.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/assembly.h>
45 #include <mono/metadata/appdomain.h>
46 #include <mono/metadata/file-io.h>
47 #include <mono/metadata/threads.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/utils/mono-poll.h>
50 /* FIXME change this code to not mess so much with the internals */
51 #include <mono/metadata/class-internals.h>
52 #include <mono/metadata/threadpool-internals.h>
53 #include <mono/metadata/domain-internals.h>
54 #include <mono/utils/mono-threads.h>
55 #include <mono/utils/mono-memory-model.h>
58 #ifdef HAVE_SYS_TIME_H
61 #ifdef HAVE_SYS_IOCTL_H
62 #include <sys/ioctl.h>
71 #ifdef HAVE_SYS_FILIO_H
72 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
74 #ifdef HAVE_SYS_SOCKIO_H
75 #include <sys/sockio.h> /* defines SIOCATMARK */
81 #ifdef HAVE_GETIFADDRS
82 // <net/if.h> must be included before <ifaddrs.h>
86 #include "mono/io-layer/socket-wrappers.h"
88 #if defined(HOST_WIN32)
89 /* This is a kludge to make this file build under cygwin:
90 * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
91 * prototypes for some but not all required functions (notably
92 * inet_ntop() is missing), but the libws2_32 library is missing the
93 * actual implementations of these functions.
99 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
102 * Some older versions of libc provide IPV6 support without defining the AI_ADDRCONFIG
103 * flag for getaddrinfo.
105 #ifndef AI_ADDRCONFIG
106 #define AI_ADDRCONFIG 0
111 * We remove this until we have a Darwin implementation
112 * that can walk the result of struct ifconf. The current
113 * implementation only works for Linux
115 #undef HAVE_SIOCGIFCONF
118 static gint32
convert_family(MonoAddressFamily mono_family
)
122 switch(mono_family
) {
123 case AddressFamily_Unknown
:
124 case AddressFamily_ImpLink
:
125 case AddressFamily_Pup
:
126 case AddressFamily_Chaos
:
127 case AddressFamily_Iso
:
128 case AddressFamily_Ecma
:
129 case AddressFamily_DataKit
:
130 case AddressFamily_Ccitt
:
131 case AddressFamily_DataLink
:
132 case AddressFamily_Lat
:
133 case AddressFamily_HyperChannel
:
134 case AddressFamily_NetBios
:
135 case AddressFamily_VoiceView
:
136 case AddressFamily_FireFox
:
137 case AddressFamily_Banyan
:
138 case AddressFamily_Atm
:
139 case AddressFamily_Cluster
:
140 case AddressFamily_Ieee12844
:
141 case AddressFamily_NetworkDesigners
:
142 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family
);
145 case AddressFamily_Unspecified
:
149 case AddressFamily_Unix
:
153 case AddressFamily_InterNetwork
:
157 case AddressFamily_Ipx
:
163 case AddressFamily_Sna
:
169 case AddressFamily_DecNet
:
175 case AddressFamily_AppleTalk
:
179 case AddressFamily_InterNetworkV6
:
184 case AddressFamily_Irda
:
190 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family
);
196 static MonoAddressFamily
convert_to_mono_family(guint16 af_family
)
198 MonoAddressFamily family
=AddressFamily_Unknown
;
202 family
=AddressFamily_Unspecified
;
206 family
=AddressFamily_Unix
;
210 family
=AddressFamily_InterNetwork
;
215 family
=AddressFamily_Ipx
;
221 family
=AddressFamily_Sna
;
227 family
=AddressFamily_DecNet
;
232 family
=AddressFamily_AppleTalk
;
237 family
=AddressFamily_InterNetworkV6
;
243 family
=AddressFamily_Irda
;
247 g_warning("unknown address family 0x%x", af_family
);
253 static gint32
convert_type(MonoSocketType mono_type
)
258 case SocketType_Stream
:
262 case SocketType_Dgram
:
276 case SocketType_Seqpacket
:
280 case SocketType_Unknown
:
281 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type
);
285 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type
);
291 static gint32
convert_proto(MonoProtocolType mono_proto
)
296 case ProtocolType_IP
:
297 case ProtocolType_IPv6
:
298 case ProtocolType_Icmp
:
299 case ProtocolType_Igmp
:
300 case ProtocolType_Ggp
:
301 case ProtocolType_Tcp
:
302 case ProtocolType_Pup
:
303 case ProtocolType_Udp
:
304 case ProtocolType_Idp
:
305 /* These protocols are known (on my system at least) */
309 case ProtocolType_ND
:
310 case ProtocolType_Raw
:
311 case ProtocolType_Ipx
:
312 case ProtocolType_Spx
:
313 case ProtocolType_SpxII
:
314 case ProtocolType_Unknown
:
315 /* These protocols arent */
316 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto
);
326 /* Convert MonoSocketFlags */
327 static gint32
convert_socketflags (gint32 sflags
)
332 /* SocketFlags.None */
335 if (sflags
& ~(SocketFlags_OutOfBand
| SocketFlags_MaxIOVectorLength
| SocketFlags_Peek
|
336 SocketFlags_DontRoute
| SocketFlags_Partial
))
337 /* Contains invalid flag values */
340 if (sflags
& SocketFlags_OutOfBand
)
342 if (sflags
& SocketFlags_Peek
)
344 if (sflags
& SocketFlags_DontRoute
)
345 flags
|= MSG_DONTROUTE
;
347 /* Ignore Partial - see bug 349688. Don't return -1, because
348 * according to the comment in that bug ms runtime doesn't for
349 * UDP sockets (this means we will silently ignore it for TCP
353 if (sflags
& SocketFlags_Partial
)
357 /* Don't do anything for MaxIOVectorLength */
358 if (sflags
& SocketFlags_MaxIOVectorLength
)
366 * 0 on success (mapped mono_level and mono_name to system_level and system_name
368 * -2 on non-fatal error (ie, must ignore)
370 static gint32
convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level
,
371 MonoSocketOptionName mono_name
,
375 switch (mono_level
) {
376 case SocketOptionLevel_Socket
:
377 *system_level
= SOL_SOCKET
;
380 case SocketOptionName_DontLinger
:
381 /* This is SO_LINGER, because the setsockopt
382 * internal call maps DontLinger to SO_LINGER
385 *system_name
= SO_LINGER
;
387 case SocketOptionName_Debug
:
388 *system_name
= SO_DEBUG
;
391 case SocketOptionName_AcceptConnection
:
392 *system_name
= SO_ACCEPTCONN
;
395 case SocketOptionName_ReuseAddress
:
396 *system_name
= SO_REUSEADDR
;
398 case SocketOptionName_KeepAlive
:
399 *system_name
= SO_KEEPALIVE
;
401 case SocketOptionName_DontRoute
:
402 *system_name
= SO_DONTROUTE
;
404 case SocketOptionName_Broadcast
:
405 *system_name
= SO_BROADCAST
;
407 case SocketOptionName_Linger
:
408 *system_name
= SO_LINGER
;
410 case SocketOptionName_OutOfBandInline
:
411 *system_name
= SO_OOBINLINE
;
413 case SocketOptionName_SendBuffer
:
414 *system_name
= SO_SNDBUF
;
416 case SocketOptionName_ReceiveBuffer
:
417 *system_name
= SO_RCVBUF
;
419 case SocketOptionName_SendLowWater
:
420 *system_name
= SO_SNDLOWAT
;
422 case SocketOptionName_ReceiveLowWater
:
423 *system_name
= SO_RCVLOWAT
;
425 case SocketOptionName_SendTimeout
:
426 *system_name
= SO_SNDTIMEO
;
428 case SocketOptionName_ReceiveTimeout
:
429 *system_name
= SO_RCVTIMEO
;
431 case SocketOptionName_Error
:
432 *system_name
= SO_ERROR
;
434 case SocketOptionName_Type
:
435 *system_name
= SO_TYPE
;
438 case SocketOptionName_PeerCred
:
439 *system_name
= SO_PEERCRED
;
442 case SocketOptionName_ExclusiveAddressUse
:
443 #ifdef SO_EXCLUSIVEADDRUSE
444 *system_name
= SO_EXCLUSIVEADDRUSE
;
447 case SocketOptionName_UseLoopback
:
448 #ifdef SO_USELOOPBACK
449 *system_name
= SO_USELOOPBACK
;
452 case SocketOptionName_MaxConnections
:
454 *system_name
= SO_MAXCONN
;
456 #elif defined(SOMAXCONN)
457 *system_name
= SOMAXCONN
;
461 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name
);
466 case SocketOptionLevel_IP
:
468 *system_level
= SOL_IP
;
471 static int cached
= 0;
475 struct protoent
*pent
;
477 pent
= getprotobyname ("IP");
478 proto
= pent
? pent
->p_proto
: 0 /* 0 a good default value?? */;
482 *system_level
= proto
;
484 #endif /* HAVE_SOL_IP */
487 case SocketOptionName_IPOptions
:
488 *system_name
= IP_OPTIONS
;
491 case SocketOptionName_HeaderIncluded
:
492 *system_name
= IP_HDRINCL
;
496 case SocketOptionName_TypeOfService
:
497 *system_name
= IP_TOS
;
501 case SocketOptionName_IpTimeToLive
:
502 *system_name
= IP_TTL
;
505 case SocketOptionName_MulticastInterface
:
506 *system_name
= IP_MULTICAST_IF
;
508 case SocketOptionName_MulticastTimeToLive
:
509 *system_name
= IP_MULTICAST_TTL
;
511 case SocketOptionName_MulticastLoopback
:
512 *system_name
= IP_MULTICAST_LOOP
;
514 case SocketOptionName_AddMembership
:
515 *system_name
= IP_ADD_MEMBERSHIP
;
517 case SocketOptionName_DropMembership
:
518 *system_name
= IP_DROP_MEMBERSHIP
;
520 #ifdef HAVE_IP_PKTINFO
521 case SocketOptionName_PacketInformation
:
522 *system_name
= IP_PKTINFO
;
524 #endif /* HAVE_IP_PKTINFO */
526 case SocketOptionName_DontFragment
:
527 #ifdef HAVE_IP_DONTFRAGMENT
528 *system_name
= IP_DONTFRAGMENT
;
530 #elif defined HAVE_IP_MTU_DISCOVER
531 /* Not quite the same */
532 *system_name
= IP_MTU_DISCOVER
;
535 /* If the flag is not available on this system, we can ignore this error */
537 #endif /* HAVE_IP_DONTFRAGMENT */
538 case SocketOptionName_AddSourceMembership
:
539 case SocketOptionName_DropSourceMembership
:
540 case SocketOptionName_BlockSource
:
541 case SocketOptionName_UnblockSource
:
542 /* Can't figure out how to map these, so fall
546 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name
);
552 case SocketOptionLevel_IPv6
:
554 *system_level
= SOL_IPV6
;
557 static int cached
= 0;
561 struct protoent
*pent
;
563 pent
= getprotobyname ("IPV6");
564 proto
= pent
? pent
->p_proto
: 41 /* 41 a good default value?? */;
568 *system_level
= proto
;
570 #endif /* HAVE_SOL_IPV6 */
573 case SocketOptionName_IpTimeToLive
:
574 case SocketOptionName_HopLimit
:
575 *system_name
= IPV6_UNICAST_HOPS
;
577 case SocketOptionName_MulticastInterface
:
578 *system_name
= IPV6_MULTICAST_IF
;
580 case SocketOptionName_MulticastTimeToLive
:
581 *system_name
= IPV6_MULTICAST_HOPS
;
583 case SocketOptionName_MulticastLoopback
:
584 *system_name
= IPV6_MULTICAST_LOOP
;
586 case SocketOptionName_AddMembership
:
587 *system_name
= IPV6_JOIN_GROUP
;
589 case SocketOptionName_DropMembership
:
590 *system_name
= IPV6_LEAVE_GROUP
;
592 case SocketOptionName_PacketInformation
:
593 #ifdef HAVE_IPV6_PKTINFO
594 *system_name
= IPV6_PKTINFO
;
597 case SocketOptionName_HeaderIncluded
:
598 case SocketOptionName_IPOptions
:
599 case SocketOptionName_TypeOfService
:
600 case SocketOptionName_DontFragment
:
601 case SocketOptionName_AddSourceMembership
:
602 case SocketOptionName_DropSourceMembership
:
603 case SocketOptionName_BlockSource
:
604 case SocketOptionName_UnblockSource
:
605 /* Can't figure out how to map these, so fall
609 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name
);
613 break; /* SocketOptionLevel_IPv6 */
616 case SocketOptionLevel_Tcp
:
618 *system_level
= SOL_TCP
;
621 static int cached
= 0;
625 struct protoent
*pent
;
627 pent
= getprotobyname ("TCP");
628 proto
= pent
? pent
->p_proto
: 6 /* is 6 a good default value?? */;
632 *system_level
= proto
;
634 #endif /* HAVE_SOL_TCP */
637 case SocketOptionName_NoDelay
:
638 *system_name
= TCP_NODELAY
;
641 /* The documentation is talking complete
642 * bollocks here: rfc-1222 is titled
643 * 'Advancing the NSFNET Routing Architecture'
644 * and doesn't mention either of the words
645 * "expedite" or "urgent".
647 case SocketOptionName_BsdUrgent
:
648 case SocketOptionName_Expedited
:
651 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name
);
656 case SocketOptionLevel_Udp
:
657 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level
);
660 case SocketOptionName_NoChecksum
:
661 case SocketOptionName_ChecksumCoverage
:
663 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name
);
670 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level
);
677 static MonoImage
*get_socket_assembly (void)
679 MonoDomain
*domain
= mono_domain_get ();
681 if (domain
->socket_assembly
== NULL
) {
682 MonoImage
*socket_assembly
;
684 socket_assembly
= mono_image_loaded ("System");
685 if (!socket_assembly
) {
686 MonoAssembly
*sa
= mono_assembly_open ("System.dll", NULL
);
689 g_assert_not_reached ();
691 socket_assembly
= mono_assembly_get_image (sa
);
694 mono_atomic_store_release (&domain
->socket_assembly
, socket_assembly
);
697 return domain
->socket_assembly
;
701 static gint32
get_family_hint(void)
703 MonoDomain
*domain
= mono_domain_get ();
705 if (!domain
->inet_family_hint
) {
706 MonoClass
*socket_class
;
707 MonoClassField
*ipv6_field
, *ipv4_field
;
708 gint32 ipv6_enabled
= -1, ipv4_enabled
= -1;
711 socket_class
= mono_class_from_name (get_socket_assembly (), "System.Net.Sockets", "Socket");
712 ipv4_field
= mono_class_get_field_from_name (socket_class
, "ipv4Supported");
713 ipv6_field
= mono_class_get_field_from_name (socket_class
, "ipv6Supported");
714 vtable
= mono_class_vtable (mono_domain_get (), socket_class
);
716 mono_runtime_class_init (vtable
);
718 mono_field_static_get_value (vtable
, ipv4_field
, &ipv4_enabled
);
719 mono_field_static_get_value (vtable
, ipv6_field
, &ipv6_enabled
);
721 mono_domain_lock (domain
);
722 if (ipv4_enabled
== 1 && ipv6_enabled
== 1) {
723 domain
->inet_family_hint
= 1;
724 } else if (ipv4_enabled
== 1) {
725 domain
->inet_family_hint
= 2;
727 domain
->inet_family_hint
= 3;
729 mono_domain_unlock (domain
);
731 switch (domain
->inet_family_hint
) {
732 case 1: return PF_UNSPEC
;
733 case 2: return PF_INET
;
734 case 3: return PF_INET6
;
741 gpointer
ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject
*this, gint32 family
, gint32 type
, gint32 proto
, gint32
*error
)
752 sock_family
=convert_family(family
);
753 if(sock_family
==-1) {
754 *error
= WSAEAFNOSUPPORT
;
758 sock_proto
=convert_proto(proto
);
760 *error
= WSAEPROTONOSUPPORT
;
764 sock_type
=convert_type(type
);
766 *error
= WSAESOCKTNOSUPPORT
;
770 sock
= _wapi_socket (sock_family
, sock_type
, sock_proto
,
771 NULL
, 0, WSA_FLAG_OVERLAPPED
);
773 if(sock
==INVALID_SOCKET
) {
774 *error
= WSAGetLastError ();
778 if (sock_family
== AF_INET
&& sock_type
== SOCK_DGRAM
) {
779 return (GUINT_TO_POINTER (sock
));
783 if (sock_family
== AF_INET6
&& sock_type
== SOCK_DGRAM
) {
784 return (GUINT_TO_POINTER (sock
));
788 return(GUINT_TO_POINTER (sock
));
791 /* FIXME: the SOCKET parameter (here and in other functions in this
792 * file) is really an IntPtr which needs to be converted to a guint32.
794 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock
,
799 LOGDEBUG (g_message ("%s: closing 0x%x", __func__
, sock
));
803 /* Clear any pending work item from this socket if the underlying
804 * polling system does not notify when the socket is closed */
805 mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock
));
809 gint32
ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
813 LOGDEBUG (g_message("%s: returning %d", __func__
, WSAGetLastError()));
815 return(WSAGetLastError());
818 gint32
ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock
,
828 /* FIXME: this might require amount to be unsigned long. */
829 ret
=ioctlsocket(sock
, FIONREAD
, &amount
);
830 if(ret
==SOCKET_ERROR
) {
831 *error
= WSAGetLastError ();
838 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock
,
849 * block == TRUE/FALSE means we will block/not block.
850 * But the ioctlsocket call takes TRUE/FALSE for non-block/block
854 ret
= ioctlsocket (sock
, FIONBIO
, (gulong
*) &block
);
855 if(ret
==SOCKET_ERROR
) {
856 *error
= WSAGetLastError ();
860 gpointer
ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock
,
871 MonoInternalThread
* curthread
= mono_thread_internal_current ();
872 curthread
->interrupt_on_stop
= (gpointer
)TRUE
;
873 newsock
= _wapi_accept (sock
, NULL
, 0);
874 curthread
->interrupt_on_stop
= (gpointer
)FALSE
;
877 newsock
= _wapi_accept (sock
, NULL
, 0);
879 if(newsock
==INVALID_SOCKET
) {
880 *error
= WSAGetLastError ();
884 return(GUINT_TO_POINTER (newsock
));
887 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock
,
897 ret
= _wapi_listen (sock
, backlog
);
898 if(ret
==SOCKET_ERROR
) {
899 *error
= WSAGetLastError ();
904 // Check whether it's ::ffff::0:0.
906 is_ipv4_mapped_any (const struct in6_addr
*addr
)
910 for (i
= 0; i
< 10; i
++) {
911 if (addr
->s6_addr
[i
])
914 if ((addr
->s6_addr
[10] != 0xff) || (addr
->s6_addr
[11] != 0xff))
916 for (i
= 12; i
< 16; i
++) {
917 if (addr
->s6_addr
[i
])
924 static MonoObject
*create_object_from_sockaddr(struct sockaddr
*saddr
,
925 int sa_size
, gint32
*error
)
927 MonoDomain
*domain
= mono_domain_get ();
928 MonoObject
*sockaddr_obj
;
930 MonoAddressFamily family
;
932 /* Build a System.Net.SocketAddress object instance */
933 if (!domain
->sockaddr_class
) {
934 domain
->sockaddr_class
=mono_class_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
935 g_assert (domain
->sockaddr_class
);
937 sockaddr_obj
=mono_object_new(domain
, domain
->sockaddr_class
);
939 /* Locate the SocketAddress data buffer in the object */
940 if (!domain
->sockaddr_data_field
) {
941 domain
->sockaddr_data_field
=mono_class_get_field_from_name (domain
->sockaddr_class
, "data");
942 g_assert (domain
->sockaddr_data_field
);
945 /* May be the +2 here is too conservative, as sa_len returns
946 * the length of the entire sockaddr_in/in6, including
947 * sizeof (unsigned short) of the family */
948 /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
949 data
=mono_array_new_cached(domain
, mono_get_byte_class (), sa_size
+2);
951 /* The data buffer is laid out as follows:
952 * bytes 0 and 1 are the address family
953 * bytes 2 and 3 are the port info
954 * the rest is the address info
957 family
=convert_to_mono_family(saddr
->sa_family
);
958 if(family
==AddressFamily_Unknown
) {
959 *error
= WSAEAFNOSUPPORT
;
963 mono_array_set(data
, guint8
, 0, family
& 0x0FF);
964 mono_array_set(data
, guint8
, 1, (family
>> 8) & 0x0FF);
966 if(saddr
->sa_family
==AF_INET
) {
967 struct sockaddr_in
*sa_in
=(struct sockaddr_in
*)saddr
;
968 guint16 port
=ntohs(sa_in
->sin_port
);
969 guint32 address
=ntohl(sa_in
->sin_addr
.s_addr
);
972 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
975 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
976 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
977 mono_array_set(data
, guint8
, 4, (address
>>24) & 0xff);
978 mono_array_set(data
, guint8
, 5, (address
>>16) & 0xff);
979 mono_array_set(data
, guint8
, 6, (address
>>8) & 0xff);
980 mono_array_set(data
, guint8
, 7, (address
) & 0xff);
982 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
984 return(sockaddr_obj
);
986 } else if (saddr
->sa_family
== AF_INET6
) {
987 struct sockaddr_in6
*sa_in
=(struct sockaddr_in6
*)saddr
;
990 guint16 port
=ntohs(sa_in
->sin6_port
);
993 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
996 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
997 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
999 if (is_ipv4_mapped_any (&sa_in
->sin6_addr
)) {
1000 // Map ::ffff:0:0 to :: (bug #5502)
1001 for(i
=0; i
<16; i
++) {
1002 mono_array_set(data
, guint8
, 8+i
, 0);
1005 for(i
=0; i
<16; i
++) {
1006 mono_array_set(data
, guint8
, 8+i
,
1007 sa_in
->sin6_addr
.s6_addr
[i
]);
1011 mono_array_set(data
, guint8
, 24, sa_in
->sin6_scope_id
& 0xff);
1012 mono_array_set(data
, guint8
, 25,
1013 (sa_in
->sin6_scope_id
>> 8) & 0xff);
1014 mono_array_set(data
, guint8
, 26,
1015 (sa_in
->sin6_scope_id
>> 16) & 0xff);
1016 mono_array_set(data
, guint8
, 27,
1017 (sa_in
->sin6_scope_id
>> 24) & 0xff);
1019 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
1021 return(sockaddr_obj
);
1023 #ifdef HAVE_SYS_UN_H
1024 } else if (saddr
->sa_family
== AF_UNIX
) {
1027 for (i
= 0; i
< sa_size
; i
++) {
1028 mono_array_set (data
, guint8
, i
+2, saddr
->sa_data
[i
]);
1031 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
1033 return sockaddr_obj
;
1036 *error
= WSAEAFNOSUPPORT
;
1042 get_sockaddr_size (int family
)
1047 if (family
== AF_INET
) {
1048 size
= sizeof (struct sockaddr_in
);
1050 } else if (family
== AF_INET6
) {
1051 size
= sizeof (struct sockaddr_in6
);
1053 #ifdef HAVE_SYS_UN_H
1054 } else if (family
== AF_UNIX
) {
1055 size
= sizeof (struct sockaddr_un
);
1061 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock
, gint32 af
, gint32
*error
)
1068 MONO_ARCH_SAVE_REGS
;
1072 salen
= get_sockaddr_size (convert_family (af
));
1074 *error
= WSAEAFNOSUPPORT
;
1077 sa
= (salen
<= 128) ? alloca (salen
) : g_malloc0 (salen
);
1078 ret
= _wapi_getsockname (sock
, (struct sockaddr
*)sa
, &salen
);
1080 if(ret
==SOCKET_ERROR
) {
1081 *error
= WSAGetLastError ();
1087 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
)));
1089 result
= create_object_from_sockaddr((struct sockaddr
*)sa
, salen
, error
);
1095 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock
, gint32 af
, gint32
*error
)
1102 MONO_ARCH_SAVE_REGS
;
1106 salen
= get_sockaddr_size (convert_family (af
));
1108 *error
= WSAEAFNOSUPPORT
;
1111 sa
= (salen
<= 128) ? alloca (salen
) : g_malloc0 (salen
);
1112 /* Note: linux returns just 2 for AF_UNIX. Always. */
1113 ret
= _wapi_getpeername (sock
, (struct sockaddr
*)sa
, &salen
);
1114 if(ret
==SOCKET_ERROR
) {
1115 *error
= WSAGetLastError ();
1121 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
)));
1123 result
= create_object_from_sockaddr((struct sockaddr
*)sa
, salen
, error
);
1129 static struct sockaddr
*create_sockaddr_from_object(MonoObject
*saddr_obj
,
1133 MonoClassField
*field
;
1138 /* Dig the SocketAddress data buffer out of the object */
1139 field
=mono_class_get_field_from_name(saddr_obj
->vtable
->klass
, "data");
1140 data
=*(MonoArray
**)(((char *)saddr_obj
) + field
->offset
);
1142 /* The data buffer is laid out as follows:
1143 * byte 0 is the address family low byte
1144 * byte 1 is the address family high byte
1146 * bytes 2 and 3 are the port info
1147 * the rest is the address info
1149 * the rest is the file name
1151 len
= mono_array_length (data
);
1153 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1156 family
= convert_family (mono_array_get (data
, guint8
, 0) + (mono_array_get (data
, guint8
, 1) << 8));
1157 if (family
== AF_INET
) {
1158 struct sockaddr_in
*sa
;
1163 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1166 sa
= g_new0 (struct sockaddr_in
, 1);
1167 port
= (mono_array_get (data
, guint8
, 2) << 8) +
1168 mono_array_get (data
, guint8
, 3);
1169 address
= (mono_array_get (data
, guint8
, 4) << 24) +
1170 (mono_array_get (data
, guint8
, 5) << 16 ) +
1171 (mono_array_get (data
, guint8
, 6) << 8) +
1172 mono_array_get (data
, guint8
, 7);
1174 sa
->sin_family
= family
;
1175 sa
->sin_addr
.s_addr
= htonl (address
);
1176 sa
->sin_port
= htons (port
);
1178 *sa_size
= sizeof(struct sockaddr_in
);
1179 return((struct sockaddr
*)sa
);
1182 } else if (family
== AF_INET6
) {
1183 struct sockaddr_in6
*sa
;
1189 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1192 sa
= g_new0 (struct sockaddr_in6
, 1);
1193 port
= mono_array_get (data
, guint8
, 3) +
1194 (mono_array_get (data
, guint8
, 2) << 8);
1195 scopeid
= mono_array_get (data
, guint8
, 24) +
1196 (mono_array_get (data
, guint8
, 25) << 8) +
1197 (mono_array_get (data
, guint8
, 26) << 16) +
1198 (mono_array_get (data
, guint8
, 27) << 24);
1200 sa
->sin6_family
= family
;
1201 sa
->sin6_port
= htons (port
);
1202 sa
->sin6_scope_id
= scopeid
;
1204 for(i
=0; i
<16; i
++) {
1205 sa
->sin6_addr
.s6_addr
[i
] = mono_array_get (data
, guint8
, 8+i
);
1208 *sa_size
= sizeof(struct sockaddr_in6
);
1209 return((struct sockaddr
*)sa
);
1211 #ifdef HAVE_SYS_UN_H
1212 } else if (family
== AF_UNIX
) {
1213 struct sockaddr_un
*sock_un
;
1216 /* Need a byte for the '\0' terminator/prefix, and the first
1217 * two bytes hold the SocketAddress family
1219 if (len
- 2 >= sizeof(sock_un
->sun_path
)) {
1220 mono_raise_exception (mono_get_exception_index_out_of_range ());
1223 sock_un
= g_new0 (struct sockaddr_un
, 1);
1225 sock_un
->sun_family
= family
;
1226 for (i
= 0; i
< len
- 2; i
++) {
1227 sock_un
->sun_path
[i
] = mono_array_get (data
, guint8
,
1233 return (struct sockaddr
*)sock_un
;
1236 *error
= WSAEAFNOSUPPORT
;
1241 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1243 struct sockaddr
*sa
;
1247 MONO_ARCH_SAVE_REGS
;
1251 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1256 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
)));
1258 ret
= _wapi_bind (sock
, sa
, sa_size
);
1259 if(ret
==SOCKET_ERROR
) {
1260 *error
= WSAGetLastError ();
1273 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock
, gint mode
,
1274 gint timeout
, gint32
*error
)
1276 MonoInternalThread
*thread
= NULL
;
1282 MONO_ARCH_SAVE_REGS
;
1284 pfds
= g_new0 (mono_pollfd
, 1);
1285 pfds
[0].fd
= GPOINTER_TO_INT (sock
);
1286 pfds
[0].events
= (mode
== SelectModeRead
) ? MONO_POLLIN
:
1287 (mode
== SelectModeWrite
) ? MONO_POLLOUT
:
1288 (MONO_POLLERR
| MONO_POLLHUP
| MONO_POLLNVAL
);
1290 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1291 start
= time (NULL
);
1295 ret
= mono_poll (pfds
, 1, timeout
);
1296 if (timeout
> 0 && ret
< 0) {
1298 int sec
= time (NULL
) - start
;
1300 timeout
-= sec
* 1000;
1308 if (ret
== -1 && errno
== EINTR
) {
1311 if (thread
== NULL
) {
1312 thread
= mono_thread_internal_current ();
1315 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1321 /* Suspend requested? */
1322 mono_thread_interruption_checkpoint ();
1326 } while (ret
== -1 && errno
== EINTR
);
1330 *error
= WSAGetLastError ();
1332 *error
= errno_to_WSA (errno
, __func__
);
1347 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1349 struct sockaddr
*sa
;
1353 MONO_ARCH_SAVE_REGS
;
1357 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1362 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
)));
1364 ret
= _wapi_connect (sock
, sa
, sa_size
);
1365 if(ret
==SOCKET_ERROR
) {
1366 *error
= WSAGetLastError ();
1372 /* These #defines from mswsock.h from wine. Defining them here allows
1373 * us to build this file on a mingw box that doesn't know the magic
1374 * numbers, but still run on a newer windows box that does.
1376 #ifndef WSAID_DISCONNECTEX
1377 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1378 typedef BOOL (WINAPI
*LPFN_DISCONNECTEX
)(SOCKET
, LPOVERLAPPED
, DWORD
, DWORD
);
1381 #ifndef WSAID_TRANSMITFILE
1382 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1383 typedef BOOL (WINAPI
*LPFN_TRANSMITFILE
)(SOCKET
, HANDLE
, DWORD
, DWORD
, LPOVERLAPPED
, LPTRANSMIT_FILE_BUFFERS
, DWORD
);
1386 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock
, MonoBoolean reuse
, gint32
*error
)
1389 glong output_bytes
= 0;
1390 GUID disco_guid
= WSAID_DISCONNECTEX
;
1391 GUID trans_guid
= WSAID_TRANSMITFILE
;
1392 LPFN_DISCONNECTEX _wapi_disconnectex
= NULL
;
1393 LPFN_TRANSMITFILE _wapi_transmitfile
= NULL
;
1396 MONO_ARCH_SAVE_REGS
;
1400 LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__
, sock
, reuse
));
1402 /* I _think_ the extension function pointers need to be looked
1403 * up for each socket. FIXME: check the best way to store
1404 * pointers to functions in managed objects that still works
1405 * on 64bit platforms.
1407 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1408 (void *)&disco_guid
, sizeof(GUID
),
1409 (void *)&_wapi_disconnectex
, sizeof(void *),
1410 &output_bytes
, NULL
, NULL
);
1412 /* make sure that WSAIoctl didn't put crap in the
1415 _wapi_disconnectex
= NULL
;
1418 * Use the SIO_GET_EXTENSION_FUNCTION_POINTER to
1419 * determine the address of the disconnect method without
1420 * taking a hard dependency on a single provider
1422 * For an explanation of why this is done, you can read
1423 * the article at http://www.codeproject.com/internet/jbsocketserver3.asp
1425 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1426 (void *)&trans_guid
, sizeof(GUID
),
1427 (void *)&_wapi_transmitfile
, sizeof(void *),
1428 &output_bytes
, NULL
, NULL
);
1430 _wapi_transmitfile
= NULL
;
1434 if (_wapi_disconnectex
!= NULL
) {
1435 bret
= _wapi_disconnectex (sock
, NULL
, TF_REUSE_SOCKET
, 0);
1436 } else if (_wapi_transmitfile
!= NULL
) {
1437 bret
= _wapi_transmitfile (sock
, NULL
, 0, 0, NULL
, NULL
,
1438 TF_DISCONNECT
| TF_REUSE_SOCKET
);
1440 *error
= ERROR_NOT_SUPPORTED
;
1444 if (bret
== FALSE
) {
1445 *error
= WSAGetLastError ();
1449 gint32
ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1456 MONO_ARCH_SAVE_REGS
;
1460 alen
= mono_array_length (buffer
);
1461 if (offset
> alen
- count
) {
1465 buf
=mono_array_addr(buffer
, guchar
, offset
);
1467 recvflags
= convert_socketflags (flags
);
1468 if (recvflags
== -1) {
1469 *error
= WSAEOPNOTSUPP
;
1475 MonoInternalThread
* curthread
= mono_thread_internal_current ();
1476 curthread
->interrupt_on_stop
= (gpointer
)TRUE
;
1477 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1478 curthread
->interrupt_on_stop
= (gpointer
)FALSE
;
1481 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1484 if(ret
==SOCKET_ERROR
) {
1485 *error
= WSAGetLastError ();
1492 gint32
ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1497 DWORD recvflags
= 0;
1499 MONO_ARCH_SAVE_REGS
;
1503 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1504 count
= mono_array_length (buffers
);
1506 recvflags
= convert_socketflags (flags
);
1507 if (recvflags
== -1) {
1508 *error
= WSAEOPNOTSUPP
;
1512 ret
= WSARecv (sock
, wsabufs
, count
, &recv
, &recvflags
, NULL
, NULL
);
1513 if (ret
== SOCKET_ERROR
) {
1514 *error
= WSAGetLastError ();
1521 gint32
ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
**sockaddr
, gint32
*error
)
1527 struct sockaddr
*sa
;
1530 MONO_ARCH_SAVE_REGS
;
1534 alen
= mono_array_length (buffer
);
1535 if (offset
> alen
- count
) {
1539 sa
=create_sockaddr_from_object(*sockaddr
, &sa_size
, error
);
1544 buf
=mono_array_addr(buffer
, guchar
, offset
);
1546 recvflags
= convert_socketflags (flags
);
1547 if (recvflags
== -1) {
1548 *error
= WSAEOPNOTSUPP
;
1552 ret
= _wapi_recvfrom (sock
, buf
, count
, recvflags
, sa
, &sa_size
);
1553 if(ret
==SOCKET_ERROR
) {
1555 *error
= WSAGetLastError ();
1559 /* If we didn't get a socket size, then we're probably a
1560 * connected connection-oriented socket and the stack hasn't
1561 * returned the remote address. All we can do is return null.
1564 *sockaddr
=create_object_from_sockaddr(sa
, sa_size
, error
);
1573 gint32
ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1580 MONO_ARCH_SAVE_REGS
;
1584 alen
= mono_array_length (buffer
);
1585 if (offset
> alen
- count
) {
1589 LOGDEBUG (g_message("%s: alen: %d", __func__
, alen
));
1591 buf
=mono_array_addr(buffer
, guchar
, offset
);
1593 LOGDEBUG (g_message("%s: Sending %d bytes", __func__
, count
));
1595 sendflags
= convert_socketflags (flags
);
1596 if (sendflags
== -1) {
1597 *error
= WSAEOPNOTSUPP
;
1601 ret
= _wapi_send (sock
, buf
, count
, sendflags
);
1602 if(ret
==SOCKET_ERROR
) {
1603 *error
= WSAGetLastError ();
1610 gint32
ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1615 DWORD sendflags
= 0;
1617 MONO_ARCH_SAVE_REGS
;
1621 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1622 count
= mono_array_length (buffers
);
1624 sendflags
= convert_socketflags (flags
);
1625 if (sendflags
== -1) {
1626 *error
= WSAEOPNOTSUPP
;
1630 ret
= WSASend (sock
, wsabufs
, count
, &sent
, sendflags
, NULL
, NULL
);
1631 if (ret
== SOCKET_ERROR
) {
1632 *error
= WSAGetLastError ();
1639 gint32
ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
*sockaddr
, gint32
*error
)
1645 struct sockaddr
*sa
;
1648 MONO_ARCH_SAVE_REGS
;
1652 alen
= mono_array_length (buffer
);
1653 if (offset
> alen
- count
) {
1657 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1662 LOGDEBUG (g_message("%s: alen: %d", __func__
, alen
));
1664 buf
=mono_array_addr(buffer
, guchar
, offset
);
1666 LOGDEBUG (g_message("%s: Sending %d bytes", __func__
, count
));
1668 sendflags
= convert_socketflags (flags
);
1669 if (sendflags
== -1) {
1670 *error
= WSAEOPNOTSUPP
;
1674 ret
= _wapi_sendto (sock
, buf
, count
, sendflags
, sa
, sa_size
);
1675 if(ret
==SOCKET_ERROR
) {
1676 *error
= WSAGetLastError ();
1684 static SOCKET
Socket_to_SOCKET(MonoObject
*sockobj
)
1687 MonoClassField
*field
;
1689 field
=mono_class_get_field_from_name(sockobj
->vtable
->klass
, "socket");
1690 sock
=GPOINTER_TO_INT (*(gpointer
*)(((char *)sockobj
)+field
->offset
));
1695 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1696 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray
**sockets
, gint32 timeout
, gint32
*error
)
1698 MonoInternalThread
*thread
= NULL
;
1705 MonoClass
*sock_arr_class
;
1708 uintptr_t socks_size
;
1710 MONO_ARCH_SAVE_REGS
;
1712 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1713 count
= mono_array_length (*sockets
);
1714 nfds
= count
- 3; /* NULL separators */
1715 pfds
= g_new0 (mono_pollfd
, nfds
);
1717 for (i
= 0; i
< count
; i
++) {
1718 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1725 /* The socket array was bogus */
1731 pfds
[idx
].fd
= Socket_to_SOCKET (obj
);
1732 pfds
[idx
].events
= (mode
== 0) ? MONO_POLLIN
: (mode
== 1) ? MONO_POLLOUT
: POLL_ERRORS
;
1736 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1737 start
= time (NULL
);
1740 ret
= mono_poll (pfds
, nfds
, timeout
);
1741 if (timeout
> 0 && ret
< 0) {
1743 int sec
= time (NULL
) - start
;
1745 timeout
-= sec
* 1000;
1751 if (ret
== -1 && errno
== EINTR
) {
1754 thread
= mono_thread_internal_current ();
1756 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1763 /* Suspend requested? */
1764 mono_thread_interruption_checkpoint ();
1768 } while (ret
== -1 && errno
== EINTR
);
1772 *error
= WSAGetLastError ();
1774 *error
= errno_to_WSA (errno
, __func__
);
1786 sock_arr_class
= ((MonoObject
*)*sockets
)->vtable
->klass
;
1787 socks_size
= ((uintptr_t)ret
) + 3; /* space for the NULL delimiters */
1788 socks
= mono_array_new_full (mono_domain_get (), sock_arr_class
, &socks_size
, NULL
);
1791 for (i
= 0; i
< count
&& ret
> 0; i
++) {
1794 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1801 pfd
= &pfds
[i
- mode
];
1802 if (pfd
->revents
== 0)
1806 if (mode
== 0 && (pfd
->revents
& (MONO_POLLIN
| POLL_ERRORS
)) != 0) {
1807 mono_array_setref (socks
, idx
++, obj
);
1808 } else if (mode
== 1 && (pfd
->revents
& (MONO_POLLOUT
| POLL_ERRORS
)) != 0) {
1809 mono_array_setref (socks
, idx
++, obj
);
1810 } else if ((pfd
->revents
& POLL_ERRORS
) != 0) {
1811 mono_array_setref (socks
, idx
++, obj
);
1819 static MonoObject
* int_to_object (MonoDomain
*domain
, int val
)
1821 return mono_value_box (domain
, mono_get_int32_class (), &val
);
1825 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoObject
**obj_val
, gint32
*error
)
1827 int system_level
= 0;
1828 int system_name
= 0;
1831 socklen_t valsize
=sizeof(val
);
1832 struct linger linger
;
1833 socklen_t lingersize
=sizeof(linger
);
1835 socklen_t time_ms_size
= sizeof (time_ms
);
1837 # if defined(__OpenBSD__)
1838 struct sockpeercred cred
;
1842 socklen_t credsize
= sizeof(cred
);
1844 MonoDomain
*domain
=mono_domain_get();
1846 MonoClass
*obj_class
;
1847 MonoClassField
*field
;
1849 MONO_ARCH_SAVE_REGS
;
1853 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1854 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
) {
1855 system_level
= SOL_SOCKET
;
1856 system_name
= SO_REUSEADDR
;
1862 ret
= convert_sockopt_level_and_name (level
, name
, &system_level
, &system_name
);
1866 *error
= WSAENOPROTOOPT
;
1870 *obj_val
= int_to_object (domain
, 0);
1874 /* No need to deal with MulticastOption names here, because
1875 * you cant getsockopt AddMembership or DropMembership (the
1876 * int getsockopt will error, causing an exception)
1879 case SocketOptionName_Linger
:
1880 case SocketOptionName_DontLinger
:
1881 ret
= _wapi_getsockopt(sock
, system_level
, system_name
, &linger
,
1885 case SocketOptionName_SendTimeout
:
1886 case SocketOptionName_ReceiveTimeout
:
1887 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, (char *) &time_ms
, &time_ms_size
);
1891 case SocketOptionName_PeerCred
:
1892 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &cred
,
1898 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &val
,
1902 if(ret
==SOCKET_ERROR
) {
1903 *error
= WSAGetLastError ();
1908 case SocketOptionName_Linger
:
1909 /* build a System.Net.Sockets.LingerOption */
1910 obj_class
=mono_class_from_name(get_socket_assembly (),
1911 "System.Net.Sockets",
1913 obj
=mono_object_new(domain
, obj_class
);
1915 /* Locate and set the fields "bool enabled" and "int
1918 field
=mono_class_get_field_from_name(obj_class
, "enabled");
1919 *(guint8
*)(((char *)obj
)+field
->offset
)=linger
.l_onoff
;
1921 field
=mono_class_get_field_from_name(obj_class
, "seconds");
1922 *(guint32
*)(((char *)obj
)+field
->offset
)=linger
.l_linger
;
1926 case SocketOptionName_DontLinger
:
1927 /* construct a bool int in val - true if linger is off */
1928 obj
= int_to_object (domain
, !linger
.l_onoff
);
1931 case SocketOptionName_SendTimeout
:
1932 case SocketOptionName_ReceiveTimeout
:
1933 obj
= int_to_object (domain
, time_ms
);
1937 case SocketOptionName_PeerCred
:
1939 /* build a Mono.Posix.PeerCred+PeerCredData if
1942 static MonoImage
*mono_posix_image
= NULL
;
1943 MonoPeerCredData
*cred_data
;
1945 if (mono_posix_image
== NULL
) {
1946 mono_posix_image
=mono_image_loaded ("Mono.Posix");
1947 if (!mono_posix_image
) {
1948 MonoAssembly
*sa
= mono_assembly_open ("Mono.Posix.dll", NULL
);
1950 *error
= WSAENOPROTOOPT
;
1953 mono_posix_image
= mono_assembly_get_image (sa
);
1958 obj_class
= mono_class_from_name(mono_posix_image
,
1961 obj
= mono_object_new(domain
, obj_class
);
1962 cred_data
= (MonoPeerCredData
*)obj
;
1963 cred_data
->pid
= cred
.pid
;
1964 cred_data
->uid
= cred
.uid
;
1965 cred_data
->gid
= cred
.gid
;
1971 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1972 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
)
1975 obj
= int_to_object (domain
, val
);
1980 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoArray
**byte_val
, gint32
*error
)
1982 int system_level
= 0;
1983 int system_name
= 0;
1988 MONO_ARCH_SAVE_REGS
;
1992 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1995 *error
= WSAENOPROTOOPT
;
2001 valsize
=mono_array_length(*byte_val
);
2002 buf
=mono_array_addr(*byte_val
, guchar
, 0);
2004 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, buf
, &valsize
);
2005 if(ret
==SOCKET_ERROR
) {
2006 *error
= WSAGetLastError ();
2010 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2011 static struct in_addr
ipaddress_to_struct_in_addr(MonoObject
*ipaddr
)
2013 struct in_addr inaddr
;
2014 MonoClassField
*field
;
2016 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Address");
2018 /* No idea why .net uses a 64bit type to hold a 32bit value...
2020 * Internal value of IPAddess is in little-endian order
2022 inaddr
.s_addr
=GUINT_FROM_LE ((guint32
)*(guint64
*)(((char *)ipaddr
)+field
->offset
));
2028 static struct in6_addr
ipaddress_to_struct_in6_addr(MonoObject
*ipaddr
)
2030 struct in6_addr in6addr
;
2031 MonoClassField
*field
;
2035 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Numbers");
2036 data
=*(MonoArray
**)(((char *)ipaddr
) + field
->offset
);
2038 /* Solaris has only the 8 bit version. */
2040 for(i
=0; i
<8; i
++) {
2041 guint16 s
= mono_array_get (data
, guint16
, i
);
2042 in6addr
.s6_addr
[2 * i
+ 1] = (s
>> 8) & 0xff;
2043 in6addr
.s6_addr
[2 * i
] = s
& 0xff;
2047 in6addr
.s6_addr16
[i
] = mono_array_get (data
, guint16
, i
);
2051 #endif /* AF_INET6 */
2054 #if defined(__APPLE__)
2056 #if defined(HAVE_GETIFADDRS) && defined(HAVE_IF_NAMETOINDEX)
2058 get_local_interface_id (int family
)
2060 struct ifaddrs
*ifap
= NULL
, *ptr
;
2063 if (getifaddrs (&ifap
)) {
2067 for (ptr
= ifap
; ptr
; ptr
= ptr
->ifa_next
) {
2068 if (!ptr
->ifa_addr
|| !ptr
->ifa_name
)
2070 if (ptr
->ifa_addr
->sa_family
!= family
)
2072 if ((ptr
->ifa_flags
& IFF_LOOPBACK
) != 0)
2074 if ((ptr
->ifa_flags
& IFF_MULTICAST
) == 0)
2077 idx
= if_nametoindex (ptr
->ifa_name
);
2086 get_local_interface_id (int family
)
2092 #endif /* __APPLE__ */
2094 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
)
2096 struct linger linger
;
2097 int system_level
= 0;
2098 int system_name
= 0;
2106 #ifdef HAVE_SOL_IPV6
2107 sol_ipv6
= SOL_IPV6
;
2110 struct protoent
*pent
;
2111 pent
= getprotobyname ("ipv6");
2112 sol_ipv6
= (pent
!= NULL
) ? pent
->p_proto
: 41;
2120 struct protoent
*pent
;
2121 pent
= getprotobyname ("ip");
2122 sol_ip
= (pent
!= NULL
) ? pent
->p_proto
: 0;
2125 #endif /* AF_INET6 */
2127 MONO_ARCH_SAVE_REGS
;
2129 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
2132 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2133 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
) {
2134 system_name
= SO_REUSEADDR
;
2135 int_val
= int_val
? 0 : 1;
2141 *error
= WSAENOPROTOOPT
;
2148 /* Only one of obj_val, byte_val or int_val has data */
2150 MonoClassField
*field
;
2154 case SocketOptionName_Linger
:
2155 /* Dig out "bool enabled" and "int seconds"
2158 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "enabled");
2159 linger
.l_onoff
=*(guint8
*)(((char *)obj_val
)+field
->offset
);
2160 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "seconds");
2161 linger
.l_linger
=*(guint32
*)(((char *)obj_val
)+field
->offset
);
2163 valsize
=sizeof(linger
);
2164 ret
= _wapi_setsockopt (sock
, system_level
,
2165 system_name
, &linger
, valsize
);
2167 case SocketOptionName_AddMembership
:
2168 case SocketOptionName_DropMembership
:
2169 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2171 MonoObject
*address
= NULL
;
2174 if(system_level
== sol_ipv6
) {
2175 struct ipv6_mreq mreq6
;
2180 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2181 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2184 mreq6
.ipv6mr_multiaddr
= ipaddress_to_struct_in6_addr (address
);
2187 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "ifIndex");
2188 mreq6
.ipv6mr_interface
=*(guint64
*)(((char *)obj_val
)+field
->offset
);
2190 #if defined(__APPLE__)
2194 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2196 * Tests on Windows and Linux show that the multicast group is only
2197 * joined on one NIC when interface = 0, so we simply use the interface
2198 * id from the first non-loopback interface (this is also what
2199 * Dns.GetHostName (string.Empty) would return).
2201 if (!mreq6
.ipv6mr_interface
)
2202 mreq6
.ipv6mr_interface
= get_local_interface_id (AF_INET6
);
2205 ret
= _wapi_setsockopt (sock
, system_level
,
2206 system_name
, &mreq6
,
2208 } else if(system_level
== sol_ip
)
2209 #endif /* AF_INET6 */
2211 #ifdef HAVE_STRUCT_IP_MREQN
2212 struct ip_mreqn mreq
= {{0}};
2214 struct ip_mreq mreq
= {{0}};
2215 #endif /* HAVE_STRUCT_IP_MREQN */
2217 /* pain! MulticastOption holds two IPAddress
2218 * members, so I have to dig the value out of
2221 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2222 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2224 /* address might not be defined and if so, set the address to ADDR_ANY.
2227 mreq
.imr_multiaddr
= ipaddress_to_struct_in_addr (address
);
2230 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "local");
2231 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2233 #ifdef HAVE_STRUCT_IP_MREQN
2235 mreq
.imr_address
= ipaddress_to_struct_in_addr (address
);
2238 field
= mono_class_get_field_from_name(obj_val
->vtable
->klass
, "iface_index");
2239 mreq
.imr_ifindex
= *(gint32
*)(((char *)obj_val
)+field
->offset
);
2242 mreq
.imr_interface
= ipaddress_to_struct_in_addr (address
);
2244 #endif /* HAVE_STRUCT_IP_MREQN */
2246 ret
= _wapi_setsockopt (sock
, system_level
,
2252 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2254 /* Cause an exception to be thrown */
2258 } else if (byte_val
!=NULL
) {
2259 int valsize
= mono_array_length (byte_val
);
2260 guchar
*buf
= mono_array_addr (byte_val
, guchar
, 0);
2263 case SocketOptionName_DontLinger
:
2265 linger
.l_onoff
= (*buf
) ? 0 : 1;
2266 linger
.l_linger
= 0;
2267 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &linger
, sizeof (linger
));
2273 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, buf
, valsize
);
2277 /* ReceiveTimeout/SendTimeout get here */
2279 case SocketOptionName_DontLinger
:
2280 linger
.l_onoff
= !int_val
;
2281 linger
.l_linger
= 0;
2282 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &linger
, sizeof (linger
));
2284 case SocketOptionName_MulticastInterface
:
2286 #ifdef HAVE_STRUCT_IP_MREQN
2287 int_val
= GUINT32_FROM_BE (int_val
);
2288 if ((int_val
& 0xff000000) == 0) {
2289 /* int_val is interface index */
2290 struct ip_mreqn mreq
= {{0}};
2291 mreq
.imr_ifindex
= int_val
;
2292 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &mreq
, sizeof (mreq
));
2295 int_val
= GUINT32_TO_BE (int_val
);
2296 #endif /* HAVE_STRUCT_IP_MREQN */
2297 #endif /* HOST_WIN32 */
2298 /* int_val is in_addr */
2299 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &int_val
, sizeof (int_val
));
2301 case SocketOptionName_DontFragment
:
2302 #ifdef HAVE_IP_MTU_DISCOVER
2303 /* Fiddle with the value slightly if we're
2307 int_val
= IP_PMTUDISC_DO
;
2313 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &int_val
, sizeof (int_val
));
2317 if(ret
==SOCKET_ERROR
) {
2318 *error
= WSAGetLastError ();
2322 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock
,
2328 MONO_ARCH_SAVE_REGS
;
2332 /* Currently, the values for how (recv=0, send=1, both=2) match
2335 ret
= _wapi_shutdown (sock
, how
);
2336 if(ret
==SOCKET_ERROR
) {
2337 *error
= WSAGetLastError ();
2342 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock
, gint32 code
,
2344 MonoArray
*output
, gint32
*error
)
2346 glong output_bytes
= 0;
2347 gchar
*i_buffer
, *o_buffer
;
2351 MONO_ARCH_SAVE_REGS
;
2355 if ((guint32
)code
== FIONBIO
) {
2356 /* Invalid command. Must use Socket.Blocking */
2360 if (input
== NULL
) {
2364 i_buffer
= mono_array_addr (input
, gchar
, 0);
2365 i_len
= mono_array_length (input
);
2368 if (output
== NULL
) {
2372 o_buffer
= mono_array_addr (output
, gchar
, 0);
2373 o_len
= mono_array_length (output
);
2376 ret
= WSAIoctl (sock
, code
, i_buffer
, i_len
, o_buffer
, o_len
, &output_bytes
, NULL
, NULL
);
2377 if (ret
== SOCKET_ERROR
) {
2378 *error
= WSAGetLastError ();
2382 return (gint
) output_bytes
;
2385 #ifdef HAVE_SIOCGIFCONF
2387 is_loopback (int family
, void *ad
)
2389 char *ptr
= (char *) ad
;
2391 if (family
== AF_INET
) {
2392 return (ptr
[0] == 127);
2396 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr
*) ptr
));
2403 get_local_ips (int family
, int *nips
)
2405 int addr_size
, offset
, fd
, i
, count
;
2406 int max_ifaces
= 50; /* 50 interfaces should be enough... */
2409 struct ifreq iflags
;
2410 char *result
, *tmp_ptr
;
2411 gboolean ignore_loopback
= FALSE
;
2414 if (family
== AF_INET
) {
2415 addr_size
= sizeof (struct in_addr
);
2416 offset
= G_STRUCT_OFFSET (struct sockaddr_in
, sin_addr
);
2418 } else if (family
== AF_INET6
) {
2419 addr_size
= sizeof (struct in6_addr
);
2420 offset
= G_STRUCT_OFFSET (struct sockaddr_in6
, sin6_addr
);
2426 fd
= socket (family
, SOCK_STREAM
, 0);
2428 ifc
.ifc_len
= max_ifaces
* sizeof (struct ifreq
);
2429 ifc
.ifc_buf
= g_malloc (ifc
.ifc_len
);
2430 if (ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0) {
2432 g_free (ifc
.ifc_buf
);
2436 count
= ifc
.ifc_len
/ sizeof (struct ifreq
);
2439 g_free (ifc
.ifc_buf
);
2444 for (i
= 0, ifr
= ifc
.ifc_req
; i
< *nips
; i
++, ifr
++) {
2445 strcpy (iflags
.ifr_name
, ifr
->ifr_name
);
2446 if (ioctl (fd
, SIOCGIFFLAGS
, &iflags
) < 0) {
2450 if ((iflags
.ifr_flags
& IFF_UP
) == 0) {
2451 ifr
->ifr_name
[0] = '\0';
2455 if ((iflags
.ifr_flags
& IFF_LOOPBACK
) == 0) {
2456 ignore_loopback
= TRUE
;
2461 result
= g_malloc (addr_size
* count
);
2463 for (i
= 0, ifr
= ifc
.ifc_req
; i
< count
; i
++, ifr
++) {
2464 if (ifr
->ifr_name
[0] == '\0') {
2469 if (ignore_loopback
&& is_loopback (family
, ((char *) &ifr
->ifr_addr
) + offset
)) {
2474 memcpy (tmp_ptr
, ((char *) &ifr
->ifr_addr
) + offset
, addr_size
);
2475 tmp_ptr
+= addr_size
;
2478 g_free (ifc
.ifc_buf
);
2481 #elif defined(HAVE_GETIFADDRS)
2483 is_loopback (int family
, void *ad
)
2485 char *ptr
= (char *) ad
;
2487 if (family
== AF_INET
) {
2488 return (ptr
[0] == 127);
2492 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr
*) ptr
));
2499 get_local_ips (int family
, int *nips
)
2501 struct ifaddrs
*ifap
= NULL
, *ptr
;
2502 int addr_size
, offset
, count
, i
;
2503 char *result
, *tmp_ptr
;
2506 if (family
== AF_INET
) {
2507 addr_size
= sizeof (struct in_addr
);
2508 offset
= G_STRUCT_OFFSET (struct sockaddr_in
, sin_addr
);
2510 } else if (family
== AF_INET6
) {
2511 addr_size
= sizeof (struct in6_addr
);
2512 offset
= G_STRUCT_OFFSET (struct sockaddr_in6
, sin6_addr
);
2518 if (getifaddrs (&ifap
)) {
2523 for (ptr
= ifap
; ptr
; ptr
= ptr
->ifa_next
) {
2526 if (ptr
->ifa_addr
->sa_family
!= family
)
2528 if (is_loopback (family
, ((char *) ptr
->ifa_addr
) + offset
))
2533 result
= g_malloc (addr_size
* count
);
2535 for (i
= 0, ptr
= ifap
; ptr
; ptr
= ptr
->ifa_next
) {
2538 if (ptr
->ifa_addr
->sa_family
!= family
)
2540 if (is_loopback (family
, ((char *) ptr
->ifa_addr
) + offset
))
2543 memcpy (tmp_ptr
, ((char *) ptr
->ifa_addr
) + offset
, addr_size
);
2544 tmp_ptr
+= addr_size
;
2553 get_local_ips (int family
, int *nips
)
2559 #endif /* HAVE_SIOCGIFCONF */
2562 static gboolean
hostent_to_IPHostEntry(struct hostent
*he
, MonoString
**h_name
,
2563 MonoArray
**h_aliases
,
2564 MonoArray
**h_addr_list
,
2565 gboolean add_local_ips
)
2567 MonoDomain
*domain
= mono_domain_get ();
2569 struct in_addr
*local_in
= NULL
;
2573 if(he
->h_length
!=4 || he
->h_addrtype
!=AF_INET
) {
2577 *h_name
=mono_string_new(domain
, he
->h_name
);
2579 while(he
->h_aliases
[i
]!=NULL
) {
2583 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), i
);
2585 while(he
->h_aliases
[i
]!=NULL
) {
2588 alias
=mono_string_new(domain
, he
->h_aliases
[i
]);
2589 mono_array_setref (*h_aliases
, i
, alias
);
2592 } else if (!add_local_ips
) {
2596 if (add_local_ips
) {
2597 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2599 *h_addr_list
= mono_array_new(domain
, mono_get_string_class (), nlocal_in
);
2600 for (i
= 0; i
< nlocal_in
; i
++) {
2601 MonoString
*addr_string
;
2602 char addr
[16], *ptr
;
2604 ptr
= (char *) &local_in
[i
];
2605 g_snprintf(addr
, 16, "%u.%u.%u.%u",
2606 (unsigned char) ptr
[0],
2607 (unsigned char) ptr
[1],
2608 (unsigned char) ptr
[2],
2609 (unsigned char) ptr
[3]);
2611 addr_string
= mono_string_new (domain
, addr
);
2612 mono_array_setref (*h_addr_list
, i
, addr_string
);
2617 } else if (he
== NULL
) {
2618 /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */
2619 *h_addr_list
= mono_array_new(domain
, mono_get_string_class (), 1);
2620 mono_array_setref (*h_addr_list
, 0, mono_string_new (domain
, "127.0.0.1"));
2625 if (nlocal_in
== 0 && he
!= NULL
) {
2627 while (he
->h_addr_list
[i
]!=NULL
) {
2631 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), i
);
2633 while(he
->h_addr_list
[i
]!=NULL
) {
2634 MonoString
*addr_string
;
2637 g_snprintf(addr
, 16, "%u.%u.%u.%u",
2638 (unsigned char)he
->h_addr_list
[i
][0],
2639 (unsigned char)he
->h_addr_list
[i
][1],
2640 (unsigned char)he
->h_addr_list
[i
][2],
2641 (unsigned char)he
->h_addr_list
[i
][3]);
2643 addr_string
=mono_string_new(domain
, addr
);
2644 mono_array_setref (*h_addr_list
, i
, addr_string
);
2652 static gboolean
ipaddr_to_IPHostEntry(const char *addr
, MonoString
**h_name
,
2653 MonoArray
**h_aliases
,
2654 MonoArray
**h_addr_list
)
2656 MonoDomain
*domain
= mono_domain_get ();
2658 *h_name
=mono_string_new(domain
, addr
);
2659 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2660 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), 1);
2661 mono_array_setref (*h_addr_list
, 0, *h_name
);
2667 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2668 static gboolean
hostent_to_IPHostEntry2(struct hostent
*he1
,struct hostent
*he2
, MonoString
**h_name
,
2669 MonoArray
**h_aliases
, MonoArray
**h_addr_list
, gboolean add_local_ips
)
2671 MonoDomain
*domain
= mono_domain_get ();
2672 int i
, host_count
, host_index
, family_hint
;
2673 struct in_addr
*local_in
= NULL
;
2675 struct in6_addr
*local_in6
= NULL
;
2677 gboolean from_local
= FALSE
;
2679 family_hint
= get_family_hint ();
2682 * Check if address length and family are correct
2684 if (he1
!= NULL
&& (he1
->h_length
!=4 || he1
->h_addrtype
!=AF_INET
)) {
2688 if (he2
!= NULL
&& (he2
->h_length
!=16 || he2
->h_addrtype
!=AF_INET6
)) {
2693 * Get the aliases and host name from he1 or he2 whichever is
2694 * not null, if he1 is not null then take aliases from he1
2696 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2697 family_hint
== PF_INET
)) {
2698 *h_name
=mono_string_new (domain
, he1
->h_name
);
2701 while(he1
->h_aliases
[i
]!=NULL
) {
2705 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
2708 while(he1
->h_aliases
[i
]!=NULL
) {
2711 alias
=mono_string_new (domain
, he1
->h_aliases
[i
]);
2712 mono_array_setref (*h_aliases
, i
, alias
);
2715 } else if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2716 family_hint
== PF_INET6
)) {
2717 *h_name
=mono_string_new (domain
, he2
->h_name
);
2720 while(he2
->h_aliases
[i
] != NULL
) {
2724 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
2727 while(he2
->h_aliases
[i
]!=NULL
) {
2730 alias
=mono_string_new (domain
, he2
->h_aliases
[i
]);
2731 mono_array_setref (*h_aliases
, i
, alias
);
2734 } else if (!add_local_ips
) {
2739 * Count the number of addresses in he1 + he2
2742 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2743 family_hint
== PF_INET
)) {
2745 while(he1
->h_addr_list
[i
]!=NULL
) {
2751 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2752 family_hint
== PF_INET6
)) {
2754 while(he2
->h_addr_list
[i
]!=NULL
) {
2764 if (add_local_ips
) {
2765 if (family_hint
== PF_UNSPEC
|| family_hint
== PF_INET
)
2766 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2768 if (family_hint
== PF_UNSPEC
|| family_hint
== PF_INET6
)
2769 local_in6
= (struct in6_addr
*) get_local_ips (AF_INET6
, &nlocal_in6
);
2771 if (nlocal_in
|| nlocal_in6
) {
2773 *h_addr_list
= mono_array_new (domain
, mono_get_string_class (),
2774 nlocal_in
+ nlocal_in6
);
2778 for (n
= 0; n
< nlocal_in6
; n
++) {
2779 MonoString
*addr_string
;
2781 char addr
[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2783 ret
= inet_ntop (AF_INET6
, &local_in6
[n
], addr
, sizeof(addr
));
2786 addr_string
= mono_string_new (domain
, addr
);
2787 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2795 for (n
= 0; n
< nlocal_in
; n
++) {
2796 MonoString
*addr_string
;
2798 char addr
[16]; /* INET_ADDRSTRLEN == 16 */
2800 ret
= inet_ntop (AF_INET
, &local_in
[n
], addr
, sizeof(addr
));
2803 addr_string
= mono_string_new (domain
, addr
);
2804 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2812 } else if (he1
== NULL
&& he2
== NULL
) {
2813 /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */
2814 *h_addr_list
= mono_array_new(domain
, mono_get_string_class (), 1);
2815 mono_array_setref (*h_addr_list
, 0, mono_string_new (domain
, "127.0.0.1"));
2825 *h_addr_list
=mono_array_new (domain
, mono_get_string_class (), host_count
);
2827 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2828 family_hint
== PF_INET6
)) {
2830 while(he2
->h_addr_list
[i
] != NULL
) {
2831 MonoString
*addr_string
;
2833 char addr
[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2835 ret
= inet_ntop (AF_INET6
, he2
->h_addr_list
[i
], addr
,
2839 addr_string
= mono_string_new (domain
, addr
);
2840 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2847 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2848 family_hint
== PF_INET
)) {
2850 while(he1
->h_addr_list
[i
] != NULL
) {
2851 MonoString
*addr_string
;
2853 char addr
[16]; /* INET_ADDRSTRLEN == 16 */
2855 ret
= inet_ntop (AF_INET
, he1
->h_addr_list
[i
], addr
,
2859 addr_string
=mono_string_new (domain
, addr
);
2860 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2871 #if defined(AF_INET6)
2873 addrinfo_to_IPHostEntry(struct addrinfo
*info
, MonoString
**h_name
,
2874 MonoArray
**h_aliases
,
2875 MonoArray
**h_addr_list
,
2876 gboolean add_local_ips
)
2879 struct addrinfo
*ai
= NULL
;
2880 struct in_addr
*local_in
= NULL
;
2882 struct in6_addr
*local_in6
= NULL
;
2886 MonoDomain
*domain
= mono_domain_get ();
2889 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2890 if (add_local_ips
) {
2891 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2892 local_in6
= (struct in6_addr
*) get_local_ips (AF_INET6
, &nlocal_in6
);
2893 if (nlocal_in
|| nlocal_in6
) {
2894 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), nlocal_in
+ nlocal_in6
);
2896 MonoString
*addr_string
;
2900 for (i
= 0; i
< nlocal_in
; i
++) {
2901 inet_ntop (AF_INET
, &local_in
[i
], addr
, sizeof (addr
));
2902 addr_string
= mono_string_new (domain
, addr
);
2903 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2909 MonoString
*addr_string
;
2914 for (i
= 0; i
< nlocal_in6
; i
++) {
2915 ret
= inet_ntop (AF_INET6
, &local_in6
[i
], addr
, sizeof (addr
));
2917 addr_string
= mono_string_new (domain
, addr
);
2918 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2927 freeaddrinfo (info
);
2936 for (count
=0, ai
=info
; ai
!=NULL
; ai
=ai
->ai_next
) {
2937 if (ai
->ai_family
!= AF_INET
&& ai
->ai_family
!= AF_INET6
)
2943 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), count
);
2945 for (ai
=info
, i
=0; ai
!=NULL
; ai
=ai
->ai_next
) {
2946 MonoString
*addr_string
;
2948 char buffer
[48]; /* Max. size for IPv6 */
2950 if((ai
->ai_family
!= PF_INET
) && (ai
->ai_family
!= PF_INET6
)) {
2954 if(ai
->ai_family
== PF_INET
) {
2955 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
), buffer
, 16);
2957 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_addr
), buffer
, 48);
2961 addr_string
=mono_string_new(domain
, buffer
);
2963 addr_string
=mono_string_new(domain
, "");
2966 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2970 if (ai
->ai_canonname
!= NULL
) {
2971 *h_name
=mono_string_new(domain
, ai
->ai_canonname
);
2973 *h_name
=mono_string_new(domain
, buffer
);
2989 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2991 gboolean add_local_ips
= FALSE
;
2992 #ifdef HAVE_SIOCGIFCONF
2993 gchar this_hostname
[256];
2995 #if !defined(HAVE_GETHOSTBYNAME2_R)
2996 struct addrinfo
*info
= NULL
, hints
;
2999 MONO_ARCH_SAVE_REGS
;
3001 hostname
=mono_string_to_utf8 (host
);
3002 if (*hostname
== '\0') {
3003 add_local_ips
= TRUE
;
3006 #ifdef HAVE_SIOCGIFCONF
3007 if (!add_local_ips
&& gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
3008 if (!strcmp (hostname
, this_hostname
)) {
3009 add_local_ips
= TRUE
;
3015 memset(&hints
, 0, sizeof(hints
));
3016 hints
.ai_family
= get_family_hint ();
3017 hints
.ai_socktype
= SOCK_STREAM
;
3018 hints
.ai_flags
= AI_CANONNAME
;
3020 if (*hostname
&& getaddrinfo(hostname
, NULL
, &hints
, &info
) == -1) {
3027 return(addrinfo_to_IPHostEntry(info
, h_name
, h_aliases
, h_addr_list
, add_local_ips
));
3029 struct hostent he1
,*hp1
, he2
, *hp2
;
3030 int buffer_size1
, buffer_size2
;
3031 char *buffer1
, *buffer2
;
3033 gboolean return_value
;
3036 MONO_ARCH_SAVE_REGS
;
3038 hostname
=mono_string_to_utf8 (host
);
3039 if (*hostname
== '\0')
3040 add_local_ips
= TRUE
;
3042 #ifdef HAVE_SIOCGIFCONF
3043 if (!add_local_ips
&& gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
3044 if (!strcmp (hostname
, this_hostname
))
3045 add_local_ips
= TRUE
;
3051 buffer1
= g_malloc0(buffer_size1
);
3052 buffer2
= g_malloc0(buffer_size2
);
3056 while (*hostname
&& gethostbyname2_r(hostname
, AF_INET
, &he1
, buffer1
, buffer_size1
,
3057 &hp1
, &herr
) == ERANGE
) {
3059 buffer1
= g_realloc(buffer1
, buffer_size1
);
3062 if (*hostname
&& hp1
== NULL
)
3064 while (gethostbyname2_r(hostname
, AF_INET6
, &he2
, buffer2
,
3065 buffer_size2
, &hp2
, &herr
) == ERANGE
) {
3067 buffer2
= g_realloc(buffer2
, buffer_size2
);
3071 return_value
= hostent_to_IPHostEntry2(hp1
, hp2
, h_name
, h_aliases
,
3072 h_addr_list
, add_local_ips
);
3078 return(return_value
);
3079 #endif /* HAVE_GETHOSTBYNAME2_R */
3081 #else /* AF_INET6 */
3082 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
3086 gboolean add_local_ips
= FALSE
;
3087 #ifdef HAVE_SIOCGIFCONF
3088 gchar this_hostname
[256];
3091 MONO_ARCH_SAVE_REGS
;
3093 hostname
=mono_string_to_utf8(host
);
3094 if (*hostname
== '\0')
3095 add_local_ips
= TRUE
;
3096 #ifdef HAVE_SIOCGIFCONF
3097 if (!add_local_ips
&& gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
3098 if (!strcmp (hostname
, this_hostname
))
3099 add_local_ips
= TRUE
;
3106 he
= _wapi_gethostbyname (hostname
);
3108 he
= _wapi_gethostbyname (hostname
);
3111 if (*hostname
&& he
==NULL
) {
3118 return(hostent_to_IPHostEntry(he
, h_name
, h_aliases
, h_addr_list
, add_local_ips
));
3120 #endif /* AF_INET6 */
3122 #ifndef HAVE_INET_PTON
3124 inet_pton (int family
, const char *address
, void *inaddrp
)
3126 if (family
== AF_INET
) {
3127 #ifdef HAVE_INET_ATON
3128 struct in_addr inaddr
;
3130 if (!inet_aton (address
, &inaddr
))
3133 memcpy (inaddrp
, &inaddr
, sizeof (struct in_addr
));
3136 /* assume the system has inet_addr(), if it doesn't
3137 have that we're pretty much screwed... */
3140 if (!strcmp (address
, "255.255.255.255")) {
3141 /* special-case hack */
3142 inaddr
= 0xffffffff;
3144 inaddr
= inet_addr (address
);
3146 #define INADDR_NONE ((in_addr_t) -1)
3148 if (inaddr
== INADDR_NONE
)
3152 memcpy (inaddrp
, &inaddr
, sizeof (guint32
));
3154 #endif /* HAVE_INET_ATON */
3159 #endif /* !HAVE_INET_PTON */
3161 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString
*addr
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
3166 struct sockaddr_in saddr
;
3167 struct sockaddr_in6 saddr6
;
3168 struct addrinfo
*info
= NULL
, hints
;
3170 char hostname
[NI_MAXHOST
] = {0};
3173 struct in_addr inaddr
;
3178 address
= mono_string_to_utf8 (addr
);
3181 if (inet_pton (AF_INET
, address
, &saddr
.sin_addr
) <= 0) {
3182 /* Maybe an ipv6 address */
3183 if (inet_pton (AF_INET6
, address
, &saddr6
.sin6_addr
) <= 0) {
3189 saddr6
.sin6_family
= AF_INET6
;
3194 saddr
.sin_family
= AF_INET
;
3198 if(family
== AF_INET
) {
3199 #if HAVE_SOCKADDR_IN_SIN_LEN
3200 saddr
.sin_len
= sizeof (saddr
);
3202 if(getnameinfo ((struct sockaddr
*)&saddr
, sizeof(saddr
),
3203 hostname
, sizeof(hostname
), NULL
, 0,
3207 } else if(family
== AF_INET6
) {
3208 #if HAVE_SOCKADDR_IN6_SIN_LEN
3209 saddr6
.sin6_len
= sizeof (saddr6
);
3211 if(getnameinfo ((struct sockaddr
*)&saddr6
, sizeof(saddr6
),
3212 hostname
, sizeof(hostname
), NULL
, 0,
3218 memset (&hints
, 0, sizeof(hints
));
3219 hints
.ai_family
= get_family_hint ();
3220 hints
.ai_socktype
= SOCK_STREAM
;
3221 hints
.ai_flags
= AI_CANONNAME
| AI_ADDRCONFIG
;
3223 if( getaddrinfo (hostname
, NULL
, &hints
, &info
) == -1 ) {
3227 return(addrinfo_to_IPHostEntry (info
, h_name
, h_aliases
, h_addr_list
, FALSE
));
3229 if (inet_pton (AF_INET
, address
, &inaddr
) <= 0) {
3234 if ((he
= gethostbyaddr ((char *) &inaddr
, sizeof (inaddr
), AF_INET
)) == NULL
) {
3235 ret
= ipaddr_to_IPHostEntry (address
, h_name
, h_aliases
, h_addr_list
);
3237 ret
= hostent_to_IPHostEntry (he
, h_name
, h_aliases
,
3238 h_addr_list
, FALSE
);
3246 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostName_internal(MonoString
**h_name
)
3248 gchar hostname
[256];
3251 MONO_ARCH_SAVE_REGS
;
3253 ret
= gethostname (hostname
, sizeof (hostname
));
3258 *h_name
=mono_string_new(mono_domain_get (), hostname
);
3264 ves_icall_System_Net_Sockets_Socket_SendFile (SOCKET sock
, MonoString
*filename
, MonoArray
*pre_buffer
, MonoArray
*post_buffer
, gint flags
)
3268 TRANSMIT_FILE_BUFFERS buffers
;
3270 MONO_ARCH_SAVE_REGS
;
3272 if (filename
== NULL
)
3275 file
= ves_icall_System_IO_MonoIO_Open (filename
, FileMode_Open
, FileAccess_Read
, FileShare_Read
, 0, &error
);
3276 if (file
== INVALID_HANDLE_VALUE
) {
3277 SetLastError (error
);
3281 memset (&buffers
, 0, sizeof (buffers
));
3282 if (pre_buffer
!= NULL
) {
3283 buffers
.Head
= mono_array_addr (pre_buffer
, guchar
, 0);
3284 buffers
.HeadLength
= mono_array_length (pre_buffer
);
3286 if (post_buffer
!= NULL
) {
3287 buffers
.Tail
= mono_array_addr (post_buffer
, guchar
, 0);
3288 buffers
.TailLength
= mono_array_length (post_buffer
);
3291 if (!TransmitFile (sock
, file
, 0, 0, NULL
, &buffers
, flags
)) {
3300 void mono_network_init(void)
3305 err
=WSAStartup(MAKEWORD(2,0), &wsadata
);
3307 g_error("%s: Couldn't initialise networking", __func__
);
3311 LOGDEBUG (g_message("%s: Using socket library: %s", __func__
, wsadata
.szDescription
));
3312 LOGDEBUG (g_message("%s: Socket system status: %s", __func__
, wsadata
.szSystemStatus
));
3315 void mono_network_cleanup(void)
3321 icall_cancel_blocking_socket_operation (MonoThread
*thread
)
3323 MonoInternalThread
*internal
= thread
->internal_thread
;
3325 if (mono_thread_info_new_interrupt_enabled ()) {
3326 mono_thread_info_abort_socket_syscall_for_close ((MonoNativeThreadId
)(gsize
)internal
->tid
);
3329 internal
->ignore_next_signal
= TRUE
;
3330 mono_thread_kill (internal
, mono_thread_get_abort_signal ());
3335 #endif /* #ifndef DISABLE_SOCKETS */