[Mono.Runtime.Tests] Exclude simd tests
[mono-project.git] / mono / metadata / w32socket.c
bloba8a4f64c63236daabd42d94d8d6811a3c4997d47
1 /**
2 * \file
3 * Socket IO internal calls
5 * Authors:
6 * Dick Porter (dick@ximian.com)
7 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * This file has been re-licensed under the MIT License:
13 * http://opensource.org/licenses/MIT
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
17 #include <config.h>
19 #ifndef DISABLE_SOCKETS
21 #if defined(__APPLE__) || defined(__FreeBSD__)
22 #define __APPLE_USE_RFC_3542
23 #endif
25 #include <glib.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #ifdef HOST_WIN32
29 #include <ws2tcpip.h>
30 #else
31 #include <sys/socket.h>
32 #ifdef HAVE_SYS_IOCTL_H
33 #include <sys/ioctl.h>
34 #endif
35 #include <netinet/in.h>
36 #include <netinet/tcp.h>
37 #ifdef HAVE_NETDB_H
38 #include <netdb.h>
39 #endif
40 #ifdef HAVE_NETINET_TCP_H
41 #include <arpa/inet.h>
42 #endif
43 #endif
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #include <errno.h>
48 #include <mono/utils/mono-errno.h>
50 #include <sys/types.h>
52 #include <mono/metadata/object.h>
53 #include <mono/metadata/exception.h>
54 #include <mono/metadata/assembly-internals.h>
55 #include <mono/metadata/appdomain.h>
56 #include <mono/metadata/w32file.h>
57 #include <mono/metadata/threads.h>
58 #include <mono/metadata/threads-types.h>
59 #include <mono/metadata/threadpool-io.h>
60 #include <mono/utils/mono-poll.h>
61 /* FIXME change this code to not mess so much with the internals */
62 #include <mono/metadata/class-internals.h>
63 #include <mono/metadata/domain-internals.h>
64 #include <mono/metadata/image-internals.h>
65 #include <mono/utils/mono-threads.h>
66 #include <mono/utils/mono-memory-model.h>
67 #include <mono/utils/networking.h>
68 #include <mono/metadata/w32handle.h>
69 #include <mono/metadata/w32socket.h>
70 #include <mono/metadata/w32socket-internals.h>
71 #include <mono/metadata/w32error.h>
73 #include <time.h>
74 #ifdef HAVE_SYS_TIME_H
75 #include <sys/time.h>
76 #endif
77 #ifdef HAVE_SYS_IOCTL_H
78 #include <sys/ioctl.h>
79 #endif
80 #ifdef HAVE_NET_IF_H
81 #include <net/if.h>
82 #endif
84 #ifdef HAVE_NETDB_H
85 #include <netdb.h>
86 #endif
87 #ifdef HAVE_SYS_FILIO_H
88 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
89 #endif
90 #ifdef HAVE_SYS_SOCKIO_H
91 #include <sys/sockio.h> /* defines SIOCATMARK */
92 #endif
93 #ifdef HAVE_SYS_UN_H
94 #include <sys/un.h>
95 #endif
97 #ifdef HAVE_GETIFADDRS
98 // <net/if.h> must be included before <ifaddrs.h>
99 #include <ifaddrs.h>
100 #endif
102 #if defined(_MSC_VER) && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
103 #include <MSWSock.h>
104 #endif
105 #include "icall-decl.h"
107 #define LOGDEBUG(...)
108 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
110 static gboolean
111 addrinfo_to_IPHostEntry_handles (MonoAddressInfo *info, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gboolean add_local_ips, MonoError *error);
113 static MonoObjectHandle
114 create_object_handle_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error);
116 static struct sockaddr*
117 create_sockaddr_from_handle (MonoObjectHandle saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error);
119 #ifdef HOST_WIN32
121 static SOCKET
122 mono_w32socket_socket (int domain, int type, int protocol)
124 SOCKET ret;
125 MONO_ENTER_GC_SAFE;
126 ret = WSASocket (domain, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
127 MONO_EXIT_GC_SAFE;
128 return ret;
131 static gint
132 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
134 gint ret;
135 MONO_ENTER_GC_SAFE;
136 ret = bind (sock, addr, addrlen);
137 MONO_EXIT_GC_SAFE;
138 return ret;
141 static gint
142 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
144 gint ret;
145 MONO_ENTER_GC_SAFE;
146 ret = getpeername (sock, name, namelen);
147 MONO_EXIT_GC_SAFE;
148 return ret;
151 static gint
152 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
154 gint ret;
155 MONO_ENTER_GC_SAFE;
156 ret = getsockname (sock, name, namelen);
157 MONO_EXIT_GC_SAFE;
158 return ret;
161 static gint
162 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
164 gint ret;
165 MONO_ENTER_GC_SAFE;
166 ret = getsockopt (sock, level, optname, (char*)optval, optlen);
167 MONO_EXIT_GC_SAFE;
168 return ret;
171 static gint
172 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen)
174 gint ret;
175 MONO_ENTER_GC_SAFE;
176 ret = setsockopt (sock, level, optname, (const char*)optval, optlen);
177 MONO_EXIT_GC_SAFE;
178 return ret;
181 static gint
182 mono_w32socket_listen (SOCKET sock, gint backlog)
184 gint ret;
185 MONO_ENTER_GC_SAFE;
186 ret = listen (sock, backlog);
187 MONO_EXIT_GC_SAFE;
188 return ret;
191 static gint
192 mono_w32socket_shutdown (SOCKET sock, gint how)
194 gint ret;
195 MONO_ENTER_GC_SAFE;
196 ret = shutdown (sock, how);
197 MONO_EXIT_GC_SAFE;
198 return ret;
201 static gint
202 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, DWORD *written)
204 gint ret;
205 MONO_ENTER_GC_SAFE;
206 ret = WSAIoctl (sock, command, input, inputlen, output, outputlen, written, NULL, NULL);
207 MONO_EXIT_GC_SAFE;
208 return ret;
211 static gboolean
212 mono_w32socket_close (SOCKET sock)
214 gboolean ret;
215 MONO_ENTER_GC_SAFE;
216 ret = closesocket (sock);
217 MONO_EXIT_GC_SAFE;
218 return ret;
221 #endif /* HOST_WIN32 */
223 static gint32
224 convert_family (MonoAddressFamily mono_family)
226 switch (mono_family) {
227 case AddressFamily_Unknown:
228 case AddressFamily_ImpLink:
229 case AddressFamily_Pup:
230 case AddressFamily_Chaos:
231 case AddressFamily_Iso:
232 case AddressFamily_Ecma:
233 case AddressFamily_DataKit:
234 case AddressFamily_Ccitt:
235 case AddressFamily_DataLink:
236 case AddressFamily_Lat:
237 case AddressFamily_HyperChannel:
238 case AddressFamily_NetBios:
239 case AddressFamily_VoiceView:
240 case AddressFamily_FireFox:
241 case AddressFamily_Banyan:
242 case AddressFamily_Atm:
243 case AddressFamily_Cluster:
244 case AddressFamily_Ieee12844:
245 case AddressFamily_NetworkDesigners:
246 g_warning ("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
247 return -1;
248 case AddressFamily_Unspecified:
249 return AF_UNSPEC;
250 case AddressFamily_Unix:
251 return AF_UNIX;
252 case AddressFamily_InterNetwork:
253 return AF_INET;
254 case AddressFamily_AppleTalk:
255 #ifdef AF_APPLETALK
256 return AF_APPLETALK;
257 #else
258 return -1;
259 #endif
260 case AddressFamily_InterNetworkV6:
261 #ifdef HAVE_STRUCT_SOCKADDR_IN6
262 return AF_INET6;
263 #else
264 return -1;
265 #endif
266 case AddressFamily_DecNet:
267 #ifdef AF_DECnet
268 return AF_DECnet;
269 #else
270 return -1;
271 #endif
272 case AddressFamily_Ipx:
273 #ifdef AF_IPX
274 return AF_IPX;
275 #else
276 return -1;
277 #endif
278 case AddressFamily_Sna:
279 #ifdef AF_SNA
280 return AF_SNA;
281 #else
282 return -1;
283 #endif
284 case AddressFamily_Irda:
285 #ifdef AF_IRDA
286 return AF_IRDA;
287 #else
288 return -1;
289 #endif
290 default:
291 g_warning ("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
292 return -1;
296 static MonoAddressFamily
297 convert_to_mono_family (guint16 af_family)
299 switch (af_family) {
300 case AF_UNSPEC:
301 return AddressFamily_Unspecified;
302 case AF_UNIX:
303 return AddressFamily_Unix;
304 case AF_INET:
305 return AddressFamily_InterNetwork;
306 #ifdef AF_IPX
307 case AF_IPX:
308 return AddressFamily_Ipx;
309 #endif
310 #ifdef AF_SNA
311 case AF_SNA:
312 return AddressFamily_Sna;
313 #endif
314 #ifdef AF_DECnet
315 case AF_DECnet:
316 return AddressFamily_DecNet;
317 #endif
318 #ifdef AF_APPLETALK
319 case AF_APPLETALK:
320 return AddressFamily_AppleTalk;
321 #endif
322 #ifdef HAVE_STRUCT_SOCKADDR_IN6
323 case AF_INET6:
324 return AddressFamily_InterNetworkV6;
325 #endif
326 #ifdef AF_IRDA
327 case AF_IRDA:
328 return AddressFamily_Irda;
329 #endif
330 default:
331 g_warning ("unknown address family 0x%x", af_family);
332 return AddressFamily_Unknown;
336 static gint32
337 convert_type (MonoSocketType mono_type)
339 switch (mono_type) {
340 case SocketType_Stream:
341 return SOCK_STREAM;
342 case SocketType_Dgram:
343 return SOCK_DGRAM;
344 case SocketType_Raw:
345 return SOCK_RAW;
346 case SocketType_Rdm:
347 #ifdef SOCK_RDM
348 return SOCK_RDM;
349 #else
350 return -1;
351 #endif
352 case SocketType_Seqpacket:
353 #ifdef SOCK_SEQPACKET
354 return SOCK_SEQPACKET;
355 #else
356 return -1;
357 #endif
358 case SocketType_Unknown:
359 g_warning ("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
360 return -1;
361 default:
362 g_warning ("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
363 return -1;
367 static gint32
368 convert_proto (MonoProtocolType mono_proto)
370 switch (mono_proto) {
371 case ProtocolType_IP:
372 case ProtocolType_IPv6:
373 case ProtocolType_Icmp:
374 case ProtocolType_Igmp:
375 case ProtocolType_Ggp:
376 case ProtocolType_Tcp:
377 case ProtocolType_Pup:
378 case ProtocolType_Udp:
379 case ProtocolType_Idp:
380 /* These protocols are known (on my system at least) */
381 return mono_proto;
382 case ProtocolType_ND:
383 case ProtocolType_Raw:
384 case ProtocolType_Ipx:
385 case ProtocolType_Spx:
386 case ProtocolType_SpxII:
387 case ProtocolType_Unknown:
388 /* These protocols arent */
389 g_warning ("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
390 return -1;
391 default:
392 return -1;
396 /* Convert MonoSocketFlags */
397 static gint32
398 convert_socketflags (gint32 sflags)
400 gint32 flags = 0;
402 if (!sflags)
403 /* SocketFlags.None */
404 return 0;
406 if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek |
407 SocketFlags_DontRoute | SocketFlags_Partial))
408 /* Contains invalid flag values */
409 return -1;
411 #ifdef MSG_OOB
412 if (sflags & SocketFlags_OutOfBand)
413 flags |= MSG_OOB;
414 #endif
415 if (sflags & SocketFlags_Peek)
416 flags |= MSG_PEEK;
417 if (sflags & SocketFlags_DontRoute)
418 flags |= MSG_DONTROUTE;
420 /* Ignore Partial - see bug 349688. Don't return -1, because
421 * according to the comment in that bug ms runtime doesn't for
422 * UDP sockets (this means we will silently ignore it for TCP
423 * too)
425 #ifdef MSG_MORE
426 if (sflags & SocketFlags_Partial)
427 flags |= MSG_MORE;
428 #endif
429 #if 0
430 /* Don't do anything for MaxIOVectorLength */
431 if (sflags & SocketFlags_MaxIOVectorLength)
432 return -1;
433 #endif
434 return flags;
438 * Returns:
439 * 0 on success (mapped mono_level and mono_name to system_level and system_name
440 * -1 on error
441 * -2 on non-fatal error (ie, must ignore)
443 static gint32
444 convert_sockopt_level_and_name (MonoSocketOptionLevel mono_level, MonoSocketOptionName mono_name, int *system_level, int *system_name)
446 switch (mono_level) {
447 case SocketOptionLevel_Socket:
448 *system_level = SOL_SOCKET;
450 switch (mono_name) {
451 case SocketOptionName_DontLinger:
452 /* This is SO_LINGER, because the setsockopt
453 * internal call maps DontLinger to SO_LINGER
454 * with l_onoff=0
456 *system_name = SO_LINGER;
457 break;
458 #ifdef SO_DEBUG
459 case SocketOptionName_Debug:
460 *system_name = SO_DEBUG;
461 break;
462 #endif
463 #ifdef SO_ACCEPTCONN
464 case SocketOptionName_AcceptConnection:
465 *system_name = SO_ACCEPTCONN;
466 break;
467 #endif
468 case SocketOptionName_ReuseAddress:
469 *system_name = SO_REUSEADDR;
470 break;
471 case SocketOptionName_KeepAlive:
472 *system_name = SO_KEEPALIVE;
473 break;
474 #ifdef SO_DONTROUTE
475 case SocketOptionName_DontRoute:
476 *system_name = SO_DONTROUTE;
477 break;
478 #endif
479 case SocketOptionName_Broadcast:
480 *system_name = SO_BROADCAST;
481 break;
482 case SocketOptionName_Linger:
483 *system_name = SO_LINGER;
484 break;
485 #ifdef SO_OOBINLINE
486 case SocketOptionName_OutOfBandInline:
487 *system_name = SO_OOBINLINE;
488 break;
489 #endif
490 case SocketOptionName_SendBuffer:
491 *system_name = SO_SNDBUF;
492 break;
493 case SocketOptionName_ReceiveBuffer:
494 *system_name = SO_RCVBUF;
495 break;
496 case SocketOptionName_SendLowWater:
497 *system_name = SO_SNDLOWAT;
498 break;
499 case SocketOptionName_ReceiveLowWater:
500 *system_name = SO_RCVLOWAT;
501 break;
502 case SocketOptionName_SendTimeout:
503 *system_name = SO_SNDTIMEO;
504 break;
505 case SocketOptionName_ReceiveTimeout:
506 *system_name = SO_RCVTIMEO;
507 break;
508 case SocketOptionName_Error:
509 *system_name = SO_ERROR;
510 break;
511 case SocketOptionName_Type:
512 *system_name = SO_TYPE;
513 break;
514 #ifdef SO_PEERCRED
515 case SocketOptionName_PeerCred:
516 *system_name = SO_PEERCRED;
517 break;
518 #endif
519 case SocketOptionName_ExclusiveAddressUse:
520 #ifdef SO_EXCLUSIVEADDRUSE
521 *system_name = SO_EXCLUSIVEADDRUSE;
522 break;
523 #endif
524 case SocketOptionName_UseLoopback:
525 #ifdef SO_USELOOPBACK
526 *system_name = SO_USELOOPBACK;
527 break;
528 #endif
529 case SocketOptionName_MaxConnections:
530 #ifdef SO_MAXCONN
531 *system_name = SO_MAXCONN;
532 break;
533 #elif defined(SOMAXCONN)
534 *system_name = SOMAXCONN;
535 break;
536 #endif
537 default:
538 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
539 return -1;
541 break;
543 case SocketOptionLevel_IP:
544 *system_level = mono_networking_get_ip_protocol ();
546 switch (mono_name) {
547 #ifdef IP_OPTIONS
548 case SocketOptionName_IPOptions:
549 *system_name = IP_OPTIONS;
550 break;
551 #endif
552 #ifdef IP_HDRINCL
553 case SocketOptionName_HeaderIncluded:
554 *system_name = IP_HDRINCL;
555 break;
556 #endif
557 #ifdef IP_TOS
558 case SocketOptionName_TypeOfService:
559 *system_name = IP_TOS;
560 break;
561 #endif
562 #ifdef IP_TTL
563 case SocketOptionName_IpTimeToLive:
564 *system_name = IP_TTL;
565 break;
566 #endif
567 case SocketOptionName_MulticastInterface:
568 *system_name = IP_MULTICAST_IF;
569 break;
570 case SocketOptionName_MulticastTimeToLive:
571 *system_name = IP_MULTICAST_TTL;
572 break;
573 case SocketOptionName_MulticastLoopback:
574 *system_name = IP_MULTICAST_LOOP;
575 break;
576 case SocketOptionName_AddMembership:
577 *system_name = IP_ADD_MEMBERSHIP;
578 break;
579 case SocketOptionName_DropMembership:
580 *system_name = IP_DROP_MEMBERSHIP;
581 break;
582 #ifdef HAVE_IP_PKTINFO
583 case SocketOptionName_PacketInformation:
584 *system_name = IP_PKTINFO;
585 break;
586 #endif /* HAVE_IP_PKTINFO */
588 case SocketOptionName_DontFragment:
589 #ifdef HAVE_IP_DONTFRAGMENT
590 *system_name = IP_DONTFRAGMENT;
591 break;
592 #elif defined HAVE_IP_MTU_DISCOVER
593 /* Not quite the same */
594 *system_name = IP_MTU_DISCOVER;
595 break;
596 #else
597 /* If the flag is not available on this system, we can ignore this error */
598 return -2;
599 #endif /* HAVE_IP_DONTFRAGMENT */
600 case SocketOptionName_AddSourceMembership:
601 case SocketOptionName_DropSourceMembership:
602 case SocketOptionName_BlockSource:
603 case SocketOptionName_UnblockSource:
604 /* Can't figure out how to map these, so fall
605 * through
607 default:
608 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
609 return -1;
611 break;
613 case SocketOptionLevel_IPv6:
614 *system_level = mono_networking_get_ipv6_protocol ();
616 switch (mono_name) {
617 case SocketOptionName_IpTimeToLive:
618 case SocketOptionName_HopLimit:
619 *system_name = IPV6_UNICAST_HOPS;
620 break;
621 case SocketOptionName_MulticastInterface:
622 *system_name = IPV6_MULTICAST_IF;
623 break;
624 case SocketOptionName_MulticastTimeToLive:
625 *system_name = IPV6_MULTICAST_HOPS;
626 break;
627 case SocketOptionName_MulticastLoopback:
628 *system_name = IPV6_MULTICAST_LOOP;
629 break;
630 case SocketOptionName_AddMembership:
631 *system_name = IPV6_JOIN_GROUP;
632 break;
633 case SocketOptionName_DropMembership:
634 *system_name = IPV6_LEAVE_GROUP;
635 break;
636 case SocketOptionName_IPv6Only:
637 #ifdef IPV6_V6ONLY
638 *system_name = IPV6_V6ONLY;
639 #else
640 return -1;
641 #endif
642 break;
643 case SocketOptionName_PacketInformation:
644 #ifdef HAVE_IPV6_PKTINFO
645 *system_name = IPV6_PKTINFO;
646 #endif
647 break;
648 case SocketOptionName_HeaderIncluded:
649 case SocketOptionName_IPOptions:
650 case SocketOptionName_TypeOfService:
651 case SocketOptionName_DontFragment:
652 case SocketOptionName_AddSourceMembership:
653 case SocketOptionName_DropSourceMembership:
654 case SocketOptionName_BlockSource:
655 case SocketOptionName_UnblockSource:
656 /* Can't figure out how to map these, so fall
657 * through
659 default:
660 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
661 return -1;
663 break; /* SocketOptionLevel_IPv6 */
665 case SocketOptionLevel_Tcp:
666 *system_level = mono_networking_get_tcp_protocol ();
668 switch (mono_name) {
669 case SocketOptionName_NoDelay:
670 *system_name = TCP_NODELAY;
671 break;
672 #if 0
673 /* The documentation is talking complete
674 * bollocks here: rfc-1222 is titled
675 * 'Advancing the NSFNET Routing Architecture'
676 * and doesn't mention either of the words
677 * "expedite" or "urgent".
679 case SocketOptionName_BsdUrgent:
680 case SocketOptionName_Expedited:
681 #endif
682 default:
683 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
684 return -1;
686 break;
688 case SocketOptionLevel_Udp:
689 g_warning ("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
691 switch(mono_name) {
692 case SocketOptionName_NoChecksum:
693 case SocketOptionName_ChecksumCoverage:
694 default:
695 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
696 return -1;
698 return -1;
699 break;
701 default:
702 g_warning ("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
703 return -1;
706 return 0;
709 static MonoImage*
710 get_socket_assembly (void)
712 MonoDomain *domain = mono_domain_get ();
714 if (domain->socket_assembly == NULL) {
715 MonoImage *socket_assembly;
717 socket_assembly = mono_image_loaded_internal ("System", FALSE);
718 if (!socket_assembly) {
719 MonoAssemblyOpenRequest req;
720 mono_assembly_request_prepare (&req.request, sizeof (req), MONO_ASMCTX_DEFAULT);
721 MonoAssembly *sa = mono_assembly_request_open ("System.dll", &req, NULL);
723 if (!sa) {
724 g_assert_not_reached ();
725 } else {
726 socket_assembly = mono_assembly_get_image_internal (sa);
729 mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
732 return domain->socket_assembly;
735 gpointer
736 ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObjectHandle this_obj, gint32 family, gint32 type, gint32 proto, gint32 *werror, MonoError *error)
738 SOCKET sock;
739 gint32 sock_family;
740 gint32 sock_proto;
741 gint32 sock_type;
743 error_init (error);
744 *werror = 0;
746 sock_family = convert_family ((MonoAddressFamily)family);
747 if (sock_family == -1) {
748 *werror = WSAEAFNOSUPPORT;
749 return NULL;
752 sock_proto = convert_proto ((MonoProtocolType)proto);
753 if (sock_proto == -1) {
754 *werror = WSAEPROTONOSUPPORT;
755 return NULL;
758 sock_type = convert_type ((MonoSocketType)type);
759 if (sock_type == -1) {
760 *werror = WSAESOCKTNOSUPPORT;
761 return NULL;
764 sock = mono_w32socket_socket (sock_family, sock_type, sock_proto);
766 if (sock == INVALID_SOCKET) {
767 *werror = mono_w32socket_get_last_error ();
768 return NULL;
771 return GUINT_TO_POINTER (sock);
774 /* FIXME: the SOCKET parameter (here and in other functions in this
775 * file) is really an IntPtr which needs to be converted to a guint32.
777 void
778 ves_icall_System_Net_Sockets_Socket_Close_internal (gsize sock, gint32 *werror, MonoError *error)
780 LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
782 error_init (error);
783 *werror = 0;
785 /* Clear any pending work item from this socket if the underlying
786 * polling system does not notify when the socket is closed */
787 mono_threadpool_io_remove_socket (GPOINTER_TO_INT (sock));
789 mono_w32socket_close ((SOCKET) sock);
792 gint32
793 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal (void)
795 LOGDEBUG (g_message("%s: returning %d", __func__, mono_w32socket_get_last_error ()));
797 return mono_w32socket_get_last_error ();
800 gint32
801 ves_icall_System_Net_Sockets_Socket_Available_internal (gsize sock, gint32 *werror, MonoError *error)
803 int ret;
804 guint64 amount;
806 error_init (error);
807 *werror = 0;
809 /* FIXME: this might require amount to be unsigned long. */
810 ret = mono_w32socket_get_available (sock, &amount);
811 if (ret == SOCKET_ERROR) {
812 *werror = mono_w32socket_get_last_error ();
813 return 0;
816 return amount;
819 void
820 ves_icall_System_Net_Sockets_Socket_Blocking_internal (gsize sock, MonoBoolean block, gint32 *werror, MonoError *error)
822 int ret;
824 error_init (error);
825 *werror = 0;
827 ret = mono_w32socket_set_blocking (sock, block);
828 if (ret == SOCKET_ERROR)
829 *werror = mono_w32socket_get_last_error ();
832 gpointer
833 ves_icall_System_Net_Sockets_Socket_Accept_internal (gsize sock, gint32 *werror, MonoBoolean blocking, MonoError *error)
835 SOCKET newsock;
837 error_init (error);
838 *werror = 0;
840 newsock = mono_w32socket_accept (sock, NULL, 0, blocking);
841 if (newsock == INVALID_SOCKET) {
842 *werror = mono_w32socket_get_last_error ();
843 return NULL;
846 return GUINT_TO_POINTER (newsock);
849 void
850 ves_icall_System_Net_Sockets_Socket_Listen_internal(gsize sock, guint32 backlog, gint32 *werror, MonoError *error)
852 int ret;
854 error_init (error);
855 *werror = 0;
857 ret = mono_w32socket_listen (sock, backlog);
858 if (ret == SOCKET_ERROR)
859 *werror = mono_w32socket_get_last_error ();
862 #ifdef HAVE_STRUCT_SOCKADDR_IN6
863 // Check whether it's ::ffff::0:0.
864 static gboolean
865 is_ipv4_mapped_any (const struct in6_addr *addr)
867 int i;
869 for (i = 0; i < 10; i++) {
870 if (addr->s6_addr [i])
871 return FALSE;
873 if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
874 return FALSE;
875 for (i = 12; i < 16; i++) {
876 if (addr->s6_addr [i])
877 return FALSE;
879 return TRUE;
881 #endif
883 static MonoObjectHandle
884 create_object_handle_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error)
886 MonoDomain *domain = mono_domain_get ();
887 MonoAddressFamily family;
889 error_init (error);
891 /* Build a System.Net.SocketAddress object instance */
892 if (!domain->sockaddr_class)
893 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
894 MonoObjectHandle sockaddr_obj = mono_object_new_handle (domain, domain->sockaddr_class, error);
895 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
897 /* Locate the SocketAddress data buffer in the object */
898 if (!domain->sockaddr_data_field) {
899 domain->sockaddr_data_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Buffer", NULL);
900 g_assert (domain->sockaddr_data_field);
903 /* Locate the SocketAddress data buffer length in the object */
904 if (!domain->sockaddr_data_length_field) {
905 domain->sockaddr_data_length_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Size", NULL);
906 g_assert (domain->sockaddr_data_length_field);
909 /* May be the +2 here is too conservative, as sa_len returns
910 * the length of the entire sockaddr_in/in6, including
911 * sizeof (unsigned short) of the family */
912 /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
913 MonoArrayHandle data = mono_array_new_handle (domain, mono_get_byte_class (), sa_size + 2, error);
914 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
916 /* The data buffer is laid out as follows:
917 * bytes 0 and 1 are the address family
918 * bytes 2 and 3 are the port info
919 * the rest is the address info
922 family = convert_to_mono_family (saddr->sa_family);
923 if (family == AddressFamily_Unknown) {
924 *werror = WSAEAFNOSUPPORT;
925 return MONO_HANDLE_NEW (MonoObject, NULL);
928 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 0, family & 0x0FF);
929 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 1, (family >> 8) & 0x0FF);
931 if (saddr->sa_family == AF_INET) {
932 struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr;
933 guint16 port = ntohs (sa_in->sin_port);
934 guint32 address = ntohl (sa_in->sin_addr.s_addr);
935 int buffer_size = 8;
937 if (sa_size < buffer_size) {
938 mono_error_set_generic_error (error, "System", "SystemException", "");
939 return MONO_HANDLE_NEW (MonoObject, NULL);
942 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 2, (port>>8) & 0xff);
943 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 3, (port) & 0xff);
944 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 4, (address>>24) & 0xff);
945 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 5, (address>>16) & 0xff);
946 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 6, (address>>8) & 0xff);
947 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 7, (address) & 0xff);
949 mono_field_set_value_internal (MONO_HANDLE_RAW (sockaddr_obj), domain->sockaddr_data_field, MONO_HANDLE_RAW (data)); /* FIXME: use handles for mono_field_set_value */
950 mono_field_set_value_internal (MONO_HANDLE_RAW (sockaddr_obj), domain->sockaddr_data_length_field, &buffer_size); /* FIXME: use handles for mono_field_set_value */
952 return sockaddr_obj;
954 #ifdef HAVE_STRUCT_SOCKADDR_IN6
955 else if (saddr->sa_family == AF_INET6) {
956 struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)saddr;
957 int i;
958 int buffer_size = 28;
960 guint16 port = ntohs (sa_in->sin6_port);
962 if (sa_size < buffer_size) {
963 mono_error_set_generic_error (error, "System", "SystemException", "");
964 return MONO_HANDLE_NEW (MonoObject, NULL);
967 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 2, (port>>8) & 0xff);
968 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 3, (port) & 0xff);
970 if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
971 // Map ::ffff:0:0 to :: (bug #5502)
972 for (i = 0; i < 16; i++)
973 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 8 + i, 0);
974 } else {
975 for (i = 0; i < 16; i++) {
976 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 8 + i,
977 sa_in->sin6_addr.s6_addr [i]);
981 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 24, sa_in->sin6_scope_id & 0xff);
982 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 25,
983 (sa_in->sin6_scope_id >> 8) & 0xff);
984 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 26,
985 (sa_in->sin6_scope_id >> 16) & 0xff);
986 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 27,
987 (sa_in->sin6_scope_id >> 24) & 0xff);
989 mono_field_set_value_internal (MONO_HANDLE_RAW (sockaddr_obj), domain->sockaddr_data_field, MONO_HANDLE_RAW (data)); /* FIXME: use handles for mono_field_set_value */
990 mono_field_set_value_internal (MONO_HANDLE_RAW (sockaddr_obj), domain->sockaddr_data_length_field, &buffer_size); /* FIXME: use handles for mono_field_set_value */
992 return sockaddr_obj;
994 #endif
995 #ifdef HAVE_SYS_UN_H
996 else if (saddr->sa_family == AF_UNIX) {
997 int i;
998 int buffer_size = sa_size + 2;
1000 for (i = 0; i < sa_size; i++)
1001 MONO_HANDLE_ARRAY_SETVAL (data, guint8, i + 2, saddr->sa_data [i]);
1003 mono_field_set_value_internal (MONO_HANDLE_RAW (sockaddr_obj), domain->sockaddr_data_field, MONO_HANDLE_RAW (data)); /* FIXME: use handles for mono_field_set_value */
1004 mono_field_set_value_internal (MONO_HANDLE_RAW (sockaddr_obj), domain->sockaddr_data_length_field, &buffer_size); /* FIXME: use handles for mono_field_set_value */
1006 return sockaddr_obj;
1008 #endif
1009 else {
1010 *werror = WSAEAFNOSUPPORT;
1011 return MONO_HANDLE_NEW (MonoObject, NULL);
1015 static int
1016 get_sockaddr_size (int family)
1018 int size;
1020 size = 0;
1021 if (family == AF_INET) {
1022 size = sizeof (struct sockaddr_in);
1024 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1025 else if (family == AF_INET6) {
1026 size = sizeof (struct sockaddr_in6);
1028 #endif
1029 #ifdef HAVE_SYS_UN_H
1030 else if (family == AF_UNIX) {
1031 size = sizeof (struct sockaddr_un);
1033 #endif
1034 return size;
1037 static MonoObjectHandle
1038 mono_w32socket_getname (gsize sock, gint32 af, gboolean local, gint32 *werror, MonoError *error)
1040 gpointer sa = NULL;
1041 socklen_t salen = 0;
1042 int ret;
1043 MonoObjectHandle result = NULL_HANDLE;
1045 *werror = 0;
1047 salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
1048 if (salen == 0) {
1049 *werror = WSAEAFNOSUPPORT;
1050 goto exit;
1052 if (salen <= 128) {
1053 sa = g_alloca (salen);
1054 memset (sa, 0, salen);
1055 } else {
1056 sa = g_malloc0 (salen);
1059 /* Note: linux returns just 2 for AF_UNIX. Always. */
1060 ret = (local ? mono_w32socket_getsockname : mono_w32socket_getpeername) (sock, (struct sockaddr *)sa, &salen);
1061 if (ret == SOCKET_ERROR) {
1062 *werror = mono_w32socket_get_last_error ();
1063 goto exit;
1066 LOGDEBUG (g_message("%s: %s to %s port %d", __func__, local ? "bound" : "connected", inet_ntoa (((struct sockaddr_in *)&sa)->sin_addr), ntohs (((struct sockaddr_in *)&sa)->sin_port)));
1068 result = create_object_handle_from_sockaddr ((struct sockaddr *)sa, salen, werror, error);
1069 exit:
1070 if (salen > 128)
1071 g_free (sa);
1072 return result;
1075 MonoObjectHandle
1076 ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal (gsize sock, gint32 af, gint32 *werror, MonoError *error)
1078 return mono_w32socket_getname (sock, af, TRUE, werror, error);
1081 MonoObjectHandle
1082 ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (gsize sock, gint32 af, gint32 *werror, MonoError *error)
1084 return mono_w32socket_getname (sock, af, FALSE, werror, error);
1087 static struct sockaddr*
1088 create_sockaddr_from_handle (MonoObjectHandle saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
1090 MonoDomain *domain = mono_domain_get ();
1091 gint32 family;
1092 int len;
1094 error_init (error);
1096 if (!domain->sockaddr_class)
1097 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
1099 /* Locate the SocketAddress data buffer in the object */
1100 if (!domain->sockaddr_data_field) {
1101 domain->sockaddr_data_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Buffer", NULL);
1102 g_assert (domain->sockaddr_data_field);
1105 /* Locate the SocketAddress data buffer length in the object */
1106 if (!domain->sockaddr_data_length_field) {
1107 domain->sockaddr_data_length_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Size", NULL);
1108 g_assert (domain->sockaddr_data_length_field);
1111 MonoArrayHandle data = MONO_HANDLE_NEW_GET_FIELD (saddr_obj, MonoArray, domain->sockaddr_data_field);
1113 /* The data buffer is laid out as follows:
1114 * byte 0 is the address family low byte
1115 * byte 1 is the address family high byte
1116 * INET:
1117 * bytes 2 and 3 are the port info
1118 * the rest is the address info
1119 * UNIX:
1120 * the rest is the file name
1122 len = MONO_HANDLE_GET_FIELD_VAL (saddr_obj, int, domain->sockaddr_data_length_field);
1123 g_assert (len >= 2);
1125 uint32_t gchandle;
1126 guint8 *buf = MONO_ARRAY_HANDLE_PIN (data, guint8, 0, &gchandle);
1127 family = convert_family ((MonoAddressFamily)(buf[0] + (buf[1] << 8)));
1128 if (family == AF_INET) {
1129 struct sockaddr_in *sa;
1130 guint16 port;
1131 guint32 address;
1133 if (len < 8) {
1134 mono_error_set_generic_error (error, "System", "SystemException", "");
1135 mono_gchandle_free_internal (gchandle);
1136 return NULL;
1139 sa = g_new0 (struct sockaddr_in, 1);
1140 port = (buf[2] << 8) + buf[3];
1141 address = (buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7];
1143 sa->sin_family = family;
1144 sa->sin_addr.s_addr = htonl (address);
1145 sa->sin_port = htons (port);
1147 *sa_size = sizeof (struct sockaddr_in);
1148 mono_gchandle_free_internal (gchandle);
1149 return (struct sockaddr *)sa;
1151 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1152 else if (family == AF_INET6) {
1153 struct sockaddr_in6 *sa;
1154 int i;
1155 guint16 port;
1156 guint32 scopeid;
1158 if (len < 28) {
1159 mono_error_set_generic_error (error, "System", "SystemException", "");
1160 mono_gchandle_free_internal (gchandle);
1161 return NULL;
1164 sa = g_new0 (struct sockaddr_in6, 1);
1165 port = buf[3] + (buf[2] << 8);
1166 scopeid = buf[24] + (buf[25] << 8) + (buf[26] << 16) + (buf[27] << 24);
1168 sa->sin6_family = family;
1169 sa->sin6_port = htons (port);
1170 sa->sin6_scope_id = scopeid;
1172 for (i = 0; i < 16; i++)
1173 sa->sin6_addr.s6_addr [i] = buf[8 + i];
1175 *sa_size = sizeof (struct sockaddr_in6);
1176 mono_gchandle_free_internal (gchandle);
1177 return (struct sockaddr *)sa;
1179 #endif
1180 #ifdef HAVE_SYS_UN_H
1181 else if (family == AF_UNIX) {
1182 struct sockaddr_un *sock_un;
1183 int i;
1185 /* Need a byte for the '\0' terminator/prefix, and the first
1186 * two bytes hold the SocketAddress family
1188 if (len - 2 >= sizeof (sock_un->sun_path)) {
1189 mono_error_set_argument_out_of_range (error, "SocketAddress.Size");
1190 mono_gchandle_free_internal (gchandle);
1191 return NULL;
1194 sock_un = g_new0 (struct sockaddr_un, 1);
1196 sock_un->sun_family = family;
1197 for (i = 0; i < len - 2; i++)
1198 sock_un->sun_path [i] = buf[i + 2];
1200 *sa_size = len;
1201 mono_gchandle_free_internal (gchandle);
1202 return (struct sockaddr *)sock_un;
1204 #endif
1205 else {
1206 *werror = WSAEAFNOSUPPORT;
1207 mono_gchandle_free_internal (gchandle);
1208 return 0;
1212 void
1213 ves_icall_System_Net_Sockets_Socket_Bind_internal (gsize sock, MonoObjectHandle sockaddr, gint32 *werror, MonoError *error)
1215 struct sockaddr *sa;
1216 socklen_t sa_size;
1217 int ret;
1219 error_init (error);
1220 *werror = 0;
1222 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1223 if (*werror != 0)
1224 return;
1225 return_if_nok (error);
1227 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)));
1229 ret = mono_w32socket_bind (sock, sa, sa_size);
1231 if (ret == SOCKET_ERROR)
1232 *werror = mono_w32socket_get_last_error ();
1234 g_free (sa);
1237 enum {
1238 SelectModeRead,
1239 SelectModeWrite,
1240 SelectModeError
1243 MonoBoolean
1244 ves_icall_System_Net_Sockets_Socket_Poll_internal (gsize sock, gint mode,
1245 gint timeout, gint32 *werror, MonoError *error)
1247 MonoInternalThread *thread = mono_thread_internal_current ();
1248 mono_pollfd *pfds;
1249 int ret;
1250 time_t start;
1251 gint rtimeout;
1253 error_init (error);
1254 *werror = 0;
1256 pfds = g_new0 (mono_pollfd, 1);
1257 pfds->fd = GPOINTER_TO_INT (sock);
1259 switch (mode) {
1260 case SelectModeRead:
1261 pfds->events = MONO_POLLIN;
1262 break;
1263 case SelectModeWrite:
1264 pfds->events = MONO_POLLOUT;
1265 break;
1266 default:
1267 pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL;
1268 break;
1271 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1272 rtimeout = timeout;
1273 start = time (NULL);
1275 do {
1276 MONO_ENTER_GC_SAFE;
1278 ret = mono_poll (pfds, 1, timeout);
1280 MONO_EXIT_GC_SAFE;
1282 if (timeout > 0 && ret < 0) {
1283 int err = errno;
1284 int sec = time (NULL) - start;
1286 timeout = rtimeout - sec * 1000;
1287 if (timeout < 0) {
1288 timeout = 0;
1291 mono_set_errno (err);
1294 if (ret == -1 && errno == EINTR) {
1295 if (mono_thread_test_state (thread, ThreadState_AbortRequested)) {
1296 g_free (pfds);
1297 return FALSE;
1300 /* Suspend requested? */
1301 mono_thread_interruption_checkpoint_void ();
1303 mono_set_errno (EINTR);
1305 } while (ret == -1 && errno == EINTR);
1307 if (ret == -1) {
1308 *werror = mono_w32socket_convert_error (errno);
1309 g_free (pfds);
1310 return FALSE;
1313 g_free (pfds);
1314 return ret != 0;
1317 void
1318 ves_icall_System_Net_Sockets_Socket_Connect_internal (gsize sock, MonoObjectHandle sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1320 struct sockaddr *sa;
1321 socklen_t sa_size;
1322 int ret;
1324 error_init (error);
1325 *werror = 0;
1327 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1328 if (*werror != 0)
1329 return;
1330 return_if_nok (error);
1332 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)));
1334 ret = mono_w32socket_connect (sock, sa, sa_size, blocking);
1335 if (ret == SOCKET_ERROR)
1336 *werror = mono_w32socket_get_last_error ();
1338 g_free (sa);
1341 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
1343 void
1344 ves_icall_System_Net_Sockets_Socket_Disconnect_internal (gsize sock, MonoBoolean reuse, gint32 *werror, MonoError *error)
1346 error_init (error);
1348 LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
1350 *werror = mono_w32socket_disconnect (sock, reuse);
1352 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
1354 MonoBoolean
1355 ves_icall_System_Net_Sockets_Socket_Duplicate_internal (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle, gint32 *werror, MonoError *error)
1357 error_init (error);
1359 *werror = 0;
1360 if (!mono_w32socket_duplicate (handle, targetProcessId, duplicate_handle)) {
1361 *werror = mono_w32error_get_last ();
1362 return FALSE;
1365 return TRUE;
1368 gint32
1369 ves_icall_System_Net_Sockets_Socket_Receive_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1371 int ret;
1372 int recvflags = 0;
1374 error_init (error);
1375 *werror = 0;
1377 recvflags = convert_socketflags (flags);
1378 if (recvflags == -1) {
1379 *werror = WSAEOPNOTSUPP;
1380 return 0;
1383 ret = mono_w32socket_recv (sock, buffer, count, recvflags, blocking);
1384 if (ret == SOCKET_ERROR) {
1385 *werror = mono_w32socket_get_last_error ();
1386 return 0;
1389 return ret;
1392 gint32
1393 ves_icall_System_Net_Sockets_Socket_Receive_array_internal (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1395 int ret;
1396 guint32 recv;
1397 guint32 recvflags = 0;
1399 error_init (error);
1400 *werror = 0;
1402 recvflags = convert_socketflags (flags);
1403 if (recvflags == -1) {
1404 *werror = WSAEOPNOTSUPP;
1405 return 0;
1408 ret = mono_w32socket_recvbuffers (sock, buffers, count, &recv, &recvflags, NULL, NULL, blocking);
1409 if (ret == SOCKET_ERROR) {
1410 *werror = mono_w32socket_get_last_error ();
1411 return 0;
1414 return recv;
1417 gint32
1418 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandleInOut sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1420 int ret;
1421 int recvflags = 0;
1422 struct sockaddr *sa;
1423 socklen_t sa_size;
1425 error_init (error);
1426 *werror = 0;
1428 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1429 if (*werror != 0)
1430 return 0;
1431 if (!is_ok (error))
1432 return 0;
1434 recvflags = convert_socketflags (flags);
1435 if (recvflags == -1) {
1436 *werror = WSAEOPNOTSUPP;
1437 return 0;
1440 ret = mono_w32socket_recvfrom (sock, buffer, count, recvflags, sa, &sa_size, blocking);
1441 if (ret == SOCKET_ERROR) {
1442 *werror = mono_w32socket_get_last_error ();
1443 g_free(sa);
1444 return 0;
1447 /* If we didn't get a socket size, then we're probably a
1448 * connected connection-oriented socket and the stack hasn't
1449 * returned the remote address. All we can do is return null.
1451 if (sa_size) {
1452 MONO_HANDLE_ASSIGN (sockaddr, create_object_handle_from_sockaddr (sa, sa_size, werror, error));
1453 if (!is_ok (error)) {
1454 g_free (sa);
1455 return 0;
1457 } else {
1458 MONO_HANDLE_ASSIGN (sockaddr, MONO_HANDLE_NEW (MonoObject, NULL));
1461 g_free (sa);
1463 return ret;
1466 gint32
1467 ves_icall_System_Net_Sockets_Socket_Send_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1469 int ret;
1470 int sendflags = 0;
1472 error_init (error);
1473 *werror = 0;
1475 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1477 sendflags = convert_socketflags (flags);
1478 if (sendflags == -1) {
1479 *werror = WSAEOPNOTSUPP;
1480 return 0;
1483 ret = mono_w32socket_send (sock, buffer, count, sendflags, blocking);
1484 if (ret == SOCKET_ERROR) {
1485 *werror = mono_w32socket_get_last_error ();
1486 return 0;
1489 return ret;
1492 gint32
1493 ves_icall_System_Net_Sockets_Socket_Send_array_internal (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1495 int ret;
1496 guint32 sent;
1497 guint32 sendflags = 0;
1499 error_init (error);
1500 *werror = 0;
1502 sendflags = convert_socketflags (flags);
1503 if (sendflags == -1) {
1504 *werror = WSAEOPNOTSUPP;
1505 return 0;
1508 ret = mono_w32socket_sendbuffers (sock, buffers, count, &sent, sendflags, NULL, NULL, blocking);
1509 if (ret == SOCKET_ERROR) {
1510 *werror = mono_w32socket_get_last_error ();
1511 return 0;
1514 return sent;
1517 gint32
1518 ves_icall_System_Net_Sockets_Socket_SendTo_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandle sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1520 int ret;
1521 int sendflags = 0;
1522 struct sockaddr *sa;
1523 socklen_t sa_size;
1525 *werror = 0;
1527 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1528 if (*werror != 0 || !is_ok (error))
1529 return 0;
1531 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1533 sendflags = convert_socketflags (flags);
1534 if (sendflags == -1) {
1535 *werror = WSAEOPNOTSUPP;
1536 g_free (sa);
1537 return 0;
1540 ret = mono_w32socket_sendto (sock, buffer, count, sendflags, sa, sa_size, blocking);
1541 if (ret == SOCKET_ERROR) {
1542 *werror = mono_w32socket_get_last_error ();
1543 g_free(sa);
1544 return 0;
1547 g_free(sa);
1548 return ret;
1551 static SOCKET
1552 Socket_to_SOCKET (MonoObjectHandle sockobj)
1554 MonoClassField *field;
1556 field = mono_class_get_field_from_name_full (mono_handle_class (sockobj), "m_Handle", NULL);
1557 MonoSafeHandleHandle safe_handle = MONO_HANDLE_NEW_GET_FIELD(sockobj, MonoSafeHandle, field);
1559 if (MONO_HANDLE_IS_NULL (safe_handle))
1560 return -1;
1562 return (SOCKET)(gsize)MONO_HANDLE_GETVAL (safe_handle, handle);
1565 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1567 static gboolean
1568 collect_pollfds_from_array (MonoArrayHandle sockets, int i, int nfds, mono_pollfd *pfds, int *idx, int *mode)
1570 HANDLE_FUNCTION_ENTER ();
1571 gboolean result = TRUE;
1572 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1573 MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1574 if (MONO_HANDLE_IS_NULL (obj)) {
1575 (*mode)++;
1576 goto leave;
1579 if (*idx >= nfds) {
1580 result = FALSE;
1581 goto leave;
1584 pfds [*idx].fd = Socket_to_SOCKET (obj);
1585 pfds [*idx].events = (*mode == 0) ? MONO_POLLIN : (*mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1586 (*idx)++;
1587 leave:
1588 HANDLE_FUNCTION_RETURN_VAL (result);
1591 static void
1592 set_socks_array_from_pollfds (MonoArrayHandle sockets, int i, mono_pollfd *pfds, int *ret, int *mode, MonoArrayHandle socks, int *idx)
1594 HANDLE_FUNCTION_ENTER ();
1595 mono_pollfd *pfd;
1597 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1598 MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1599 if (MONO_HANDLE_IS_NULL (obj)) {
1600 (*mode)++;
1601 (*idx)++;
1602 goto leave;
1605 pfd = &pfds [i - *mode];
1606 if (pfd->revents == 0)
1607 goto leave;
1609 (*ret)--;
1610 if (((*mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0)) ||
1611 ((*mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0)) ||
1612 ((pfd->revents & POLL_ERRORS) != 0)) {
1613 MONO_HANDLE_ARRAY_SETREF (socks, *idx, obj);
1614 (*idx)++;
1616 leave:
1617 HANDLE_FUNCTION_RETURN ();
1620 void
1621 ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArrayHandleOut sockets, gint32 timeout, gint32 *werror, MonoError *error)
1623 MonoInternalThread *thread = mono_thread_internal_current ();
1624 mono_pollfd *pfds;
1625 int nfds, idx;
1626 int ret;
1627 int i, count;
1628 int mode;
1629 MonoClass *sock_arr_class;
1630 time_t start;
1631 uintptr_t socks_size;
1632 gint32 rtimeout;
1634 error_init (error);
1635 *werror = 0;
1637 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1638 count = mono_array_handle_length (sockets);
1639 nfds = count - 3; /* NULL separators */
1640 pfds = g_new0 (mono_pollfd, nfds);
1641 mode = idx = 0;
1642 for (i = 0; i < count; i++) {
1643 if (!collect_pollfds_from_array (sockets, i, nfds, pfds, &idx, &mode)) {
1644 /* The socket array was bogus */
1645 g_free (pfds);
1646 *werror = WSAEFAULT;
1647 return;
1651 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1652 rtimeout = timeout;
1653 start = time (NULL);
1654 do {
1655 MONO_ENTER_GC_SAFE;
1657 ret = mono_poll (pfds, nfds, timeout);
1659 MONO_EXIT_GC_SAFE;
1661 if (timeout > 0 && ret < 0) {
1662 int err = errno;
1663 int sec = time (NULL) - start;
1665 timeout = rtimeout - sec * 1000;
1666 if (timeout < 0)
1667 timeout = 0;
1668 mono_set_errno (err);
1671 if (ret == -1 && errno == EINTR) {
1672 if (mono_thread_test_state (thread, ThreadState_AbortRequested)) {
1673 g_free (pfds);
1674 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1675 return;
1678 /* Suspend requested? */
1679 mono_thread_interruption_checkpoint_void ();
1681 mono_set_errno (EINTR);
1683 } while (ret == -1 && errno == EINTR);
1685 if (ret == -1) {
1686 *werror = mono_w32socket_convert_error (errno);
1687 g_free (pfds);
1688 return;
1691 if (ret == 0) {
1692 g_free (pfds);
1693 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1694 return;
1697 sock_arr_class = mono_handle_class (sockets);
1698 socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1699 MonoArrayHandle socks = MONO_HANDLE_NEW (MonoArray, mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, error));
1700 if (!is_ok (error)) {
1701 g_free (pfds);
1702 return;
1705 mode = idx = 0;
1706 for (i = 0; i < count && ret > 0; i++) {
1707 set_socks_array_from_pollfds (sockets, i, pfds, &ret, &mode, socks, &idx);
1710 MONO_HANDLE_ASSIGN (sockets, socks);
1711 g_free (pfds);
1714 static MonoObjectHandle
1715 int_to_object_handle (MonoDomain *domain, int val, MonoError *error)
1717 return MONO_HANDLE_NEW (MonoObject, mono_value_box_checked (domain, mono_get_int32_class (), &val, error));
1720 void
1721 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (gsize sock, gint32 level, gint32 name, MonoObjectHandleOut obj_val, gint32 *werror, MonoError *error)
1723 int system_level = 0;
1724 int system_name = 0;
1725 int ret;
1726 int val = 0;
1727 socklen_t valsize = sizeof (val);
1728 struct linger linger;
1729 socklen_t lingersize = sizeof (linger);
1730 int time_ms = 0;
1731 socklen_t time_ms_size = sizeof (time_ms);
1732 #ifdef SO_PEERCRED
1733 # if defined(__OpenBSD__)
1734 struct sockpeercred cred;
1735 # else
1736 struct ucred cred;
1737 # endif
1738 socklen_t credsize = sizeof (cred);
1739 #endif
1740 MonoDomain *domain = mono_domain_get ();
1741 MonoClass *obj_class;
1742 MonoClassField *field;
1744 error_init (error);
1745 *werror = 0;
1747 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1748 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1749 system_level = SOL_SOCKET;
1750 system_name = SO_REUSEADDR;
1751 ret = 0;
1752 } else
1753 #endif
1755 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1758 if (ret == -1) {
1759 *werror = WSAENOPROTOOPT;
1760 return;
1762 if (ret == -2) {
1763 MONO_HANDLE_ASSIGN (obj_val, int_to_object_handle (domain, 0, error));
1764 return;
1767 /* No need to deal with MulticastOption names here, because
1768 * you cant getsockopt AddMembership or DropMembership (the
1769 * int getsockopt will error, causing an exception)
1771 switch (name) {
1772 case SocketOptionName_Linger:
1773 case SocketOptionName_DontLinger:
1774 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &linger, &lingersize);
1775 break;
1777 case SocketOptionName_SendTimeout:
1778 case SocketOptionName_ReceiveTimeout:
1779 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &time_ms, &time_ms_size);
1780 break;
1782 #ifdef SO_PEERCRED
1783 case SocketOptionName_PeerCred:
1784 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &cred, &credsize);
1785 break;
1786 #endif
1788 default:
1789 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &val, &valsize);
1792 if (ret == SOCKET_ERROR) {
1793 *werror = mono_w32socket_get_last_error ();
1794 return;
1797 switch (name) {
1798 case SocketOptionName_Linger: {
1799 /* build a System.Net.Sockets.LingerOption */
1800 obj_class = mono_class_load_from_name (get_socket_assembly (),
1801 "System.Net.Sockets",
1802 "LingerOption");
1803 MonoObjectHandle obj = mono_object_new_handle (domain, obj_class, error);
1804 return_if_nok (error);
1806 /* Locate and set the fields "bool enabled" and "int
1807 * lingerTime"
1809 field = mono_class_get_field_from_name_full (obj_class, "enabled", NULL);
1810 MONO_HANDLE_SET_FIELD_VAL (obj, guint8, field, linger.l_onoff);
1812 field = mono_class_get_field_from_name_full (obj_class, "lingerTime", NULL);
1813 MONO_HANDLE_SET_FIELD_VAL (obj, guint32, field, linger.l_linger);
1815 MONO_HANDLE_ASSIGN (obj_val, obj);
1816 break;
1818 case SocketOptionName_DontLinger: {
1819 /* construct a bool int in val - true if linger is off */
1820 MonoObjectHandle obj = int_to_object_handle (domain, !linger.l_onoff, error);
1821 return_if_nok (error);
1823 MONO_HANDLE_ASSIGN (obj_val, obj);
1824 break;
1826 case SocketOptionName_SendTimeout:
1827 case SocketOptionName_ReceiveTimeout: {
1828 MonoObjectHandle obj = int_to_object_handle (domain, time_ms, error);
1829 return_if_nok (error);
1831 MONO_HANDLE_ASSIGN (obj_val, obj);
1832 break;
1835 #ifdef SO_PEERCRED
1836 case SocketOptionName_PeerCred: {
1838 * build a Mono.Posix.PeerCred+PeerCredData if
1839 * possible
1841 static MonoImage *mono_posix_image = NULL;
1843 if (mono_posix_image == NULL) {
1844 mono_posix_image = mono_image_loaded_internal ("Mono.Posix", FALSE);
1845 if (!mono_posix_image) {
1846 MonoAssemblyOpenRequest req;
1847 mono_assembly_request_prepare (&req.request, sizeof (req), MONO_ASMCTX_DEFAULT);
1848 MonoAssembly *sa = mono_assembly_request_open ("Mono.Posix.dll", &req, NULL);
1849 if (!sa) {
1850 *werror = WSAENOPROTOOPT;
1851 return;
1852 } else {
1853 mono_posix_image = mono_assembly_get_image_internal (sa);
1858 obj_class = mono_class_load_from_name (mono_posix_image,
1859 "Mono.Posix",
1860 "PeerCredData");
1861 MonoPeerCredDataHandle cred_data = MONO_HANDLE_CAST (MonoPeerCredData, mono_object_new_handle (domain, obj_class, error));
1862 return_if_nok (error);
1864 MONO_HANDLE_SETVAL (cred_data, pid, gint, cred.pid);
1865 MONO_HANDLE_SETVAL (cred_data, uid, gint, cred.uid);
1866 MONO_HANDLE_SETVAL (cred_data, gid, gint, cred.gid);
1868 MONO_HANDLE_ASSIGN (obj_val, cred_data);
1869 break;
1871 #endif
1873 default: {
1874 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1875 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
1876 val = val ? 0 : 1;
1877 #endif
1878 MonoObjectHandle obj = int_to_object_handle (domain, val, error);
1879 return_if_nok (error);
1881 MONO_HANDLE_ASSIGN (obj_val, obj);
1886 void
1887 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (gsize sock, gint32 level, gint32 name, MonoArrayHandle byte_val, gint32 *werror, MonoError *error)
1889 int system_level = 0;
1890 int system_name = 0;
1891 int ret;
1892 socklen_t valsize;
1894 error_init (error);
1895 *werror = 0;
1897 ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
1898 &system_name);
1899 if (ret == -1) {
1900 *werror = WSAENOPROTOOPT;
1901 return;
1903 if (ret == -2)
1904 return;
1906 valsize = mono_array_handle_length (byte_val);
1908 uint32_t gchandle;
1909 guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
1911 ret = mono_w32socket_getsockopt (sock, system_level, system_name, buf, &valsize);
1913 mono_gchandle_free_internal (gchandle);
1915 if (ret == SOCKET_ERROR)
1916 *werror = mono_w32socket_get_last_error ();
1919 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1920 static struct in_addr
1921 ipaddress_handle_to_struct_in_addr (MonoObjectHandle ipaddr)
1923 struct in_addr inaddr;
1924 MonoClassField *field;
1926 field = mono_class_get_field_from_name_full (mono_handle_class (ipaddr), "m_Address", NULL);
1927 g_assert (field);
1929 /* No idea why .net uses a 64bit type to hold a 32bit value...
1931 * Internal value of IPAddess is in little-endian order
1933 inaddr.s_addr = GUINT_FROM_LE ((guint32)MONO_HANDLE_GET_FIELD_VAL (ipaddr, guint64, field));
1935 return inaddr;
1938 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1939 static struct in6_addr
1940 ipaddress_handle_to_struct_in6_addr (MonoObjectHandle ipaddr)
1942 struct in6_addr in6addr;
1943 MonoClassField *field;
1944 int i;
1946 field = mono_class_get_field_from_name_full (mono_handle_class (ipaddr), "m_Numbers", NULL);
1947 g_assert (field);
1948 MonoArrayHandle data = MONO_HANDLE_NEW_GET_FIELD (ipaddr, MonoArray, field);
1950 for (i = 0; i < 8; i++) {
1951 guint16 v;
1952 MONO_HANDLE_ARRAY_GETVAL (v, data, guint16, i);
1953 const guint16 s = GUINT16_TO_BE (v);
1955 /* Solaris/MacOS have only the 8 bit version. */
1956 #ifndef s6_addr16
1957 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
1958 in6addr.s6_addr[2 * i] = s & 0xff;
1959 #else
1960 in6addr.s6_addr16[i] = s;
1961 #endif
1963 return in6addr;
1965 #endif
1966 #endif
1968 #if defined(__APPLE__) || defined(__FreeBSD__)
1970 static int
1971 get_local_interface_id (int family)
1973 #if !defined(HAVE_GETIFADDRS) || !defined(HAVE_IF_NAMETOINDEX)
1974 return 0;
1975 #else
1976 struct ifaddrs *ifap = NULL, *ptr;
1977 int idx = 0;
1979 if (getifaddrs (&ifap))
1980 return 0;
1982 for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
1983 if (!ptr->ifa_addr || !ptr->ifa_name)
1984 continue;
1985 if (ptr->ifa_addr->sa_family != family)
1986 continue;
1987 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
1988 continue;
1989 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
1990 continue;
1992 idx = if_nametoindex (ptr->ifa_name);
1993 break;
1996 freeifaddrs (ifap);
1997 return idx;
1998 #endif
2001 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
2003 void
2004 ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal (gsize sock, gint32 level, gint32 name, MonoObjectHandle obj_val, MonoArrayHandle byte_val, gint32 int_val, gint32 *werror, MonoError *error)
2006 struct linger linger;
2007 int system_level = 0;
2008 int system_name = 0;
2009 int ret;
2010 int sol_ip;
2011 int sol_ipv6;
2013 error_init (error);
2014 *werror = 0;
2016 sol_ipv6 = mono_networking_get_ipv6_protocol ();
2017 sol_ip = mono_networking_get_ip_protocol ();
2019 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2020 &system_name);
2022 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2023 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2024 system_name = SO_REUSEADDR;
2025 int_val = int_val ? 0 : 1;
2026 ret = 0;
2028 #endif
2030 if (ret == -1) {
2031 *werror = WSAENOPROTOOPT;
2032 return;
2034 if (ret == -2)
2035 return;
2037 /* Only one of obj_val, byte_val or int_val has data */
2038 if (!MONO_HANDLE_IS_NULL (obj_val)) {
2039 MonoClass *obj_class = mono_handle_class (obj_val);
2040 MonoClassField *field;
2041 int valsize;
2043 switch (name) {
2044 case SocketOptionName_Linger:
2045 /* Dig out "bool enabled" and "int lingerTime"
2046 * fields
2048 field = mono_class_get_field_from_name_full (obj_class, "enabled", NULL);
2049 linger.l_onoff = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint8, field);
2050 field = mono_class_get_field_from_name_full (obj_class, "lingerTime", NULL);
2051 linger.l_linger = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint32, field);
2053 valsize = sizeof (linger);
2054 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, valsize);
2055 break;
2056 case SocketOptionName_AddMembership:
2057 case SocketOptionName_DropMembership:
2058 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2060 MonoObjectHandle address = MONO_HANDLE_NEW (MonoObject, NULL);
2061 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2062 if (system_level == sol_ipv6) {
2063 struct ipv6_mreq mreq6;
2066 * Get group address
2068 field = mono_class_get_field_from_name_full (obj_class, "m_Group", NULL);
2069 g_assert (field);
2070 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2072 if (!MONO_HANDLE_IS_NULL (address))
2073 mreq6.ipv6mr_multiaddr = ipaddress_handle_to_struct_in6_addr (address);
2075 field = mono_class_get_field_from_name_full (obj_class, "m_Interface", NULL);
2076 mreq6.ipv6mr_interface = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint64, field);
2078 #if defined(__APPLE__) || defined(__FreeBSD__)
2080 * Bug #5504:
2082 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2084 * Tests on Windows and Linux show that the multicast group is only
2085 * joined on one NIC when interface = 0, so we simply use the interface
2086 * id from the first non-loopback interface (this is also what
2087 * Dns.GetHostName (string.Empty) would return).
2089 if (!mreq6.ipv6mr_interface)
2090 mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2091 #endif
2093 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq6, sizeof (mreq6));
2095 break; // Don't check sol_ip
2097 #endif
2098 if (system_level == sol_ip) {
2099 #ifdef HAVE_STRUCT_IP_MREQN
2100 struct ip_mreqn mreq = {{0}};
2101 #else
2102 struct ip_mreq mreq = {{0}};
2103 #endif /* HAVE_STRUCT_IP_MREQN */
2106 * pain! MulticastOption holds two IPAddress
2107 * members, so I have to dig the value out of
2108 * those :-(
2110 field = mono_class_get_field_from_name_full (obj_class, "group", NULL);
2111 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2113 /* address might not be defined and if so, set the address to ADDR_ANY.
2115 if (!MONO_HANDLE_IS_NULL (address))
2116 mreq.imr_multiaddr = ipaddress_handle_to_struct_in_addr (address);
2118 field = mono_class_get_field_from_name_full (obj_class, "localAddress", NULL);
2119 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2121 #ifdef HAVE_STRUCT_IP_MREQN
2122 if (!MONO_HANDLE_IS_NULL (address))
2123 mreq.imr_address = ipaddress_handle_to_struct_in_addr (address);
2125 field = mono_class_get_field_from_name_full (obj_class, "ifIndex", NULL);
2126 mreq.imr_ifindex = MONO_HANDLE_GET_FIELD_VAL (obj_val, gint32, field);
2127 #else
2128 if (!MONO_HANDLE_IS_NULL (address))
2129 mreq.imr_interface = ipaddress_handle_to_struct_in_addr (address);
2130 #endif /* HAVE_STRUCT_IP_MREQN */
2132 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
2134 break;
2136 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2137 default:
2138 /* Cause an exception to be thrown */
2139 *werror = WSAEINVAL;
2140 return;
2142 } else if (!MONO_HANDLE_IS_NULL (byte_val)) {
2143 int valsize = mono_array_handle_length (byte_val);
2144 uint32_t gchandle;
2145 guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
2147 switch(name) {
2148 case SocketOptionName_DontLinger:
2149 if (valsize == 1) {
2150 linger.l_onoff = (*buf) ? 0 : 1;
2151 linger.l_linger = 0;
2152 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2153 } else {
2154 *werror = WSAEINVAL;
2156 break;
2157 default:
2158 ret = mono_w32socket_setsockopt (sock, system_level, system_name, buf, valsize);
2159 break;
2161 mono_gchandle_free_internal (gchandle);
2162 } else {
2163 /* ReceiveTimeout/SendTimeout get here */
2164 switch (name) {
2165 case SocketOptionName_DontLinger:
2166 linger.l_onoff = !int_val;
2167 linger.l_linger = 0;
2168 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2169 break;
2170 case SocketOptionName_MulticastInterface:
2171 #ifndef HOST_WIN32
2172 #ifdef HAVE_STRUCT_IP_MREQN
2173 int_val = GUINT32_FROM_BE (int_val);
2174 if ((int_val & 0xff000000) == 0) {
2175 /* int_val is interface index */
2176 struct ip_mreqn mreq = {{0}};
2177 mreq.imr_ifindex = int_val;
2178 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
2179 break;
2181 int_val = GUINT32_TO_BE (int_val);
2182 #endif /* HAVE_STRUCT_IP_MREQN */
2183 #endif /* HOST_WIN32 */
2184 /* int_val is in_addr */
2185 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &int_val, sizeof (int_val));
2186 break;
2187 case SocketOptionName_DontFragment:
2188 #ifdef HAVE_IP_MTU_DISCOVER
2189 /* Fiddle with the value slightly if we're
2190 * turning DF on
2192 if (int_val == 1)
2193 int_val = IP_PMTUDISC_DO;
2194 /* Fall through */
2195 #endif
2197 default:
2198 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &int_val, sizeof (int_val));
2202 if (ret == SOCKET_ERROR) {
2203 *werror = mono_w32socket_get_last_error ();
2205 #ifdef HAVE_IP_MTU_DISCOVER
2206 if (system_name == IP_MTU_DISCOVER) {
2207 switch (system_level) {
2208 case IP_PMTUDISC_DONT:
2209 case IP_PMTUDISC_WANT:
2210 case IP_PMTUDISC_DO:
2211 #ifdef IP_PMTUDISC_PROBE
2212 case IP_PMTUDISC_PROBE:
2213 #endif
2214 #ifdef IP_PMTUDISC_INTERFACE
2215 case IP_PMTUDISC_INTERFACE:
2216 #endif
2217 #ifdef IP_PMTUDISC_OMIT
2218 case IP_PMTUDISC_OMIT:
2219 #endif
2221 * This happens if HAVE_IP_MTU_DISCOVER is set but the OS
2222 * doesn't actually understand it. The only OS that this is
2223 * known to happen on currently is Windows Subsystem for Linux
2224 * (newer versions have been fixed to recognize it). Just
2225 * pretend everything is fine.
2227 ret = 0;
2228 *werror = 0;
2229 break;
2230 default:
2231 break;
2234 #endif
2238 void
2239 ves_icall_System_Net_Sockets_Socket_Shutdown_internal (gsize sock, gint32 how, gint32 *werror, MonoError *error)
2241 int ret;
2243 error_init (error);
2244 *werror = 0;
2246 /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2247 ret = mono_w32socket_shutdown (sock, how);
2248 if (ret == SOCKET_ERROR)
2249 *werror = mono_w32socket_get_last_error ();
2252 gint
2253 ves_icall_System_Net_Sockets_Socket_IOControl_internal (gsize sock, gint32 code, MonoArrayHandle input, MonoArrayHandle output, gint32 *werror, MonoError *error)
2255 #ifdef HOST_WIN32
2256 DWORD output_bytes = 0;
2257 #else
2258 glong output_bytes = 0;
2259 #endif
2260 gchar *i_buffer, *o_buffer;
2261 gint i_len, o_len;
2262 uint32_t i_gchandle = 0;
2263 uint32_t o_gchandle = 0;
2264 gint ret;
2266 error_init (error);
2267 *werror = 0;
2269 if ((guint32)code == FIONBIO)
2270 /* Invalid command. Must use Socket.Blocking */
2271 return -1;
2273 if (MONO_HANDLE_IS_NULL (input)) {
2274 i_buffer = NULL;
2275 i_len = 0;
2276 i_gchandle = 0;
2277 } else {
2278 i_len = mono_array_handle_length (input);
2279 i_buffer = MONO_ARRAY_HANDLE_PIN (input, gchar, 0, &i_gchandle);
2282 if (MONO_HANDLE_IS_NULL (output)) {
2283 o_buffer = NULL;
2284 o_len = 0;
2285 o_gchandle = 0;
2286 } else {
2287 o_len = mono_array_handle_length (output);
2288 o_buffer = MONO_ARRAY_HANDLE_PIN (output, gchar, 0, &o_gchandle);
2291 ret = mono_w32socket_ioctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes);
2293 mono_gchandle_free_internal (i_gchandle);
2294 mono_gchandle_free_internal (o_gchandle);
2296 if (ret == SOCKET_ERROR) {
2297 *werror = mono_w32socket_get_last_error ();
2298 return -1;
2301 return (gint)output_bytes;
2304 static gboolean
2305 addrinfo_add_string (MonoDomain *domain, const char *s, MonoArrayHandle arr, int index, MonoError *error)
2307 HANDLE_FUNCTION_ENTER ();
2308 error_init (error);
2309 MonoStringHandle str = mono_string_new_handle (domain, s, error);
2310 goto_if_nok (error, leave);
2311 MONO_HANDLE_ARRAY_SETREF (arr, index, str);
2312 leave:
2313 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2317 static int
2318 addrinfo_add_local_ips (MonoDomain *domain, MonoArrayHandleOut h_addr_list, MonoError *error)
2320 HANDLE_FUNCTION_ENTER ();
2321 struct in_addr *local_in = NULL;
2322 int nlocal_in = 0;
2323 struct in6_addr *local_in6 = NULL;
2324 int nlocal_in6 = 0;
2325 int addr_index = 0;
2327 error_init (error);
2328 local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2329 local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2330 if (nlocal_in || nlocal_in6) {
2331 char addr [INET6_ADDRSTRLEN];
2332 MONO_HANDLE_ASSIGN (h_addr_list, mono_array_new_handle (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error));
2333 goto_if_nok (error, leave);
2335 if (nlocal_in) {
2336 int i;
2338 for (i = 0; i < nlocal_in; i++) {
2339 MonoAddress maddr;
2340 mono_address_init (&maddr, AF_INET, &local_in [i]);
2341 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2342 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2343 goto leave;
2344 addr_index++;
2348 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2349 if (nlocal_in6) {
2350 int i;
2352 for (i = 0; i < nlocal_in6; i++) {
2353 MonoAddress maddr;
2354 mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2355 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2356 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2357 goto leave;
2358 addr_index++;
2362 #endif
2365 leave:
2366 g_free (local_in);
2367 g_free (local_in6);
2368 HANDLE_FUNCTION_RETURN_VAL (addr_index);
2371 static gboolean
2372 addrinfo_to_IPHostEntry_handles (MonoAddressInfo *info, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gboolean add_local_ips, MonoError *error)
2374 HANDLE_FUNCTION_ENTER ();
2375 MonoAddressEntry *ai = NULL;
2376 MonoDomain *domain = mono_domain_get ();
2378 error_init (error);
2379 MONO_HANDLE_ASSIGN (h_aliases, mono_array_new_handle (domain, mono_get_string_class (), 0, error));
2380 goto_if_nok (error, leave);
2381 if (add_local_ips) {
2382 int addr_index = addrinfo_add_local_ips (domain, h_addr_list, error);
2383 goto_if_nok (error, leave);
2384 if (addr_index > 0)
2385 goto leave;
2388 gint32 count;
2389 count = 0;
2390 for (ai = info->entries; ai != NULL; ai = ai->next) {
2391 if (ai->family != AF_INET && ai->family != AF_INET6)
2392 continue;
2393 count++;
2396 int addr_index;
2397 addr_index = 0;
2398 MONO_HANDLE_ASSIGN (h_addr_list, mono_array_new_handle (domain, mono_get_string_class (), count, error));
2399 goto_if_nok (error, leave);
2401 gboolean name_assigned;
2402 name_assigned = FALSE;
2403 for (ai = info->entries; ai != NULL; ai = ai->next) {
2404 MonoAddress maddr;
2405 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2407 if ((ai->family != PF_INET) && (ai->family != PF_INET6))
2408 continue;
2410 mono_address_init (&maddr, ai->family, &ai->address);
2411 const char *addr = NULL;
2412 if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
2413 addr = buffer;
2414 else
2415 addr = "";
2416 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2417 goto leave;
2419 if (!name_assigned) {
2420 name_assigned = TRUE;
2421 const char *name = ai->canonical_name != NULL ? ai->canonical_name : buffer;
2422 MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (domain, name, error));
2423 goto_if_nok (error, leave);
2426 addr_index++;
2429 leave:
2430 if (info)
2431 mono_free_address_info (info);
2433 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2436 MonoBoolean
2437 ves_icall_System_Net_Dns_GetHostByName_internal (MonoStringHandle host, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2439 gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2440 gchar this_hostname [256];
2441 MonoAddressInfo *info = NULL;
2443 error_init (error);
2445 char *hostname = mono_string_handle_to_utf8 (host, error);
2446 return_val_if_nok (error, FALSE);
2448 if (*hostname == '\0') {
2449 add_local_ips = TRUE;
2450 MONO_HANDLE_ASSIGN (h_name, host);
2453 if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2454 if (!strcmp (hostname, this_hostname)) {
2455 add_local_ips = TRUE;
2456 MONO_HANDLE_ASSIGN (h_name, host);
2460 #ifdef HOST_WIN32
2461 // Win32 APIs already returns local interface addresses for empty hostname ("")
2462 // so we never want to add them manually.
2463 add_local_ips = FALSE;
2464 if (mono_get_address_info(hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2465 add_info_ok = FALSE;
2466 #else
2467 if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2468 add_info_ok = FALSE;
2469 #endif
2471 g_free(hostname);
2473 if (add_info_ok) {
2474 MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, add_local_ips, error);
2475 return result;
2477 return FALSE;
2480 MonoBoolean
2481 ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoStringHandle addr, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2483 char *address;
2484 struct sockaddr_in saddr;
2485 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2486 struct sockaddr_in6 saddr6;
2487 #endif
2488 MonoAddressInfo *info = NULL;
2489 gint32 family;
2490 gchar hostname [NI_MAXHOST] = { 0 };
2491 gboolean ret;
2493 error_init (error);
2495 address = mono_string_handle_to_utf8 (addr, error);
2496 return_val_if_nok (error, FALSE);
2498 if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2499 family = AF_INET;
2500 saddr.sin_family = AF_INET;
2502 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2503 else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2504 family = AF_INET6;
2505 saddr6.sin6_family = AF_INET6;
2507 #endif
2508 else {
2509 g_free (address);
2510 return FALSE;
2513 g_free (address);
2515 switch (family) {
2516 case AF_INET: {
2517 #if HAVE_SOCKADDR_IN_SIN_LEN
2518 saddr.sin_len = sizeof (saddr);
2519 #endif
2520 MONO_ENTER_GC_SAFE;
2521 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2522 MONO_EXIT_GC_SAFE;
2523 break;
2525 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2526 case AF_INET6: {
2527 #if HAVE_SOCKADDR_IN6_SIN_LEN
2528 saddr6.sin6_len = sizeof (saddr6);
2529 #endif
2530 MONO_ENTER_GC_SAFE;
2531 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2532 MONO_EXIT_GC_SAFE;
2533 break;
2535 #endif
2536 default:
2537 g_assert_not_reached ();
2540 if (!ret)
2541 return FALSE;
2543 if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2544 return FALSE;
2546 MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, FALSE, error);
2547 return result;
2550 MonoBoolean
2551 ves_icall_System_Net_Dns_GetHostName_internal (MonoStringHandleOut h_name, MonoError *error)
2553 gchar hostname [NI_MAXHOST] = { 0 };
2554 int ret;
2556 error_init (error);
2557 MONO_ENTER_GC_SAFE;
2558 ret = gethostname (hostname, sizeof (hostname));
2559 MONO_EXIT_GC_SAFE;
2560 if (ret == -1)
2561 return FALSE;
2563 MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (mono_domain_get (), hostname, error));
2564 return TRUE;
2567 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
2568 MonoBoolean
2569 ves_icall_System_Net_Sockets_Socket_SendFile_internal (gsize sock, MonoStringHandle filename, MonoArrayHandle pre_buffer, MonoArrayHandle post_buffer, gint flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
2571 HANDLE file;
2572 gboolean ret;
2573 TRANSMIT_FILE_BUFFERS buffers;
2574 uint32_t pre_buffer_gchandle = 0;
2575 uint32_t post_buffer_gchandle = 0;
2577 error_init (error);
2578 *werror = 0;
2580 if (MONO_HANDLE_IS_NULL (filename))
2581 return FALSE;
2583 /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2585 uint32_t filename_gchandle;
2586 gunichar2 *filename_chars = mono_string_handle_pin_chars (filename, &filename_gchandle);
2587 file = mono_w32file_create (filename_chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0);
2588 mono_gchandle_free_internal (filename_gchandle);
2589 if (file == INVALID_HANDLE_VALUE) {
2590 *werror = mono_w32error_get_last ();
2591 return FALSE;
2594 memset (&buffers, 0, sizeof (buffers));
2595 if (!MONO_HANDLE_IS_NULL (pre_buffer)) {
2596 buffers.Head = MONO_ARRAY_HANDLE_PIN (pre_buffer, guchar, 0, &pre_buffer_gchandle);
2597 buffers.HeadLength = mono_array_handle_length (pre_buffer);
2599 if (!MONO_HANDLE_IS_NULL (post_buffer)) {
2600 buffers.Tail = MONO_ARRAY_HANDLE_PIN (post_buffer, guchar, 0, &post_buffer_gchandle);
2601 buffers.TailLength = mono_array_handle_length (post_buffer);
2604 ret = mono_w32socket_transmit_file (sock, file, &buffers, flags, blocking);
2606 if (pre_buffer_gchandle)
2607 mono_gchandle_free_internal (pre_buffer_gchandle);
2608 if (post_buffer_gchandle)
2609 mono_gchandle_free_internal (post_buffer_gchandle);
2611 if (!ret)
2612 *werror = mono_w32socket_get_last_error ();
2614 mono_w32file_close (file);
2616 if (*werror)
2617 return FALSE;
2619 return ret;
2621 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
2623 void
2624 mono_network_init (void)
2626 mono_networking_init ();
2627 mono_w32socket_initialize ();
2630 void
2631 mono_network_cleanup (void)
2633 mono_w32socket_cleanup ();
2634 mono_networking_shutdown ();
2637 void
2638 ves_icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error)
2640 error_init (error);
2641 MonoInternalThreadHandle internal = MONO_HANDLE_NEW_GET (MonoInternalThread, thread, internal_thread);
2642 g_assert (!MONO_HANDLE_IS_NULL (internal));
2644 guint64 tid = mono_internal_thread_handle_ptr (internal)->tid;
2645 mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (tid));
2648 #endif /* #ifndef DISABLE_SOCKETS */