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>
30 #include <sys/socket.h>
31 #include <sys/ioctl.h>
32 #include <netinet/in.h>
33 #include <netinet/tcp.h>
35 #include <arpa/inet.h>
38 #include <mono/metadata/object.h>
39 #include <mono/io-layer/io-layer.h>
40 #include <mono/metadata/socket-io.h>
41 #include <mono/metadata/exception.h>
42 #include <mono/metadata/assembly.h>
43 #include <mono/metadata/appdomain.h>
44 #include <mono/metadata/file-io.h>
45 #include <mono/metadata/threads.h>
46 #include <mono/metadata/threads-types.h>
47 #include <mono/utils/mono-poll.h>
48 /* FIXME change this code to not mess so much with the internals */
49 #include <mono/metadata/class-internals.h>
50 #include <mono/metadata/threadpool-internals.h>
51 #include <mono/metadata/domain-internals.h>
53 #ifdef HAVE_SYS_TIME_H
56 #ifdef HAVE_SYS_IOCTL_H
57 #include <sys/ioctl.h>
66 #ifdef HAVE_SYS_FILIO_H
67 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
69 #ifdef HAVE_SYS_SOCKIO_H
70 #include <sys/sockio.h> /* defines SIOCATMARK */
76 #include "mono/io-layer/socket-wrappers.h"
78 #if defined(HOST_WIN32)
79 /* This is a kludge to make this file build under cygwin:
80 * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
81 * prototypes for some but not all required functions (notably
82 * inet_ntop() is missing), but the libws2_32 library is missing the
83 * actual implementations of these functions.
89 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
92 * Some older versions of libc provide IPV6 support without defining the AI_ADDRCONFIG
93 * flag for getaddrinfo.
96 #define AI_ADDRCONFIG 0
99 static gint32
convert_family(MonoAddressFamily mono_family
)
103 switch(mono_family
) {
104 case AddressFamily_Unknown
:
105 case AddressFamily_ImpLink
:
106 case AddressFamily_Pup
:
107 case AddressFamily_Chaos
:
108 case AddressFamily_Iso
:
109 case AddressFamily_Ecma
:
110 case AddressFamily_DataKit
:
111 case AddressFamily_Ccitt
:
112 case AddressFamily_DataLink
:
113 case AddressFamily_Lat
:
114 case AddressFamily_HyperChannel
:
115 case AddressFamily_NetBios
:
116 case AddressFamily_VoiceView
:
117 case AddressFamily_FireFox
:
118 case AddressFamily_Banyan
:
119 case AddressFamily_Atm
:
120 case AddressFamily_Cluster
:
121 case AddressFamily_Ieee12844
:
122 case AddressFamily_NetworkDesigners
:
123 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family
);
126 case AddressFamily_Unspecified
:
130 case AddressFamily_Unix
:
134 case AddressFamily_InterNetwork
:
138 case AddressFamily_Ipx
:
144 case AddressFamily_Sna
:
150 case AddressFamily_DecNet
:
156 case AddressFamily_AppleTalk
:
160 case AddressFamily_InterNetworkV6
:
165 case AddressFamily_Irda
:
171 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family
);
177 static MonoAddressFamily
convert_to_mono_family(guint16 af_family
)
179 MonoAddressFamily family
=AddressFamily_Unknown
;
183 family
=AddressFamily_Unspecified
;
187 family
=AddressFamily_Unix
;
191 family
=AddressFamily_InterNetwork
;
196 family
=AddressFamily_Ipx
;
202 family
=AddressFamily_Sna
;
208 family
=AddressFamily_DecNet
;
213 family
=AddressFamily_AppleTalk
;
218 family
=AddressFamily_InterNetworkV6
;
224 family
=AddressFamily_Irda
;
228 g_warning("unknown address family 0x%x", af_family
);
234 static gint32
convert_type(MonoSocketType mono_type
)
239 case SocketType_Stream
:
243 case SocketType_Dgram
:
257 case SocketType_Seqpacket
:
261 case SocketType_Unknown
:
262 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type
);
266 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type
);
272 static gint32
convert_proto(MonoProtocolType mono_proto
)
277 case ProtocolType_IP
:
278 case ProtocolType_IPv6
:
279 case ProtocolType_Icmp
:
280 case ProtocolType_Igmp
:
281 case ProtocolType_Ggp
:
282 case ProtocolType_Tcp
:
283 case ProtocolType_Pup
:
284 case ProtocolType_Udp
:
285 case ProtocolType_Idp
:
286 /* These protocols are known (on my system at least) */
290 case ProtocolType_ND
:
291 case ProtocolType_Raw
:
292 case ProtocolType_Ipx
:
293 case ProtocolType_Spx
:
294 case ProtocolType_SpxII
:
295 case ProtocolType_Unknown
:
296 /* These protocols arent */
297 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto
);
307 /* Convert MonoSocketFlags */
308 static gint32
convert_socketflags (gint32 sflags
)
313 /* SocketFlags.None */
316 if (sflags
& ~(SocketFlags_OutOfBand
| SocketFlags_MaxIOVectorLength
| SocketFlags_Peek
|
317 SocketFlags_DontRoute
| SocketFlags_Partial
))
318 /* Contains invalid flag values */
321 if (sflags
& SocketFlags_OutOfBand
)
323 if (sflags
& SocketFlags_Peek
)
325 if (sflags
& SocketFlags_DontRoute
)
326 flags
|= MSG_DONTROUTE
;
328 /* Ignore Partial - see bug 349688. Don't return -1, because
329 * according to the comment in that bug ms runtime doesn't for
330 * UDP sockets (this means we will silently ignore it for TCP
334 if (sflags
& SocketFlags_Partial
)
338 /* Don't do anything for MaxIOVectorLength */
339 if (sflags
& SocketFlags_MaxIOVectorLength
)
347 * 0 on success (mapped mono_level and mono_name to system_level and system_name
349 * -2 on non-fatal error (ie, must ignore)
351 static gint32
convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level
,
352 MonoSocketOptionName mono_name
,
356 switch (mono_level
) {
357 case SocketOptionLevel_Socket
:
358 *system_level
= SOL_SOCKET
;
361 case SocketOptionName_DontLinger
:
362 /* This is SO_LINGER, because the setsockopt
363 * internal call maps DontLinger to SO_LINGER
366 *system_name
= SO_LINGER
;
368 case SocketOptionName_Debug
:
369 *system_name
= SO_DEBUG
;
372 case SocketOptionName_AcceptConnection
:
373 *system_name
= SO_ACCEPTCONN
;
376 case SocketOptionName_ReuseAddress
:
377 *system_name
= SO_REUSEADDR
;
379 case SocketOptionName_KeepAlive
:
380 *system_name
= SO_KEEPALIVE
;
382 case SocketOptionName_DontRoute
:
383 *system_name
= SO_DONTROUTE
;
385 case SocketOptionName_Broadcast
:
386 *system_name
= SO_BROADCAST
;
388 case SocketOptionName_Linger
:
389 *system_name
= SO_LINGER
;
391 case SocketOptionName_OutOfBandInline
:
392 *system_name
= SO_OOBINLINE
;
394 case SocketOptionName_SendBuffer
:
395 *system_name
= SO_SNDBUF
;
397 case SocketOptionName_ReceiveBuffer
:
398 *system_name
= SO_RCVBUF
;
400 case SocketOptionName_SendLowWater
:
401 *system_name
= SO_SNDLOWAT
;
403 case SocketOptionName_ReceiveLowWater
:
404 *system_name
= SO_RCVLOWAT
;
406 case SocketOptionName_SendTimeout
:
407 *system_name
= SO_SNDTIMEO
;
409 case SocketOptionName_ReceiveTimeout
:
410 *system_name
= SO_RCVTIMEO
;
412 case SocketOptionName_Error
:
413 *system_name
= SO_ERROR
;
415 case SocketOptionName_Type
:
416 *system_name
= SO_TYPE
;
419 case SocketOptionName_PeerCred
:
420 *system_name
= SO_PEERCRED
;
423 case SocketOptionName_ExclusiveAddressUse
:
424 #ifdef SO_EXCLUSIVEADDRUSE
425 *system_name
= SO_EXCLUSIVEADDRUSE
;
428 case SocketOptionName_UseLoopback
:
429 #ifdef SO_USELOOPBACK
430 *system_name
= SO_USELOOPBACK
;
433 case SocketOptionName_MaxConnections
:
435 *system_name
= SO_MAXCONN
;
437 #elif defined(SOMAXCONN)
438 *system_name
= SOMAXCONN
;
442 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name
);
447 case SocketOptionLevel_IP
:
449 *system_level
= SOL_IP
;
452 static int cached
= 0;
456 struct protoent
*pent
;
458 pent
= getprotobyname ("IP");
459 proto
= pent
? pent
->p_proto
: 0 /* 0 a good default value?? */;
463 *system_level
= proto
;
465 #endif /* HAVE_SOL_IP */
468 case SocketOptionName_IPOptions
:
469 *system_name
= IP_OPTIONS
;
472 case SocketOptionName_HeaderIncluded
:
473 *system_name
= IP_HDRINCL
;
477 case SocketOptionName_TypeOfService
:
478 *system_name
= IP_TOS
;
482 case SocketOptionName_IpTimeToLive
:
483 *system_name
= IP_TTL
;
486 case SocketOptionName_MulticastInterface
:
487 *system_name
= IP_MULTICAST_IF
;
489 case SocketOptionName_MulticastTimeToLive
:
490 *system_name
= IP_MULTICAST_TTL
;
492 case SocketOptionName_MulticastLoopback
:
493 *system_name
= IP_MULTICAST_LOOP
;
495 case SocketOptionName_AddMembership
:
496 *system_name
= IP_ADD_MEMBERSHIP
;
498 case SocketOptionName_DropMembership
:
499 *system_name
= IP_DROP_MEMBERSHIP
;
501 #ifdef HAVE_IP_PKTINFO
502 case SocketOptionName_PacketInformation
:
503 *system_name
= IP_PKTINFO
;
505 #endif /* HAVE_IP_PKTINFO */
507 case SocketOptionName_DontFragment
:
508 #ifdef HAVE_IP_DONTFRAGMENT
509 *system_name
= IP_DONTFRAGMENT
;
511 #elif defined HAVE_IP_MTU_DISCOVER
512 /* Not quite the same */
513 *system_name
= IP_MTU_DISCOVER
;
516 /* If the flag is not available on this system, we can ignore this error */
518 #endif /* HAVE_IP_DONTFRAGMENT */
519 case SocketOptionName_AddSourceMembership
:
520 case SocketOptionName_DropSourceMembership
:
521 case SocketOptionName_BlockSource
:
522 case SocketOptionName_UnblockSource
:
523 /* Can't figure out how to map these, so fall
527 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name
);
533 case SocketOptionLevel_IPv6
:
535 *system_level
= SOL_IPV6
;
538 static int cached
= 0;
542 struct protoent
*pent
;
544 pent
= getprotobyname ("IPV6");
545 proto
= pent
? pent
->p_proto
: 41 /* 41 a good default value?? */;
549 *system_level
= proto
;
551 #endif /* HAVE_SOL_IPV6 */
554 case SocketOptionName_IpTimeToLive
:
555 case SocketOptionName_HopLimit
:
556 *system_name
= IPV6_UNICAST_HOPS
;
558 case SocketOptionName_MulticastInterface
:
559 *system_name
= IPV6_MULTICAST_IF
;
561 case SocketOptionName_MulticastTimeToLive
:
562 *system_name
= IPV6_MULTICAST_HOPS
;
564 case SocketOptionName_MulticastLoopback
:
565 *system_name
= IPV6_MULTICAST_LOOP
;
567 case SocketOptionName_AddMembership
:
568 *system_name
= IPV6_JOIN_GROUP
;
570 case SocketOptionName_DropMembership
:
571 *system_name
= IPV6_LEAVE_GROUP
;
573 case SocketOptionName_PacketInformation
:
574 #ifdef HAVE_IPV6_PKTINFO
575 *system_name
= IPV6_PKTINFO
;
578 case SocketOptionName_HeaderIncluded
:
579 case SocketOptionName_IPOptions
:
580 case SocketOptionName_TypeOfService
:
581 case SocketOptionName_DontFragment
:
582 case SocketOptionName_AddSourceMembership
:
583 case SocketOptionName_DropSourceMembership
:
584 case SocketOptionName_BlockSource
:
585 case SocketOptionName_UnblockSource
:
586 /* Can't figure out how to map these, so fall
590 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name
);
594 break; /* SocketOptionLevel_IPv6 */
597 case SocketOptionLevel_Tcp
:
599 *system_level
= SOL_TCP
;
602 static int cached
= 0;
606 struct protoent
*pent
;
608 pent
= getprotobyname ("TCP");
609 proto
= pent
? pent
->p_proto
: 6 /* is 6 a good default value?? */;
613 *system_level
= proto
;
615 #endif /* HAVE_SOL_TCP */
618 case SocketOptionName_NoDelay
:
619 *system_name
= TCP_NODELAY
;
622 /* The documentation is talking complete
623 * bollocks here: rfc-1222 is titled
624 * 'Advancing the NSFNET Routing Architecture'
625 * and doesn't mention either of the words
626 * "expedite" or "urgent".
628 case SocketOptionName_BsdUrgent
:
629 case SocketOptionName_Expedited
:
632 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name
);
637 case SocketOptionLevel_Udp
:
638 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level
);
641 case SocketOptionName_NoChecksum
:
642 case SocketOptionName_ChecksumCoverage
:
644 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name
);
651 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level
);
658 static MonoImage
*get_socket_assembly (void)
660 static const char *version
= NULL
;
661 static gboolean moonlight
;
662 MonoDomain
*domain
= mono_domain_get ();
664 if (version
== NULL
) {
665 version
= mono_get_runtime_info ()->framework_version
;
666 moonlight
= !strcmp (version
, "2.1");
669 if (domain
->socket_assembly
== NULL
) {
670 MonoImage
*socket_assembly
;
673 socket_assembly
= mono_image_loaded ("System.Net");
674 if (!socket_assembly
) {
675 MonoAssembly
*sa
= mono_assembly_open ("System.Net.dll", NULL
);
678 g_assert_not_reached ();
680 socket_assembly
= mono_assembly_get_image (sa
);
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
);
696 domain
->socket_assembly
= socket_assembly
;
699 return domain
->socket_assembly
;
703 static gint32
get_family_hint(void)
705 MonoDomain
*domain
= mono_domain_get ();
707 if (!domain
->inet_family_hint
) {
708 MonoClass
*socket_class
;
709 MonoClassField
*ipv6_field
, *ipv4_field
;
710 gint32 ipv6_enabled
= -1, ipv4_enabled
= -1;
713 socket_class
= mono_class_from_name (get_socket_assembly (), "System.Net.Sockets", "Socket");
714 ipv4_field
= mono_class_get_field_from_name (socket_class
, "ipv4Supported");
715 ipv6_field
= mono_class_get_field_from_name (socket_class
, "ipv6Supported");
716 vtable
= mono_class_vtable (mono_domain_get (), socket_class
);
718 mono_runtime_class_init (vtable
);
720 mono_field_static_get_value (vtable
, ipv4_field
, &ipv4_enabled
);
721 mono_field_static_get_value (vtable
, ipv6_field
, &ipv6_enabled
);
723 mono_domain_lock (domain
);
724 if (ipv4_enabled
== 1 && ipv6_enabled
== 1) {
725 domain
->inet_family_hint
= 1;
726 } else if (ipv4_enabled
== 1) {
727 domain
->inet_family_hint
= 2;
729 domain
->inet_family_hint
= 3;
731 mono_domain_unlock (domain
);
733 switch (domain
->inet_family_hint
) {
734 case 1: return PF_UNSPEC
;
735 case 2: return PF_INET
;
736 case 3: return PF_INET6
;
743 gpointer
ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject
*this, gint32 family
, gint32 type
, gint32 proto
, gint32
*error
)
754 sock_family
=convert_family(family
);
755 if(sock_family
==-1) {
756 *error
= WSAEAFNOSUPPORT
;
760 sock_proto
=convert_proto(proto
);
762 *error
= WSAEPROTONOSUPPORT
;
766 sock_type
=convert_type(type
);
768 *error
= WSAESOCKTNOSUPPORT
;
772 sock
= _wapi_socket (sock_family
, sock_type
, sock_proto
,
773 NULL
, 0, WSA_FLAG_OVERLAPPED
);
775 if(sock
==INVALID_SOCKET
) {
776 *error
= WSAGetLastError ();
780 if (sock_family
== AF_INET
&& sock_type
== SOCK_DGRAM
) {
781 return (GUINT_TO_POINTER (sock
));
785 if (sock_family
== AF_INET6
&& sock_type
== SOCK_DGRAM
) {
786 return (GUINT_TO_POINTER (sock
));
790 return(GUINT_TO_POINTER (sock
));
793 /* FIXME: the SOCKET parameter (here and in other functions in this
794 * file) is really an IntPtr which needs to be converted to a guint32.
796 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock
,
801 LOGDEBUG (g_message ("%s: closing 0x%x", __func__
, sock
));
805 /* Clear any pending work item from this socket if the underlying
806 * polling system does not notify when the socket is closed */
807 mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock
));
811 gint32
ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
815 LOGDEBUG (g_message("%s: returning %d", __func__
, WSAGetLastError()));
817 return(WSAGetLastError());
820 gint32
ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock
,
830 ret
=ioctlsocket(sock
, FIONREAD
, &amount
);
831 if(ret
==SOCKET_ERROR
) {
832 *error
= WSAGetLastError ();
839 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock
,
850 * block == TRUE/FALSE means we will block/not block.
851 * But the ioctlsocket call takes TRUE/FALSE for non-block/block
855 ret
= ioctlsocket (sock
, FIONBIO
, (gulong
*) &block
);
856 if(ret
==SOCKET_ERROR
) {
857 *error
= WSAGetLastError ();
861 gpointer
ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock
,
872 MonoInternalThread
* curthread
= mono_thread_internal_current ();
873 curthread
->interrupt_on_stop
= (gpointer
)TRUE
;
874 newsock
= _wapi_accept (sock
, NULL
, 0);
875 curthread
->interrupt_on_stop
= (gpointer
)FALSE
;
878 newsock
= _wapi_accept (sock
, NULL
, 0);
880 if(newsock
==INVALID_SOCKET
) {
881 *error
= WSAGetLastError ();
885 return(GUINT_TO_POINTER (newsock
));
888 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock
,
898 ret
= _wapi_listen (sock
, backlog
);
899 if(ret
==SOCKET_ERROR
) {
900 *error
= WSAGetLastError ();
904 static MonoObject
*create_object_from_sockaddr(struct sockaddr
*saddr
,
905 int sa_size
, gint32
*error
)
907 MonoDomain
*domain
= mono_domain_get ();
908 MonoObject
*sockaddr_obj
;
910 MonoAddressFamily family
;
912 /* Build a System.Net.SocketAddress object instance */
913 if (!domain
->sockaddr_class
) {
914 domain
->sockaddr_class
=mono_class_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
915 g_assert (domain
->sockaddr_class
);
917 sockaddr_obj
=mono_object_new(domain
, domain
->sockaddr_class
);
919 /* Locate the SocketAddress data buffer in the object */
920 if (!domain
->sockaddr_data_field
) {
921 domain
->sockaddr_data_field
=mono_class_get_field_from_name (domain
->sockaddr_class
, "data");
922 g_assert (domain
->sockaddr_data_field
);
925 /* May be the +2 here is too conservative, as sa_len returns
926 * the length of the entire sockaddr_in/in6, including
927 * sizeof (unsigned short) of the family */
928 /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
929 data
=mono_array_new_cached(domain
, mono_get_byte_class (), sa_size
+2);
931 /* The data buffer is laid out as follows:
932 * bytes 0 and 1 are the address family
933 * bytes 2 and 3 are the port info
934 * the rest is the address info
937 family
=convert_to_mono_family(saddr
->sa_family
);
938 if(family
==AddressFamily_Unknown
) {
939 *error
= WSAEAFNOSUPPORT
;
943 mono_array_set(data
, guint8
, 0, family
& 0x0FF);
944 mono_array_set(data
, guint8
, 1, (family
>> 8) & 0x0FF);
946 if(saddr
->sa_family
==AF_INET
) {
947 struct sockaddr_in
*sa_in
=(struct sockaddr_in
*)saddr
;
948 guint16 port
=ntohs(sa_in
->sin_port
);
949 guint32 address
=ntohl(sa_in
->sin_addr
.s_addr
);
952 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
955 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
956 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
957 mono_array_set(data
, guint8
, 4, (address
>>24) & 0xff);
958 mono_array_set(data
, guint8
, 5, (address
>>16) & 0xff);
959 mono_array_set(data
, guint8
, 6, (address
>>8) & 0xff);
960 mono_array_set(data
, guint8
, 7, (address
) & 0xff);
962 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
964 return(sockaddr_obj
);
966 } else if (saddr
->sa_family
== AF_INET6
) {
967 struct sockaddr_in6
*sa_in
=(struct sockaddr_in6
*)saddr
;
970 guint16 port
=ntohs(sa_in
->sin6_port
);
973 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
976 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
977 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
979 for(i
=0; i
<16; i
++) {
980 mono_array_set(data
, guint8
, 8+i
,
981 sa_in
->sin6_addr
.s6_addr
[i
]);
984 mono_array_set(data
, guint8
, 24, sa_in
->sin6_scope_id
& 0xff);
985 mono_array_set(data
, guint8
, 25,
986 (sa_in
->sin6_scope_id
>> 8) & 0xff);
987 mono_array_set(data
, guint8
, 26,
988 (sa_in
->sin6_scope_id
>> 16) & 0xff);
989 mono_array_set(data
, guint8
, 27,
990 (sa_in
->sin6_scope_id
>> 24) & 0xff);
992 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
994 return(sockaddr_obj
);
997 } else if (saddr
->sa_family
== AF_UNIX
) {
1000 for (i
= 0; i
< sa_size
; i
++) {
1001 mono_array_set (data
, guint8
, i
+2, saddr
->sa_data
[i
]);
1004 mono_field_set_value (sockaddr_obj
, domain
->sockaddr_data_field
, data
);
1006 return sockaddr_obj
;
1009 *error
= WSAEAFNOSUPPORT
;
1015 get_sockaddr_size (int family
)
1020 if (family
== AF_INET
) {
1021 size
= sizeof (struct sockaddr_in
);
1023 } else if (family
== AF_INET6
) {
1024 size
= sizeof (struct sockaddr_in6
);
1026 #ifdef HAVE_SYS_UN_H
1027 } else if (family
== AF_UNIX
) {
1028 size
= sizeof (struct sockaddr_un
);
1034 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock
, gint32 af
, gint32
*error
)
1041 MONO_ARCH_SAVE_REGS
;
1045 salen
= get_sockaddr_size (convert_family (af
));
1047 *error
= WSAEAFNOSUPPORT
;
1050 sa
= g_malloc0 (salen
);
1051 ret
= _wapi_getsockname (sock
, (struct sockaddr
*)sa
, &salen
);
1053 if(ret
==SOCKET_ERROR
) {
1054 *error
= WSAGetLastError ();
1059 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
)));
1061 result
= create_object_from_sockaddr((struct sockaddr
*)sa
, salen
, error
);
1066 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock
, gint32 af
, gint32
*error
)
1073 MONO_ARCH_SAVE_REGS
;
1077 salen
= get_sockaddr_size (convert_family (af
));
1079 *error
= WSAEAFNOSUPPORT
;
1082 sa
= g_malloc0 (salen
);
1083 /* Note: linux returns just 2 for AF_UNIX. Always. */
1084 ret
= _wapi_getpeername (sock
, (struct sockaddr
*)sa
, &salen
);
1085 if(ret
==SOCKET_ERROR
) {
1086 *error
= WSAGetLastError ();
1091 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
)));
1093 result
= create_object_from_sockaddr((struct sockaddr
*)sa
, salen
, error
);
1098 static struct sockaddr
*create_sockaddr_from_object(MonoObject
*saddr_obj
,
1102 MonoClassField
*field
;
1107 /* Dig the SocketAddress data buffer out of the object */
1108 field
=mono_class_get_field_from_name(saddr_obj
->vtable
->klass
, "data");
1109 data
=*(MonoArray
**)(((char *)saddr_obj
) + field
->offset
);
1111 /* The data buffer is laid out as follows:
1112 * byte 0 is the address family low byte
1113 * byte 1 is the address family high byte
1115 * bytes 2 and 3 are the port info
1116 * the rest is the address info
1118 * the rest is the file name
1120 len
= mono_array_length (data
);
1122 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1125 family
= convert_family (mono_array_get (data
, guint8
, 0) + (mono_array_get (data
, guint8
, 1) << 8));
1126 if (family
== AF_INET
) {
1127 struct sockaddr_in
*sa
;
1132 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1135 sa
= g_new0 (struct sockaddr_in
, 1);
1136 port
= (mono_array_get (data
, guint8
, 2) << 8) +
1137 mono_array_get (data
, guint8
, 3);
1138 address
= (mono_array_get (data
, guint8
, 4) << 24) +
1139 (mono_array_get (data
, guint8
, 5) << 16 ) +
1140 (mono_array_get (data
, guint8
, 6) << 8) +
1141 mono_array_get (data
, guint8
, 7);
1143 sa
->sin_family
= family
;
1144 sa
->sin_addr
.s_addr
= htonl (address
);
1145 sa
->sin_port
= htons (port
);
1147 *sa_size
= sizeof(struct sockaddr_in
);
1148 return((struct sockaddr
*)sa
);
1151 } else if (family
== AF_INET6
) {
1152 struct sockaddr_in6
*sa
;
1158 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1161 sa
= g_new0 (struct sockaddr_in6
, 1);
1162 port
= mono_array_get (data
, guint8
, 3) +
1163 (mono_array_get (data
, guint8
, 2) << 8);
1164 scopeid
= mono_array_get (data
, guint8
, 24) +
1165 (mono_array_get (data
, guint8
, 25) << 8) +
1166 (mono_array_get (data
, guint8
, 26) << 16) +
1167 (mono_array_get (data
, guint8
, 27) << 24);
1169 sa
->sin6_family
= family
;
1170 sa
->sin6_port
= htons (port
);
1171 sa
->sin6_scope_id
= scopeid
;
1173 for(i
=0; i
<16; i
++) {
1174 sa
->sin6_addr
.s6_addr
[i
] = mono_array_get (data
, guint8
, 8+i
);
1177 *sa_size
= sizeof(struct sockaddr_in6
);
1178 return((struct sockaddr
*)sa
);
1180 #ifdef HAVE_SYS_UN_H
1181 } else if (family
== AF_UNIX
) {
1182 struct sockaddr_un
*sock_un
;
1185 /* Need a byte for the '\0' terminator/prefix, and the first
1186 * two bytes hold the SocketAddress family
1188 if (len
- 2 >= MONO_SIZEOF_SUNPATH
) {
1189 mono_raise_exception (mono_get_exception_index_out_of_range ());
1192 sock_un
= g_new0 (struct sockaddr_un
, 1);
1194 sock_un
->sun_family
= family
;
1195 for (i
= 0; i
< len
- 2; i
++) {
1196 sock_un
->sun_path
[i
] = mono_array_get (data
, guint8
,
1202 return (struct sockaddr
*)sock_un
;
1205 *error
= WSAEAFNOSUPPORT
;
1210 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1212 struct sockaddr
*sa
;
1216 MONO_ARCH_SAVE_REGS
;
1220 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1225 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
)));
1227 ret
= _wapi_bind (sock
, sa
, sa_size
);
1228 if(ret
==SOCKET_ERROR
) {
1229 *error
= WSAGetLastError ();
1242 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock
, gint mode
,
1243 gint timeout
, gint32
*error
)
1245 MonoInternalThread
*thread
= NULL
;
1251 MONO_ARCH_SAVE_REGS
;
1253 pfds
= g_new0 (mono_pollfd
, 1);
1254 pfds
[0].fd
= GPOINTER_TO_INT (sock
);
1255 pfds
[0].events
= (mode
== SelectModeRead
) ? MONO_POLLIN
:
1256 (mode
== SelectModeWrite
) ? MONO_POLLOUT
:
1257 (MONO_POLLERR
| MONO_POLLHUP
| MONO_POLLNVAL
);
1259 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1260 start
= time (NULL
);
1264 ret
= mono_poll (pfds
, 1, timeout
);
1265 if (timeout
> 0 && ret
< 0) {
1267 int sec
= time (NULL
) - start
;
1269 timeout
-= sec
* 1000;
1277 if (ret
== -1 && errno
== EINTR
) {
1280 if (thread
== NULL
) {
1281 thread
= mono_thread_internal_current ();
1284 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1290 /* Suspend requested? */
1291 mono_thread_interruption_checkpoint ();
1295 } while (ret
== -1 && errno
== EINTR
);
1299 *error
= WSAGetLastError ();
1301 *error
= errno_to_WSA (errno
, __func__
);
1316 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1318 struct sockaddr
*sa
;
1322 MONO_ARCH_SAVE_REGS
;
1326 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1331 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
)));
1333 ret
= _wapi_connect (sock
, sa
, sa_size
);
1334 if(ret
==SOCKET_ERROR
) {
1335 *error
= WSAGetLastError ();
1341 /* These #defines from mswsock.h from wine. Defining them here allows
1342 * us to build this file on a mingw box that doesn't know the magic
1343 * numbers, but still run on a newer windows box that does.
1345 #ifndef WSAID_DISCONNECTEX
1346 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1347 typedef BOOL (WINAPI
*LPFN_DISCONNECTEX
)(SOCKET
, LPOVERLAPPED
, DWORD
, DWORD
);
1350 #ifndef WSAID_TRANSMITFILE
1351 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1352 typedef BOOL (WINAPI
*LPFN_TRANSMITFILE
)(SOCKET
, HANDLE
, DWORD
, DWORD
, LPOVERLAPPED
, LPTRANSMIT_FILE_BUFFERS
, DWORD
);
1355 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock
, MonoBoolean reuse
, gint32
*error
)
1358 glong output_bytes
= 0;
1359 GUID disco_guid
= WSAID_DISCONNECTEX
;
1360 GUID trans_guid
= WSAID_TRANSMITFILE
;
1361 LPFN_DISCONNECTEX _wapi_disconnectex
= NULL
;
1362 LPFN_TRANSMITFILE _wapi_transmitfile
= NULL
;
1365 MONO_ARCH_SAVE_REGS
;
1369 LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__
, sock
, reuse
));
1371 /* I _think_ the extension function pointers need to be looked
1372 * up for each socket. FIXME: check the best way to store
1373 * pointers to functions in managed objects that still works
1374 * on 64bit platforms.
1376 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1377 (void *)&disco_guid
, sizeof(GUID
),
1378 (void *)&_wapi_disconnectex
, sizeof(void *),
1379 &output_bytes
, NULL
, NULL
);
1381 /* make sure that WSAIoctl didn't put crap in the
1384 _wapi_disconnectex
= NULL
;
1386 /* Look up the TransmitFile extension function pointer
1387 * instead of calling TransmitFile() directly, because
1388 * apparently "Several of the extension functions have
1389 * been available since WinSock 1.1 and are exported
1390 * from MSWsock.dll, however it's not advisable to
1391 * link directly to this dll as this ties you to the
1392 * Microsoft WinSock provider. A provider neutral way
1393 * of accessing these extension functions is to load
1394 * them dynamically via WSAIoctl using the
1395 * SIO_GET_EXTENSION_FUNCTION_POINTER op code. This
1396 * should, theoretically, allow you to access these
1397 * functions from any provider that supports them..."
1398 * (http://www.codeproject.com/internet/jbsocketserver3.asp)
1400 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1401 (void *)&trans_guid
, sizeof(GUID
),
1402 (void *)&_wapi_transmitfile
, sizeof(void *),
1403 &output_bytes
, NULL
, NULL
);
1405 _wapi_transmitfile
= NULL
;
1409 if (_wapi_disconnectex
!= NULL
) {
1410 bret
= _wapi_disconnectex (sock
, NULL
, TF_REUSE_SOCKET
, 0);
1411 } else if (_wapi_transmitfile
!= NULL
) {
1412 bret
= _wapi_transmitfile (sock
, NULL
, 0, 0, NULL
, NULL
,
1413 TF_DISCONNECT
| TF_REUSE_SOCKET
);
1415 *error
= ERROR_NOT_SUPPORTED
;
1419 if (bret
== FALSE
) {
1420 *error
= WSAGetLastError ();
1424 gint32
ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1431 MONO_ARCH_SAVE_REGS
;
1435 alen
= mono_array_length (buffer
);
1436 if (offset
> alen
- count
) {
1440 buf
=mono_array_addr(buffer
, guchar
, offset
);
1442 recvflags
= convert_socketflags (flags
);
1443 if (recvflags
== -1) {
1444 *error
= WSAEOPNOTSUPP
;
1450 MonoInternalThread
* curthread
= mono_thread_internal_current ();
1451 curthread
->interrupt_on_stop
= (gpointer
)TRUE
;
1452 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1453 curthread
->interrupt_on_stop
= (gpointer
)FALSE
;
1456 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1459 if(ret
==SOCKET_ERROR
) {
1460 *error
= WSAGetLastError ();
1467 gint32
ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1472 DWORD recvflags
= 0;
1474 MONO_ARCH_SAVE_REGS
;
1478 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1479 count
= mono_array_length (buffers
);
1481 recvflags
= convert_socketflags (flags
);
1482 if (recvflags
== -1) {
1483 *error
= WSAEOPNOTSUPP
;
1487 ret
= WSARecv (sock
, wsabufs
, count
, &recv
, &recvflags
, NULL
, NULL
);
1488 if (ret
== SOCKET_ERROR
) {
1489 *error
= WSAGetLastError ();
1496 gint32
ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
**sockaddr
, gint32
*error
)
1502 struct sockaddr
*sa
;
1505 MONO_ARCH_SAVE_REGS
;
1509 alen
= mono_array_length (buffer
);
1510 if (offset
> alen
- count
) {
1514 sa
=create_sockaddr_from_object(*sockaddr
, &sa_size
, error
);
1519 buf
=mono_array_addr(buffer
, guchar
, offset
);
1521 recvflags
= convert_socketflags (flags
);
1522 if (recvflags
== -1) {
1523 *error
= WSAEOPNOTSUPP
;
1527 ret
= _wapi_recvfrom (sock
, buf
, count
, recvflags
, sa
, &sa_size
);
1528 if(ret
==SOCKET_ERROR
) {
1530 *error
= WSAGetLastError ();
1534 /* If we didn't get a socket size, then we're probably a
1535 * connected connection-oriented socket and the stack hasn't
1536 * returned the remote address. All we can do is return null.
1539 *sockaddr
=create_object_from_sockaddr(sa
, sa_size
, error
);
1548 gint32
ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1555 MONO_ARCH_SAVE_REGS
;
1559 alen
= mono_array_length (buffer
);
1560 if (offset
> alen
- count
) {
1564 LOGDEBUG (g_message("%s: alen: %d", __func__
, alen
));
1566 buf
=mono_array_addr(buffer
, guchar
, offset
);
1568 LOGDEBUG (g_message("%s: Sending %d bytes", __func__
, count
));
1570 sendflags
= convert_socketflags (flags
);
1571 if (sendflags
== -1) {
1572 *error
= WSAEOPNOTSUPP
;
1576 ret
= _wapi_send (sock
, buf
, count
, sendflags
);
1577 if(ret
==SOCKET_ERROR
) {
1578 *error
= WSAGetLastError ();
1585 gint32
ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1590 DWORD sendflags
= 0;
1592 MONO_ARCH_SAVE_REGS
;
1596 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1597 count
= mono_array_length (buffers
);
1599 sendflags
= convert_socketflags (flags
);
1600 if (sendflags
== -1) {
1601 *error
= WSAEOPNOTSUPP
;
1605 ret
= WSASend (sock
, wsabufs
, count
, &sent
, sendflags
, NULL
, NULL
);
1606 if (ret
== SOCKET_ERROR
) {
1607 *error
= WSAGetLastError ();
1614 gint32
ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
*sockaddr
, gint32
*error
)
1620 struct sockaddr
*sa
;
1623 MONO_ARCH_SAVE_REGS
;
1627 alen
= mono_array_length (buffer
);
1628 if (offset
> alen
- count
) {
1632 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1637 LOGDEBUG (g_message("%s: alen: %d", __func__
, alen
));
1639 buf
=mono_array_addr(buffer
, guchar
, offset
);
1641 LOGDEBUG (g_message("%s: Sending %d bytes", __func__
, count
));
1643 sendflags
= convert_socketflags (flags
);
1644 if (sendflags
== -1) {
1645 *error
= WSAEOPNOTSUPP
;
1649 ret
= _wapi_sendto (sock
, buf
, count
, sendflags
, sa
, sa_size
);
1650 if(ret
==SOCKET_ERROR
) {
1651 *error
= WSAGetLastError ();
1659 static SOCKET
Socket_to_SOCKET(MonoObject
*sockobj
)
1662 MonoClassField
*field
;
1664 field
=mono_class_get_field_from_name(sockobj
->vtable
->klass
, "socket");
1665 sock
=GPOINTER_TO_INT (*(gpointer
*)(((char *)sockobj
)+field
->offset
));
1670 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1671 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray
**sockets
, gint32 timeout
, gint32
*error
)
1673 MonoInternalThread
*thread
= NULL
;
1680 MonoClass
*sock_arr_class
;
1683 uintptr_t socks_size
;
1685 MONO_ARCH_SAVE_REGS
;
1687 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1688 count
= mono_array_length (*sockets
);
1689 nfds
= count
- 3; /* NULL separators */
1690 pfds
= g_new0 (mono_pollfd
, nfds
);
1692 for (i
= 0; i
< count
; i
++) {
1693 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1700 /* The socket array was bogus */
1706 pfds
[idx
].fd
= Socket_to_SOCKET (obj
);
1707 pfds
[idx
].events
= (mode
== 0) ? MONO_POLLIN
: (mode
== 1) ? MONO_POLLOUT
: POLL_ERRORS
;
1711 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1712 start
= time (NULL
);
1715 ret
= mono_poll (pfds
, nfds
, timeout
);
1716 if (timeout
> 0 && ret
< 0) {
1718 int sec
= time (NULL
) - start
;
1720 timeout
-= sec
* 1000;
1726 if (ret
== -1 && errno
== EINTR
) {
1729 thread
= mono_thread_internal_current ();
1731 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1738 /* Suspend requested? */
1739 mono_thread_interruption_checkpoint ();
1743 } while (ret
== -1 && errno
== EINTR
);
1747 *error
= WSAGetLastError ();
1749 *error
= errno_to_WSA (errno
, __func__
);
1761 sock_arr_class
= ((MonoObject
*)*sockets
)->vtable
->klass
;
1762 socks_size
= ((uintptr_t)ret
) + 3; /* space for the NULL delimiters */
1763 socks
= mono_array_new_full (mono_domain_get (), sock_arr_class
, &socks_size
, NULL
);
1766 for (i
= 0; i
< count
&& ret
> 0; i
++) {
1769 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1776 pfd
= &pfds
[i
- mode
];
1777 if (pfd
->revents
== 0)
1781 if (mode
== 0 && (pfd
->revents
& (MONO_POLLIN
| POLL_ERRORS
)) != 0) {
1782 mono_array_setref (socks
, idx
++, obj
);
1783 } else if (mode
== 1 && (pfd
->revents
& (MONO_POLLOUT
| POLL_ERRORS
)) != 0) {
1784 mono_array_setref (socks
, idx
++, obj
);
1785 } else if ((pfd
->revents
& POLL_ERRORS
) != 0) {
1786 mono_array_setref (socks
, idx
++, obj
);
1794 static MonoObject
* int_to_object (MonoDomain
*domain
, int val
)
1796 return mono_value_box (domain
, mono_get_int32_class (), &val
);
1800 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoObject
**obj_val
, gint32
*error
)
1806 socklen_t valsize
=sizeof(val
);
1807 struct linger linger
;
1808 socklen_t lingersize
=sizeof(linger
);
1810 socklen_t time_ms_size
= sizeof (time_ms
);
1812 # if defined(__OpenBSD__)
1813 struct sockpeercred cred
;
1817 socklen_t credsize
= sizeof(cred
);
1819 MonoDomain
*domain
=mono_domain_get();
1821 MonoClass
*obj_class
;
1822 MonoClassField
*field
;
1824 MONO_ARCH_SAVE_REGS
;
1828 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1829 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
) {
1830 system_level
= SOL_SOCKET
;
1831 system_name
= SO_REUSEADDR
;
1837 ret
= convert_sockopt_level_and_name (level
, name
, &system_level
, &system_name
);
1841 *error
= WSAENOPROTOOPT
;
1845 *obj_val
= int_to_object (domain
, 0);
1849 /* No need to deal with MulticastOption names here, because
1850 * you cant getsockopt AddMembership or DropMembership (the
1851 * int getsockopt will error, causing an exception)
1854 case SocketOptionName_Linger
:
1855 case SocketOptionName_DontLinger
:
1856 ret
= _wapi_getsockopt(sock
, system_level
, system_name
, &linger
,
1860 case SocketOptionName_SendTimeout
:
1861 case SocketOptionName_ReceiveTimeout
:
1862 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, (char *) &time_ms
, &time_ms_size
);
1866 case SocketOptionName_PeerCred
:
1867 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &cred
,
1873 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &val
,
1877 if(ret
==SOCKET_ERROR
) {
1878 *error
= WSAGetLastError ();
1883 case SocketOptionName_Linger
:
1884 /* build a System.Net.Sockets.LingerOption */
1885 obj_class
=mono_class_from_name(get_socket_assembly (),
1886 "System.Net.Sockets",
1888 obj
=mono_object_new(domain
, obj_class
);
1890 /* Locate and set the fields "bool enabled" and "int
1893 field
=mono_class_get_field_from_name(obj_class
, "enabled");
1894 *(guint8
*)(((char *)obj
)+field
->offset
)=linger
.l_onoff
;
1896 field
=mono_class_get_field_from_name(obj_class
, "seconds");
1897 *(guint32
*)(((char *)obj
)+field
->offset
)=linger
.l_linger
;
1901 case SocketOptionName_DontLinger
:
1902 /* construct a bool int in val - true if linger is off */
1903 obj
= int_to_object (domain
, !linger
.l_onoff
);
1906 case SocketOptionName_SendTimeout
:
1907 case SocketOptionName_ReceiveTimeout
:
1908 obj
= int_to_object (domain
, time_ms
);
1912 case SocketOptionName_PeerCred
:
1914 /* build a Mono.Posix.PeerCred+PeerCredData if
1917 static MonoImage
*mono_posix_image
= NULL
;
1918 MonoPeerCredData
*cred_data
;
1920 if (mono_posix_image
== NULL
) {
1921 mono_posix_image
=mono_image_loaded ("Mono.Posix");
1922 if (!mono_posix_image
) {
1923 MonoAssembly
*sa
= mono_assembly_open ("Mono.Posix.dll", NULL
);
1925 *error
= WSAENOPROTOOPT
;
1928 mono_posix_image
= mono_assembly_get_image (sa
);
1933 obj_class
= mono_class_from_name(mono_posix_image
,
1936 obj
= mono_object_new(domain
, obj_class
);
1937 cred_data
= (MonoPeerCredData
*)obj
;
1938 cred_data
->pid
= cred
.pid
;
1939 cred_data
->uid
= cred
.uid
;
1940 cred_data
->gid
= cred
.gid
;
1946 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1947 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
)
1950 obj
= int_to_object (domain
, val
);
1955 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoArray
**byte_val
, gint32
*error
)
1963 MONO_ARCH_SAVE_REGS
;
1967 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1970 *error
= WSAENOPROTOOPT
;
1976 valsize
=mono_array_length(*byte_val
);
1977 buf
=mono_array_addr(*byte_val
, guchar
, 0);
1979 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, buf
, &valsize
);
1980 if(ret
==SOCKET_ERROR
) {
1981 *error
= WSAGetLastError ();
1985 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1986 static struct in_addr
ipaddress_to_struct_in_addr(MonoObject
*ipaddr
)
1988 struct in_addr inaddr
;
1989 MonoClassField
*field
;
1991 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Address");
1993 /* No idea why .net uses a 64bit type to hold a 32bit value...
1995 * Internal value of IPAddess is in little-endian order
1997 inaddr
.s_addr
=GUINT_FROM_LE ((guint32
)*(guint64
*)(((char *)ipaddr
)+field
->offset
));
2003 static struct in6_addr
ipaddress_to_struct_in6_addr(MonoObject
*ipaddr
)
2005 struct in6_addr in6addr
;
2006 MonoClassField
*field
;
2010 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Numbers");
2011 data
=*(MonoArray
**)(((char *)ipaddr
) + field
->offset
);
2013 /* Solaris has only the 8 bit version. */
2015 for(i
=0; i
<8; i
++) {
2016 guint16 s
= mono_array_get (data
, guint16
, i
);
2017 in6addr
.s6_addr
[2 * i
] = (s
>> 8) & 0xff;
2018 in6addr
.s6_addr
[2 * i
+ 1] = s
& 0xff;
2022 in6addr
.s6_addr16
[i
] = mono_array_get (data
, guint16
, i
);
2026 #endif /* AF_INET6 */
2029 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
)
2031 struct linger linger
;
2041 #ifdef HAVE_SOL_IPV6
2042 sol_ipv6
= SOL_IPV6
;
2045 struct protoent
*pent
;
2046 pent
= getprotobyname ("ipv6");
2047 sol_ipv6
= (pent
!= NULL
) ? pent
->p_proto
: 41;
2055 struct protoent
*pent
;
2056 pent
= getprotobyname ("ip");
2057 sol_ip
= (pent
!= NULL
) ? pent
->p_proto
: 0;
2060 #endif /* AF_INET6 */
2062 MONO_ARCH_SAVE_REGS
;
2064 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
2067 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2068 if (level
== SocketOptionLevel_Socket
&& name
== SocketOptionName_ExclusiveAddressUse
) {
2069 system_name
= SO_REUSEADDR
;
2070 int_val
= int_val
? 0 : 1;
2076 *error
= WSAENOPROTOOPT
;
2083 /* Only one of obj_val, byte_val or int_val has data */
2085 MonoClassField
*field
;
2089 case SocketOptionName_Linger
:
2090 /* Dig out "bool enabled" and "int seconds"
2093 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "enabled");
2094 linger
.l_onoff
=*(guint8
*)(((char *)obj_val
)+field
->offset
);
2095 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "seconds");
2096 linger
.l_linger
=*(guint32
*)(((char *)obj_val
)+field
->offset
);
2098 valsize
=sizeof(linger
);
2099 ret
= _wapi_setsockopt (sock
, system_level
,
2100 system_name
, &linger
, valsize
);
2102 case SocketOptionName_AddMembership
:
2103 case SocketOptionName_DropMembership
:
2104 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2106 MonoObject
*address
= NULL
;
2109 if(system_level
== sol_ipv6
) {
2110 struct ipv6_mreq mreq6
;
2115 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2116 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2119 mreq6
.ipv6mr_multiaddr
= ipaddress_to_struct_in6_addr (address
);
2122 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "ifIndex");
2123 mreq6
.ipv6mr_interface
=*(guint64
*)(((char *)obj_val
)+field
->offset
);
2125 ret
= _wapi_setsockopt (sock
, system_level
,
2126 system_name
, &mreq6
,
2128 } else if(system_level
== sol_ip
)
2129 #endif /* AF_INET6 */
2131 #ifdef HAVE_STRUCT_IP_MREQN
2132 struct ip_mreqn mreq
= {{0}};
2134 struct ip_mreq mreq
= {{0}};
2135 #endif /* HAVE_STRUCT_IP_MREQN */
2137 /* pain! MulticastOption holds two IPAddress
2138 * members, so I have to dig the value out of
2141 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2142 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2144 /* address might not be defined and if so, set the address to ADDR_ANY.
2147 mreq
.imr_multiaddr
= ipaddress_to_struct_in_addr (address
);
2150 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "local");
2151 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2153 #ifdef HAVE_STRUCT_IP_MREQN
2155 mreq
.imr_address
= ipaddress_to_struct_in_addr (address
);
2159 mreq
.imr_interface
= ipaddress_to_struct_in_addr (address
);
2161 #endif /* HAVE_STRUCT_IP_MREQN */
2163 ret
= _wapi_setsockopt (sock
, system_level
,
2169 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2171 /* Cause an exception to be thrown */
2175 } else if (byte_val
!=NULL
) {
2176 int valsize
= mono_array_length (byte_val
);
2177 guchar
*buf
= mono_array_addr (byte_val
, guchar
, 0);
2180 case SocketOptionName_DontLinger
:
2182 linger
.l_onoff
= (*buf
) ? 0 : 1;
2183 linger
.l_linger
= 0;
2184 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &linger
, sizeof (linger
));
2190 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, buf
, valsize
);
2194 /* ReceiveTimeout/SendTimeout get here */
2196 case SocketOptionName_DontLinger
:
2197 linger
.l_onoff
= !int_val
;
2198 linger
.l_linger
= 0;
2199 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &linger
, sizeof (linger
));
2201 case SocketOptionName_DontFragment
:
2202 #ifdef HAVE_IP_MTU_DISCOVER
2203 /* Fiddle with the value slightly if we're
2207 int_val
= IP_PMTUDISC_DO
;
2213 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &int_val
, sizeof (int_val
));
2217 if(ret
==SOCKET_ERROR
) {
2218 *error
= WSAGetLastError ();
2222 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock
,
2228 MONO_ARCH_SAVE_REGS
;
2232 /* Currently, the values for how (recv=0, send=1, both=2) match
2235 ret
= _wapi_shutdown (sock
, how
);
2236 if(ret
==SOCKET_ERROR
) {
2237 *error
= WSAGetLastError ();
2242 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock
, gint32 code
,
2244 MonoArray
*output
, gint32
*error
)
2246 glong output_bytes
= 0;
2247 gchar
*i_buffer
, *o_buffer
;
2251 MONO_ARCH_SAVE_REGS
;
2255 if (code
== FIONBIO
) {
2256 /* Invalid command. Must use Socket.Blocking */
2260 if (input
== NULL
) {
2264 i_buffer
= mono_array_addr (input
, gchar
, 0);
2265 i_len
= mono_array_length (input
);
2268 if (output
== NULL
) {
2272 o_buffer
= mono_array_addr (output
, gchar
, 0);
2273 o_len
= mono_array_length (output
);
2276 ret
= WSAIoctl (sock
, code
, i_buffer
, i_len
, o_buffer
, o_len
, &output_bytes
, NULL
, NULL
);
2277 if (ret
== SOCKET_ERROR
) {
2278 *error
= WSAGetLastError ();
2282 return (gint
) output_bytes
;
2285 #ifdef HAVE_SIOCGIFCONF
2287 is_loopback (int family
, void *ad
)
2289 char *ptr
= (char *) ad
;
2291 if (family
== AF_INET
) {
2292 return (ptr
[0] == 127);
2296 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr
*) ptr
));
2303 get_local_ips (int family
, int *nips
)
2305 int addr_size
, offset
, fd
, i
, count
;
2306 int max_ifaces
= 50; /* 50 interfaces should be enough... */
2309 struct ifreq iflags
;
2310 char *result
, *tmp_ptr
;
2311 gboolean ignore_loopback
= FALSE
;
2314 if (family
== AF_INET
) {
2315 addr_size
= sizeof (struct in_addr
);
2316 offset
= G_STRUCT_OFFSET (struct sockaddr_in
, sin_addr
);
2318 } else if (family
== AF_INET6
) {
2319 addr_size
= sizeof (struct in6_addr
);
2320 offset
= G_STRUCT_OFFSET (struct sockaddr_in6
, sin6_addr
);
2326 fd
= socket (family
, SOCK_STREAM
, 0);
2328 ifc
.ifc_len
= max_ifaces
* sizeof (struct ifreq
);
2329 ifc
.ifc_buf
= g_malloc (ifc
.ifc_len
);
2330 if (ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0) {
2332 g_free (ifc
.ifc_buf
);
2336 count
= ifc
.ifc_len
/ sizeof (struct ifreq
);
2339 g_free (ifc
.ifc_buf
);
2344 for (i
= 0, ifr
= ifc
.ifc_req
; i
< *nips
; i
++, ifr
++) {
2345 strcpy (iflags
.ifr_name
, ifr
->ifr_name
);
2346 if (ioctl (fd
, SIOCGIFFLAGS
, &iflags
) < 0) {
2350 if ((iflags
.ifr_flags
& IFF_UP
) == 0) {
2351 ifr
->ifr_name
[0] = '\0';
2355 if ((iflags
.ifr_flags
& IFF_LOOPBACK
) == 0) {
2356 ignore_loopback
= TRUE
;
2361 result
= g_malloc (addr_size
* count
);
2363 for (i
= 0, ifr
= ifc
.ifc_req
; i
< count
; i
++, ifr
++) {
2364 if (ifr
->ifr_name
[0] == '\0') {
2369 if (ignore_loopback
&& is_loopback (family
, ((char *) &ifr
->ifr_addr
) + offset
)) {
2374 memcpy (tmp_ptr
, ((char *) &ifr
->ifr_addr
) + offset
, addr_size
);
2375 tmp_ptr
+= addr_size
;
2378 g_free (ifc
.ifc_buf
);
2383 get_local_ips (int family
, int *nips
)
2389 #endif /* HAVE_SIOCGIFCONF */
2392 static gboolean
hostent_to_IPHostEntry(struct hostent
*he
, MonoString
**h_name
,
2393 MonoArray
**h_aliases
,
2394 MonoArray
**h_addr_list
,
2395 gboolean add_local_ips
)
2397 MonoDomain
*domain
= mono_domain_get ();
2399 struct in_addr
*local_in
= NULL
;
2403 if(he
->h_length
!=4 || he
->h_addrtype
!=AF_INET
) {
2407 *h_name
=mono_string_new(domain
, he
->h_name
);
2409 while(he
->h_aliases
[i
]!=NULL
) {
2413 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), i
);
2415 while(he
->h_aliases
[i
]!=NULL
) {
2418 alias
=mono_string_new(domain
, he
->h_aliases
[i
]);
2419 mono_array_setref (*h_aliases
, i
, alias
);
2422 } else if (!add_local_ips
) {
2426 if (add_local_ips
) {
2427 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2429 *h_addr_list
= mono_array_new(domain
, mono_get_string_class (), nlocal_in
);
2430 for (i
= 0; i
< nlocal_in
; i
++) {
2431 MonoString
*addr_string
;
2432 char addr
[16], *ptr
;
2434 ptr
= (char *) &local_in
[i
];
2435 g_snprintf(addr
, 16, "%u.%u.%u.%u",
2436 (unsigned char) ptr
[0],
2437 (unsigned char) ptr
[1],
2438 (unsigned char) ptr
[2],
2439 (unsigned char) ptr
[3]);
2441 addr_string
= mono_string_new (domain
, addr
);
2442 mono_array_setref (*h_addr_list
, i
, addr_string
);
2447 } else if (he
== NULL
) {
2448 /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */
2449 *h_addr_list
= mono_array_new(domain
, mono_get_string_class (), 1);
2450 mono_array_setref (*h_addr_list
, 0, mono_string_new (domain
, "127.0.0.1"));
2455 if (nlocal_in
== 0 && he
!= NULL
) {
2457 while (he
->h_addr_list
[i
]!=NULL
) {
2461 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), i
);
2463 while(he
->h_addr_list
[i
]!=NULL
) {
2464 MonoString
*addr_string
;
2467 g_snprintf(addr
, 16, "%u.%u.%u.%u",
2468 (unsigned char)he
->h_addr_list
[i
][0],
2469 (unsigned char)he
->h_addr_list
[i
][1],
2470 (unsigned char)he
->h_addr_list
[i
][2],
2471 (unsigned char)he
->h_addr_list
[i
][3]);
2473 addr_string
=mono_string_new(domain
, addr
);
2474 mono_array_setref (*h_addr_list
, i
, addr_string
);
2482 static gboolean
ipaddr_to_IPHostEntry(const char *addr
, MonoString
**h_name
,
2483 MonoArray
**h_aliases
,
2484 MonoArray
**h_addr_list
)
2486 MonoDomain
*domain
= mono_domain_get ();
2488 *h_name
=mono_string_new(domain
, addr
);
2489 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2490 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), 1);
2491 mono_array_setref (*h_addr_list
, 0, *h_name
);
2497 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2498 static gboolean
hostent_to_IPHostEntry2(struct hostent
*he1
,struct hostent
*he2
, MonoString
**h_name
,
2499 MonoArray
**h_aliases
, MonoArray
**h_addr_list
, gboolean add_local_ips
)
2501 MonoDomain
*domain
= mono_domain_get ();
2502 int i
, host_count
, host_index
, family_hint
;
2503 struct in_addr
*local_in
= NULL
;
2505 struct in6_addr
*local_in6
= NULL
;
2507 gboolean from_local
= FALSE
;
2509 family_hint
= get_family_hint ();
2512 * Check if address length and family are correct
2514 if (he1
!= NULL
&& (he1
->h_length
!=4 || he1
->h_addrtype
!=AF_INET
)) {
2518 if (he2
!= NULL
&& (he2
->h_length
!=16 || he2
->h_addrtype
!=AF_INET6
)) {
2523 * Get the aliases and host name from he1 or he2 whichever is
2524 * not null, if he1 is not null then take aliases from he1
2526 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2527 family_hint
== PF_INET
)) {
2528 *h_name
=mono_string_new (domain
, he1
->h_name
);
2531 while(he1
->h_aliases
[i
]!=NULL
) {
2535 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
2538 while(he1
->h_aliases
[i
]!=NULL
) {
2541 alias
=mono_string_new (domain
, he1
->h_aliases
[i
]);
2542 mono_array_setref (*h_aliases
, i
, alias
);
2545 } else if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2546 family_hint
== PF_INET6
)) {
2547 *h_name
=mono_string_new (domain
, he2
->h_name
);
2550 while(he2
->h_aliases
[i
] != NULL
) {
2554 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
2557 while(he2
->h_aliases
[i
]!=NULL
) {
2560 alias
=mono_string_new (domain
, he2
->h_aliases
[i
]);
2561 mono_array_setref (*h_aliases
, i
, alias
);
2564 } else if (!add_local_ips
) {
2569 * Count the number of addresses in he1 + he2
2572 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2573 family_hint
== PF_INET
)) {
2575 while(he1
->h_addr_list
[i
]!=NULL
) {
2581 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2582 family_hint
== PF_INET6
)) {
2584 while(he2
->h_addr_list
[i
]!=NULL
) {
2594 if (add_local_ips
) {
2595 if (family_hint
== PF_UNSPEC
|| family_hint
== PF_INET
)
2596 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2598 if (family_hint
== PF_UNSPEC
|| family_hint
== PF_INET6
)
2599 local_in6
= (struct in6_addr
*) get_local_ips (AF_INET6
, &nlocal_in6
);
2601 if (nlocal_in
|| nlocal_in6
) {
2603 *h_addr_list
= mono_array_new (domain
, mono_get_string_class (),
2604 nlocal_in
+ nlocal_in6
);
2608 for (n
= 0; n
< nlocal_in6
; n
++) {
2609 MonoString
*addr_string
;
2611 char addr
[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2613 ret
= inet_ntop (AF_INET6
, &local_in6
[n
], addr
, sizeof(addr
));
2616 addr_string
= mono_string_new (domain
, addr
);
2617 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2625 for (n
= 0; n
< nlocal_in
; n
++) {
2626 MonoString
*addr_string
;
2628 char addr
[16]; /* INET_ADDRSTRLEN == 16 */
2630 ret
= inet_ntop (AF_INET
, &local_in
[n
], addr
, sizeof(addr
));
2633 addr_string
= mono_string_new (domain
, addr
);
2634 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2642 } else if (he1
== NULL
&& he2
== NULL
) {
2643 /* If requesting "" and there are no other interfaces up, MS returns 127.0.0.1 */
2644 *h_addr_list
= mono_array_new(domain
, mono_get_string_class (), 1);
2645 mono_array_setref (*h_addr_list
, 0, mono_string_new (domain
, "127.0.0.1"));
2655 *h_addr_list
=mono_array_new (domain
, mono_get_string_class (), host_count
);
2657 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2658 family_hint
== PF_INET6
)) {
2660 while(he2
->h_addr_list
[i
] != NULL
) {
2661 MonoString
*addr_string
;
2663 char addr
[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2665 ret
= inet_ntop (AF_INET6
, he2
->h_addr_list
[i
], addr
,
2669 addr_string
= mono_string_new (domain
, addr
);
2670 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2677 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2678 family_hint
== PF_INET
)) {
2680 while(he1
->h_addr_list
[i
] != NULL
) {
2681 MonoString
*addr_string
;
2683 char addr
[16]; /* INET_ADDRSTRLEN == 16 */
2685 ret
= inet_ntop (AF_INET
, he1
->h_addr_list
[i
], addr
,
2689 addr_string
=mono_string_new (domain
, addr
);
2690 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2701 #if defined(AF_INET6)
2703 addrinfo_to_IPHostEntry(struct addrinfo
*info
, MonoString
**h_name
,
2704 MonoArray
**h_aliases
,
2705 MonoArray
**h_addr_list
,
2706 gboolean add_local_ips
)
2709 struct addrinfo
*ai
= NULL
;
2710 struct in_addr
*local_in
= NULL
;
2712 struct in6_addr
*local_in6
= NULL
;
2716 MonoDomain
*domain
= mono_domain_get ();
2719 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2720 if (add_local_ips
) {
2721 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2722 local_in6
= (struct in6_addr
*) get_local_ips (AF_INET6
, &nlocal_in6
);
2723 if (nlocal_in
|| nlocal_in6
) {
2724 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), nlocal_in
+ nlocal_in6
);
2726 MonoString
*addr_string
;
2730 for (i
= 0; i
< nlocal_in
; i
++) {
2731 inet_ntop (AF_INET
, &local_in
[i
], addr
, sizeof (addr
));
2732 addr_string
= mono_string_new (domain
, addr
);
2733 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2739 MonoString
*addr_string
;
2744 for (i
= 0; i
< nlocal_in6
; i
++) {
2745 ret
= inet_ntop (AF_INET6
, &local_in6
[i
], addr
, sizeof (addr
));
2747 addr_string
= mono_string_new (domain
, addr
);
2748 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2757 freeaddrinfo (info
);
2766 for (count
=0, ai
=info
; ai
!=NULL
; ai
=ai
->ai_next
) {
2767 if (ai
->ai_family
!= AF_INET
&& ai
->ai_family
!= AF_INET6
)
2773 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), count
);
2775 for (ai
=info
, i
=0; ai
!=NULL
; ai
=ai
->ai_next
) {
2776 MonoString
*addr_string
;
2778 char buffer
[48]; /* Max. size for IPv6 */
2780 if((ai
->ai_family
!= PF_INET
) && (ai
->ai_family
!= PF_INET6
)) {
2784 if(ai
->ai_family
== PF_INET
) {
2785 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
), buffer
, 16);
2787 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_addr
), buffer
, 48);
2791 addr_string
=mono_string_new(domain
, buffer
);
2793 addr_string
=mono_string_new(domain
, "");
2796 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2800 if (ai
->ai_canonname
!= NULL
) {
2801 *h_name
=mono_string_new(domain
, ai
->ai_canonname
);
2803 *h_name
=mono_string_new(domain
, buffer
);
2819 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2821 gboolean add_local_ips
= FALSE
;
2822 #ifdef HAVE_SIOCGIFCONF
2823 gchar this_hostname
[256];
2825 #if !defined(HAVE_GETHOSTBYNAME2_R)
2826 struct addrinfo
*info
= NULL
, hints
;
2829 MONO_ARCH_SAVE_REGS
;
2831 hostname
=mono_string_to_utf8 (host
);
2832 if (*hostname
== '\0') {
2833 add_local_ips
= TRUE
;
2836 #ifdef HAVE_SIOCGIFCONF
2837 if (!add_local_ips
&& gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
2838 if (!strcmp (hostname
, this_hostname
)) {
2839 add_local_ips
= TRUE
;
2845 memset(&hints
, 0, sizeof(hints
));
2846 hints
.ai_family
= get_family_hint ();
2847 hints
.ai_socktype
= SOCK_STREAM
;
2848 hints
.ai_flags
= AI_CANONNAME
;
2850 if (*hostname
&& getaddrinfo(hostname
, NULL
, &hints
, &info
) == -1) {
2856 return(addrinfo_to_IPHostEntry(info
, h_name
, h_aliases
, h_addr_list
, add_local_ips
));
2858 struct hostent he1
,*hp1
, he2
, *hp2
;
2859 int buffer_size1
, buffer_size2
;
2860 char *buffer1
, *buffer2
;
2862 gboolean return_value
;
2865 MONO_ARCH_SAVE_REGS
;
2867 hostname
=mono_string_to_utf8 (host
);
2868 if (*hostname
== '\0')
2869 add_local_ips
= TRUE
;
2871 #ifdef HAVE_SIOCGIFCONF
2872 if (!add_local_ips
&& gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
2873 if (!strcmp (hostname
, this_hostname
))
2874 add_local_ips
= TRUE
;
2880 buffer1
= g_malloc0(buffer_size1
);
2881 buffer2
= g_malloc0(buffer_size2
);
2885 while (*hostname
&& gethostbyname2_r(hostname
, AF_INET
, &he1
, buffer1
, buffer_size1
,
2886 &hp1
, &herr
) == ERANGE
) {
2888 buffer1
= g_realloc(buffer1
, buffer_size1
);
2891 if (*hostname
&& hp1
== NULL
)
2893 while (gethostbyname2_r(hostname
, AF_INET6
, &he2
, buffer2
,
2894 buffer_size2
, &hp2
, &herr
) == ERANGE
) {
2896 buffer2
= g_realloc(buffer2
, buffer_size2
);
2900 return_value
= hostent_to_IPHostEntry2(hp1
, hp2
, h_name
, h_aliases
,
2901 h_addr_list
, add_local_ips
);
2907 return(return_value
);
2908 #endif /* HAVE_GETHOSTBYNAME2_R */
2910 #else /* AF_INET6 */
2911 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2915 gboolean add_local_ips
= FALSE
;
2916 #ifdef HAVE_SIOCGIFCONF
2917 gchar this_hostname
[256];
2920 MONO_ARCH_SAVE_REGS
;
2922 hostname
=mono_string_to_utf8(host
);
2923 if (*hostname
== '\0')
2924 add_local_ips
= TRUE
;
2925 #ifdef HAVE_SIOCGIFCONF
2926 if (!add_local_ips
&& gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
2927 if (!strcmp (hostname
, this_hostname
))
2928 add_local_ips
= TRUE
;
2935 he
= _wapi_gethostbyname (hostname
);
2937 he
= _wapi_gethostbyname (hostname
);
2941 if (*hostname
&& he
==NULL
)
2944 return(hostent_to_IPHostEntry(he
, h_name
, h_aliases
, h_addr_list
, add_local_ips
));
2946 #endif /* AF_INET6 */
2948 #ifndef HAVE_INET_PTON
2950 inet_pton (int family
, const char *address
, void *inaddrp
)
2952 if (family
== AF_INET
) {
2953 #ifdef HAVE_INET_ATON
2954 struct in_addr inaddr
;
2956 if (!inet_aton (address
, &inaddr
))
2959 memcpy (inaddrp
, &inaddr
, sizeof (struct in_addr
));
2962 /* assume the system has inet_addr(), if it doesn't
2963 have that we're pretty much screwed... */
2966 if (!strcmp (address
, "255.255.255.255")) {
2967 /* special-case hack */
2968 inaddr
= 0xffffffff;
2970 inaddr
= inet_addr (address
);
2972 #define INADDR_NONE ((in_addr_t) -1)
2974 if (inaddr
== INADDR_NONE
)
2978 memcpy (inaddrp
, &inaddr
, sizeof (guint32
));
2980 #endif /* HAVE_INET_ATON */
2985 #endif /* !HAVE_INET_PTON */
2987 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString
*addr
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2992 struct sockaddr_in saddr
;
2993 struct sockaddr_in6 saddr6
;
2994 struct addrinfo
*info
= NULL
, hints
;
2996 char hostname
[1024] = {0};
2999 struct in_addr inaddr
;
3004 address
= mono_string_to_utf8 (addr
);
3007 if (inet_pton (AF_INET
, address
, &saddr
.sin_addr
) <= 0) {
3008 /* Maybe an ipv6 address */
3009 if (inet_pton (AF_INET6
, address
, &saddr6
.sin6_addr
) <= 0) {
3015 saddr6
.sin6_family
= AF_INET6
;
3020 saddr
.sin_family
= AF_INET
;
3024 if(family
== AF_INET
) {
3025 #if HAVE_SOCKADDR_IN_SIN_LEN
3026 saddr
.sin_len
= sizeof (saddr
);
3028 if(getnameinfo ((struct sockaddr
*)&saddr
, sizeof(saddr
),
3029 hostname
, sizeof(hostname
), NULL
, 0,
3033 } else if(family
== AF_INET6
) {
3034 #if HAVE_SOCKADDR_IN6_SIN_LEN
3035 saddr6
.sin6_len
= sizeof (saddr6
);
3037 if(getnameinfo ((struct sockaddr
*)&saddr6
, sizeof(saddr6
),
3038 hostname
, sizeof(hostname
), NULL
, 0,
3044 memset (&hints
, 0, sizeof(hints
));
3045 hints
.ai_family
= get_family_hint ();
3046 hints
.ai_socktype
= SOCK_STREAM
;
3047 hints
.ai_flags
= AI_CANONNAME
| AI_ADDRCONFIG
;
3049 if( getaddrinfo (hostname
, NULL
, &hints
, &info
) == -1 ) {
3053 return(addrinfo_to_IPHostEntry (info
, h_name
, h_aliases
, h_addr_list
, FALSE
));
3055 if (inet_pton (AF_INET
, address
, &inaddr
) <= 0) {
3060 if ((he
= gethostbyaddr ((char *) &inaddr
, sizeof (inaddr
), AF_INET
)) == NULL
) {
3061 ret
= ipaddr_to_IPHostEntry (address
, h_name
, h_aliases
, h_addr_list
);
3063 ret
= hostent_to_IPHostEntry (he
, h_name
, h_aliases
,
3064 h_addr_list
, FALSE
);
3072 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostName_internal(MonoString
**h_name
)
3074 gchar hostname
[256];
3077 MONO_ARCH_SAVE_REGS
;
3079 ret
= gethostname (hostname
, sizeof (hostname
));
3084 *h_name
=mono_string_new(mono_domain_get (), hostname
);
3090 ves_icall_System_Net_Sockets_Socket_SendFile (SOCKET sock
, MonoString
*filename
, MonoArray
*pre_buffer
, MonoArray
*post_buffer
, gint flags
)
3094 TRANSMIT_FILE_BUFFERS buffers
;
3096 MONO_ARCH_SAVE_REGS
;
3098 if (filename
== NULL
)
3101 file
= ves_icall_System_IO_MonoIO_Open (filename
, FileMode_Open
, FileAccess_Read
, FileShare_Read
, 0, &error
);
3102 if (file
== INVALID_HANDLE_VALUE
) {
3103 SetLastError (error
);
3107 memset (&buffers
, 0, sizeof (buffers
));
3108 if (pre_buffer
!= NULL
) {
3109 buffers
.Head
= mono_array_addr (pre_buffer
, guchar
, 0);
3110 buffers
.HeadLength
= mono_array_length (pre_buffer
);
3112 if (post_buffer
!= NULL
) {
3113 buffers
.Tail
= mono_array_addr (post_buffer
, guchar
, 0);
3114 buffers
.TailLength
= mono_array_length (post_buffer
);
3117 if (!TransmitFile (sock
, file
, 0, 0, NULL
, &buffers
, flags
)) {
3126 void mono_network_init(void)
3131 err
=WSAStartup(MAKEWORD(2,0), &wsadata
);
3133 g_error("%s: Couldn't initialise networking", __func__
);
3137 LOGDEBUG (g_message("%s: Using socket library: %s", __func__
, wsadata
.szDescription
));
3138 LOGDEBUG (g_message("%s: Socket system status: %s", __func__
, wsadata
.szSystemStatus
));
3141 void mono_network_cleanup(void)
3147 icall_cancel_blocking_socket_operation (MonoThread
*thread
)
3149 #if !defined(HOST_WIN32) && !defined(__MACH__)
3150 MonoInternalThread
*internal
= thread
->internal_thread
;
3152 internal
->ignore_next_signal
= TRUE
;
3153 mono_thread_kill (internal
, mono_thread_get_abort_signal ());
3157 #endif /* #ifndef DISABLE_SOCKETS */