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
16 #if defined(__APPLE__) || defined(__FreeBSD__)
17 #define __APPLE_USE_RFC_3542
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <netinet/in.h>
29 #include <netinet/tcp.h>
31 #include <arpa/inet.h>
38 #include <sys/types.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>
56 #include <mono/utils/networking.h>
59 #ifdef HAVE_SYS_TIME_H
62 #ifdef HAVE_SYS_IOCTL_H
63 #include <sys/ioctl.h>
72 #ifdef HAVE_SYS_FILIO_H
73 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
75 #ifdef HAVE_SYS_SOCKIO_H
76 #include <sys/sockio.h> /* defines SIOCATMARK */
82 #ifdef HAVE_GETIFADDRS
83 // <net/if.h> must be included before <ifaddrs.h>
87 #include "mono/io-layer/socket-wrappers.h"
90 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
92 static gint32
convert_family(MonoAddressFamily mono_family
)
97 case AddressFamily_Unknown
:
98 case AddressFamily_ImpLink
:
99 case AddressFamily_Pup
:
100 case AddressFamily_Chaos
:
101 case AddressFamily_Iso
:
102 case AddressFamily_Ecma
:
103 case AddressFamily_DataKit
:
104 case AddressFamily_Ccitt
:
105 case AddressFamily_DataLink
:
106 case AddressFamily_Lat
:
107 case AddressFamily_HyperChannel
:
108 case AddressFamily_NetBios
:
109 case AddressFamily_VoiceView
:
110 case AddressFamily_FireFox
:
111 case AddressFamily_Banyan
:
112 case AddressFamily_Atm
:
113 case AddressFamily_Cluster
:
114 case AddressFamily_Ieee12844
:
115 case AddressFamily_NetworkDesigners
:
116 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family
);
119 case AddressFamily_Unspecified
:
123 case AddressFamily_Unix
:
127 case AddressFamily_InterNetwork
:
131 case AddressFamily_Ipx
:
137 case AddressFamily_Sna
:
143 case AddressFamily_DecNet
:
149 case AddressFamily_AppleTalk
:
153 case AddressFamily_InterNetworkV6
:
157 case AddressFamily_Irda
:
163 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family
);
169 static MonoAddressFamily
convert_to_mono_family(guint16 af_family
)
171 MonoAddressFamily family
=AddressFamily_Unknown
;
175 family
=AddressFamily_Unspecified
;
179 family
=AddressFamily_Unix
;
183 family
=AddressFamily_InterNetwork
;
188 family
=AddressFamily_Ipx
;
194 family
=AddressFamily_Sna
;
200 family
=AddressFamily_DecNet
;
205 family
=AddressFamily_AppleTalk
;
209 family
=AddressFamily_InterNetworkV6
;
214 family
=AddressFamily_Irda
;
218 g_warning("unknown address family 0x%x", af_family
);
224 static gint32
convert_type(MonoSocketType mono_type
)
229 case SocketType_Stream
:
233 case SocketType_Dgram
:
247 case SocketType_Seqpacket
:
251 case SocketType_Unknown
:
252 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type
);
256 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type
);
262 static gint32
convert_proto(MonoProtocolType mono_proto
)
267 case ProtocolType_IP
:
268 case ProtocolType_IPv6
:
269 case ProtocolType_Icmp
:
270 case ProtocolType_Igmp
:
271 case ProtocolType_Ggp
:
272 case ProtocolType_Tcp
:
273 case ProtocolType_Pup
:
274 case ProtocolType_Udp
:
275 case ProtocolType_Idp
:
276 /* These protocols are known (on my system at least) */
280 case ProtocolType_ND
:
281 case ProtocolType_Raw
:
282 case ProtocolType_Ipx
:
283 case ProtocolType_Spx
:
284 case ProtocolType_SpxII
:
285 case ProtocolType_Unknown
:
286 /* These protocols arent */
287 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto
);
297 /* Convert MonoSocketFlags */
298 static gint32
convert_socketflags (gint32 sflags
)
303 /* SocketFlags.None */
306 if (sflags
& ~(SocketFlags_OutOfBand
| SocketFlags_MaxIOVectorLength
| SocketFlags_Peek
|
307 SocketFlags_DontRoute
| SocketFlags_Partial
))
308 /* Contains invalid flag values */
311 if (sflags
& SocketFlags_OutOfBand
)
313 if (sflags
& SocketFlags_Peek
)
315 if (sflags
& SocketFlags_DontRoute
)
316 flags
|= MSG_DONTROUTE
;
318 /* Ignore Partial - see bug 349688. Don't return -1, because
319 * according to the comment in that bug ms runtime doesn't for
320 * UDP sockets (this means we will silently ignore it for TCP
324 if (sflags
& SocketFlags_Partial
)
328 /* Don't do anything for MaxIOVectorLength */
329 if (sflags
& SocketFlags_MaxIOVectorLength
)
337 * 0 on success (mapped mono_level and mono_name to system_level and system_name
339 * -2 on non-fatal error (ie, must ignore)
341 static gint32
convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level
,
342 MonoSocketOptionName mono_name
,
346 switch (mono_level
) {
347 case SocketOptionLevel_Socket
:
348 *system_level
= SOL_SOCKET
;
351 case SocketOptionName_DontLinger
:
352 /* This is SO_LINGER, because the setsockopt
353 * internal call maps DontLinger to SO_LINGER
356 *system_name
= SO_LINGER
;
358 case SocketOptionName_Debug
:
359 *system_name
= SO_DEBUG
;
362 case SocketOptionName_AcceptConnection
:
363 *system_name
= SO_ACCEPTCONN
;
366 case SocketOptionName_ReuseAddress
:
367 *system_name
= SO_REUSEADDR
;
369 case SocketOptionName_KeepAlive
:
370 *system_name
= SO_KEEPALIVE
;
372 case SocketOptionName_DontRoute
:
373 *system_name
= SO_DONTROUTE
;
375 case SocketOptionName_Broadcast
:
376 *system_name
= SO_BROADCAST
;
378 case SocketOptionName_Linger
:
379 *system_name
= SO_LINGER
;
381 case SocketOptionName_OutOfBandInline
:
382 *system_name
= SO_OOBINLINE
;
384 case SocketOptionName_SendBuffer
:
385 *system_name
= SO_SNDBUF
;
387 case SocketOptionName_ReceiveBuffer
:
388 *system_name
= SO_RCVBUF
;
390 case SocketOptionName_SendLowWater
:
391 *system_name
= SO_SNDLOWAT
;
393 case SocketOptionName_ReceiveLowWater
:
394 *system_name
= SO_RCVLOWAT
;
396 case SocketOptionName_SendTimeout
:
397 *system_name
= SO_SNDTIMEO
;
399 case SocketOptionName_ReceiveTimeout
:
400 *system_name
= SO_RCVTIMEO
;
402 case SocketOptionName_Error
:
403 *system_name
= SO_ERROR
;
405 case SocketOptionName_Type
:
406 *system_name
= SO_TYPE
;
409 case SocketOptionName_PeerCred
:
410 *system_name
= SO_PEERCRED
;
413 case SocketOptionName_ExclusiveAddressUse
:
414 #ifdef SO_EXCLUSIVEADDRUSE
415 *system_name
= SO_EXCLUSIVEADDRUSE
;
418 case SocketOptionName_UseLoopback
:
419 #ifdef SO_USELOOPBACK
420 *system_name
= SO_USELOOPBACK
;
423 case SocketOptionName_MaxConnections
:
425 *system_name
= SO_MAXCONN
;
427 #elif defined(SOMAXCONN)
428 *system_name
= SOMAXCONN
;
432 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name
);
437 case SocketOptionLevel_IP
:
438 *system_level
= mono_networking_get_ip_protocol ();
441 case SocketOptionName_IPOptions
:
442 *system_name
= IP_OPTIONS
;
445 case SocketOptionName_HeaderIncluded
:
446 *system_name
= IP_HDRINCL
;
450 case SocketOptionName_TypeOfService
:
451 *system_name
= IP_TOS
;
455 case SocketOptionName_IpTimeToLive
:
456 *system_name
= IP_TTL
;
459 case SocketOptionName_MulticastInterface
:
460 *system_name
= IP_MULTICAST_IF
;
462 case SocketOptionName_MulticastTimeToLive
:
463 *system_name
= IP_MULTICAST_TTL
;
465 case SocketOptionName_MulticastLoopback
:
466 *system_name
= IP_MULTICAST_LOOP
;
468 case SocketOptionName_AddMembership
:
469 *system_name
= IP_ADD_MEMBERSHIP
;
471 case SocketOptionName_DropMembership
:
472 *system_name
= IP_DROP_MEMBERSHIP
;
474 #ifdef HAVE_IP_PKTINFO
475 case SocketOptionName_PacketInformation
:
476 *system_name
= IP_PKTINFO
;
478 #endif /* HAVE_IP_PKTINFO */
480 case SocketOptionName_DontFragment
:
481 #ifdef HAVE_IP_DONTFRAGMENT
482 *system_name
= IP_DONTFRAGMENT
;
484 #elif defined HAVE_IP_MTU_DISCOVER
485 /* Not quite the same */
486 *system_name
= IP_MTU_DISCOVER
;
489 /* If the flag is not available on this system, we can ignore this error */
491 #endif /* HAVE_IP_DONTFRAGMENT */
492 case SocketOptionName_AddSourceMembership
:
493 case SocketOptionName_DropSourceMembership
:
494 case SocketOptionName_BlockSource
:
495 case SocketOptionName_UnblockSource
:
496 /* Can't figure out how to map these, so fall
500 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name
);
505 case SocketOptionLevel_IPv6
:
506 *system_level
= mono_networking_get_ipv6_protocol ();
509 case SocketOptionName_IpTimeToLive
:
510 case SocketOptionName_HopLimit
:
511 *system_name
= IPV6_UNICAST_HOPS
;
513 case SocketOptionName_MulticastInterface
:
514 *system_name
= IPV6_MULTICAST_IF
;
516 case SocketOptionName_MulticastTimeToLive
:
517 *system_name
= IPV6_MULTICAST_HOPS
;
519 case SocketOptionName_MulticastLoopback
:
520 *system_name
= IPV6_MULTICAST_LOOP
;
522 case SocketOptionName_AddMembership
:
523 *system_name
= IPV6_JOIN_GROUP
;
525 case SocketOptionName_DropMembership
:
526 *system_name
= IPV6_LEAVE_GROUP
;
528 case SocketOptionName_PacketInformation
:
529 #ifdef HAVE_IPV6_PKTINFO
530 *system_name
= IPV6_PKTINFO
;
533 case SocketOptionName_HeaderIncluded
:
534 case SocketOptionName_IPOptions
:
535 case SocketOptionName_TypeOfService
:
536 case SocketOptionName_DontFragment
:
537 case SocketOptionName_AddSourceMembership
:
538 case SocketOptionName_DropSourceMembership
:
539 case SocketOptionName_BlockSource
:
540 case SocketOptionName_UnblockSource
:
541 /* Can't figure out how to map these, so fall
545 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name
);
549 break; /* SocketOptionLevel_IPv6 */
551 case SocketOptionLevel_Tcp
:
552 *system_level
= mono_networking_get_tcp_protocol ();
555 case SocketOptionName_NoDelay
:
556 *system_name
= TCP_NODELAY
;
559 /* The documentation is talking complete
560 * bollocks here: rfc-1222 is titled
561 * 'Advancing the NSFNET Routing Architecture'
562 * and doesn't mention either of the words
563 * "expedite" or "urgent".
565 case SocketOptionName_BsdUrgent
:
566 case SocketOptionName_Expedited
:
569 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name
);
574 case SocketOptionLevel_Udp
:
575 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level
);
578 case SocketOptionName_NoChecksum
:
579 case SocketOptionName_ChecksumCoverage
:
581 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name
);
588 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level
);
595 static MonoImage
*get_socket_assembly (void)
597 MonoDomain
*domain
= mono_domain_get ();
599 if (domain
->socket_assembly
== NULL
) {
600 MonoImage
*socket_assembly
;
602 socket_assembly
= mono_image_loaded ("System");
603 if (!socket_assembly
) {
604 MonoAssembly
*sa
= mono_assembly_open ("System.dll", NULL
);
607 g_assert_not_reached ();
609 socket_assembly
= mono_assembly_get_image (sa
);
612 mono_atomic_store_release (&domain
->socket_assembly
, socket_assembly
);
615 return domain
->socket_assembly
;
618 static gint32
get_family_hint(void)
620 MonoDomain
*domain
= mono_domain_get ();
622 if (!domain
->inet_family_hint
) {
623 MonoClass
*socket_class
;
624 MonoClassField
*ipv6_field
, *ipv4_field
;
625 gint32 ipv6_enabled
= -1, ipv4_enabled
= -1;
628 socket_class
= mono_class_from_name (get_socket_assembly (), "System.Net.Sockets", "Socket");
629 ipv4_field
= mono_class_get_field_from_name (socket_class
, "ipv4Supported");
630 ipv6_field
= mono_class_get_field_from_name (socket_class
, "ipv6Supported");
631 vtable
= mono_class_vtable (mono_domain_get (), socket_class
);
633 mono_runtime_class_init (vtable
);
635 mono_field_static_get_value (vtable
, ipv4_field
, &ipv4_enabled
);
636 mono_field_static_get_value (vtable
, ipv6_field
, &ipv6_enabled
);
638 mono_domain_lock (domain
);
639 if (ipv4_enabled
== 1 && ipv6_enabled
== 1) {
640 domain
->inet_family_hint
= 1;
641 } else if (ipv4_enabled
== 1) {
642 domain
->inet_family_hint
= 2;
644 domain
->inet_family_hint
= 3;
646 mono_domain_unlock (domain
);
648 switch (domain
->inet_family_hint
) {
649 case 1: return PF_UNSPEC
;
650 case 2: return PF_INET
;
651 case 3: return PF_INET6
;
657 gpointer
ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject
*this, gint32 family
, gint32 type
, gint32 proto
, gint32
*error
)
668 sock_family
=convert_family(family
);
669 if(sock_family
==-1) {
670 *error
= WSAEAFNOSUPPORT
;
674 sock_proto
=convert_proto(proto
);
676 *error
= WSAEPROTONOSUPPORT
;
680 sock_type
=convert_type(type
);
682 *error
= WSAESOCKTNOSUPPORT
;
686 sock
= _wapi_socket (sock_family
, sock_type
, sock_proto
,
687 NULL
, 0, WSA_FLAG_OVERLAPPED
);
689 if(sock
==INVALID_SOCKET
) {
690 *error
= WSAGetLastError ();
694 return(GUINT_TO_POINTER (sock
));
697 /* FIXME: the SOCKET parameter (here and in other functions in this
698 * file) is really an IntPtr which needs to be converted to a guint32.
700 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock
,
705 LOGDEBUG (g_message ("%s: closing 0x%x", __func__
, sock
));
709 /* Clear any pending work item from this socket if the underlying
710 * polling system does not notify when the socket is closed */
711 mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock
));
715 gint32
ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
719 LOGDEBUG (g_message("%s: returning %d", __func__
, WSAGetLastError()));
721 return(WSAGetLastError());
724 gint32
ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock
,
734 /* FIXME: this might require amount to be unsigned long. */
735 ret
=ioctlsocket(sock
, FIONREAD
, &amount
);
736 if(ret
==SOCKET_ERROR
) {
737 *error
= WSAGetLastError ();
744 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock
,
755 * block == TRUE/FALSE means we will block/not block.
756 * But the ioctlsocket call takes TRUE/FALSE for non-block/block
760 ret
= ioctlsocket (sock
, FIONBIO
, (gulong
*) &block
);
761 if(ret
==SOCKET_ERROR
) {
762 *error
= WSAGetLastError ();
766 gpointer
ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock
,
777 MonoInternalThread
* curthread
= mono_thread_internal_current ();
778 curthread
->interrupt_on_stop
= (gpointer
)TRUE
;
779 newsock
= _wapi_accept (sock
, NULL
, 0);
780 curthread
->interrupt_on_stop
= (gpointer
)FALSE
;
783 newsock
= _wapi_accept (sock
, NULL
, 0);
785 if(newsock
==INVALID_SOCKET
) {
786 *error
= WSAGetLastError ();
790 return(GUINT_TO_POINTER (newsock
));
793 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock
,
803 ret
= _wapi_listen (sock
, backlog
);
804 if(ret
==SOCKET_ERROR
) {
805 *error
= WSAGetLastError ();
809 // Check whether it's ::ffff::0:0.
811 is_ipv4_mapped_any (const struct in6_addr
*addr
)
815 for (i
= 0; i
< 10; i
++) {
816 if (addr
->s6_addr
[i
])
819 if ((addr
->s6_addr
[10] != 0xff) || (addr
->s6_addr
[11] != 0xff))
821 for (i
= 12; i
< 16; i
++) {
822 if (addr
->s6_addr
[i
])
828 static MonoObject
*create_object_from_sockaddr(struct sockaddr
*saddr
,
829 int sa_size
, gint32
*error
)
831 MonoDomain
*domain
= mono_domain_get ();
832 MonoObject
*sockaddr_obj
;
834 MonoAddressFamily family
;
836 /* Build a System.Net.SocketAddress object instance */
837 if (!domain
->sockaddr_class
) {
838 domain
->sockaddr_class
=mono_class_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
839 g_assert (domain
->sockaddr_class
);
841 sockaddr_obj
=mono_object_new(domain
, domain
->sockaddr_class
);
843 /* Locate the SocketAddress data buffer in the object */
844 if (!domain
->sockaddr_data_field
) {
845 domain
->sockaddr_data_field
=mono_class_get_field_from_name (domain
->sockaddr_class
, "data");
846 g_assert (domain
->sockaddr_data_field
);
849 /* May be the +2 here is too conservative, as sa_len returns
850 * the length of the entire sockaddr_in/in6, including
851 * sizeof (unsigned short) of the family */
852 /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
853 data
=mono_array_new_cached(domain
, mono_get_byte_class (), sa_size
+2);
855 /* The data buffer is laid out as follows:
856 * bytes 0 and 1 are the address family
857 * bytes 2 and 3 are the port info
858 * the rest is the address info
861 family
=convert_to_mono_family(saddr
->sa_family
);
862 if(family
==AddressFamily_Unknown
) {
863 *error
= WSAEAFNOSUPPORT
;
867 mono_array_set(data
, guint8
, 0, family
& 0x0FF);
868 mono_array_set(data
, guint8
, 1, (family
>> 8) & 0x0FF);
870 if(saddr
->sa_family
==AF_INET
) {
871 struct sockaddr_in
*sa_in
=(struct sockaddr_in
*)saddr
;
872 guint16 port
=ntohs(sa_in
->sin_port
);
873 guint32 address
=ntohl(sa_in
->sin_addr
.s_addr
);
876 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
879 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
880 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
881 mono_array_set(data
, guint8
, 4, (address
>>24) & 0xff);
882 mono_array_set(data
, guint8
, 5, (address
>>16) & 0xff);
883 mono_array_set(data
, guint8
, 6, (address
>>8) & 0xff);
884 mono_array_set(data
, guint8
, 7, (address
) & 0xff);
886 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
888 return(sockaddr_obj
);
889 } else if (saddr
->sa_family
== AF_INET6
) {
890 struct sockaddr_in6
*sa_in
=(struct sockaddr_in6
*)saddr
;
893 guint16 port
=ntohs(sa_in
->sin6_port
);
896 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
899 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
900 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
902 if (is_ipv4_mapped_any (&sa_in
->sin6_addr
)) {
903 // Map ::ffff:0:0 to :: (bug #5502)
904 for(i
=0; i
<16; i
++) {
905 mono_array_set(data
, guint8
, 8+i
, 0);
908 for(i
=0; i
<16; i
++) {
909 mono_array_set(data
, guint8
, 8+i
,
910 sa_in
->sin6_addr
.s6_addr
[i
]);
914 mono_array_set(data
, guint8
, 24, sa_in
->sin6_scope_id
& 0xff);
915 mono_array_set(data
, guint8
, 25,
916 (sa_in
->sin6_scope_id
>> 8) & 0xff);
917 mono_array_set(data
, guint8
, 26,
918 (sa_in
->sin6_scope_id
>> 16) & 0xff);
919 mono_array_set(data
, guint8
, 27,
920 (sa_in
->sin6_scope_id
>> 24) & 0xff);
922 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
924 return(sockaddr_obj
);
926 } else if (saddr
->sa_family
== AF_UNIX
) {
929 for (i
= 0; i
< sa_size
; i
++) {
930 mono_array_set (data
, guint8
, i
+2, saddr
->sa_data
[i
]);
933 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
938 *error
= WSAEAFNOSUPPORT
;
944 get_sockaddr_size (int family
)
949 if (family
== AF_INET
) {
950 size
= sizeof (struct sockaddr_in
);
951 } else if (family
== AF_INET6
) {
952 size
= sizeof (struct sockaddr_in6
);
954 } else if (family
== AF_UNIX
) {
955 size
= sizeof (struct sockaddr_un
);
961 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock
, gint32 af
, gint32
*error
)
972 salen
= get_sockaddr_size (convert_family (af
));
974 *error
= WSAEAFNOSUPPORT
;
977 sa
= (salen
<= 128) ? alloca (salen
) : g_malloc0 (salen
);
978 ret
= _wapi_getsockname (sock
, (struct sockaddr
*)sa
, &salen
);
980 if(ret
==SOCKET_ERROR
) {
981 *error
= WSAGetLastError ();
987 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
)));
989 result
= create_object_from_sockaddr((struct sockaddr
*)sa
, salen
, error
);
995 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock
, gint32 af
, gint32
*error
)
1002 MONO_ARCH_SAVE_REGS
;
1006 salen
= get_sockaddr_size (convert_family (af
));
1008 *error
= WSAEAFNOSUPPORT
;
1011 sa
= (salen
<= 128) ? alloca (salen
) : g_malloc0 (salen
);
1012 /* Note: linux returns just 2 for AF_UNIX. Always. */
1013 ret
= _wapi_getpeername (sock
, (struct sockaddr
*)sa
, &salen
);
1014 if(ret
==SOCKET_ERROR
) {
1015 *error
= WSAGetLastError ();
1021 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
)));
1023 result
= create_object_from_sockaddr((struct sockaddr
*)sa
, salen
, error
);
1029 static struct sockaddr
*create_sockaddr_from_object(MonoObject
*saddr_obj
,
1033 MonoClassField
*field
;
1038 /* Dig the SocketAddress data buffer out of the object */
1039 field
=mono_class_get_field_from_name(saddr_obj
->vtable
->klass
, "data");
1040 data
=*(MonoArray
**)(((char *)saddr_obj
) + field
->offset
);
1042 /* The data buffer is laid out as follows:
1043 * byte 0 is the address family low byte
1044 * byte 1 is the address family high byte
1046 * bytes 2 and 3 are the port info
1047 * the rest is the address info
1049 * the rest is the file name
1051 len
= mono_array_length (data
);
1053 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1056 family
= convert_family (mono_array_get (data
, guint8
, 0) + (mono_array_get (data
, guint8
, 1) << 8));
1057 if (family
== AF_INET
) {
1058 struct sockaddr_in
*sa
;
1063 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1066 sa
= g_new0 (struct sockaddr_in
, 1);
1067 port
= (mono_array_get (data
, guint8
, 2) << 8) +
1068 mono_array_get (data
, guint8
, 3);
1069 address
= (mono_array_get (data
, guint8
, 4) << 24) +
1070 (mono_array_get (data
, guint8
, 5) << 16 ) +
1071 (mono_array_get (data
, guint8
, 6) << 8) +
1072 mono_array_get (data
, guint8
, 7);
1074 sa
->sin_family
= family
;
1075 sa
->sin_addr
.s_addr
= htonl (address
);
1076 sa
->sin_port
= htons (port
);
1078 *sa_size
= sizeof(struct sockaddr_in
);
1079 return((struct sockaddr
*)sa
);
1080 } else if (family
== AF_INET6
) {
1081 struct sockaddr_in6
*sa
;
1087 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1090 sa
= g_new0 (struct sockaddr_in6
, 1);
1091 port
= mono_array_get (data
, guint8
, 3) +
1092 (mono_array_get (data
, guint8
, 2) << 8);
1093 scopeid
= mono_array_get (data
, guint8
, 24) +
1094 (mono_array_get (data
, guint8
, 25) << 8) +
1095 (mono_array_get (data
, guint8
, 26) << 16) +
1096 (mono_array_get (data
, guint8
, 27) << 24);
1098 sa
->sin6_family
= family
;
1099 sa
->sin6_port
= htons (port
);
1100 sa
->sin6_scope_id
= scopeid
;
1102 for(i
=0; i
<16; i
++) {
1103 sa
->sin6_addr
.s6_addr
[i
] = mono_array_get (data
, guint8
, 8+i
);
1106 *sa_size
= sizeof(struct sockaddr_in6
);
1107 return((struct sockaddr
*)sa
);
1108 #ifdef HAVE_SYS_UN_H
1109 } else if (family
== AF_UNIX
) {
1110 struct sockaddr_un
*sock_un
;
1113 /* Need a byte for the '\0' terminator/prefix, and the first
1114 * two bytes hold the SocketAddress family
1116 if (len
- 2 >= sizeof(sock_un
->sun_path
)) {
1117 mono_raise_exception (mono_get_exception_index_out_of_range ());
1120 sock_un
= g_new0 (struct sockaddr_un
, 1);
1122 sock_un
->sun_family
= family
;
1123 for (i
= 0; i
< len
- 2; i
++) {
1124 sock_un
->sun_path
[i
] = mono_array_get (data
, guint8
,
1130 return (struct sockaddr
*)sock_un
;
1133 *error
= WSAEAFNOSUPPORT
;
1138 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1140 struct sockaddr
*sa
;
1144 MONO_ARCH_SAVE_REGS
;
1148 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1153 LOGDEBUG (g_message("%s: binding to %s port %d", __func__
, inet_ntoa(((struct sockaddr_in
*)sa
)->sin_addr
), ntohs (((struct sockaddr_in
*)sa
)->sin_port
)));
1155 ret
= _wapi_bind (sock
, sa
, sa_size
);
1156 if(ret
==SOCKET_ERROR
) {
1157 *error
= WSAGetLastError ();
1170 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock
, gint mode
,
1171 gint timeout
, gint32
*error
)
1173 MonoInternalThread
*thread
= NULL
;
1179 MONO_ARCH_SAVE_REGS
;
1181 pfds
= g_new0 (mono_pollfd
, 1);
1182 pfds
[0].fd
= GPOINTER_TO_INT (sock
);
1183 pfds
[0].events
= (mode
== SelectModeRead
) ? MONO_POLLIN
:
1184 (mode
== SelectModeWrite
) ? MONO_POLLOUT
:
1185 (MONO_POLLERR
| MONO_POLLHUP
| MONO_POLLNVAL
);
1187 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1188 start
= time (NULL
);
1192 ret
= mono_poll (pfds
, 1, timeout
);
1193 if (timeout
> 0 && ret
< 0) {
1195 int sec
= time (NULL
) - start
;
1197 timeout
-= sec
* 1000;
1205 if (ret
== -1 && errno
== EINTR
) {
1208 if (thread
== NULL
) {
1209 thread
= mono_thread_internal_current ();
1212 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1218 /* Suspend requested? */
1219 mono_thread_interruption_checkpoint ();
1223 } while (ret
== -1 && errno
== EINTR
);
1227 *error
= WSAGetLastError ();
1229 *error
= errno_to_WSA (errno
, __func__
);
1244 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1246 struct sockaddr
*sa
;
1250 MONO_ARCH_SAVE_REGS
;
1254 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1259 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
)));
1261 ret
= _wapi_connect (sock
, sa
, sa_size
);
1262 if(ret
==SOCKET_ERROR
) {
1263 *error
= WSAGetLastError ();
1269 /* These #defines from mswsock.h from wine. Defining them here allows
1270 * us to build this file on a mingw box that doesn't know the magic
1271 * numbers, but still run on a newer windows box that does.
1273 #ifndef WSAID_DISCONNECTEX
1274 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1275 typedef BOOL (WINAPI
*LPFN_DISCONNECTEX
)(SOCKET
, LPOVERLAPPED
, DWORD
, DWORD
);
1278 #ifndef WSAID_TRANSMITFILE
1279 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1280 typedef BOOL (WINAPI
*LPFN_TRANSMITFILE
)(SOCKET
, HANDLE
, DWORD
, DWORD
, LPOVERLAPPED
, LPTRANSMIT_FILE_BUFFERS
, DWORD
);
1283 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock
, MonoBoolean reuse
, gint32
*error
)
1286 glong output_bytes
= 0;
1287 GUID disco_guid
= WSAID_DISCONNECTEX
;
1288 GUID trans_guid
= WSAID_TRANSMITFILE
;
1289 LPFN_DISCONNECTEX _wapi_disconnectex
= NULL
;
1290 LPFN_TRANSMITFILE _wapi_transmitfile
= NULL
;
1293 MONO_ARCH_SAVE_REGS
;
1297 LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__
, sock
, reuse
));
1299 /* I _think_ the extension function pointers need to be looked
1300 * up for each socket. FIXME: check the best way to store
1301 * pointers to functions in managed objects that still works
1302 * on 64bit platforms.
1304 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1305 (void *)&disco_guid
, sizeof(GUID
),
1306 (void *)&_wapi_disconnectex
, sizeof(void *),
1307 &output_bytes
, NULL
, NULL
);
1309 /* make sure that WSAIoctl didn't put crap in the
1312 _wapi_disconnectex
= NULL
;
1315 * Use the SIO_GET_EXTENSION_FUNCTION_POINTER to
1316 * determine the address of the disconnect method without
1317 * taking a hard dependency on a single provider
1319 * For an explanation of why this is done, you can read
1320 * the article at http://www.codeproject.com/internet/jbsocketserver3.asp
1322 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1323 (void *)&trans_guid
, sizeof(GUID
),
1324 (void *)&_wapi_transmitfile
, sizeof(void *),
1325 &output_bytes
, NULL
, NULL
);
1327 _wapi_transmitfile
= NULL
;
1331 if (_wapi_disconnectex
!= NULL
) {
1332 bret
= _wapi_disconnectex (sock
, NULL
, TF_REUSE_SOCKET
, 0);
1333 } else if (_wapi_transmitfile
!= NULL
) {
1334 bret
= _wapi_transmitfile (sock
, NULL
, 0, 0, NULL
, NULL
,
1335 TF_DISCONNECT
| TF_REUSE_SOCKET
);
1337 *error
= ERROR_NOT_SUPPORTED
;
1341 if (bret
== FALSE
) {
1342 *error
= WSAGetLastError ();
1346 gint32
ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1353 MONO_ARCH_SAVE_REGS
;
1357 alen
= mono_array_length (buffer
);
1358 if (offset
> alen
- count
) {
1362 buf
=mono_array_addr(buffer
, guchar
, offset
);
1364 recvflags
= convert_socketflags (flags
);
1365 if (recvflags
== -1) {
1366 *error
= WSAEOPNOTSUPP
;
1372 MonoInternalThread
* curthread
= mono_thread_internal_current ();
1373 curthread
->interrupt_on_stop
= (gpointer
)TRUE
;
1374 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1375 curthread
->interrupt_on_stop
= (gpointer
)FALSE
;
1378 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1381 if(ret
==SOCKET_ERROR
) {
1382 *error
= WSAGetLastError ();
1389 gint32
ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1394 DWORD recvflags
= 0;
1396 MONO_ARCH_SAVE_REGS
;
1400 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1401 count
= mono_array_length (buffers
);
1403 recvflags
= convert_socketflags (flags
);
1404 if (recvflags
== -1) {
1405 *error
= WSAEOPNOTSUPP
;
1409 ret
= WSARecv (sock
, wsabufs
, count
, &recv
, &recvflags
, NULL
, NULL
);
1410 if (ret
== SOCKET_ERROR
) {
1411 *error
= WSAGetLastError ();
1418 gint32
ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
**sockaddr
, gint32
*error
)
1424 struct sockaddr
*sa
;
1427 MONO_ARCH_SAVE_REGS
;
1431 alen
= mono_array_length (buffer
);
1432 if (offset
> alen
- count
) {
1436 sa
=create_sockaddr_from_object(*sockaddr
, &sa_size
, error
);
1441 buf
=mono_array_addr(buffer
, guchar
, offset
);
1443 recvflags
= convert_socketflags (flags
);
1444 if (recvflags
== -1) {
1445 *error
= WSAEOPNOTSUPP
;
1449 ret
= _wapi_recvfrom (sock
, buf
, count
, recvflags
, sa
, &sa_size
);
1450 if(ret
==SOCKET_ERROR
) {
1452 *error
= WSAGetLastError ();
1456 /* If we didn't get a socket size, then we're probably a
1457 * connected connection-oriented socket and the stack hasn't
1458 * returned the remote address. All we can do is return null.
1461 *sockaddr
=create_object_from_sockaddr(sa
, sa_size
, error
);
1470 gint32
ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1477 MONO_ARCH_SAVE_REGS
;
1481 alen
= mono_array_length (buffer
);
1482 if (offset
> alen
- count
) {
1486 LOGDEBUG (g_message("%s: alen: %d", __func__
, alen
));
1488 buf
=mono_array_addr(buffer
, guchar
, offset
);
1490 LOGDEBUG (g_message("%s: Sending %d bytes", __func__
, count
));
1492 sendflags
= convert_socketflags (flags
);
1493 if (sendflags
== -1) {
1494 *error
= WSAEOPNOTSUPP
;
1498 ret
= _wapi_send (sock
, buf
, count
, sendflags
);
1499 if(ret
==SOCKET_ERROR
) {
1500 *error
= WSAGetLastError ();
1507 gint32
ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1512 DWORD sendflags
= 0;
1514 MONO_ARCH_SAVE_REGS
;
1518 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1519 count
= mono_array_length (buffers
);
1521 sendflags
= convert_socketflags (flags
);
1522 if (sendflags
== -1) {
1523 *error
= WSAEOPNOTSUPP
;
1527 ret
= WSASend (sock
, wsabufs
, count
, &sent
, sendflags
, NULL
, NULL
);
1528 if (ret
== SOCKET_ERROR
) {
1529 *error
= WSAGetLastError ();
1536 gint32
ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
*sockaddr
, gint32
*error
)
1542 struct sockaddr
*sa
;
1545 MONO_ARCH_SAVE_REGS
;
1549 alen
= mono_array_length (buffer
);
1550 if (offset
> alen
- count
) {
1554 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1559 LOGDEBUG (g_message("%s: alen: %d", __func__
, alen
));
1561 buf
=mono_array_addr(buffer
, guchar
, offset
);
1563 LOGDEBUG (g_message("%s: Sending %d bytes", __func__
, count
));
1565 sendflags
= convert_socketflags (flags
);
1566 if (sendflags
== -1) {
1567 *error
= WSAEOPNOTSUPP
;
1571 ret
= _wapi_sendto (sock
, buf
, count
, sendflags
, sa
, sa_size
);
1572 if(ret
==SOCKET_ERROR
) {
1573 *error
= WSAGetLastError ();
1581 static SOCKET
Socket_to_SOCKET(MonoObject
*sockobj
)
1584 MonoClassField
*field
;
1586 field
=mono_class_get_field_from_name(sockobj
->vtable
->klass
, "socket");
1587 sock
=GPOINTER_TO_INT (*(gpointer
*)(((char *)sockobj
)+field
->offset
));
1592 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1593 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray
**sockets
, gint32 timeout
, gint32
*error
)
1595 MonoInternalThread
*thread
= NULL
;
1602 MonoClass
*sock_arr_class
;
1605 uintptr_t socks_size
;
1607 MONO_ARCH_SAVE_REGS
;
1609 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1610 count
= mono_array_length (*sockets
);
1611 nfds
= count
- 3; /* NULL separators */
1612 pfds
= g_new0 (mono_pollfd
, nfds
);
1614 for (i
= 0; i
< count
; i
++) {
1615 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1622 /* The socket array was bogus */
1628 pfds
[idx
].fd
= Socket_to_SOCKET (obj
);
1629 pfds
[idx
].events
= (mode
== 0) ? MONO_POLLIN
: (mode
== 1) ? MONO_POLLOUT
: POLL_ERRORS
;
1633 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1634 start
= time (NULL
);
1637 ret
= mono_poll (pfds
, nfds
, timeout
);
1638 if (timeout
> 0 && ret
< 0) {
1640 int sec
= time (NULL
) - start
;
1642 timeout
-= sec
* 1000;
1648 if (ret
== -1 && errno
== EINTR
) {
1651 thread
= mono_thread_internal_current ();
1653 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1660 /* Suspend requested? */
1661 mono_thread_interruption_checkpoint ();
1665 } while (ret
== -1 && errno
== EINTR
);
1669 *error
= WSAGetLastError ();
1671 *error
= errno_to_WSA (errno
, __func__
);
1683 sock_arr_class
= ((MonoObject
*)*sockets
)->vtable
->klass
;
1684 socks_size
= ((uintptr_t)ret
) + 3; /* space for the NULL delimiters */
1685 socks
= mono_array_new_full (mono_domain_get (), sock_arr_class
, &socks_size
, NULL
);
1688 for (i
= 0; i
< count
&& ret
> 0; i
++) {
1691 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1698 pfd
= &pfds
[i
- mode
];
1699 if (pfd
->revents
== 0)
1703 if (mode
== 0 && (pfd
->revents
& (MONO_POLLIN
| POLL_ERRORS
)) != 0) {
1704 mono_array_setref (socks
, idx
++, obj
);
1705 } else if (mode
== 1 && (pfd
->revents
& (MONO_POLLOUT
| POLL_ERRORS
)) != 0) {
1706 mono_array_setref (socks
, idx
++, obj
);
1707 } else if ((pfd
->revents
& POLL_ERRORS
) != 0) {
1708 mono_array_setref (socks
, idx
++, obj
);
1716 static MonoObject
* int_to_object (MonoDomain
*domain
, int val
)
1718 return mono_value_box (domain
, mono_get_int32_class (), &val
);
1722 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoObject
**obj_val
, gint32
*error
)
1724 int system_level
= 0;
1725 int system_name
= 0;
1728 socklen_t valsize
=sizeof(val
);
1729 struct linger linger
;
1730 socklen_t lingersize
=sizeof(linger
);
1732 socklen_t time_ms_size
= sizeof (time_ms
);
1734 # if defined(__OpenBSD__)
1735 struct sockpeercred cred
;
1739 socklen_t credsize
= sizeof(cred
);
1741 MonoDomain
*domain
=mono_domain_get();
1743 MonoClass
*obj_class
;
1744 MonoClassField
*field
;
1746 MONO_ARCH_SAVE_REGS
;
1750 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1751 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
) {
1752 system_level
= SOL_SOCKET
;
1753 system_name
= SO_REUSEADDR
;
1759 ret
= convert_sockopt_level_and_name (level
, name
, &system_level
, &system_name
);
1763 *error
= WSAENOPROTOOPT
;
1767 *obj_val
= int_to_object (domain
, 0);
1771 /* No need to deal with MulticastOption names here, because
1772 * you cant getsockopt AddMembership or DropMembership (the
1773 * int getsockopt will error, causing an exception)
1776 case SocketOptionName_Linger
:
1777 case SocketOptionName_DontLinger
:
1778 ret
= _wapi_getsockopt(sock
, system_level
, system_name
, &linger
,
1782 case SocketOptionName_SendTimeout
:
1783 case SocketOptionName_ReceiveTimeout
:
1784 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, (char *) &time_ms
, &time_ms_size
);
1788 case SocketOptionName_PeerCred
:
1789 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &cred
,
1795 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &val
,
1799 if(ret
==SOCKET_ERROR
) {
1800 *error
= WSAGetLastError ();
1805 case SocketOptionName_Linger
:
1806 /* build a System.Net.Sockets.LingerOption */
1807 obj_class
=mono_class_from_name(get_socket_assembly (),
1808 "System.Net.Sockets",
1810 obj
=mono_object_new(domain
, obj_class
);
1812 /* Locate and set the fields "bool enabled" and "int
1815 field
=mono_class_get_field_from_name(obj_class
, "enabled");
1816 *(guint8
*)(((char *)obj
)+field
->offset
)=linger
.l_onoff
;
1818 field
=mono_class_get_field_from_name(obj_class
, "seconds");
1819 *(guint32
*)(((char *)obj
)+field
->offset
)=linger
.l_linger
;
1823 case SocketOptionName_DontLinger
:
1824 /* construct a bool int in val - true if linger is off */
1825 obj
= int_to_object (domain
, !linger
.l_onoff
);
1828 case SocketOptionName_SendTimeout
:
1829 case SocketOptionName_ReceiveTimeout
:
1830 obj
= int_to_object (domain
, time_ms
);
1834 case SocketOptionName_PeerCred
:
1836 /* build a Mono.Posix.PeerCred+PeerCredData if
1839 static MonoImage
*mono_posix_image
= NULL
;
1840 MonoPeerCredData
*cred_data
;
1842 if (mono_posix_image
== NULL
) {
1843 mono_posix_image
=mono_image_loaded ("Mono.Posix");
1844 if (!mono_posix_image
) {
1845 MonoAssembly
*sa
= mono_assembly_open ("Mono.Posix.dll", NULL
);
1847 *error
= WSAENOPROTOOPT
;
1850 mono_posix_image
= mono_assembly_get_image (sa
);
1855 obj_class
= mono_class_from_name(mono_posix_image
,
1858 obj
= mono_object_new(domain
, obj_class
);
1859 cred_data
= (MonoPeerCredData
*)obj
;
1860 cred_data
->pid
= cred
.pid
;
1861 cred_data
->uid
= cred
.uid
;
1862 cred_data
->gid
= cred
.gid
;
1868 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1869 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
)
1872 obj
= int_to_object (domain
, val
);
1877 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoArray
**byte_val
, gint32
*error
)
1879 int system_level
= 0;
1880 int system_name
= 0;
1885 MONO_ARCH_SAVE_REGS
;
1889 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1892 *error
= WSAENOPROTOOPT
;
1898 valsize
=mono_array_length(*byte_val
);
1899 buf
=mono_array_addr(*byte_val
, guchar
, 0);
1901 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, buf
, &valsize
);
1902 if(ret
==SOCKET_ERROR
) {
1903 *error
= WSAGetLastError ();
1907 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1908 static struct in_addr
ipaddress_to_struct_in_addr(MonoObject
*ipaddr
)
1910 struct in_addr inaddr
;
1911 MonoClassField
*field
;
1913 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Address");
1915 /* No idea why .net uses a 64bit type to hold a 32bit value...
1917 * Internal value of IPAddess is in little-endian order
1919 inaddr
.s_addr
=GUINT_FROM_LE ((guint32
)*(guint64
*)(((char *)ipaddr
)+field
->offset
));
1924 static struct in6_addr
ipaddress_to_struct_in6_addr(MonoObject
*ipaddr
)
1926 struct in6_addr in6addr
;
1927 MonoClassField
*field
;
1931 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Numbers");
1932 data
=*(MonoArray
**)(((char *)ipaddr
) + field
->offset
);
1934 /* Solaris has only the 8 bit version. */
1936 for(i
=0; i
<8; i
++) {
1937 guint16 s
= mono_array_get (data
, guint16
, i
);
1938 in6addr
.s6_addr
[2 * i
+ 1] = (s
>> 8) & 0xff;
1939 in6addr
.s6_addr
[2 * i
] = s
& 0xff;
1943 in6addr
.s6_addr16
[i
] = mono_array_get (data
, guint16
, i
);
1949 #if defined(__APPLE__) || defined(__FreeBSD__)
1951 #if defined(HAVE_GETIFADDRS) && defined(HAVE_IF_NAMETOINDEX)
1953 get_local_interface_id (int family
)
1955 struct ifaddrs
*ifap
= NULL
, *ptr
;
1958 if (getifaddrs (&ifap
)) {
1962 for (ptr
= ifap
; ptr
; ptr
= ptr
->ifa_next
) {
1963 if (!ptr
->ifa_addr
|| !ptr
->ifa_name
)
1965 if (ptr
->ifa_addr
->sa_family
!= family
)
1967 if ((ptr
->ifa_flags
& IFF_LOOPBACK
) != 0)
1969 if ((ptr
->ifa_flags
& IFF_MULTICAST
) == 0)
1972 idx
= if_nametoindex (ptr
->ifa_name
);
1981 get_local_interface_id (int family
)
1987 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
1989 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
)
1991 struct linger linger
;
1992 int system_level
= 0;
1993 int system_name
= 0;
2000 sol_ipv6
= mono_networking_get_ipv6_protocol ();
2001 sol_ip
= mono_networking_get_ip_protocol ();
2003 MONO_ARCH_SAVE_REGS
;
2005 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
2008 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2009 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
) {
2010 system_name
= SO_REUSEADDR
;
2011 int_val
= int_val
? 0 : 1;
2017 *error
= WSAENOPROTOOPT
;
2024 /* Only one of obj_val, byte_val or int_val has data */
2026 MonoClassField
*field
;
2030 case SocketOptionName_Linger
:
2031 /* Dig out "bool enabled" and "int seconds"
2034 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "enabled");
2035 linger
.l_onoff
=*(guint8
*)(((char *)obj_val
)+field
->offset
);
2036 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "seconds");
2037 linger
.l_linger
=*(guint32
*)(((char *)obj_val
)+field
->offset
);
2039 valsize
=sizeof(linger
);
2040 ret
= _wapi_setsockopt (sock
, system_level
,
2041 system_name
, &linger
, valsize
);
2043 case SocketOptionName_AddMembership
:
2044 case SocketOptionName_DropMembership
:
2045 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2047 MonoObject
*address
= NULL
;
2049 if(system_level
== sol_ipv6
) {
2050 struct ipv6_mreq mreq6
;
2055 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2056 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2059 mreq6
.ipv6mr_multiaddr
= ipaddress_to_struct_in6_addr (address
);
2062 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "ifIndex");
2063 mreq6
.ipv6mr_interface
=*(guint64
*)(((char *)obj_val
)+field
->offset
);
2065 #if defined(__APPLE__) || defined(__FreeBSD__)
2069 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2071 * Tests on Windows and Linux show that the multicast group is only
2072 * joined on one NIC when interface = 0, so we simply use the interface
2073 * id from the first non-loopback interface (this is also what
2074 * Dns.GetHostName (string.Empty) would return).
2076 if (!mreq6
.ipv6mr_interface
)
2077 mreq6
.ipv6mr_interface
= get_local_interface_id (AF_INET6
);
2080 ret
= _wapi_setsockopt (sock
, system_level
,
2081 system_name
, &mreq6
,
2083 } else if(system_level
== sol_ip
) {
2084 #ifdef HAVE_STRUCT_IP_MREQN
2085 struct ip_mreqn mreq
= {{0}};
2087 struct ip_mreq mreq
= {{0}};
2088 #endif /* HAVE_STRUCT_IP_MREQN */
2090 /* pain! MulticastOption holds two IPAddress
2091 * members, so I have to dig the value out of
2094 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2095 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2097 /* address might not be defined and if so, set the address to ADDR_ANY.
2100 mreq
.imr_multiaddr
= ipaddress_to_struct_in_addr (address
);
2103 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "local");
2104 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2106 #ifdef HAVE_STRUCT_IP_MREQN
2108 mreq
.imr_address
= ipaddress_to_struct_in_addr (address
);
2111 field
= mono_class_get_field_from_name(obj_val
->vtable
->klass
, "iface_index");
2112 mreq
.imr_ifindex
= *(gint32
*)(((char *)obj_val
)+field
->offset
);
2115 mreq
.imr_interface
= ipaddress_to_struct_in_addr (address
);
2117 #endif /* HAVE_STRUCT_IP_MREQN */
2119 ret
= _wapi_setsockopt (sock
, system_level
,
2125 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2127 /* Cause an exception to be thrown */
2131 } else if (byte_val
!=NULL
) {
2132 int valsize
= mono_array_length (byte_val
);
2133 guchar
*buf
= mono_array_addr (byte_val
, guchar
, 0);
2136 case SocketOptionName_DontLinger
:
2138 linger
.l_onoff
= (*buf
) ? 0 : 1;
2139 linger
.l_linger
= 0;
2140 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &linger
, sizeof (linger
));
2146 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, buf
, valsize
);
2150 /* ReceiveTimeout/SendTimeout get here */
2152 case SocketOptionName_DontLinger
:
2153 linger
.l_onoff
= !int_val
;
2154 linger
.l_linger
= 0;
2155 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &linger
, sizeof (linger
));
2157 case SocketOptionName_MulticastInterface
:
2159 #ifdef HAVE_STRUCT_IP_MREQN
2160 int_val
= GUINT32_FROM_BE (int_val
);
2161 if ((int_val
& 0xff000000) == 0) {
2162 /* int_val is interface index */
2163 struct ip_mreqn mreq
= {{0}};
2164 mreq
.imr_ifindex
= int_val
;
2165 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &mreq
, sizeof (mreq
));
2168 int_val
= GUINT32_TO_BE (int_val
);
2169 #endif /* HAVE_STRUCT_IP_MREQN */
2170 #endif /* HOST_WIN32 */
2171 /* int_val is in_addr */
2172 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &int_val
, sizeof (int_val
));
2174 case SocketOptionName_DontFragment
:
2175 #ifdef HAVE_IP_MTU_DISCOVER
2176 /* Fiddle with the value slightly if we're
2180 int_val
= IP_PMTUDISC_DO
;
2186 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &int_val
, sizeof (int_val
));
2190 if(ret
==SOCKET_ERROR
) {
2191 *error
= WSAGetLastError ();
2195 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock
,
2201 MONO_ARCH_SAVE_REGS
;
2205 /* Currently, the values for how (recv=0, send=1, both=2) match
2208 ret
= _wapi_shutdown (sock
, how
);
2209 if(ret
==SOCKET_ERROR
) {
2210 *error
= WSAGetLastError ();
2215 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock
, gint32 code
,
2217 MonoArray
*output
, gint32
*error
)
2219 glong output_bytes
= 0;
2220 gchar
*i_buffer
, *o_buffer
;
2224 MONO_ARCH_SAVE_REGS
;
2228 if ((guint32
)code
== FIONBIO
) {
2229 /* Invalid command. Must use Socket.Blocking */
2233 if (input
== NULL
) {
2237 i_buffer
= mono_array_addr (input
, gchar
, 0);
2238 i_len
= mono_array_length (input
);
2241 if (output
== NULL
) {
2245 o_buffer
= mono_array_addr (output
, gchar
, 0);
2246 o_len
= mono_array_length (output
);
2249 ret
= WSAIoctl (sock
, code
, i_buffer
, i_len
, o_buffer
, o_len
, &output_bytes
, NULL
, NULL
);
2250 if (ret
== SOCKET_ERROR
) {
2251 *error
= WSAGetLastError ();
2255 return (gint
) output_bytes
;
2259 addrinfo_to_IPHostEntry(MonoAddressInfo
*info
, MonoString
**h_name
,
2260 MonoArray
**h_aliases
,
2261 MonoArray
**h_addr_list
,
2262 gboolean add_local_ips
)
2265 MonoAddressEntry
*ai
= NULL
;
2266 struct in_addr
*local_in
= NULL
;
2268 struct in6_addr
*local_in6
= NULL
;
2272 MonoDomain
*domain
= mono_domain_get ();
2275 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2276 if (add_local_ips
) {
2277 local_in
= (struct in_addr
*) mono_get_local_interfaces (AF_INET
, &nlocal_in
);
2278 local_in6
= (struct in6_addr
*) mono_get_local_interfaces (AF_INET6
, &nlocal_in6
);
2279 if (nlocal_in
|| nlocal_in6
) {
2280 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), nlocal_in
+ nlocal_in6
);
2282 MonoString
*addr_string
;
2286 for (i
= 0; i
< nlocal_in
; i
++) {
2287 inet_ntop (AF_INET
, &local_in
[i
], addr
, sizeof (addr
));
2288 addr_string
= mono_string_new (domain
, addr
);
2289 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2295 MonoString
*addr_string
;
2300 for (i
= 0; i
< nlocal_in6
; i
++) {
2301 ret
= inet_ntop (AF_INET6
, &local_in6
[i
], addr
, sizeof (addr
));
2303 addr_string
= mono_string_new (domain
, addr
);
2304 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2313 mono_free_address_info (info
);
2322 for (count
= 0, ai
= info
->entries
; ai
!= NULL
; ai
= ai
->next
) {
2323 if (ai
->family
!= AF_INET
&& ai
->family
!= AF_INET6
)
2329 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), count
);
2331 for (ai
= info
->entries
, i
= 0; ai
!= NULL
; ai
= ai
->next
) {
2332 MonoString
*addr_string
;
2334 char buffer
[INET6_ADDRSTRLEN
]; /* Max. size for IPv6 */
2336 if((ai
->family
!= PF_INET
) && (ai
->family
!= PF_INET6
)) {
2340 ret
= inet_ntop (ai
->family
, &ai
->address
, buffer
, INET6_ADDRSTRLEN
);
2343 addr_string
=mono_string_new(domain
, buffer
);
2345 addr_string
=mono_string_new(domain
, "");
2348 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2352 if (ai
->canonical_name
!= NULL
) {
2353 *h_name
=mono_string_new(domain
, ai
->canonical_name
);
2355 *h_name
=mono_string_new(domain
, buffer
);
2363 mono_free_address_info (info
);
2370 get_addrinfo_family_hint (void)
2372 switch (get_family_hint ()) {
2373 case PF_UNSPEC
: return MONO_HINT_UNSPECIFIED
;
2374 case PF_INET
: return MONO_HINT_IPV4
;
2376 case PF_INET6
: return MONO_HINT_IPV6
;
2379 g_error ("invalid hint");
2384 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2386 gboolean add_local_ips
= FALSE
;
2387 gchar this_hostname
[256];
2388 MonoAddressInfo
*info
= NULL
;
2391 MONO_ARCH_SAVE_REGS
;
2393 hostname
=mono_string_to_utf8 (host
);
2394 if (*hostname
== '\0') {
2395 add_local_ips
= TRUE
;
2398 if (!add_local_ips
&& gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
2399 if (!strcmp (hostname
, this_hostname
)) {
2400 add_local_ips
= TRUE
;
2405 if (*hostname
&& mono_get_address_info (hostname
, 0, MONO_HINT_CANONICAL_NAME
| get_addrinfo_family_hint (), &info
)) {
2412 return (addrinfo_to_IPHostEntry(info
, h_name
, h_aliases
, h_addr_list
, add_local_ips
));
2415 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString
*addr
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2418 struct sockaddr_in saddr
;
2419 struct sockaddr_in6 saddr6
;
2420 MonoAddressInfo
*info
= NULL
;
2422 char hostname
[NI_MAXHOST
] = {0};
2425 address
= mono_string_to_utf8 (addr
);
2427 if (inet_pton (AF_INET
, address
, &saddr
.sin_addr
) <= 0) {
2428 /* Maybe an ipv6 address */
2429 if (inet_pton (AF_INET6
, address
, &saddr6
.sin6_addr
) <= 0) {
2435 saddr6
.sin6_family
= AF_INET6
;
2440 saddr
.sin_family
= AF_INET
;
2444 if(family
== AF_INET
) {
2445 #if HAVE_SOCKADDR_IN_SIN_LEN
2446 saddr
.sin_len
= sizeof (saddr
);
2448 if(getnameinfo ((struct sockaddr
*)&saddr
, sizeof(saddr
),
2449 hostname
, sizeof(hostname
), NULL
, 0,
2453 } else if(family
== AF_INET6
) {
2454 #if HAVE_SOCKADDR_IN6_SIN_LEN
2455 saddr6
.sin6_len
= sizeof (saddr6
);
2457 if(getnameinfo ((struct sockaddr
*)&saddr6
, sizeof(saddr6
),
2458 hostname
, sizeof(hostname
), NULL
, 0,
2464 if (mono_get_address_info (hostname
, 0, get_addrinfo_family_hint () | MONO_HINT_CANONICAL_NAME
| MONO_HINT_CONFIGURED_ONLY
, &info
))
2467 return(addrinfo_to_IPHostEntry (info
, h_name
, h_aliases
, h_addr_list
, FALSE
));
2470 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostName_internal(MonoString
**h_name
)
2472 gchar hostname
[256];
2475 MONO_ARCH_SAVE_REGS
;
2477 ret
= gethostname (hostname
, sizeof (hostname
));
2482 *h_name
=mono_string_new(mono_domain_get (), hostname
);
2488 ves_icall_System_Net_Sockets_Socket_SendFile (SOCKET sock
, MonoString
*filename
, MonoArray
*pre_buffer
, MonoArray
*post_buffer
, gint flags
)
2492 TRANSMIT_FILE_BUFFERS buffers
;
2494 MONO_ARCH_SAVE_REGS
;
2496 if (filename
== NULL
)
2499 file
= ves_icall_System_IO_MonoIO_Open (filename
, FileMode_Open
, FileAccess_Read
, FileShare_Read
, 0, &error
);
2500 if (file
== INVALID_HANDLE_VALUE
) {
2501 SetLastError (error
);
2505 memset (&buffers
, 0, sizeof (buffers
));
2506 if (pre_buffer
!= NULL
) {
2507 buffers
.Head
= mono_array_addr (pre_buffer
, guchar
, 0);
2508 buffers
.HeadLength
= mono_array_length (pre_buffer
);
2510 if (post_buffer
!= NULL
) {
2511 buffers
.Tail
= mono_array_addr (post_buffer
, guchar
, 0);
2512 buffers
.TailLength
= mono_array_length (post_buffer
);
2515 if (!TransmitFile (sock
, file
, 0, 0, NULL
, &buffers
, flags
)) {
2524 void mono_network_init(void)
2529 err
=WSAStartup(MAKEWORD(2,0), &wsadata
);
2531 g_error("%s: Couldn't initialise networking", __func__
);
2535 LOGDEBUG (g_message("%s: Using socket library: %s", __func__
, wsadata
.szDescription
));
2536 LOGDEBUG (g_message("%s: Socket system status: %s", __func__
, wsadata
.szSystemStatus
));
2539 void mono_network_cleanup(void)
2545 icall_cancel_blocking_socket_operation (MonoThread
*thread
)
2547 MonoInternalThread
*internal
= thread
->internal_thread
;
2549 if (mono_thread_info_new_interrupt_enabled ()) {
2550 mono_thread_info_abort_socket_syscall_for_close ((MonoNativeThreadId
)(gsize
)internal
->tid
);
2553 internal
->ignore_next_signal
= TRUE
;
2554 mono_thread_kill (internal
, mono_thread_get_abort_signal ());
2559 #endif /* #ifndef DISABLE_SOCKETS */