2 * socket-io.c: Socket IO internal calls
5 * Dick Porter (dick@ximian.com)
6 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * This file has been re-licensed under the MIT License:
12 * http://opensource.org/licenses/MIT
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
18 #ifndef DISABLE_SOCKETS
20 #if defined(__APPLE__) || defined(__FreeBSD__)
21 #define __APPLE_USE_RFC_3542
30 #include <sys/socket.h>
31 #ifdef HAVE_SYS_IOCTL_H
32 #include <sys/ioctl.h>
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
39 #include <arpa/inet.h>
46 #include <sys/types.h>
48 #include <mono/metadata/object.h>
49 #include <mono/io-layer/io-layer.h>
50 #include <mono/metadata/socket-io.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/assembly.h>
53 #include <mono/metadata/appdomain.h>
54 #include <mono/metadata/file-io.h>
55 #include <mono/metadata/threads.h>
56 #include <mono/metadata/threads-types.h>
57 #include <mono/metadata/threadpool-ms-io.h>
58 #include <mono/utils/mono-poll.h>
59 /* FIXME change this code to not mess so much with the internals */
60 #include <mono/metadata/class-internals.h>
61 #include <mono/metadata/domain-internals.h>
62 #include <mono/utils/mono-threads.h>
63 #include <mono/utils/mono-memory-model.h>
64 #include <mono/utils/networking.h>
65 #include <mono/utils/w32handle.h>
68 #ifdef HAVE_SYS_TIME_H
71 #ifdef HAVE_SYS_IOCTL_H
72 #include <sys/ioctl.h>
81 #ifdef HAVE_SYS_FILIO_H
82 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
84 #ifdef HAVE_SYS_SOCKIO_H
85 #include <sys/sockio.h> /* defines SIOCATMARK */
91 #ifdef HAVE_GETIFADDRS
92 // <net/if.h> must be included before <ifaddrs.h>
96 #include "mono/io-layer/socket-wrappers.h"
99 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
102 abort_syscall (gpointer data)
104 mono_thread_info_abort_socket_syscall_for_close ((MonoNativeThreadId) (gsize) data);
108 convert_family (MonoAddressFamily mono_family)
110 switch (mono_family) {
111 case AddressFamily_Unknown:
112 case AddressFamily_ImpLink:
113 case AddressFamily_Pup:
114 case AddressFamily_Chaos:
115 case AddressFamily_Iso:
116 case AddressFamily_Ecma:
117 case AddressFamily_DataKit:
118 case AddressFamily_Ccitt:
119 case AddressFamily_DataLink:
120 case AddressFamily_Lat:
121 case AddressFamily_HyperChannel:
122 case AddressFamily_NetBios:
123 case AddressFamily_VoiceView:
124 case AddressFamily_FireFox:
125 case AddressFamily_Banyan:
126 case AddressFamily_Atm:
127 case AddressFamily_Cluster:
128 case AddressFamily_Ieee12844:
129 case AddressFamily_NetworkDesigners:
130 g_warning ("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
132 case AddressFamily_Unspecified:
134 case AddressFamily_Unix:
136 case AddressFamily_InterNetwork:
138 case AddressFamily_AppleTalk:
140 case AddressFamily_InterNetworkV6:
142 case AddressFamily_DecNet:
148 case AddressFamily_Ipx:
154 case AddressFamily_Sna:
160 case AddressFamily_Irda:
167 g_warning ("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
172 static MonoAddressFamily
173 convert_to_mono_family (guint16 af_family)
177 return AddressFamily_Unspecified;
179 return AddressFamily_Unix;
181 return AddressFamily_InterNetwork;
184 return AddressFamily_Ipx;
188 return AddressFamily_Sna;
192 return AddressFamily_DecNet;
195 return AddressFamily_AppleTalk;
197 return AddressFamily_InterNetworkV6;
200 return AddressFamily_Irda;
203 g_warning ("unknown address family 0x%x", af_family);
204 return AddressFamily_Unknown;
209 convert_type (MonoSocketType mono_type)
212 case SocketType_Stream:
214 case SocketType_Dgram:
224 case SocketType_Seqpacket:
225 return SOCK_SEQPACKET;
226 case SocketType_Unknown:
227 g_warning ("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
230 g_warning ("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
236 convert_proto (MonoProtocolType mono_proto)
238 switch (mono_proto) {
239 case ProtocolType_IP:
240 case ProtocolType_IPv6:
241 case ProtocolType_Icmp:
242 case ProtocolType_Igmp:
243 case ProtocolType_Ggp:
244 case ProtocolType_Tcp:
245 case ProtocolType_Pup:
246 case ProtocolType_Udp:
247 case ProtocolType_Idp:
248 /* These protocols are known (on my system at least) */
250 case ProtocolType_ND:
251 case ProtocolType_Raw:
252 case ProtocolType_Ipx:
253 case ProtocolType_Spx:
254 case ProtocolType_SpxII:
255 case ProtocolType_Unknown:
256 /* These protocols arent */
257 g_warning ("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
264 /* Convert MonoSocketFlags */
266 convert_socketflags (gint32 sflags)
271 /* SocketFlags.None */
274 if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek |
275 SocketFlags_DontRoute | SocketFlags_Partial))
276 /* Contains invalid flag values */
279 if (sflags & SocketFlags_OutOfBand)
281 if (sflags & SocketFlags_Peek)
283 if (sflags & SocketFlags_DontRoute)
284 flags |= MSG_DONTROUTE;
286 /* Ignore Partial - see bug 349688. Don't return -1, because
287 * according to the comment in that bug ms runtime doesn't for
288 * UDP sockets (this means we will silently ignore it for TCP
292 if (sflags & SocketFlags_Partial)
296 /* Don't do anything for MaxIOVectorLength */
297 if (sflags & SocketFlags_MaxIOVectorLength)
305 * 0 on success (mapped mono_level and mono_name to system_level and system_name
307 * -2 on non-fatal error (ie, must ignore)
310 convert_sockopt_level_and_name (MonoSocketOptionLevel mono_level, MonoSocketOptionName mono_name, int *system_level, int *system_name)
312 switch (mono_level) {
313 case SocketOptionLevel_Socket:
314 *system_level = SOL_SOCKET;
317 case SocketOptionName_DontLinger:
318 /* This is SO_LINGER, because the setsockopt
319 * internal call maps DontLinger to SO_LINGER
322 *system_name = SO_LINGER;
324 case SocketOptionName_Debug:
325 *system_name = SO_DEBUG;
328 case SocketOptionName_AcceptConnection:
329 *system_name = SO_ACCEPTCONN;
332 case SocketOptionName_ReuseAddress:
333 *system_name = SO_REUSEADDR;
335 case SocketOptionName_KeepAlive:
336 *system_name = SO_KEEPALIVE;
338 case SocketOptionName_DontRoute:
339 *system_name = SO_DONTROUTE;
341 case SocketOptionName_Broadcast:
342 *system_name = SO_BROADCAST;
344 case SocketOptionName_Linger:
345 *system_name = SO_LINGER;
347 case SocketOptionName_OutOfBandInline:
348 *system_name = SO_OOBINLINE;
350 case SocketOptionName_SendBuffer:
351 *system_name = SO_SNDBUF;
353 case SocketOptionName_ReceiveBuffer:
354 *system_name = SO_RCVBUF;
356 case SocketOptionName_SendLowWater:
357 *system_name = SO_SNDLOWAT;
359 case SocketOptionName_ReceiveLowWater:
360 *system_name = SO_RCVLOWAT;
362 case SocketOptionName_SendTimeout:
363 *system_name = SO_SNDTIMEO;
365 case SocketOptionName_ReceiveTimeout:
366 *system_name = SO_RCVTIMEO;
368 case SocketOptionName_Error:
369 *system_name = SO_ERROR;
371 case SocketOptionName_Type:
372 *system_name = SO_TYPE;
375 case SocketOptionName_PeerCred:
376 *system_name = SO_PEERCRED;
379 case SocketOptionName_ExclusiveAddressUse:
380 #ifdef SO_EXCLUSIVEADDRUSE
381 *system_name = SO_EXCLUSIVEADDRUSE;
384 case SocketOptionName_UseLoopback:
385 #ifdef SO_USELOOPBACK
386 *system_name = SO_USELOOPBACK;
389 case SocketOptionName_MaxConnections:
391 *system_name = SO_MAXCONN;
393 #elif defined(SOMAXCONN)
394 *system_name = SOMAXCONN;
398 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
403 case SocketOptionLevel_IP:
404 *system_level = mono_networking_get_ip_protocol ();
407 case SocketOptionName_IPOptions:
408 *system_name = IP_OPTIONS;
411 case SocketOptionName_HeaderIncluded:
412 *system_name = IP_HDRINCL;
416 case SocketOptionName_TypeOfService:
417 *system_name = IP_TOS;
421 case SocketOptionName_IpTimeToLive:
422 *system_name = IP_TTL;
425 case SocketOptionName_MulticastInterface:
426 *system_name = IP_MULTICAST_IF;
428 case SocketOptionName_MulticastTimeToLive:
429 *system_name = IP_MULTICAST_TTL;
431 case SocketOptionName_MulticastLoopback:
432 *system_name = IP_MULTICAST_LOOP;
434 case SocketOptionName_AddMembership:
435 *system_name = IP_ADD_MEMBERSHIP;
437 case SocketOptionName_DropMembership:
438 *system_name = IP_DROP_MEMBERSHIP;
440 #ifdef HAVE_IP_PKTINFO
441 case SocketOptionName_PacketInformation:
442 *system_name = IP_PKTINFO;
444 #endif /* HAVE_IP_PKTINFO */
446 case SocketOptionName_DontFragment:
447 #ifdef HAVE_IP_DONTFRAGMENT
448 *system_name = IP_DONTFRAGMENT;
450 #elif defined HAVE_IP_MTU_DISCOVER
451 /* Not quite the same */
452 *system_name = IP_MTU_DISCOVER;
455 /* If the flag is not available on this system, we can ignore this error */
457 #endif /* HAVE_IP_DONTFRAGMENT */
458 case SocketOptionName_AddSourceMembership:
459 case SocketOptionName_DropSourceMembership:
460 case SocketOptionName_BlockSource:
461 case SocketOptionName_UnblockSource:
462 /* Can't figure out how to map these, so fall
466 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
471 case SocketOptionLevel_IPv6:
472 *system_level = mono_networking_get_ipv6_protocol ();
475 case SocketOptionName_IpTimeToLive:
476 case SocketOptionName_HopLimit:
477 *system_name = IPV6_UNICAST_HOPS;
479 case SocketOptionName_MulticastInterface:
480 *system_name = IPV6_MULTICAST_IF;
482 case SocketOptionName_MulticastTimeToLive:
483 *system_name = IPV6_MULTICAST_HOPS;
485 case SocketOptionName_MulticastLoopback:
486 *system_name = IPV6_MULTICAST_LOOP;
488 case SocketOptionName_AddMembership:
489 *system_name = IPV6_JOIN_GROUP;
491 case SocketOptionName_DropMembership:
492 *system_name = IPV6_LEAVE_GROUP;
494 case SocketOptionName_IPv6Only:
496 *system_name = IPV6_V6ONLY;
501 case SocketOptionName_PacketInformation:
502 #ifdef HAVE_IPV6_PKTINFO
503 *system_name = IPV6_PKTINFO;
506 case SocketOptionName_HeaderIncluded:
507 case SocketOptionName_IPOptions:
508 case SocketOptionName_TypeOfService:
509 case SocketOptionName_DontFragment:
510 case SocketOptionName_AddSourceMembership:
511 case SocketOptionName_DropSourceMembership:
512 case SocketOptionName_BlockSource:
513 case SocketOptionName_UnblockSource:
514 /* Can't figure out how to map these, so fall
518 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
521 break; /* SocketOptionLevel_IPv6 */
523 case SocketOptionLevel_Tcp:
524 *system_level = mono_networking_get_tcp_protocol ();
527 case SocketOptionName_NoDelay:
528 *system_name = TCP_NODELAY;
531 /* The documentation is talking complete
532 * bollocks here: rfc-1222 is titled
533 * 'Advancing the NSFNET Routing Architecture'
534 * and doesn't mention either of the words
535 * "expedite" or "urgent".
537 case SocketOptionName_BsdUrgent:
538 case SocketOptionName_Expedited:
541 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
546 case SocketOptionLevel_Udp:
547 g_warning ("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
550 case SocketOptionName_NoChecksum:
551 case SocketOptionName_ChecksumCoverage:
553 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
560 g_warning ("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
568 get_socket_assembly (void)
570 MonoDomain *domain = mono_domain_get ();
572 if (domain->socket_assembly == NULL) {
573 MonoImage *socket_assembly;
575 socket_assembly = mono_image_loaded ("System");
576 if (!socket_assembly) {
577 MonoAssembly *sa = mono_assembly_open ("System.dll", NULL);
580 g_assert_not_reached ();
582 socket_assembly = mono_assembly_get_image (sa);
585 mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
588 return domain->socket_assembly;
592 get_family_hint (MonoError *error)
594 MonoDomain *domain = mono_domain_get ();
596 mono_error_init (error);
598 if (!domain->inet_family_hint) {
599 MonoImage *socket_assembly;
600 MonoClass *socket_class;
601 MonoClassField *ipv6_field, *ipv4_field;
602 gint32 ipv6_enabled = -1, ipv4_enabled = -1;
605 socket_assembly = get_socket_assembly ();
606 g_assert (socket_assembly);
608 socket_class = mono_class_load_from_name (socket_assembly, "System.Net.Sockets", "Socket");
610 ipv4_field = mono_class_get_field_from_name (socket_class, "ipv4_supported");
611 g_assert (ipv4_field);
613 ipv6_field = mono_class_get_field_from_name (socket_class, "ipv6_supported");
614 g_assert (ipv6_field);
616 vtable = mono_class_vtable (mono_domain_get (), socket_class);
619 mono_runtime_class_init_full (vtable, error);
620 return_val_if_nok (error, -1);
622 mono_field_static_get_value_checked (vtable, ipv4_field, &ipv4_enabled, error);
623 return_val_if_nok (error, -1);
624 mono_field_static_get_value_checked (vtable, ipv6_field, &ipv6_enabled, error);
625 return_val_if_nok (error, -1);
627 mono_domain_lock (domain);
628 if (ipv4_enabled == 1 && ipv6_enabled == 1) {
629 domain->inet_family_hint = 1;
630 } else if (ipv4_enabled == 1) {
631 domain->inet_family_hint = 2;
633 domain->inet_family_hint = 3;
635 mono_domain_unlock (domain);
637 switch (domain->inet_family_hint) {
638 case 1: return PF_UNSPEC;
639 case 2: return PF_INET;
640 case 3: return PF_INET6;
647 ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObject *this_obj, gint32 family, gint32 type, gint32 proto, gint32 *werror)
656 sock_family = convert_family ((MonoAddressFamily)family);
657 if (sock_family == -1) {
658 *werror = WSAEAFNOSUPPORT;
662 sock_proto = convert_proto ((MonoProtocolType)proto);
663 if (sock_proto == -1) {
664 *werror = WSAEPROTONOSUPPORT;
668 sock_type = convert_type ((MonoSocketType)type);
669 if (sock_type == -1) {
670 *werror = WSAESOCKTNOSUPPORT;
674 sock = _wapi_socket (sock_family, sock_type, sock_proto,
675 NULL, 0, WSA_FLAG_OVERLAPPED);
677 if (sock == INVALID_SOCKET) {
678 *werror = WSAGetLastError ();
682 return GUINT_TO_POINTER (sock);
685 /* FIXME: the SOCKET parameter (here and in other functions in this
686 * file) is really an IntPtr which needs to be converted to a guint32.
689 ves_icall_System_Net_Sockets_Socket_Close_internal (SOCKET sock, gint32 *werror)
691 LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
695 /* Clear any pending work item from this socket if the underlying
696 * polling system does not notify when the socket is closed */
697 mono_threadpool_ms_io_remove_socket (GPOINTER_TO_INT (sock));
705 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal (void)
707 LOGDEBUG (g_message("%s: returning %d", __func__, WSAGetLastError ()));
709 return WSAGetLastError ();
713 ves_icall_System_Net_Sockets_Socket_Available_internal (SOCKET sock, gint32 *werror)
720 /* FIXME: this might require amount to be unsigned long. */
721 ret = ioctlsocket (sock, FIONREAD, &amount);
722 if (ret == SOCKET_ERROR) {
723 *werror = WSAGetLastError ();
731 ves_icall_System_Net_Sockets_Socket_Blocking_internal (SOCKET sock, gboolean block, gint32 *werror)
738 * block == TRUE/FALSE means we will block/not block.
739 * But the ioctlsocket call takes TRUE/FALSE for non-block/block
743 ret = ioctlsocket (sock, FIONBIO, (gulong *)&block);
744 if (ret == SOCKET_ERROR)
745 *werror = WSAGetLastError ();
749 ves_icall_System_Net_Sockets_Socket_Accept_internal (SOCKET sock, gint32 *werror, gboolean blocking)
751 gboolean interrupted;
756 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
766 MonoInternalThread *curthread = mono_thread_internal_current ();
767 curthread->interrupt_on_stop = (gpointer)TRUE;
768 newsock = _wapi_accept (sock, NULL, 0);
769 curthread->interrupt_on_stop = (gpointer)FALSE;
772 newsock = _wapi_accept (sock, NULL, 0);
777 mono_thread_info_uninstall_interrupt (&interrupted);
783 if (newsock == INVALID_SOCKET) {
784 *werror = WSAGetLastError ();
788 return GUINT_TO_POINTER (newsock);
792 ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock, guint32 backlog, gint32 *werror)
800 ret = _wapi_listen (sock, backlog);
804 if (ret == SOCKET_ERROR)
805 *werror = WSAGetLastError ();
808 // Check whether it's ::ffff::0:0.
810 is_ipv4_mapped_any (const struct in6_addr *addr)
814 for (i = 0; i < 10; i++) {
815 if (addr->s6_addr [i])
818 if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
820 for (i = 12; i < 16; i++) {
821 if (addr->s6_addr [i])
828 create_object_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error)
830 MonoDomain *domain = mono_domain_get ();
831 MonoObject *sockaddr_obj;
833 MonoAddressFamily family;
835 mono_error_init (error);
837 /* Build a System.Net.SocketAddress object instance */
838 if (!domain->sockaddr_class)
839 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
840 sockaddr_obj = mono_object_new_checked (domain, domain->sockaddr_class, error);
841 return_val_if_nok (error, NULL);
843 /* Locate the SocketAddress data buffer in the object */
844 if (!domain->sockaddr_data_field) {
845 domain->sockaddr_data_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Buffer");
846 g_assert (domain->sockaddr_data_field);
849 /* Locate the SocketAddress data buffer length in the object */
850 if (!domain->sockaddr_data_length_field) {
851 domain->sockaddr_data_length_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Size");
852 g_assert (domain->sockaddr_data_length_field);
855 /* May be the +2 here is too conservative, as sa_len returns
856 * the length of the entire sockaddr_in/in6, including
857 * sizeof (unsigned short) of the family */
858 /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
859 data = mono_array_new_cached (domain, mono_get_byte_class (), sa_size + 2, error);
860 return_val_if_nok (error, NULL);
862 /* The data buffer is laid out as follows:
863 * bytes 0 and 1 are the address family
864 * bytes 2 and 3 are the port info
865 * the rest is the address info
868 family = convert_to_mono_family (saddr->sa_family);
869 if (family == AddressFamily_Unknown) {
870 *werror = WSAEAFNOSUPPORT;
874 mono_array_set (data, guint8, 0, family & 0x0FF);
875 mono_array_set (data, guint8, 1, (family >> 8) & 0x0FF);
877 if (saddr->sa_family == AF_INET) {
878 struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr;
879 guint16 port = ntohs (sa_in->sin_port);
880 guint32 address = ntohl (sa_in->sin_addr.s_addr);
883 if (sa_size < buffer_size) {
884 mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
888 mono_array_set (data, guint8, 2, (port>>8) & 0xff);
889 mono_array_set (data, guint8, 3, (port) & 0xff);
890 mono_array_set (data, guint8, 4, (address>>24) & 0xff);
891 mono_array_set (data, guint8, 5, (address>>16) & 0xff);
892 mono_array_set (data, guint8, 6, (address>>8) & 0xff);
893 mono_array_set (data, guint8, 7, (address) & 0xff);
895 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
896 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_length_field, &buffer_size);
899 } else if (saddr->sa_family == AF_INET6) {
900 struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)saddr;
902 int buffer_size = 28;
904 guint16 port = ntohs (sa_in->sin6_port);
906 if (sa_size < buffer_size) {
907 mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
911 mono_array_set (data, guint8, 2, (port>>8) & 0xff);
912 mono_array_set (data, guint8, 3, (port) & 0xff);
914 if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
915 // Map ::ffff:0:0 to :: (bug #5502)
916 for (i = 0; i < 16; i++)
917 mono_array_set (data, guint8, 8 + i, 0);
919 for (i = 0; i < 16; i++) {
920 mono_array_set (data, guint8, 8 + i,
921 sa_in->sin6_addr.s6_addr [i]);
925 mono_array_set (data, guint8, 24, sa_in->sin6_scope_id & 0xff);
926 mono_array_set (data, guint8, 25,
927 (sa_in->sin6_scope_id >> 8) & 0xff);
928 mono_array_set (data, guint8, 26,
929 (sa_in->sin6_scope_id >> 16) & 0xff);
930 mono_array_set (data, guint8, 27,
931 (sa_in->sin6_scope_id >> 24) & 0xff);
933 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
934 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_length_field, &buffer_size);
939 else if (saddr->sa_family == AF_UNIX) {
941 int buffer_size = sa_size + 2;
943 for (i = 0; i < sa_size; i++)
944 mono_array_set (data, guint8, i + 2, saddr->sa_data [i]);
946 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_field, data);
947 mono_field_set_value (sockaddr_obj, domain->sockaddr_data_length_field, &buffer_size);
953 *werror = WSAEAFNOSUPPORT;
959 get_sockaddr_size (int family)
964 if (family == AF_INET) {
965 size = sizeof (struct sockaddr_in);
966 } else if (family == AF_INET6) {
967 size = sizeof (struct sockaddr_in6);
970 else if (family == AF_UNIX) {
971 size = sizeof (struct sockaddr_un);
978 ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal (SOCKET sock, gint32 af, gint32 *werror)
988 salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
990 *werror = WSAEAFNOSUPPORT;
993 sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
997 ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
1001 if (ret == SOCKET_ERROR) {
1002 *werror = WSAGetLastError ();
1008 LOGDEBUG (g_message("%s: bound to %s port %d", __func__, inet_ntoa (((struct sockaddr_in *)&sa)->sin_addr), ntohs (((struct sockaddr_in *)&sa)->sin_port)));
1010 result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
1013 if (!mono_error_ok (&error))
1014 mono_error_set_pending_exception (&error);
1019 ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (SOCKET sock, gint32 af, gint32 *werror)
1029 salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
1031 *werror = WSAEAFNOSUPPORT;
1034 sa = (salen <= 128) ? (gchar *)alloca (salen) : (gchar *)g_malloc0 (salen);
1035 /* Note: linux returns just 2 for AF_UNIX. Always. */
1039 ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
1043 if (ret == SOCKET_ERROR) {
1044 *werror = WSAGetLastError ();
1050 LOGDEBUG (g_message("%s: connected to %s port %d", __func__, inet_ntoa (((struct sockaddr_in *)&sa)->sin_addr), ntohs (((struct sockaddr_in *)&sa)->sin_port)));
1052 result = create_object_from_sockaddr ((struct sockaddr *)sa, salen, werror, &error);
1055 if (!mono_error_ok (&error))
1056 mono_error_set_pending_exception (&error);
1060 static struct sockaddr*
1061 create_sockaddr_from_object (MonoObject *saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
1063 MonoDomain *domain = mono_domain_get ();
1068 mono_error_init (error);
1070 if (!domain->sockaddr_class)
1071 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
1073 /* Locate the SocketAddress data buffer in the object */
1074 if (!domain->sockaddr_data_field) {
1075 domain->sockaddr_data_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Buffer");
1076 g_assert (domain->sockaddr_data_field);
1079 /* Locate the SocketAddress data buffer length in the object */
1080 if (!domain->sockaddr_data_length_field) {
1081 domain->sockaddr_data_length_field = mono_class_get_field_from_name (domain->sockaddr_class, "m_Size");
1082 g_assert (domain->sockaddr_data_length_field);
1085 data = *(MonoArray **)(((char *)saddr_obj) + domain->sockaddr_data_field->offset);
1087 /* The data buffer is laid out as follows:
1088 * byte 0 is the address family low byte
1089 * byte 1 is the address family high byte
1091 * bytes 2 and 3 are the port info
1092 * the rest is the address info
1094 * the rest is the file name
1096 len = *(int *)(((char *)saddr_obj) + domain->sockaddr_data_length_field->offset);
1097 g_assert (len >= 2);
1099 family = convert_family ((MonoAddressFamily)(mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8)));
1100 if (family == AF_INET) {
1101 struct sockaddr_in *sa;
1106 mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1110 sa = g_new0 (struct sockaddr_in, 1);
1111 port = (mono_array_get (data, guint8, 2) << 8) +
1112 mono_array_get (data, guint8, 3);
1113 address = (mono_array_get (data, guint8, 4) << 24) +
1114 (mono_array_get (data, guint8, 5) << 16 ) +
1115 (mono_array_get (data, guint8, 6) << 8) +
1116 mono_array_get (data, guint8, 7);
1118 sa->sin_family = family;
1119 sa->sin_addr.s_addr = htonl (address);
1120 sa->sin_port = htons (port);
1122 *sa_size = sizeof (struct sockaddr_in);
1123 return (struct sockaddr *)sa;
1124 } else if (family == AF_INET6) {
1125 struct sockaddr_in6 *sa;
1131 mono_error_set_exception_instance (error, mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1135 sa = g_new0 (struct sockaddr_in6, 1);
1136 port = mono_array_get (data, guint8, 3) +
1137 (mono_array_get (data, guint8, 2) << 8);
1138 scopeid = mono_array_get (data, guint8, 24) +
1139 (mono_array_get (data, guint8, 25) << 8) +
1140 (mono_array_get (data, guint8, 26) << 16) +
1141 (mono_array_get (data, guint8, 27) << 24);
1143 sa->sin6_family = family;
1144 sa->sin6_port = htons (port);
1145 sa->sin6_scope_id = scopeid;
1147 for (i = 0; i < 16; i++)
1148 sa->sin6_addr.s6_addr [i] = mono_array_get (data, guint8, 8 + i);
1150 *sa_size = sizeof (struct sockaddr_in6);
1151 return (struct sockaddr *)sa;
1153 #ifdef HAVE_SYS_UN_H
1154 else if (family == AF_UNIX) {
1155 struct sockaddr_un *sock_un;
1158 /* Need a byte for the '\0' terminator/prefix, and the first
1159 * two bytes hold the SocketAddress family
1161 if (len - 2 >= sizeof (sock_un->sun_path)) {
1162 mono_error_set_exception_instance (error, mono_get_exception_index_out_of_range ());
1166 sock_un = g_new0 (struct sockaddr_un, 1);
1168 sock_un->sun_family = family;
1169 for (i = 0; i < len - 2; i++)
1170 sock_un->sun_path [i] = mono_array_get (data, guint8, i + 2);
1173 return (struct sockaddr *)sock_un;
1177 *werror = WSAEAFNOSUPPORT;
1183 ves_icall_System_Net_Sockets_Socket_Bind_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror)
1186 struct sockaddr *sa;
1192 sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
1195 if (!mono_error_ok (&error)) {
1196 mono_error_set_pending_exception (&error);
1200 LOGDEBUG (g_message("%s: binding to %s port %d", __func__, inet_ntoa (((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)));
1202 ret = _wapi_bind (sock, sa, sa_size);
1204 if (ret == SOCKET_ERROR)
1205 *werror = WSAGetLastError ();
1217 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1218 gint timeout, gint32 *werror)
1220 MonoInternalThread *thread = mono_thread_internal_current ();
1223 gboolean interrupted;
1228 pfds = g_new0 (mono_pollfd, 1);
1229 pfds->fd = GPOINTER_TO_INT (sock);
1232 case SelectModeRead:
1233 pfds->events = MONO_POLLIN;
1235 case SelectModeWrite:
1236 pfds->events = MONO_POLLOUT;
1239 pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL;
1243 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1244 start = time (NULL);
1247 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1256 ret = mono_poll (pfds, 1, timeout);
1260 mono_thread_info_uninstall_interrupt (&interrupted);
1267 if (timeout > 0 && ret < 0) {
1269 int sec = time (NULL) - start;
1271 timeout -= sec * 1000;
1279 if (ret == -1 && errno == EINTR) {
1280 if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
1285 /* Suspend requested? */
1286 mono_thread_interruption_checkpoint ();
1290 } while (ret == -1 && errno == EINTR);
1294 *werror = WSAGetLastError ();
1296 *werror = errno_to_WSA (errno, __func__);
1307 ves_icall_System_Net_Sockets_Socket_Connect_internal (SOCKET sock, MonoObject *sockaddr, gint32 *werror)
1310 struct sockaddr *sa;
1313 gboolean interrupted;
1317 sa = create_sockaddr_from_object (sockaddr, &sa_size, werror, &error);
1320 if (!mono_error_ok (&error)) {
1321 mono_error_set_pending_exception (&error);
1325 LOGDEBUG (g_message("%s: connecting to %s port %d", __func__, inet_ntoa (((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port)));
1327 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1335 ret = _wapi_connect (sock, sa, sa_size);
1339 mono_thread_info_uninstall_interrupt (&interrupted);
1345 if (ret == SOCKET_ERROR)
1346 *werror = WSAGetLastError ();
1351 /* These #defines from mswsock.h from wine. Defining them here allows
1352 * us to build this file on a mingw box that doesn't know the magic
1353 * numbers, but still run on a newer windows box that does.
1355 #ifndef WSAID_DISCONNECTEX
1356 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1357 typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
1360 #ifndef WSAID_TRANSMITFILE
1361 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1362 typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
1366 ves_icall_System_Net_Sockets_Socket_Disconnect_internal (SOCKET sock, MonoBoolean reuse, gint32 *werror)
1369 glong output_bytes = 0;
1370 GUID disco_guid = WSAID_DISCONNECTEX;
1371 GUID trans_guid = WSAID_TRANSMITFILE;
1372 LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
1373 LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
1374 gboolean interrupted;
1378 LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
1382 /* I _think_ the extension function pointers need to be looked
1383 * up for each socket. FIXME: check the best way to store
1384 * pointers to functions in managed objects that still works
1385 * on 64bit platforms.
1387 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&disco_guid, sizeof (GUID),
1388 (gchar *)&_wapi_disconnectex, sizeof (void *), &output_bytes, NULL, NULL);
1393 /* make sure that WSAIoctl didn't put crap in the
1396 _wapi_disconnectex = NULL;
1401 * Use the SIO_GET_EXTENSION_FUNCTION_POINTER to
1402 * determine the address of the disconnect method without
1403 * taking a hard dependency on a single provider
1405 * For an explanation of why this is done, you can read
1406 * the article at http://www.codeproject.com/internet/jbsocketserver3.asp
1408 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER, (gchar *)&trans_guid, sizeof(GUID),
1409 (gchar *)&_wapi_transmitfile, sizeof(void *), &output_bytes, NULL, NULL);
1414 _wapi_transmitfile = NULL;
1417 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1425 if (_wapi_disconnectex != NULL) {
1426 if (!_wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0))
1427 *werror = WSAGetLastError ();
1428 } else if (_wapi_transmitfile != NULL) {
1429 if (!_wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL, TF_DISCONNECT | TF_REUSE_SOCKET))
1430 *werror = WSAGetLastError ();
1432 *werror = ERROR_NOT_SUPPORTED;
1437 mono_thread_info_uninstall_interrupt (&interrupted);
1443 ves_icall_System_Net_Sockets_Socket_Receive_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror)
1449 gboolean interrupted;
1450 MonoInternalThread* curthread G_GNUC_UNUSED = mono_thread_internal_current ();
1454 alen = mono_array_length (buffer);
1455 if (offset > alen - count)
1458 buf = mono_array_addr (buffer, guchar, offset);
1460 recvflags = convert_socketflags (flags);
1461 if (recvflags == -1) {
1462 *werror = WSAEOPNOTSUPP;
1466 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1474 curthread->interrupt_on_stop = (gpointer)TRUE;
1475 ret = _wapi_recv (sock, buf, count, recvflags);
1476 curthread->interrupt_on_stop = (gpointer)FALSE;
1479 ret = _wapi_recv (sock, buf, count, recvflags);
1484 mono_thread_info_uninstall_interrupt (&interrupted);
1490 if (ret == SOCKET_ERROR) {
1491 *werror = WSAGetLastError ();
1499 ves_icall_System_Net_Sockets_Socket_Receive_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror)
1502 gboolean interrupted;
1505 DWORD recvflags = 0;
1509 wsabufs = mono_array_addr (buffers, WSABUF, 0);
1510 count = mono_array_length (buffers);
1512 recvflags = convert_socketflags (flags);
1513 if (recvflags == -1) {
1514 *werror = WSAEOPNOTSUPP;
1518 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1526 ret = WSARecv (sock, wsabufs, count, &recv, &recvflags, NULL, NULL);
1530 mono_thread_info_uninstall_interrupt (&interrupted);
1536 if (ret == SOCKET_ERROR) {
1537 *werror = WSAGetLastError ();
1545 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *werror)
1552 struct sockaddr *sa;
1554 gboolean interrupted;
1558 alen = mono_array_length (buffer);
1559 if (offset > alen - count)
1562 sa = create_sockaddr_from_object (*sockaddr, &sa_size, werror, &error);
1565 if (!mono_error_ok (&error)) {
1566 mono_error_set_pending_exception (&error);
1570 buf = mono_array_addr (buffer, guchar, offset);
1572 recvflags = convert_socketflags (flags);
1573 if (recvflags == -1) {
1574 *werror = WSAEOPNOTSUPP;
1578 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1587 ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1591 mono_thread_info_uninstall_interrupt (&interrupted);
1598 if (ret==SOCKET_ERROR) {
1600 *werror = WSAGetLastError ();
1604 /* If we didn't get a socket size, then we're probably a
1605 * connected connection-oriented socket and the stack hasn't
1606 * returned the remote address. All we can do is return null.
1609 *sockaddr = create_object_from_sockaddr (sa, sa_size, werror, &error);
1610 if (!mono_error_ok (&error)) {
1611 mono_error_set_pending_exception (&error);
1625 ves_icall_System_Net_Sockets_Socket_Send_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *werror)
1631 gboolean interrupted;
1635 alen = mono_array_length (buffer);
1636 if (offset > alen - count)
1639 LOGDEBUG (g_message("%s: alen: %d", __func__, alen));
1641 buf = mono_array_addr (buffer, guchar, offset);
1643 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1645 sendflags = convert_socketflags (flags);
1646 if (sendflags == -1) {
1647 *werror = WSAEOPNOTSUPP;
1651 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1659 ret = _wapi_send (sock, buf, count, sendflags);
1663 mono_thread_info_uninstall_interrupt (&interrupted);
1669 if (ret == SOCKET_ERROR) {
1670 *werror = WSAGetLastError ();
1678 ves_icall_System_Net_Sockets_Socket_Send_array_internal (SOCKET sock, MonoArray *buffers, gint32 flags, gint32 *werror)
1683 DWORD sendflags = 0;
1684 gboolean interrupted;
1688 wsabufs = mono_array_addr (buffers, WSABUF, 0);
1689 count = mono_array_length (buffers);
1691 sendflags = convert_socketflags (flags);
1692 if (sendflags == -1) {
1693 *werror = WSAEOPNOTSUPP;
1697 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1705 ret = WSASend (sock, wsabufs, count, &sent, sendflags, NULL, NULL);
1709 mono_thread_info_uninstall_interrupt (&interrupted);
1715 if (ret == SOCKET_ERROR) {
1716 *werror = WSAGetLastError ();
1724 ves_icall_System_Net_Sockets_Socket_SendTo_internal (SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *werror)
1731 struct sockaddr *sa;
1733 gboolean interrupted;
1737 alen = mono_array_length (buffer);
1738 if (offset > alen - count) {
1742 sa = create_sockaddr_from_object(sockaddr, &sa_size, werror, &error);
1745 if (!mono_error_ok (&error)) {
1746 mono_error_set_pending_exception (&error);
1750 LOGDEBUG (g_message ("%s: alen: %d", __func__, alen));
1752 buf = mono_array_addr (buffer, guchar, offset);
1754 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1756 sendflags = convert_socketflags (flags);
1757 if (sendflags == -1) {
1759 *werror = WSAEOPNOTSUPP;
1763 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1772 ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1776 mono_thread_info_uninstall_interrupt (&interrupted);
1783 if (ret == SOCKET_ERROR)
1784 *werror = WSAGetLastError ();
1792 Socket_to_SOCKET (MonoObject *sockobj)
1794 MonoSafeHandle *safe_handle;
1795 MonoClassField *field;
1797 field = mono_class_get_field_from_name (sockobj->vtable->klass, "safe_handle");
1798 safe_handle = ((MonoSafeHandle *)(*(gpointer *)(((char *)sockobj) + field->offset)));
1800 if (safe_handle == NULL)
1803 return (SOCKET)safe_handle->handle;
1806 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1809 ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArray **sockets, gint32 timeout, gint32 *werror)
1812 MonoInternalThread *thread = mono_thread_internal_current ();
1819 MonoClass *sock_arr_class;
1822 uintptr_t socks_size;
1823 gboolean interrupted;
1827 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1828 count = mono_array_length (*sockets);
1829 nfds = count - 3; /* NULL separators */
1830 pfds = g_new0 (mono_pollfd, nfds);
1832 for (i = 0; i < count; i++) {
1833 obj = mono_array_get (*sockets, MonoObject *, i);
1840 /* The socket array was bogus */
1842 *werror = WSAEFAULT;
1846 pfds [idx].fd = Socket_to_SOCKET (obj);
1847 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1851 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1852 start = time (NULL);
1854 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
1863 ret = mono_poll (pfds, nfds, timeout);
1867 mono_thread_info_uninstall_interrupt (&interrupted);
1874 if (timeout > 0 && ret < 0) {
1876 int sec = time (NULL) - start;
1878 timeout -= sec * 1000;
1884 if (ret == -1 && errno == EINTR) {
1885 if (mono_thread_test_state (thread, (MonoThreadState)(ThreadState_AbortRequested | ThreadState_StopRequested))) {
1891 /* Suspend requested? */
1892 mono_thread_interruption_checkpoint ();
1896 } while (ret == -1 && errno == EINTR);
1900 *werror = WSAGetLastError ();
1902 *werror = errno_to_WSA (errno, __func__);
1914 sock_arr_class = ((MonoObject *)*sockets)->vtable->klass;
1915 socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1916 socks = mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, &error);
1917 if (!mono_error_ok (&error)) {
1918 mono_error_set_pending_exception (&error);
1924 for (i = 0; i < count && ret > 0; i++) {
1927 obj = mono_array_get (*sockets, MonoObject *, i);
1934 pfd = &pfds [i - mode];
1935 if (pfd->revents == 0)
1939 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1940 mono_array_setref (socks, idx++, obj);
1941 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1942 mono_array_setref (socks, idx++, obj);
1943 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1944 mono_array_setref (socks, idx++, obj);
1953 int_to_object (MonoDomain *domain, int val, MonoError *error)
1955 return mono_value_box_checked (domain, mono_get_int32_class (), &val, error);
1959 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *werror)
1961 int system_level = 0;
1962 int system_name = 0;
1965 socklen_t valsize = sizeof (val);
1966 struct linger linger;
1967 socklen_t lingersize = sizeof (linger);
1969 socklen_t time_ms_size = sizeof (time_ms);
1971 # if defined(__OpenBSD__)
1972 struct sockpeercred cred;
1976 socklen_t credsize = sizeof (cred);
1979 MonoDomain *domain = mono_domain_get ();
1981 MonoClass *obj_class;
1982 MonoClassField *field;
1986 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1987 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1988 system_level = SOL_SOCKET;
1989 system_name = SO_REUSEADDR;
1994 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1998 *werror = WSAENOPROTOOPT;
2002 *obj_val = int_to_object (domain, 0, &error);
2003 mono_error_set_pending_exception (&error);
2009 /* No need to deal with MulticastOption names here, because
2010 * you cant getsockopt AddMembership or DropMembership (the
2011 * int getsockopt will error, causing an exception)
2014 case SocketOptionName_Linger:
2015 case SocketOptionName_DontLinger:
2016 ret = _wapi_getsockopt (sock, system_level, system_name, &linger, &lingersize);
2019 case SocketOptionName_SendTimeout:
2020 case SocketOptionName_ReceiveTimeout:
2021 ret = _wapi_getsockopt (sock, system_level, system_name, (char *)&time_ms, &time_ms_size);
2025 case SocketOptionName_PeerCred:
2026 ret = _wapi_getsockopt (sock, system_level, system_name, &cred, &credsize);
2031 ret = _wapi_getsockopt (sock, system_level, system_name, &val, &valsize);
2036 if (ret == SOCKET_ERROR) {
2037 *werror = WSAGetLastError ();
2042 case SocketOptionName_Linger:
2043 /* build a System.Net.Sockets.LingerOption */
2044 obj_class = mono_class_load_from_name (get_socket_assembly (),
2045 "System.Net.Sockets",
2047 obj = mono_object_new_checked (domain, obj_class, &error);
2048 if (!mono_error_ok (&error)) {
2049 mono_error_set_pending_exception (&error);
2053 /* Locate and set the fields "bool enabled" and "int
2056 field = mono_class_get_field_from_name(obj_class, "enabled");
2057 *(guint8 *)(((char *)obj)+field->offset) = linger.l_onoff;
2059 field = mono_class_get_field_from_name(obj_class, "lingerTime");
2060 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
2062 case SocketOptionName_DontLinger:
2063 /* construct a bool int in val - true if linger is off */
2064 obj = int_to_object (domain, !linger.l_onoff, &error);
2065 mono_error_set_pending_exception (&error);
2067 case SocketOptionName_SendTimeout:
2068 case SocketOptionName_ReceiveTimeout:
2069 obj = int_to_object (domain, time_ms, &error);
2070 mono_error_set_pending_exception (&error);
2074 case SocketOptionName_PeerCred: {
2076 * build a Mono.Posix.PeerCred+PeerCredData if
2079 static MonoImage *mono_posix_image = NULL;
2080 MonoPeerCredData *cred_data;
2082 if (mono_posix_image == NULL) {
2083 mono_posix_image = mono_image_loaded ("Mono.Posix");
2084 if (!mono_posix_image) {
2085 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
2087 *werror = WSAENOPROTOOPT;
2090 mono_posix_image = mono_assembly_get_image (sa);
2095 obj_class = mono_class_load_from_name (mono_posix_image,
2098 obj = mono_object_new_checked (domain, obj_class, &error);
2099 if (!mono_error_ok (&error)) {
2100 mono_error_set_pending_exception (&error);
2103 cred_data = (MonoPeerCredData *)obj;
2104 cred_data->pid = cred.pid;
2105 cred_data->uid = cred.uid;
2106 cred_data->gid = cred.gid;
2112 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2113 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
2116 obj = int_to_object (domain, val, &error);
2117 mono_error_set_pending_exception (&error);
2124 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *werror)
2126 int system_level = 0;
2127 int system_name = 0;
2134 ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2137 *werror = WSAENOPROTOOPT;
2143 valsize = mono_array_length (*byte_val);
2144 buf = mono_array_addr (*byte_val, guchar, 0);
2148 ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
2152 if (ret == SOCKET_ERROR)
2153 *werror = WSAGetLastError ();
2156 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2157 static struct in_addr
2158 ipaddress_to_struct_in_addr (MonoObject *ipaddr)
2160 struct in_addr inaddr;
2161 MonoClassField *field;
2163 field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Address");
2165 /* No idea why .net uses a 64bit type to hold a 32bit value...
2167 * Internal value of IPAddess is in little-endian order
2169 inaddr.s_addr = GUINT_FROM_LE ((guint32)*(guint64 *)(((char *)ipaddr) + field->offset));
2174 static struct in6_addr
2175 ipaddress_to_struct_in6_addr (MonoObject *ipaddr)
2177 struct in6_addr in6addr;
2178 MonoClassField *field;
2182 field = mono_class_get_field_from_name (ipaddr->vtable->klass, "m_Numbers");
2184 data = *(MonoArray **)(((char *)ipaddr) + field->offset);
2186 for (i = 0; i < 8; i++) {
2187 const guint16 s = GUINT16_TO_BE (mono_array_get (data, guint16, i));
2189 /* Solaris/MacOS have only the 8 bit version. */
2191 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
2192 in6addr.s6_addr[2 * i] = s & 0xff;
2194 in6addr.s6_addr16[i] = s;
2201 #if defined(__APPLE__) || defined(__FreeBSD__)
2204 get_local_interface_id (int family)
2206 #if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
2209 struct ifaddrs *ifap = NULL, *ptr;
2212 if (getifaddrs (&ifap))
2215 for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
2216 if (!ptr->ifa_addr || !ptr->ifa_name)
2218 if (ptr->ifa_addr->sa_family != family)
2220 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
2222 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
2225 idx = if_nametoindex (ptr->ifa_name);
2234 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
2237 ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal (SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val, gint32 *werror)
2239 struct linger linger;
2240 int system_level = 0;
2241 int system_name = 0;
2248 sol_ipv6 = mono_networking_get_ipv6_protocol ();
2249 sol_ip = mono_networking_get_ip_protocol ();
2251 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2254 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2255 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2256 system_name = SO_REUSEADDR;
2257 int_val = int_val ? 0 : 1;
2263 *werror = WSAENOPROTOOPT;
2269 /* Only one of obj_val, byte_val or int_val has data */
2271 MonoClassField *field;
2275 case SocketOptionName_Linger:
2276 /* Dig out "bool enabled" and "int lingerTime"
2279 field = mono_class_get_field_from_name (obj_val->vtable->klass, "enabled");
2280 linger.l_onoff = *(guint8 *)(((char *)obj_val) + field->offset);
2281 field = mono_class_get_field_from_name (obj_val->vtable->klass, "lingerTime");
2282 linger.l_linger = *(guint32 *)(((char *)obj_val) + field->offset);
2284 valsize = sizeof (linger);
2285 ret = _wapi_setsockopt (sock, system_level,
2286 system_name, &linger, valsize);
2288 case SocketOptionName_AddMembership:
2289 case SocketOptionName_DropMembership:
2290 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2292 MonoObject *address = NULL;
2294 if (system_level == sol_ipv6) {
2295 struct ipv6_mreq mreq6;
2300 field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Group");
2302 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2305 mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
2307 field = mono_class_get_field_from_name (obj_val->vtable->klass, "m_Interface");
2308 mreq6.ipv6mr_interface = *(guint64 *)(((char *)obj_val) + field->offset);
2310 #if defined(__APPLE__) || defined(__FreeBSD__)
2314 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2316 * Tests on Windows and Linux show that the multicast group is only
2317 * joined on one NIC when interface = 0, so we simply use the interface
2318 * id from the first non-loopback interface (this is also what
2319 * Dns.GetHostName (string.Empty) would return).
2321 if (!mreq6.ipv6mr_interface)
2322 mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2325 ret = _wapi_setsockopt (sock, system_level,
2326 system_name, &mreq6,
2328 } else if (system_level == sol_ip) {
2329 #ifdef HAVE_STRUCT_IP_MREQN
2330 struct ip_mreqn mreq = {{0}};
2332 struct ip_mreq mreq = {{0}};
2333 #endif /* HAVE_STRUCT_IP_MREQN */
2336 * pain! MulticastOption holds two IPAddress
2337 * members, so I have to dig the value out of
2340 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
2341 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2343 /* address might not be defined and if so, set the address to ADDR_ANY.
2346 mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
2348 field = mono_class_get_field_from_name (obj_val->vtable->klass, "localAddress");
2349 address = *(MonoObject **)(((char *)obj_val) + field->offset);
2351 #ifdef HAVE_STRUCT_IP_MREQN
2353 mreq.imr_address = ipaddress_to_struct_in_addr (address);
2355 field = mono_class_get_field_from_name (obj_val->vtable->klass, "ifIndex");
2356 mreq.imr_ifindex = *(gint32 *)(((char *)obj_val) + field->offset);
2359 mreq.imr_interface = ipaddress_to_struct_in_addr (address);
2360 #endif /* HAVE_STRUCT_IP_MREQN */
2362 ret = _wapi_setsockopt (sock, system_level,
2368 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2370 /* Cause an exception to be thrown */
2371 *werror = WSAEINVAL;
2374 } else if (byte_val!=NULL) {
2375 int valsize = mono_array_length (byte_val);
2376 guchar *buf = mono_array_addr (byte_val, guchar, 0);
2379 case SocketOptionName_DontLinger:
2381 linger.l_onoff = (*buf) ? 0 : 1;
2382 linger.l_linger = 0;
2383 ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2385 *werror = WSAEINVAL;
2389 ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
2393 /* ReceiveTimeout/SendTimeout get here */
2395 case SocketOptionName_DontLinger:
2396 linger.l_onoff = !int_val;
2397 linger.l_linger = 0;
2398 ret = _wapi_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2400 case SocketOptionName_MulticastInterface:
2402 #ifdef HAVE_STRUCT_IP_MREQN
2403 int_val = GUINT32_FROM_BE (int_val);
2404 if ((int_val & 0xff000000) == 0) {
2405 /* int_val is interface index */
2406 struct ip_mreqn mreq = {{0}};
2407 mreq.imr_ifindex = int_val;
2408 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &mreq, sizeof (mreq));
2411 int_val = GUINT32_TO_BE (int_val);
2412 #endif /* HAVE_STRUCT_IP_MREQN */
2413 #endif /* HOST_WIN32 */
2414 /* int_val is in_addr */
2415 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2417 case SocketOptionName_DontFragment:
2418 #ifdef HAVE_IP_MTU_DISCOVER
2419 /* Fiddle with the value slightly if we're
2423 int_val = IP_PMTUDISC_DO;
2428 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2432 if (ret == SOCKET_ERROR)
2433 *werror = WSAGetLastError ();
2437 ves_icall_System_Net_Sockets_Socket_Shutdown_internal (SOCKET sock, gint32 how, gint32 *werror)
2440 gboolean interrupted;
2444 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2452 /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2453 ret = _wapi_shutdown (sock, how);
2457 mono_thread_info_uninstall_interrupt (&interrupted);
2463 if (ret == SOCKET_ERROR)
2464 *werror = WSAGetLastError ();
2468 ves_icall_System_Net_Sockets_Socket_IOControl_internal (SOCKET sock, gint32 code, MonoArray *input, MonoArray *output, gint32 *werror)
2470 glong output_bytes = 0;
2471 gchar *i_buffer, *o_buffer;
2477 if ((guint32)code == FIONBIO)
2478 /* Invalid command. Must use Socket.Blocking */
2481 if (input == NULL) {
2485 i_buffer = mono_array_addr (input, gchar, 0);
2486 i_len = mono_array_length (input);
2489 if (output == NULL) {
2493 o_buffer = mono_array_addr (output, gchar, 0);
2494 o_len = mono_array_length (output);
2499 ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2503 if (ret == SOCKET_ERROR) {
2504 *werror = WSAGetLastError ();
2508 return (gint)output_bytes;
2512 addrinfo_to_IPHostEntry (MonoAddressInfo *info, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips, MonoError *error)
2515 MonoAddressEntry *ai = NULL;
2516 struct in_addr *local_in = NULL;
2518 struct in6_addr *local_in6 = NULL;
2521 MonoDomain *domain = mono_domain_get ();
2523 mono_error_init (error);
2525 *h_aliases = mono_array_new_checked (domain, mono_get_string_class (), 0, error);
2526 return_val_if_nok (error, FALSE);
2527 if (add_local_ips) {
2528 local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2529 local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2530 if (nlocal_in || nlocal_in6) {
2531 char addr [INET6_ADDRSTRLEN];
2532 *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error);
2537 MonoString *addr_string;
2540 for (i = 0; i < nlocal_in; i++) {
2542 mono_address_init (&maddr, AF_INET, &local_in [i]);
2543 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2544 addr_string = mono_string_new (domain, addr);
2545 mono_array_setref (*h_addr_list, addr_index, addr_string);
2552 MonoString *addr_string;
2555 for (i = 0; i < nlocal_in6; i++) {
2557 mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2558 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2559 addr_string = mono_string_new (domain, addr);
2560 mono_array_setref (*h_addr_list, addr_index, addr_string);
2570 mono_free_address_info (info);
2571 return is_ok (error);;
2578 for (count = 0, ai = info->entries; ai != NULL; ai = ai->next) {
2579 if (ai->family != AF_INET && ai->family != AF_INET6)
2584 *h_addr_list = mono_array_new_checked (domain, mono_get_string_class (), count, error);
2588 for (ai = info->entries, i = 0; ai != NULL; ai = ai->next) {
2590 MonoString *addr_string;
2591 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2593 if ((ai->family != PF_INET) && (ai->family != PF_INET6))
2596 mono_address_init (&maddr, ai->family, &ai->address);
2597 if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
2598 addr_string = mono_string_new (domain, buffer);
2600 addr_string = mono_string_new (domain, "");
2602 mono_array_setref (*h_addr_list, addr_index, addr_string);
2606 if (ai->canonical_name != NULL) {
2607 *h_name = mono_string_new (domain, ai->canonical_name);
2609 *h_name = mono_string_new (domain, buffer);
2618 mono_free_address_info (info);
2620 return is_ok (error);
2624 get_addrinfo_family_hint (MonoError *error)
2628 mono_error_init (error);
2630 hint = get_family_hint (error);
2631 return_val_if_nok (error, 0);
2635 return MONO_HINT_UNSPECIFIED;
2637 return MONO_HINT_IPV4;
2640 return MONO_HINT_IPV6;
2643 g_error ("invalid hint");
2649 ves_icall_System_Net_Dns_GetHostByName_internal (MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2652 gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2653 gchar this_hostname [256];
2654 MonoAddressInfo *info = NULL;
2657 char *hostname = mono_string_to_utf8_checked (host, &error);
2658 if (mono_error_set_pending_exception (&error))
2661 hint = get_addrinfo_family_hint (&error);
2662 if (!mono_error_ok (&error)) {
2663 mono_error_set_pending_exception (&error);
2667 if (*hostname == '\0') {
2668 add_local_ips = TRUE;
2672 if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2673 if (!strcmp (hostname, this_hostname)) {
2674 add_local_ips = TRUE;
2679 if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2680 add_info_ok = FALSE;
2685 MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, add_local_ips, &error);
2686 mono_error_set_pending_exception (&error);
2693 ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2696 struct sockaddr_in saddr;
2697 struct sockaddr_in6 saddr6;
2698 MonoAddressInfo *info = NULL;
2700 gint32 family, hint;
2701 gchar hostname [NI_MAXHOST] = { 0 };
2704 address = mono_string_to_utf8_checked (addr, &error);
2705 if (mono_error_set_pending_exception (&error))
2708 if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2710 saddr.sin_family = AF_INET;
2711 } else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2713 saddr6.sin6_family = AF_INET6;
2725 #if HAVE_SOCKADDR_IN_SIN_LEN
2726 saddr.sin_len = sizeof (saddr);
2728 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2732 #if HAVE_SOCKADDR_IN6_SIN_LEN
2733 saddr6.sin6_len = sizeof (saddr6);
2735 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2739 g_assert_not_reached ();
2747 hint = get_addrinfo_family_hint (&error);
2748 if (!mono_error_ok (&error)) {
2749 mono_error_set_pending_exception (&error);
2752 if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2755 MonoBoolean result = addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE, &error);
2756 mono_error_set_pending_exception (&error);
2761 ves_icall_System_Net_Dns_GetHostName_internal (MonoString **h_name)
2763 gchar hostname [NI_MAXHOST] = { 0 };
2766 ret = gethostname (hostname, sizeof (hostname));
2770 *h_name = mono_string_new (mono_domain_get (), hostname);
2776 ves_icall_System_Net_Sockets_Socket_SendFile_internal (SOCKET sock, MonoString *filename, MonoArray *pre_buffer, MonoArray *post_buffer, gint flags)
2781 gboolean interrupted;
2782 TRANSMIT_FILE_BUFFERS buffers;
2784 if (filename == NULL)
2787 /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2789 file = ves_icall_System_IO_MonoIO_Open (filename, FileMode_Open, FileAccess_Read, FileShare_Read, 0, &werror);
2791 if (file == INVALID_HANDLE_VALUE) {
2792 SetLastError (werror);
2796 memset (&buffers, 0, sizeof (buffers));
2797 if (pre_buffer != NULL) {
2798 buffers.Head = mono_array_addr (pre_buffer, guchar, 0);
2799 buffers.HeadLength = mono_array_length (pre_buffer);
2801 if (post_buffer != NULL) {
2802 buffers.Tail = mono_array_addr (post_buffer, guchar, 0);
2803 buffers.TailLength = mono_array_length (post_buffer);
2806 mono_thread_info_install_interrupt (abort_syscall, (gpointer) (gsize) mono_native_thread_id_get (), &interrupted);
2809 SetLastError (WSAEINTR);
2815 ret = TransmitFile (sock, file, 0, 0, NULL, &buffers, flags);
2819 mono_thread_info_uninstall_interrupt (&interrupted);
2822 SetLastError (WSAEINTR);
2836 ves_icall_System_Net_Sockets_Socket_SupportPortReuse (MonoProtocolType proto)
2838 #if defined (SO_REUSEPORT) || defined (HOST_WIN32)
2842 /* Linux always supports double binding for UDP, even on older kernels. */
2843 if (proto == ProtocolType_Udp)
2851 mono_network_init (void)
2853 mono_networking_init ();
2857 mono_network_cleanup (void)
2859 _wapi_cleanup_networking ();
2860 mono_networking_shutdown ();
2864 icall_cancel_blocking_socket_operation (MonoThread *thread)
2866 MonoInternalThread *internal;
2868 internal = thread->internal_thread;
2869 g_assert (internal);
2871 mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
2874 #endif /* #ifndef DISABLE_SOCKETS */