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>
42 #ifdef HAVE_SYS_FILIO_H
43 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
45 #ifdef HAVE_SYS_SOCKIO_H
46 #include <sys/sockio.h> /* defines SIOCATMARK */
52 #include "mono/io-layer/socket-wrappers.h"
55 /* This is a kludge to make this file build under cygwin:
56 * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
57 * prototypes for some but not all required functions (notably
58 * inet_ntop() is missing), but the libws2_32 library is missing the
59 * actual implementations of these functions.
66 static gint32 convert_family(MonoAddressFamily mono_family)
71 case AddressFamily_Unknown:
72 case AddressFamily_ImpLink:
73 case AddressFamily_Pup:
74 case AddressFamily_Chaos:
75 case AddressFamily_Iso:
76 case AddressFamily_Ecma:
77 case AddressFamily_DataKit:
78 case AddressFamily_Ccitt:
79 case AddressFamily_DataLink:
80 case AddressFamily_Lat:
81 case AddressFamily_HyperChannel:
82 case AddressFamily_NetBios:
83 case AddressFamily_VoiceView:
84 case AddressFamily_FireFox:
85 case AddressFamily_Banyan:
86 case AddressFamily_Atm:
87 case AddressFamily_Cluster:
88 case AddressFamily_Ieee12844:
89 case AddressFamily_NetworkDesigners:
90 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
93 case AddressFamily_Unspecified:
97 case AddressFamily_Unix:
101 case AddressFamily_InterNetwork:
105 case AddressFamily_Ipx:
111 case AddressFamily_Sna:
115 case AddressFamily_DecNet:
119 case AddressFamily_AppleTalk:
123 case AddressFamily_InterNetworkV6:
128 case AddressFamily_Irda:
134 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
140 static MonoAddressFamily convert_to_mono_family(guint16 af_family)
142 MonoAddressFamily family=AddressFamily_Unknown;
146 family=AddressFamily_Unspecified;
150 family=AddressFamily_Unix;
154 family=AddressFamily_InterNetwork;
159 family=AddressFamily_Ipx;
164 family=AddressFamily_Sna;
168 family=AddressFamily_DecNet;
172 family=AddressFamily_AppleTalk;
177 family=AddressFamily_InterNetworkV6;
183 family=AddressFamily_Irda;
187 g_warning("unknown address family 0x%x", af_family);
193 static gint32 convert_type(MonoSocketType mono_type)
198 case SocketType_Stream:
202 case SocketType_Dgram:
214 case SocketType_Seqpacket:
218 case SocketType_Unknown:
219 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
223 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
229 static gint32 convert_proto(MonoProtocolType mono_proto)
234 case ProtocolType_IP:
235 case ProtocolType_IPv6:
236 case ProtocolType_Icmp:
237 case ProtocolType_Igmp:
238 case ProtocolType_Ggp:
239 case ProtocolType_Tcp:
240 case ProtocolType_Pup:
241 case ProtocolType_Udp:
242 case ProtocolType_Idp:
243 /* These protocols are known (on my system at least) */
247 case ProtocolType_ND:
248 case ProtocolType_Raw:
249 case ProtocolType_Ipx:
250 case ProtocolType_Spx:
251 case ProtocolType_SpxII:
252 case ProtocolType_Unknown:
253 /* These protocols arent */
254 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
264 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
265 MonoSocketOptionName mono_name,
269 switch (mono_level) {
270 case SocketOptionLevel_Socket:
271 *system_level = SOL_SOCKET;
274 case SocketOptionName_DontLinger:
275 /* This is SO_LINGER, because the setsockopt
276 * internal call maps DontLinger to SO_LINGER
279 *system_name = SO_LINGER;
281 case SocketOptionName_Debug:
282 *system_name = SO_DEBUG;
285 case SocketOptionName_AcceptConnection:
286 *system_name = SO_ACCEPTCONN;
289 case SocketOptionName_ReuseAddress:
290 *system_name = SO_REUSEADDR;
292 case SocketOptionName_KeepAlive:
293 *system_name = SO_KEEPALIVE;
295 case SocketOptionName_DontRoute:
296 *system_name = SO_DONTROUTE;
298 case SocketOptionName_Broadcast:
299 *system_name = SO_BROADCAST;
301 case SocketOptionName_Linger:
302 *system_name = SO_LINGER;
304 case SocketOptionName_OutOfBandInline:
305 *system_name = SO_OOBINLINE;
307 case SocketOptionName_SendBuffer:
308 *system_name = SO_SNDBUF;
310 case SocketOptionName_ReceiveBuffer:
311 *system_name = SO_RCVBUF;
313 case SocketOptionName_SendLowWater:
314 *system_name = SO_SNDLOWAT;
316 case SocketOptionName_ReceiveLowWater:
317 *system_name = SO_RCVLOWAT;
319 case SocketOptionName_SendTimeout:
320 *system_name = SO_SNDTIMEO;
322 case SocketOptionName_ReceiveTimeout:
323 *system_name = SO_RCVTIMEO;
325 case SocketOptionName_Error:
326 *system_name = SO_ERROR;
328 case SocketOptionName_Type:
329 *system_name = SO_TYPE;
331 case SocketOptionName_ExclusiveAddressUse:
332 case SocketOptionName_UseLoopback:
333 case SocketOptionName_MaxConnections:
334 /* Can't figure out how to map these, so fall
338 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
343 case SocketOptionLevel_IP:
345 *system_level = SOL_IP;
348 static int cached = 0;
352 struct protoent *pent;
354 pent = getprotobyname ("IP");
355 proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
359 *system_level = proto;
361 #endif /* HAVE_SOL_IP */
364 case SocketOptionName_IPOptions:
365 *system_name = IP_OPTIONS;
368 case SocketOptionName_HeaderIncluded:
369 *system_name = IP_HDRINCL;
373 case SocketOptionName_TypeOfService:
374 *system_name = IP_TOS;
378 case SocketOptionName_IpTimeToLive:
379 *system_name = IP_TTL;
382 case SocketOptionName_MulticastInterface:
383 *system_name = IP_MULTICAST_IF;
385 case SocketOptionName_MulticastTimeToLive:
386 *system_name = IP_MULTICAST_TTL;
388 case SocketOptionName_MulticastLoopback:
389 *system_name = IP_MULTICAST_LOOP;
391 case SocketOptionName_AddMembership:
392 *system_name = IP_ADD_MEMBERSHIP;
394 case SocketOptionName_DropMembership:
395 *system_name = IP_DROP_MEMBERSHIP;
397 #ifdef HAVE_IP_PKTINFO
398 case SocketOptionName_PacketInformation:
399 *system_name = IP_PKTINFO;
401 #endif /* HAVE_IP_PKTINFO */
402 case SocketOptionName_DontFragment:
403 case SocketOptionName_AddSourceMembership:
404 case SocketOptionName_DropSourceMembership:
405 case SocketOptionName_BlockSource:
406 case SocketOptionName_UnblockSource:
407 /* Can't figure out how to map these, so fall
411 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
417 case SocketOptionLevel_IPv6:
419 *system_level = SOL_IPV6;
422 static int cached = 0;
426 struct protoent *pent;
428 pent = getprotobyname ("IPV6");
429 proto = pent ? pent->p_proto : 41 /* 41 a good default value?? */;
433 *system_level = proto;
435 #endif /* HAVE_SOL_IPV6 */
438 case SocketOptionName_IpTimeToLive:
439 *system_name = IPV6_UNICAST_HOPS;
441 case SocketOptionName_MulticastInterface:
442 *system_name = IPV6_MULTICAST_IF;
444 case SocketOptionName_MulticastTimeToLive:
445 *system_name = IPV6_MULTICAST_HOPS;
447 case SocketOptionName_MulticastLoopback:
448 *system_name = IPV6_MULTICAST_LOOP;
450 case SocketOptionName_AddMembership:
451 *system_name = IPV6_JOIN_GROUP;
453 case SocketOptionName_DropMembership:
454 *system_name = IPV6_LEAVE_GROUP;
456 case SocketOptionName_PacketInformation:
457 *system_name = IPV6_PKTINFO;
459 case SocketOptionName_HeaderIncluded:
460 case SocketOptionName_IPOptions:
461 case SocketOptionName_TypeOfService:
462 case SocketOptionName_DontFragment:
463 case SocketOptionName_AddSourceMembership:
464 case SocketOptionName_DropSourceMembership:
465 case SocketOptionName_BlockSource:
466 case SocketOptionName_UnblockSource:
467 /* Can't figure out how to map these, so fall
471 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
475 break; /// SocketOptionLevel_IPv6
478 case SocketOptionLevel_Tcp:
480 *system_level = SOL_TCP;
483 static int cached = 0;
487 struct protoent *pent;
489 pent = getprotobyname ("TCP");
490 proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
494 *system_level = proto;
496 #endif /* HAVE_SOL_TCP */
499 case SocketOptionName_NoDelay:
500 *system_name = TCP_NODELAY;
503 /* The documentation is talking complete
504 * bollocks here: rfc-1222 is titled
505 * 'Advancing the NSFNET Routing Architecture'
506 * and doesn't mention either of the words
507 * "expedite" or "urgent".
509 case SocketOptionName_BsdUrgent:
510 case SocketOptionName_Expedited:
513 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
518 case SocketOptionLevel_Udp:
519 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
522 case SocketOptionName_NoChecksum:
523 case SocketOptionName_ChecksumCoverage:
525 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
532 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
539 #define STASH_SYS_ASS(this) \
540 if(system_assembly == NULL) { \
541 system_assembly=mono_image_loaded ("System"); \
544 static MonoImage *system_assembly=NULL;
548 static gint32 get_family_hint(void)
550 MonoClass *socket_class;
551 MonoClassField *ipv6_field, *ipv4_field;
552 gint32 ipv6_enabled = -1, ipv4_enabled = -1;
555 socket_class = mono_class_from_name (system_assembly,
556 "System.Net.Sockets", "Socket");
557 ipv4_field = mono_class_get_field_from_name (socket_class,
559 ipv6_field = mono_class_get_field_from_name (socket_class,
561 vtable = mono_class_vtable (mono_domain_get (), socket_class);
563 mono_field_static_get_value(vtable, ipv4_field, &ipv4_enabled);
564 mono_field_static_get_value(vtable, ipv6_field, &ipv6_enabled);
566 if(ipv4_enabled == 1 && ipv6_enabled == 1) {
568 } else if(ipv4_enabled == 1) {
576 gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto, gint32 *error)
589 sock_family=convert_family(family);
590 if(sock_family==-1) {
591 *error = WSAEAFNOSUPPORT;
595 sock_proto=convert_proto(proto);
597 *error = WSAEPROTONOSUPPORT;
601 sock_type=convert_type(type);
603 *error = WSAESOCKTNOSUPPORT;
607 sock = _wapi_socket (sock_family, sock_type, sock_proto,
608 NULL, 0, WSA_FLAG_OVERLAPPED);
610 if(sock==INVALID_SOCKET) {
611 *error = WSAGetLastError ();
615 if (sock_family == AF_INET && sock_type == SOCK_DGRAM) {
616 return (GUINT_TO_POINTER (sock));
620 if (sock_family == AF_INET6 && sock_type == SOCK_DGRAM) {
621 return (GUINT_TO_POINTER (sock));
625 #ifndef PLATFORM_WIN32
626 /* .net seems to set this by default for SOCK_STREAM,
627 * not for SOCK_DGRAM (see bug #36322)
629 * It seems winsock has a rather different idea of what
630 * SO_REUSEADDR means. If it's set, then a new socket can be
631 * bound over an existing listening socket. There's a new
632 * windows-specific option called SO_EXCLUSIVEADDRUSE but
633 * using that means the socket MUST be closed properly, or a
634 * denial of service can occur. Luckily for us, winsock
635 * behaves as though any other system would when SO_REUSEADDR
636 * is true, so we don't need to do anything else here. See
642 ret = _wapi_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (true));
643 if(ret==SOCKET_ERROR) {
644 *error = WSAGetLastError ();
652 return(GUINT_TO_POINTER (sock));
655 /* FIXME: the SOCKET parameter (here and in other functions in this
656 * file) is really an IntPtr which needs to be converted to a guint32.
658 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock,
664 g_message (G_GNUC_PRETTY_FUNCTION ": closing 0x%x", sock);
672 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
677 g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
680 return(WSAGetLastError());
683 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock,
693 ret=ioctlsocket(sock, FIONREAD, &amount);
694 if(ret==SOCKET_ERROR) {
695 *error = WSAGetLastError ();
702 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
712 ret = ioctlsocket (sock, FIONBIO, (gulong *) &block);
713 if(ret==SOCKET_ERROR) {
714 *error = WSAGetLastError ();
718 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock,
727 newsock = _wapi_accept (sock, NULL, 0);
728 if(newsock==INVALID_SOCKET) {
729 *error = WSAGetLastError ();
733 return(GUINT_TO_POINTER (newsock));
736 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
746 ret = _wapi_listen (sock, backlog);
747 if(ret==SOCKET_ERROR) {
748 *error = WSAGetLastError ();
752 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
753 int sa_size, gint32 *error)
755 MonoDomain *domain = mono_domain_get ();
756 MonoObject *sockaddr_obj;
757 MonoClass *sockaddr_class;
758 MonoClassField *field;
760 MonoAddressFamily family;
762 /* Build a System.Net.SocketAddress object instance */
763 sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
764 sockaddr_obj=mono_object_new(domain, sockaddr_class);
766 /* Locate the SocketAddress data buffer in the object */
767 field=mono_class_get_field_from_name(sockaddr_class, "data");
769 /* Make sure there is space for the family and size bytes */
770 data=mono_array_new(domain, mono_defaults.byte_class, sa_size+2);
772 /* The data buffer is laid out as follows:
773 * byte 0 is the address family
774 * byte 1 is the buffer length
775 * bytes 2 and 3 are the port info
776 * the rest is the address info
779 family=convert_to_mono_family(saddr->sa_family);
780 if(family==AddressFamily_Unknown) {
781 *error = WSAEAFNOSUPPORT;
785 mono_array_set(data, guint8, 0, family & 0x0FF);
786 mono_array_set(data, guint8, 1, ((family << 8) & 0x0FFFF));
788 if(saddr->sa_family==AF_INET) {
789 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
790 guint16 port=ntohs(sa_in->sin_port);
791 guint32 address=ntohl(sa_in->sin_addr.s_addr);
794 mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
797 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
798 mono_array_set(data, guint8, 3, (port) & 0xff);
799 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
800 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
801 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
802 mono_array_set(data, guint8, 7, (address) & 0xff);
804 *(MonoArray **)(((char *)sockaddr_obj) + field->offset)=data;
806 return(sockaddr_obj);
808 } else if (saddr->sa_family == AF_INET6) {
809 struct sockaddr_in6 *sa_in=(struct sockaddr_in6 *)saddr;
812 guint16 port=ntohs(sa_in->sin6_port);
815 mono_raise_exception((MonoException *)mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
818 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
819 mono_array_set(data, guint8, 3, (port) & 0xff);
821 for(i=0; i<16; i++) {
822 mono_array_set(data, guint8, 8+i,
823 sa_in->sin6_addr.s6_addr[i]);
826 mono_array_set(data, guint8, 24, sa_in->sin6_scope_id & 0xff);
827 mono_array_set(data, guint8, 25,
828 (sa_in->sin6_scope_id >> 8) & 0xff);
829 mono_array_set(data, guint8, 26,
830 (sa_in->sin6_scope_id >> 16) & 0xff);
831 mono_array_set(data, guint8, 27,
832 (sa_in->sin6_scope_id >> 24) & 0xff);
834 *(MonoArray **)(((char *)sockaddr_obj) + field->offset)=data;
836 return(sockaddr_obj);
839 } else if (saddr->sa_family == AF_UNIX) {
842 for (i = 0; i < sa_size; i++) {
843 mono_array_set (data, guint8, i+2, saddr->sa_data[i]);
846 *(MonoArray **)(((char *)sockaddr_obj) + field->offset) = data;
851 *error = WSAEAFNOSUPPORT;
856 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 *error)
858 gchar sa[32]; /// sockaddr in not big enough for sockaddr_in6
867 ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
869 if(ret==SOCKET_ERROR) {
870 *error = WSAGetLastError ();
875 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));
878 return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
882 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 *error)
884 gchar sa[32]; /// sockaddr in not big enough for sockaddr_in6
893 ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
895 if(ret==SOCKET_ERROR) {
896 *error = WSAGetLastError ();
901 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));
904 return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
908 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
912 MonoClassField *field;
917 /* Dig the SocketAddress data buffer out of the object */
918 field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
919 data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
921 /* The data buffer is laid out as follows:
922 * byte 0 is the address family low byte
923 * byte 1 is the address family high byte
925 * bytes 2 and 3 are the port info
926 * the rest is the address info
928 * the rest is the file name
930 len = mono_array_length (data);
932 mono_raise_exception (mono_exception_from_name(mono_defaults.corlib, "System", "SystemException"));
935 family = convert_family (mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8));
936 if(family==AF_INET) {
937 struct sockaddr_in *sa=g_new0(struct sockaddr_in, 1);
938 guint16 port=(mono_array_get(data, guint8, 2) << 8) +
939 mono_array_get(data, guint8, 3);
940 guint32 address=(mono_array_get(data, guint8, 4) << 24) +
941 (mono_array_get(data, guint8, 5) << 16 ) +
942 (mono_array_get(data, guint8, 6) << 8) +
943 mono_array_get(data, guint8, 7);
945 sa->sin_family=family;
946 sa->sin_addr.s_addr=htonl(address);
947 sa->sin_port=htons(port);
949 *sa_size=sizeof(struct sockaddr_in);
950 return((struct sockaddr *)sa);
953 } else if (family == AF_INET6) {
954 struct sockaddr_in6 *sa=g_new0(struct sockaddr_in6, 1);
957 guint16 port = mono_array_get(data, guint8, 3) + (mono_array_get(data, guint8, 2) << 8);
958 guint32 scopeid = mono_array_get(data, guint8, 24) +
959 (mono_array_get(data, guint8, 25)<<8) +
960 (mono_array_get(data, guint8, 26)<<16) +
961 (mono_array_get(data, guint8, 27)<<24);
963 sa->sin6_family=family;
964 sa->sin6_port=htons(port);
965 sa->sin6_scope_id = scopeid;
968 sa->sin6_addr.s6_addr[i] = mono_array_get(data, guint8, 8+i);
970 *sa_size=sizeof(struct sockaddr_in6);
971 return((struct sockaddr *)sa);
974 } else if (family == AF_UNIX) {
975 struct sockaddr_un *sock_un = g_new0 (struct sockaddr_un, 1);
978 if (len - 2 > MONO_SIZEOF_SUNPATH)
979 mono_raise_exception (mono_get_exception_index_out_of_range ());
981 sock_un->sun_family = family;
982 for (i = 0; i < len - 2; i++)
983 sock_un->sun_path [i] = mono_array_get (data, guint8,
985 sock_un->sun_path [len - 2] = '\0';
986 *sa_size = sizeof (struct sockaddr_un);
988 return (struct sockaddr *)sock_un;
991 *error = WSAEAFNOSUPPORT;
996 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1002 MONO_ARCH_SAVE_REGS;
1006 sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1012 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));
1015 ret = _wapi_bind (sock, sa, sa_size);
1016 if(ret==SOCKET_ERROR) {
1017 *error = WSAGetLastError ();
1030 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1031 gint timeout, gint32 *error)
1036 struct timeval *tvptr;
1039 MONO_ARCH_SAVE_REGS;
1042 /* FIXME: in case of extra iteration (WSAEINTR), substract time
1043 * from the initial timeout */
1046 _wapi_FD_SET (sock, &fds);
1048 divvy = div (timeout, 1000000);
1049 tv.tv_sec = divvy.quot;
1050 tv.tv_usec = divvy.rem;
1056 if (mode == SelectModeRead) {
1057 ret = _wapi_select (0, &fds, NULL, NULL, tvptr);
1058 } else if (mode == SelectModeWrite) {
1059 ret = _wapi_select (0, NULL, &fds, NULL, tvptr);
1060 } else if (mode == SelectModeError) {
1061 ret = _wapi_select (0, NULL, NULL, &fds, tvptr);
1063 g_assert_not_reached ();
1065 } while ((ret == SOCKET_ERROR) && (*error == WSAGetLastError ()) == WSAEINTR);
1067 return (ret != SOCKET_ERROR && _wapi_FD_ISSET (sock, &fds));
1070 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1072 struct sockaddr *sa;
1076 MONO_ARCH_SAVE_REGS;
1080 sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1086 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));
1089 ret = _wapi_connect (sock, sa, sa_size);
1090 if(ret==SOCKET_ERROR) {
1091 *error = WSAGetLastError ();
1097 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1104 MONO_ARCH_SAVE_REGS;
1108 alen=mono_array_length(buffer);
1109 if(offset+count>alen) {
1113 buf=mono_array_addr(buffer, guchar, offset);
1115 ret = _wapi_recv (sock, buf, count, recvflags);
1116 if(ret==SOCKET_ERROR) {
1117 *error = WSAGetLastError ();
1124 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
1130 struct sockaddr *sa;
1133 MONO_ARCH_SAVE_REGS;
1137 alen=mono_array_length(buffer);
1138 if(offset+count>alen) {
1142 sa=create_sockaddr_from_object(*sockaddr, &sa_size, error);
1147 buf=mono_array_addr(buffer, guchar, offset);
1149 ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1150 if(ret==SOCKET_ERROR) {
1152 *error = WSAGetLastError ();
1156 *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
1162 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1169 MONO_ARCH_SAVE_REGS;
1173 alen=mono_array_length(buffer);
1174 if(offset+count>alen) {
1179 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1182 buf=mono_array_addr(buffer, guchar, offset);
1185 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1188 ret = _wapi_send (sock, buf, count, sendflags);
1189 if(ret==SOCKET_ERROR) {
1190 *error = WSAGetLastError ();
1197 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
1203 struct sockaddr *sa;
1206 MONO_ARCH_SAVE_REGS;
1210 alen=mono_array_length(buffer);
1211 if(offset+count>alen) {
1215 sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1221 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1224 buf=mono_array_addr(buffer, guchar, offset);
1227 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1230 ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1231 if(ret==SOCKET_ERROR) {
1232 *error = WSAGetLastError ();
1240 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
1243 MonoClassField *field;
1245 field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
1246 sock=*(SOCKET *)(((char *)sockobj)+field->offset);
1251 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **read_socks, MonoArray **write_socks, MonoArray **err_socks, gint32 timeout, gint32 *error)
1253 fd_set readfds, writefds, errfds;
1254 fd_set *readptr = NULL, *writeptr = NULL, *errptr = NULL;
1258 int readarrsize = 0, writearrsize = 0, errarrsize = 0;
1259 MonoDomain *domain=mono_domain_get();
1260 MonoClass *sock_arr_class;
1266 MONO_ARCH_SAVE_REGS;
1269 readarrsize=mono_array_length(*read_socks);
1273 if(readarrsize>FD_SETSIZE) {
1281 for(i=0; i<readarrsize; i++) {
1282 handle = Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i));
1283 _wapi_FD_SET(handle, &readfds);
1288 writearrsize=mono_array_length(*write_socks);
1290 if(writearrsize>FD_SETSIZE) {
1296 writeptr = &writefds;
1298 for(i=0; i<writearrsize; i++) {
1299 handle = Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i));
1300 _wapi_FD_SET(handle, &writefds);
1305 errarrsize=mono_array_length(*err_socks);
1307 if(errarrsize>FD_SETSIZE) {
1315 for(i=0; i<errarrsize; i++) {
1316 handle = Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i));
1317 _wapi_FD_SET(handle, &errfds);
1321 /* Negative timeout meaning block until ready is only
1322 * specified in Poll, not Select
1325 divvy = div (timeout, 1000000);
1329 tv.tv_sec=divvy.quot;
1330 tv.tv_usec=divvy.rem;
1332 ret = _wapi_select (0, readptr, writeptr, errptr, &tv);
1334 ret = _wapi_select (0, readptr, writeptr, errptr, NULL);
1336 } while ((ret==SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR));
1338 if(ret==SOCKET_ERROR) {
1339 *error = WSAGetLastError ();
1344 sock_arr_class=((MonoObject *)*read_socks)->vtable->klass;
1347 for(i=0; i<readarrsize; i++) {
1348 if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*read_socks, MonoObject *, i)), &readfds)) {
1352 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
1354 for(i=0; i<readarrsize; i++) {
1355 MonoObject *sock=mono_array_get(*read_socks, MonoObject *, i);
1357 if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &readfds)) {
1358 mono_array_set(socks, MonoObject *, count, sock);
1368 sock_arr_class=((MonoObject *)*write_socks)->vtable->klass;
1370 for(i=0; i<writearrsize; i++) {
1371 if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*write_socks, MonoObject *, i)), &writefds)) {
1375 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
1377 for(i=0; i<writearrsize; i++) {
1378 MonoObject *sock=mono_array_get(*write_socks, MonoObject *, i);
1380 if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &writefds)) {
1381 mono_array_set(socks, MonoObject *, count, sock);
1387 *write_socks = NULL;
1391 sock_arr_class=((MonoObject *)*err_socks)->vtable->klass;
1393 for(i=0; i<errarrsize; i++) {
1394 if(_wapi_FD_ISSET(Socket_to_SOCKET(mono_array_get(*err_socks, MonoObject *, i)), &errfds)) {
1398 socks=mono_array_new_full(domain, sock_arr_class, &count, NULL);
1400 for(i=0; i<errarrsize; i++) {
1401 MonoObject *sock=mono_array_get(*err_socks, MonoObject *, i);
1403 if(_wapi_FD_ISSET(Socket_to_SOCKET(sock), &errfds)) {
1404 mono_array_set(socks, MonoObject *, count, sock);
1412 static MonoObject* int_to_object (MonoDomain *domain, int val)
1414 /* construct an Int32 object to hold val */
1415 MonoObject* obj = mono_object_new(domain, mono_defaults.int32_class);
1417 /* Locate and set the "m_value" field */
1418 MonoClassField *field = mono_class_get_field_from_name(mono_defaults.int32_class,
1420 *(gint32 *)(((char *)obj)+field->offset)=val;
1425 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error)
1431 int valsize=sizeof(val);
1432 struct linger linger;
1433 int lingersize=sizeof(linger);
1435 int tvsize=sizeof(tv);
1436 MonoDomain *domain=mono_domain_get();
1438 MonoClass *obj_class;
1439 MonoClassField *field;
1441 MONO_ARCH_SAVE_REGS;
1445 ret=convert_sockopt_level_and_name(level, name, &system_level,
1448 *error = WSAENOPROTOOPT;
1452 /* No need to deal with MulticastOption names here, because
1453 * you cant getsockopt AddMembership or DropMembership (the
1454 * int getsockopt will error, causing an exception)
1457 case SocketOptionName_Linger:
1458 case SocketOptionName_DontLinger:
1459 ret = _wapi_getsockopt(sock, system_level, system_name, &linger,
1463 case SocketOptionName_SendTimeout:
1464 case SocketOptionName_ReceiveTimeout:
1465 ret = _wapi_getsockopt (sock, system_level, system_name, &tv,
1470 ret = _wapi_getsockopt (sock, system_level, system_name, &val,
1474 if(ret==SOCKET_ERROR) {
1475 *error = WSAGetLastError ();
1480 case SocketOptionName_Linger:
1481 /* build a System.Net.Sockets.LingerOption */
1482 obj_class=mono_class_from_name(system_assembly,
1483 "System.Net.Sockets",
1485 obj=mono_object_new(domain, obj_class);
1487 /* Locate and set the fields "bool enabled" and "int
1490 field=mono_class_get_field_from_name(obj_class, "enabled");
1491 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1493 field=mono_class_get_field_from_name(obj_class, "seconds");
1494 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1498 case SocketOptionName_DontLinger:
1499 /* construct a bool int in val - true if linger is off */
1500 obj = int_to_object (domain, !linger.l_onoff);
1503 case SocketOptionName_SendTimeout:
1504 case SocketOptionName_ReceiveTimeout:
1505 obj = int_to_object (domain, (tv.tv_sec * 1000) + (tv.tv_usec / 1000));
1509 obj = int_to_object (domain, val);
1515 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error)
1523 MONO_ARCH_SAVE_REGS;
1527 ret=convert_sockopt_level_and_name(level, name, &system_level,
1530 *error = WSAENOPROTOOPT;
1534 valsize=mono_array_length(*byte_val);
1535 buf=mono_array_addr(*byte_val, guchar, 0);
1537 ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
1538 if(ret==SOCKET_ERROR) {
1539 *error = WSAGetLastError ();
1543 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1544 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1546 struct in_addr inaddr;
1547 MonoClassField *field;
1549 field=mono_class_get_field_from_name(ipaddr->vtable->klass, "address");
1551 /* No idea why .net uses a 64bit type to hold a 32bit value...
1553 * Internal value of IPAddess is in Network Order, there is no need
1554 * to call htonl here.
1556 inaddr.s_addr=(guint32)*(guint64 *)(((char *)ipaddr)+field->offset);
1563 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
1565 struct in6_addr in6addr;
1566 MonoClassField *field;
1570 field=mono_class_get_field_from_name(ipaddr->vtable->klass, "_numbers");
1571 data=*(MonoArray **)(((char *)ipaddr) + field->offset);
1573 /* Solaris has only the 8 bit version. */
1575 for(i=0; i<8; i++) {
1576 guint16 s = mono_array_get (data, guint16, i);
1577 in6addr.s6_addr[2 * i] = (s >> 8) & 0xff;
1578 in6addr.s6_addr[2 * i + 1] = s & 0xff;
1582 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
1586 #endif /* AF_INET6 */
1588 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)
1599 #ifdef HAVE_SOL_IPV6
1600 sol_ipv6 = SOL_IPV6;
1603 struct protoent *pent;
1604 pent = getprotobyname ("ipv6");
1605 sol_ipv6 = (pent != NULL) ? pent->p_proto : 41;
1613 struct protoent *pent;
1614 pent = getprotobyname ("ip");
1615 sol_ip = (pent != NULL) ? pent->p_proto : 0;
1618 #endif /* AF_INET6 */
1620 MONO_ARCH_SAVE_REGS;
1622 ret=convert_sockopt_level_and_name(level, name, &system_level,
1625 *error = WSAENOPROTOOPT;
1629 /* Only one of obj_val, byte_val or int_val has data */
1631 MonoClassField *field;
1632 struct linger linger;
1636 case SocketOptionName_DontLinger:
1639 valsize=sizeof(linger);
1640 ret = _wapi_setsockopt (sock, system_level,
1641 system_name, &linger, valsize);
1644 case SocketOptionName_Linger:
1645 /* Dig out "bool enabled" and "int seconds"
1648 field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1649 linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1650 field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1651 linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1653 valsize=sizeof(linger);
1654 ret = _wapi_setsockopt (sock, system_level,
1655 system_name, &linger, valsize);
1657 case SocketOptionName_AddMembership:
1658 case SocketOptionName_DropMembership:
1659 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1661 MonoObject *address = NULL;
1664 if(system_level == sol_ipv6) {
1665 struct ipv6_mreq mreq6;
1670 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1671 address = *(gpointer *)(((char *)obj_val) + field->offset);
1674 mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
1677 field=mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
1678 mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
1680 ret = _wapi_setsockopt (sock, system_level,
1681 system_name, &mreq6,
1683 } else if(system_level == sol_ip)
1684 #endif /* AF_INET6 */
1686 #ifdef HAVE_STRUCT_IP_MREQN
1687 struct ip_mreqn mreq = {{0}};
1689 struct ip_mreq mreq = {{0}};
1690 #endif /* HAVE_STRUCT_IP_MREQN */
1692 /* pain! MulticastOption holds two IPAddress
1693 * members, so I have to dig the value out of
1696 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1697 address = *(gpointer *)(((char *)obj_val) + field->offset);
1699 /* address might not be defined and if so, set the address to ADDR_ANY.
1702 mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
1705 field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1706 address = *(gpointer *)(((char *)obj_val) + field->offset);
1708 #ifdef HAVE_STRUCT_IP_MREQN
1710 mreq.imr_address = ipaddress_to_struct_in_addr (address);
1714 mreq.imr_interface = ipaddress_to_struct_in_addr (address);
1716 #endif /* HAVE_STRUCT_IP_MREQN */
1718 ret = _wapi_setsockopt (sock, system_level,
1724 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
1726 /* Cause an exception to be thrown */
1730 } else if (byte_val!=NULL) {
1731 int valsize=mono_array_length(byte_val);
1732 guchar *buf=mono_array_addr(byte_val, guchar, 0);
1734 ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
1735 if(ret==SOCKET_ERROR) {
1736 *error = WSAGetLastError ();
1741 case SocketOptionName_SendTimeout:
1742 case SocketOptionName_ReceiveTimeout: {
1744 tv.tv_sec = int_val / 1000;
1745 tv.tv_usec = (int_val % 1000) * 1000;
1746 ret = _wapi_setsockopt (sock, system_level, system_name, &tv, sizeof (tv));
1750 ret = _wapi_setsockopt (sock, system_level, system_name, &int_val,
1755 if(ret==SOCKET_ERROR) {
1756 *error = WSAGetLastError ();
1760 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
1766 MONO_ARCH_SAVE_REGS;
1770 /* Currently, the values for how (recv=0, send=1, both=2) match
1773 ret = _wapi_shutdown (sock, how);
1774 if(ret==SOCKET_ERROR) {
1775 *error = WSAGetLastError ();
1780 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
1782 MonoArray *output, gint32 *error)
1784 gulong output_bytes = 0;
1785 gchar *i_buffer, *o_buffer;
1789 MONO_ARCH_SAVE_REGS;
1793 if (code == FIONBIO) {
1794 /* Invalid command. Must use Socket.Blocking */
1798 if (input == NULL) {
1802 i_buffer = mono_array_addr (input, gchar, 0);
1803 i_len = mono_array_length (input);
1806 if (output == NULL) {
1810 o_buffer = mono_array_addr (output, gchar, 0);
1811 o_len = mono_array_length (output);
1814 ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
1815 if (ret == SOCKET_ERROR) {
1816 *error = WSAGetLastError ();
1820 return (gint) output_bytes;
1824 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
1825 MonoArray **h_aliases,
1826 MonoArray **h_addr_list)
1828 MonoDomain *domain = mono_domain_get ();
1831 if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
1835 *h_name=mono_string_new(domain, he->h_name);
1838 while(he->h_aliases[i]!=NULL) {
1842 *h_aliases=mono_array_new(domain, mono_defaults.string_class, i);
1844 while(he->h_aliases[i]!=NULL) {
1847 alias=mono_string_new(domain, he->h_aliases[i]);
1848 mono_array_set(*h_aliases, MonoString *, i, alias);
1853 while(he->h_addr_list[i]!=NULL) {
1857 *h_addr_list=mono_array_new(domain, mono_defaults.string_class, i);
1859 while(he->h_addr_list[i]!=NULL) {
1860 MonoString *addr_string;
1863 g_snprintf(addr, 16, "%u.%u.%u.%u",
1864 (unsigned char)he->h_addr_list[i][0],
1865 (unsigned char)he->h_addr_list[i][1],
1866 (unsigned char)he->h_addr_list[i][2],
1867 (unsigned char)he->h_addr_list[i][3]);
1869 addr_string=mono_string_new(domain, addr);
1870 mono_array_set(*h_addr_list, MonoString *, i, addr_string);
1878 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
1879 static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
1881 MonoDomain *domain = mono_domain_get ();
1882 int i, host_count, host_index, family_hint;
1884 family_hint = get_family_hint ();
1886 if(he1 == NULL && he2 == NULL) {
1891 * Check if address length and family are correct
1893 if (he1 != NULL && (he1->h_length!=4 || he1->h_addrtype!=AF_INET)) {
1897 if (he2 != NULL && (he2->h_length!=16 || he2->h_addrtype!=AF_INET6)) {
1902 * Get the aliases and host name from he1 or he2 whichever is
1903 * not null, if he1 is not null then take aliases from he1
1905 if (he1 != NULL && (family_hint == PF_UNSPEC ||
1906 family_hint == PF_INET)) {
1907 *h_name=mono_string_new (domain, he1->h_name);
1910 while(he1->h_aliases[i]!=NULL) {
1914 *h_aliases=mono_array_new (domain, mono_defaults.string_class,
1917 while(he1->h_aliases[i]!=NULL) {
1920 alias=mono_string_new (domain, he1->h_aliases[i]);
1921 mono_array_set (*h_aliases, MonoString *, i, alias);
1924 } else if (family_hint == PF_UNSPEC || family_hint == PF_INET6) {
1925 *h_name=mono_string_new (domain, he2->h_name);
1928 while(he2->h_aliases [i] != NULL) {
1932 *h_aliases=mono_array_new (domain, mono_defaults.string_class,
1935 while(he2->h_aliases[i]!=NULL) {
1938 alias=mono_string_new (domain, he2->h_aliases[i]);
1939 mono_array_set (*h_aliases, MonoString *, i, alias);
1945 * Count the number of addresses in he1 + he2
1948 if (he1 != NULL && (family_hint == PF_UNSPEC ||
1949 family_hint == PF_INET)) {
1951 while(he1->h_addr_list[i]!=NULL) {
1957 if (he2 != NULL && (family_hint == PF_UNSPEC ||
1958 family_hint == PF_INET6)) {
1960 while(he2->h_addr_list[i]!=NULL) {
1969 *h_addr_list=mono_array_new (domain, mono_defaults.string_class,
1974 if (he2 != NULL && (family_hint == PF_UNSPEC ||
1975 family_hint == PF_INET6)) {
1977 while(he2->h_addr_list[i] != NULL) {
1978 MonoString *addr_string;
1981 inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
1984 addr_string = mono_string_new (domain, addr);
1985 mono_array_set (*h_addr_list, MonoString *, host_index,
1992 if (he1 != NULL && (family_hint == PF_UNSPEC ||
1993 family_hint == PF_INET)) {
1995 while(he1->h_addr_list[i] != NULL) {
1996 MonoString *addr_string;
1999 inet_ntop (AF_INET, he1->h_addr_list[i], addr,
2002 addr_string=mono_string_new (domain, addr);
2003 mono_array_set (*h_addr_list, MonoString *, host_index,
2014 #if defined(AF_INET6)
2016 addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
2017 MonoArray **h_aliases,
2018 MonoArray **h_addr_list)
2021 struct addrinfo *ai = NULL;
2023 MonoDomain *domain = mono_domain_get ();
2025 for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
2026 if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
2033 *h_aliases=mono_array_new(domain, mono_defaults.string_class, 0);
2034 *h_addr_list=mono_array_new(domain, mono_defaults.string_class, count);
2036 for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
2037 MonoString *addr_string;
2040 gint32 buffer_size = 0;
2042 if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
2048 buffer = g_malloc0(buffer_size);
2050 if(ai->ai_family == PF_INET) {
2051 ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, buffer_size);
2053 ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, buffer_size);
2060 } while(ret == 0 && errno == ENOSPC);
2063 addr_string=mono_string_new(domain, buffer);
2066 addr_string=mono_string_new(domain, "");
2069 mono_array_set(*h_addr_list, MonoString *, i, addr_string);
2071 if(!i && ai->ai_canonname != NULL) {
2072 *h_name=mono_string_new(domain, ai->ai_canonname);
2087 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2089 #if !defined(HAVE_GETHOSTBYNAME2_R)
2090 struct addrinfo *info = NULL, hints;
2093 MONO_ARCH_SAVE_REGS;
2095 hostname=mono_string_to_utf8 (host);
2097 memset(&hints, 0, sizeof(hints));
2098 hints.ai_family = get_family_hint ();
2099 hints.ai_socktype = SOCK_STREAM;
2100 hints.ai_flags = AI_CANONNAME;
2102 if (getaddrinfo(hostname, NULL, &hints, &info) == -1) {
2108 return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list));
2110 struct hostent he1,*hp1, he2, *hp2;
2111 int buffer_size1, buffer_size2;
2112 char *buffer1, *buffer2;
2114 gboolean return_value;
2117 MONO_ARCH_SAVE_REGS;
2119 hostname=mono_string_to_utf8 (host);
2123 buffer1 = g_malloc0(buffer_size1);
2124 buffer2 = g_malloc0(buffer_size2);
2126 while (gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1,
2127 &hp1, &herr) == ERANGE) {
2129 buffer1 = g_realloc(buffer1, buffer_size1);
2132 while (gethostbyname2_r(hostname, AF_INET6, &he2, buffer2,
2133 buffer_size2, &hp2, &herr) == ERANGE) {
2135 buffer2 = g_realloc(buffer2, buffer_size2);
2138 return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
2144 return(return_value);
2145 #endif /* HAVE_GETHOSTBYNAME2_R */
2147 #else /* AF_INET6 */
2148 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2153 MONO_ARCH_SAVE_REGS;
2155 hostname=mono_string_to_utf8(host);
2157 he = _wapi_gethostbyname (hostname);
2164 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list));
2166 #endif /* AF_INET6 */
2168 #ifndef HAVE_INET_PTON
2170 inet_pton (int family, const char *address, void *inaddrp)
2172 if (family == AF_INET) {
2173 #ifdef HAVE_INET_ATON
2174 struct in_addr inaddr;
2176 if (!inet_aton (address, &inaddr))
2179 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
2182 /* assume the system has inet_addr(), if it doesn't
2183 have that we're pretty much screwed... */
2186 if (!strcmp (address, "255.255.255.255")) {
2187 /* special-case hack */
2188 inaddr = 0xffffffff;
2190 inaddr = inet_addr (address);
2192 #define INADDR_NONE ((in_addr_t) -1)
2194 if (inaddr == INADDR_NONE)
2198 memcpy (inaddrp, &inaddr, sizeof (guint32));
2200 #endif /* HAVE_INET_ATON */
2205 #endif /* !HAVE_INET_PTON */
2207 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2212 struct sockaddr_in saddr;
2213 struct sockaddr_in6 saddr6;
2214 struct addrinfo *info = NULL, hints;
2216 char hostname[1024] = {0};
2218 struct in_addr inaddr;
2222 MONO_ARCH_SAVE_REGS;
2224 address = mono_string_to_utf8 (addr);
2227 if (inet_pton (AF_INET, address, &saddr.sin_addr ) <= 0) {
2228 /* Maybe an ipv6 address */
2229 if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) <= 0) {
2235 saddr6.sin6_family = AF_INET6;
2240 saddr.sin_family = AF_INET;
2244 if(family == AF_INET) {
2245 if(getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr),
2246 hostname, sizeof(hostname), NULL, 0,
2247 NI_NAMEREQD) != 0) {
2250 } else if(family == AF_INET6) {
2251 if(getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6),
2252 hostname, sizeof(hostname), NULL, 0,
2253 NI_NAMEREQD) != 0) {
2258 memset (&hints, 0, sizeof(hints));
2259 hints.ai_family = get_family_hint ();
2260 hints.ai_socktype = SOCK_STREAM;
2261 hints.ai_flags = AI_CANONNAME;
2263 if( getaddrinfo (hostname, NULL, &hints, &info) == -1 ) {
2267 return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list));
2269 if (inet_pton (AF_INET, address, &inaddr) <= 0) {
2275 if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) {
2279 return(hostent_to_IPHostEntry (he, h_name, h_aliases, h_addr_list));
2283 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
2285 guchar hostname[256];
2288 MONO_ARCH_SAVE_REGS;
2290 ret = gethostname (hostname, sizeof (hostname));
2295 *h_name=mono_string_new(mono_domain_get (), hostname);
2301 /* Async interface */
2304 ves_icall_System_Net_Sockets_Socket_AsyncReceive (MonoSocketAsyncResult *ares, gint *error)
2306 MONO_ARCH_SAVE_REGS;
2308 *error = ERROR_NOT_SUPPORTED;
2312 ves_icall_System_Net_Sockets_Socket_AsyncSend (MonoSocketAsyncResult *ares, gint *error)
2314 MONO_ARCH_SAVE_REGS;
2316 *error = ERROR_NOT_SUPPORTED;
2320 wsa_overlapped_callback (guint32 error, guint32 numbytes, gpointer result)
2322 MonoSocketAsyncResult *ares = (MonoSocketAsyncResult *) result;
2325 ares->completed = TRUE;
2326 ares->error = error;
2327 ares->total = numbytes;
2329 if (ares->callback != NULL) {
2333 thread = mono_thread_attach (mono_object_domain (ares));
2334 mono_runtime_invoke (ares->callback->method_info->method, NULL, p, NULL);
2336 mono_thread_detach (thread);
2339 if (ares->wait_handle != NULL)
2340 SetEvent (ares->wait_handle->handle);
2344 ves_icall_System_Net_Sockets_Socket_AsyncReceive (MonoSocketAsyncResult *ares, gint *error)
2348 MONO_ARCH_SAVE_REGS;
2350 if (_wapi_socket_async_read (ares->handle,
2351 mono_array_addr (ares->buffer, gchar, ares->offset),
2355 wsa_overlapped_callback) == FALSE) {
2356 *error = WSAGetLastError ();
2359 ares->completed_synch = TRUE;
2360 wsa_overlapped_callback (0, bytesread, ares);
2365 ves_icall_System_Net_Sockets_Socket_AsyncSend (MonoSocketAsyncResult *ares, gint *error)
2367 gint32 byteswritten;
2369 MONO_ARCH_SAVE_REGS;
2371 if (_wapi_socket_async_write (ares->handle,
2372 mono_array_addr (ares->buffer, gchar, ares->offset),
2376 wsa_overlapped_callback) == FALSE) {
2377 *error = WSAGetLastError ();
2380 ares->completed_synch = TRUE;
2381 wsa_overlapped_callback (0, byteswritten, ares);
2384 #endif /* USE_AIO */
2386 void mono_network_init(void)
2391 err=WSAStartup(MAKEWORD(2,0), &wsadata);
2393 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
2398 g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
2399 g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
2403 void mono_network_cleanup(void)