Misc AIX/PASE tweaks (#15651)
[mono-project.git] / mono / metadata / w32socket.c
blob16e6f4fb1ce6abf067d40ccb9258c5b05168397b
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 #elif defined(HAVE_QP2GETIFADDRS)
101 /* Bizarrely, IBM i implements this, but AIX doesn't, so on i, it has a different name... */
102 #include <as400_types.h>
103 #include <as400_protos.h>
104 /* Defines to just reuse ifaddrs code */
105 #define ifaddrs ifaddrs_pase
106 #define freeifaddrs Qp2freeifaddrs
107 #define getifaddrs Qp2getifaddrs
108 #endif
110 #if defined(_MSC_VER) && G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
111 #include <MSWSock.h>
112 #endif
113 #include "icall-decl.h"
115 #define LOGDEBUG(...)
116 /* define LOGDEBUG(...) g_message(__VA_ARGS__) */
118 static gboolean
119 addrinfo_to_IPHostEntry_handles (MonoAddressInfo *info, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gboolean add_local_ips, MonoError *error);
121 static MonoObjectHandle
122 create_object_handle_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error);
124 static struct sockaddr*
125 create_sockaddr_from_handle (MonoObjectHandle saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error);
127 #ifdef HOST_WIN32
129 static SOCKET
130 mono_w32socket_socket (int domain, int type, int protocol)
132 SOCKET ret;
133 MONO_ENTER_GC_SAFE;
134 ret = WSASocket (domain, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED);
135 MONO_EXIT_GC_SAFE;
136 return ret;
139 static gint
140 mono_w32socket_bind (SOCKET sock, struct sockaddr *addr, socklen_t addrlen)
142 gint ret;
143 MONO_ENTER_GC_SAFE;
144 ret = bind (sock, addr, addrlen);
145 MONO_EXIT_GC_SAFE;
146 return ret;
149 static gint
150 mono_w32socket_getpeername (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
152 gint ret;
153 MONO_ENTER_GC_SAFE;
154 ret = getpeername (sock, name, namelen);
155 MONO_EXIT_GC_SAFE;
156 return ret;
159 static gint
160 mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen)
162 gint ret;
163 MONO_ENTER_GC_SAFE;
164 ret = getsockname (sock, name, namelen);
165 MONO_EXIT_GC_SAFE;
166 return ret;
169 static gint
170 mono_w32socket_getsockopt (SOCKET sock, gint level, gint optname, gpointer optval, socklen_t *optlen)
172 gint ret;
173 MONO_ENTER_GC_SAFE;
174 ret = getsockopt (sock, level, optname, (char*)optval, optlen);
175 MONO_EXIT_GC_SAFE;
176 return ret;
179 static gint
180 mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, gconstpointer optval, socklen_t optlen)
182 gint ret;
183 MONO_ENTER_GC_SAFE;
184 ret = setsockopt (sock, level, optname, (const char*)optval, optlen);
185 MONO_EXIT_GC_SAFE;
186 return ret;
189 static gint
190 mono_w32socket_listen (SOCKET sock, gint backlog)
192 gint ret;
193 MONO_ENTER_GC_SAFE;
194 ret = listen (sock, backlog);
195 MONO_EXIT_GC_SAFE;
196 return ret;
199 static gint
200 mono_w32socket_shutdown (SOCKET sock, gint how)
202 gint ret;
203 MONO_ENTER_GC_SAFE;
204 ret = shutdown (sock, how);
205 MONO_EXIT_GC_SAFE;
206 return ret;
209 static gint
210 mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, DWORD *written)
212 gint ret;
213 MONO_ENTER_GC_SAFE;
214 ret = WSAIoctl (sock, command, input, inputlen, output, outputlen, written, NULL, NULL);
215 MONO_EXIT_GC_SAFE;
216 return ret;
219 static gboolean
220 mono_w32socket_close (SOCKET sock)
222 gboolean ret;
223 MONO_ENTER_GC_SAFE;
224 ret = closesocket (sock);
225 MONO_EXIT_GC_SAFE;
226 return ret;
229 #endif /* HOST_WIN32 */
231 static gint32
232 convert_family (MonoAddressFamily mono_family)
234 switch (mono_family) {
235 case AddressFamily_Unknown:
236 case AddressFamily_ImpLink:
237 case AddressFamily_Pup:
238 case AddressFamily_Chaos:
239 case AddressFamily_Iso:
240 case AddressFamily_Ecma:
241 case AddressFamily_DataKit:
242 case AddressFamily_Ccitt:
243 case AddressFamily_DataLink:
244 case AddressFamily_Lat:
245 case AddressFamily_HyperChannel:
246 case AddressFamily_NetBios:
247 case AddressFamily_VoiceView:
248 case AddressFamily_FireFox:
249 case AddressFamily_Banyan:
250 case AddressFamily_Atm:
251 case AddressFamily_Cluster:
252 case AddressFamily_Ieee12844:
253 case AddressFamily_NetworkDesigners:
254 g_warning ("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
255 return -1;
256 case AddressFamily_Unspecified:
257 return AF_UNSPEC;
258 case AddressFamily_Unix:
259 return AF_UNIX;
260 case AddressFamily_InterNetwork:
261 return AF_INET;
262 case AddressFamily_AppleTalk:
263 #ifdef AF_APPLETALK
264 return AF_APPLETALK;
265 #else
266 return -1;
267 #endif
268 case AddressFamily_InterNetworkV6:
269 #ifdef HAVE_STRUCT_SOCKADDR_IN6
270 return AF_INET6;
271 #else
272 return -1;
273 #endif
274 case AddressFamily_DecNet:
275 #ifdef AF_DECnet
276 return AF_DECnet;
277 #else
278 return -1;
279 #endif
280 case AddressFamily_Ipx:
281 #ifdef AF_IPX
282 return AF_IPX;
283 #else
284 return -1;
285 #endif
286 case AddressFamily_Sna:
287 #ifdef AF_SNA
288 return AF_SNA;
289 #else
290 return -1;
291 #endif
292 case AddressFamily_Irda:
293 #ifdef AF_IRDA
294 return AF_IRDA;
295 #else
296 return -1;
297 #endif
298 default:
299 g_warning ("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
300 return -1;
304 static MonoAddressFamily
305 convert_to_mono_family (guint16 af_family)
307 switch (af_family) {
308 case AF_UNSPEC:
309 return AddressFamily_Unspecified;
310 case AF_UNIX:
311 return AddressFamily_Unix;
312 case AF_INET:
313 return AddressFamily_InterNetwork;
314 #ifdef AF_IPX
315 case AF_IPX:
316 return AddressFamily_Ipx;
317 #endif
318 #ifdef AF_SNA
319 case AF_SNA:
320 return AddressFamily_Sna;
321 #endif
322 #ifdef AF_DECnet
323 case AF_DECnet:
324 return AddressFamily_DecNet;
325 #endif
326 #ifdef AF_APPLETALK
327 case AF_APPLETALK:
328 return AddressFamily_AppleTalk;
329 #endif
330 #ifdef HAVE_STRUCT_SOCKADDR_IN6
331 case AF_INET6:
332 return AddressFamily_InterNetworkV6;
333 #endif
334 #ifdef AF_IRDA
335 case AF_IRDA:
336 return AddressFamily_Irda;
337 #endif
338 default:
339 g_warning ("unknown address family 0x%x", af_family);
340 return AddressFamily_Unknown;
344 static gint32
345 convert_type (MonoSocketType mono_type)
347 switch (mono_type) {
348 case SocketType_Stream:
349 return SOCK_STREAM;
350 case SocketType_Dgram:
351 return SOCK_DGRAM;
352 case SocketType_Raw:
353 return SOCK_RAW;
354 case SocketType_Rdm:
355 #ifdef SOCK_RDM
356 return SOCK_RDM;
357 #else
358 return -1;
359 #endif
360 case SocketType_Seqpacket:
361 #ifdef SOCK_SEQPACKET
362 return SOCK_SEQPACKET;
363 #else
364 return -1;
365 #endif
366 case SocketType_Unknown:
367 g_warning ("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
368 return -1;
369 default:
370 g_warning ("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
371 return -1;
375 static gint32
376 convert_proto (MonoProtocolType mono_proto)
378 switch (mono_proto) {
379 case ProtocolType_IP:
380 case ProtocolType_IPv6:
381 case ProtocolType_Icmp:
382 case ProtocolType_Igmp:
383 case ProtocolType_Ggp:
384 case ProtocolType_Tcp:
385 case ProtocolType_Pup:
386 case ProtocolType_Udp:
387 case ProtocolType_Idp:
388 /* These protocols are known (on my system at least) */
389 return mono_proto;
390 case ProtocolType_ND:
391 case ProtocolType_Raw:
392 case ProtocolType_Ipx:
393 case ProtocolType_Spx:
394 case ProtocolType_SpxII:
395 case ProtocolType_Unknown:
396 /* These protocols arent */
397 g_warning ("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
398 return -1;
399 default:
400 return -1;
404 /* Convert MonoSocketFlags */
405 static gint32
406 convert_socketflags (gint32 sflags)
408 gint32 flags = 0;
410 if (!sflags)
411 /* SocketFlags.None */
412 return 0;
414 if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek |
415 SocketFlags_DontRoute | SocketFlags_Partial))
416 /* Contains invalid flag values */
417 return -1;
419 #ifdef MSG_OOB
420 if (sflags & SocketFlags_OutOfBand)
421 flags |= MSG_OOB;
422 #endif
423 if (sflags & SocketFlags_Peek)
424 flags |= MSG_PEEK;
425 if (sflags & SocketFlags_DontRoute)
426 flags |= MSG_DONTROUTE;
428 /* Ignore Partial - see bug 349688. Don't return -1, because
429 * according to the comment in that bug ms runtime doesn't for
430 * UDP sockets (this means we will silently ignore it for TCP
431 * too)
433 #ifdef MSG_MORE
434 if (sflags & SocketFlags_Partial)
435 flags |= MSG_MORE;
436 #endif
437 #if 0
438 /* Don't do anything for MaxIOVectorLength */
439 if (sflags & SocketFlags_MaxIOVectorLength)
440 return -1;
441 #endif
442 return flags;
446 * Returns:
447 * 0 on success (mapped mono_level and mono_name to system_level and system_name
448 * -1 on error
449 * -2 on non-fatal error (ie, must ignore)
451 static gint32
452 convert_sockopt_level_and_name (MonoSocketOptionLevel mono_level, MonoSocketOptionName mono_name, int *system_level, int *system_name)
454 switch (mono_level) {
455 case SocketOptionLevel_Socket:
456 *system_level = SOL_SOCKET;
458 switch (mono_name) {
459 case SocketOptionName_DontLinger:
460 /* This is SO_LINGER, because the setsockopt
461 * internal call maps DontLinger to SO_LINGER
462 * with l_onoff=0
464 *system_name = SO_LINGER;
465 break;
466 #ifdef SO_DEBUG
467 case SocketOptionName_Debug:
468 *system_name = SO_DEBUG;
469 break;
470 #endif
471 #ifdef SO_ACCEPTCONN
472 case SocketOptionName_AcceptConnection:
473 *system_name = SO_ACCEPTCONN;
474 break;
475 #endif
476 case SocketOptionName_ReuseAddress:
477 *system_name = SO_REUSEADDR;
478 break;
479 case SocketOptionName_KeepAlive:
480 *system_name = SO_KEEPALIVE;
481 break;
482 #ifdef SO_DONTROUTE
483 case SocketOptionName_DontRoute:
484 *system_name = SO_DONTROUTE;
485 break;
486 #endif
487 case SocketOptionName_Broadcast:
488 *system_name = SO_BROADCAST;
489 break;
490 case SocketOptionName_Linger:
491 *system_name = SO_LINGER;
492 break;
493 #ifdef SO_OOBINLINE
494 case SocketOptionName_OutOfBandInline:
495 *system_name = SO_OOBINLINE;
496 break;
497 #endif
498 case SocketOptionName_SendBuffer:
499 *system_name = SO_SNDBUF;
500 break;
501 case SocketOptionName_ReceiveBuffer:
502 *system_name = SO_RCVBUF;
503 break;
504 case SocketOptionName_SendLowWater:
505 *system_name = SO_SNDLOWAT;
506 break;
507 case SocketOptionName_ReceiveLowWater:
508 *system_name = SO_RCVLOWAT;
509 break;
510 case SocketOptionName_SendTimeout:
511 *system_name = SO_SNDTIMEO;
512 break;
513 case SocketOptionName_ReceiveTimeout:
514 *system_name = SO_RCVTIMEO;
515 break;
516 case SocketOptionName_Error:
517 *system_name = SO_ERROR;
518 break;
519 case SocketOptionName_Type:
520 *system_name = SO_TYPE;
521 break;
522 #ifdef SO_PEERCRED
523 case SocketOptionName_PeerCred:
524 *system_name = SO_PEERCRED;
525 break;
526 #endif
527 case SocketOptionName_ExclusiveAddressUse:
528 #ifdef SO_EXCLUSIVEADDRUSE
529 *system_name = SO_EXCLUSIVEADDRUSE;
530 break;
531 #endif
532 case SocketOptionName_UseLoopback:
533 #ifdef SO_USELOOPBACK
534 *system_name = SO_USELOOPBACK;
535 break;
536 #endif
537 case SocketOptionName_MaxConnections:
538 #ifdef SO_MAXCONN
539 *system_name = SO_MAXCONN;
540 break;
541 #elif defined(SOMAXCONN)
542 *system_name = SOMAXCONN;
543 break;
544 #endif
545 default:
546 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
547 return -1;
549 break;
551 case SocketOptionLevel_IP:
552 *system_level = mono_networking_get_ip_protocol ();
554 switch (mono_name) {
555 #ifdef IP_OPTIONS
556 case SocketOptionName_IPOptions:
557 *system_name = IP_OPTIONS;
558 break;
559 #endif
560 #ifdef IP_HDRINCL
561 case SocketOptionName_HeaderIncluded:
562 *system_name = IP_HDRINCL;
563 break;
564 #endif
565 #ifdef IP_TOS
566 case SocketOptionName_TypeOfService:
567 *system_name = IP_TOS;
568 break;
569 #endif
570 #ifdef IP_TTL
571 case SocketOptionName_IpTimeToLive:
572 *system_name = IP_TTL;
573 break;
574 #endif
575 case SocketOptionName_MulticastInterface:
576 *system_name = IP_MULTICAST_IF;
577 break;
578 case SocketOptionName_MulticastTimeToLive:
579 *system_name = IP_MULTICAST_TTL;
580 break;
581 case SocketOptionName_MulticastLoopback:
582 *system_name = IP_MULTICAST_LOOP;
583 break;
584 case SocketOptionName_AddMembership:
585 *system_name = IP_ADD_MEMBERSHIP;
586 break;
587 case SocketOptionName_DropMembership:
588 *system_name = IP_DROP_MEMBERSHIP;
589 break;
590 #ifdef HAVE_IP_PKTINFO
591 case SocketOptionName_PacketInformation:
592 *system_name = IP_PKTINFO;
593 break;
594 #endif /* HAVE_IP_PKTINFO */
596 case SocketOptionName_DontFragment:
597 #ifdef HAVE_IP_DONTFRAGMENT
598 *system_name = IP_DONTFRAGMENT;
599 break;
600 #elif defined HAVE_IP_MTU_DISCOVER
601 /* Not quite the same */
602 *system_name = IP_MTU_DISCOVER;
603 break;
604 #else
605 /* If the flag is not available on this system, we can ignore this error */
606 return -2;
607 #endif /* HAVE_IP_DONTFRAGMENT */
608 case SocketOptionName_AddSourceMembership:
609 case SocketOptionName_DropSourceMembership:
610 case SocketOptionName_BlockSource:
611 case SocketOptionName_UnblockSource:
612 /* Can't figure out how to map these, so fall
613 * through
615 default:
616 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
617 return -1;
619 break;
621 case SocketOptionLevel_IPv6:
622 *system_level = mono_networking_get_ipv6_protocol ();
624 switch (mono_name) {
625 case SocketOptionName_IpTimeToLive:
626 case SocketOptionName_HopLimit:
627 *system_name = IPV6_UNICAST_HOPS;
628 break;
629 case SocketOptionName_MulticastInterface:
630 *system_name = IPV6_MULTICAST_IF;
631 break;
632 case SocketOptionName_MulticastTimeToLive:
633 *system_name = IPV6_MULTICAST_HOPS;
634 break;
635 case SocketOptionName_MulticastLoopback:
636 *system_name = IPV6_MULTICAST_LOOP;
637 break;
638 case SocketOptionName_AddMembership:
639 *system_name = IPV6_JOIN_GROUP;
640 break;
641 case SocketOptionName_DropMembership:
642 *system_name = IPV6_LEAVE_GROUP;
643 break;
644 case SocketOptionName_IPv6Only:
645 #ifdef IPV6_V6ONLY
646 *system_name = IPV6_V6ONLY;
647 #else
648 return -1;
649 #endif
650 break;
651 case SocketOptionName_PacketInformation:
652 #ifdef HAVE_IPV6_PKTINFO
653 *system_name = IPV6_PKTINFO;
654 #endif
655 break;
656 case SocketOptionName_HeaderIncluded:
657 case SocketOptionName_IPOptions:
658 case SocketOptionName_TypeOfService:
659 case SocketOptionName_DontFragment:
660 case SocketOptionName_AddSourceMembership:
661 case SocketOptionName_DropSourceMembership:
662 case SocketOptionName_BlockSource:
663 case SocketOptionName_UnblockSource:
664 /* Can't figure out how to map these, so fall
665 * through
667 default:
668 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
669 return -1;
671 break; /* SocketOptionLevel_IPv6 */
673 case SocketOptionLevel_Tcp:
674 *system_level = mono_networking_get_tcp_protocol ();
676 switch (mono_name) {
677 case SocketOptionName_NoDelay:
678 *system_name = TCP_NODELAY;
679 break;
680 #if 0
681 /* The documentation is talking complete
682 * bollocks here: rfc-1222 is titled
683 * 'Advancing the NSFNET Routing Architecture'
684 * and doesn't mention either of the words
685 * "expedite" or "urgent".
687 case SocketOptionName_BsdUrgent:
688 case SocketOptionName_Expedited:
689 #endif
690 default:
691 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
692 return -1;
694 break;
696 case SocketOptionLevel_Udp:
697 g_warning ("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
699 switch(mono_name) {
700 case SocketOptionName_NoChecksum:
701 case SocketOptionName_ChecksumCoverage:
702 default:
703 g_warning ("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
704 return -1;
706 return -1;
707 break;
709 default:
710 g_warning ("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
711 return -1;
714 return 0;
717 static MonoImage*
718 get_socket_assembly (void)
720 MonoDomain *domain = mono_domain_get ();
722 if (domain->socket_assembly == NULL) {
723 MonoImage *socket_assembly;
725 socket_assembly = mono_image_loaded_internal ("System", FALSE);
726 if (!socket_assembly) {
727 MonoAssemblyOpenRequest req;
728 mono_assembly_request_prepare (&req.request, sizeof (req), MONO_ASMCTX_DEFAULT);
729 MonoAssembly *sa = mono_assembly_request_open ("System.dll", &req, NULL);
731 if (!sa) {
732 g_assert_not_reached ();
733 } else {
734 socket_assembly = mono_assembly_get_image_internal (sa);
737 mono_atomic_store_release (&domain->socket_assembly, socket_assembly);
740 return domain->socket_assembly;
743 gpointer
744 ves_icall_System_Net_Sockets_Socket_Socket_internal (MonoObjectHandle this_obj, gint32 family, gint32 type, gint32 proto, gint32 *werror, MonoError *error)
746 SOCKET sock;
747 gint32 sock_family;
748 gint32 sock_proto;
749 gint32 sock_type;
751 error_init (error);
752 *werror = 0;
754 sock_family = convert_family ((MonoAddressFamily)family);
755 if (sock_family == -1) {
756 *werror = WSAEAFNOSUPPORT;
757 return NULL;
760 sock_proto = convert_proto ((MonoProtocolType)proto);
761 if (sock_proto == -1) {
762 *werror = WSAEPROTONOSUPPORT;
763 return NULL;
766 sock_type = convert_type ((MonoSocketType)type);
767 if (sock_type == -1) {
768 *werror = WSAESOCKTNOSUPPORT;
769 return NULL;
772 sock = mono_w32socket_socket (sock_family, sock_type, sock_proto);
774 if (sock == INVALID_SOCKET) {
775 *werror = mono_w32socket_get_last_error ();
776 return NULL;
779 return GUINT_TO_POINTER (sock);
782 /* FIXME: the SOCKET parameter (here and in other functions in this
783 * file) is really an IntPtr which needs to be converted to a guint32.
785 void
786 ves_icall_System_Net_Sockets_Socket_Close_internal (gsize sock, gint32 *werror, MonoError *error)
788 LOGDEBUG (g_message ("%s: closing 0x%x", __func__, sock));
790 error_init (error);
791 *werror = 0;
793 /* Clear any pending work item from this socket if the underlying
794 * polling system does not notify when the socket is closed */
795 mono_threadpool_io_remove_socket (GPOINTER_TO_INT (sock));
797 mono_w32socket_close ((SOCKET) sock);
800 gint32
801 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal (void)
803 LOGDEBUG (g_message("%s: returning %d", __func__, mono_w32socket_get_last_error ()));
805 return mono_w32socket_get_last_error ();
808 gint32
809 ves_icall_System_Net_Sockets_Socket_Available_internal (gsize sock, gint32 *werror, MonoError *error)
811 int ret;
812 guint64 amount;
814 error_init (error);
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_internal (gsize sock, MonoBoolean block, gint32 *werror, MonoError *error)
830 int ret;
832 error_init (error);
833 *werror = 0;
835 ret = mono_w32socket_set_blocking (sock, block);
836 if (ret == SOCKET_ERROR)
837 *werror = mono_w32socket_get_last_error ();
840 gpointer
841 ves_icall_System_Net_Sockets_Socket_Accept_internal (gsize sock, gint32 *werror, MonoBoolean blocking, MonoError *error)
843 SOCKET newsock;
845 error_init (error);
846 *werror = 0;
848 newsock = mono_w32socket_accept (sock, NULL, 0, blocking);
849 if (newsock == INVALID_SOCKET) {
850 *werror = mono_w32socket_get_last_error ();
851 return NULL;
854 return GUINT_TO_POINTER (newsock);
857 void
858 ves_icall_System_Net_Sockets_Socket_Listen_internal(gsize sock, guint32 backlog, gint32 *werror, MonoError *error)
860 int ret;
862 error_init (error);
863 *werror = 0;
865 ret = mono_w32socket_listen (sock, backlog);
866 if (ret == SOCKET_ERROR)
867 *werror = mono_w32socket_get_last_error ();
870 #ifdef HAVE_STRUCT_SOCKADDR_IN6
871 // Check whether it's ::ffff::0:0.
872 static gboolean
873 is_ipv4_mapped_any (const struct in6_addr *addr)
875 int i;
877 for (i = 0; i < 10; i++) {
878 if (addr->s6_addr [i])
879 return FALSE;
881 if ((addr->s6_addr [10] != 0xff) || (addr->s6_addr [11] != 0xff))
882 return FALSE;
883 for (i = 12; i < 16; i++) {
884 if (addr->s6_addr [i])
885 return FALSE;
887 return TRUE;
889 #endif
891 static MonoObjectHandle
892 create_object_handle_from_sockaddr (struct sockaddr *saddr, int sa_size, gint32 *werror, MonoError *error)
894 MonoDomain *domain = mono_domain_get ();
895 MonoAddressFamily family;
897 error_init (error);
899 /* Build a System.Net.SocketAddress object instance */
900 if (!domain->sockaddr_class)
901 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
902 MonoObjectHandle sockaddr_obj = mono_object_new_handle (domain, domain->sockaddr_class, error);
903 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
905 /* Locate the SocketAddress data buffer in the object */
906 if (!domain->sockaddr_data_field) {
907 domain->sockaddr_data_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Buffer", NULL);
908 g_assert (domain->sockaddr_data_field);
911 /* Locate the SocketAddress data buffer length in the object */
912 if (!domain->sockaddr_data_length_field) {
913 domain->sockaddr_data_length_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Size", NULL);
914 g_assert (domain->sockaddr_data_length_field);
917 /* May be the +2 here is too conservative, as sa_len returns
918 * the length of the entire sockaddr_in/in6, including
919 * sizeof (unsigned short) of the family */
920 /* We can't really avoid the +2 as all code below depends on this size - INCLUDING unix domain sockets.*/
921 MonoArrayHandle data = mono_array_new_handle (domain, mono_get_byte_class (), sa_size + 2, error);
922 return_val_if_nok (error, MONO_HANDLE_NEW (MonoObject, NULL));
924 /* The data buffer is laid out as follows:
925 * bytes 0 and 1 are the address family
926 * bytes 2 and 3 are the port info
927 * the rest is the address info
930 family = convert_to_mono_family (saddr->sa_family);
931 if (family == AddressFamily_Unknown) {
932 *werror = WSAEAFNOSUPPORT;
933 return MONO_HANDLE_NEW (MonoObject, NULL);
936 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 0, family & 0x0FF);
937 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 1, (family >> 8) & 0x0FF);
939 if (saddr->sa_family == AF_INET) {
940 struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr;
941 guint16 port = ntohs (sa_in->sin_port);
942 guint32 address = ntohl (sa_in->sin_addr.s_addr);
943 int buffer_size = 8;
945 if (sa_size < buffer_size) {
946 mono_error_set_generic_error (error, "System", "SystemException", "");
947 return MONO_HANDLE_NEW (MonoObject, NULL);
950 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 2, (port>>8) & 0xff);
951 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 3, (port) & 0xff);
952 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 4, (address>>24) & 0xff);
953 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 5, (address>>16) & 0xff);
954 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 6, (address>>8) & 0xff);
955 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 7, (address) & 0xff);
957 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 */
958 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 */
960 return sockaddr_obj;
962 #ifdef HAVE_STRUCT_SOCKADDR_IN6
963 else if (saddr->sa_family == AF_INET6) {
964 struct sockaddr_in6 *sa_in = (struct sockaddr_in6 *)saddr;
965 int i;
966 int buffer_size = 28;
968 guint16 port = ntohs (sa_in->sin6_port);
970 if (sa_size < buffer_size) {
971 mono_error_set_generic_error (error, "System", "SystemException", "");
972 return MONO_HANDLE_NEW (MonoObject, NULL);
975 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 2, (port>>8) & 0xff);
976 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 3, (port) & 0xff);
978 if (is_ipv4_mapped_any (&sa_in->sin6_addr)) {
979 // Map ::ffff:0:0 to :: (bug #5502)
980 for (i = 0; i < 16; i++)
981 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 8 + i, 0);
982 } else {
983 for (i = 0; i < 16; i++) {
984 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 8 + i,
985 sa_in->sin6_addr.s6_addr [i]);
989 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 24, sa_in->sin6_scope_id & 0xff);
990 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 25,
991 (sa_in->sin6_scope_id >> 8) & 0xff);
992 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 26,
993 (sa_in->sin6_scope_id >> 16) & 0xff);
994 MONO_HANDLE_ARRAY_SETVAL (data, guint8, 27,
995 (sa_in->sin6_scope_id >> 24) & 0xff);
997 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 */
998 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 */
1000 return sockaddr_obj;
1002 #endif
1003 #ifdef HAVE_SYS_UN_H
1004 else if (saddr->sa_family == AF_UNIX) {
1005 int i;
1006 int buffer_size = sa_size + 2;
1008 for (i = 0; i < sa_size; i++)
1009 MONO_HANDLE_ARRAY_SETVAL (data, guint8, i + 2, saddr->sa_data [i]);
1011 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 */
1012 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 */
1014 return sockaddr_obj;
1016 #endif
1017 else {
1018 *werror = WSAEAFNOSUPPORT;
1019 return MONO_HANDLE_NEW (MonoObject, NULL);
1023 static int
1024 get_sockaddr_size (int family)
1026 int size;
1028 size = 0;
1029 if (family == AF_INET) {
1030 size = sizeof (struct sockaddr_in);
1032 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1033 else if (family == AF_INET6) {
1034 size = sizeof (struct sockaddr_in6);
1036 #endif
1037 #ifdef HAVE_SYS_UN_H
1038 else if (family == AF_UNIX) {
1039 size = sizeof (struct sockaddr_un);
1041 #endif
1042 return size;
1045 static MonoObjectHandle
1046 mono_w32socket_getname (gsize sock, gint32 af, gboolean local, gint32 *werror, MonoError *error)
1048 gpointer sa = NULL;
1049 socklen_t salen = 0;
1050 int ret;
1051 MonoObjectHandle result = NULL_HANDLE;
1053 *werror = 0;
1055 salen = get_sockaddr_size (convert_family ((MonoAddressFamily)af));
1056 if (salen == 0) {
1057 *werror = WSAEAFNOSUPPORT;
1058 goto exit;
1060 if (salen <= 128) {
1061 sa = g_alloca (salen);
1062 memset (sa, 0, salen);
1063 } else {
1064 sa = g_malloc0 (salen);
1067 /* Note: linux returns just 2 for AF_UNIX. Always. */
1068 ret = (local ? mono_w32socket_getsockname : mono_w32socket_getpeername) (sock, (struct sockaddr *)sa, &salen);
1069 if (ret == SOCKET_ERROR) {
1070 *werror = mono_w32socket_get_last_error ();
1071 goto exit;
1074 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)));
1076 result = create_object_handle_from_sockaddr ((struct sockaddr *)sa, salen, werror, error);
1077 exit:
1078 if (salen > 128)
1079 g_free (sa);
1080 return result;
1083 MonoObjectHandle
1084 ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal (gsize sock, gint32 af, gint32 *werror, MonoError *error)
1086 return mono_w32socket_getname (sock, af, TRUE, werror, error);
1089 MonoObjectHandle
1090 ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal (gsize sock, gint32 af, gint32 *werror, MonoError *error)
1092 return mono_w32socket_getname (sock, af, FALSE, werror, error);
1095 static struct sockaddr*
1096 create_sockaddr_from_handle (MonoObjectHandle saddr_obj, socklen_t *sa_size, gint32 *werror, MonoError *error)
1098 MonoDomain *domain = mono_domain_get ();
1099 gint32 family;
1100 int len;
1102 error_init (error);
1104 if (!domain->sockaddr_class)
1105 domain->sockaddr_class = mono_class_load_from_name (get_socket_assembly (), "System.Net", "SocketAddress");
1107 /* Locate the SocketAddress data buffer in the object */
1108 if (!domain->sockaddr_data_field) {
1109 domain->sockaddr_data_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Buffer", NULL);
1110 g_assert (domain->sockaddr_data_field);
1113 /* Locate the SocketAddress data buffer length in the object */
1114 if (!domain->sockaddr_data_length_field) {
1115 domain->sockaddr_data_length_field = mono_class_get_field_from_name_full (domain->sockaddr_class, "m_Size", NULL);
1116 g_assert (domain->sockaddr_data_length_field);
1119 MonoArrayHandle data = MONO_HANDLE_NEW_GET_FIELD (saddr_obj, MonoArray, domain->sockaddr_data_field);
1121 /* The data buffer is laid out as follows:
1122 * byte 0 is the address family low byte
1123 * byte 1 is the address family high byte
1124 * INET:
1125 * bytes 2 and 3 are the port info
1126 * the rest is the address info
1127 * UNIX:
1128 * the rest is the file name
1130 len = MONO_HANDLE_GET_FIELD_VAL (saddr_obj, int, domain->sockaddr_data_length_field);
1131 g_assert (len >= 2);
1133 uint32_t gchandle;
1134 guint8 *buf = MONO_ARRAY_HANDLE_PIN (data, guint8, 0, &gchandle);
1135 family = convert_family ((MonoAddressFamily)(buf[0] + (buf[1] << 8)));
1136 if (family == AF_INET) {
1137 struct sockaddr_in *sa;
1138 guint16 port;
1139 guint32 address;
1141 if (len < 8) {
1142 mono_error_set_generic_error (error, "System", "SystemException", "");
1143 mono_gchandle_free_internal (gchandle);
1144 return NULL;
1147 sa = g_new0 (struct sockaddr_in, 1);
1148 port = (buf[2] << 8) + buf[3];
1149 address = (buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7];
1151 sa->sin_family = family;
1152 sa->sin_addr.s_addr = htonl (address);
1153 sa->sin_port = htons (port);
1155 *sa_size = sizeof (struct sockaddr_in);
1156 mono_gchandle_free_internal (gchandle);
1157 return (struct sockaddr *)sa;
1159 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1160 else if (family == AF_INET6) {
1161 struct sockaddr_in6 *sa;
1162 int i;
1163 guint16 port;
1164 guint32 scopeid;
1166 if (len < 28) {
1167 mono_error_set_generic_error (error, "System", "SystemException", "");
1168 mono_gchandle_free_internal (gchandle);
1169 return NULL;
1172 sa = g_new0 (struct sockaddr_in6, 1);
1173 port = buf[3] + (buf[2] << 8);
1174 scopeid = buf[24] + (buf[25] << 8) + (buf[26] << 16) + (buf[27] << 24);
1176 sa->sin6_family = family;
1177 sa->sin6_port = htons (port);
1178 sa->sin6_scope_id = scopeid;
1180 for (i = 0; i < 16; i++)
1181 sa->sin6_addr.s6_addr [i] = buf[8 + i];
1183 *sa_size = sizeof (struct sockaddr_in6);
1184 mono_gchandle_free_internal (gchandle);
1185 return (struct sockaddr *)sa;
1187 #endif
1188 #ifdef HAVE_SYS_UN_H
1189 else if (family == AF_UNIX) {
1190 struct sockaddr_un *sock_un;
1191 int i;
1193 /* Need a byte for the '\0' terminator/prefix, and the first
1194 * two bytes hold the SocketAddress family
1196 if (len - 2 >= sizeof (sock_un->sun_path)) {
1197 mono_error_set_argument_out_of_range (error, "SocketAddress.Size", "MonoArgumentException:SocketAddress.Size");
1198 mono_gchandle_free_internal (gchandle);
1199 return NULL;
1202 sock_un = g_new0 (struct sockaddr_un, 1);
1204 sock_un->sun_family = family;
1205 for (i = 0; i < len - 2; i++)
1206 sock_un->sun_path [i] = buf[i + 2];
1208 *sa_size = len;
1209 mono_gchandle_free_internal (gchandle);
1210 return (struct sockaddr *)sock_un;
1212 #endif
1213 else {
1214 *werror = WSAEAFNOSUPPORT;
1215 mono_gchandle_free_internal (gchandle);
1216 return 0;
1220 void
1221 ves_icall_System_Net_Sockets_Socket_Bind_internal (gsize sock, MonoObjectHandle sockaddr, gint32 *werror, MonoError *error)
1223 struct sockaddr *sa;
1224 socklen_t sa_size;
1225 int ret;
1227 error_init (error);
1228 *werror = 0;
1230 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1231 if (*werror != 0)
1232 return;
1233 return_if_nok (error);
1235 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)));
1237 ret = mono_w32socket_bind (sock, sa, sa_size);
1239 if (ret == SOCKET_ERROR)
1240 *werror = mono_w32socket_get_last_error ();
1242 g_free (sa);
1245 enum {
1246 SelectModeRead,
1247 SelectModeWrite,
1248 SelectModeError
1251 MonoBoolean
1252 ves_icall_System_Net_Sockets_Socket_Poll_internal (gsize sock, gint mode,
1253 gint timeout, gint32 *werror, MonoError *error)
1255 MonoInternalThread *thread = mono_thread_internal_current ();
1256 mono_pollfd *pfds;
1257 int ret;
1258 time_t start;
1259 gint rtimeout;
1261 error_init (error);
1262 *werror = 0;
1264 pfds = g_new0 (mono_pollfd, 1);
1265 pfds->fd = GPOINTER_TO_INT (sock);
1267 switch (mode) {
1268 case SelectModeRead:
1269 pfds->events = MONO_POLLIN;
1270 break;
1271 case SelectModeWrite:
1272 pfds->events = MONO_POLLOUT;
1273 break;
1274 default:
1275 pfds->events = MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL;
1276 break;
1279 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1280 rtimeout = timeout;
1281 start = time (NULL);
1283 do {
1284 MONO_ENTER_GC_SAFE;
1286 ret = mono_poll (pfds, 1, timeout);
1288 MONO_EXIT_GC_SAFE;
1290 if (timeout > 0 && ret < 0) {
1291 int err = errno;
1292 int sec = time (NULL) - start;
1294 timeout = rtimeout - sec * 1000;
1295 if (timeout < 0) {
1296 timeout = 0;
1299 mono_set_errno (err);
1302 if (ret == -1 && errno == EINTR) {
1303 if (mono_thread_test_state (thread, ThreadState_AbortRequested)) {
1304 g_free (pfds);
1305 return FALSE;
1308 /* Suspend requested? */
1309 mono_thread_interruption_checkpoint_void ();
1311 mono_set_errno (EINTR);
1313 } while (ret == -1 && errno == EINTR);
1315 if (ret == -1) {
1316 *werror = mono_w32socket_convert_error (errno);
1317 g_free (pfds);
1318 return FALSE;
1321 g_free (pfds);
1322 return ret != 0;
1325 void
1326 ves_icall_System_Net_Sockets_Socket_Connect_internal (gsize sock, MonoObjectHandle sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1328 struct sockaddr *sa;
1329 socklen_t sa_size;
1330 int ret;
1332 error_init (error);
1333 *werror = 0;
1335 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1336 if (*werror != 0)
1337 return;
1338 return_if_nok (error);
1340 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)));
1342 ret = mono_w32socket_connect (sock, sa, sa_size, blocking);
1343 if (ret == SOCKET_ERROR)
1344 *werror = mono_w32socket_get_last_error ();
1346 g_free (sa);
1349 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
1351 void
1352 ves_icall_System_Net_Sockets_Socket_Disconnect_internal (gsize sock, MonoBoolean reuse, gint32 *werror, MonoError *error)
1354 error_init (error);
1356 LOGDEBUG (g_message("%s: disconnecting from socket %p (reuse %d)", __func__, sock, reuse));
1358 *werror = mono_w32socket_disconnect (sock, reuse);
1360 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
1362 MonoBoolean
1363 ves_icall_System_Net_Sockets_Socket_Duplicate_internal (gpointer handle, gint32 targetProcessId, gpointer *duplicate_handle, gint32 *werror, MonoError *error)
1365 error_init (error);
1367 *werror = 0;
1368 if (!mono_w32socket_duplicate (handle, targetProcessId, duplicate_handle)) {
1369 *werror = mono_w32error_get_last ();
1370 return FALSE;
1373 return TRUE;
1376 gint32
1377 ves_icall_System_Net_Sockets_Socket_Receive_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1379 int ret;
1380 int recvflags = 0;
1382 error_init (error);
1383 *werror = 0;
1385 recvflags = convert_socketflags (flags);
1386 if (recvflags == -1) {
1387 *werror = WSAEOPNOTSUPP;
1388 return 0;
1391 ret = mono_w32socket_recv (sock, buffer, count, recvflags, blocking);
1392 if (ret == SOCKET_ERROR) {
1393 *werror = mono_w32socket_get_last_error ();
1394 return 0;
1397 return ret;
1400 gint32
1401 ves_icall_System_Net_Sockets_Socket_Receive_array_internal (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1403 int ret;
1404 guint32 recv;
1405 guint32 recvflags = 0;
1407 error_init (error);
1408 *werror = 0;
1410 recvflags = convert_socketflags (flags);
1411 if (recvflags == -1) {
1412 *werror = WSAEOPNOTSUPP;
1413 return 0;
1416 ret = mono_w32socket_recvbuffers (sock, buffers, count, &recv, &recvflags, NULL, NULL, blocking);
1417 if (ret == SOCKET_ERROR) {
1418 *werror = mono_w32socket_get_last_error ();
1419 return 0;
1422 return recv;
1425 gint32
1426 ves_icall_System_Net_Sockets_Socket_ReceiveFrom_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandleInOut sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1428 int ret;
1429 int recvflags = 0;
1430 struct sockaddr *sa;
1431 socklen_t sa_size;
1433 error_init (error);
1434 *werror = 0;
1436 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1437 if (*werror != 0)
1438 return 0;
1439 if (!is_ok (error))
1440 return 0;
1442 recvflags = convert_socketflags (flags);
1443 if (recvflags == -1) {
1444 *werror = WSAEOPNOTSUPP;
1445 return 0;
1448 ret = mono_w32socket_recvfrom (sock, buffer, count, recvflags, sa, &sa_size, blocking);
1449 if (ret == SOCKET_ERROR) {
1450 *werror = mono_w32socket_get_last_error ();
1451 g_free(sa);
1452 return 0;
1455 /* If we didn't get a socket size, then we're probably a
1456 * connected connection-oriented socket and the stack hasn't
1457 * returned the remote address. All we can do is return null.
1459 if (sa_size) {
1460 MONO_HANDLE_ASSIGN (sockaddr, create_object_handle_from_sockaddr (sa, sa_size, werror, error));
1461 if (!is_ok (error)) {
1462 g_free (sa);
1463 return 0;
1465 } else {
1466 MONO_HANDLE_ASSIGN (sockaddr, MONO_HANDLE_NEW (MonoObject, NULL));
1469 g_free (sa);
1471 return ret;
1474 gint32
1475 ves_icall_System_Net_Sockets_Socket_Send_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1477 int ret;
1478 int sendflags = 0;
1480 error_init (error);
1481 *werror = 0;
1483 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1485 sendflags = convert_socketflags (flags);
1486 if (sendflags == -1) {
1487 *werror = WSAEOPNOTSUPP;
1488 return 0;
1491 ret = mono_w32socket_send (sock, buffer, count, sendflags, blocking);
1492 if (ret == SOCKET_ERROR) {
1493 *werror = mono_w32socket_get_last_error ();
1494 return 0;
1497 return ret;
1500 gint32
1501 ves_icall_System_Net_Sockets_Socket_Send_array_internal (gsize sock, WSABUF *buffers, gint32 count, gint32 flags, gint32 *werror, MonoBoolean blocking, MonoError *error)
1503 int ret;
1504 guint32 sent;
1505 guint32 sendflags = 0;
1507 error_init (error);
1508 *werror = 0;
1510 sendflags = convert_socketflags (flags);
1511 if (sendflags == -1) {
1512 *werror = WSAEOPNOTSUPP;
1513 return 0;
1516 ret = mono_w32socket_sendbuffers (sock, buffers, count, &sent, sendflags, NULL, NULL, blocking);
1517 if (ret == SOCKET_ERROR) {
1518 *werror = mono_w32socket_get_last_error ();
1519 return 0;
1522 return sent;
1525 gint32
1526 ves_icall_System_Net_Sockets_Socket_SendTo_internal (gsize sock, gchar *buffer, gint32 count, gint32 flags, MonoObjectHandle sockaddr, gint32 *werror, MonoBoolean blocking, MonoError *error)
1528 int ret;
1529 int sendflags = 0;
1530 struct sockaddr *sa;
1531 socklen_t sa_size;
1533 *werror = 0;
1535 sa = create_sockaddr_from_handle (sockaddr, &sa_size, werror, error);
1536 if (*werror != 0 || !is_ok (error))
1537 return 0;
1539 LOGDEBUG (g_message("%s: Sending %d bytes", __func__, count));
1541 sendflags = convert_socketflags (flags);
1542 if (sendflags == -1) {
1543 *werror = WSAEOPNOTSUPP;
1544 g_free (sa);
1545 return 0;
1548 ret = mono_w32socket_sendto (sock, buffer, count, sendflags, sa, sa_size, blocking);
1549 if (ret == SOCKET_ERROR) {
1550 *werror = mono_w32socket_get_last_error ();
1551 g_free(sa);
1552 return 0;
1555 g_free(sa);
1556 return ret;
1559 static SOCKET
1560 Socket_to_SOCKET (MonoObjectHandle sockobj)
1562 MonoClassField *field;
1564 field = mono_class_get_field_from_name_full (mono_handle_class (sockobj), "m_Handle", NULL);
1565 MonoSafeHandleHandle safe_handle = MONO_HANDLE_NEW_GET_FIELD(sockobj, MonoSafeHandle, field);
1567 if (MONO_HANDLE_IS_NULL (safe_handle))
1568 return -1;
1570 return (SOCKET)(gsize)MONO_HANDLE_GETVAL (safe_handle, handle);
1573 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1575 static gboolean
1576 collect_pollfds_from_array (MonoArrayHandle sockets, int i, int nfds, mono_pollfd *pfds, int *idx, int *mode)
1578 HANDLE_FUNCTION_ENTER ();
1579 gboolean result = TRUE;
1580 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1581 MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1582 if (MONO_HANDLE_IS_NULL (obj)) {
1583 (*mode)++;
1584 goto leave;
1587 if (*idx >= nfds) {
1588 result = FALSE;
1589 goto leave;
1592 pfds [*idx].fd = Socket_to_SOCKET (obj);
1593 pfds [*idx].events = (*mode == 0) ? MONO_POLLIN : (*mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1594 (*idx)++;
1595 leave:
1596 HANDLE_FUNCTION_RETURN_VAL (result);
1599 static void
1600 set_socks_array_from_pollfds (MonoArrayHandle sockets, int i, mono_pollfd *pfds, int *ret, int *mode, MonoArrayHandle socks, int *idx)
1602 HANDLE_FUNCTION_ENTER ();
1603 mono_pollfd *pfd;
1605 MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, NULL);
1606 MONO_HANDLE_ARRAY_GETREF (obj, sockets, i);
1607 if (MONO_HANDLE_IS_NULL (obj)) {
1608 (*mode)++;
1609 (*idx)++;
1610 goto leave;
1613 pfd = &pfds [i - *mode];
1614 if (pfd->revents == 0)
1615 goto leave;
1617 (*ret)--;
1618 if (((*mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0)) ||
1619 ((*mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0)) ||
1620 ((pfd->revents & POLL_ERRORS) != 0)) {
1621 MONO_HANDLE_ARRAY_SETREF (socks, *idx, obj);
1622 (*idx)++;
1624 leave:
1625 HANDLE_FUNCTION_RETURN ();
1628 void
1629 ves_icall_System_Net_Sockets_Socket_Select_internal (MonoArrayHandleOut sockets, gint32 timeout, gint32 *werror, MonoError *error)
1631 MonoInternalThread *thread = mono_thread_internal_current ();
1632 mono_pollfd *pfds;
1633 int nfds, idx;
1634 int ret;
1635 int i, count;
1636 int mode;
1637 MonoClass *sock_arr_class;
1638 time_t start;
1639 uintptr_t socks_size;
1640 gint32 rtimeout;
1642 error_init (error);
1643 *werror = 0;
1645 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1646 count = mono_array_handle_length (sockets);
1647 nfds = count - 3; /* NULL separators */
1648 pfds = g_new0 (mono_pollfd, nfds);
1649 mode = idx = 0;
1650 for (i = 0; i < count; i++) {
1651 if (!collect_pollfds_from_array (sockets, i, nfds, pfds, &idx, &mode)) {
1652 /* The socket array was bogus */
1653 g_free (pfds);
1654 *werror = WSAEFAULT;
1655 return;
1659 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1660 rtimeout = timeout;
1661 start = time (NULL);
1662 do {
1663 MONO_ENTER_GC_SAFE;
1665 ret = mono_poll (pfds, nfds, timeout);
1667 MONO_EXIT_GC_SAFE;
1669 if (timeout > 0 && ret < 0) {
1670 int err = errno;
1671 int sec = time (NULL) - start;
1673 timeout = rtimeout - sec * 1000;
1674 if (timeout < 0)
1675 timeout = 0;
1676 mono_set_errno (err);
1679 if (ret == -1 && errno == EINTR) {
1680 if (mono_thread_test_state (thread, ThreadState_AbortRequested)) {
1681 g_free (pfds);
1682 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1683 return;
1686 /* Suspend requested? */
1687 mono_thread_interruption_checkpoint_void ();
1689 mono_set_errno (EINTR);
1691 } while (ret == -1 && errno == EINTR);
1693 if (ret == -1) {
1694 *werror = mono_w32socket_convert_error (errno);
1695 g_free (pfds);
1696 return;
1699 if (ret == 0) {
1700 g_free (pfds);
1701 MONO_HANDLE_ASSIGN (sockets, MONO_HANDLE_NEW (MonoObject, NULL));
1702 return;
1705 sock_arr_class = mono_handle_class (sockets);
1706 socks_size = ((uintptr_t)ret) + 3; /* space for the NULL delimiters */
1707 MonoArrayHandle socks = MONO_HANDLE_NEW (MonoArray, mono_array_new_full_checked (mono_domain_get (), sock_arr_class, &socks_size, NULL, error));
1708 if (!is_ok (error)) {
1709 g_free (pfds);
1710 return;
1713 mode = idx = 0;
1714 for (i = 0; i < count && ret > 0; i++) {
1715 set_socks_array_from_pollfds (sockets, i, pfds, &ret, &mode, socks, &idx);
1718 MONO_HANDLE_ASSIGN (sockets, socks);
1719 g_free (pfds);
1722 static MonoObjectHandle
1723 int_to_object_handle (MonoDomain *domain, int val, MonoError *error)
1725 return MONO_HANDLE_NEW (MonoObject, mono_value_box_checked (domain, mono_get_int32_class (), &val, error));
1728 void
1729 ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal (gsize sock, gint32 level, gint32 name, MonoObjectHandleOut obj_val, gint32 *werror, MonoError *error)
1731 int system_level = 0;
1732 int system_name = 0;
1733 int ret;
1734 int val = 0;
1735 socklen_t valsize = sizeof (val);
1736 struct linger linger;
1737 socklen_t lingersize = sizeof (linger);
1738 int time_ms = 0;
1739 socklen_t time_ms_size = sizeof (time_ms);
1740 #ifdef SO_PEERCRED
1741 # if defined(__OpenBSD__)
1742 struct sockpeercred cred;
1743 # else
1744 struct ucred cred;
1745 # endif
1746 socklen_t credsize = sizeof (cred);
1747 #endif
1748 MonoDomain *domain = mono_domain_get ();
1749 MonoClass *obj_class;
1750 MonoClassField *field;
1752 error_init (error);
1753 *werror = 0;
1755 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1756 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
1757 system_level = SOL_SOCKET;
1758 system_name = SO_REUSEADDR;
1759 ret = 0;
1760 } else
1761 #endif
1763 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level, &system_name);
1766 if (ret == -1) {
1767 *werror = WSAENOPROTOOPT;
1768 return;
1770 if (ret == -2) {
1771 MONO_HANDLE_ASSIGN (obj_val, int_to_object_handle (domain, 0, error));
1772 return;
1775 /* No need to deal with MulticastOption names here, because
1776 * you cant getsockopt AddMembership or DropMembership (the
1777 * int getsockopt will error, causing an exception)
1779 switch (name) {
1780 case SocketOptionName_Linger:
1781 case SocketOptionName_DontLinger:
1782 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &linger, &lingersize);
1783 break;
1785 case SocketOptionName_SendTimeout:
1786 case SocketOptionName_ReceiveTimeout:
1787 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &time_ms, &time_ms_size);
1788 break;
1790 #ifdef SO_PEERCRED
1791 case SocketOptionName_PeerCred:
1792 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &cred, &credsize);
1793 break;
1794 #endif
1796 default:
1797 ret = mono_w32socket_getsockopt (sock, system_level, system_name, &val, &valsize);
1800 if (ret == SOCKET_ERROR) {
1801 *werror = mono_w32socket_get_last_error ();
1802 return;
1805 switch (name) {
1806 case SocketOptionName_Linger: {
1807 /* build a System.Net.Sockets.LingerOption */
1808 obj_class = mono_class_load_from_name (get_socket_assembly (),
1809 "System.Net.Sockets",
1810 "LingerOption");
1811 MonoObjectHandle obj = mono_object_new_handle (domain, obj_class, error);
1812 return_if_nok (error);
1814 /* Locate and set the fields "bool enabled" and "int
1815 * lingerTime"
1817 field = mono_class_get_field_from_name_full (obj_class, "enabled", NULL);
1818 MONO_HANDLE_SET_FIELD_VAL (obj, guint8, field, linger.l_onoff);
1820 field = mono_class_get_field_from_name_full (obj_class, "lingerTime", NULL);
1821 MONO_HANDLE_SET_FIELD_VAL (obj, guint32, field, linger.l_linger);
1823 MONO_HANDLE_ASSIGN (obj_val, obj);
1824 break;
1826 case SocketOptionName_DontLinger: {
1827 /* construct a bool int in val - true if linger is off */
1828 MonoObjectHandle obj = int_to_object_handle (domain, !linger.l_onoff, error);
1829 return_if_nok (error);
1831 MONO_HANDLE_ASSIGN (obj_val, obj);
1832 break;
1834 case SocketOptionName_SendTimeout:
1835 case SocketOptionName_ReceiveTimeout: {
1836 MonoObjectHandle obj = int_to_object_handle (domain, time_ms, error);
1837 return_if_nok (error);
1839 MONO_HANDLE_ASSIGN (obj_val, obj);
1840 break;
1843 #ifdef SO_PEERCRED
1844 case SocketOptionName_PeerCred: {
1846 * build a Mono.Posix.PeerCred+PeerCredData if
1847 * possible
1849 static MonoImage *mono_posix_image = NULL;
1851 if (mono_posix_image == NULL) {
1852 mono_posix_image = mono_image_loaded_internal ("Mono.Posix", FALSE);
1853 if (!mono_posix_image) {
1854 MonoAssemblyOpenRequest req;
1855 mono_assembly_request_prepare (&req.request, sizeof (req), MONO_ASMCTX_DEFAULT);
1856 MonoAssembly *sa = mono_assembly_request_open ("Mono.Posix.dll", &req, NULL);
1857 if (!sa) {
1858 *werror = WSAENOPROTOOPT;
1859 return;
1860 } else {
1861 mono_posix_image = mono_assembly_get_image_internal (sa);
1866 obj_class = mono_class_load_from_name (mono_posix_image,
1867 "Mono.Posix",
1868 "PeerCredData");
1869 MonoPeerCredDataHandle cred_data = MONO_HANDLE_CAST (MonoPeerCredData, mono_object_new_handle (domain, obj_class, error));
1870 return_if_nok (error);
1872 MONO_HANDLE_SETVAL (cred_data, pid, gint, cred.pid);
1873 MONO_HANDLE_SETVAL (cred_data, uid, gint, cred.uid);
1874 MONO_HANDLE_SETVAL (cred_data, gid, gint, cred.gid);
1876 MONO_HANDLE_ASSIGN (obj_val, cred_data);
1877 break;
1879 #endif
1881 default: {
1882 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
1883 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse)
1884 val = val ? 0 : 1;
1885 #endif
1886 MonoObjectHandle obj = int_to_object_handle (domain, val, error);
1887 return_if_nok (error);
1889 MONO_HANDLE_ASSIGN (obj_val, obj);
1894 void
1895 ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal (gsize sock, gint32 level, gint32 name, MonoArrayHandle byte_val, gint32 *werror, MonoError *error)
1897 int system_level = 0;
1898 int system_name = 0;
1899 int ret;
1900 socklen_t valsize;
1902 error_init (error);
1903 *werror = 0;
1905 ret = convert_sockopt_level_and_name((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
1906 &system_name);
1907 if (ret == -1) {
1908 *werror = WSAENOPROTOOPT;
1909 return;
1911 if (ret == -2)
1912 return;
1914 valsize = mono_array_handle_length (byte_val);
1916 uint32_t gchandle;
1917 guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
1919 ret = mono_w32socket_getsockopt (sock, system_level, system_name, buf, &valsize);
1921 mono_gchandle_free_internal (gchandle);
1923 if (ret == SOCKET_ERROR)
1924 *werror = mono_w32socket_get_last_error ();
1927 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1928 static struct in_addr
1929 ipaddress_handle_to_struct_in_addr (MonoObjectHandle ipaddr)
1931 struct in_addr inaddr;
1932 MonoClassField *field;
1934 field = mono_class_get_field_from_name_full (mono_handle_class (ipaddr), "_addressOrScopeId", NULL);
1935 g_assert (field);
1937 /* No idea why .net uses a 64bit type to hold a 32bit value...
1939 * Internal value of IPAddess is in little-endian order
1941 inaddr.s_addr = GUINT_FROM_LE ((guint32)MONO_HANDLE_GET_FIELD_VAL (ipaddr, guint32, field));
1943 return inaddr;
1946 #ifdef HAVE_STRUCT_SOCKADDR_IN6
1947 static struct in6_addr
1948 ipaddress_handle_to_struct_in6_addr (MonoObjectHandle ipaddr)
1950 struct in6_addr in6addr;
1951 MonoClassField *field;
1952 int i;
1954 field = mono_class_get_field_from_name_full (mono_handle_class (ipaddr), "_numbers", NULL);
1955 g_assert (field);
1956 MonoArrayHandle data = MONO_HANDLE_NEW_GET_FIELD (ipaddr, MonoArray, field);
1958 for (i = 0; i < 8; i++) {
1959 guint16 v;
1960 MONO_HANDLE_ARRAY_GETVAL (v, data, guint16, i);
1961 const guint16 s = GUINT16_TO_BE (v);
1963 /* Solaris/MacOS have only the 8 bit version. */
1964 #ifndef s6_addr16
1965 in6addr.s6_addr[2 * i + 1] = (s >> 8) & 0xff;
1966 in6addr.s6_addr[2 * i] = s & 0xff;
1967 #else
1968 in6addr.s6_addr16[i] = s;
1969 #endif
1971 return in6addr;
1973 #endif
1974 #endif
1976 #if defined(__APPLE__) || defined(__FreeBSD__)
1978 static int
1979 get_local_interface_id (int family)
1981 #if !(defined(HAVE_GETIFADDRS) || defined(HAVE_QP2GETIFADDRS)) || !defined(HAVE_IF_NAMETOINDEX)
1982 return 0;
1983 #else
1984 struct ifaddrs *ifap = NULL, *ptr;
1985 int idx = 0;
1987 if (getifaddrs (&ifap))
1988 return 0;
1990 for (ptr = ifap; ptr; ptr = ptr->ifa_next) {
1991 if (!ptr->ifa_addr || !ptr->ifa_name)
1992 continue;
1993 if (ptr->ifa_addr->sa_family != family)
1994 continue;
1995 if ((ptr->ifa_flags & IFF_LOOPBACK) != 0)
1996 continue;
1997 if ((ptr->ifa_flags & IFF_MULTICAST) == 0)
1998 continue;
2000 idx = if_nametoindex (ptr->ifa_name);
2001 break;
2004 freeifaddrs (ifap);
2005 return idx;
2006 #endif
2009 #endif /* defined(__APPLE__) || defined(__FreeBSD__) */
2011 void
2012 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)
2014 struct linger linger;
2015 int system_level = 0;
2016 int system_name = 0;
2017 int ret;
2018 int sol_ip;
2019 int sol_ipv6;
2021 error_init (error);
2022 *werror = 0;
2024 sol_ipv6 = mono_networking_get_ipv6_protocol ();
2025 sol_ip = mono_networking_get_ip_protocol ();
2027 ret = convert_sockopt_level_and_name ((MonoSocketOptionLevel)level, (MonoSocketOptionName)name, &system_level,
2028 &system_name);
2030 #if !defined(SO_EXCLUSIVEADDRUSE) && defined(SO_REUSEADDR)
2031 if (level == SocketOptionLevel_Socket && name == SocketOptionName_ExclusiveAddressUse) {
2032 system_name = SO_REUSEADDR;
2033 int_val = int_val ? 0 : 1;
2034 ret = 0;
2036 #endif
2038 if (ret == -1) {
2039 *werror = WSAENOPROTOOPT;
2040 return;
2042 if (ret == -2)
2043 return;
2045 /* Only one of obj_val, byte_val or int_val has data */
2046 if (!MONO_HANDLE_IS_NULL (obj_val)) {
2047 MonoClass *obj_class = mono_handle_class (obj_val);
2048 MonoClassField *field;
2049 int valsize;
2051 switch (name) {
2052 case SocketOptionName_Linger:
2053 /* Dig out "bool enabled" and "int lingerTime"
2054 * fields
2056 field = mono_class_get_field_from_name_full (obj_class, "enabled", NULL);
2057 linger.l_onoff = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint8, field);
2058 field = mono_class_get_field_from_name_full (obj_class, "lingerTime", NULL);
2059 linger.l_linger = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint32, field);
2061 valsize = sizeof (linger);
2062 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, valsize);
2063 break;
2064 case SocketOptionName_AddMembership:
2065 case SocketOptionName_DropMembership:
2066 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
2068 MonoObjectHandle address = MONO_HANDLE_NEW (MonoObject, NULL);
2069 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2070 if (system_level == sol_ipv6) {
2071 struct ipv6_mreq mreq6;
2074 * Get group address
2076 field = mono_class_get_field_from_name_full (obj_class, "m_Group", NULL);
2077 g_assert (field);
2078 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2080 if (!MONO_HANDLE_IS_NULL (address))
2081 mreq6.ipv6mr_multiaddr = ipaddress_handle_to_struct_in6_addr (address);
2083 field = mono_class_get_field_from_name_full (obj_class, "m_Interface", NULL);
2084 mreq6.ipv6mr_interface = MONO_HANDLE_GET_FIELD_VAL (obj_val, guint64, field);
2086 #if defined(__APPLE__) || defined(__FreeBSD__)
2088 * Bug #5504:
2090 * Mac OS Lion doesn't allow ipv6mr_interface = 0.
2092 * Tests on Windows and Linux show that the multicast group is only
2093 * joined on one NIC when interface = 0, so we simply use the interface
2094 * id from the first non-loopback interface (this is also what
2095 * Dns.GetHostName (string.Empty) would return).
2097 if (!mreq6.ipv6mr_interface)
2098 mreq6.ipv6mr_interface = get_local_interface_id (AF_INET6);
2099 #endif
2101 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq6, sizeof (mreq6));
2103 break; // Don't check sol_ip
2105 #endif
2106 if (system_level == sol_ip) {
2107 #ifdef HAVE_STRUCT_IP_MREQN
2108 struct ip_mreqn mreq = {{0}};
2109 #else
2110 struct ip_mreq mreq = {{0}};
2111 #endif /* HAVE_STRUCT_IP_MREQN */
2114 * pain! MulticastOption holds two IPAddress
2115 * members, so I have to dig the value out of
2116 * those :-(
2118 field = mono_class_get_field_from_name_full (obj_class, "group", NULL);
2119 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2121 /* address might not be defined and if so, set the address to ADDR_ANY.
2123 if (!MONO_HANDLE_IS_NULL (address))
2124 mreq.imr_multiaddr = ipaddress_handle_to_struct_in_addr (address);
2126 field = mono_class_get_field_from_name_full (obj_class, "localAddress", NULL);
2127 MONO_HANDLE_ASSIGN (address, MONO_HANDLE_NEW_GET_FIELD (obj_val, MonoObject, field));
2129 #ifdef HAVE_STRUCT_IP_MREQN
2130 if (!MONO_HANDLE_IS_NULL (address))
2131 mreq.imr_address = ipaddress_handle_to_struct_in_addr (address);
2133 field = mono_class_get_field_from_name_full (obj_class, "ifIndex", NULL);
2134 mreq.imr_ifindex = MONO_HANDLE_GET_FIELD_VAL (obj_val, gint32, field);
2135 #else
2136 if (!MONO_HANDLE_IS_NULL (address))
2137 mreq.imr_interface = ipaddress_handle_to_struct_in_addr (address);
2138 #endif /* HAVE_STRUCT_IP_MREQN */
2140 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
2142 break;
2144 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
2145 default:
2146 /* Cause an exception to be thrown */
2147 *werror = WSAEINVAL;
2148 return;
2150 } else if (!MONO_HANDLE_IS_NULL (byte_val)) {
2151 int valsize = mono_array_handle_length (byte_val);
2152 uint32_t gchandle;
2153 guchar *buf = MONO_ARRAY_HANDLE_PIN (byte_val, guchar, 0, &gchandle);
2155 switch(name) {
2156 case SocketOptionName_DontLinger:
2157 if (valsize == 1) {
2158 linger.l_onoff = (*buf) ? 0 : 1;
2159 linger.l_linger = 0;
2160 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2161 } else {
2162 *werror = WSAEINVAL;
2164 break;
2165 default:
2166 ret = mono_w32socket_setsockopt (sock, system_level, system_name, buf, valsize);
2167 break;
2169 mono_gchandle_free_internal (gchandle);
2170 } else {
2171 /* ReceiveTimeout/SendTimeout get here */
2172 switch (name) {
2173 case SocketOptionName_DontLinger:
2174 linger.l_onoff = !int_val;
2175 linger.l_linger = 0;
2176 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &linger, sizeof (linger));
2177 break;
2178 case SocketOptionName_MulticastInterface:
2179 #ifndef HOST_WIN32
2180 #ifdef HAVE_STRUCT_IP_MREQN
2181 int_val = GUINT32_FROM_BE (int_val);
2182 if ((int_val & 0xff000000) == 0) {
2183 /* int_val is interface index */
2184 struct ip_mreqn mreq = {{0}};
2185 mreq.imr_ifindex = int_val;
2186 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &mreq, sizeof (mreq));
2187 break;
2189 int_val = GUINT32_TO_BE (int_val);
2190 #endif /* HAVE_STRUCT_IP_MREQN */
2191 #endif /* HOST_WIN32 */
2192 /* int_val is in_addr */
2193 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &int_val, sizeof (int_val));
2194 break;
2195 case SocketOptionName_DontFragment:
2196 #ifdef HAVE_IP_MTU_DISCOVER
2197 /* Fiddle with the value slightly if we're
2198 * turning DF on
2200 if (int_val == 1)
2201 int_val = IP_PMTUDISC_DO;
2202 /* Fall through */
2203 #endif
2205 default:
2206 ret = mono_w32socket_setsockopt (sock, system_level, system_name, &int_val, sizeof (int_val));
2210 if (ret == SOCKET_ERROR) {
2211 *werror = mono_w32socket_get_last_error ();
2213 #ifdef HAVE_IP_MTU_DISCOVER
2214 if (system_name == IP_MTU_DISCOVER) {
2215 switch (system_level) {
2216 case IP_PMTUDISC_DONT:
2217 case IP_PMTUDISC_WANT:
2218 case IP_PMTUDISC_DO:
2219 #ifdef IP_PMTUDISC_PROBE
2220 case IP_PMTUDISC_PROBE:
2221 #endif
2222 #ifdef IP_PMTUDISC_INTERFACE
2223 case IP_PMTUDISC_INTERFACE:
2224 #endif
2225 #ifdef IP_PMTUDISC_OMIT
2226 case IP_PMTUDISC_OMIT:
2227 #endif
2229 * This happens if HAVE_IP_MTU_DISCOVER is set but the OS
2230 * doesn't actually understand it. The only OS that this is
2231 * known to happen on currently is Windows Subsystem for Linux
2232 * (newer versions have been fixed to recognize it). Just
2233 * pretend everything is fine.
2235 ret = 0;
2236 *werror = 0;
2237 break;
2238 default:
2239 break;
2242 #endif
2246 void
2247 ves_icall_System_Net_Sockets_Socket_Shutdown_internal (gsize sock, gint32 how, gint32 *werror, MonoError *error)
2249 int ret;
2251 error_init (error);
2252 *werror = 0;
2254 /* Currently, the values for how (recv=0, send=1, both=2) match the BSD API */
2255 ret = mono_w32socket_shutdown (sock, how);
2256 if (ret == SOCKET_ERROR)
2257 *werror = mono_w32socket_get_last_error ();
2260 gint
2261 ves_icall_System_Net_Sockets_Socket_IOControl_internal (gsize sock, gint32 code, MonoArrayHandle input, MonoArrayHandle output, gint32 *werror, MonoError *error)
2263 #ifdef HOST_WIN32
2264 DWORD output_bytes = 0;
2265 #else
2266 glong output_bytes = 0;
2267 #endif
2268 gchar *i_buffer, *o_buffer;
2269 gint i_len, o_len;
2270 uint32_t i_gchandle = 0;
2271 uint32_t o_gchandle = 0;
2272 gint ret;
2274 error_init (error);
2275 *werror = 0;
2277 if ((guint32)code == FIONBIO)
2278 /* Invalid command. Must use Socket.Blocking */
2279 return -1;
2281 if (MONO_HANDLE_IS_NULL (input)) {
2282 i_buffer = NULL;
2283 i_len = 0;
2284 i_gchandle = 0;
2285 } else {
2286 i_len = mono_array_handle_length (input);
2287 i_buffer = MONO_ARRAY_HANDLE_PIN (input, gchar, 0, &i_gchandle);
2290 if (MONO_HANDLE_IS_NULL (output)) {
2291 o_buffer = NULL;
2292 o_len = 0;
2293 o_gchandle = 0;
2294 } else {
2295 o_len = mono_array_handle_length (output);
2296 o_buffer = MONO_ARRAY_HANDLE_PIN (output, gchar, 0, &o_gchandle);
2299 ret = mono_w32socket_ioctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes);
2301 mono_gchandle_free_internal (i_gchandle);
2302 mono_gchandle_free_internal (o_gchandle);
2304 if (ret == SOCKET_ERROR) {
2305 *werror = mono_w32socket_get_last_error ();
2306 return -1;
2309 return (gint)output_bytes;
2312 static gboolean
2313 addrinfo_add_string (MonoDomain *domain, const char *s, MonoArrayHandle arr, int index, MonoError *error)
2315 HANDLE_FUNCTION_ENTER ();
2316 error_init (error);
2317 MonoStringHandle str = mono_string_new_handle (domain, s, error);
2318 goto_if_nok (error, leave);
2319 MONO_HANDLE_ARRAY_SETREF (arr, index, str);
2320 leave:
2321 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2325 static int
2326 addrinfo_add_local_ips (MonoDomain *domain, MonoArrayHandleOut h_addr_list, MonoError *error)
2328 HANDLE_FUNCTION_ENTER ();
2329 struct in_addr *local_in = NULL;
2330 int nlocal_in = 0;
2331 struct in6_addr *local_in6 = NULL;
2332 int nlocal_in6 = 0;
2333 int addr_index = 0;
2335 error_init (error);
2336 local_in = (struct in_addr *) mono_get_local_interfaces (AF_INET, &nlocal_in);
2337 local_in6 = (struct in6_addr *) mono_get_local_interfaces (AF_INET6, &nlocal_in6);
2338 if (nlocal_in || nlocal_in6) {
2339 char addr [INET6_ADDRSTRLEN];
2340 MONO_HANDLE_ASSIGN (h_addr_list, mono_array_new_handle (domain, mono_get_string_class (), nlocal_in + nlocal_in6, error));
2341 goto_if_nok (error, leave);
2343 if (nlocal_in) {
2344 int i;
2346 for (i = 0; i < nlocal_in; i++) {
2347 MonoAddress maddr;
2348 mono_address_init (&maddr, AF_INET, &local_in [i]);
2349 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2350 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2351 goto leave;
2352 addr_index++;
2356 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2357 if (nlocal_in6) {
2358 int i;
2360 for (i = 0; i < nlocal_in6; i++) {
2361 MonoAddress maddr;
2362 mono_address_init (&maddr, AF_INET6, &local_in6 [i]);
2363 if (mono_networking_addr_to_str (&maddr, addr, sizeof (addr))) {
2364 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2365 goto leave;
2366 addr_index++;
2370 #endif
2373 leave:
2374 g_free (local_in);
2375 g_free (local_in6);
2376 HANDLE_FUNCTION_RETURN_VAL (addr_index);
2379 static gboolean
2380 addrinfo_to_IPHostEntry_handles (MonoAddressInfo *info, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gboolean add_local_ips, MonoError *error)
2382 HANDLE_FUNCTION_ENTER ();
2383 MonoAddressEntry *ai = NULL;
2384 MonoDomain *domain = mono_domain_get ();
2386 error_init (error);
2387 MONO_HANDLE_ASSIGN (h_aliases, mono_array_new_handle (domain, mono_get_string_class (), 0, error));
2388 goto_if_nok (error, leave);
2389 if (add_local_ips) {
2390 int addr_index = addrinfo_add_local_ips (domain, h_addr_list, error);
2391 goto_if_nok (error, leave);
2392 if (addr_index > 0)
2393 goto leave;
2396 gint32 count;
2397 count = 0;
2398 for (ai = info->entries; ai != NULL; ai = ai->next) {
2399 if (ai->family != AF_INET && ai->family != AF_INET6)
2400 continue;
2401 count++;
2404 int addr_index;
2405 addr_index = 0;
2406 MONO_HANDLE_ASSIGN (h_addr_list, mono_array_new_handle (domain, mono_get_string_class (), count, error));
2407 goto_if_nok (error, leave);
2409 gboolean name_assigned;
2410 name_assigned = FALSE;
2411 for (ai = info->entries; ai != NULL; ai = ai->next) {
2412 MonoAddress maddr;
2413 char buffer [INET6_ADDRSTRLEN]; /* Max. size for IPv6 */
2415 if ((ai->family != PF_INET) && (ai->family != PF_INET6))
2416 continue;
2418 mono_address_init (&maddr, ai->family, &ai->address);
2419 const char *addr = NULL;
2420 if (mono_networking_addr_to_str (&maddr, buffer, sizeof (buffer)))
2421 addr = buffer;
2422 else
2423 addr = "";
2424 if (!addrinfo_add_string (domain, addr, h_addr_list, addr_index, error))
2425 goto leave;
2427 if (!name_assigned) {
2428 name_assigned = TRUE;
2429 const char *name = ai->canonical_name != NULL ? ai->canonical_name : buffer;
2430 MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (domain, name, error));
2431 goto_if_nok (error, leave);
2434 addr_index++;
2437 leave:
2438 if (info)
2439 mono_free_address_info (info);
2441 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
2444 MonoBoolean
2445 ves_icall_System_Net_Dns_GetHostByName_internal (MonoStringHandle host, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2447 gboolean add_local_ips = FALSE, add_info_ok = TRUE;
2448 gchar this_hostname [256];
2449 MonoAddressInfo *info = NULL;
2451 error_init (error);
2453 char *hostname = mono_string_handle_to_utf8 (host, error);
2454 return_val_if_nok (error, FALSE);
2456 if (*hostname == '\0') {
2457 add_local_ips = TRUE;
2458 MONO_HANDLE_ASSIGN (h_name, host);
2461 if (!add_local_ips && gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2462 if (!strcmp (hostname, this_hostname)) {
2463 add_local_ips = TRUE;
2464 MONO_HANDLE_ASSIGN (h_name, host);
2468 #ifdef HOST_WIN32
2469 // Win32 APIs already returns local interface addresses for empty hostname ("")
2470 // so we never want to add them manually.
2471 add_local_ips = FALSE;
2472 if (mono_get_address_info(hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2473 add_info_ok = FALSE;
2474 #else
2475 if (*hostname && mono_get_address_info (hostname, 0, MONO_HINT_CANONICAL_NAME | hint, &info))
2476 add_info_ok = FALSE;
2477 #endif
2479 g_free(hostname);
2481 if (add_info_ok) {
2482 MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, add_local_ips, error);
2483 return result;
2485 return FALSE;
2488 MonoBoolean
2489 ves_icall_System_Net_Dns_GetHostByAddr_internal (MonoStringHandle addr, MonoStringHandleOut h_name, MonoArrayHandleOut h_aliases, MonoArrayHandleOut h_addr_list, gint32 hint, MonoError *error)
2491 char *address;
2492 struct sockaddr_in saddr;
2493 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2494 struct sockaddr_in6 saddr6;
2495 #endif
2496 MonoAddressInfo *info = NULL;
2497 gint32 family;
2498 gchar hostname [NI_MAXHOST] = { 0 };
2499 gboolean ret;
2501 error_init (error);
2503 address = mono_string_handle_to_utf8 (addr, error);
2504 return_val_if_nok (error, FALSE);
2506 if (inet_pton (AF_INET, address, &saddr.sin_addr ) == 1) {
2507 family = AF_INET;
2508 saddr.sin_family = AF_INET;
2510 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2511 else if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) == 1) {
2512 family = AF_INET6;
2513 saddr6.sin6_family = AF_INET6;
2515 #endif
2516 else {
2517 g_free (address);
2518 return FALSE;
2521 g_free (address);
2523 switch (family) {
2524 case AF_INET: {
2525 #if HAVE_SOCKADDR_IN_SIN_LEN
2526 saddr.sin_len = sizeof (saddr);
2527 #endif
2528 MONO_ENTER_GC_SAFE;
2529 ret = getnameinfo ((struct sockaddr*)&saddr, sizeof (saddr), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2530 MONO_EXIT_GC_SAFE;
2531 break;
2533 #ifdef HAVE_STRUCT_SOCKADDR_IN6
2534 case AF_INET6: {
2535 #if HAVE_SOCKADDR_IN6_SIN_LEN
2536 saddr6.sin6_len = sizeof (saddr6);
2537 #endif
2538 MONO_ENTER_GC_SAFE;
2539 ret = getnameinfo ((struct sockaddr*)&saddr6, sizeof (saddr6), hostname, sizeof (hostname), NULL, 0, 0) == 0;
2540 MONO_EXIT_GC_SAFE;
2541 break;
2543 #endif
2544 default:
2545 g_assert_not_reached ();
2548 if (!ret)
2549 return FALSE;
2551 if (mono_get_address_info (hostname, 0, hint | MONO_HINT_CANONICAL_NAME | MONO_HINT_CONFIGURED_ONLY, &info) != 0)
2552 return FALSE;
2554 MonoBoolean result = addrinfo_to_IPHostEntry_handles (info, h_name, h_aliases, h_addr_list, FALSE, error);
2555 return result;
2558 MonoBoolean
2559 ves_icall_System_Net_Dns_GetHostName_internal (MonoStringHandleOut h_name, MonoError *error)
2561 gchar hostname [NI_MAXHOST] = { 0 };
2562 int ret;
2564 error_init (error);
2565 MONO_ENTER_GC_SAFE;
2566 ret = gethostname (hostname, sizeof (hostname));
2567 MONO_EXIT_GC_SAFE;
2568 if (ret == -1)
2569 return FALSE;
2571 MONO_HANDLE_ASSIGN (h_name, mono_string_new_handle (mono_domain_get (), hostname, error));
2572 return TRUE;
2575 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
2576 MonoBoolean
2577 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)
2579 HANDLE file;
2580 gboolean ret;
2581 TRANSMIT_FILE_BUFFERS buffers;
2582 uint32_t pre_buffer_gchandle = 0;
2583 uint32_t post_buffer_gchandle = 0;
2585 error_init (error);
2586 *werror = 0;
2588 if (MONO_HANDLE_IS_NULL (filename))
2589 return FALSE;
2591 /* FIXME: replace file by a proper fd that we can call open and close on, as they are interruptible */
2593 uint32_t filename_gchandle;
2594 gunichar2 *filename_chars = mono_string_handle_pin_chars (filename, &filename_gchandle);
2595 file = mono_w32file_create (filename_chars, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0);
2596 mono_gchandle_free_internal (filename_gchandle);
2597 if (file == INVALID_HANDLE_VALUE) {
2598 *werror = mono_w32error_get_last ();
2599 return FALSE;
2602 memset (&buffers, 0, sizeof (buffers));
2603 if (!MONO_HANDLE_IS_NULL (pre_buffer)) {
2604 buffers.Head = MONO_ARRAY_HANDLE_PIN (pre_buffer, guchar, 0, &pre_buffer_gchandle);
2605 buffers.HeadLength = mono_array_handle_length (pre_buffer);
2607 if (!MONO_HANDLE_IS_NULL (post_buffer)) {
2608 buffers.Tail = MONO_ARRAY_HANDLE_PIN (post_buffer, guchar, 0, &post_buffer_gchandle);
2609 buffers.TailLength = mono_array_handle_length (post_buffer);
2612 ret = mono_w32socket_transmit_file (sock, file, &buffers, flags, blocking);
2614 if (pre_buffer_gchandle)
2615 mono_gchandle_free_internal (pre_buffer_gchandle);
2616 if (post_buffer_gchandle)
2617 mono_gchandle_free_internal (post_buffer_gchandle);
2619 if (!ret)
2620 *werror = mono_w32socket_get_last_error ();
2622 mono_w32file_close (file);
2624 if (*werror)
2625 return FALSE;
2627 return ret;
2629 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */
2631 void
2632 mono_network_init (void)
2634 mono_networking_init ();
2635 mono_w32socket_initialize ();
2638 void
2639 mono_network_cleanup (void)
2641 mono_w32socket_cleanup ();
2642 mono_networking_shutdown ();
2645 void
2646 ves_icall_cancel_blocking_socket_operation (MonoThreadObjectHandle thread, MonoError *error)
2648 error_init (error);
2649 MonoInternalThreadHandle internal = MONO_HANDLE_NEW_GET (MonoInternalThread, thread, internal_thread);
2650 g_assert (!MONO_HANDLE_IS_NULL (internal));
2652 guint64 tid = mono_internal_thread_handle_ptr (internal)->tid;
2653 mono_thread_info_abort_socket_syscall_for_close (MONO_UINT_TO_NATIVE_THREAD_ID (tid));
2656 #endif /* #ifndef DISABLE_SOCKETS */