[merp] Remove dead code (#20043)
[mono-project.git] / mono / metadata / w32socket.c
blob477a25d43b10842e06982db44b098074c0340cf6
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 #include <mono/metadata/w32socket.h>
21 #if !defined(DISABLE_SOCKETS) && !defined(ENABLE_NETCORE)
23 #if defined(__APPLE__) || defined(__FreeBSD__)
24 #define __APPLE_USE_RFC_3542
25 #endif
27 #include <glib.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #ifdef HOST_WIN32
31 #include <ws2tcpip.h>
32 #else
33 #include <sys/socket.h>
34 #ifdef HAVE_SYS_IOCTL_H
35 #include <sys/ioctl.h>
36 #endif
37 #include <netinet/in.h>
38 #include <netinet/tcp.h>
39 #ifdef HAVE_NETDB_H
40 #include <netdb.h>
41 #endif
42 #ifdef HAVE_NETINET_TCP_H
43 #include <arpa/inet.h>
44 #endif
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <errno.h>
50 #include <mono/utils/mono-errno.h>
52 #include <sys/types.h>
54 #include <mono/metadata/object.h>
55 #include <mono/metadata/exception.h>
56 #include <mono/metadata/assembly-internals.h>
57 #include <mono/metadata/appdomain.h>
58 #include <mono/metadata/w32file.h>
59 #include <mono/metadata/threads.h>
60 #include <mono/metadata/threads-types.h>
61 #include <mono/metadata/threadpool-io.h>
62 #include <mono/utils/mono-poll.h>
63 /* FIXME change this code to not mess so much with the internals */
64 #include <mono/metadata/class-internals.h>
65 #include <mono/metadata/domain-internals.h>
66 #include <mono/metadata/image-internals.h>
67 #include <mono/utils/mono-threads.h>
68 #include <mono/utils/mono-memory-model.h>
69 #include <mono/utils/networking.h>
70 #include <mono/metadata/w32handle.h>
71 #include <mono/metadata/w32socket-internals.h>
72 #include <mono/metadata/w32error.h>
74 #include <time.h>
75 #ifdef HAVE_SYS_TIME_H
76 #include <sys/time.h>
77 #endif
78 #ifdef HAVE_SYS_IOCTL_H
79 #include <sys/ioctl.h>
80 #endif
81 #ifdef HAVE_NET_IF_H
82 #include <net/if.h>
83 #endif
85 #ifdef HAVE_NETDB_H
86 #include <netdb.h>
87 #endif
88 #ifdef HAVE_SYS_FILIO_H
89 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
90 #endif
91 #ifdef HAVE_SYS_SOCKIO_H
92 #include <sys/sockio.h> /* defines SIOCATMARK */
93 #endif
94 #ifdef HAVE_SYS_UN_H
95 #include <sys/un.h>
96 #endif
98 #ifdef HAVE_GETIFADDRS
99 // <net/if.h> must be included before <ifaddrs.h>
100 #include <ifaddrs.h>
101 #elif defined(HAVE_QP2GETIFADDRS)
102 /* Bizarrely, IBM i implements this, but AIX doesn't, so on i, it has a different name... */
103 #include <as400_types.h>
104 #include <as400_protos.h>
105 /* Defines to just reuse ifaddrs code */
106 #define ifaddrs ifaddrs_pase
107 #define freeifaddrs Qp2freeifaddrs
108 #define getifaddrs Qp2getifaddrs
109 #endif
111 #if defined(_MSC_VER) && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
112 #include <MSWSock.h>
113 #endif
114 #include "icall-decl.h"
116 #define LOGDEBUG(...)
117 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
119 static gboolean
120 addrinfo_to_IPHostEntry_handles (MonoAddressInfo *info, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gboolean add_local_ips, MonoError *error);
122 static MonoObjectHandle
123 create_object_handle_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error);
125 static struct sockaddr*
126 create_sockaddr_from_handle (MonoObjectHandle saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error);
128 #ifdef HOST_WIN32
130 static SOCKET
131 mono_w32socket_socket (int domain, int type, int protocol)
133 SOCKET ret;
134 MONO_ENTER_GC_SAFE;
135 ret = WSASocket (domain, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
136 MONO_EXIT_GC_SAFE;
137 return ret;
140 static gint
141 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
143 gint ret;
144 MONO_ENTER_GC_SAFE;
145 ret = bind (sock, addr, addrlen);
146 MONO_EXIT_GC_SAFE;
147 return ret;
150 static gint
151 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
153 gint ret;
154 MONO_ENTER_GC_SAFE;
155 ret = getpeername (sock, name, namelen);
156 MONO_EXIT_GC_SAFE;
157 return ret;
160 static gint
161 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
163 gint ret;
164 MONO_ENTER_GC_SAFE;
165 ret = getsockname (sock, name, namelen);
166 MONO_EXIT_GC_SAFE;
167 return ret;
170 static gint
171 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
173 gint ret;
174 MONO_ENTER_GC_SAFE;
175 ret = getsockopt (sock, level, optname, (char*)optval, optlen);
176 MONO_EXIT_GC_SAFE;
177 return ret;
180 static gint
181 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen)
183 gint ret;
184 MONO_ENTER_GC_SAFE;
185 ret = setsockopt (sock, level, optname, (const char*)optval, optlen);
186 MONO_EXIT_GC_SAFE;
187 return ret;
190 static gint
191 mono_w32socket_listen (SOCKET sock, gint backlog)
193 gint ret;
194 MONO_ENTER_GC_SAFE;
195 ret = listen (sock, backlog);
196 MONO_EXIT_GC_SAFE;
197 return ret;
200 static gint
201 mono_w32socket_shutdown (SOCKET sock, gint how)
203 gint ret;
204 MONO_ENTER_GC_SAFE;
205 ret = shutdown (sock, how);
206 MONO_EXIT_GC_SAFE;
207 return ret;
210 static gint
211 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, DWORD *written)
213 gint ret;
214 MONO_ENTER_GC_SAFE;
215 ret = WSAIoctl (sock, command, input, inputlen, output, outputlen, written, NULL, NULL);
216 MONO_EXIT_GC_SAFE;
217 return ret;
220 static gboolean
221 mono_w32socket_close (SOCKET sock)
223 gboolean ret;
224 MONO_ENTER_GC_SAFE;
225 ret = closesocket (sock);
226 MONO_EXIT_GC_SAFE;
227 return ret;
230 #endif /* HOST_WIN32 */
232 static gint32
233 convert_family (MonoAddressFamily mono_family)
235 switch (mono_family) {
236 case AddressFamily_Unknown:
237 case AddressFamily_ImpLink:
238 case AddressFamily_Pup:
239 case AddressFamily_Chaos:
240 case AddressFamily_Iso:
241 case AddressFamily_Ecma:
242 case AddressFamily_DataKit:
243 case AddressFamily_Ccitt:
244 case AddressFamily_DataLink:
245 case AddressFamily_Lat:
246 case AddressFamily_HyperChannel:
247 case AddressFamily_NetBios:
248 case AddressFamily_VoiceView:
249 case AddressFamily_FireFox:
250 case AddressFamily_Banyan:
251 case AddressFamily_Atm:
252 case AddressFamily_Cluster:
253 case AddressFamily_Ieee12844:
254 case AddressFamily_NetworkDesigners:
255 g_warning ("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
256 return -1;
257 case AddressFamily_Unspecified:
258 return AF_UNSPEC;
259 case AddressFamily_Unix:
260 return AF_UNIX;
261 case AddressFamily_InterNetwork:
262 return AF_INET;
263 case AddressFamily_AppleTalk:
264 #ifdef AF_APPLETALK
265 return AF_APPLETALK;
266 #else
267 return -1;
268 #endif
269 case AddressFamily_InterNetworkV6:
270 #ifdef HAVE_STRUCT_SOCKADDR_IN6
271 return AF_INET6;
272 #else
273 return -1;
274 #endif
275 case AddressFamily_DecNet:
276 #ifdef AF_DECnet
277 return AF_DECnet;
278 #else
279 return -1;
280 #endif
281 case AddressFamily_Ipx:
282 #ifdef AF_IPX
283 return AF_IPX;
284 #else
285 return -1;
286 #endif
287 case AddressFamily_Sna:
288 #ifdef AF_SNA
289 return AF_SNA;
290 #else
291 return -1;
292 #endif
293 case AddressFamily_Irda:
294 #ifdef AF_IRDA
295 return AF_IRDA;
296 #else
297 return -1;
298 #endif
299 default:
300 g_warning ("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
301 return -1;
305 static MonoAddressFamily
306 convert_to_mono_family (guint16 af_family)
308 switch (af_family) {
309 case AF_UNSPEC:
310 return AddressFamily_Unspecified;
311 case AF_UNIX:
312 return AddressFamily_Unix;
313 case AF_INET:
314 return AddressFamily_InterNetwork;
315 #ifdef AF_IPX
316 case AF_IPX:
317 return AddressFamily_Ipx;
318 #endif
319 #ifdef AF_SNA
320 case AF_SNA:
321 return AddressFamily_Sna;
322 #endif
323 #ifdef AF_DECnet
324 case AF_DECnet:
325 return AddressFamily_DecNet;
326 #endif
327 #ifdef AF_APPLETALK
328 case AF_APPLETALK:
329 return AddressFamily_AppleTalk;
330 #endif
331 #ifdef HAVE_STRUCT_SOCKADDR_IN6
332 case AF_INET6:
333 return AddressFamily_InterNetworkV6;
334 #endif
335 #ifdef AF_IRDA
336 case AF_IRDA:
337 return AddressFamily_Irda;
338 #endif
339 default:
340 g_warning ("unknown address family 0x%x", af_family);
341 return AddressFamily_Unknown;
345 static gint32
346 convert_type (MonoSocketType mono_type)
348 switch (mono_type) {
349 case SocketType_Stream:
350 return SOCK_STREAM;
351 case SocketType_Dgram:
352 return SOCK_DGRAM;
353 case SocketType_Raw:
354 return SOCK_RAW;
355 case SocketType_Rdm:
356 #ifdef SOCK_RDM
357 return SOCK_RDM;
358 #else
359 return -1;
360 #endif
361 case SocketType_Seqpacket:
362 #ifdef SOCK_SEQPACKET
363 return SOCK_SEQPACKET;
364 #else
365 return -1;
366 #endif
367 case SocketType_Unknown:
368 g_warning ("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
369 return -1;
370 default:
371 g_warning ("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
372 return -1;
376 static gint32
377 convert_proto (MonoProtocolType mono_proto)
379 switch (mono_proto) {
380 case ProtocolType_IP:
381 case ProtocolType_IPv6:
382 case ProtocolType_Icmp:
383 case ProtocolType_Igmp:
384 case ProtocolType_Ggp:
385 case ProtocolType_Tcp:
386 case ProtocolType_Pup:
387 case ProtocolType_Udp:
388 case ProtocolType_Idp:
389 /* These protocols are known (on my system at least) */
390 return mono_proto;
391 case ProtocolType_ND:
392 case ProtocolType_Raw:
393 case ProtocolType_Ipx:
394 case ProtocolType_Spx:
395 case ProtocolType_SpxII:
396 case ProtocolType_Unknown:
397 /* These protocols arent */
398 g_warning ("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
399 return -1;
400 default:
401 return -1;
405 /* Convert MonoSocketFlags */
406 static gint32
407 convert_socketflags (gint32 sflags)
409 gint32 flags = 0;
411 if (!sflags)
412 /* SocketFlags.None */
413 return 0;
415 if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek |
416 SocketFlags_DontRoute | SocketFlags_Partial))
417 /* Contains invalid flag values */
418 return -1;
420 #ifdef MSG_OOB
421 if (sflags & SocketFlags_OutOfBand)
422 flags |= MSG_OOB;
423 #endif
424 if (sflags & SocketFlags_Peek)
425 flags |= MSG_PEEK;
426 if (sflags & SocketFlags_DontRoute)
427 flags |= MSG_DONTROUTE;
429 /* Ignore Partial - see bug 349688. Don't return -1, because
430 * according to the comment in that bug ms runtime doesn't for
431 * UDP sockets (this means we will silently ignore it for TCP
432 * too)
434 #ifdef MSG_MORE
435 if (sflags & SocketFlags_Partial)
436 flags |= MSG_MORE;
437 #endif
438 #if 0
439 /* Don't do anything for MaxIOVectorLength */
440 if (sflags & SocketFlags_MaxIOVectorLength)
441 return -1;
442 #endif
443 return flags;
447 * Returns:
448 * 0 on success (mapped mono_level and mono_name to system_level and system_name
449 * -1 on error
450 * -2 on non-fatal error (ie, must ignore)
452 static gint32
453 convert_sockopt_level_and_name (MonoSocketOptionLevel mono_level, MonoSocketOptionName mono_name, int *system_level, int *system_name)
455 switch (mono_level) {
456 case SocketOptionLevel_Socket:
457 *system_level = SOL_SOCKET;
459 switch (mono_name) {
460 case SocketOptionName_DontLinger:
461 /* This is SO_LINGER, because the setsockopt
462 * internal call maps DontLinger to SO_LINGER
463 * with l_onoff=0
465 *system_name = SO_LINGER;
466 break;
467 #ifdef SO_DEBUG
468 case SocketOptionName_Debug:
469 *system_name = SO_DEBUG;
470 break;
471 #endif
472 #ifdef SO_ACCEPTCONN
473 case SocketOptionName_AcceptConnection:
474 *system_name = SO_ACCEPTCONN;
475 break;
476 #endif
477 case SocketOptionName_ReuseAddress:
478 *system_name = SO_REUSEADDR;
479 break;
480 case SocketOptionName_KeepAlive:
481 *system_name = SO_KEEPALIVE;
482 break;
483 #ifdef SO_DONTROUTE
484 case SocketOptionName_DontRoute:
485 *system_name = SO_DONTROUTE;
486 break;
487 #endif
488 case SocketOptionName_Broadcast:
489 *system_name = SO_BROADCAST;
490 break;
491 case SocketOptionName_Linger:
492 *system_name = SO_LINGER;
493 break;
494 #ifdef SO_OOBINLINE
495 case SocketOptionName_OutOfBandInline:
496 *system_name = SO_OOBINLINE;
497 break;
498 #endif
499 case SocketOptionName_SendBuffer:
500 *system_name = SO_SNDBUF;
501 break;
502 case SocketOptionName_ReceiveBuffer:
503 *system_name = SO_RCVBUF;
504 break;
505 case SocketOptionName_SendLowWater:
506 *system_name = SO_SNDLOWAT;
507 break;
508 case SocketOptionName_ReceiveLowWater:
509 *system_name = SO_RCVLOWAT;
510 break;
511 case SocketOptionName_SendTimeout:
512 *system_name = SO_SNDTIMEO;
513 break;
514 case SocketOptionName_ReceiveTimeout:
515 *system_name = SO_RCVTIMEO;
516 break;
517 case SocketOptionName_Error:
518 *system_name = SO_ERROR;
519 break;
520 case SocketOptionName_Type:
521 *system_name = SO_TYPE;
522 break;
523 #ifdef SO_PEERCRED
524 case SocketOptionName_PeerCred:
525 *system_name = SO_PEERCRED;
526 break;
527 #endif
528 case SocketOptionName_ExclusiveAddressUse:
529 #ifdef SO_EXCLUSIVEADDRUSE
530 *system_name = SO_EXCLUSIVEADDRUSE;
531 break;
532 #endif
533 case SocketOptionName_UseLoopback:
534 #ifdef SO_USELOOPBACK
535 *system_name = SO_USELOOPBACK;
536 break;
537 #endif
538 case SocketOptionName_MaxConnections:
539 #ifdef SO_MAXCONN
540 *system_name = SO_MAXCONN;
541 break;
542 #elif defined(SOMAXCONN)
543 *system_name = SOMAXCONN;
544 break;
545 #endif
546 default:
547 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
548 return -1;
550 break;
552 case SocketOptionLevel_IP:
553 *system_level = mono_networking_get_ip_protocol ();
555 switch (mono_name) {
556 #ifdef IP_OPTIONS
557 case SocketOptionName_IPOptions:
558 *system_name = IP_OPTIONS;
559 break;
560 #endif
561 #ifdef IP_HDRINCL
562 case SocketOptionName_HeaderIncluded:
563 *system_name = IP_HDRINCL;
564 break;
565 #endif
566 #ifdef IP_TOS
567 case SocketOptionName_TypeOfService:
568 *system_name = IP_TOS;
569 break;
570 #endif
571 #ifdef IP_TTL
572 case SocketOptionName_IpTimeToLive:
573 *system_name = IP_TTL;
574 break;
575 #endif
576 case SocketOptionName_MulticastInterface:
577 *system_name = IP_MULTICAST_IF;
578 break;
579 case SocketOptionName_MulticastTimeToLive:
580 *system_name = IP_MULTICAST_TTL;
581 break;
582 case SocketOptionName_MulticastLoopback:
583 *system_name = IP_MULTICAST_LOOP;
584 break;
585 case SocketOptionName_AddMembership:
586 *system_name = IP_ADD_MEMBERSHIP;
587 break;
588 case SocketOptionName_DropMembership:
589 *system_name = IP_DROP_MEMBERSHIP;
590 break;
591 #ifdef HAVE_IP_PKTINFO
592 case SocketOptionName_PacketInformation:
593 *system_name = IP_PKTINFO;
594 break;
595 #endif /* HAVE_IP_PKTINFO */
597 case SocketOptionName_DontFragment:
598 #ifdef HAVE_IP_DONTFRAGMENT
599 *system_name = IP_DONTFRAGMENT;
600 break;
601 #elif defined HAVE_IP_MTU_DISCOVER
602 /* Not quite the same */
603 *system_name = IP_MTU_DISCOVER;
604 break;
605 #else
606 /* If the flag is not available on this system, we can ignore this error */
607 return -2;
608 #endif /* HAVE_IP_DONTFRAGMENT */
609 case SocketOptionName_AddSourceMembership:
610 case SocketOptionName_DropSourceMembership:
611 case SocketOptionName_BlockSource:
612 case SocketOptionName_UnblockSource:
613 /* Can't figure out how to map these, so fall
614 * through
616 default:
617 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
618 return -1;
620 break;
622 case SocketOptionLevel_IPv6:
623 *system_level = mono_networking_get_ipv6_protocol ();
625 switch (mono_name) {
626 case SocketOptionName_IpTimeToLive:
627 case SocketOptionName_HopLimit:
628 *system_name = IPV6_UNICAST_HOPS;
629 break;
630 case SocketOptionName_MulticastInterface:
631 *system_name = IPV6_MULTICAST_IF;
632 break;
633 case SocketOptionName_MulticastTimeToLive:
634 *system_name = IPV6_MULTICAST_HOPS;
635 break;
636 case SocketOptionName_MulticastLoopback:
637 *system_name = IPV6_MULTICAST_LOOP;
638 break;
639 case SocketOptionName_AddMembership:
640 *system_name = IPV6_JOIN_GROUP;
641 break;
642 case SocketOptionName_DropMembership:
643 *system_name = IPV6_LEAVE_GROUP;
644 break;
645 case SocketOptionName_IPv6Only:
646 #ifdef IPV6_V6ONLY
647 *system_name = IPV6_V6ONLY;
648 #else
649 return -1;
650 #endif
651 break;
652 case SocketOptionName_PacketInformation:
653 #ifdef HAVE_IPV6_PKTINFO
654 *system_name = IPV6_PKTINFO;
655 #endif
656 break;
657 case SocketOptionName_HeaderIncluded:
658 case SocketOptionName_IPOptions:
659 case SocketOptionName_TypeOfService:
660 case SocketOptionName_DontFragment:
661 case SocketOptionName_AddSourceMembership:
662 case SocketOptionName_DropSourceMembership:
663 case SocketOptionName_BlockSource:
664 case SocketOptionName_UnblockSource:
665 /* Can't figure out how to map these, so fall
666 * through
668 default:
669 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
670 return -1;
672 break; /* SocketOptionLevel_IPv6 */
674 case SocketOptionLevel_Tcp:
675 *system_level = mono_networking_get_tcp_protocol ();
677 switch (mono_name) {
678 case SocketOptionName_NoDelay:
679 *system_name = TCP_NODELAY;
680 break;
681 #if 0
682 /* The documentation is talking complete
683 * bollocks here: rfc-1222 is titled
684 * 'Advancing the NSFNET Routing Architecture'
685 * and doesn't mention either of the words
686 * "expedite" or "urgent".
688 case SocketOptionName_BsdUrgent:
689 case SocketOptionName_Expedited:
690 #endif
691 default:
692 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
693 return -1;
695 break;
697 case SocketOptionLevel_Udp:
698 g_warning ("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
700 switch(mono_name) {
701 case SocketOptionName_NoChecksum:
702 case SocketOptionName_ChecksumCoverage:
703 default:
704 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
705 return -1;
707 return -1;
708 break;
710 default:
711 g_warning ("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
712 return -1;
715 return 0;
718 static MonoImage*
719 get_socket_assembly (void)
721 MonoDomain *domain = mono_domain_get ();
723 if (domain->socket_assembly == NULL) {
724 MonoImage *socket_assembly;
725 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
727 socket_assembly = mono_image_loaded_internal (alc, "System", FALSE);
728 if (!socket_assembly) {
729 MonoAssemblyOpenRequest req;
730 mono_assembly_request_prepare_open (&req, MONO_ASMCTX_DEFAULT, alc);
731 MonoAssembly *sa = mono_assembly_request_open ("System.dll", &req, NULL);
733 if (!sa) {
734 g_assert_not_reached ();
735 } else {
736 socket_assembly = mono_assembly_get_image_internal (sa);
739 mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
742 return domain->socket_assembly;
745 gpointer
746 ves_icall_System_Net_Sockets_Socket_Socket_icall (gint32 family, gint32 type, gint32 proto, gint32 *werror, MonoError *error)
748 SOCKET sock;
749 gint32 sock_family;
750 gint32 sock_proto;
751 gint32 sock_type;
753 error_init (error);
754 *werror = 0;
756 sock_family = convert_family ((MonoAddressFamily)family);
757 if (sock_family == -1) {
758 *werror = WSAEAFNOSUPPORT;
759 return NULL;
762 sock_proto = convert_proto ((MonoProtocolType)proto);
763 if (sock_proto == -1) {
764 *werror = WSAEPROTONOSUPPORT;
765 return NULL;
768 sock_type = convert_type ((MonoSocketType)type);
769 if (sock_type == -1) {
770 *werror = WSAESOCKTNOSUPPORT;
771 return NULL;
774 sock = mono_w32socket_socket (sock_family, sock_type, sock_proto);
776 if (sock == INVALID_SOCKET) {
777 *werror = mono_w32socket_get_last_error ();
778 return NULL;
781 return GUINT_TO_POINTER (sock);
784 /* FIXME: the SOCKET parameter (here and in other functions in this
785 * file) is really an IntPtr which needs to be converted to a guint32.
787 void
788 ves_icall_System_Net_Sockets_Socket_Close_icall (gsize sock, gint32 *werror)
790 LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
792 *werror = 0;
794 /* Clear any pending work item from this socket if the underlying
795 * polling system does not notify when the socket is closed */
796 mono_threadpool_io_remove_socket (GPOINTER_TO_INT (sock));
798 mono_w32socket_close ((SOCKET) sock);
801 gint32
802 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_icall (void)
804 LOGDEBUG (g_message("%s: returning %d", __func__, mono_w32socket_get_last_error ()));
806 return mono_w32socket_get_last_error ();
809 gint32
810 ves_icall_System_Net_Sockets_Socket_Available_icall (gsize sock, gint32 *werror)
812 int ret;
813 guint64 amount;
815 *werror = 0;
817 /* FIXME: this might require amount to be unsigned long. */
818 ret = mono_w32socket_get_available (sock, &amount);
819 if (ret == SOCKET_ERROR) {
820 *werror = mono_w32socket_get_last_error ();
821 return 0;
824 return amount;
827 void
828 ves_icall_System_Net_Sockets_Socket_Blocking_icall (gsize sock, MonoBoolean block, gint32 *werror)
830 int ret;
832 *werror = 0;
834 ret = mono_w32socket_set_blocking (sock, block);
835 if (ret == SOCKET_ERROR)
836 *werror = mono_w32socket_get_last_error ();
839 gpointer
840 ves_icall_System_Net_Sockets_Socket_Accept_icall (gsize sock, gint32 *werror, MonoBoolean blocking)
842 SOCKET newsock;
844 *werror = 0;
846 newsock = mono_w32socket_accept (sock, NULL, 0, blocking);
847 if (newsock == INVALID_SOCKET) {
848 *werror = mono_w32socket_get_last_error ();
849 return NULL;
852 return GUINT_TO_POINTER (newsock);
855 void
856 ves_icall_System_Net_Sockets_Socket_Listen_icall (gsize sock, guint32 backlog, gint32 *werror)
858 int ret;
860 *werror = 0;
862 ret = mono_w32socket_listen (sock, backlog);
863 if (ret == SOCKET_ERROR)
864 *werror = mono_w32socket_get_last_error ();
867 #ifdef HAVE_STRUCT_SOCKADDR_IN6
868 // Check whether it's ::ffff::0:0.
869 static gboolean
870 is_ipv4_mapped_any (const struct in6_addr *addr)
872 int i;
874 for (i = 0; i < 10; i++) {
875 if (addr->s6_addr [i])
876 return FALSE;
878 if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
879 return FALSE;
880 for (i = 12; i < 16; i++) {
881 if (addr->s6_addr [i])
882 return FALSE;
884 return TRUE;
886 #endif
888 static MonoObjectHandle
889 create_object_handle_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error)
891 MonoDomain *domain = mono_domain_get ();
892 MonoAddressFamily family;
894 error_init (error);
896 /* Build a System.Net.SocketAddress object instance */
897 if (!domain->sockaddr_class)
898 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
899 MonoObjectHandle sockaddr_obj = mono_object_new_handle (domain, domain->sockaddr_class, error);
900 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
902 /* Locate the SocketAddress data buffer in the object */
903 if (!domain->sockaddr_data_field) {
904 domain->sockaddr_data_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Buffer", NULL);
905 g_assert (domain->sockaddr_data_field);
908 /* Locate the SocketAddress data buffer length in the object */
909 if (!domain->sockaddr_data_length_field) {
910 domain->sockaddr_data_length_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Size", NULL);
911 g_assert (domain->sockaddr_data_length_field);
914 /* May be the +2 here is too conservative, as sa_len returns
915 * the length of the entire sockaddr_in/in6, including
916 * sizeof (unsigned short) of the family */
917 /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
918 MonoArrayHandle data = mono_array_new_handle (domain, mono_get_byte_class (), sa_size + 2, error);
919 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
921 /* The data buffer is laid out as follows:
922 * bytes 0 and 1 are the address family
923 * bytes 2 and 3 are the port info
924 * the rest is the address info
927 family = convert_to_mono_family (saddr->sa_family);
928 if (family == AddressFamily_Unknown) {
929 *werror = WSAEAFNOSUPPORT;
930 return MONO_HANDLE_NEW (MonoObject, NULL);
933 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 0, family & 0x0FF);
934 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 1, (family >> 8) & 0x0FF);
936 if (saddr->sa_family == AF_INET) {
937 struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr;
938 guint16 port = ntohs (sa_in->sin_port);
939 guint32 address = ntohl (sa_in->sin_addr.s_addr);
940 int buffer_size = 8;
942 if (sa_size < buffer_size) {
943 mono_error_set_generic_error (error, "System", "SystemException", "");
944 return MONO_HANDLE_NEW (MonoObject, NULL);
947 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 2, (port>>8) & 0xff);
948 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 3, (port) & 0xff);
949 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 4, (address>>24) & 0xff);
950 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 5, (address>>16) & 0xff);
951 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 6, (address>>8) & 0xff);
952 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 7, (address) & 0xff);
954 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 */
955 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 */
957 return sockaddr_obj;
959 #ifdef HAVE_STRUCT_SOCKADDR_IN6
960 else if (saddr->sa_family == AF_INET6) {
961 struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)saddr;
962 int i;
963 int buffer_size = 28;
965 guint16 port = ntohs (sa_in->sin6_port);
967 if (sa_size < buffer_size) {
968 mono_error_set_generic_error (error, "System", "SystemException", "");
969 return MONO_HANDLE_NEW (MonoObject, NULL);
972 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 2, (port>>8) & 0xff);
973 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 3, (port) & 0xff);
975 if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
976 // Map ::ffff:0:0 to :: (bug #5502)
977 for (i = 0; i < 16; i++)
978 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 8 + i, 0);
979 } else {
980 for (i = 0; i < 16; i++) {
981 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 8 + i,
982 sa_in->sin6_addr.s6_addr [i]);
986 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 24, sa_in->sin6_scope_id & 0xff);
987 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 25,
988 (sa_in->sin6_scope_id >> 8) & 0xff);
989 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 26,
990 (sa_in->sin6_scope_id >> 16) & 0xff);
991 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 27,
992 (sa_in->sin6_scope_id >> 24) & 0xff);
994 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 */
995 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 */
997 return sockaddr_obj;
999 #endif
1000 #ifdef HAVE_SYS_UN_H
1001 else if (saddr->sa_family == AF_UNIX) {
1002 int i;
1003 int buffer_size = sa_size + 2;
1005 for (i = 0; i < sa_size; i++)
1006 MONO_HANDLE_ARRAY_SETVAL (data, guint8, i + 2, saddr->sa_data [i]);
1008 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 */
1009 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 */
1011 return sockaddr_obj;
1013 #endif
1014 else {
1015 *werror = WSAEAFNOSUPPORT;
1016 return MONO_HANDLE_NEW (MonoObject, NULL);
1020 static int
1021 get_sockaddr_size (int family)
1023 int size;
1025 size = 0;
1026 if (family == AF_INET) {
1027 size = sizeof (struct sockaddr_in);
1029 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1030 else if (family == AF_INET6) {
1031 size = sizeof (struct sockaddr_in6);
1033 #endif
1034 #ifdef HAVE_SYS_UN_H
1035 else if (family == AF_UNIX) {
1036 size = sizeof (struct sockaddr_un);
1038 #endif
1039 return size;
1042 static MonoObjectHandle
1043 mono_w32socket_getname (gsize sock, gint32 af, gboolean local, gint32 *werror, MonoError *error)
1045 gpointer sa = NULL;
1046 socklen_t salen = 0;
1047 int ret;
1048 MonoObjectHandle result = NULL_HANDLE;
1050 *werror = 0;
1052 salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
1053 if (salen == 0) {
1054 *werror = WSAEAFNOSUPPORT;
1055 goto exit;
1057 if (salen <= 128) {
1058 sa = g_alloca (salen);
1059 memset (sa, 0, salen);
1060 } else {
1061 sa = g_malloc0 (salen);
1064 /* Note: linux returns just 2 for AF_UNIX. Always. */
1065 ret = (local ? mono_w32socket_getsockname : mono_w32socket_getpeername) (sock, (struct sockaddr *)sa, &salen);
1066 if (ret == SOCKET_ERROR) {
1067 *werror = mono_w32socket_get_last_error ();
1068 goto exit;
1071 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)));
1073 result = create_object_handle_from_sockaddr ((struct sockaddr *)sa, salen, werror, error);
1074 exit:
1075 if (salen > 128)
1076 g_free (sa);
1077 return result;
1080 MonoObjectHandle
1081 ves_icall_System_Net_Sockets_Socket_LocalEndPoint_icall (gsize sock, gint32 af, gint32 *werror, MonoError *error)
1083 return mono_w32socket_getname (sock, af, TRUE, werror, error);
1086 MonoObjectHandle
1087 ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_icall (gsize sock, gint32 af, gint32 *werror, MonoError *error)
1089 return mono_w32socket_getname (sock, af, FALSE, werror, error);
1092 static struct sockaddr*
1093 create_sockaddr_from_handle (MonoObjectHandle saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
1095 MonoDomain *domain = mono_domain_get ();
1096 gint32 family;
1097 int len;
1099 error_init (error);
1101 if (!domain->sockaddr_class)
1102 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
1104 /* Locate the SocketAddress data buffer in the object */
1105 if (!domain->sockaddr_data_field) {
1106 domain->sockaddr_data_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Buffer", NULL);
1107 g_assert (domain->sockaddr_data_field);
1110 /* Locate the SocketAddress data buffer length in the object */
1111 if (!domain->sockaddr_data_length_field) {
1112 domain->sockaddr_data_length_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Size", NULL);
1113 g_assert (domain->sockaddr_data_length_field);
1116 MonoArrayHandle data = MONO_HANDLE_NEW_GET_FIELD (saddr_obj, MonoArray, domain->sockaddr_data_field);
1118 /* The data buffer is laid out as follows:
1119 * byte 0 is the address family low byte
1120 * byte 1 is the address family high byte
1121 * INET:
1122 * bytes 2 and 3 are the port info
1123 * the rest is the address info
1124 * UNIX:
1125 * the rest is the file name
1127 len = MONO_HANDLE_GET_FIELD_VAL (saddr_obj, int, domain->sockaddr_data_length_field);
1128 g_assert (len >= 2);
1130 uint32_t gchandle;
1131 guint8 *buf = MONO_ARRAY_HANDLE_PIN (data, guint8, 0, &gchandle);
1132 family = convert_family ((MonoAddressFamily)(buf[0] + (buf[1] << 8)));
1133 if (family == AF_INET) {
1134 struct sockaddr_in *sa;
1135 guint16 port;
1136 guint32 address;
1138 if (len < 8) {
1139 mono_error_set_generic_error (error, "System", "SystemException", "");
1140 mono_gchandle_free_internal (gchandle);
1141 return NULL;
1144 sa = g_new0 (struct sockaddr_in, 1);
1145 port = (buf[2] << 8) + buf[3];
1146 address = (buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7];
1148 sa->sin_family = family;
1149 sa->sin_addr.s_addr = htonl (address);
1150 sa->sin_port = htons (port);
1152 *sa_size = sizeof (struct sockaddr_in);
1153 mono_gchandle_free_internal (gchandle);
1154 return (struct sockaddr *)sa;
1156 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1157 else if (family == AF_INET6) {
1158 struct sockaddr_in6 *sa;
1159 int i;
1160 guint16 port;
1161 guint32 scopeid;
1163 if (len < 28) {
1164 mono_error_set_generic_error (error, "System", "SystemException", "");
1165 mono_gchandle_free_internal (gchandle);
1166 return NULL;
1169 sa = g_new0 (struct sockaddr_in6, 1);
1170 port = buf[3] + (buf[2] << 8);
1171 scopeid = buf[24] + (buf[25] << 8) + (buf[26] << 16) + (buf[27] << 24);
1173 sa->sin6_family = family;
1174 sa->sin6_port = htons (port);
1175 sa->sin6_scope_id = scopeid;
1177 for (i = 0; i < 16; i++)
1178 sa->sin6_addr.s6_addr [i] = buf[8 + i];
1180 *sa_size = sizeof (struct sockaddr_in6);
1181 mono_gchandle_free_internal (gchandle);
1182 return (struct sockaddr *)sa;
1184 #endif
1185 #ifdef HAVE_SYS_UN_H
1186 else if (family == AF_UNIX) {
1187 struct sockaddr_un *sock_un;
1188 int i;
1190 /* Need a byte for the '\0' terminator/prefix, and the first
1191 * two bytes hold the SocketAddress family
1193 if (len - 2 >= sizeof (sock_un->sun_path)) {
1194 mono_error_set_argument_out_of_range (error, "SocketAddress.Size", "MonoArgumentException:SocketAddress.Size");
1195 mono_gchandle_free_internal (gchandle);
1196 return NULL;
1199 sock_un = g_new0 (struct sockaddr_un, 1);
1201 sock_un->sun_family = family;
1202 for (i = 0; i < len - 2; i++)
1203 sock_un->sun_path [i] = buf[i + 2];
1205 *sa_size = len;
1206 mono_gchandle_free_internal (gchandle);
1207 return (struct sockaddr *)sock_un;
1209 #endif
1210 else {
1211 *werror = WSAEAFNOSUPPORT;
1212 mono_gchandle_free_internal (gchandle);
1213 return 0;
1217 void
1218 ves_icall_System_Net_Sockets_Socket_Bind_icall (gsize sock, MonoObjectHandle sockaddr, gint32 *werror, MonoError *error)
1220 struct sockaddr *sa;
1221 socklen_t sa_size;
1222 int ret;
1224 error_init (error);
1225 *werror = 0;
1227 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1228 if (*werror != 0)
1229 return;
1230 return_if_nok (error);
1232 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)));
1234 ret = mono_w32socket_bind (sock, sa, sa_size);
1236 if (ret == SOCKET_ERROR)
1237 *werror = mono_w32socket_get_last_error ();
1239 g_free (sa);
1242 enum {
1243 SelectModeRead,
1244 SelectModeWrite,
1245 SelectModeError
1248 MonoBoolean
1249 ves_icall_System_Net_Sockets_Socket_Poll_icall (gsize sock, gint mode, gint timeout, gint32 *werror)
1251 MonoInternalThread *thread = mono_thread_internal_current ();
1252 mono_pollfd *pfds;
1253 int ret;
1254 time_t start;
1255 gint rtimeout;
1257 *werror = 0;
1259 pfds = g_new0 (mono_pollfd, 1);
1260 pfds->fd = GPOINTER_TO_INT (sock);
1262 switch (mode) {
1263 case SelectModeRead:
1264 pfds->events = MONO_POLLIN;
1265 break;
1266 case SelectModeWrite:
1267 pfds->events = MONO_POLLOUT;
1268 break;
1269 default:
1270 pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL;
1271 break;
1274 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1275 rtimeout = timeout;
1276 start = time (NULL);
1278 do {
1279 MONO_ENTER_GC_SAFE;
1281 ret = mono_poll (pfds, 1, timeout);
1283 MONO_EXIT_GC_SAFE;
1285 if (timeout > 0 && ret < 0) {
1286 int err = errno;
1287 int sec = time (NULL) - start;
1289 timeout = rtimeout - sec * 1000;
1290 if (timeout < 0) {
1291 timeout = 0;
1294 mono_set_errno (err);
1297 if (ret == -1 && errno == EINTR) {
1298 if (mono_thread_test_state (thread, ThreadState_AbortRequested)) {
1299 g_free (pfds);
1300 return FALSE;
1303 /* Suspend requested? */
1304 mono_thread_interruption_checkpoint_void ();
1306 mono_set_errno (EINTR);
1308 } while (ret == -1 && errno == EINTR);
1310 if (ret == -1) {
1311 *werror = mono_w32socket_convert_error (errno);
1312 g_free (pfds);
1313 return FALSE;
1316 g_free (pfds);
1317 return ret != 0;
1320 void
1321 ves_icall_System_Net_Sockets_Socket_Connect_icall (gsize sock, MonoObjectHandle sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1323 struct sockaddr *sa;
1324 socklen_t sa_size;
1325 int ret;
1327 error_init (error);
1328 *werror = 0;
1330 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1331 if (*werror != 0)
1332 return;
1333 return_if_nok (error);
1335 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)));
1337 ret = mono_w32socket_connect (sock, sa, sa_size, blocking);
1338 if (ret == SOCKET_ERROR)
1339 *werror = mono_w32socket_get_last_error ();
1341 g_free (sa);
1344 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
1346 void
1347 ves_icall_System_Net_Sockets_Socket_Disconnect_icall (gsize sock, MonoBoolean reuse, gint32 *werror)
1349 LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
1351 *werror = mono_w32socket_disconnect (sock, reuse);
1354 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
1356 MonoBoolean
1357 ves_icall_System_Net_Sockets_Socket_Duplicate_icall (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle, gint32 *werror)
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_icall (gsize sock, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking)
1371 int ret;
1372 int recvflags = 0;
1374 *werror = 0;
1376 recvflags = convert_socketflags (flags);
1377 if (recvflags == -1) {
1378 *werror = WSAEOPNOTSUPP;
1379 return 0;
1382 ret = mono_w32socket_recv (sock, buffer, count, recvflags, blocking);
1383 if (ret == SOCKET_ERROR) {
1384 *werror = mono_w32socket_get_last_error ();
1385 return 0;
1388 return ret;
1391 gint32
1392 ves_icall_System_Net_Sockets_Socket_Receive_array_icall (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking)
1394 int ret;
1395 guint32 recv;
1396 guint32 recvflags = 0;
1398 *werror = 0;
1400 recvflags = convert_socketflags (flags);
1401 if (recvflags == -1) {
1402 *werror = WSAEOPNOTSUPP;
1403 return 0;
1406 ret = mono_w32socket_recvbuffers (sock, buffers, count, &recv, &recvflags, NULL, NULL, blocking);
1407 if (ret == SOCKET_ERROR) {
1408 *werror = mono_w32socket_get_last_error ();
1409 return 0;
1412 return recv;
1415 gint32
1416 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_icall (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandleInOut sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1418 int ret;
1419 int recvflags = 0;
1420 struct sockaddr *sa;
1421 socklen_t sa_size;
1423 error_init (error);
1424 *werror = 0;
1426 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1427 if (*werror != 0)
1428 return 0;
1429 if (!is_ok (error))
1430 return 0;
1432 recvflags = convert_socketflags (flags);
1433 if (recvflags == -1) {
1434 *werror = WSAEOPNOTSUPP;
1435 return 0;
1438 ret = mono_w32socket_recvfrom (sock, buffer, count, recvflags, sa, &sa_size, blocking);
1439 if (ret == SOCKET_ERROR) {
1440 *werror = mono_w32socket_get_last_error ();
1441 g_free(sa);
1442 return 0;
1445 /* If we didn't get a socket size, then we're probably a
1446 * connected connection-oriented socket and the stack hasn't
1447 * returned the remote address. All we can do is return null.
1449 if (sa_size) {
1450 MONO_HANDLE_ASSIGN (sockaddr, create_object_handle_from_sockaddr (sa, sa_size, werror, error));
1451 if (!is_ok (error)) {
1452 g_free (sa);
1453 return 0;
1455 } else {
1456 MONO_HANDLE_ASSIGN (sockaddr, MONO_HANDLE_NEW (MonoObject, NULL));
1459 g_free (sa);
1461 return ret;
1464 gint32
1465 ves_icall_System_Net_Sockets_Socket_Send_icall (gsize sock, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking)
1467 int ret;
1468 int sendflags = 0;
1470 *werror = 0;
1472 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1474 sendflags = convert_socketflags (flags);
1475 if (sendflags == -1) {
1476 *werror = WSAEOPNOTSUPP;
1477 return 0;
1480 ret = mono_w32socket_send (sock, buffer, count, sendflags, blocking);
1481 if (ret == SOCKET_ERROR) {
1482 *werror = mono_w32socket_get_last_error ();
1483 return 0;
1486 return ret;
1489 gint32
1490 ves_icall_System_Net_Sockets_Socket_Send_array_icall (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking)
1492 int ret;
1493 guint32 sent;
1494 guint32 sendflags = 0;
1496 *werror = 0;
1498 sendflags = convert_socketflags (flags);
1499 if (sendflags == -1) {
1500 *werror = WSAEOPNOTSUPP;
1501 return 0;
1504 ret = mono_w32socket_sendbuffers (sock, buffers, count, &sent, sendflags, NULL, NULL, blocking);
1505 if (ret == SOCKET_ERROR) {
1506 *werror = mono_w32socket_get_last_error ();
1507 return 0;
1510 return sent;
1513 gint32
1514 ves_icall_System_Net_Sockets_Socket_SendTo_icall (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandle sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1516 int ret;
1517 int sendflags = 0;
1518 struct sockaddr *sa;
1519 socklen_t sa_size;
1521 *werror = 0;
1523 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1524 if (*werror != 0 || !is_ok (error))
1525 return 0;
1527 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1529 sendflags = convert_socketflags (flags);
1530 if (sendflags == -1) {
1531 *werror = WSAEOPNOTSUPP;
1532 g_free (sa);
1533 return 0;
1536 ret = mono_w32socket_sendto (sock, buffer, count, sendflags, sa, sa_size, blocking);
1537 if (ret == SOCKET_ERROR) {
1538 *werror = mono_w32socket_get_last_error ();
1539 g_free(sa);
1540 return 0;
1543 g_free(sa);
1544 return ret;
1547 static SOCKET
1548 Socket_to_SOCKET (MonoObjectHandle sockobj)
1550 MonoClassField *field;
1552 field = mono_class_get_field_from_name_full (mono_handle_class (sockobj), "m_Handle", NULL);
1553 MonoSafeHandleHandle safe_handle = MONO_HANDLE_NEW_GET_FIELD(sockobj, MonoSafeHandle, field);
1555 if (MONO_HANDLE_IS_NULL (safe_handle))
1556 return -1;
1558 return (SOCKET)(gsize)MONO_HANDLE_GETVAL (safe_handle, handle);
1561 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1563 static gboolean
1564 collect_pollfds_from_array (MonoArrayHandle sockets, int i, int nfds, mono_pollfd *pfds, int *idx, int *mode)
1566 HANDLE_FUNCTION_ENTER ();
1567 gboolean result = TRUE;
1568 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1569 MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1570 if (MONO_HANDLE_IS_NULL (obj)) {
1571 (*mode)++;
1572 goto leave;
1575 if (*idx >= nfds) {
1576 result = FALSE;
1577 goto leave;
1580 pfds [*idx].fd = Socket_to_SOCKET (obj);
1581 pfds [*idx].events = (*mode == 0) ? MONO_POLLIN : (*mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1582 (*idx)++;
1583 leave:
1584 HANDLE_FUNCTION_RETURN_VAL (result);
1587 static void
1588 set_socks_array_from_pollfds (MonoArrayHandle sockets, int i, mono_pollfd *pfds, int *ret, int *mode, MonoArrayHandle socks, int *idx)
1590 HANDLE_FUNCTION_ENTER ();
1591 mono_pollfd *pfd;
1593 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1594 MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1595 if (MONO_HANDLE_IS_NULL (obj)) {
1596 (*mode)++;
1597 (*idx)++;
1598 goto leave;
1601 pfd = &pfds [i - *mode];
1602 if (pfd->revents == 0)
1603 goto leave;
1605 (*ret)--;
1606 if (((*mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0)) ||
1607 ((*mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0)) ||
1608 ((pfd->revents & POLL_ERRORS) != 0)) {
1609 MONO_HANDLE_ARRAY_SETREF (socks, *idx, obj);
1610 (*idx)++;
1612 leave:
1613 HANDLE_FUNCTION_RETURN ();
1616 void
1617 ves_icall_System_Net_Sockets_Socket_Select_icall (MonoArrayHandleOut sockets, gint32 timeout, gint32 *werror, MonoError *error)
1619 MonoInternalThread *thread = mono_thread_internal_current ();
1620 mono_pollfd *pfds;
1621 int nfds, idx;
1622 int ret;
1623 int i, count;
1624 int mode;
1625 MonoClass *sock_arr_class;
1626 time_t start;
1627 uintptr_t socks_size;
1628 gint32 rtimeout;
1630 error_init (error);
1631 *werror = 0;
1633 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1634 count = mono_array_handle_length (sockets);
1635 nfds = count - 3; /* NULL separators */
1636 pfds = g_new0 (mono_pollfd, nfds);
1637 mode = idx = 0;
1638 for (i = 0; i < count; i++) {
1639 if (!collect_pollfds_from_array (sockets, i, nfds, pfds, &idx, &mode)) {
1640 /* The socket array was bogus */
1641 g_free (pfds);
1642 *werror = WSAEFAULT;
1643 return;
1647 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1648 rtimeout = timeout;
1649 start = time (NULL);
1650 do {
1651 MONO_ENTER_GC_SAFE;
1653 ret = mono_poll (pfds, nfds, timeout);
1655 MONO_EXIT_GC_SAFE;
1657 if (timeout > 0 && ret < 0) {
1658 int err = errno;
1659 int sec = time (NULL) - start;
1661 timeout = rtimeout - sec * 1000;
1662 if (timeout < 0)
1663 timeout = 0;
1664 mono_set_errno (err);
1667 if (ret == -1 && errno == EINTR) {
1668 if (mono_thread_test_state (thread, ThreadState_AbortRequested)) {
1669 g_free (pfds);
1670 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1671 return;
1674 /* Suspend requested? */
1675 mono_thread_interruption_checkpoint_void ();
1677 mono_set_errno (EINTR);
1679 } while (ret == -1 && errno == EINTR);
1681 if (ret == -1) {
1682 *werror = mono_w32socket_convert_error (errno);
1683 g_free (pfds);
1684 return;
1687 if (ret == 0) {
1688 g_free (pfds);
1689 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1690 return;
1693 sock_arr_class = mono_handle_class (sockets);
1694 socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1695 MonoArrayHandle socks = MONO_HANDLE_NEW (MonoArray, mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, error));
1696 if (!is_ok (error)) {
1697 g_free (pfds);
1698 return;
1701 mode = idx = 0;
1702 for (i = 0; i < count && ret > 0; i++) {
1703 set_socks_array_from_pollfds (sockets, i, pfds, &ret, &mode, socks, &idx);
1706 MONO_HANDLE_ASSIGN (sockets, socks);
1707 g_free (pfds);
1710 static MonoObjectHandle
1711 int_to_object_handle (MonoDomain *domain, int val, MonoError *error)
1713 return MONO_HANDLE_NEW (MonoObject, mono_value_box_checked (domain, mono_get_int32_class (), &val, error));
1716 void
1717 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_icall (gsize sock, gint32 level, gint32 name, MonoObjectHandleOut obj_val, gint32 *werror, MonoError *error)
1719 int system_level = 0;
1720 int system_name = 0;
1721 int ret;
1722 int val = 0;
1723 socklen_t valsize = sizeof (val);
1724 struct linger linger;
1725 socklen_t lingersize = sizeof (linger);
1726 int time_ms = 0;
1727 socklen_t time_ms_size = sizeof (time_ms);
1728 #ifdef SO_PEERCRED
1729 # if defined(__OpenBSD__)
1730 struct sockpeercred cred;
1731 # else
1732 struct ucred cred;
1733 # endif
1734 socklen_t credsize = sizeof (cred);
1735 #endif
1736 MonoDomain *domain = mono_domain_get ();
1737 MonoClass *obj_class;
1738 MonoClassField *field;
1740 error_init (error);
1741 *werror = 0;
1743 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1744 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1745 system_level = SOL_SOCKET;
1746 system_name = SO_REUSEADDR;
1747 ret = 0;
1748 } else
1749 #endif
1751 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1754 if (ret == -1) {
1755 *werror = WSAENOPROTOOPT;
1756 return;
1758 if (ret == -2) {
1759 MONO_HANDLE_ASSIGN (obj_val, int_to_object_handle (domain, 0, error));
1760 return;
1763 /* No need to deal with MulticastOption names here, because
1764 * you cant getsockopt AddMembership or DropMembership (the
1765 * int getsockopt will error, causing an exception)
1767 switch (name) {
1768 case SocketOptionName_Linger:
1769 case SocketOptionName_DontLinger:
1770 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &linger, &lingersize);
1771 break;
1773 case SocketOptionName_SendTimeout:
1774 case SocketOptionName_ReceiveTimeout:
1775 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &time_ms, &time_ms_size);
1776 break;
1778 #ifdef SO_PEERCRED
1779 case SocketOptionName_PeerCred:
1780 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &cred, &credsize);
1781 break;
1782 #endif
1784 default:
1785 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &val, &valsize);
1788 if (ret == SOCKET_ERROR) {
1789 *werror = mono_w32socket_get_last_error ();
1790 return;
1793 switch (name) {
1794 case SocketOptionName_Linger: {
1795 /* build a System.Net.Sockets.LingerOption */
1796 obj_class = mono_class_load_from_name (get_socket_assembly (),
1797 "System.Net.Sockets",
1798 "LingerOption");
1799 MonoObjectHandle obj = mono_object_new_handle (domain, obj_class, error);
1800 return_if_nok (error);
1802 /* Locate and set the fields "bool enabled" and "int
1803 * lingerTime"
1805 field = mono_class_get_field_from_name_full (obj_class, "enabled", NULL);
1806 MONO_HANDLE_SET_FIELD_VAL (obj, guint8, field, linger.l_onoff);
1808 field = mono_class_get_field_from_name_full (obj_class, "lingerTime", NULL);
1809 MONO_HANDLE_SET_FIELD_VAL (obj, guint32, field, linger.l_linger);
1811 MONO_HANDLE_ASSIGN (obj_val, obj);
1812 break;
1814 case SocketOptionName_DontLinger: {
1815 /* construct a bool int in val - true if linger is off */
1816 MonoObjectHandle obj = int_to_object_handle (domain, !linger.l_onoff, error);
1817 return_if_nok (error);
1819 MONO_HANDLE_ASSIGN (obj_val, obj);
1820 break;
1822 case SocketOptionName_SendTimeout:
1823 case SocketOptionName_ReceiveTimeout: {
1824 MonoObjectHandle obj = int_to_object_handle (domain, time_ms, error);
1825 return_if_nok (error);
1827 MONO_HANDLE_ASSIGN (obj_val, obj);
1828 break;
1831 #ifdef SO_PEERCRED
1832 case SocketOptionName_PeerCred: {
1834 * build a Mono.Posix.PeerCred+PeerCredData if
1835 * possible
1837 static MonoImage *mono_posix_image = NULL;
1839 if (mono_posix_image == NULL) {
1840 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
1841 mono_posix_image = mono_image_loaded_internal (alc, "Mono.Posix", FALSE);
1842 if (!mono_posix_image) {
1843 MonoAssemblyOpenRequest req;
1844 mono_assembly_request_prepare_open (&req, MONO_ASMCTX_DEFAULT, alc);
1845 MonoAssembly *sa = mono_assembly_request_open ("Mono.Posix.dll", &req, NULL);
1846 if (!sa) {
1847 *werror = WSAENOPROTOOPT;
1848 return;
1849 } else {
1850 mono_posix_image = mono_assembly_get_image_internal (sa);
1855 obj_class = mono_class_load_from_name (mono_posix_image,
1856 "Mono.Posix",
1857 "PeerCredData");
1858 MonoPeerCredDataHandle cred_data = MONO_HANDLE_CAST (MonoPeerCredData, mono_object_new_handle (domain, obj_class, error));
1859 return_if_nok (error);
1861 MONO_HANDLE_SETVAL (cred_data, pid, gint, cred.pid);
1862 MONO_HANDLE_SETVAL (cred_data, uid, gint, cred.uid);
1863 MONO_HANDLE_SETVAL (cred_data, gid, gint, cred.gid);
1865 MONO_HANDLE_ASSIGN (obj_val, cred_data);
1866 break;
1868 #endif
1870 default: {
1871 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1872 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
1873 val = val ? 0 : 1;
1874 #endif
1875 MonoObjectHandle obj = int_to_object_handle (domain, val, error);
1876 return_if_nok (error);
1878 MONO_HANDLE_ASSIGN (obj_val, obj);
1882 void
1883 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_icall (gsize sock, gint32 level, gint32 name, MonoArrayHandle byte_val, gint32 *werror, MonoError *error)
1885 int system_level = 0;
1886 int system_name = 0;
1887 int ret;
1888 socklen_t valsize;
1890 error_init (error);
1891 *werror = 0;
1893 ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
1894 &system_name);
1895 if (ret == -1) {
1896 *werror = WSAENOPROTOOPT;
1897 return;
1899 if (ret == -2)
1900 return;
1902 valsize = mono_array_handle_length (byte_val);
1904 uint32_t gchandle;
1905 guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
1907 ret = mono_w32socket_getsockopt (sock, system_level, system_name, buf, &valsize);
1909 mono_gchandle_free_internal (gchandle);
1911 if (ret == SOCKET_ERROR)
1912 *werror = mono_w32socket_get_last_error ();
1915 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1916 static struct in_addr
1917 ipaddress_handle_to_struct_in_addr (MonoObjectHandle ipaddr)
1919 struct in_addr inaddr;
1920 MonoClassField *field;
1922 field = mono_class_get_field_from_name_full (mono_handle_class (ipaddr), "_addressOrScopeId", NULL);
1923 g_assert (field);
1925 /* No idea why .net uses a 64bit type to hold a 32bit value...
1927 * Internal value of IPAddess is in little-endian order
1929 inaddr.s_addr = GUINT_FROM_LE ((guint32)MONO_HANDLE_GET_FIELD_VAL (ipaddr, guint32, field));
1931 return inaddr;
1934 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1935 static struct in6_addr
1936 ipaddress_handle_to_struct_in6_addr (MonoObjectHandle ipaddr)
1938 struct in6_addr in6addr;
1939 MonoClassField *field;
1940 int i;
1942 field = mono_class_get_field_from_name_full (mono_handle_class (ipaddr), "_numbers", NULL);
1943 g_assert (field);
1944 MonoArrayHandle data = MONO_HANDLE_NEW_GET_FIELD (ipaddr, MonoArray, field);
1946 for (i = 0; i < 8; i++) {
1947 guint16 v;
1948 MONO_HANDLE_ARRAY_GETVAL (v, data, guint16, i);
1949 const guint16 s = GUINT16_TO_BE (v);
1951 /* Solaris/MacOS have only the 8 bit version. */
1952 #ifndef s6_addr16
1953 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
1954 in6addr.s6_addr[2 * i] = s & 0xff;
1955 #else
1956 in6addr.s6_addr16[i] = s;
1957 #endif
1959 return in6addr;
1961 #endif
1962 #endif
1964 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1965 #if defined(__APPLE__) || defined(__FreeBSD__)
1966 static int
1967 get_local_interface_id (int family)
1969 #if !(defined(HAVE_GETIFADDRS) || defined(HAVE_QP2GETIFADDRS)) || !defined(HAVE_IF_NAMETOINDEX)
1970 return 0;
1971 #else
1972 struct ifaddrs *ifap = NULL, *ptr;
1973 int idx = 0;
1975 if (getifaddrs (&ifap))
1976 return 0;
1978 for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
1979 if (!ptr->ifa_addr || !ptr->ifa_name)
1980 continue;
1981 if (ptr->ifa_addr->sa_family != family)
1982 continue;
1983 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
1984 continue;
1985 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
1986 continue;
1988 idx = if_nametoindex (ptr->ifa_name);
1989 break;
1992 freeifaddrs (ifap);
1993 return idx;
1994 #endif
1996 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
1997 #endif /* HAVE_STRUCT_SOCKADDR_IN6 */
1999 void
2000 ves_icall_System_Net_Sockets_Socket_SetSocketOption_icall (gsize sock, gint32 level, gint32 name, MonoObjectHandle obj_val, MonoArrayHandle byte_val, gint32 int_val, gint32 *werror, MonoError *error)
2002 struct linger linger;
2003 int system_level = 0;
2004 int system_name = 0;
2005 int ret;
2006 int sol_ip;
2007 int sol_ipv6;
2009 error_init (error);
2010 *werror = 0;
2012 sol_ipv6 = mono_networking_get_ipv6_protocol ();
2013 sol_ip = mono_networking_get_ip_protocol ();
2015 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2016 &system_name);
2018 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2019 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2020 system_name = SO_REUSEADDR;
2021 int_val = int_val ? 0 : 1;
2022 ret = 0;
2024 #endif
2026 if (ret == -1) {
2027 *werror = WSAENOPROTOOPT;
2028 return;
2030 if (ret == -2)
2031 return;
2033 /* Only one of obj_val, byte_val or int_val has data */
2034 if (!MONO_HANDLE_IS_NULL (obj_val)) {
2035 MonoClass *obj_class = mono_handle_class (obj_val);
2036 MonoClassField *field;
2037 int valsize;
2039 switch (name) {
2040 case SocketOptionName_Linger:
2041 /* Dig out "bool enabled" and "int lingerTime"
2042 * fields
2044 field = mono_class_get_field_from_name_full (obj_class, "enabled", NULL);
2045 linger.l_onoff = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint8, field);
2046 field = mono_class_get_field_from_name_full (obj_class, "lingerTime", NULL);
2047 linger.l_linger = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint32, field);
2049 valsize = sizeof (linger);
2050 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, valsize);
2051 break;
2052 case SocketOptionName_AddMembership:
2053 case SocketOptionName_DropMembership:
2054 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2056 MonoObjectHandle address = MONO_HANDLE_NEW (MonoObject, NULL);
2057 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2058 if (system_level == sol_ipv6) {
2059 struct ipv6_mreq mreq6;
2062 * Get group address
2064 field = mono_class_get_field_from_name_full (obj_class, "m_Group", NULL);
2065 g_assert (field);
2066 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2068 if (!MONO_HANDLE_IS_NULL (address))
2069 mreq6.ipv6mr_multiaddr = ipaddress_handle_to_struct_in6_addr (address);
2071 field = mono_class_get_field_from_name_full (obj_class, "m_Interface", NULL);
2072 mreq6.ipv6mr_interface = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint64, field);
2074 #if defined(__APPLE__) || defined(__FreeBSD__)
2076 * Bug #5504:
2078 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2080 * Tests on Windows and Linux show that the multicast group is only
2081 * joined on one NIC when interface = 0, so we simply use the interface
2082 * id from the first non-loopback interface (this is also what
2083 * Dns.GetHostName (string.Empty) would return).
2085 if (!mreq6.ipv6mr_interface)
2086 mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2087 #endif
2089 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq6, sizeof (mreq6));
2091 break; // Don't check sol_ip
2093 #endif
2094 if (system_level == sol_ip) {
2095 #ifdef HAVE_STRUCT_IP_MREQN
2096 struct ip_mreqn mreq = {{0}};
2097 #else
2098 struct ip_mreq mreq = {{0}};
2099 #endif /* HAVE_STRUCT_IP_MREQN */
2102 * pain! MulticastOption holds two IPAddress
2103 * members, so I have to dig the value out of
2104 * those :-(
2106 field = mono_class_get_field_from_name_full (obj_class, "group", NULL);
2107 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2109 /* address might not be defined and if so, set the address to ADDR_ANY.
2111 if (!MONO_HANDLE_IS_NULL (address))
2112 mreq.imr_multiaddr = ipaddress_handle_to_struct_in_addr (address);
2114 field = mono_class_get_field_from_name_full (obj_class, "localAddress", NULL);
2115 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2117 #ifdef HAVE_STRUCT_IP_MREQN
2118 if (!MONO_HANDLE_IS_NULL (address))
2119 mreq.imr_address = ipaddress_handle_to_struct_in_addr (address);
2121 field = mono_class_get_field_from_name_full (obj_class, "ifIndex", NULL);
2122 mreq.imr_ifindex = MONO_HANDLE_GET_FIELD_VAL (obj_val, gint32, field);
2123 #else
2124 if (!MONO_HANDLE_IS_NULL (address))
2125 mreq.imr_interface = ipaddress_handle_to_struct_in_addr (address);
2126 #endif /* HAVE_STRUCT_IP_MREQN */
2128 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
2130 break;
2132 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2133 default:
2134 /* Cause an exception to be thrown */
2135 *werror = WSAEINVAL;
2136 return;
2138 } else if (!MONO_HANDLE_IS_NULL (byte_val)) {
2139 int valsize = mono_array_handle_length (byte_val);
2140 uint32_t gchandle;
2141 guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
2143 switch(name) {
2144 case SocketOptionName_DontLinger:
2145 if (valsize == 1) {
2146 linger.l_onoff = (*buf) ? 0 : 1;
2147 linger.l_linger = 0;
2148 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2149 } else {
2150 *werror = WSAEINVAL;
2152 break;
2153 default:
2154 ret = mono_w32socket_setsockopt (sock, system_level, system_name, buf, valsize);
2155 break;
2157 mono_gchandle_free_internal (gchandle);
2158 } else {
2159 /* ReceiveTimeout/SendTimeout get here */
2160 switch (name) {
2161 case SocketOptionName_DontLinger:
2162 linger.l_onoff = !int_val;
2163 linger.l_linger = 0;
2164 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2165 break;
2166 case SocketOptionName_MulticastInterface:
2167 #ifndef HOST_WIN32
2168 #ifdef HAVE_STRUCT_IP_MREQN
2169 int_val = GUINT32_FROM_BE (int_val);
2170 if ((int_val & 0xff000000) == 0) {
2171 /* int_val is interface index */
2172 struct ip_mreqn mreq = {{0}};
2173 mreq.imr_ifindex = int_val;
2174 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
2175 break;
2177 int_val = GUINT32_TO_BE (int_val);
2178 #endif /* HAVE_STRUCT_IP_MREQN */
2179 #endif /* HOST_WIN32 */
2180 /* int_val is in_addr */
2181 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &int_val, sizeof (int_val));
2182 break;
2183 case SocketOptionName_DontFragment:
2184 #ifdef HAVE_IP_MTU_DISCOVER
2185 /* Fiddle with the value slightly if we're
2186 * turning DF on
2188 if (int_val == 1)
2189 int_val = IP_PMTUDISC_DO;
2190 /* Fall through */
2191 #endif
2193 default:
2194 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &int_val, sizeof (int_val));
2198 if (ret == SOCKET_ERROR) {
2199 *werror = mono_w32socket_get_last_error ();
2201 #ifdef HAVE_IP_MTU_DISCOVER
2202 if (system_name == IP_MTU_DISCOVER) {
2203 switch (system_level) {
2204 case IP_PMTUDISC_DONT:
2205 case IP_PMTUDISC_WANT:
2206 case IP_PMTUDISC_DO:
2207 #ifdef IP_PMTUDISC_PROBE
2208 case IP_PMTUDISC_PROBE:
2209 #endif
2210 #ifdef IP_PMTUDISC_INTERFACE
2211 case IP_PMTUDISC_INTERFACE:
2212 #endif
2213 #ifdef IP_PMTUDISC_OMIT
2214 case IP_PMTUDISC_OMIT:
2215 #endif
2217 * This happens if HAVE_IP_MTU_DISCOVER is set but the OS
2218 * doesn't actually understand it. The only OS that this is
2219 * known to happen on currently is Windows Subsystem for Linux
2220 * (newer versions have been fixed to recognize it). Just
2221 * pretend everything is fine.
2223 ret = 0;
2224 *werror = 0;
2225 break;
2226 default:
2227 break;
2230 #endif
2234 void
2235 ves_icall_System_Net_Sockets_Socket_Shutdown_icall (gsize sock, gint32 how, gint32 *werror)
2237 int ret;
2239 *werror = 0;
2241 /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2242 ret = mono_w32socket_shutdown (sock, how);
2243 if (ret == SOCKET_ERROR)
2244 *werror = mono_w32socket_get_last_error ();
2247 gint
2248 ves_icall_System_Net_Sockets_Socket_IOControl_icall (gsize sock, gint32 code, MonoArrayHandle input, MonoArrayHandle output, gint32 *werror, MonoError *error)
2250 #ifdef HOST_WIN32
2251 DWORD output_bytes = 0;
2252 #else
2253 glong output_bytes = 0;
2254 #endif
2255 gchar *i_buffer, *o_buffer;
2256 gint i_len, o_len;
2257 uint32_t i_gchandle = 0;
2258 uint32_t o_gchandle = 0;
2259 gint ret;
2261 error_init (error);
2262 *werror = 0;
2264 if ((guint32)code == FIONBIO)
2265 /* Invalid command. Must use Socket.Blocking */
2266 return -1;
2268 if (MONO_HANDLE_IS_NULL (input)) {
2269 i_buffer = NULL;
2270 i_len = 0;
2271 i_gchandle = 0;
2272 } else {
2273 i_len = mono_array_handle_length (input);
2274 i_buffer = MONO_ARRAY_HANDLE_PIN (input, gchar, 0, &i_gchandle);
2277 if (MONO_HANDLE_IS_NULL (output)) {
2278 o_buffer = NULL;
2279 o_len = 0;
2280 o_gchandle = 0;
2281 } else {
2282 o_len = mono_array_handle_length (output);
2283 o_buffer = MONO_ARRAY_HANDLE_PIN (output, gchar, 0, &o_gchandle);
2286 ret = mono_w32socket_ioctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes);
2288 mono_gchandle_free_internal (i_gchandle);
2289 mono_gchandle_free_internal (o_gchandle);
2291 if (ret == SOCKET_ERROR) {
2292 *werror = mono_w32socket_get_last_error ();
2293 return -1;
2296 return (gint)output_bytes;
2299 static gboolean
2300 addrinfo_add_string (MonoDomain *domain, const char *s, MonoArrayHandle arr, int index, MonoError *error)
2302 HANDLE_FUNCTION_ENTER ();
2303 error_init (error);
2304 MonoStringHandle str = mono_string_new_handle (domain, s, error);
2305 goto_if_nok (error, leave);
2306 MONO_HANDLE_ARRAY_SETREF (arr, index, str);
2307 leave:
2308 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2312 static int
2313 addrinfo_add_local_ips (MonoDomain *domain, MonoArrayHandleOut h_addr_list, MonoError *error)
2315 HANDLE_FUNCTION_ENTER ();
2316 struct in_addr *local_in = NULL;
2317 int nlocal_in = 0;
2318 struct in6_addr *local_in6 = NULL;
2319 int nlocal_in6 = 0;
2320 int addr_index = 0;
2322 error_init (error);
2323 local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2324 local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2325 if (nlocal_in || nlocal_in6) {
2326 char addr [INET6_ADDRSTRLEN];
2327 MONO_HANDLE_ASSIGN (h_addr_list, mono_array_new_handle (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error));
2328 goto_if_nok (error, leave);
2330 if (nlocal_in) {
2331 int i;
2333 for (i = 0; i < nlocal_in; i++) {
2334 MonoAddress maddr;
2335 mono_address_init (&maddr, AF_INET, &local_in [i]);
2336 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2337 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2338 goto leave;
2339 addr_index++;
2343 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2344 if (nlocal_in6) {
2345 int i;
2347 for (i = 0; i < nlocal_in6; i++) {
2348 MonoAddress maddr;
2349 mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2350 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2351 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2352 goto leave;
2353 addr_index++;
2357 #endif
2360 leave:
2361 g_free (local_in);
2362 g_free (local_in6);
2363 HANDLE_FUNCTION_RETURN_VAL (addr_index);
2366 static gboolean
2367 addrinfo_to_IPHostEntry_handles (MonoAddressInfo *info, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gboolean add_local_ips, MonoError *error)
2369 HANDLE_FUNCTION_ENTER ();
2370 MonoAddressEntry *ai = NULL;
2371 MonoDomain *domain = mono_domain_get ();
2373 error_init (error);
2374 MONO_HANDLE_ASSIGN (h_aliases, mono_array_new_handle (domain, mono_get_string_class (), 0, error));
2375 goto_if_nok (error, leave);
2376 if (add_local_ips) {
2377 int addr_index = addrinfo_add_local_ips (domain, h_addr_list, error);
2378 goto_if_nok (error, leave);
2379 if (addr_index > 0)
2380 goto leave;
2383 gint32 count;
2384 count = 0;
2385 for (ai = info->entries; ai != NULL; ai = ai->next) {
2386 if (ai->family != AF_INET && ai->family != AF_INET6)
2387 continue;
2388 count++;
2391 int addr_index;
2392 addr_index = 0;
2393 MONO_HANDLE_ASSIGN (h_addr_list, mono_array_new_handle (domain, mono_get_string_class (), count, error));
2394 goto_if_nok (error, leave);
2396 gboolean name_assigned;
2397 name_assigned = FALSE;
2398 for (ai = info->entries; ai != NULL; ai = ai->next) {
2399 MonoAddress maddr;
2400 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2402 if ((ai->family != PF_INET) && (ai->family != PF_INET6))
2403 continue;
2405 mono_address_init (&maddr, ai->family, &ai->address);
2406 const char *addr = NULL;
2407 if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
2408 addr = buffer;
2409 else
2410 addr = "";
2411 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2412 goto leave;
2414 if (!name_assigned) {
2415 name_assigned = TRUE;
2416 const char *name = ai->canonical_name != NULL ? ai->canonical_name : buffer;
2417 MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (domain, name, error));
2418 goto_if_nok (error, leave);
2421 addr_index++;
2424 leave:
2425 if (info)
2426 mono_free_address_info (info);
2428 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2431 MonoBoolean
2432 ves_icall_System_Net_Dns_GetHostByName (MonoStringHandle host, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2434 gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2435 gchar this_hostname [256];
2436 MonoAddressInfo *info = NULL;
2438 error_init (error);
2440 char *hostname = mono_string_handle_to_utf8 (host, error);
2441 return_val_if_nok (error, FALSE);
2443 if (*hostname == '\0') {
2444 add_local_ips = TRUE;
2445 MONO_HANDLE_ASSIGN (h_name, host);
2448 if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2449 if (!strcmp (hostname, this_hostname)) {
2450 add_local_ips = TRUE;
2451 MONO_HANDLE_ASSIGN (h_name, host);
2455 #ifdef HOST_WIN32
2456 // Win32 APIs already returns local interface addresses for empty hostname ("")
2457 // so we never want to add them manually.
2458 add_local_ips = FALSE;
2459 if (mono_get_address_info(hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2460 add_info_ok = FALSE;
2461 #else
2462 if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2463 add_info_ok = FALSE;
2464 #endif
2466 g_free(hostname);
2468 if (add_info_ok) {
2469 MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, add_local_ips, error);
2470 return result;
2472 return FALSE;
2475 MonoBoolean
2476 ves_icall_System_Net_Dns_GetHostByAddr (MonoStringHandle addr, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2478 char *address;
2479 struct sockaddr_in saddr;
2480 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2481 struct sockaddr_in6 saddr6;
2482 #endif
2483 MonoAddressInfo *info = NULL;
2484 gint32 family;
2485 gchar hostname [NI_MAXHOST] = { 0 };
2486 gboolean ret;
2488 error_init (error);
2490 address = mono_string_handle_to_utf8 (addr, error);
2491 return_val_if_nok (error, FALSE);
2493 if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2494 family = AF_INET;
2495 saddr.sin_family = AF_INET;
2497 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2498 else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2499 family = AF_INET6;
2500 saddr6.sin6_family = AF_INET6;
2502 #endif
2503 else {
2504 g_free (address);
2505 return FALSE;
2508 g_free (address);
2510 switch (family) {
2511 case AF_INET: {
2512 #if HAVE_SOCKADDR_IN_SIN_LEN
2513 saddr.sin_len = sizeof (saddr);
2514 #endif
2515 MONO_ENTER_GC_SAFE;
2516 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2517 MONO_EXIT_GC_SAFE;
2518 break;
2520 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2521 case AF_INET6: {
2522 #if HAVE_SOCKADDR_IN6_SIN_LEN
2523 saddr6.sin6_len = sizeof (saddr6);
2524 #endif
2525 MONO_ENTER_GC_SAFE;
2526 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2527 MONO_EXIT_GC_SAFE;
2528 break;
2530 #endif
2531 default:
2532 g_assert_not_reached ();
2535 if (!ret)
2536 return FALSE;
2538 if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2539 return FALSE;
2541 MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, FALSE, error);
2542 return result;
2545 MonoBoolean
2546 ves_icall_System_Net_Dns_GetHostName (MonoStringHandleOut h_name, MonoError *error)
2548 gchar hostname [NI_MAXHOST] = { 0 };
2549 int ret;
2551 error_init (error);
2552 MONO_ENTER_GC_SAFE;
2553 ret = gethostname (hostname, sizeof (hostname));
2554 MONO_EXIT_GC_SAFE;
2555 if (ret == -1)
2556 return FALSE;
2558 MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (mono_domain_get (), hostname, error));
2559 return TRUE;
2562 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
2564 MonoBoolean
2565 ves_icall_System_Net_Sockets_Socket_SendFile_icall (gsize sock, MonoStringHandle filename, MonoArrayHandle pre_buffer, MonoArrayHandle post_buffer, gint flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
2567 HANDLE file;
2568 gboolean ret;
2569 TRANSMIT_FILE_BUFFERS buffers;
2570 uint32_t pre_buffer_gchandle = 0;
2571 uint32_t post_buffer_gchandle = 0;
2573 error_init (error);
2574 *werror = 0;
2576 if (MONO_HANDLE_IS_NULL (filename))
2577 return FALSE;
2579 /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2581 uint32_t filename_gchandle;
2582 gunichar2 *filename_chars = mono_string_handle_pin_chars (filename, &filename_gchandle);
2583 file = mono_w32file_create (filename_chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0);
2584 mono_gchandle_free_internal (filename_gchandle);
2585 if (file == INVALID_HANDLE_VALUE) {
2586 *werror = mono_w32error_get_last ();
2587 return FALSE;
2590 memset (&buffers, 0, sizeof (buffers));
2591 if (!MONO_HANDLE_IS_NULL (pre_buffer)) {
2592 buffers.Head = MONO_ARRAY_HANDLE_PIN (pre_buffer, guchar, 0, &pre_buffer_gchandle);
2593 buffers.HeadLength = mono_array_handle_length (pre_buffer);
2595 if (!MONO_HANDLE_IS_NULL (post_buffer)) {
2596 buffers.Tail = MONO_ARRAY_HANDLE_PIN (post_buffer, guchar, 0, &post_buffer_gchandle);
2597 buffers.TailLength = mono_array_handle_length (post_buffer);
2600 ret = mono_w32socket_transmit_file (sock, file, &buffers, flags, blocking);
2602 if (pre_buffer_gchandle)
2603 mono_gchandle_free_internal (pre_buffer_gchandle);
2604 if (post_buffer_gchandle)
2605 mono_gchandle_free_internal (post_buffer_gchandle);
2607 if (!ret)
2608 *werror = mono_w32socket_get_last_error ();
2610 mono_w32file_close (file);
2612 if (*werror)
2613 return FALSE;
2615 return ret;
2618 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
2620 void
2621 mono_network_init (void)
2623 mono_networking_init ();
2624 mono_w32socket_initialize ();
2627 void
2628 mono_network_cleanup (void)
2630 mono_w32socket_cleanup ();
2631 mono_networking_shutdown ();
2634 void
2635 ves_icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error)
2637 error_init (error);
2638 MonoInternalThreadHandle internal = MONO_HANDLE_NEW_GET (MonoInternalThread, thread, internal_thread);
2639 g_assert (!MONO_HANDLE_IS_NULL (internal));
2641 guint64 tid = mono_internal_thread_handle_ptr (internal)->tid;
2642 mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (tid));
2645 #else
2647 void
2648 mono_network_init (void)
2652 void
2653 mono_network_cleanup (void)
2657 #endif // !defined(DISABLE_SOCKETS) && !defined(ENABLE_NETCORE)