2 * socket-io.c: Socket IO internal calls
5 * Dick Porter (dick@ximian.com)
6 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 * (C) 2001 Ximian, Inc.
9 * Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
22 #include <mono/metadata/object.h>
23 #include <mono/io-layer/io-layer.h>
24 #include <mono/metadata/socket-io.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/assembly.h>
27 #include <mono/metadata/appdomain.h>
28 #include <mono/metadata/threads.h>
29 #include <mono/metadata/threads-types.h>
30 #include <mono/utils/mono-poll.h>
31 /* FIXME change this code to not mess so much with the internals */
32 #include <mono/metadata/class-internals.h>
33 #include <mono/metadata/threadpool-internals.h>
34 #include <mono/metadata/domain-internals.h>
36 #ifdef HAVE_SYS_TIME_H
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
49 #ifdef HAVE_SYS_FILIO_H
50 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
52 #ifdef HAVE_SYS_SOCKIO_H
53 #include <sys/sockio.h> /* defines SIOCATMARK */
59 #include "mono/io-layer/socket-wrappers.h"
62 /* This is a kludge to make this file build under cygwin:
63 * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
64 * prototypes for some but not all required functions (notably
65 * inet_ntop() is missing), but the libws2_32 library is missing the
66 * actual implementations of these functions.
73 static gint32
convert_family(MonoAddressFamily mono_family
)
78 case AddressFamily_Unknown
:
79 case AddressFamily_ImpLink
:
80 case AddressFamily_Pup
:
81 case AddressFamily_Chaos
:
82 case AddressFamily_Iso
:
83 case AddressFamily_Ecma
:
84 case AddressFamily_DataKit
:
85 case AddressFamily_Ccitt
:
86 case AddressFamily_DataLink
:
87 case AddressFamily_Lat
:
88 case AddressFamily_HyperChannel
:
89 case AddressFamily_NetBios
:
90 case AddressFamily_VoiceView
:
91 case AddressFamily_FireFox
:
92 case AddressFamily_Banyan
:
93 case AddressFamily_Atm
:
94 case AddressFamily_Cluster
:
95 case AddressFamily_Ieee12844
:
96 case AddressFamily_NetworkDesigners
:
97 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family
);
100 case AddressFamily_Unspecified
:
104 case AddressFamily_Unix
:
108 case AddressFamily_InterNetwork
:
112 case AddressFamily_Ipx
:
118 case AddressFamily_Sna
:
122 case AddressFamily_DecNet
:
126 case AddressFamily_AppleTalk
:
130 case AddressFamily_InterNetworkV6
:
135 case AddressFamily_Irda
:
141 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family
);
147 static MonoAddressFamily
convert_to_mono_family(guint16 af_family
)
149 MonoAddressFamily family
=AddressFamily_Unknown
;
153 family
=AddressFamily_Unspecified
;
157 family
=AddressFamily_Unix
;
161 family
=AddressFamily_InterNetwork
;
166 family
=AddressFamily_Ipx
;
171 family
=AddressFamily_Sna
;
175 family
=AddressFamily_DecNet
;
179 family
=AddressFamily_AppleTalk
;
184 family
=AddressFamily_InterNetworkV6
;
190 family
=AddressFamily_Irda
;
194 g_warning("unknown address family 0x%x", af_family
);
200 static gint32
convert_type(MonoSocketType mono_type
)
205 case SocketType_Stream
:
209 case SocketType_Dgram
:
221 case SocketType_Seqpacket
:
225 case SocketType_Unknown
:
226 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type
);
230 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type
);
236 static gint32
convert_proto(MonoProtocolType mono_proto
)
241 case ProtocolType_IP
:
242 case ProtocolType_IPv6
:
243 case ProtocolType_Icmp
:
244 case ProtocolType_Igmp
:
245 case ProtocolType_Ggp
:
246 case ProtocolType_Tcp
:
247 case ProtocolType_Pup
:
248 case ProtocolType_Udp
:
249 case ProtocolType_Idp
:
250 /* These protocols are known (on my system at least) */
254 case ProtocolType_ND
:
255 case ProtocolType_Raw
:
256 case ProtocolType_Ipx
:
257 case ProtocolType_Spx
:
258 case ProtocolType_SpxII
:
259 case ProtocolType_Unknown
:
260 /* These protocols arent */
261 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto
);
271 /* Convert MonoSocketFlags */
272 static gint32
convert_socketflags (gint32 sflags
)
277 /* SocketFlags.None */
280 if (sflags
& ~(SocketFlags_OutOfBand
| SocketFlags_MaxIOVectorLength
| SocketFlags_Peek
|
281 SocketFlags_DontRoute
| SocketFlags_Partial
))
282 /* Contains invalid flag values */
285 if (sflags
& SocketFlags_OutOfBand
)
287 if (sflags
& SocketFlags_Peek
)
289 if (sflags
& SocketFlags_DontRoute
)
290 flags
|= MSG_DONTROUTE
;
292 /* Ignore Partial - see bug 349688. Don't return -1, because
293 * according to the comment in that bug ms runtime doesn't for
294 * UDP sockets (this means we will silently ignore it for TCP
297 if (sflags
& SocketFlags_Partial
)
304 if (sflags
& SocketFlags_MaxIOVectorLength
)
305 /* FIXME: Don't know what to do for MaxIOVectorLength query */
308 return (flags
? flags
: -1);
313 * 0 on success (mapped mono_level and mono_name to system_level and system_name
315 * -2 on non-fatal error (ie, must ignore)
317 static gint32
convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level
,
318 MonoSocketOptionName mono_name
,
322 switch (mono_level
) {
323 case SocketOptionLevel_Socket
:
324 *system_level
= SOL_SOCKET
;
327 case SocketOptionName_DontLinger
:
328 /* This is SO_LINGER, because the setsockopt
329 * internal call maps DontLinger to SO_LINGER
332 *system_name
= SO_LINGER
;
334 case SocketOptionName_Debug
:
335 *system_name
= SO_DEBUG
;
338 case SocketOptionName_AcceptConnection
:
339 *system_name
= SO_ACCEPTCONN
;
342 case SocketOptionName_ReuseAddress
:
343 *system_name
= SO_REUSEADDR
;
345 case SocketOptionName_KeepAlive
:
346 *system_name
= SO_KEEPALIVE
;
348 case SocketOptionName_DontRoute
:
349 *system_name
= SO_DONTROUTE
;
351 case SocketOptionName_Broadcast
:
352 *system_name
= SO_BROADCAST
;
354 case SocketOptionName_Linger
:
355 *system_name
= SO_LINGER
;
357 case SocketOptionName_OutOfBandInline
:
358 *system_name
= SO_OOBINLINE
;
360 case SocketOptionName_SendBuffer
:
361 *system_name
= SO_SNDBUF
;
363 case SocketOptionName_ReceiveBuffer
:
364 *system_name
= SO_RCVBUF
;
366 case SocketOptionName_SendLowWater
:
367 *system_name
= SO_SNDLOWAT
;
369 case SocketOptionName_ReceiveLowWater
:
370 *system_name
= SO_RCVLOWAT
;
372 case SocketOptionName_SendTimeout
:
373 *system_name
= SO_SNDTIMEO
;
375 case SocketOptionName_ReceiveTimeout
:
376 *system_name
= SO_RCVTIMEO
;
378 case SocketOptionName_Error
:
379 *system_name
= SO_ERROR
;
381 case SocketOptionName_Type
:
382 *system_name
= SO_TYPE
;
385 case SocketOptionName_PeerCred
:
386 *system_name
= SO_PEERCRED
;
389 case SocketOptionName_ExclusiveAddressUse
:
390 case SocketOptionName_UseLoopback
:
391 case SocketOptionName_MaxConnections
:
392 /* Can't figure out how to map these, so fall
396 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name
);
401 case SocketOptionLevel_IP
:
403 *system_level
= SOL_IP
;
406 static int cached
= 0;
410 struct protoent
*pent
;
412 pent
= getprotobyname ("IP");
413 proto
= pent
? pent
->p_proto
: 0 /* 0 a good default value?? */;
417 *system_level
= proto
;
419 #endif /* HAVE_SOL_IP */
422 case SocketOptionName_IPOptions
:
423 *system_name
= IP_OPTIONS
;
426 case SocketOptionName_HeaderIncluded
:
427 *system_name
= IP_HDRINCL
;
431 case SocketOptionName_TypeOfService
:
432 *system_name
= IP_TOS
;
436 case SocketOptionName_IpTimeToLive
:
437 *system_name
= IP_TTL
;
440 case SocketOptionName_MulticastInterface
:
441 *system_name
= IP_MULTICAST_IF
;
443 case SocketOptionName_MulticastTimeToLive
:
444 *system_name
= IP_MULTICAST_TTL
;
446 case SocketOptionName_MulticastLoopback
:
447 *system_name
= IP_MULTICAST_LOOP
;
449 case SocketOptionName_AddMembership
:
450 *system_name
= IP_ADD_MEMBERSHIP
;
452 case SocketOptionName_DropMembership
:
453 *system_name
= IP_DROP_MEMBERSHIP
;
455 #ifdef HAVE_IP_PKTINFO
456 case SocketOptionName_PacketInformation
:
457 *system_name
= IP_PKTINFO
;
459 #endif /* HAVE_IP_PKTINFO */
461 case SocketOptionName_DontFragment
:
462 #ifdef HAVE_IP_DONTFRAGMENT
463 *system_name
= IP_DONTFRAGMENT
;
465 #elif defined HAVE_IP_MTU_DISCOVER
466 /* Not quite the same */
467 *system_name
= IP_MTU_DISCOVER
;
470 /* If the flag is not available on this system, we can ignore this error */
472 #endif /* HAVE_IP_DONTFRAGMENT */
473 case SocketOptionName_AddSourceMembership
:
474 case SocketOptionName_DropSourceMembership
:
475 case SocketOptionName_BlockSource
:
476 case SocketOptionName_UnblockSource
:
477 /* Can't figure out how to map these, so fall
481 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name
);
487 case SocketOptionLevel_IPv6
:
489 *system_level
= SOL_IPV6
;
492 static int cached
= 0;
496 struct protoent
*pent
;
498 pent
= getprotobyname ("IPV6");
499 proto
= pent
? pent
->p_proto
: 41 /* 41 a good default value?? */;
503 *system_level
= proto
;
505 #endif /* HAVE_SOL_IPV6 */
508 case SocketOptionName_IpTimeToLive
:
509 *system_name
= IPV6_UNICAST_HOPS
;
511 case SocketOptionName_MulticastInterface
:
512 *system_name
= IPV6_MULTICAST_IF
;
514 case SocketOptionName_MulticastTimeToLive
:
515 *system_name
= IPV6_MULTICAST_HOPS
;
517 case SocketOptionName_MulticastLoopback
:
518 *system_name
= IPV6_MULTICAST_LOOP
;
520 case SocketOptionName_AddMembership
:
521 *system_name
= IPV6_JOIN_GROUP
;
523 case SocketOptionName_DropMembership
:
524 *system_name
= IPV6_LEAVE_GROUP
;
526 case SocketOptionName_PacketInformation
:
527 #ifdef HAVE_IPV6_PKTINFO
528 *system_name
= IPV6_PKTINFO
;
531 case SocketOptionName_HeaderIncluded
:
532 case SocketOptionName_IPOptions
:
533 case SocketOptionName_TypeOfService
:
534 case SocketOptionName_DontFragment
:
535 case SocketOptionName_AddSourceMembership
:
536 case SocketOptionName_DropSourceMembership
:
537 case SocketOptionName_BlockSource
:
538 case SocketOptionName_UnblockSource
:
539 /* Can't figure out how to map these, so fall
543 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name
);
547 break; /* SocketOptionLevel_IPv6 */
550 case SocketOptionLevel_Tcp
:
552 *system_level
= SOL_TCP
;
555 static int cached
= 0;
559 struct protoent
*pent
;
561 pent
= getprotobyname ("TCP");
562 proto
= pent
? pent
->p_proto
: 6 /* is 6 a good default value?? */;
566 *system_level
= proto
;
568 #endif /* HAVE_SOL_TCP */
571 case SocketOptionName_NoDelay
:
572 *system_name
= TCP_NODELAY
;
575 /* The documentation is talking complete
576 * bollocks here: rfc-1222 is titled
577 * 'Advancing the NSFNET Routing Architecture'
578 * and doesn't mention either of the words
579 * "expedite" or "urgent".
581 case SocketOptionName_BsdUrgent
:
582 case SocketOptionName_Expedited
:
585 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name
);
590 case SocketOptionLevel_Udp
:
591 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level
);
594 case SocketOptionName_NoChecksum
:
595 case SocketOptionName_ChecksumCoverage
:
597 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name
);
604 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level
);
611 static MonoImage
*get_socket_assembly (void)
613 static const char *version
= NULL
;
614 static gboolean moonlight
;
615 static MonoImage
*socket_assembly
= NULL
;
617 if (version
== NULL
) {
618 version
= mono_get_runtime_info ()->framework_version
;
619 moonlight
= !strcmp (version
, "2.1");
622 if (socket_assembly
== NULL
) {
624 socket_assembly
= mono_image_loaded ("System.Net");
625 if (!socket_assembly
) {
626 MonoAssembly
*sa
= mono_assembly_open ("System.Net.dll", NULL
);
629 g_assert_not_reached ();
631 socket_assembly
= mono_assembly_get_image (sa
);
635 socket_assembly
= mono_image_loaded ("System");
636 if (!socket_assembly
) {
637 MonoAssembly
*sa
= mono_assembly_open ("System.dll", NULL
);
640 g_assert_not_reached ();
642 socket_assembly
= mono_assembly_get_image (sa
);
648 return(socket_assembly
);
652 static gint32
get_family_hint(void)
654 MonoDomain
*domain
= mono_domain_get ();
656 if (!domain
->inet_family_hint
) {
657 MonoClass
*socket_class
;
658 MonoClassField
*ipv6_field
, *ipv4_field
;
659 gint32 ipv6_enabled
= -1, ipv4_enabled
= -1;
662 socket_class
= mono_class_from_name (get_socket_assembly (), "System.Net.Sockets", "Socket");
663 ipv4_field
= mono_class_get_field_from_name (socket_class
, "ipv4Supported");
664 ipv6_field
= mono_class_get_field_from_name (socket_class
, "ipv6Supported");
665 vtable
= mono_class_vtable (mono_domain_get (), socket_class
);
666 mono_runtime_class_init (vtable
);
668 mono_field_static_get_value (vtable
, ipv4_field
, &ipv4_enabled
);
669 mono_field_static_get_value (vtable
, ipv6_field
, &ipv6_enabled
);
671 mono_domain_lock (domain
);
672 if (ipv4_enabled
== 1 && ipv6_enabled
== 1) {
673 domain
->inet_family_hint
= 1;
674 } else if (ipv4_enabled
== 1) {
675 domain
->inet_family_hint
= 2;
677 domain
->inet_family_hint
= 3;
679 mono_domain_unlock (domain
);
681 switch (domain
->inet_family_hint
) {
682 case 1: return PF_UNSPEC
;
683 case 2: return PF_INET
;
684 case 3: return PF_INET6
;
691 gpointer
ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject
*this, gint32 family
, gint32 type
, gint32 proto
, gint32
*error
)
702 sock_family
=convert_family(family
);
703 if(sock_family
==-1) {
704 *error
= WSAEAFNOSUPPORT
;
708 sock_proto
=convert_proto(proto
);
710 *error
= WSAEPROTONOSUPPORT
;
714 sock_type
=convert_type(type
);
716 *error
= WSAESOCKTNOSUPPORT
;
720 sock
= _wapi_socket (sock_family
, sock_type
, sock_proto
,
721 NULL
, 0, WSA_FLAG_OVERLAPPED
);
723 if(sock
==INVALID_SOCKET
) {
724 *error
= WSAGetLastError ();
728 if (sock_family
== AF_INET
&& sock_type
== SOCK_DGRAM
) {
729 return (GUINT_TO_POINTER (sock
));
733 if (sock_family
== AF_INET6
&& sock_type
== SOCK_DGRAM
) {
734 return (GUINT_TO_POINTER (sock
));
738 return(GUINT_TO_POINTER (sock
));
741 /* FIXME: the SOCKET parameter (here and in other functions in this
742 * file) is really an IntPtr which needs to be converted to a guint32.
744 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock
,
750 g_message (G_GNUC_PRETTY_FUNCTION
": closing 0x%x", sock
);
755 /* Clear any pending work item from this socket if the underlying
756 * polling system does not notify when the socket is closed */
757 mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock
));
761 gint32
ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
766 g_message(G_GNUC_PRETTY_FUNCTION
": returning %d", WSAGetLastError());
769 return(WSAGetLastError());
772 gint32
ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock
,
782 ret
=ioctlsocket(sock
, FIONREAD
, &amount
);
783 if(ret
==SOCKET_ERROR
) {
784 *error
= WSAGetLastError ();
791 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock
,
802 * block == TRUE/FALSE means we will block/not block.
803 * But the ioctlsocket call takes TRUE/FALSE for non-block/block
807 ret
= ioctlsocket (sock
, FIONBIO
, (gulong
*) &block
);
808 if(ret
==SOCKET_ERROR
) {
809 *error
= WSAGetLastError ();
813 gpointer
ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock
,
822 newsock
= _wapi_accept (sock
, NULL
, 0);
823 if(newsock
==INVALID_SOCKET
) {
824 *error
= WSAGetLastError ();
828 return(GUINT_TO_POINTER (newsock
));
831 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock
,
841 ret
= _wapi_listen (sock
, backlog
);
842 if(ret
==SOCKET_ERROR
) {
843 *error
= WSAGetLastError ();
847 static MonoObject
*create_object_from_sockaddr(struct sockaddr
*saddr
,
848 int sa_size
, gint32
*error
)
850 MonoDomain
*domain
= mono_domain_get ();
851 MonoObject
*sockaddr_obj
;
852 MonoClass
*sockaddr_class
;
853 MonoClassField
*field
;
855 MonoAddressFamily family
;
857 /* Build a System.Net.SocketAddress object instance */
858 sockaddr_class
=mono_class_from_name(get_socket_assembly (), "System.Net", "SocketAddress");
859 sockaddr_obj
=mono_object_new(domain
, sockaddr_class
);
861 /* Locate the SocketAddress data buffer in the object */
862 field
=mono_class_get_field_from_name(sockaddr_class
, "data");
864 /* Make sure there is space for the family and size bytes */
866 if (saddr
->sa_family
== AF_UNIX
) {
867 /* sa_len includes the entire sockaddr size, so we don't need the
868 * N bytes (sizeof (unsigned short)) of the family. */
869 data
=mono_array_new(domain
, mono_get_byte_class (), sa_size
);
873 /* May be the +2 here is too conservative, as sa_len returns
874 * the length of the entire sockaddr_in/in6, including
875 * sizeof (unsigned short) of the family */
876 data
=mono_array_new(domain
, mono_get_byte_class (), sa_size
+2);
879 /* The data buffer is laid out as follows:
880 * bytes 0 and 1 are the address family
881 * bytes 2 and 3 are the port info
882 * the rest is the address info
885 family
=convert_to_mono_family(saddr
->sa_family
);
886 if(family
==AddressFamily_Unknown
) {
887 *error
= WSAEAFNOSUPPORT
;
891 mono_array_set(data
, guint8
, 0, family
& 0x0FF);
892 mono_array_set(data
, guint8
, 1, (family
>> 8) & 0x0FF);
894 if(saddr
->sa_family
==AF_INET
) {
895 struct sockaddr_in
*sa_in
=(struct sockaddr_in
*)saddr
;
896 guint16 port
=ntohs(sa_in
->sin_port
);
897 guint32 address
=ntohl(sa_in
->sin_addr
.s_addr
);
900 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
903 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
904 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
905 mono_array_set(data
, guint8
, 4, (address
>>24) & 0xff);
906 mono_array_set(data
, guint8
, 5, (address
>>16) & 0xff);
907 mono_array_set(data
, guint8
, 6, (address
>>8) & 0xff);
908 mono_array_set(data
, guint8
, 7, (address
) & 0xff);
910 mono_field_set_value (sockaddr_obj
, field
, data
);
912 return(sockaddr_obj
);
914 } else if (saddr
->sa_family
== AF_INET6
) {
915 struct sockaddr_in6
*sa_in
=(struct sockaddr_in6
*)saddr
;
918 guint16 port
=ntohs(sa_in
->sin6_port
);
921 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
924 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
925 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
927 for(i
=0; i
<16; i
++) {
928 mono_array_set(data
, guint8
, 8+i
,
929 sa_in
->sin6_addr
.s6_addr
[i
]);
932 mono_array_set(data
, guint8
, 24, sa_in
->sin6_scope_id
& 0xff);
933 mono_array_set(data
, guint8
, 25,
934 (sa_in
->sin6_scope_id
>> 8) & 0xff);
935 mono_array_set(data
, guint8
, 26,
936 (sa_in
->sin6_scope_id
>> 16) & 0xff);
937 mono_array_set(data
, guint8
, 27,
938 (sa_in
->sin6_scope_id
>> 24) & 0xff);
940 mono_field_set_value (sockaddr_obj
, field
, data
);
942 return(sockaddr_obj
);
945 } else if (saddr
->sa_family
== AF_UNIX
) {
948 for (i
= 0; i
< sa_size
; i
++) {
949 mono_array_set (data
, guint8
, i
+2, saddr
->sa_data
[i
]);
952 mono_field_set_value (sockaddr_obj
, field
, data
);
957 *error
= WSAEAFNOSUPPORT
;
962 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock
, gint32
*error
)
964 gchar sa
[32]; /* sockaddr in not big enough for sockaddr_in6 */
973 ret
= _wapi_getsockname (sock
, (struct sockaddr
*)sa
, &salen
);
975 if(ret
==SOCKET_ERROR
) {
976 *error
= WSAGetLastError ();
981 g_message(G_GNUC_PRETTY_FUNCTION
": bound to %s port %d", inet_ntoa(((struct sockaddr_in
*)&sa
)->sin_addr
), ntohs(((struct sockaddr_in
*)&sa
)->sin_port
));
984 return(create_object_from_sockaddr((struct sockaddr
*)sa
, salen
,
988 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock
, gint32
*error
)
990 gchar sa
[32]; /* sockaddr in not big enough for sockaddr_in6 */
999 ret
= _wapi_getpeername (sock
, (struct sockaddr
*)sa
, &salen
);
1001 if(ret
==SOCKET_ERROR
) {
1002 *error
= WSAGetLastError ();
1007 g_message(G_GNUC_PRETTY_FUNCTION
": connected to %s port %d", inet_ntoa(((struct sockaddr_in
*)&sa
)->sin_addr
), ntohs(((struct sockaddr_in
*)&sa
)->sin_port
));
1010 return(create_object_from_sockaddr((struct sockaddr
*)sa
, salen
,
1014 static struct sockaddr
*create_sockaddr_from_object(MonoObject
*saddr_obj
,
1018 MonoClassField
*field
;
1023 /* Dig the SocketAddress data buffer out of the object */
1024 field
=mono_class_get_field_from_name(saddr_obj
->vtable
->klass
, "data");
1025 data
=*(MonoArray
**)(((char *)saddr_obj
) + field
->offset
);
1027 /* The data buffer is laid out as follows:
1028 * byte 0 is the address family low byte
1029 * byte 1 is the address family high byte
1031 * bytes 2 and 3 are the port info
1032 * the rest is the address info
1034 * the rest is the file name
1036 len
= mono_array_length (data
);
1038 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1041 family
= convert_family (mono_array_get (data
, guint8
, 0) + (mono_array_get (data
, guint8
, 1) << 8));
1042 if (family
== AF_INET
) {
1043 struct sockaddr_in
*sa
;
1048 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1051 sa
= g_new0 (struct sockaddr_in
, 1);
1052 port
= (mono_array_get (data
, guint8
, 2) << 8) +
1053 mono_array_get (data
, guint8
, 3);
1054 address
= (mono_array_get (data
, guint8
, 4) << 24) +
1055 (mono_array_get (data
, guint8
, 5) << 16 ) +
1056 (mono_array_get (data
, guint8
, 6) << 8) +
1057 mono_array_get (data
, guint8
, 7);
1059 sa
->sin_family
= family
;
1060 sa
->sin_addr
.s_addr
= htonl (address
);
1061 sa
->sin_port
= htons (port
);
1063 *sa_size
= sizeof(struct sockaddr_in
);
1064 return((struct sockaddr
*)sa
);
1067 } else if (family
== AF_INET6
) {
1068 struct sockaddr_in6
*sa
;
1074 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1077 sa
= g_new0 (struct sockaddr_in6
, 1);
1078 port
= mono_array_get (data
, guint8
, 3) +
1079 (mono_array_get (data
, guint8
, 2) << 8);
1080 scopeid
= mono_array_get (data
, guint8
, 24) +
1081 (mono_array_get (data
, guint8
, 25) << 8) +
1082 (mono_array_get (data
, guint8
, 26) << 16) +
1083 (mono_array_get (data
, guint8
, 27) << 24);
1085 sa
->sin6_family
= family
;
1086 sa
->sin6_port
= htons (port
);
1087 sa
->sin6_scope_id
= scopeid
;
1089 for(i
=0; i
<16; i
++) {
1090 sa
->sin6_addr
.s6_addr
[i
] = mono_array_get (data
, guint8
, 8+i
);
1093 *sa_size
= sizeof(struct sockaddr_in6
);
1094 return((struct sockaddr
*)sa
);
1096 #ifdef HAVE_SYS_UN_H
1097 } else if (family
== AF_UNIX
) {
1098 struct sockaddr_un
*sock_un
;
1101 /* Need a byte for the '\0' terminator/prefix, and the first
1102 * two bytes hold the SocketAddress family
1104 if (len
- 2 >= MONO_SIZEOF_SUNPATH
) {
1105 mono_raise_exception (mono_get_exception_index_out_of_range ());
1108 sock_un
= g_new0 (struct sockaddr_un
, 1);
1110 sock_un
->sun_family
= family
;
1111 for (i
= 0; i
< len
- 2; i
++) {
1112 sock_un
->sun_path
[i
] = mono_array_get (data
, guint8
,
1118 return (struct sockaddr
*)sock_un
;
1121 *error
= WSAEAFNOSUPPORT
;
1126 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1128 struct sockaddr
*sa
;
1132 MONO_ARCH_SAVE_REGS
;
1136 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1142 g_message(G_GNUC_PRETTY_FUNCTION
": binding to %s port %d", inet_ntoa(((struct sockaddr_in
*)sa
)->sin_addr
), ntohs (((struct sockaddr_in
*)sa
)->sin_port
));
1145 ret
= _wapi_bind (sock
, sa
, sa_size
);
1146 if(ret
==SOCKET_ERROR
) {
1147 *error
= WSAGetLastError ();
1160 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock
, gint mode
,
1161 gint timeout
, gint32
*error
)
1163 MonoThread
*thread
= NULL
;
1169 MONO_ARCH_SAVE_REGS
;
1171 pfds
= g_new0 (mono_pollfd
, 1);
1172 pfds
[0].fd
= GPOINTER_TO_INT (sock
);
1173 pfds
[0].events
= (mode
== SelectModeRead
) ? MONO_POLLIN
:
1174 (mode
== SelectModeWrite
) ? MONO_POLLOUT
:
1175 (MONO_POLLERR
| MONO_POLLHUP
| MONO_POLLNVAL
);
1177 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1178 start
= time (NULL
);
1182 ret
= mono_poll (pfds
, 1, timeout
);
1183 if (timeout
> 0 && ret
< 0) {
1185 int sec
= time (NULL
) - start
;
1187 timeout
-= sec
* 1000;
1195 if (ret
== -1 && errno
== EINTR
) {
1198 if (thread
== NULL
) {
1199 thread
= mono_thread_current ();
1202 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1208 /* Suspend requested? */
1209 mono_thread_interruption_checkpoint ();
1213 } while (ret
== -1 && errno
== EINTR
);
1216 #ifdef PLATFORM_WIN32
1217 *error
= WSAGetLastError ();
1219 *error
= errno_to_WSA (errno
, __func__
);
1234 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1236 struct sockaddr
*sa
;
1240 MONO_ARCH_SAVE_REGS
;
1244 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1250 g_message(G_GNUC_PRETTY_FUNCTION
": connecting to %s port %d", inet_ntoa(((struct sockaddr_in
*)sa
)->sin_addr
), ntohs (((struct sockaddr_in
*)sa
)->sin_port
));
1253 ret
= _wapi_connect (sock
, sa
, sa_size
);
1254 if(ret
==SOCKET_ERROR
) {
1255 *error
= WSAGetLastError ();
1261 /* These #defines from mswsock.h from wine. Defining them here allows
1262 * us to build this file on a mingw box that doesn't know the magic
1263 * numbers, but still run on a newer windows box that does.
1265 #ifndef WSAID_DISCONNECTEX
1266 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1267 typedef BOOL (WINAPI
*LPFN_DISCONNECTEX
)(SOCKET
, LPOVERLAPPED
, DWORD
, DWORD
);
1270 #ifndef WSAID_TRANSMITFILE
1271 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1272 typedef BOOL (WINAPI
*LPFN_TRANSMITFILE
)(SOCKET
, HANDLE
, DWORD
, DWORD
, LPOVERLAPPED
, LPTRANSMIT_FILE_BUFFERS
, DWORD
);
1275 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock
, MonoBoolean reuse
, gint32
*error
)
1278 glong output_bytes
= 0;
1279 GUID disco_guid
= WSAID_DISCONNECTEX
;
1280 GUID trans_guid
= WSAID_TRANSMITFILE
;
1281 LPFN_DISCONNECTEX _wapi_disconnectex
= NULL
;
1282 LPFN_TRANSMITFILE _wapi_transmitfile
= NULL
;
1285 MONO_ARCH_SAVE_REGS
;
1290 g_message("%s: disconnecting from socket %p (reuse %d)", __func__
,
1294 /* I _think_ the extension function pointers need to be looked
1295 * up for each socket. FIXME: check the best way to store
1296 * pointers to functions in managed objects that still works
1297 * on 64bit platforms.
1299 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1300 (void *)&disco_guid
, sizeof(GUID
),
1301 (void *)&_wapi_disconnectex
, sizeof(void *),
1302 &output_bytes
, NULL
, NULL
);
1304 /* make sure that WSAIoctl didn't put crap in the
1307 _wapi_disconnectex
= NULL
;
1309 /* Look up the TransmitFile extension function pointer
1310 * instead of calling TransmitFile() directly, because
1311 * apparently "Several of the extension functions have
1312 * been available since WinSock 1.1 and are exported
1313 * from MSWsock.dll, however it's not advisable to
1314 * link directly to this dll as this ties you to the
1315 * Microsoft WinSock provider. A provider neutral way
1316 * of accessing these extension functions is to load
1317 * them dynamically via WSAIoctl using the
1318 * SIO_GET_EXTENSION_FUNCTION_POINTER op code. This
1319 * should, theoretically, allow you to access these
1320 * functions from any provider that supports them..."
1321 * (http://www.codeproject.com/internet/jbsocketserver3.asp)
1323 ret
= WSAIoctl (sock
, SIO_GET_EXTENSION_FUNCTION_POINTER
,
1324 (void *)&trans_guid
, sizeof(GUID
),
1325 (void *)&_wapi_transmitfile
, sizeof(void *),
1326 &output_bytes
, NULL
, NULL
);
1328 _wapi_transmitfile
= NULL
;
1332 if (_wapi_disconnectex
!= NULL
) {
1333 bret
= _wapi_disconnectex (sock
, NULL
, TF_REUSE_SOCKET
, 0);
1334 } else if (_wapi_transmitfile
!= NULL
) {
1335 bret
= _wapi_transmitfile (sock
, NULL
, 0, 0, NULL
, NULL
,
1336 TF_DISCONNECT
| TF_REUSE_SOCKET
);
1338 *error
= ERROR_NOT_SUPPORTED
;
1342 if (bret
== FALSE
) {
1343 *error
= WSAGetLastError ();
1347 gint32
ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1354 MONO_ARCH_SAVE_REGS
;
1358 alen
= mono_array_length (buffer
);
1359 if (offset
> alen
- count
) {
1363 buf
=mono_array_addr(buffer
, guchar
, offset
);
1365 recvflags
= convert_socketflags (flags
);
1366 if (recvflags
== -1) {
1367 *error
= WSAEOPNOTSUPP
;
1371 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1372 if(ret
==SOCKET_ERROR
) {
1373 *error
= WSAGetLastError ();
1380 gint32
ves_icall_System_Net_Sockets_Socket_Receive_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1385 DWORD recvflags
= 0;
1387 MONO_ARCH_SAVE_REGS
;
1391 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1392 count
= mono_array_length (buffers
);
1394 recvflags
= convert_socketflags (flags
);
1395 if (recvflags
== -1) {
1396 *error
= WSAEOPNOTSUPP
;
1400 ret
= WSARecv (sock
, wsabufs
, count
, &recv
, &recvflags
, NULL
, NULL
);
1401 if (ret
== SOCKET_ERROR
) {
1402 *error
= WSAGetLastError ();
1409 gint32
ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
**sockaddr
, gint32
*error
)
1415 struct sockaddr
*sa
;
1418 MONO_ARCH_SAVE_REGS
;
1422 alen
= mono_array_length (buffer
);
1423 if (offset
> alen
- count
) {
1427 sa
=create_sockaddr_from_object(*sockaddr
, &sa_size
, error
);
1432 buf
=mono_array_addr(buffer
, guchar
, offset
);
1434 recvflags
= convert_socketflags (flags
);
1435 if (recvflags
== -1) {
1436 *error
= WSAEOPNOTSUPP
;
1440 ret
= _wapi_recvfrom (sock
, buf
, count
, recvflags
, sa
, &sa_size
);
1441 if(ret
==SOCKET_ERROR
) {
1443 *error
= WSAGetLastError ();
1447 /* If we didn't get a socket size, then we're probably a
1448 * connected connection-oriented socket and the stack hasn't
1449 * returned the remote address. All we can do is return null.
1452 *sockaddr
=create_object_from_sockaddr(sa
, sa_size
, error
);
1461 gint32
ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1468 MONO_ARCH_SAVE_REGS
;
1472 alen
= mono_array_length (buffer
);
1473 if (offset
> alen
- count
) {
1478 g_message(G_GNUC_PRETTY_FUNCTION
": alen: %d", alen
);
1481 buf
=mono_array_addr(buffer
, guchar
, offset
);
1484 g_message(G_GNUC_PRETTY_FUNCTION
": Sending %d bytes", count
);
1487 sendflags
= convert_socketflags (flags
);
1488 if (sendflags
== -1) {
1489 *error
= WSAEOPNOTSUPP
;
1493 ret
= _wapi_send (sock
, buf
, count
, sendflags
);
1494 if(ret
==SOCKET_ERROR
) {
1495 *error
= WSAGetLastError ();
1502 gint32
ves_icall_System_Net_Sockets_Socket_Send_array_internal(SOCKET sock
, MonoArray
*buffers
, gint32 flags
, gint32
*error
)
1507 DWORD sendflags
= 0;
1509 MONO_ARCH_SAVE_REGS
;
1513 wsabufs
= mono_array_addr (buffers
, WSABUF
, 0);
1514 count
= mono_array_length (buffers
);
1516 sendflags
= convert_socketflags (flags
);
1517 if (sendflags
== -1) {
1518 *error
= WSAEOPNOTSUPP
;
1522 ret
= WSASend (sock
, wsabufs
, count
, &sent
, sendflags
, NULL
, NULL
);
1523 if (ret
== SOCKET_ERROR
) {
1524 *error
= WSAGetLastError ();
1531 gint32
ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
*sockaddr
, gint32
*error
)
1537 struct sockaddr
*sa
;
1540 MONO_ARCH_SAVE_REGS
;
1544 alen
= mono_array_length (buffer
);
1545 if (offset
> alen
- count
) {
1549 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1555 g_message(G_GNUC_PRETTY_FUNCTION
": alen: %d", alen
);
1558 buf
=mono_array_addr(buffer
, guchar
, offset
);
1561 g_message(G_GNUC_PRETTY_FUNCTION
": Sending %d bytes", count
);
1564 sendflags
= convert_socketflags (flags
);
1565 if (sendflags
== -1) {
1566 *error
= WSAEOPNOTSUPP
;
1570 ret
= _wapi_sendto (sock
, buf
, count
, sendflags
, sa
, sa_size
);
1571 if(ret
==SOCKET_ERROR
) {
1572 *error
= WSAGetLastError ();
1580 static SOCKET
Socket_to_SOCKET(MonoObject
*sockobj
)
1583 MonoClassField
*field
;
1585 field
=mono_class_get_field_from_name(sockobj
->vtable
->klass
, "socket");
1586 sock
=GPOINTER_TO_INT (*(gpointer
*)(((char *)sockobj
)+field
->offset
));
1591 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1592 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray
**sockets
, gint32 timeout
, gint32
*error
)
1594 MonoThread
*thread
= NULL
;
1601 MonoClass
*sock_arr_class
;
1604 mono_array_size_t socks_size
;
1606 MONO_ARCH_SAVE_REGS
;
1608 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1609 count
= mono_array_length (*sockets
);
1610 nfds
= count
- 3; /* NULL separators */
1611 pfds
= g_new0 (mono_pollfd
, nfds
);
1613 for (i
= 0; i
< count
; i
++) {
1614 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1621 /* The socket array was bogus */
1627 pfds
[idx
].fd
= Socket_to_SOCKET (obj
);
1628 pfds
[idx
].events
= (mode
== 0) ? MONO_POLLIN
: (mode
== 1) ? MONO_POLLOUT
: POLL_ERRORS
;
1632 timeout
= (timeout
>= 0) ? (timeout
/ 1000) : -1;
1633 start
= time (NULL
);
1636 ret
= mono_poll (pfds
, nfds
, timeout
);
1637 if (timeout
> 0 && ret
< 0) {
1639 int sec
= time (NULL
) - start
;
1641 timeout
-= sec
* 1000;
1647 if (ret
== -1 && errno
== EINTR
) {
1650 thread
= mono_thread_current ();
1652 leave
= mono_thread_test_state (thread
, ThreadState_AbortRequested
| ThreadState_StopRequested
);
1659 /* Suspend requested? */
1660 mono_thread_interruption_checkpoint ();
1664 } while (ret
== -1 && errno
== EINTR
);
1667 #ifdef PLATFORM_WIN32
1668 *error
= WSAGetLastError ();
1670 *error
= errno_to_WSA (errno
, __func__
);
1682 sock_arr_class
= ((MonoObject
*)*sockets
)->vtable
->klass
;
1683 socks_size
= ((mono_array_size_t
)ret
) + 3; /* space for the NULL delimiters */
1684 socks
= mono_array_new_full (mono_domain_get (), sock_arr_class
, &socks_size
, NULL
);
1687 for (i
= 0; i
< count
&& ret
> 0; i
++) {
1690 obj
= mono_array_get (*sockets
, MonoObject
*, i
);
1697 pfd
= &pfds
[i
- mode
];
1698 if (pfd
->revents
== 0)
1702 if (mode
== 0 && (pfd
->revents
& (MONO_POLLIN
| POLL_ERRORS
)) != 0) {
1703 mono_array_setref (socks
, idx
++, obj
);
1704 } else if (mode
== 1 && (pfd
->revents
& (MONO_POLLOUT
| POLL_ERRORS
)) != 0) {
1705 mono_array_setref (socks
, idx
++, obj
);
1706 } else if ((pfd
->revents
& POLL_ERRORS
) != 0) {
1707 mono_array_setref (socks
, idx
++, obj
);
1715 static MonoObject
* int_to_object (MonoDomain
*domain
, int val
)
1717 return mono_value_box (domain
, mono_get_int32_class (), &val
);
1721 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoObject
**obj_val
, gint32
*error
)
1727 socklen_t valsize
=sizeof(val
);
1728 struct linger linger
;
1729 socklen_t lingersize
=sizeof(linger
);
1731 socklen_t time_ms_size
= sizeof (time_ms
);
1734 socklen_t credsize
= sizeof(cred
);
1736 MonoDomain
*domain
=mono_domain_get();
1738 MonoClass
*obj_class
;
1739 MonoClassField
*field
;
1741 MONO_ARCH_SAVE_REGS
;
1745 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1748 *error
= WSAENOPROTOOPT
;
1752 *obj_val
= int_to_object (domain
, 0);
1756 /* No need to deal with MulticastOption names here, because
1757 * you cant getsockopt AddMembership or DropMembership (the
1758 * int getsockopt will error, causing an exception)
1761 case SocketOptionName_Linger
:
1762 case SocketOptionName_DontLinger
:
1763 ret
= _wapi_getsockopt(sock
, system_level
, system_name
, &linger
,
1767 case SocketOptionName_SendTimeout
:
1768 case SocketOptionName_ReceiveTimeout
:
1769 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, (char *) &time_ms
, &time_ms_size
);
1773 case SocketOptionName_PeerCred
:
1774 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &cred
,
1780 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &val
,
1784 if(ret
==SOCKET_ERROR
) {
1785 *error
= WSAGetLastError ();
1790 case SocketOptionName_Linger
:
1791 /* build a System.Net.Sockets.LingerOption */
1792 obj_class
=mono_class_from_name(get_socket_assembly (),
1793 "System.Net.Sockets",
1795 obj
=mono_object_new(domain
, obj_class
);
1797 /* Locate and set the fields "bool enabled" and "int
1800 field
=mono_class_get_field_from_name(obj_class
, "enabled");
1801 *(guint8
*)(((char *)obj
)+field
->offset
)=linger
.l_onoff
;
1803 field
=mono_class_get_field_from_name(obj_class
, "seconds");
1804 *(guint32
*)(((char *)obj
)+field
->offset
)=linger
.l_linger
;
1808 case SocketOptionName_DontLinger
:
1809 /* construct a bool int in val - true if linger is off */
1810 obj
= int_to_object (domain
, !linger
.l_onoff
);
1813 case SocketOptionName_SendTimeout
:
1814 case SocketOptionName_ReceiveTimeout
:
1815 obj
= int_to_object (domain
, time_ms
);
1819 case SocketOptionName_PeerCred
:
1821 /* build a Mono.Posix.PeerCred+PeerCredData if
1824 static MonoImage
*mono_posix_image
= NULL
;
1825 MonoPeerCredData
*cred_data
;
1827 if (mono_posix_image
== NULL
) {
1828 mono_posix_image
=mono_image_loaded ("Mono.Posix");
1829 if (!mono_posix_image
) {
1830 MonoAssembly
*sa
= mono_assembly_open ("Mono.Posix.dll", NULL
);
1832 *error
= WSAENOPROTOOPT
;
1835 mono_posix_image
= mono_assembly_get_image (sa
);
1840 obj_class
= mono_class_from_name(mono_posix_image
,
1843 obj
= mono_object_new(domain
, obj_class
);
1844 cred_data
= (MonoPeerCredData
*)obj
;
1845 cred_data
->pid
= cred
.pid
;
1846 cred_data
->uid
= cred
.uid
;
1847 cred_data
->gid
= cred
.gid
;
1853 obj
= int_to_object (domain
, val
);
1859 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoArray
**byte_val
, gint32
*error
)
1867 MONO_ARCH_SAVE_REGS
;
1871 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1874 *error
= WSAENOPROTOOPT
;
1880 valsize
=mono_array_length(*byte_val
);
1881 buf
=mono_array_addr(*byte_val
, guchar
, 0);
1883 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, buf
, &valsize
);
1884 if(ret
==SOCKET_ERROR
) {
1885 *error
= WSAGetLastError ();
1889 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1890 static struct in_addr
ipaddress_to_struct_in_addr(MonoObject
*ipaddr
)
1892 struct in_addr inaddr
;
1893 MonoClassField
*field
;
1895 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Address");
1897 /* No idea why .net uses a 64bit type to hold a 32bit value...
1899 * Internal value of IPAddess is in little-endian order
1901 inaddr
.s_addr
=GUINT_FROM_LE ((guint32
)*(guint64
*)(((char *)ipaddr
)+field
->offset
));
1908 static struct in6_addr
ipaddress_to_struct_in6_addr(MonoObject
*ipaddr
)
1910 struct in6_addr in6addr
;
1911 MonoClassField
*field
;
1915 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "m_Numbers");
1916 data
=*(MonoArray
**)(((char *)ipaddr
) + field
->offset
);
1918 /* Solaris has only the 8 bit version. */
1920 for(i
=0; i
<8; i
++) {
1921 guint16 s
= mono_array_get (data
, guint16
, i
);
1922 in6addr
.s6_addr
[2 * i
] = (s
>> 8) & 0xff;
1923 in6addr
.s6_addr
[2 * i
+ 1] = s
& 0xff;
1927 in6addr
.s6_addr16
[i
] = mono_array_get (data
, guint16
, i
);
1931 #endif /* AF_INET6 */
1933 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
)
1944 #ifdef HAVE_SOL_IPV6
1945 sol_ipv6
= SOL_IPV6
;
1948 struct protoent
*pent
;
1949 pent
= getprotobyname ("ipv6");
1950 sol_ipv6
= (pent
!= NULL
) ? pent
->p_proto
: 41;
1958 struct protoent
*pent
;
1959 pent
= getprotobyname ("ip");
1960 sol_ip
= (pent
!= NULL
) ? pent
->p_proto
: 0;
1963 #endif /* AF_INET6 */
1965 MONO_ARCH_SAVE_REGS
;
1967 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1970 *error
= WSAENOPROTOOPT
;
1977 /* Only one of obj_val, byte_val or int_val has data */
1979 MonoClassField
*field
;
1980 struct linger linger
;
1984 case SocketOptionName_DontLinger
:
1987 valsize
=sizeof(linger
);
1988 ret
= _wapi_setsockopt (sock
, system_level
,
1989 system_name
, &linger
, valsize
);
1992 case SocketOptionName_Linger
:
1993 /* Dig out "bool enabled" and "int seconds"
1996 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "enabled");
1997 linger
.l_onoff
=*(guint8
*)(((char *)obj_val
)+field
->offset
);
1998 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "seconds");
1999 linger
.l_linger
=*(guint32
*)(((char *)obj_val
)+field
->offset
);
2001 valsize
=sizeof(linger
);
2002 ret
= _wapi_setsockopt (sock
, system_level
,
2003 system_name
, &linger
, valsize
);
2005 case SocketOptionName_AddMembership
:
2006 case SocketOptionName_DropMembership
:
2007 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2009 MonoObject
*address
= NULL
;
2012 if(system_level
== sol_ipv6
) {
2013 struct ipv6_mreq mreq6
;
2018 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2019 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2022 mreq6
.ipv6mr_multiaddr
= ipaddress_to_struct_in6_addr (address
);
2025 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "ifIndex");
2026 mreq6
.ipv6mr_interface
=*(guint64
*)(((char *)obj_val
)+field
->offset
);
2028 ret
= _wapi_setsockopt (sock
, system_level
,
2029 system_name
, &mreq6
,
2031 } else if(system_level
== sol_ip
)
2032 #endif /* AF_INET6 */
2034 #ifdef HAVE_STRUCT_IP_MREQN
2035 struct ip_mreqn mreq
= {{0}};
2037 struct ip_mreq mreq
= {{0}};
2038 #endif /* HAVE_STRUCT_IP_MREQN */
2040 /* pain! MulticastOption holds two IPAddress
2041 * members, so I have to dig the value out of
2044 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
2045 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2047 /* address might not be defined and if so, set the address to ADDR_ANY.
2050 mreq
.imr_multiaddr
= ipaddress_to_struct_in_addr (address
);
2053 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "local");
2054 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
2056 #ifdef HAVE_STRUCT_IP_MREQN
2058 mreq
.imr_address
= ipaddress_to_struct_in_addr (address
);
2062 mreq
.imr_interface
= ipaddress_to_struct_in_addr (address
);
2064 #endif /* HAVE_STRUCT_IP_MREQN */
2066 ret
= _wapi_setsockopt (sock
, system_level
,
2072 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2074 /* Cause an exception to be thrown */
2078 } else if (byte_val
!=NULL
) {
2079 int valsize
=mono_array_length(byte_val
);
2080 guchar
*buf
=mono_array_addr(byte_val
, guchar
, 0);
2082 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, buf
, valsize
);
2083 if(ret
==SOCKET_ERROR
) {
2084 *error
= WSAGetLastError ();
2088 /* ReceiveTimeout/SendTimeout get here */
2090 case SocketOptionName_DontFragment
:
2091 #ifdef HAVE_IP_MTU_DISCOVER
2092 /* Fiddle with the value slightly if we're
2096 int_val
= IP_PMTUDISC_DO
;
2102 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, (char *) &int_val
, sizeof (int_val
));
2106 if(ret
==SOCKET_ERROR
) {
2107 *error
= WSAGetLastError ();
2111 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock
,
2117 MONO_ARCH_SAVE_REGS
;
2121 /* Currently, the values for how (recv=0, send=1, both=2) match
2124 ret
= _wapi_shutdown (sock
, how
);
2125 if(ret
==SOCKET_ERROR
) {
2126 *error
= WSAGetLastError ();
2131 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock
, gint32 code
,
2133 MonoArray
*output
, gint32
*error
)
2135 glong output_bytes
= 0;
2136 gchar
*i_buffer
, *o_buffer
;
2140 MONO_ARCH_SAVE_REGS
;
2144 if (code
== FIONBIO
) {
2145 /* Invalid command. Must use Socket.Blocking */
2149 if (input
== NULL
) {
2153 i_buffer
= mono_array_addr (input
, gchar
, 0);
2154 i_len
= mono_array_length (input
);
2157 if (output
== NULL
) {
2161 o_buffer
= mono_array_addr (output
, gchar
, 0);
2162 o_len
= mono_array_length (output
);
2165 ret
= WSAIoctl (sock
, code
, i_buffer
, i_len
, o_buffer
, o_len
, &output_bytes
, NULL
, NULL
);
2166 if (ret
== SOCKET_ERROR
) {
2167 *error
= WSAGetLastError ();
2171 return (gint
) output_bytes
;
2174 #ifdef HAVE_SIOCGIFCONF
2176 is_loopback (int family
, void *ad
)
2178 char *ptr
= (char *) ad
;
2180 if (family
== AF_INET
) {
2181 return (ptr
[0] == 127);
2185 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr
*) ptr
));
2192 get_local_ips (int family
, int *nips
)
2194 int addr_size
, offset
, fd
, i
, count
;
2195 int max_ifaces
= 50; /* 50 interfaces should be enough... */
2198 struct ifreq iflags
;
2199 char *result
, *tmp_ptr
;
2200 gboolean ignore_loopback
= FALSE
;
2203 if (family
== AF_INET
) {
2204 addr_size
= sizeof (struct in_addr
);
2205 offset
= G_STRUCT_OFFSET (struct sockaddr_in
, sin_addr
);
2207 } else if (family
== AF_INET6
) {
2208 addr_size
= sizeof (struct in6_addr
);
2209 offset
= G_STRUCT_OFFSET (struct sockaddr_in6
, sin6_addr
);
2215 fd
= socket (family
, SOCK_STREAM
, 0);
2217 ifc
.ifc_len
= max_ifaces
* sizeof (struct ifreq
);
2218 ifc
.ifc_buf
= g_malloc (ifc
.ifc_len
);
2219 if (ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0) {
2221 g_free (ifc
.ifc_buf
);
2225 count
= ifc
.ifc_len
/ sizeof (struct ifreq
);
2228 g_free (ifc
.ifc_buf
);
2233 for (i
= 0, ifr
= ifc
.ifc_req
; i
< *nips
; i
++, ifr
++) {
2234 strcpy (iflags
.ifr_name
, ifr
->ifr_name
);
2235 if (ioctl (fd
, SIOCGIFFLAGS
, &iflags
) < 0) {
2239 if ((iflags
.ifr_flags
& IFF_UP
) == 0) {
2240 ifr
->ifr_name
[0] = '\0';
2244 if ((iflags
.ifr_flags
& IFF_LOOPBACK
) == 0) {
2245 ignore_loopback
= TRUE
;
2250 result
= g_malloc (addr_size
* count
);
2252 for (i
= 0, ifr
= ifc
.ifc_req
; i
< count
; i
++, ifr
++) {
2253 if (ifr
->ifr_name
[0] == '\0') {
2258 if (ignore_loopback
&& is_loopback (family
, ((char *) &ifr
->ifr_addr
) + offset
)) {
2263 memcpy (tmp_ptr
, ((char *) &ifr
->ifr_addr
) + offset
, addr_size
);
2264 tmp_ptr
+= addr_size
;
2267 g_free (ifc
.ifc_buf
);
2272 get_local_ips (int family
, int *nips
)
2278 #endif /* HAVE_SIOCGIFCONF */
2281 static gboolean
hostent_to_IPHostEntry(struct hostent
*he
, MonoString
**h_name
,
2282 MonoArray
**h_aliases
,
2283 MonoArray
**h_addr_list
,
2284 gboolean add_local_ips
)
2286 MonoDomain
*domain
= mono_domain_get ();
2288 struct in_addr
*local_in
= NULL
;
2291 if(he
->h_length
!=4 || he
->h_addrtype
!=AF_INET
) {
2295 *h_name
=mono_string_new(domain
, he
->h_name
);
2298 while(he
->h_aliases
[i
]!=NULL
) {
2302 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), i
);
2304 while(he
->h_aliases
[i
]!=NULL
) {
2307 alias
=mono_string_new(domain
, he
->h_aliases
[i
]);
2308 mono_array_setref (*h_aliases
, i
, alias
);
2312 if (add_local_ips
) {
2313 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2315 *h_addr_list
= mono_array_new(domain
, mono_get_string_class (), nlocal_in
);
2316 for (i
= 0; i
< nlocal_in
; i
++) {
2317 MonoString
*addr_string
;
2318 char addr
[16], *ptr
;
2320 ptr
= (char *) &local_in
[i
];
2321 g_snprintf(addr
, 16, "%u.%u.%u.%u",
2322 (unsigned char) ptr
[0],
2323 (unsigned char) ptr
[1],
2324 (unsigned char) ptr
[2],
2325 (unsigned char) ptr
[3]);
2327 addr_string
= mono_string_new (domain
, addr
);
2328 mono_array_setref (*h_addr_list
, i
, addr_string
);
2336 if (nlocal_in
== 0) {
2338 while (he
->h_addr_list
[i
]!=NULL
) {
2342 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), i
);
2344 while(he
->h_addr_list
[i
]!=NULL
) {
2345 MonoString
*addr_string
;
2348 g_snprintf(addr
, 16, "%u.%u.%u.%u",
2349 (unsigned char)he
->h_addr_list
[i
][0],
2350 (unsigned char)he
->h_addr_list
[i
][1],
2351 (unsigned char)he
->h_addr_list
[i
][2],
2352 (unsigned char)he
->h_addr_list
[i
][3]);
2354 addr_string
=mono_string_new(domain
, addr
);
2355 mono_array_setref (*h_addr_list
, i
, addr_string
);
2363 static gboolean
ipaddr_to_IPHostEntry(const char *addr
, MonoString
**h_name
,
2364 MonoArray
**h_aliases
,
2365 MonoArray
**h_addr_list
)
2367 MonoDomain
*domain
= mono_domain_get ();
2369 *h_name
=mono_string_new(domain
, addr
);
2370 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2371 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), 1);
2372 mono_array_setref (*h_addr_list
, 0, *h_name
);
2378 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2379 static gboolean
hostent_to_IPHostEntry2(struct hostent
*he1
,struct hostent
*he2
, MonoString
**h_name
,
2380 MonoArray
**h_aliases
, MonoArray
**h_addr_list
, gboolean add_local_ips
)
2382 MonoDomain
*domain
= mono_domain_get ();
2383 int i
, host_count
, host_index
, family_hint
;
2384 struct in_addr
*local_in
= NULL
;
2386 struct in6_addr
*local_in6
= NULL
;
2388 gboolean from_local
= FALSE
;
2390 family_hint
= get_family_hint ();
2392 if(he1
== NULL
&& he2
== NULL
) {
2397 * Check if address length and family are correct
2399 if (he1
!= NULL
&& (he1
->h_length
!=4 || he1
->h_addrtype
!=AF_INET
)) {
2403 if (he2
!= NULL
&& (he2
->h_length
!=16 || he2
->h_addrtype
!=AF_INET6
)) {
2408 * Get the aliases and host name from he1 or he2 whichever is
2409 * not null, if he1 is not null then take aliases from he1
2411 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2412 family_hint
== PF_INET
)) {
2413 *h_name
=mono_string_new (domain
, he1
->h_name
);
2416 while(he1
->h_aliases
[i
]!=NULL
) {
2420 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
2423 while(he1
->h_aliases
[i
]!=NULL
) {
2426 alias
=mono_string_new (domain
, he1
->h_aliases
[i
]);
2427 mono_array_setref (*h_aliases
, i
, alias
);
2430 } else if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2431 family_hint
== PF_INET6
)) {
2432 *h_name
=mono_string_new (domain
, he2
->h_name
);
2435 while(he2
->h_aliases
[i
] != NULL
) {
2439 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
2442 while(he2
->h_aliases
[i
]!=NULL
) {
2445 alias
=mono_string_new (domain
, he2
->h_aliases
[i
]);
2446 mono_array_setref (*h_aliases
, i
, alias
);
2454 * Count the number of addresses in he1 + he2
2457 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2458 family_hint
== PF_INET
)) {
2460 while(he1
->h_addr_list
[i
]!=NULL
) {
2466 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2467 family_hint
== PF_INET6
)) {
2469 while(he2
->h_addr_list
[i
]!=NULL
) {
2479 if (add_local_ips
) {
2480 if (family_hint
== PF_UNSPEC
|| family_hint
== PF_INET
)
2481 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2483 if (family_hint
== PF_UNSPEC
|| family_hint
== PF_INET6
)
2484 local_in6
= (struct in6_addr
*) get_local_ips (AF_INET6
, &nlocal_in6
);
2486 if (nlocal_in
|| nlocal_in6
) {
2488 *h_addr_list
= mono_array_new (domain
, mono_get_string_class (),
2489 nlocal_in
+ nlocal_in6
);
2493 for (n
= 0; n
< nlocal_in6
; n
++) {
2494 MonoString
*addr_string
;
2496 char addr
[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2498 ret
= inet_ntop (AF_INET6
, &local_in6
[n
], addr
, sizeof(addr
));
2501 addr_string
= mono_string_new (domain
, addr
);
2502 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2510 for (n
= 0; n
< nlocal_in
; n
++) {
2511 MonoString
*addr_string
;
2513 char addr
[16]; /* INET_ADDRSTRLEN == 16 */
2515 ret
= inet_ntop (AF_INET
, &local_in
[n
], addr
, sizeof(addr
));
2518 addr_string
= mono_string_new (domain
, addr
);
2519 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2533 *h_addr_list
=mono_array_new (domain
, mono_get_string_class (), host_count
);
2535 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2536 family_hint
== PF_INET6
)) {
2538 while(he2
->h_addr_list
[i
] != NULL
) {
2539 MonoString
*addr_string
;
2541 char addr
[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2543 ret
= inet_ntop (AF_INET6
, he2
->h_addr_list
[i
], addr
,
2547 addr_string
= mono_string_new (domain
, addr
);
2548 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2555 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2556 family_hint
== PF_INET
)) {
2558 while(he1
->h_addr_list
[i
] != NULL
) {
2559 MonoString
*addr_string
;
2561 char addr
[16]; /* INET_ADDRSTRLEN == 16 */
2563 ret
= inet_ntop (AF_INET
, he1
->h_addr_list
[i
], addr
,
2567 addr_string
=mono_string_new (domain
, addr
);
2568 mono_array_setref (*h_addr_list
, host_index
, addr_string
);
2579 #if defined(AF_INET6)
2581 addrinfo_to_IPHostEntry(struct addrinfo
*info
, MonoString
**h_name
,
2582 MonoArray
**h_aliases
,
2583 MonoArray
**h_addr_list
,
2584 gboolean add_local_ips
)
2587 struct addrinfo
*ai
= NULL
;
2588 struct in_addr
*local_in
= NULL
;
2590 struct in6_addr
*local_in6
= NULL
;
2594 MonoDomain
*domain
= mono_domain_get ();
2597 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2598 if (add_local_ips
) {
2599 local_in
= (struct in_addr
*) get_local_ips (AF_INET
, &nlocal_in
);
2600 local_in6
= (struct in6_addr
*) get_local_ips (AF_INET6
, &nlocal_in6
);
2601 if (nlocal_in
|| nlocal_in6
) {
2602 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), nlocal_in
+ nlocal_in6
);
2604 MonoString
*addr_string
;
2608 for (i
= 0; i
< nlocal_in
; i
++) {
2609 inet_ntop (AF_INET
, &local_in
[i
], addr
, sizeof (addr
));
2610 addr_string
= mono_string_new (domain
, addr
);
2611 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2617 MonoString
*addr_string
;
2622 for (i
= 0; i
< nlocal_in6
; i
++) {
2623 ret
= inet_ntop (AF_INET6
, &local_in6
[i
], addr
, sizeof (addr
));
2625 addr_string
= mono_string_new (domain
, addr
);
2626 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2635 freeaddrinfo (info
);
2644 for (count
=0, ai
=info
; ai
!=NULL
; ai
=ai
->ai_next
) {
2645 if (ai
->ai_family
!= AF_INET
&& ai
->ai_family
!= AF_INET6
)
2651 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), count
);
2653 for (ai
=info
, i
=0; ai
!=NULL
; ai
=ai
->ai_next
) {
2654 MonoString
*addr_string
;
2656 char buffer
[48]; /* Max. size for IPv6 */
2658 if((ai
->ai_family
!= PF_INET
) && (ai
->ai_family
!= PF_INET6
)) {
2662 if(ai
->ai_family
== PF_INET
) {
2663 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
), buffer
, 16);
2665 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_addr
), buffer
, 48);
2669 addr_string
=mono_string_new(domain
, buffer
);
2671 addr_string
=mono_string_new(domain
, "");
2674 mono_array_setref (*h_addr_list
, addr_index
, addr_string
);
2676 if(!i
&& ai
->ai_canonname
!= NULL
) {
2677 *h_name
=mono_string_new(domain
, ai
->ai_canonname
);
2692 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2694 gboolean add_local_ips
= FALSE
;
2695 #ifdef HAVE_SIOCGIFCONF
2696 gchar this_hostname
[256];
2698 #if !defined(HAVE_GETHOSTBYNAME2_R)
2699 struct addrinfo
*info
= NULL
, hints
;
2702 MONO_ARCH_SAVE_REGS
;
2704 hostname
=mono_string_to_utf8 (host
);
2705 #ifdef HAVE_SIOCGIFCONF
2706 if (gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
2707 if (!strcmp (hostname
, this_hostname
))
2708 add_local_ips
= TRUE
;
2712 memset(&hints
, 0, sizeof(hints
));
2713 hints
.ai_family
= get_family_hint ();
2714 hints
.ai_socktype
= SOCK_STREAM
;
2715 hints
.ai_flags
= AI_CANONNAME
;
2717 if (getaddrinfo(hostname
, NULL
, &hints
, &info
) == -1) {
2723 return(addrinfo_to_IPHostEntry(info
, h_name
, h_aliases
, h_addr_list
, add_local_ips
));
2725 struct hostent he1
,*hp1
, he2
, *hp2
;
2726 int buffer_size1
, buffer_size2
;
2727 char *buffer1
, *buffer2
;
2729 gboolean return_value
;
2732 MONO_ARCH_SAVE_REGS
;
2734 hostname
=mono_string_to_utf8 (host
);
2736 #ifdef HAVE_SIOCGIFCONF
2737 if (gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
2738 if (!strcmp (hostname
, this_hostname
))
2739 add_local_ips
= TRUE
;
2745 buffer1
= g_malloc0(buffer_size1
);
2746 buffer2
= g_malloc0(buffer_size2
);
2748 while (gethostbyname2_r(hostname
, AF_INET
, &he1
, buffer1
, buffer_size1
,
2749 &hp1
, &herr
) == ERANGE
) {
2751 buffer1
= g_realloc(buffer1
, buffer_size1
);
2756 while (gethostbyname2_r(hostname
, AF_INET6
, &he2
, buffer2
,
2757 buffer_size2
, &hp2
, &herr
) == ERANGE
) {
2759 buffer2
= g_realloc(buffer2
, buffer_size2
);
2765 return_value
= hostent_to_IPHostEntry2(hp1
, hp2
, h_name
, h_aliases
,
2766 h_addr_list
, add_local_ips
);
2772 return(return_value
);
2773 #endif /* HAVE_GETHOSTBYNAME2_R */
2775 #else /* AF_INET6 */
2776 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2780 gboolean add_local_ips
= FALSE
;
2781 #ifdef HAVE_SIOCGIFCONF
2782 gchar this_hostname
[256];
2785 MONO_ARCH_SAVE_REGS
;
2787 hostname
=mono_string_to_utf8(host
);
2788 #ifdef HAVE_SIOCGIFCONF
2789 if (gethostname (this_hostname
, sizeof (this_hostname
)) != -1) {
2790 if (!strcmp (hostname
, this_hostname
))
2791 add_local_ips
= TRUE
;
2795 he
= _wapi_gethostbyname (hostname
);
2802 return(hostent_to_IPHostEntry(he
, h_name
, h_aliases
, h_addr_list
, add_local_ips
));
2804 #endif /* AF_INET6 */
2806 #ifndef HAVE_INET_PTON
2808 inet_pton (int family
, const char *address
, void *inaddrp
)
2810 if (family
== AF_INET
) {
2811 #ifdef HAVE_INET_ATON
2812 struct in_addr inaddr
;
2814 if (!inet_aton (address
, &inaddr
))
2817 memcpy (inaddrp
, &inaddr
, sizeof (struct in_addr
));
2820 /* assume the system has inet_addr(), if it doesn't
2821 have that we're pretty much screwed... */
2824 if (!strcmp (address
, "255.255.255.255")) {
2825 /* special-case hack */
2826 inaddr
= 0xffffffff;
2828 inaddr
= inet_addr (address
);
2830 #define INADDR_NONE ((in_addr_t) -1)
2832 if (inaddr
== INADDR_NONE
)
2836 memcpy (inaddrp
, &inaddr
, sizeof (guint32
));
2838 #endif /* HAVE_INET_ATON */
2843 #endif /* !HAVE_INET_PTON */
2845 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString
*addr
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2851 struct sockaddr_in saddr
;
2852 struct sockaddr_in6 saddr6
;
2853 struct addrinfo
*info
= NULL
, hints
;
2855 char hostname
[1024] = {0};
2858 struct in_addr inaddr
;
2863 v1
= mono_framework_version () == 1;
2865 address
= mono_string_to_utf8 (addr
);
2868 if (inet_pton (AF_INET
, address
, &saddr
.sin_addr
) <= 0) {
2869 /* Maybe an ipv6 address */
2870 if (inet_pton (AF_INET6
, address
, &saddr6
.sin6_addr
) <= 0) {
2876 saddr6
.sin6_family
= AF_INET6
;
2881 saddr
.sin_family
= AF_INET
;
2886 flags
= NI_NAMEREQD
;
2889 if(family
== AF_INET
) {
2890 #if HAVE_SOCKADDR_IN_SIN_LEN
2891 saddr
.sin_len
= sizeof (saddr
);
2893 if(getnameinfo ((struct sockaddr
*)&saddr
, sizeof(saddr
),
2894 hostname
, sizeof(hostname
), NULL
, 0,
2898 } else if(family
== AF_INET6
) {
2899 #if HAVE_SOCKADDR_IN6_SIN_LEN
2900 saddr6
.sin6_len
= sizeof (saddr6
);
2902 if(getnameinfo ((struct sockaddr
*)&saddr6
, sizeof(saddr6
),
2903 hostname
, sizeof(hostname
), NULL
, 0,
2909 memset (&hints
, 0, sizeof(hints
));
2910 hints
.ai_family
= get_family_hint ();
2911 hints
.ai_socktype
= SOCK_STREAM
;
2912 hints
.ai_flags
= AI_CANONNAME
;
2914 if( getaddrinfo (hostname
, NULL
, &hints
, &info
) == -1 ) {
2918 return(addrinfo_to_IPHostEntry (info
, h_name
, h_aliases
, h_addr_list
, FALSE
));
2920 if (inet_pton (AF_INET
, address
, &inaddr
) <= 0) {
2925 if ((he
= gethostbyaddr ((char *) &inaddr
, sizeof (inaddr
), AF_INET
)) == NULL
) {
2929 ret
= ipaddr_to_IPHostEntry (address
, h_name
,
2930 h_aliases
, h_addr_list
);
2933 ret
= hostent_to_IPHostEntry (he
, h_name
, h_aliases
,
2934 h_addr_list
, FALSE
);
2942 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostName_internal(MonoString
**h_name
)
2944 gchar hostname
[256];
2947 MONO_ARCH_SAVE_REGS
;
2949 ret
= gethostname (hostname
, sizeof (hostname
));
2954 *h_name
=mono_string_new(mono_domain_get (), hostname
);
2959 void mono_network_init(void)
2964 err
=WSAStartup(MAKEWORD(2,0), &wsadata
);
2966 g_error(G_GNUC_PRETTY_FUNCTION
": Couldn't initialise networking");
2971 g_message(G_GNUC_PRETTY_FUNCTION
": Using socket library: %s", wsadata
.szDescription
);
2972 g_message(G_GNUC_PRETTY_FUNCTION
": Socket system status: %s", wsadata
.szSystemStatus
);
2976 void mono_network_cleanup(void)