2 * socket-io.c: Socket IO internal calls
5 * Dick Porter (dick@ximian.com)
7 * (C) 2001 Ximian, Inc.
18 #ifndef PLATFORM_WIN32
22 #elif defined(HAVE_SYS_AIO_H)
30 #include <mono/metadata/object.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/socket-io.h>
33 #include <mono/metadata/exception.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/threads.h>
36 /* FIXME change this code to not mess so much with the internals */
37 #include <mono/metadata/class-internals.h>
44 #ifdef HAVE_SYS_FILIO_H
45 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
47 #ifdef HAVE_SYS_SOCKIO_H
48 #include <sys/sockio.h> /* defines SIOCATMARK */
54 #include "mono/io-layer/socket-wrappers.h"
57 /* This is a kludge to make this file build under cygwin:
58 * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
59 * prototypes for some but not all required functions (notably
60 * inet_ntop() is missing), but the libws2_32 library is missing the
61 * actual implementations of these functions.
68 static gint32
convert_family(MonoAddressFamily mono_family
)
73 case AddressFamily_Unknown
:
74 case AddressFamily_ImpLink
:
75 case AddressFamily_Pup
:
76 case AddressFamily_Chaos
:
77 case AddressFamily_Iso
:
78 case AddressFamily_Ecma
:
79 case AddressFamily_DataKit
:
80 case AddressFamily_Ccitt
:
81 case AddressFamily_DataLink
:
82 case AddressFamily_Lat
:
83 case AddressFamily_HyperChannel
:
84 case AddressFamily_NetBios
:
85 case AddressFamily_VoiceView
:
86 case AddressFamily_FireFox
:
87 case AddressFamily_Banyan
:
88 case AddressFamily_Atm
:
89 case AddressFamily_Cluster
:
90 case AddressFamily_Ieee12844
:
91 case AddressFamily_NetworkDesigners
:
92 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family
);
95 case AddressFamily_Unspecified
:
99 case AddressFamily_Unix
:
103 case AddressFamily_InterNetwork
:
107 case AddressFamily_Ipx
:
113 case AddressFamily_Sna
:
117 case AddressFamily_DecNet
:
121 case AddressFamily_AppleTalk
:
125 case AddressFamily_InterNetworkV6
:
130 case AddressFamily_Irda
:
136 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family
);
142 static MonoAddressFamily
convert_to_mono_family(guint16 af_family
)
144 MonoAddressFamily family
=AddressFamily_Unknown
;
148 family
=AddressFamily_Unspecified
;
152 family
=AddressFamily_Unix
;
156 family
=AddressFamily_InterNetwork
;
161 family
=AddressFamily_Ipx
;
166 family
=AddressFamily_Sna
;
170 family
=AddressFamily_DecNet
;
174 family
=AddressFamily_AppleTalk
;
179 family
=AddressFamily_InterNetworkV6
;
185 family
=AddressFamily_Irda
;
189 g_warning("unknown address family 0x%x", af_family
);
195 static gint32
convert_type(MonoSocketType mono_type
)
200 case SocketType_Stream
:
204 case SocketType_Dgram
:
216 case SocketType_Seqpacket
:
220 case SocketType_Unknown
:
221 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type
);
225 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type
);
231 static gint32
convert_proto(MonoProtocolType mono_proto
)
236 case ProtocolType_IP
:
237 case ProtocolType_IPv6
:
238 case ProtocolType_Icmp
:
239 case ProtocolType_Igmp
:
240 case ProtocolType_Ggp
:
241 case ProtocolType_Tcp
:
242 case ProtocolType_Pup
:
243 case ProtocolType_Udp
:
244 case ProtocolType_Idp
:
245 /* These protocols are known (on my system at least) */
249 case ProtocolType_ND
:
250 case ProtocolType_Raw
:
251 case ProtocolType_Ipx
:
252 case ProtocolType_Spx
:
253 case ProtocolType_SpxII
:
254 case ProtocolType_Unknown
:
255 /* These protocols arent */
256 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto
);
266 static gint32
convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level
,
267 MonoSocketOptionName mono_name
,
271 switch (mono_level
) {
272 case SocketOptionLevel_Socket
:
273 *system_level
= SOL_SOCKET
;
276 case SocketOptionName_DontLinger
:
277 /* This is SO_LINGER, because the setsockopt
278 * internal call maps DontLinger to SO_LINGER
281 *system_name
= SO_LINGER
;
283 case SocketOptionName_Debug
:
284 *system_name
= SO_DEBUG
;
287 case SocketOptionName_AcceptConnection
:
288 *system_name
= SO_ACCEPTCONN
;
291 case SocketOptionName_ReuseAddress
:
292 *system_name
= SO_REUSEADDR
;
294 case SocketOptionName_KeepAlive
:
295 *system_name
= SO_KEEPALIVE
;
297 case SocketOptionName_DontRoute
:
298 *system_name
= SO_DONTROUTE
;
300 case SocketOptionName_Broadcast
:
301 *system_name
= SO_BROADCAST
;
303 case SocketOptionName_Linger
:
304 *system_name
= SO_LINGER
;
306 case SocketOptionName_OutOfBandInline
:
307 *system_name
= SO_OOBINLINE
;
309 case SocketOptionName_SendBuffer
:
310 *system_name
= SO_SNDBUF
;
312 case SocketOptionName_ReceiveBuffer
:
313 *system_name
= SO_RCVBUF
;
315 case SocketOptionName_SendLowWater
:
316 *system_name
= SO_SNDLOWAT
;
318 case SocketOptionName_ReceiveLowWater
:
319 *system_name
= SO_RCVLOWAT
;
321 case SocketOptionName_SendTimeout
:
322 *system_name
= SO_SNDTIMEO
;
324 case SocketOptionName_ReceiveTimeout
:
325 *system_name
= SO_RCVTIMEO
;
327 case SocketOptionName_Error
:
328 *system_name
= SO_ERROR
;
330 case SocketOptionName_Type
:
331 *system_name
= SO_TYPE
;
334 case SocketOptionName_PeerCred
:
335 *system_name
= SO_PEERCRED
;
338 case SocketOptionName_ExclusiveAddressUse
:
339 case SocketOptionName_UseLoopback
:
340 case SocketOptionName_MaxConnections
:
341 /* Can't figure out how to map these, so fall
345 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name
);
350 case SocketOptionLevel_IP
:
352 *system_level
= SOL_IP
;
355 static int cached
= 0;
359 struct protoent
*pent
;
361 pent
= getprotobyname ("IP");
362 proto
= pent
? pent
->p_proto
: 0 /* 0 a good default value?? */;
366 *system_level
= proto
;
368 #endif /* HAVE_SOL_IP */
371 case SocketOptionName_IPOptions
:
372 *system_name
= IP_OPTIONS
;
375 case SocketOptionName_HeaderIncluded
:
376 *system_name
= IP_HDRINCL
;
380 case SocketOptionName_TypeOfService
:
381 *system_name
= IP_TOS
;
385 case SocketOptionName_IpTimeToLive
:
386 *system_name
= IP_TTL
;
389 case SocketOptionName_MulticastInterface
:
390 *system_name
= IP_MULTICAST_IF
;
392 case SocketOptionName_MulticastTimeToLive
:
393 *system_name
= IP_MULTICAST_TTL
;
395 case SocketOptionName_MulticastLoopback
:
396 *system_name
= IP_MULTICAST_LOOP
;
398 case SocketOptionName_AddMembership
:
399 *system_name
= IP_ADD_MEMBERSHIP
;
401 case SocketOptionName_DropMembership
:
402 *system_name
= IP_DROP_MEMBERSHIP
;
404 #ifdef HAVE_IP_PKTINFO
405 case SocketOptionName_PacketInformation
:
406 *system_name
= IP_PKTINFO
;
408 #endif /* HAVE_IP_PKTINFO */
409 case SocketOptionName_DontFragment
:
410 case SocketOptionName_AddSourceMembership
:
411 case SocketOptionName_DropSourceMembership
:
412 case SocketOptionName_BlockSource
:
413 case SocketOptionName_UnblockSource
:
414 /* Can't figure out how to map these, so fall
418 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name
);
424 case SocketOptionLevel_IPv6
:
426 *system_level
= SOL_IPV6
;
429 static int cached
= 0;
433 struct protoent
*pent
;
435 pent
= getprotobyname ("IPV6");
436 proto
= pent
? pent
->p_proto
: 41 /* 41 a good default value?? */;
440 *system_level
= proto
;
442 #endif /* HAVE_SOL_IPV6 */
445 case SocketOptionName_IpTimeToLive
:
446 *system_name
= IPV6_UNICAST_HOPS
;
448 case SocketOptionName_MulticastInterface
:
449 *system_name
= IPV6_MULTICAST_IF
;
451 case SocketOptionName_MulticastTimeToLive
:
452 *system_name
= IPV6_MULTICAST_HOPS
;
454 case SocketOptionName_MulticastLoopback
:
455 *system_name
= IPV6_MULTICAST_LOOP
;
457 case SocketOptionName_AddMembership
:
458 *system_name
= IPV6_JOIN_GROUP
;
460 case SocketOptionName_DropMembership
:
461 *system_name
= IPV6_LEAVE_GROUP
;
463 case SocketOptionName_PacketInformation
:
464 *system_name
= IPV6_PKTINFO
;
466 case SocketOptionName_HeaderIncluded
:
467 case SocketOptionName_IPOptions
:
468 case SocketOptionName_TypeOfService
:
469 case SocketOptionName_DontFragment
:
470 case SocketOptionName_AddSourceMembership
:
471 case SocketOptionName_DropSourceMembership
:
472 case SocketOptionName_BlockSource
:
473 case SocketOptionName_UnblockSource
:
474 /* Can't figure out how to map these, so fall
478 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name
);
482 break; /* SocketOptionLevel_IPv6 */
485 case SocketOptionLevel_Tcp
:
487 *system_level
= SOL_TCP
;
490 static int cached
= 0;
494 struct protoent
*pent
;
496 pent
= getprotobyname ("TCP");
497 proto
= pent
? pent
->p_proto
: 6 /* is 6 a good default value?? */;
501 *system_level
= proto
;
503 #endif /* HAVE_SOL_TCP */
506 case SocketOptionName_NoDelay
:
507 *system_name
= TCP_NODELAY
;
510 /* The documentation is talking complete
511 * bollocks here: rfc-1222 is titled
512 * 'Advancing the NSFNET Routing Architecture'
513 * and doesn't mention either of the words
514 * "expedite" or "urgent".
516 case SocketOptionName_BsdUrgent
:
517 case SocketOptionName_Expedited
:
520 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name
);
525 case SocketOptionLevel_Udp
:
526 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level
);
529 case SocketOptionName_NoChecksum
:
530 case SocketOptionName_ChecksumCoverage
:
532 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name
);
539 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level
);
546 #define STASH_SYS_ASS(this) \
547 if(system_assembly == NULL) { \
548 system_assembly=mono_image_loaded ("System"); \
551 static MonoImage
*system_assembly
=NULL
;
555 static gint32
get_family_hint(void)
557 MonoClass
*socket_class
;
558 MonoClassField
*ipv6_field
, *ipv4_field
;
559 gint32 ipv6_enabled
= -1, ipv4_enabled
= -1;
562 socket_class
= mono_class_from_name (system_assembly
,
563 "System.Net.Sockets", "Socket");
564 ipv4_field
= mono_class_get_field_from_name (socket_class
,
566 ipv6_field
= mono_class_get_field_from_name (socket_class
,
568 vtable
= mono_class_vtable (mono_domain_get (), socket_class
);
570 mono_field_static_get_value(vtable
, ipv4_field
, &ipv4_enabled
);
571 mono_field_static_get_value(vtable
, ipv6_field
, &ipv6_enabled
);
573 if(ipv4_enabled
== 1 && ipv6_enabled
== 1) {
575 } else if(ipv4_enabled
== 1) {
583 gpointer
ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject
*this, gint32 family
, gint32 type
, gint32 proto
, gint32
*error
)
596 sock_family
=convert_family(family
);
597 if(sock_family
==-1) {
598 *error
= WSAEAFNOSUPPORT
;
602 sock_proto
=convert_proto(proto
);
604 *error
= WSAEPROTONOSUPPORT
;
608 sock_type
=convert_type(type
);
610 *error
= WSAESOCKTNOSUPPORT
;
614 sock
= _wapi_socket (sock_family
, sock_type
, sock_proto
,
615 NULL
, 0, WSA_FLAG_OVERLAPPED
);
617 if(sock
==INVALID_SOCKET
) {
618 *error
= WSAGetLastError ();
622 if (sock_family
== AF_INET
&& sock_type
== SOCK_DGRAM
) {
623 return (GUINT_TO_POINTER (sock
));
627 if (sock_family
== AF_INET6
&& sock_type
== SOCK_DGRAM
) {
628 return (GUINT_TO_POINTER (sock
));
632 #ifndef PLATFORM_WIN32
633 /* .net seems to set this by default for SOCK_STREAM,
634 * not for SOCK_DGRAM (see bug #36322)
636 * It seems winsock has a rather different idea of what
637 * SO_REUSEADDR means. If it's set, then a new socket can be
638 * bound over an existing listening socket. There's a new
639 * windows-specific option called SO_EXCLUSIVEADDRUSE but
640 * using that means the socket MUST be closed properly, or a
641 * denial of service can occur. Luckily for us, winsock
642 * behaves as though any other system would when SO_REUSEADDR
643 * is true, so we don't need to do anything else here. See
649 ret
= _wapi_setsockopt (sock
, SOL_SOCKET
, SO_REUSEADDR
, &true, sizeof (true));
650 if(ret
==SOCKET_ERROR
) {
651 *error
= WSAGetLastError ();
659 return(GUINT_TO_POINTER (sock
));
662 /* FIXME: the SOCKET parameter (here and in other functions in this
663 * file) is really an IntPtr which needs to be converted to a guint32.
665 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock
,
671 g_message (G_GNUC_PRETTY_FUNCTION
": closing 0x%x", sock
);
679 gint32
ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
684 g_message(G_GNUC_PRETTY_FUNCTION
": returning %d", WSAGetLastError());
687 return(WSAGetLastError());
690 gint32
ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock
,
700 ret
=ioctlsocket(sock
, FIONREAD
, &amount
);
701 if(ret
==SOCKET_ERROR
) {
702 *error
= WSAGetLastError ();
709 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock
,
719 ret
= ioctlsocket (sock
, FIONBIO
, (gulong
*) &block
);
720 if(ret
==SOCKET_ERROR
) {
721 *error
= WSAGetLastError ();
725 gpointer
ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock
,
734 newsock
= _wapi_accept (sock
, NULL
, 0);
735 if(newsock
==INVALID_SOCKET
) {
736 *error
= WSAGetLastError ();
740 return(GUINT_TO_POINTER (newsock
));
743 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock
,
753 ret
= _wapi_listen (sock
, backlog
);
754 if(ret
==SOCKET_ERROR
) {
755 *error
= WSAGetLastError ();
759 static MonoObject
*create_object_from_sockaddr(struct sockaddr
*saddr
,
760 int sa_size
, gint32
*error
)
762 MonoDomain
*domain
= mono_domain_get ();
763 MonoObject
*sockaddr_obj
;
764 MonoClass
*sockaddr_class
;
765 MonoClassField
*field
;
767 MonoAddressFamily family
;
769 /* Build a System.Net.SocketAddress object instance */
770 sockaddr_class
=mono_class_from_name(system_assembly
, "System.Net", "SocketAddress");
771 sockaddr_obj
=mono_object_new(domain
, sockaddr_class
);
773 /* Locate the SocketAddress data buffer in the object */
774 field
=mono_class_get_field_from_name(sockaddr_class
, "data");
776 /* Make sure there is space for the family and size bytes */
777 data
=mono_array_new(domain
, mono_get_byte_class (), sa_size
+2);
779 /* The data buffer is laid out as follows:
780 * byte 0 is the address family
781 * byte 1 is the buffer length
782 * bytes 2 and 3 are the port info
783 * the rest is the address info
786 family
=convert_to_mono_family(saddr
->sa_family
);
787 if(family
==AddressFamily_Unknown
) {
788 *error
= WSAEAFNOSUPPORT
;
792 mono_array_set(data
, guint8
, 0, family
& 0x0FF);
793 mono_array_set(data
, guint8
, 1, ((family
<< 8) & 0x0FFFF));
795 if(saddr
->sa_family
==AF_INET
) {
796 struct sockaddr_in
*sa_in
=(struct sockaddr_in
*)saddr
;
797 guint16 port
=ntohs(sa_in
->sin_port
);
798 guint32 address
=ntohl(sa_in
->sin_addr
.s_addr
);
801 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
804 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
805 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
806 mono_array_set(data
, guint8
, 4, (address
>>24) & 0xff);
807 mono_array_set(data
, guint8
, 5, (address
>>16) & 0xff);
808 mono_array_set(data
, guint8
, 6, (address
>>8) & 0xff);
809 mono_array_set(data
, guint8
, 7, (address
) & 0xff);
811 mono_field_set_value (sockaddr_obj
, field
, data
);
813 return(sockaddr_obj
);
815 } else if (saddr
->sa_family
== AF_INET6
) {
816 struct sockaddr_in6
*sa_in
=(struct sockaddr_in6
*)saddr
;
819 guint16 port
=ntohs(sa_in
->sin6_port
);
822 mono_raise_exception((MonoException
*)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
825 mono_array_set(data
, guint8
, 2, (port
>>8) & 0xff);
826 mono_array_set(data
, guint8
, 3, (port
) & 0xff);
828 for(i
=0; i
<16; i
++) {
829 mono_array_set(data
, guint8
, 8+i
,
830 sa_in
->sin6_addr
.s6_addr
[i
]);
833 mono_array_set(data
, guint8
, 24, sa_in
->sin6_scope_id
& 0xff);
834 mono_array_set(data
, guint8
, 25,
835 (sa_in
->sin6_scope_id
>> 8) & 0xff);
836 mono_array_set(data
, guint8
, 26,
837 (sa_in
->sin6_scope_id
>> 16) & 0xff);
838 mono_array_set(data
, guint8
, 27,
839 (sa_in
->sin6_scope_id
>> 24) & 0xff);
841 mono_field_set_value (sockaddr_obj
, field
, data
);
843 return(sockaddr_obj
);
846 } else if (saddr
->sa_family
== AF_UNIX
) {
849 for (i
= 0; i
< sa_size
; i
++) {
850 mono_array_set (data
, guint8
, i
+2, saddr
->sa_data
[i
]);
853 mono_field_set_value (sockaddr_obj
, field
, data
);
858 *error
= WSAEAFNOSUPPORT
;
863 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock
, gint32
*error
)
865 gchar sa
[32]; /* sockaddr in not big enough for sockaddr_in6 */
874 ret
= _wapi_getsockname (sock
, (struct sockaddr
*)sa
, &salen
);
876 if(ret
==SOCKET_ERROR
) {
877 *error
= WSAGetLastError ();
882 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
));
885 return(create_object_from_sockaddr((struct sockaddr
*)sa
, salen
,
889 extern MonoObject
*ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock
, gint32
*error
)
891 gchar sa
[32]; /* sockaddr in not big enough for sockaddr_in6 */
900 ret
= _wapi_getpeername (sock
, (struct sockaddr
*)sa
, &salen
);
902 if(ret
==SOCKET_ERROR
) {
903 *error
= WSAGetLastError ();
908 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
));
911 return(create_object_from_sockaddr((struct sockaddr
*)sa
, salen
,
915 static struct sockaddr
*create_sockaddr_from_object(MonoObject
*saddr_obj
,
919 MonoClassField
*field
;
924 /* Dig the SocketAddress data buffer out of the object */
925 field
=mono_class_get_field_from_name(saddr_obj
->vtable
->klass
, "data");
926 data
=*(MonoArray
**)(((char *)saddr_obj
) + field
->offset
);
928 /* The data buffer is laid out as follows:
929 * byte 0 is the address family low byte
930 * byte 1 is the address family high byte
932 * bytes 2 and 3 are the port info
933 * the rest is the address info
935 * the rest is the file name
937 len
= mono_array_length (data
);
939 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
942 family
= convert_family (mono_array_get (data
, guint8
, 0) + (mono_array_get (data
, guint8
, 1) << 8));
943 if(family
==AF_INET
) {
944 struct sockaddr_in
*sa
=g_new0(struct sockaddr_in
, 1);
945 guint16 port
=(mono_array_get(data
, guint8
, 2) << 8) +
946 mono_array_get(data
, guint8
, 3);
947 guint32 address
=(mono_array_get(data
, guint8
, 4) << 24) +
948 (mono_array_get(data
, guint8
, 5) << 16 ) +
949 (mono_array_get(data
, guint8
, 6) << 8) +
950 mono_array_get(data
, guint8
, 7);
952 sa
->sin_family
=family
;
953 sa
->sin_addr
.s_addr
=htonl(address
);
954 sa
->sin_port
=htons(port
);
956 *sa_size
=sizeof(struct sockaddr_in
);
957 return((struct sockaddr
*)sa
);
960 } else if (family
== AF_INET6
) {
961 struct sockaddr_in6
*sa
=g_new0(struct sockaddr_in6
, 1);
964 guint16 port
= mono_array_get(data
, guint8
, 3) + (mono_array_get(data
, guint8
, 2) << 8);
965 guint32 scopeid
= mono_array_get(data
, guint8
, 24) +
966 (mono_array_get(data
, guint8
, 25)<<8) +
967 (mono_array_get(data
, guint8
, 26)<<16) +
968 (mono_array_get(data
, guint8
, 27)<<24);
970 sa
->sin6_family
=family
;
971 sa
->sin6_port
=htons(port
);
972 sa
->sin6_scope_id
= scopeid
;
975 sa
->sin6_addr
.s6_addr
[i
] = mono_array_get(data
, guint8
, 8+i
);
977 *sa_size
=sizeof(struct sockaddr_in6
);
978 return((struct sockaddr
*)sa
);
981 } else if (family
== AF_UNIX
) {
982 struct sockaddr_un
*sock_un
= g_new0 (struct sockaddr_un
, 1);
985 if (len
- 2 > MONO_SIZEOF_SUNPATH
)
986 mono_raise_exception (mono_get_exception_index_out_of_range ());
988 sock_un
->sun_family
= family
;
989 for (i
= 0; i
< len
- 2; i
++)
990 sock_un
->sun_path
[i
] = mono_array_get (data
, guint8
,
992 sock_un
->sun_path
[len
- 2] = '\0';
993 *sa_size
= sizeof (struct sockaddr_un
);
995 return (struct sockaddr
*)sock_un
;
998 *error
= WSAEAFNOSUPPORT
;
1003 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1005 struct sockaddr
*sa
;
1009 MONO_ARCH_SAVE_REGS
;
1013 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1019 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
));
1022 ret
= _wapi_bind (sock
, sa
, sa_size
);
1023 if(ret
==SOCKET_ERROR
) {
1024 *error
= WSAGetLastError ();
1037 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock
, gint mode
,
1038 gint timeout
, gint32
*error
)
1043 struct timeval
*tvptr
;
1046 MONO_ARCH_SAVE_REGS
;
1049 /* FIXME: in case of extra iteration (WSAEINTR), substract time
1050 * from the initial timeout */
1053 _wapi_FD_SET (sock
, &fds
);
1055 divvy
= div (timeout
, 1000000);
1056 tv
.tv_sec
= divvy
.quot
;
1057 tv
.tv_usec
= divvy
.rem
;
1063 if (mode
== SelectModeRead
) {
1064 ret
= _wapi_select (0, &fds
, NULL
, NULL
, tvptr
);
1065 } else if (mode
== SelectModeWrite
) {
1066 ret
= _wapi_select (0, NULL
, &fds
, NULL
, tvptr
);
1067 } else if (mode
== SelectModeError
) {
1068 ret
= _wapi_select (0, NULL
, NULL
, &fds
, tvptr
);
1070 g_assert_not_reached ();
1072 } while ((ret
== SOCKET_ERROR
) && (*error
== WSAGetLastError ()) == WSAEINTR
);
1074 return (ret
!= SOCKET_ERROR
&& _wapi_FD_ISSET (sock
, &fds
));
1077 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock
, MonoObject
*sockaddr
, gint32
*error
)
1079 struct sockaddr
*sa
;
1083 MONO_ARCH_SAVE_REGS
;
1087 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1093 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
));
1096 ret
= _wapi_connect (sock
, sa
, sa_size
);
1097 if(ret
==SOCKET_ERROR
) {
1098 *error
= WSAGetLastError ();
1104 gint32
ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1111 MONO_ARCH_SAVE_REGS
;
1115 alen
=mono_array_length(buffer
);
1116 if(offset
+count
>alen
) {
1120 buf
=mono_array_addr(buffer
, guchar
, offset
);
1122 ret
= _wapi_recv (sock
, buf
, count
, recvflags
);
1123 if(ret
==SOCKET_ERROR
) {
1124 *error
= WSAGetLastError ();
1131 gint32
ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
**sockaddr
, gint32
*error
)
1137 struct sockaddr
*sa
;
1140 MONO_ARCH_SAVE_REGS
;
1144 alen
=mono_array_length(buffer
);
1145 if(offset
+count
>alen
) {
1149 sa
=create_sockaddr_from_object(*sockaddr
, &sa_size
, error
);
1154 buf
=mono_array_addr(buffer
, guchar
, offset
);
1156 ret
= _wapi_recvfrom (sock
, buf
, count
, recvflags
, sa
, &sa_size
);
1157 if(ret
==SOCKET_ERROR
) {
1159 *error
= WSAGetLastError ();
1163 /* If we didn't get a socket size, then we're probably a
1164 * connected connection-oriented socket and the stack hasn't
1165 * returned the remote address. All we can do is return null.
1168 *sockaddr
=create_object_from_sockaddr(sa
, sa_size
, error
);
1177 gint32
ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, gint32
*error
)
1184 MONO_ARCH_SAVE_REGS
;
1188 alen
=mono_array_length(buffer
);
1189 if(offset
+count
>alen
) {
1194 g_message(G_GNUC_PRETTY_FUNCTION
": alen: %d", alen
);
1197 buf
=mono_array_addr(buffer
, guchar
, offset
);
1200 g_message(G_GNUC_PRETTY_FUNCTION
": Sending %d bytes", count
);
1203 ret
= _wapi_send (sock
, buf
, count
, sendflags
);
1204 if(ret
==SOCKET_ERROR
) {
1205 *error
= WSAGetLastError ();
1212 gint32
ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock
, MonoArray
*buffer
, gint32 offset
, gint32 count
, gint32 flags
, MonoObject
*sockaddr
, gint32
*error
)
1218 struct sockaddr
*sa
;
1221 MONO_ARCH_SAVE_REGS
;
1225 alen
=mono_array_length(buffer
);
1226 if(offset
+count
>alen
) {
1230 sa
=create_sockaddr_from_object(sockaddr
, &sa_size
, error
);
1236 g_message(G_GNUC_PRETTY_FUNCTION
": alen: %d", alen
);
1239 buf
=mono_array_addr(buffer
, guchar
, offset
);
1242 g_message(G_GNUC_PRETTY_FUNCTION
": Sending %d bytes", count
);
1245 ret
= _wapi_sendto (sock
, buf
, count
, sendflags
, sa
, sa_size
);
1246 if(ret
==SOCKET_ERROR
) {
1247 *error
= WSAGetLastError ();
1255 static SOCKET
Socket_to_SOCKET(MonoObject
*sockobj
)
1258 MonoClassField
*field
;
1260 field
=mono_class_get_field_from_name(sockobj
->vtable
->klass
, "socket");
1261 sock
=*(SOCKET
*)(((char *)sockobj
)+field
->offset
);
1266 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray
**read_socks
, MonoArray
**write_socks
, MonoArray
**err_socks
, gint32 timeout
, gint32
*error
)
1268 fd_set readfds
, writefds
, errfds
;
1269 fd_set
*readptr
= NULL
, *writeptr
= NULL
, *errptr
= NULL
;
1273 int readarrsize
= 0, writearrsize
= 0, errarrsize
= 0;
1274 MonoDomain
*domain
=mono_domain_get();
1275 MonoClass
*sock_arr_class
;
1281 MONO_ARCH_SAVE_REGS
;
1284 readarrsize
=mono_array_length(*read_socks
);
1288 if(readarrsize
>FD_SETSIZE
) {
1296 for(i
=0; i
<readarrsize
; i
++) {
1297 handle
= Socket_to_SOCKET(mono_array_get(*read_socks
, MonoObject
*, i
));
1298 _wapi_FD_SET(handle
, &readfds
);
1303 writearrsize
=mono_array_length(*write_socks
);
1305 if(writearrsize
>FD_SETSIZE
) {
1311 writeptr
= &writefds
;
1313 for(i
=0; i
<writearrsize
; i
++) {
1314 handle
= Socket_to_SOCKET(mono_array_get(*write_socks
, MonoObject
*, i
));
1315 _wapi_FD_SET(handle
, &writefds
);
1320 errarrsize
=mono_array_length(*err_socks
);
1322 if(errarrsize
>FD_SETSIZE
) {
1330 for(i
=0; i
<errarrsize
; i
++) {
1331 handle
= Socket_to_SOCKET(mono_array_get(*err_socks
, MonoObject
*, i
));
1332 _wapi_FD_SET(handle
, &errfds
);
1336 /* Negative timeout meaning block until ready is only
1337 * specified in Poll, not Select
1340 divvy
= div (timeout
, 1000000);
1344 tv
.tv_sec
=divvy
.quot
;
1345 tv
.tv_usec
=divvy
.rem
;
1347 ret
= _wapi_select (0, readptr
, writeptr
, errptr
, &tv
);
1349 ret
= _wapi_select (0, readptr
, writeptr
, errptr
, NULL
);
1351 } while ((ret
==SOCKET_ERROR
) && (WSAGetLastError() == WSAEINTR
));
1353 if(ret
==SOCKET_ERROR
) {
1354 *error
= WSAGetLastError ();
1359 sock_arr_class
=((MonoObject
*)*read_socks
)->vtable
->klass
;
1362 for(i
=0; i
<readarrsize
; i
++) {
1363 if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks
, MonoObject
*, i
)), &readfds
)) {
1367 socks
=mono_array_new_full(domain
, sock_arr_class
, &count
, NULL
);
1369 for(i
=0; i
<readarrsize
; i
++) {
1370 MonoObject
*sock
=mono_array_get(*read_socks
, MonoObject
*, i
);
1372 if(_wapi_FD_ISSET(Socket_to_SOCKET(sock
), &readfds
)) {
1373 mono_array_set(socks
, MonoObject
*, count
, sock
);
1383 sock_arr_class
=((MonoObject
*)*write_socks
)->vtable
->klass
;
1385 for(i
=0; i
<writearrsize
; i
++) {
1386 if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks
, MonoObject
*, i
)), &writefds
)) {
1390 socks
=mono_array_new_full(domain
, sock_arr_class
, &count
, NULL
);
1392 for(i
=0; i
<writearrsize
; i
++) {
1393 MonoObject
*sock
=mono_array_get(*write_socks
, MonoObject
*, i
);
1395 if(_wapi_FD_ISSET(Socket_to_SOCKET(sock
), &writefds
)) {
1396 mono_array_set(socks
, MonoObject
*, count
, sock
);
1402 *write_socks
= NULL
;
1406 sock_arr_class
=((MonoObject
*)*err_socks
)->vtable
->klass
;
1408 for(i
=0; i
<errarrsize
; i
++) {
1409 if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks
, MonoObject
*, i
)), &errfds
)) {
1413 socks
=mono_array_new_full(domain
, sock_arr_class
, &count
, NULL
);
1415 for(i
=0; i
<errarrsize
; i
++) {
1416 MonoObject
*sock
=mono_array_get(*err_socks
, MonoObject
*, i
);
1418 if(_wapi_FD_ISSET(Socket_to_SOCKET(sock
), &errfds
)) {
1419 mono_array_set(socks
, MonoObject
*, count
, sock
);
1427 static MonoObject
* int_to_object (MonoDomain
*domain
, int val
)
1429 return mono_value_box (domain
, mono_get_int32_class (), &val
);
1433 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoObject
**obj_val
, gint32
*error
)
1439 int valsize
=sizeof(val
);
1440 struct linger linger
;
1441 int lingersize
=sizeof(linger
);
1443 int tvsize
=sizeof(tv
);
1446 int credsize
= sizeof(cred
);
1448 MonoDomain
*domain
=mono_domain_get();
1450 MonoClass
*obj_class
;
1451 MonoClassField
*field
;
1453 MONO_ARCH_SAVE_REGS
;
1457 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1460 *error
= WSAENOPROTOOPT
;
1464 /* No need to deal with MulticastOption names here, because
1465 * you cant getsockopt AddMembership or DropMembership (the
1466 * int getsockopt will error, causing an exception)
1469 case SocketOptionName_Linger
:
1470 case SocketOptionName_DontLinger
:
1471 ret
= _wapi_getsockopt(sock
, system_level
, system_name
, &linger
,
1475 case SocketOptionName_SendTimeout
:
1476 case SocketOptionName_ReceiveTimeout
:
1477 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &tv
,
1482 case SocketOptionName_PeerCred
:
1483 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &cred
,
1489 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, &val
,
1493 if(ret
==SOCKET_ERROR
) {
1494 *error
= WSAGetLastError ();
1499 case SocketOptionName_Linger
:
1500 /* build a System.Net.Sockets.LingerOption */
1501 obj_class
=mono_class_from_name(system_assembly
,
1502 "System.Net.Sockets",
1504 obj
=mono_object_new(domain
, obj_class
);
1506 /* Locate and set the fields "bool enabled" and "int
1509 field
=mono_class_get_field_from_name(obj_class
, "enabled");
1510 *(guint8
*)(((char *)obj
)+field
->offset
)=linger
.l_onoff
;
1512 field
=mono_class_get_field_from_name(obj_class
, "seconds");
1513 *(guint32
*)(((char *)obj
)+field
->offset
)=linger
.l_linger
;
1517 case SocketOptionName_DontLinger
:
1518 /* construct a bool int in val - true if linger is off */
1519 obj
= int_to_object (domain
, !linger
.l_onoff
);
1522 case SocketOptionName_SendTimeout
:
1523 case SocketOptionName_ReceiveTimeout
:
1524 obj
= int_to_object (domain
, (tv
.tv_sec
* 1000) + (tv
.tv_usec
/ 1000));
1528 case SocketOptionName_PeerCred
:
1530 /* build a Mono.Posix.PeerCred+PeerCredData if
1533 MonoImage
*mono_posix_image
= mono_image_loaded ("Mono.Posix");
1534 MonoPeerCredData
*cred_data
;
1536 if (mono_posix_image
== NULL
) {
1537 *error
= WSAENOPROTOOPT
;
1541 obj_class
= mono_class_from_name(mono_posix_image
,
1543 "PeerCred/PeerCredData");
1544 obj
= mono_object_new(domain
, obj_class
);
1545 cred_data
= (MonoPeerCredData
*)obj
;
1546 cred_data
->pid
= cred
.pid
;
1547 cred_data
->uid
= cred
.uid
;
1548 cred_data
->gid
= cred
.gid
;
1554 obj
= int_to_object (domain
, val
);
1560 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock
, gint32 level
, gint32 name
, MonoArray
**byte_val
, gint32
*error
)
1568 MONO_ARCH_SAVE_REGS
;
1572 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1575 *error
= WSAENOPROTOOPT
;
1579 valsize
=mono_array_length(*byte_val
);
1580 buf
=mono_array_addr(*byte_val
, guchar
, 0);
1582 ret
= _wapi_getsockopt (sock
, system_level
, system_name
, buf
, &valsize
);
1583 if(ret
==SOCKET_ERROR
) {
1584 *error
= WSAGetLastError ();
1588 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1589 static struct in_addr
ipaddress_to_struct_in_addr(MonoObject
*ipaddr
)
1591 struct in_addr inaddr
;
1592 MonoClassField
*field
;
1594 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "address");
1596 /* No idea why .net uses a 64bit type to hold a 32bit value...
1598 * Internal value of IPAddess is in Network Order, there is no need
1599 * to call htonl here.
1601 inaddr
.s_addr
=(guint32
)*(guint64
*)(((char *)ipaddr
)+field
->offset
);
1608 static struct in6_addr
ipaddress_to_struct_in6_addr(MonoObject
*ipaddr
)
1610 struct in6_addr in6addr
;
1611 MonoClassField
*field
;
1615 field
=mono_class_get_field_from_name(ipaddr
->vtable
->klass
, "_numbers");
1616 data
=*(MonoArray
**)(((char *)ipaddr
) + field
->offset
);
1618 /* Solaris has only the 8 bit version. */
1620 for(i
=0; i
<8; i
++) {
1621 guint16 s
= mono_array_get (data
, guint16
, i
);
1622 in6addr
.s6_addr
[2 * i
] = (s
>> 8) & 0xff;
1623 in6addr
.s6_addr
[2 * i
+ 1] = s
& 0xff;
1627 in6addr
.s6_addr16
[i
] = mono_array_get (data
, guint16
, i
);
1631 #endif /* AF_INET6 */
1633 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
)
1644 #ifdef HAVE_SOL_IPV6
1645 sol_ipv6
= SOL_IPV6
;
1648 struct protoent
*pent
;
1649 pent
= getprotobyname ("ipv6");
1650 sol_ipv6
= (pent
!= NULL
) ? pent
->p_proto
: 41;
1658 struct protoent
*pent
;
1659 pent
= getprotobyname ("ip");
1660 sol_ip
= (pent
!= NULL
) ? pent
->p_proto
: 0;
1663 #endif /* AF_INET6 */
1665 MONO_ARCH_SAVE_REGS
;
1667 ret
=convert_sockopt_level_and_name(level
, name
, &system_level
,
1670 *error
= WSAENOPROTOOPT
;
1674 /* Only one of obj_val, byte_val or int_val has data */
1676 MonoClassField
*field
;
1677 struct linger linger
;
1681 case SocketOptionName_DontLinger
:
1684 valsize
=sizeof(linger
);
1685 ret
= _wapi_setsockopt (sock
, system_level
,
1686 system_name
, &linger
, valsize
);
1689 case SocketOptionName_Linger
:
1690 /* Dig out "bool enabled" and "int seconds"
1693 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "enabled");
1694 linger
.l_onoff
=*(guint8
*)(((char *)obj_val
)+field
->offset
);
1695 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "seconds");
1696 linger
.l_linger
=*(guint32
*)(((char *)obj_val
)+field
->offset
);
1698 valsize
=sizeof(linger
);
1699 ret
= _wapi_setsockopt (sock
, system_level
,
1700 system_name
, &linger
, valsize
);
1702 case SocketOptionName_AddMembership
:
1703 case SocketOptionName_DropMembership
:
1704 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1706 MonoObject
*address
= NULL
;
1709 if(system_level
== sol_ipv6
) {
1710 struct ipv6_mreq mreq6
;
1715 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
1716 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
1719 mreq6
.ipv6mr_multiaddr
= ipaddress_to_struct_in6_addr (address
);
1722 field
=mono_class_get_field_from_name(obj_val
->vtable
->klass
, "ifIndex");
1723 mreq6
.ipv6mr_interface
=*(guint64
*)(((char *)obj_val
)+field
->offset
);
1725 ret
= _wapi_setsockopt (sock
, system_level
,
1726 system_name
, &mreq6
,
1728 } else if(system_level
== sol_ip
)
1729 #endif /* AF_INET6 */
1731 #ifdef HAVE_STRUCT_IP_MREQN
1732 struct ip_mreqn mreq
= {{0}};
1734 struct ip_mreq mreq
= {{0}};
1735 #endif /* HAVE_STRUCT_IP_MREQN */
1737 /* pain! MulticastOption holds two IPAddress
1738 * members, so I have to dig the value out of
1741 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "group");
1742 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
1744 /* address might not be defined and if so, set the address to ADDR_ANY.
1747 mreq
.imr_multiaddr
= ipaddress_to_struct_in_addr (address
);
1750 field
= mono_class_get_field_from_name (obj_val
->vtable
->klass
, "local");
1751 address
= *(gpointer
*)(((char *)obj_val
) + field
->offset
);
1753 #ifdef HAVE_STRUCT_IP_MREQN
1755 mreq
.imr_address
= ipaddress_to_struct_in_addr (address
);
1759 mreq
.imr_interface
= ipaddress_to_struct_in_addr (address
);
1761 #endif /* HAVE_STRUCT_IP_MREQN */
1763 ret
= _wapi_setsockopt (sock
, system_level
,
1769 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
1771 /* Cause an exception to be thrown */
1775 } else if (byte_val
!=NULL
) {
1776 int valsize
=mono_array_length(byte_val
);
1777 guchar
*buf
=mono_array_addr(byte_val
, guchar
, 0);
1779 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, buf
, valsize
);
1780 if(ret
==SOCKET_ERROR
) {
1781 *error
= WSAGetLastError ();
1786 case SocketOptionName_SendTimeout
:
1787 case SocketOptionName_ReceiveTimeout
: {
1789 tv
.tv_sec
= int_val
/ 1000;
1790 tv
.tv_usec
= (int_val
% 1000) * 1000;
1791 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &tv
, sizeof (tv
));
1795 ret
= _wapi_setsockopt (sock
, system_level
, system_name
, &int_val
,
1800 if(ret
==SOCKET_ERROR
) {
1801 *error
= WSAGetLastError ();
1805 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock
,
1811 MONO_ARCH_SAVE_REGS
;
1815 /* Currently, the values for how (recv=0, send=1, both=2) match
1818 ret
= _wapi_shutdown (sock
, how
);
1819 if(ret
==SOCKET_ERROR
) {
1820 *error
= WSAGetLastError ();
1825 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock
, gint32 code
,
1827 MonoArray
*output
, gint32
*error
)
1829 gulong output_bytes
= 0;
1830 gchar
*i_buffer
, *o_buffer
;
1834 MONO_ARCH_SAVE_REGS
;
1838 if (code
== FIONBIO
) {
1839 /* Invalid command. Must use Socket.Blocking */
1843 if (input
== NULL
) {
1847 i_buffer
= mono_array_addr (input
, gchar
, 0);
1848 i_len
= mono_array_length (input
);
1851 if (output
== NULL
) {
1855 o_buffer
= mono_array_addr (output
, gchar
, 0);
1856 o_len
= mono_array_length (output
);
1859 ret
= WSAIoctl (sock
, code
, i_buffer
, i_len
, o_buffer
, o_len
, &output_bytes
, NULL
, NULL
);
1860 if (ret
== SOCKET_ERROR
) {
1861 *error
= WSAGetLastError ();
1865 return (gint
) output_bytes
;
1869 static gboolean
hostent_to_IPHostEntry(struct hostent
*he
, MonoString
**h_name
,
1870 MonoArray
**h_aliases
,
1871 MonoArray
**h_addr_list
)
1873 MonoDomain
*domain
= mono_domain_get ();
1876 if(he
->h_length
!=4 || he
->h_addrtype
!=AF_INET
) {
1880 *h_name
=mono_string_new(domain
, he
->h_name
);
1883 while(he
->h_aliases
[i
]!=NULL
) {
1887 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), i
);
1889 while(he
->h_aliases
[i
]!=NULL
) {
1892 alias
=mono_string_new(domain
, he
->h_aliases
[i
]);
1893 mono_array_set(*h_aliases
, MonoString
*, i
, alias
);
1898 while(he
->h_addr_list
[i
]!=NULL
) {
1902 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), i
);
1904 while(he
->h_addr_list
[i
]!=NULL
) {
1905 MonoString
*addr_string
;
1908 g_snprintf(addr
, 16, "%u.%u.%u.%u",
1909 (unsigned char)he
->h_addr_list
[i
][0],
1910 (unsigned char)he
->h_addr_list
[i
][1],
1911 (unsigned char)he
->h_addr_list
[i
][2],
1912 (unsigned char)he
->h_addr_list
[i
][3]);
1914 addr_string
=mono_string_new(domain
, addr
);
1915 mono_array_set(*h_addr_list
, MonoString
*, i
, addr_string
);
1923 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
1924 static gboolean
hostent_to_IPHostEntry2(struct hostent
*he1
,struct hostent
*he2
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
1926 MonoDomain
*domain
= mono_domain_get ();
1927 int i
, host_count
, host_index
, family_hint
;
1929 family_hint
= get_family_hint ();
1931 if(he1
== NULL
&& he2
== NULL
) {
1936 * Check if address length and family are correct
1938 if (he1
!= NULL
&& (he1
->h_length
!=4 || he1
->h_addrtype
!=AF_INET
)) {
1942 if (he2
!= NULL
&& (he2
->h_length
!=16 || he2
->h_addrtype
!=AF_INET6
)) {
1947 * Get the aliases and host name from he1 or he2 whichever is
1948 * not null, if he1 is not null then take aliases from he1
1950 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
1951 family_hint
== PF_INET
)) {
1952 *h_name
=mono_string_new (domain
, he1
->h_name
);
1955 while(he1
->h_aliases
[i
]!=NULL
) {
1959 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
1962 while(he1
->h_aliases
[i
]!=NULL
) {
1965 alias
=mono_string_new (domain
, he1
->h_aliases
[i
]);
1966 mono_array_set (*h_aliases
, MonoString
*, i
, alias
);
1969 } else if (family_hint
== PF_UNSPEC
|| family_hint
== PF_INET6
) {
1970 *h_name
=mono_string_new (domain
, he2
->h_name
);
1973 while(he2
->h_aliases
[i
] != NULL
) {
1977 *h_aliases
=mono_array_new (domain
, mono_get_string_class (),
1980 while(he2
->h_aliases
[i
]!=NULL
) {
1983 alias
=mono_string_new (domain
, he2
->h_aliases
[i
]);
1984 mono_array_set (*h_aliases
, MonoString
*, i
, alias
);
1990 * Count the number of addresses in he1 + he2
1993 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
1994 family_hint
== PF_INET
)) {
1996 while(he1
->h_addr_list
[i
]!=NULL
) {
2002 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2003 family_hint
== PF_INET6
)) {
2005 while(he2
->h_addr_list
[i
]!=NULL
) {
2014 *h_addr_list
=mono_array_new (domain
, mono_get_string_class (),
2019 if (he2
!= NULL
&& (family_hint
== PF_UNSPEC
||
2020 family_hint
== PF_INET6
)) {
2022 while(he2
->h_addr_list
[i
] != NULL
) {
2023 MonoString
*addr_string
;
2026 inet_ntop (AF_INET6
, he2
->h_addr_list
[i
], addr
,
2029 addr_string
= mono_string_new (domain
, addr
);
2030 mono_array_set (*h_addr_list
, MonoString
*, host_index
,
2037 if (he1
!= NULL
&& (family_hint
== PF_UNSPEC
||
2038 family_hint
== PF_INET
)) {
2040 while(he1
->h_addr_list
[i
] != NULL
) {
2041 MonoString
*addr_string
;
2044 inet_ntop (AF_INET
, he1
->h_addr_list
[i
], addr
,
2047 addr_string
=mono_string_new (domain
, addr
);
2048 mono_array_set (*h_addr_list
, MonoString
*, host_index
,
2059 #if defined(AF_INET6)
2061 addrinfo_to_IPHostEntry(struct addrinfo
*info
, MonoString
**h_name
,
2062 MonoArray
**h_aliases
,
2063 MonoArray
**h_addr_list
)
2066 struct addrinfo
*ai
= NULL
;
2068 MonoDomain
*domain
= mono_domain_get ();
2070 for (count
=0, ai
=info
; ai
!=NULL
; ai
=ai
->ai_next
) {
2071 if((ai
->ai_family
!= PF_INET
) && (ai
->ai_family
!= PF_INET6
)) {
2078 *h_aliases
=mono_array_new(domain
, mono_get_string_class (), 0);
2079 *h_addr_list
=mono_array_new(domain
, mono_get_string_class (), count
);
2081 for (ai
=info
, i
=0; ai
!=NULL
; ai
=ai
->ai_next
) {
2082 MonoString
*addr_string
;
2085 gint32 buffer_size
= 0;
2087 if((ai
->ai_family
!= PF_INET
) && (ai
->ai_family
!= PF_INET6
)) {
2093 buffer
= g_malloc0(buffer_size
);
2095 if(ai
->ai_family
== PF_INET
) {
2096 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
), buffer
, buffer_size
);
2098 ret
= inet_ntop(ai
->ai_family
, (void*)&(((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_addr
), buffer
, buffer_size
);
2105 } while(ret
== 0 && errno
== ENOSPC
);
2108 addr_string
=mono_string_new(domain
, buffer
);
2111 addr_string
=mono_string_new(domain
, "");
2114 mono_array_set(*h_addr_list
, MonoString
*, i
, addr_string
);
2116 if(!i
&& ai
->ai_canonname
!= NULL
) {
2117 *h_name
=mono_string_new(domain
, ai
->ai_canonname
);
2132 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2134 #if !defined(HAVE_GETHOSTBYNAME2_R)
2135 struct addrinfo
*info
= NULL
, hints
;
2138 MONO_ARCH_SAVE_REGS
;
2140 hostname
=mono_string_to_utf8 (host
);
2142 memset(&hints
, 0, sizeof(hints
));
2143 hints
.ai_family
= get_family_hint ();
2144 hints
.ai_socktype
= SOCK_STREAM
;
2145 hints
.ai_flags
= AI_CANONNAME
;
2147 if (getaddrinfo(hostname
, NULL
, &hints
, &info
) == -1) {
2153 return(addrinfo_to_IPHostEntry(info
, h_name
, h_aliases
, h_addr_list
));
2155 struct hostent he1
,*hp1
, he2
, *hp2
;
2156 int buffer_size1
, buffer_size2
;
2157 char *buffer1
, *buffer2
;
2159 gboolean return_value
;
2162 MONO_ARCH_SAVE_REGS
;
2164 hostname
=mono_string_to_utf8 (host
);
2168 buffer1
= g_malloc0(buffer_size1
);
2169 buffer2
= g_malloc0(buffer_size2
);
2171 while (gethostbyname2_r(hostname
, AF_INET
, &he1
, buffer1
, buffer_size1
,
2172 &hp1
, &herr
) == ERANGE
) {
2174 buffer1
= g_realloc(buffer1
, buffer_size1
);
2179 while (gethostbyname2_r(hostname
, AF_INET6
, &he2
, buffer2
,
2180 buffer_size2
, &hp2
, &herr
) == ERANGE
) {
2182 buffer2
= g_realloc(buffer2
, buffer_size2
);
2188 return_value
= hostent_to_IPHostEntry2(hp1
, hp2
, h_name
, h_aliases
,
2195 return(return_value
);
2196 #endif /* HAVE_GETHOSTBYNAME2_R */
2198 #else /* AF_INET6 */
2199 MonoBoolean
ves_icall_System_Net_Dns_GetHostByName_internal(MonoString
*host
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2204 MONO_ARCH_SAVE_REGS
;
2206 hostname
=mono_string_to_utf8(host
);
2208 he
= _wapi_gethostbyname (hostname
);
2215 return(hostent_to_IPHostEntry(he
, h_name
, h_aliases
, h_addr_list
));
2217 #endif /* AF_INET6 */
2219 #ifndef HAVE_INET_PTON
2221 inet_pton (int family
, const char *address
, void *inaddrp
)
2223 if (family
== AF_INET
) {
2224 #ifdef HAVE_INET_ATON
2225 struct in_addr inaddr
;
2227 if (!inet_aton (address
, &inaddr
))
2230 memcpy (inaddrp
, &inaddr
, sizeof (struct in_addr
));
2233 /* assume the system has inet_addr(), if it doesn't
2234 have that we're pretty much screwed... */
2237 if (!strcmp (address
, "255.255.255.255")) {
2238 /* special-case hack */
2239 inaddr
= 0xffffffff;
2241 inaddr
= inet_addr (address
);
2243 #define INADDR_NONE ((in_addr_t) -1)
2245 if (inaddr
== INADDR_NONE
)
2249 memcpy (inaddrp
, &inaddr
, sizeof (guint32
));
2251 #endif /* HAVE_INET_ATON */
2256 #endif /* !HAVE_INET_PTON */
2258 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString
*addr
, MonoString
**h_name
, MonoArray
**h_aliases
, MonoArray
**h_addr_list
)
2263 struct sockaddr_in saddr
;
2264 struct sockaddr_in6 saddr6
;
2265 struct addrinfo
*info
= NULL
, hints
;
2267 char hostname
[1024] = {0};
2269 struct in_addr inaddr
;
2273 MONO_ARCH_SAVE_REGS
;
2275 address
= mono_string_to_utf8 (addr
);
2278 if (inet_pton (AF_INET
, address
, &saddr
.sin_addr
) <= 0) {
2279 /* Maybe an ipv6 address */
2280 if (inet_pton (AF_INET6
, address
, &saddr6
.sin6_addr
) <= 0) {
2286 saddr6
.sin6_family
= AF_INET6
;
2291 saddr
.sin_family
= AF_INET
;
2295 if(family
== AF_INET
) {
2296 if(getnameinfo ((struct sockaddr
*)&saddr
, sizeof(saddr
),
2297 hostname
, sizeof(hostname
), NULL
, 0,
2298 NI_NAMEREQD
) != 0) {
2301 } else if(family
== AF_INET6
) {
2302 if(getnameinfo ((struct sockaddr
*)&saddr6
, sizeof(saddr6
),
2303 hostname
, sizeof(hostname
), NULL
, 0,
2304 NI_NAMEREQD
) != 0) {
2309 memset (&hints
, 0, sizeof(hints
));
2310 hints
.ai_family
= get_family_hint ();
2311 hints
.ai_socktype
= SOCK_STREAM
;
2312 hints
.ai_flags
= AI_CANONNAME
;
2314 if( getaddrinfo (hostname
, NULL
, &hints
, &info
) == -1 ) {
2318 return(addrinfo_to_IPHostEntry (info
, h_name
, h_aliases
, h_addr_list
));
2320 if (inet_pton (AF_INET
, address
, &inaddr
) <= 0) {
2326 if ((he
= gethostbyaddr ((char *) &inaddr
, sizeof (inaddr
), AF_INET
)) == NULL
) {
2330 return(hostent_to_IPHostEntry (he
, h_name
, h_aliases
, h_addr_list
));
2334 extern MonoBoolean
ves_icall_System_Net_Dns_GetHostName_internal(MonoString
**h_name
)
2336 guchar hostname
[256];
2339 MONO_ARCH_SAVE_REGS
;
2341 ret
= gethostname (hostname
, sizeof (hostname
));
2346 *h_name
=mono_string_new(mono_domain_get (), hostname
);
2352 /* Async interface */
2355 ves_icall_System_Net_Sockets_Socket_AsyncReceive (MonoSocketAsyncResult
*ares
, gint
*error
)
2357 MONO_ARCH_SAVE_REGS
;
2359 *error
= ERROR_NOT_SUPPORTED
;
2363 ves_icall_System_Net_Sockets_Socket_AsyncSend (MonoSocketAsyncResult
*ares
, gint
*error
)
2365 MONO_ARCH_SAVE_REGS
;
2367 *error
= ERROR_NOT_SUPPORTED
;
2371 wsa_overlapped_callback (guint32 error
, guint32 numbytes
, gpointer result
)
2373 MonoSocketAsyncResult
*ares
= (MonoSocketAsyncResult
*) result
;
2376 ares
->completed
= TRUE
;
2377 ares
->error
= error
;
2378 ares
->total
= numbytes
;
2380 if (ares
->callback
!= NULL
) {
2384 thread
= mono_thread_attach (mono_object_domain (ares
));
2385 mono_runtime_invoke (ares
->callback
->method_info
->method
, NULL
, p
, NULL
);
2387 mono_thread_detach (thread
);
2390 if (ares
->wait_handle
!= NULL
)
2391 SetEvent (ares
->wait_handle
->handle
);
2395 ves_icall_System_Net_Sockets_Socket_AsyncReceive (MonoSocketAsyncResult
*ares
, gint
*error
)
2399 MONO_ARCH_SAVE_REGS
;
2401 if (_wapi_socket_async_read (ares
->handle
,
2402 mono_array_addr (ares
->buffer
, gchar
, ares
->offset
),
2406 wsa_overlapped_callback
) == FALSE
) {
2407 *error
= WSAGetLastError ();
2410 ares
->completed_synch
= TRUE
;
2411 wsa_overlapped_callback (0, bytesread
, ares
);
2416 ves_icall_System_Net_Sockets_Socket_AsyncSend (MonoSocketAsyncResult
*ares
, gint
*error
)
2418 gint32 byteswritten
;
2420 MONO_ARCH_SAVE_REGS
;
2422 if (_wapi_socket_async_write (ares
->handle
,
2423 mono_array_addr (ares
->buffer
, gchar
, ares
->offset
),
2427 wsa_overlapped_callback
) == FALSE
) {
2428 *error
= WSAGetLastError ();
2431 ares
->completed_synch
= TRUE
;
2432 wsa_overlapped_callback (0, byteswritten
, ares
);
2435 #endif /* USE_AIO */
2437 void mono_network_init(void)
2442 err
=WSAStartup(MAKEWORD(2,0), &wsadata
);
2444 g_error(G_GNUC_PRETTY_FUNCTION
": Couldn't initialise networking");
2449 g_message(G_GNUC_PRETTY_FUNCTION
": Using socket library: %s", wsadata
.szDescription
);
2450 g_message(G_GNUC_PRETTY_FUNCTION
": Socket system status: %s", wsadata
.szSystemStatus
);
2454 void mono_network_cleanup(void)