2007-01-19 Miguel de Icaza <miguel@novell.com>
[mono-project.git] / mono / metadata / socket-io.c
blobe2c4552fb6dbf881c097c22d401143ec076a809d
1 /*
2 * socket-io.c: Socket IO internal calls
4 * Authors:
5 * Dick Porter (dick@ximian.com)
6 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 * (C) 2001 Ximian, Inc.
9 * Copyright (c) 2005-2006 Novell, Inc. (http://www.novell.com)
12 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <errno.h>
20 #include <mono/metadata/object.h>
21 #include <mono/io-layer/io-layer.h>
22 #include <mono/metadata/socket-io.h>
23 #include <mono/metadata/exception.h>
24 #include <mono/metadata/assembly.h>
25 #include <mono/metadata/appdomain.h>
26 #include <mono/metadata/threads.h>
27 #include <mono/metadata/threads-types.h>
28 #include <mono/utils/mono-poll.h>
29 /* FIXME change this code to not mess so much with the internals */
30 #include <mono/metadata/class-internals.h>
31 #include <mono/metadata/threadpool-internals.h>
32 #include <mono/metadata/domain-internals.h>
34 #include <sys/time.h>
35 #ifdef HAVE_SYS_IOCTL_H
36 #include <sys/ioctl.h>
37 #endif
38 #ifdef HAVE_NET_IF_H
39 #include <net/if.h>
40 #endif
42 #ifdef HAVE_NETDB_H
43 #include <netdb.h>
44 #endif
45 #ifdef HAVE_SYS_FILIO_H
46 #include <sys/filio.h> /* defines FIONBIO and FIONREAD */
47 #endif
48 #ifdef HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h> /* defines SIOCATMARK */
50 #endif
51 #ifdef HAVE_SYS_UN_H
52 #include <sys/un.h>
53 #endif
55 #include "mono/io-layer/socket-wrappers.h"
57 #ifdef PLATFORM_WIN32
58 /* This is a kludge to make this file build under cygwin:
59 * w32api/ws2tcpip.h has definitions for some AF_INET6 values and
60 * prototypes for some but not all required functions (notably
61 * inet_ntop() is missing), but the libws2_32 library is missing the
62 * actual implementations of these functions.
64 #undef AF_INET6
65 #endif
67 #undef DEBUG
69 static gint32 convert_family(MonoAddressFamily mono_family)
71 gint32 family=-1;
73 switch(mono_family) {
74 case AddressFamily_Unknown:
75 case AddressFamily_ImpLink:
76 case AddressFamily_Pup:
77 case AddressFamily_Chaos:
78 case AddressFamily_Iso:
79 case AddressFamily_Ecma:
80 case AddressFamily_DataKit:
81 case AddressFamily_Ccitt:
82 case AddressFamily_DataLink:
83 case AddressFamily_Lat:
84 case AddressFamily_HyperChannel:
85 case AddressFamily_NetBios:
86 case AddressFamily_VoiceView:
87 case AddressFamily_FireFox:
88 case AddressFamily_Banyan:
89 case AddressFamily_Atm:
90 case AddressFamily_Cluster:
91 case AddressFamily_Ieee12844:
92 case AddressFamily_NetworkDesigners:
93 g_warning("System.Net.Sockets.AddressFamily has unsupported value 0x%x", mono_family);
94 break;
96 case AddressFamily_Unspecified:
97 family=AF_UNSPEC;
98 break;
100 case AddressFamily_Unix:
101 family=AF_UNIX;
102 break;
104 case AddressFamily_InterNetwork:
105 family=AF_INET;
106 break;
108 case AddressFamily_Ipx:
109 #ifdef AF_IPX
110 family=AF_IPX;
111 #endif
112 break;
114 case AddressFamily_Sna:
115 family=AF_SNA;
116 break;
118 case AddressFamily_DecNet:
119 family=AF_DECnet;
120 break;
122 case AddressFamily_AppleTalk:
123 family=AF_APPLETALK;
124 break;
126 case AddressFamily_InterNetworkV6:
127 #ifdef AF_INET6
128 family=AF_INET6;
129 #endif
130 break;
131 case AddressFamily_Irda:
132 #ifdef AF_IRDA
133 family=AF_IRDA;
134 #endif
135 break;
136 default:
137 g_warning("System.Net.Sockets.AddressFamily has unknown value 0x%x", mono_family);
140 return(family);
143 static MonoAddressFamily convert_to_mono_family(guint16 af_family)
145 MonoAddressFamily family=AddressFamily_Unknown;
147 switch(af_family) {
148 case AF_UNSPEC:
149 family=AddressFamily_Unspecified;
150 break;
152 case AF_UNIX:
153 family=AddressFamily_Unix;
154 break;
156 case AF_INET:
157 family=AddressFamily_InterNetwork;
158 break;
160 #ifdef AF_IPX
161 case AF_IPX:
162 family=AddressFamily_Ipx;
163 break;
164 #endif
166 case AF_SNA:
167 family=AddressFamily_Sna;
168 break;
170 case AF_DECnet:
171 family=AddressFamily_DecNet;
172 break;
174 case AF_APPLETALK:
175 family=AddressFamily_AppleTalk;
176 break;
178 #ifdef AF_INET6
179 case AF_INET6:
180 family=AddressFamily_InterNetworkV6;
181 break;
182 #endif
184 #ifdef AF_IRDA
185 case AF_IRDA:
186 family=AddressFamily_Irda;
187 break;
188 #endif
189 default:
190 g_warning("unknown address family 0x%x", af_family);
193 return(family);
196 static gint32 convert_type(MonoSocketType mono_type)
198 gint32 type=-1;
200 switch(mono_type) {
201 case SocketType_Stream:
202 type=SOCK_STREAM;
203 break;
205 case SocketType_Dgram:
206 type=SOCK_DGRAM;
207 break;
209 case SocketType_Raw:
210 type=SOCK_RAW;
211 break;
213 case SocketType_Rdm:
214 type=SOCK_RDM;
215 break;
217 case SocketType_Seqpacket:
218 type=SOCK_SEQPACKET;
219 break;
221 case SocketType_Unknown:
222 g_warning("System.Net.Sockets.SocketType has unsupported value 0x%x", mono_type);
223 break;
225 default:
226 g_warning("System.Net.Sockets.SocketType has unknown value 0x%x", mono_type);
229 return(type);
232 static gint32 convert_proto(MonoProtocolType mono_proto)
234 gint32 proto=-1;
236 switch(mono_proto) {
237 case ProtocolType_IP:
238 case ProtocolType_IPv6:
239 case ProtocolType_Icmp:
240 case ProtocolType_Igmp:
241 case ProtocolType_Ggp:
242 case ProtocolType_Tcp:
243 case ProtocolType_Pup:
244 case ProtocolType_Udp:
245 case ProtocolType_Idp:
246 /* These protocols are known (on my system at least) */
247 proto=mono_proto;
248 break;
250 case ProtocolType_ND:
251 case ProtocolType_Raw:
252 case ProtocolType_Ipx:
253 case ProtocolType_Spx:
254 case ProtocolType_SpxII:
255 case ProtocolType_Unknown:
256 /* These protocols arent */
257 g_warning("System.Net.Sockets.ProtocolType has unsupported value 0x%x", mono_proto);
258 break;
260 default:
261 break;
264 return(proto);
267 /* Convert MonoSocketFlags */
268 static gint32 convert_socketflags (gint32 sflags)
270 gint32 flags = 0;
272 if (!sflags)
273 /* SocketFlags.None */
274 return 0;
276 if (sflags & ~(SocketFlags_OutOfBand | SocketFlags_MaxIOVectorLength | SocketFlags_Peek |
277 SocketFlags_DontRoute | SocketFlags_Partial))
278 /* Contains invalid flag values */
279 return -1;
281 if (sflags & SocketFlags_OutOfBand)
282 flags |= MSG_OOB;
283 if (sflags & SocketFlags_Peek)
284 flags |= MSG_PEEK;
285 if (sflags & SocketFlags_DontRoute)
286 flags |= MSG_DONTROUTE;
287 if (sflags & SocketFlags_Partial)
288 #ifdef MSG_MORE
289 flags |= MSG_MORE;
290 #else
291 return -1;
292 #endif
293 if (sflags & SocketFlags_MaxIOVectorLength)
294 /* FIXME: Don't know what to do for MaxIOVectorLength query */
295 return -1;
297 return (flags ? flags : -1);
301 * Returns:
302 * 0 on success (mapped mono_level and mono_name to system_level and system_name
303 * -1 on error
304 * -2 on non-fatal error (ie, must ignore)
306 static gint32 convert_sockopt_level_and_name(MonoSocketOptionLevel mono_level,
307 MonoSocketOptionName mono_name,
308 int *system_level,
309 int *system_name)
311 switch (mono_level) {
312 case SocketOptionLevel_Socket:
313 *system_level = SOL_SOCKET;
315 switch(mono_name) {
316 case SocketOptionName_DontLinger:
317 /* This is SO_LINGER, because the setsockopt
318 * internal call maps DontLinger to SO_LINGER
319 * with l_onoff=0
321 *system_name = SO_LINGER;
322 break;
323 case SocketOptionName_Debug:
324 *system_name = SO_DEBUG;
325 break;
326 #ifdef SO_ACCEPTCONN
327 case SocketOptionName_AcceptConnection:
328 *system_name = SO_ACCEPTCONN;
329 break;
330 #endif
331 case SocketOptionName_ReuseAddress:
332 *system_name = SO_REUSEADDR;
333 break;
334 case SocketOptionName_KeepAlive:
335 *system_name = SO_KEEPALIVE;
336 break;
337 case SocketOptionName_DontRoute:
338 *system_name = SO_DONTROUTE;
339 break;
340 case SocketOptionName_Broadcast:
341 *system_name = SO_BROADCAST;
342 break;
343 case SocketOptionName_Linger:
344 *system_name = SO_LINGER;
345 break;
346 case SocketOptionName_OutOfBandInline:
347 *system_name = SO_OOBINLINE;
348 break;
349 case SocketOptionName_SendBuffer:
350 *system_name = SO_SNDBUF;
351 break;
352 case SocketOptionName_ReceiveBuffer:
353 *system_name = SO_RCVBUF;
354 break;
355 case SocketOptionName_SendLowWater:
356 *system_name = SO_SNDLOWAT;
357 break;
358 case SocketOptionName_ReceiveLowWater:
359 *system_name = SO_RCVLOWAT;
360 break;
361 case SocketOptionName_SendTimeout:
362 *system_name = SO_SNDTIMEO;
363 break;
364 case SocketOptionName_ReceiveTimeout:
365 *system_name = SO_RCVTIMEO;
366 break;
367 case SocketOptionName_Error:
368 *system_name = SO_ERROR;
369 break;
370 case SocketOptionName_Type:
371 *system_name = SO_TYPE;
372 break;
373 #ifdef SO_PEERCRED
374 case SocketOptionName_PeerCred:
375 *system_name = SO_PEERCRED;
376 break;
377 #endif
378 case SocketOptionName_ExclusiveAddressUse:
379 case SocketOptionName_UseLoopback:
380 case SocketOptionName_MaxConnections:
381 /* Can't figure out how to map these, so fall
382 * through
384 default:
385 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at Socket level", mono_name);
386 return(-1);
388 break;
390 case SocketOptionLevel_IP:
391 #ifdef HAVE_SOL_IP
392 *system_level = SOL_IP;
393 #else
394 if (1) {
395 static int cached = 0;
396 static int proto;
398 if (!cached) {
399 struct protoent *pent;
401 pent = getprotobyname ("IP");
402 proto = pent ? pent->p_proto : 0 /* 0 a good default value?? */;
403 cached = 1;
406 *system_level = proto;
408 #endif /* HAVE_SOL_IP */
410 switch(mono_name) {
411 case SocketOptionName_IPOptions:
412 *system_name = IP_OPTIONS;
413 break;
414 #ifdef IP_HDRINCL
415 case SocketOptionName_HeaderIncluded:
416 *system_name = IP_HDRINCL;
417 break;
418 #endif
419 #ifdef IP_TOS
420 case SocketOptionName_TypeOfService:
421 *system_name = IP_TOS;
422 break;
423 #endif
424 #ifdef IP_TTL
425 case SocketOptionName_IpTimeToLive:
426 *system_name = IP_TTL;
427 break;
428 #endif
429 case SocketOptionName_MulticastInterface:
430 *system_name = IP_MULTICAST_IF;
431 break;
432 case SocketOptionName_MulticastTimeToLive:
433 *system_name = IP_MULTICAST_TTL;
434 break;
435 case SocketOptionName_MulticastLoopback:
436 *system_name = IP_MULTICAST_LOOP;
437 break;
438 case SocketOptionName_AddMembership:
439 *system_name = IP_ADD_MEMBERSHIP;
440 break;
441 case SocketOptionName_DropMembership:
442 *system_name = IP_DROP_MEMBERSHIP;
443 break;
444 #ifdef HAVE_IP_PKTINFO
445 case SocketOptionName_PacketInformation:
446 *system_name = IP_PKTINFO;
447 break;
448 #endif /* HAVE_IP_PKTINFO */
450 case SocketOptionName_DontFragment:
451 #ifdef HAVE_IP_DONTFRAGMENT
452 *system_name = IP_DONTFRAGMENT;
453 break;
454 #elif defined HAVE_IP_MTU_DISCOVER
455 /* Not quite the same */
456 *system_name = IP_MTU_DISCOVER;
457 break;
458 #else
459 return (-2);
460 #endif /* HAVE_IP_DONTFRAGMENT */
461 case SocketOptionName_AddSourceMembership:
462 case SocketOptionName_DropSourceMembership:
463 case SocketOptionName_BlockSource:
464 case SocketOptionName_UnblockSource:
465 /* Can't figure out how to map these, so fall
466 * through
468 default:
469 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IP level", mono_name);
470 return(-1);
472 break;
474 #ifdef AF_INET6
475 case SocketOptionLevel_IPv6:
476 #ifdef HAVE_SOL_IPV6
477 *system_level = SOL_IPV6;
478 #else
479 if (1) {
480 static int cached = 0;
481 static int proto;
483 if (!cached) {
484 struct protoent *pent;
486 pent = getprotobyname ("IPV6");
487 proto = pent ? pent->p_proto : 41 /* 41 a good default value?? */;
488 cached = 1;
491 *system_level = proto;
493 #endif /* HAVE_SOL_IPV6 */
495 switch(mono_name) {
496 case SocketOptionName_IpTimeToLive:
497 *system_name = IPV6_UNICAST_HOPS;
498 break;
499 case SocketOptionName_MulticastInterface:
500 *system_name = IPV6_MULTICAST_IF;
501 break;
502 case SocketOptionName_MulticastTimeToLive:
503 *system_name = IPV6_MULTICAST_HOPS;
504 break;
505 case SocketOptionName_MulticastLoopback:
506 *system_name = IPV6_MULTICAST_LOOP;
507 break;
508 case SocketOptionName_AddMembership:
509 *system_name = IPV6_JOIN_GROUP;
510 break;
511 case SocketOptionName_DropMembership:
512 *system_name = IPV6_LEAVE_GROUP;
513 break;
514 case SocketOptionName_PacketInformation:
515 #ifdef HAVE_IPV6_PKTINFO
516 *system_name = IPV6_PKTINFO;
517 #endif
518 break;
519 case SocketOptionName_HeaderIncluded:
520 case SocketOptionName_IPOptions:
521 case SocketOptionName_TypeOfService:
522 case SocketOptionName_DontFragment:
523 case SocketOptionName_AddSourceMembership:
524 case SocketOptionName_DropSourceMembership:
525 case SocketOptionName_BlockSource:
526 case SocketOptionName_UnblockSource:
527 /* Can't figure out how to map these, so fall
528 * through
530 default:
531 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at IPv6 level", mono_name);
532 return(-1);
535 break; /* SocketOptionLevel_IPv6 */
536 #endif
538 case SocketOptionLevel_Tcp:
539 #ifdef HAVE_SOL_TCP
540 *system_level = SOL_TCP;
541 #else
542 if (1) {
543 static int cached = 0;
544 static int proto;
546 if (!cached) {
547 struct protoent *pent;
549 pent = getprotobyname ("TCP");
550 proto = pent ? pent->p_proto : 6 /* is 6 a good default value?? */;
551 cached = 1;
554 *system_level = proto;
556 #endif /* HAVE_SOL_TCP */
558 switch(mono_name) {
559 case SocketOptionName_NoDelay:
560 *system_name = TCP_NODELAY;
561 break;
562 #if 0
563 /* The documentation is talking complete
564 * bollocks here: rfc-1222 is titled
565 * 'Advancing the NSFNET Routing Architecture'
566 * and doesn't mention either of the words
567 * "expedite" or "urgent".
569 case SocketOptionName_BsdUrgent:
570 case SocketOptionName_Expedited:
571 #endif
572 default:
573 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at TCP level", mono_name);
574 return(-1);
576 break;
578 case SocketOptionLevel_Udp:
579 g_warning("System.Net.Sockets.SocketOptionLevel has unsupported value 0x%x", mono_level);
581 switch(mono_name) {
582 case SocketOptionName_NoChecksum:
583 case SocketOptionName_ChecksumCoverage:
584 default:
585 g_warning("System.Net.Sockets.SocketOptionName 0x%x is not supported at UDP level", mono_name);
586 return(-1);
588 return(-1);
589 break;
591 default:
592 g_warning("System.Net.Sockets.SocketOptionLevel has unknown value 0x%x", mono_level);
593 return(-1);
596 return(0);
599 #define STASH_SYS_ASS(this) \
600 if(system_assembly == NULL) { \
601 system_assembly=mono_image_loaded ("System"); \
602 if (!system_assembly) { \
603 MonoAssembly *sa = mono_assembly_open ("System.dll", NULL); \
604 if (!sa) g_assert_not_reached (); \
605 else {system_assembly = mono_assembly_get_image (sa);} \
609 static MonoImage *system_assembly=NULL;
612 #ifdef AF_INET6
613 static gint32 get_family_hint(void)
615 MonoClass *socket_class;
616 MonoClassField *ipv6_field, *ipv4_field;
617 gint32 ipv6_enabled = -1, ipv4_enabled = -1;
618 MonoVTable *vtable;
620 socket_class = mono_class_from_name (system_assembly,
621 "System.Net.Sockets", "Socket");
622 ipv4_field = mono_class_get_field_from_name (socket_class,
623 "ipv4Supported");
624 ipv6_field = mono_class_get_field_from_name (socket_class,
625 "ipv6Supported");
626 vtable = mono_class_vtable (mono_domain_get (), socket_class);
628 mono_field_static_get_value(vtable, ipv4_field, &ipv4_enabled);
629 mono_field_static_get_value(vtable, ipv6_field, &ipv6_enabled);
631 if(ipv4_enabled == 1 && ipv6_enabled == 1) {
632 return(PF_UNSPEC);
633 } else if(ipv4_enabled == 1) {
634 return(PF_INET);
635 } else {
636 return(PF_INET6);
639 #endif
641 gpointer ves_icall_System_Net_Sockets_Socket_Socket_internal(MonoObject *this, gint32 family, gint32 type, gint32 proto, gint32 *error)
643 SOCKET sock;
644 gint32 sock_family;
645 gint32 sock_proto;
646 gint32 sock_type;
648 MONO_ARCH_SAVE_REGS;
650 STASH_SYS_ASS(this);
652 *error = 0;
654 sock_family=convert_family(family);
655 if(sock_family==-1) {
656 *error = WSAEAFNOSUPPORT;
657 return(NULL);
660 sock_proto=convert_proto(proto);
661 if(sock_proto==-1) {
662 *error = WSAEPROTONOSUPPORT;
663 return(NULL);
666 sock_type=convert_type(type);
667 if(sock_type==-1) {
668 *error = WSAESOCKTNOSUPPORT;
669 return(NULL);
672 sock = _wapi_socket (sock_family, sock_type, sock_proto,
673 NULL, 0, WSA_FLAG_OVERLAPPED);
675 if(sock==INVALID_SOCKET) {
676 *error = WSAGetLastError ();
677 return(NULL);
680 if (sock_family == AF_INET && sock_type == SOCK_DGRAM) {
681 return (GUINT_TO_POINTER (sock));
684 #ifdef AF_INET6
685 if (sock_family == AF_INET6 && sock_type == SOCK_DGRAM) {
686 return (GUINT_TO_POINTER (sock));
688 #endif
690 #ifndef PLATFORM_WIN32
691 /* .net seems to set this by default for SOCK_STREAM,
692 * not for SOCK_DGRAM (see bug #36322)
694 * It seems winsock has a rather different idea of what
695 * SO_REUSEADDR means. If it's set, then a new socket can be
696 * bound over an existing listening socket. There's a new
697 * windows-specific option called SO_EXCLUSIVEADDRUSE but
698 * using that means the socket MUST be closed properly, or a
699 * denial of service can occur. Luckily for us, winsock
700 * behaves as though any other system would when SO_REUSEADDR
701 * is true, so we don't need to do anything else here. See
702 * bug 53992.
705 int ret, true = 1;
707 ret = _wapi_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof (true));
708 if(ret==SOCKET_ERROR) {
709 *error = WSAGetLastError ();
711 closesocket(sock);
712 return(NULL);
715 #endif
717 return(GUINT_TO_POINTER (sock));
720 /* FIXME: the SOCKET parameter (here and in other functions in this
721 * file) is really an IntPtr which needs to be converted to a guint32.
723 void ves_icall_System_Net_Sockets_Socket_Close_internal(SOCKET sock,
724 gint32 *error)
726 MONO_ARCH_SAVE_REGS;
728 #ifdef DEBUG
729 g_message (G_GNUC_PRETTY_FUNCTION ": closing 0x%x", sock);
730 #endif
732 *error = 0;
734 /* Clear any pending work item from this socket if the underlying
735 * polling system does not notify when the socket is closed */
736 mono_thread_pool_remove_socket (GPOINTER_TO_INT (sock));
737 closesocket(sock);
740 gint32 ves_icall_System_Net_Sockets_SocketException_WSAGetLastError_internal(void)
742 MONO_ARCH_SAVE_REGS;
744 #ifdef DEBUG
745 g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", WSAGetLastError());
746 #endif
748 return(WSAGetLastError());
751 gint32 ves_icall_System_Net_Sockets_Socket_Available_internal(SOCKET sock,
752 gint32 *error)
754 int ret;
755 gulong amount;
757 MONO_ARCH_SAVE_REGS;
759 *error = 0;
761 ret=ioctlsocket(sock, FIONREAD, &amount);
762 if(ret==SOCKET_ERROR) {
763 *error = WSAGetLastError ();
764 return(0);
767 return(amount);
770 void ves_icall_System_Net_Sockets_Socket_Blocking_internal(SOCKET sock,
771 gboolean block,
772 gint32 *error)
774 int ret;
776 MONO_ARCH_SAVE_REGS;
778 *error = 0;
781 * block == TRUE/FALSE means we will block/not block.
782 * But the ioctlsocket call takes TRUE/FALSE for non-block/block
784 block = !block;
786 ret = ioctlsocket (sock, FIONBIO, (gulong *) &block);
787 if(ret==SOCKET_ERROR) {
788 *error = WSAGetLastError ();
792 gpointer ves_icall_System_Net_Sockets_Socket_Accept_internal(SOCKET sock,
793 gint32 *error)
795 SOCKET newsock;
797 MONO_ARCH_SAVE_REGS;
799 *error = 0;
801 newsock = _wapi_accept (sock, NULL, 0);
802 if(newsock==INVALID_SOCKET) {
803 *error = WSAGetLastError ();
804 return(NULL);
807 return(GUINT_TO_POINTER (newsock));
810 void ves_icall_System_Net_Sockets_Socket_Listen_internal(SOCKET sock,
811 guint32 backlog,
812 gint32 *error)
814 int ret;
816 MONO_ARCH_SAVE_REGS;
818 *error = 0;
820 ret = _wapi_listen (sock, backlog);
821 if(ret==SOCKET_ERROR) {
822 *error = WSAGetLastError ();
826 static MonoObject *create_object_from_sockaddr(struct sockaddr *saddr,
827 int sa_size, gint32 *error)
829 MonoDomain *domain = mono_domain_get ();
830 MonoObject *sockaddr_obj;
831 MonoClass *sockaddr_class;
832 MonoClassField *field;
833 MonoArray *data;
834 MonoAddressFamily family;
836 /* Build a System.Net.SocketAddress object instance */
837 sockaddr_class=mono_class_from_name(system_assembly, "System.Net", "SocketAddress");
838 sockaddr_obj=mono_object_new(domain, sockaddr_class);
840 /* Locate the SocketAddress data buffer in the object */
841 field=mono_class_get_field_from_name(sockaddr_class, "data");
843 /* Make sure there is space for the family and size bytes */
844 #ifdef HAVE_SYS_UN_H
845 if (saddr->sa_family == AF_UNIX) {
846 /* sa_len includes the entire sockaddr size, so we don't need the
847 * N bytes (sizeof (unsigned short)) of the family. */
848 data=mono_array_new(domain, mono_get_byte_class (), sa_size);
849 } else
850 #endif
852 /* May be the +2 here is too conservative, as sa_len returns
853 * the length of the entire sockaddr_in/in6, including
854 * sizeof (unsigned short) of the family */
855 data=mono_array_new(domain, mono_get_byte_class (), sa_size+2);
858 /* The data buffer is laid out as follows:
859 * bytes 0 and 1 are the address family
860 * bytes 2 and 3 are the port info
861 * the rest is the address info
864 family=convert_to_mono_family(saddr->sa_family);
865 if(family==AddressFamily_Unknown) {
866 *error = WSAEAFNOSUPPORT;
867 return(NULL);
870 mono_array_set(data, guint8, 0, family & 0x0FF);
871 mono_array_set(data, guint8, 1, (family >> 8) & 0x0FF);
873 if(saddr->sa_family==AF_INET) {
874 struct sockaddr_in *sa_in=(struct sockaddr_in *)saddr;
875 guint16 port=ntohs(sa_in->sin_port);
876 guint32 address=ntohl(sa_in->sin_addr.s_addr);
878 if(sa_size<8) {
879 mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
882 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
883 mono_array_set(data, guint8, 3, (port) & 0xff);
884 mono_array_set(data, guint8, 4, (address>>24) & 0xff);
885 mono_array_set(data, guint8, 5, (address>>16) & 0xff);
886 mono_array_set(data, guint8, 6, (address>>8) & 0xff);
887 mono_array_set(data, guint8, 7, (address) & 0xff);
889 mono_field_set_value (sockaddr_obj, field, data);
891 return(sockaddr_obj);
892 #ifdef AF_INET6
893 } else if (saddr->sa_family == AF_INET6) {
894 struct sockaddr_in6 *sa_in=(struct sockaddr_in6 *)saddr;
895 int i;
897 guint16 port=ntohs(sa_in->sin6_port);
899 if(sa_size<28) {
900 mono_raise_exception((MonoException *)mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
903 mono_array_set(data, guint8, 2, (port>>8) & 0xff);
904 mono_array_set(data, guint8, 3, (port) & 0xff);
906 for(i=0; i<16; i++) {
907 mono_array_set(data, guint8, 8+i,
908 sa_in->sin6_addr.s6_addr[i]);
911 mono_array_set(data, guint8, 24, sa_in->sin6_scope_id & 0xff);
912 mono_array_set(data, guint8, 25,
913 (sa_in->sin6_scope_id >> 8) & 0xff);
914 mono_array_set(data, guint8, 26,
915 (sa_in->sin6_scope_id >> 16) & 0xff);
916 mono_array_set(data, guint8, 27,
917 (sa_in->sin6_scope_id >> 24) & 0xff);
919 mono_field_set_value (sockaddr_obj, field, data);
921 return(sockaddr_obj);
922 #endif
923 #ifdef HAVE_SYS_UN_H
924 } else if (saddr->sa_family == AF_UNIX) {
925 int i;
927 for (i = 0; i < sa_size; i++) {
928 mono_array_set (data, guint8, i+2, saddr->sa_data[i]);
931 mono_field_set_value (sockaddr_obj, field, data);
933 return sockaddr_obj;
934 #endif
935 } else {
936 *error = WSAEAFNOSUPPORT;
937 return(NULL);
941 extern MonoObject *ves_icall_System_Net_Sockets_Socket_LocalEndPoint_internal(SOCKET sock, gint32 *error)
943 gchar sa[32]; /* sockaddr in not big enough for sockaddr_in6 */
944 socklen_t salen;
945 int ret;
947 MONO_ARCH_SAVE_REGS;
949 *error = 0;
951 salen=sizeof(sa);
952 ret = _wapi_getsockname (sock, (struct sockaddr *)sa, &salen);
954 if(ret==SOCKET_ERROR) {
955 *error = WSAGetLastError ();
956 return(NULL);
959 #ifdef DEBUG
960 g_message(G_GNUC_PRETTY_FUNCTION ": bound to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port));
961 #endif
963 return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
964 error));
967 extern MonoObject *ves_icall_System_Net_Sockets_Socket_RemoteEndPoint_internal(SOCKET sock, gint32 *error)
969 gchar sa[32]; /* sockaddr in not big enough for sockaddr_in6 */
970 socklen_t salen;
971 int ret;
973 MONO_ARCH_SAVE_REGS;
975 *error = 0;
977 salen=sizeof(sa);
978 ret = _wapi_getpeername (sock, (struct sockaddr *)sa, &salen);
980 if(ret==SOCKET_ERROR) {
981 *error = WSAGetLastError ();
982 return(NULL);
985 #ifdef DEBUG
986 g_message(G_GNUC_PRETTY_FUNCTION ": connected to %s port %d", inet_ntoa(((struct sockaddr_in *)&sa)->sin_addr), ntohs(((struct sockaddr_in *)&sa)->sin_port));
987 #endif
989 return(create_object_from_sockaddr((struct sockaddr *)sa, salen,
990 error));
993 static struct sockaddr *create_sockaddr_from_object(MonoObject *saddr_obj,
994 socklen_t *sa_size,
995 gint32 *error)
997 MonoClassField *field;
998 MonoArray *data;
999 gint32 family;
1000 int len;
1002 /* Dig the SocketAddress data buffer out of the object */
1003 field=mono_class_get_field_from_name(saddr_obj->vtable->klass, "data");
1004 data=*(MonoArray **)(((char *)saddr_obj) + field->offset);
1006 /* The data buffer is laid out as follows:
1007 * byte 0 is the address family low byte
1008 * byte 1 is the address family high byte
1009 * INET:
1010 * bytes 2 and 3 are the port info
1011 * the rest is the address info
1012 * UNIX:
1013 * the rest is the file name
1015 len = mono_array_length (data);
1016 if (len < 2) {
1017 mono_raise_exception (mono_exception_from_name(mono_get_corlib (), "System", "SystemException"));
1020 family = convert_family (mono_array_get (data, guint8, 0) + (mono_array_get (data, guint8, 1) << 8));
1021 if (family == AF_INET) {
1022 struct sockaddr_in *sa;
1023 guint16 port;
1024 guint32 address;
1026 if (len < 8) {
1027 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1030 sa = g_new0 (struct sockaddr_in, 1);
1031 port = (mono_array_get (data, guint8, 2) << 8) +
1032 mono_array_get (data, guint8, 3);
1033 address = (mono_array_get (data, guint8, 4) << 24) +
1034 (mono_array_get (data, guint8, 5) << 16 ) +
1035 (mono_array_get (data, guint8, 6) << 8) +
1036 mono_array_get (data, guint8, 7);
1038 sa->sin_family = family;
1039 sa->sin_addr.s_addr = htonl (address);
1040 sa->sin_port = htons (port);
1042 *sa_size = sizeof(struct sockaddr_in);
1043 return((struct sockaddr *)sa);
1045 #ifdef AF_INET6
1046 } else if (family == AF_INET6) {
1047 struct sockaddr_in6 *sa;
1048 int i;
1049 guint16 port;
1050 guint32 scopeid;
1052 if (len < 28) {
1053 mono_raise_exception (mono_exception_from_name (mono_get_corlib (), "System", "SystemException"));
1056 sa = g_new0 (struct sockaddr_in6, 1);
1057 port = mono_array_get (data, guint8, 3) +
1058 (mono_array_get (data, guint8, 2) << 8);
1059 scopeid = mono_array_get (data, guint8, 24) +
1060 (mono_array_get (data, guint8, 25) << 8) +
1061 (mono_array_get (data, guint8, 26) << 16) +
1062 (mono_array_get (data, guint8, 27) << 24);
1064 sa->sin6_family = family;
1065 sa->sin6_port = htons (port);
1066 sa->sin6_scope_id = scopeid;
1068 for(i=0; i<16; i++) {
1069 sa->sin6_addr.s6_addr[i] = mono_array_get (data, guint8, 8+i);
1072 *sa_size = sizeof(struct sockaddr_in6);
1073 return((struct sockaddr *)sa);
1074 #endif
1075 #ifdef HAVE_SYS_UN_H
1076 } else if (family == AF_UNIX) {
1077 struct sockaddr_un *sock_un;
1078 int i;
1080 /* Need a byte for the '\0' terminator/prefix, and the first
1081 * two bytes hold the SocketAddress family
1083 if (len - 2 >= MONO_SIZEOF_SUNPATH) {
1084 mono_raise_exception (mono_get_exception_index_out_of_range ());
1087 sock_un = g_new0 (struct sockaddr_un, 1);
1089 sock_un->sun_family = family;
1090 for (i = 0; i < len - 2; i++) {
1091 sock_un->sun_path [i] = mono_array_get (data, guint8,
1092 i + 2);
1095 *sa_size = len;
1097 return (struct sockaddr *)sock_un;
1098 #endif
1099 } else {
1100 *error = WSAEAFNOSUPPORT;
1101 return(0);
1105 extern void ves_icall_System_Net_Sockets_Socket_Bind_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1107 struct sockaddr *sa;
1108 socklen_t sa_size;
1109 int ret;
1111 MONO_ARCH_SAVE_REGS;
1113 *error = 0;
1115 sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1116 if (*error != 0) {
1117 return;
1120 #ifdef DEBUG
1121 g_message(G_GNUC_PRETTY_FUNCTION ": binding to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port));
1122 #endif
1124 ret = _wapi_bind (sock, sa, sa_size);
1125 if(ret==SOCKET_ERROR) {
1126 *error = WSAGetLastError ();
1129 g_free(sa);
1132 enum {
1133 SelectModeRead,
1134 SelectModeWrite,
1135 SelectModeError
1138 MonoBoolean
1139 ves_icall_System_Net_Sockets_Socket_Poll_internal (SOCKET sock, gint mode,
1140 gint timeout, gint32 *error)
1142 MonoThread *thread = NULL;
1143 mono_pollfd *pfds;
1144 int ret;
1145 time_t start;
1148 MONO_ARCH_SAVE_REGS;
1150 pfds = g_new0 (mono_pollfd, 1);
1151 pfds[0].fd = GPOINTER_TO_INT (sock);
1152 pfds[0].events = (mode == SelectModeRead) ? MONO_POLLIN :
1153 (mode == SelectModeWrite) ? MONO_POLLOUT :
1154 (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL);
1156 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1157 start = time (NULL);
1158 do {
1159 *error = 0;
1161 ret = mono_poll (pfds, 1, timeout);
1162 if (timeout > 0 && ret < 0) {
1163 int err = errno;
1164 int sec = time (NULL) - start;
1166 timeout -= sec * 1000;
1167 if (timeout < 0) {
1168 timeout = 0;
1171 errno = err;
1174 if (ret == -1 && errno == EINTR) {
1175 int leave = 0;
1177 if (thread == NULL) {
1178 thread = mono_thread_current ();
1181 mono_monitor_enter (thread->synch_lock);
1182 leave = ((thread->state & ThreadState_AbortRequested) != 0 ||
1183 (thread->state & ThreadState_StopRequested) != 0);
1184 mono_monitor_exit (thread->synch_lock);
1186 if (leave != 0) {
1187 g_free (pfds);
1188 return(FALSE);
1189 } else {
1190 /* Suspend requested? */
1191 mono_thread_interruption_checkpoint ();
1193 errno = EINTR;
1195 } while (ret == -1 && errno == EINTR);
1197 if (ret == -1) {
1198 #ifdef PLATFORM_WIN32
1199 *error = WSAGetLastError ();
1200 #else
1201 *error = errno_to_WSA (errno, __func__);
1202 #endif
1203 g_free (pfds);
1204 return(FALSE);
1207 g_free (pfds);
1209 if (ret == 0) {
1210 return(FALSE);
1211 } else {
1212 return (TRUE);
1216 extern void ves_icall_System_Net_Sockets_Socket_Connect_internal(SOCKET sock, MonoObject *sockaddr, gint32 *error)
1218 struct sockaddr *sa;
1219 socklen_t sa_size;
1220 int ret;
1222 MONO_ARCH_SAVE_REGS;
1224 *error = 0;
1226 sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1227 if (*error != 0) {
1228 return;
1231 #ifdef DEBUG
1232 g_message(G_GNUC_PRETTY_FUNCTION ": connecting to %s port %d", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr), ntohs (((struct sockaddr_in *)sa)->sin_port));
1233 #endif
1235 ret = _wapi_connect (sock, sa, sa_size);
1236 if(ret==SOCKET_ERROR) {
1237 *error = WSAGetLastError ();
1240 g_free(sa);
1243 /* These #defines from mswsock.h from wine. Defining them here allows
1244 * us to build this file on a mingw box that doesn't know the magic
1245 * numbers, but still run on a newer windows box that does.
1247 #ifndef WSAID_DISCONNECTEX
1248 #define WSAID_DISCONNECTEX {0x7fda2e11,0x8630,0x436f,{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
1249 typedef BOOL (WINAPI *LPFN_DISCONNECTEX)(SOCKET, LPOVERLAPPED, DWORD, DWORD);
1250 #endif
1252 #ifndef WSAID_TRANSMITFILE
1253 #define WSAID_TRANSMITFILE {0xb5367df0,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
1254 typedef BOOL (WINAPI *LPFN_TRANSMITFILE)(SOCKET, HANDLE, DWORD, DWORD, LPOVERLAPPED, LPTRANSMIT_FILE_BUFFERS, DWORD);
1255 #endif
1257 extern void ves_icall_System_Net_Sockets_Socket_Disconnect_internal(SOCKET sock, MonoBoolean reuse, gint32 *error)
1259 int ret;
1260 glong output_bytes = 0;
1261 GUID disco_guid = WSAID_DISCONNECTEX;
1262 GUID trans_guid = WSAID_TRANSMITFILE;
1263 LPFN_DISCONNECTEX _wapi_disconnectex = NULL;
1264 LPFN_TRANSMITFILE _wapi_transmitfile = NULL;
1265 gboolean bret;
1267 MONO_ARCH_SAVE_REGS;
1269 *error = 0;
1271 #ifdef DEBUG
1272 g_message("%s: disconnecting from socket %p (reuse %d)", __func__,
1273 sock, reuse);
1274 #endif
1276 /* I _think_ the extension function pointers need to be looked
1277 * up for each socket. FIXME: check the best way to store
1278 * pointers to functions in managed objects that still works
1279 * on 64bit platforms.
1281 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1282 (void *)&disco_guid, sizeof(GUID),
1283 (void *)&_wapi_disconnectex, sizeof(void *),
1284 &output_bytes, NULL, NULL);
1285 if (ret != 0) {
1286 /* make sure that WSAIoctl didn't put crap in the
1287 * output pointer
1289 _wapi_disconnectex = NULL;
1291 /* Look up the TransmitFile extension function pointer
1292 * instead of calling TransmitFile() directly, because
1293 * apparently "Several of the extension functions have
1294 * been available since WinSock 1.1 and are exported
1295 * from MSWsock.dll, however it's not advisable to
1296 * link directly to this dll as this ties you to the
1297 * Microsoft WinSock provider. A provider neutral way
1298 * of accessing these extension functions is to load
1299 * them dynamically via WSAIoctl using the
1300 * SIO_GET_EXTENSION_FUNCTION_POINTER op code. This
1301 * should, theoretically, allow you to access these
1302 * functions from any provider that supports them..."
1303 * (http://www.codeproject.com/internet/jbsocketserver3.asp)
1305 ret = WSAIoctl (sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
1306 (void *)&trans_guid, sizeof(GUID),
1307 (void *)&_wapi_transmitfile, sizeof(void *),
1308 &output_bytes, NULL, NULL);
1309 if (ret != 0) {
1310 _wapi_transmitfile = NULL;
1314 if (_wapi_disconnectex != NULL) {
1315 bret = _wapi_disconnectex (sock, NULL, TF_REUSE_SOCKET, 0);
1316 } else if (_wapi_transmitfile != NULL) {
1317 bret = _wapi_transmitfile (sock, NULL, 0, 0, NULL, NULL,
1318 TF_DISCONNECT | TF_REUSE_SOCKET);
1319 } else {
1320 *error = ERROR_NOT_SUPPORTED;
1321 return;
1324 if (bret == FALSE) {
1325 *error = WSAGetLastError ();
1329 gint32 ves_icall_System_Net_Sockets_Socket_Receive_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1331 int ret;
1332 guchar *buf;
1333 gint32 alen;
1334 int recvflags=0;
1336 MONO_ARCH_SAVE_REGS;
1338 *error = 0;
1340 alen = mono_array_length (buffer);
1341 if (offset > alen - count) {
1342 return(0);
1345 buf=mono_array_addr(buffer, guchar, offset);
1347 recvflags = convert_socketflags (flags);
1348 if (recvflags == -1) {
1349 *error = WSAEOPNOTSUPP;
1350 return (0);
1353 ret = _wapi_recv (sock, buf, count, recvflags);
1354 if(ret==SOCKET_ERROR) {
1355 *error = WSAGetLastError ();
1356 return(0);
1359 return(ret);
1362 gint32 ves_icall_System_Net_Sockets_Socket_RecvFrom_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject **sockaddr, gint32 *error)
1364 int ret;
1365 guchar *buf;
1366 gint32 alen;
1367 int recvflags=0;
1368 struct sockaddr *sa;
1369 socklen_t sa_size;
1371 MONO_ARCH_SAVE_REGS;
1373 *error = 0;
1375 alen = mono_array_length (buffer);
1376 if (offset > alen - count) {
1377 return(0);
1380 sa=create_sockaddr_from_object(*sockaddr, &sa_size, error);
1381 if (*error != 0) {
1382 return(0);
1385 buf=mono_array_addr(buffer, guchar, offset);
1387 recvflags = convert_socketflags (flags);
1388 if (recvflags == -1) {
1389 *error = WSAEOPNOTSUPP;
1390 return (0);
1393 ret = _wapi_recvfrom (sock, buf, count, recvflags, sa, &sa_size);
1394 if(ret==SOCKET_ERROR) {
1395 g_free(sa);
1396 *error = WSAGetLastError ();
1397 return(0);
1400 /* If we didn't get a socket size, then we're probably a
1401 * connected connection-oriented socket and the stack hasn't
1402 * returned the remote address. All we can do is return null.
1404 if ( sa_size != 0 )
1405 *sockaddr=create_object_from_sockaddr(sa, sa_size, error);
1406 else
1407 *sockaddr=NULL;
1409 g_free(sa);
1411 return(ret);
1414 gint32 ves_icall_System_Net_Sockets_Socket_Send_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, gint32 *error)
1416 int ret;
1417 guchar *buf;
1418 gint32 alen;
1419 int sendflags=0;
1421 MONO_ARCH_SAVE_REGS;
1423 *error = 0;
1425 alen = mono_array_length (buffer);
1426 if (offset > alen - count) {
1427 return(0);
1430 #ifdef DEBUG
1431 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1432 #endif
1434 buf=mono_array_addr(buffer, guchar, offset);
1436 #ifdef DEBUG
1437 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1438 #endif
1440 sendflags = convert_socketflags (flags);
1441 if (sendflags == -1) {
1442 *error = WSAEOPNOTSUPP;
1443 return (0);
1446 ret = _wapi_send (sock, buf, count, sendflags);
1447 if(ret==SOCKET_ERROR) {
1448 *error = WSAGetLastError ();
1449 return(0);
1452 return(ret);
1455 gint32 ves_icall_System_Net_Sockets_Socket_SendTo_internal(SOCKET sock, MonoArray *buffer, gint32 offset, gint32 count, gint32 flags, MonoObject *sockaddr, gint32 *error)
1457 int ret;
1458 guchar *buf;
1459 gint32 alen;
1460 int sendflags=0;
1461 struct sockaddr *sa;
1462 socklen_t sa_size;
1464 MONO_ARCH_SAVE_REGS;
1466 *error = 0;
1468 alen = mono_array_length (buffer);
1469 if (offset > alen - count) {
1470 return(0);
1473 sa=create_sockaddr_from_object(sockaddr, &sa_size, error);
1474 if(*error != 0) {
1475 return(0);
1478 #ifdef DEBUG
1479 g_message(G_GNUC_PRETTY_FUNCTION ": alen: %d", alen);
1480 #endif
1482 buf=mono_array_addr(buffer, guchar, offset);
1484 #ifdef DEBUG
1485 g_message(G_GNUC_PRETTY_FUNCTION ": Sending %d bytes", count);
1486 #endif
1488 sendflags = convert_socketflags (flags);
1489 if (sendflags == -1) {
1490 *error = WSAEOPNOTSUPP;
1491 return (0);
1494 ret = _wapi_sendto (sock, buf, count, sendflags, sa, sa_size);
1495 if(ret==SOCKET_ERROR) {
1496 *error = WSAGetLastError ();
1499 g_free(sa);
1501 return(ret);
1504 static SOCKET Socket_to_SOCKET(MonoObject *sockobj)
1506 SOCKET sock;
1507 MonoClassField *field;
1509 field=mono_class_get_field_from_name(sockobj->vtable->klass, "socket");
1510 sock=*(SOCKET *)(((char *)sockobj)+field->offset);
1512 return(sock);
1515 #define POLL_ERRORS (MONO_POLLERR | MONO_POLLHUP | MONO_POLLNVAL)
1516 void ves_icall_System_Net_Sockets_Socket_Select_internal(MonoArray **sockets, gint32 timeout, gint32 *error)
1518 MonoThread *thread = NULL;
1519 MonoObject *obj;
1520 mono_pollfd *pfds;
1521 int nfds, idx;
1522 int ret;
1523 int i, count;
1524 int mode;
1525 MonoClass *sock_arr_class;
1526 MonoArray *socks;
1527 time_t start;
1529 MONO_ARCH_SAVE_REGS;
1531 /* *sockets -> READ, null, WRITE, null, ERROR, null */
1532 count = mono_array_length (*sockets);
1533 nfds = count - 3; /* NULL separators */
1534 pfds = g_new0 (mono_pollfd, nfds);
1535 mode = idx = 0;
1536 for (i = 0; i < count; i++) {
1537 obj = mono_array_get (*sockets, MonoObject *, i);
1538 if (obj == NULL) {
1539 mode++;
1540 continue;
1543 if (idx >= nfds) {
1544 /* The socket array was bogus */
1545 g_free (pfds);
1546 *error = WSAEFAULT;
1547 return;
1550 pfds [idx].fd = GPOINTER_TO_INT (Socket_to_SOCKET (obj));
1551 pfds [idx].events = (mode == 0) ? MONO_POLLIN : (mode == 1) ? MONO_POLLOUT : POLL_ERRORS;
1552 idx++;
1555 timeout = (timeout >= 0) ? (timeout / 1000) : -1;
1556 start = time (NULL);
1557 do {
1558 *error = 0;
1559 ret = mono_poll (pfds, nfds, timeout);
1560 if (timeout > 0 && ret < 0) {
1561 int err = errno;
1562 int sec = time (NULL) - start;
1564 timeout -= sec * 1000;
1565 if (timeout < 0)
1566 timeout = 0;
1567 errno = err;
1570 if (ret == -1 && errno == EINTR) {
1571 int leave = 0;
1572 if (thread == NULL)
1573 thread = mono_thread_current ();
1575 mono_monitor_enter (thread->synch_lock);
1576 leave = ((thread->state & ThreadState_AbortRequested) != 0 ||
1577 (thread->state & ThreadState_StopRequested) != 0);
1578 mono_monitor_exit (thread->synch_lock);
1579 if (leave != 0) {
1580 g_free (pfds);
1581 *sockets = NULL;
1582 return;
1583 } else {
1584 /* Suspend requested? */
1585 mono_thread_interruption_checkpoint ();
1587 errno = EINTR;
1589 } while (ret == -1 && errno == EINTR);
1591 if (ret == -1) {
1592 #ifdef PLATFORM_WIN32
1593 *error = WSAGetLastError ();
1594 #else
1595 *error = errno_to_WSA (errno, __func__);
1596 #endif
1597 g_free (pfds);
1598 return;
1601 if (ret == 0) {
1602 g_free (pfds);
1603 *sockets = NULL;
1604 return;
1607 sock_arr_class= ((MonoObject *)*sockets)->vtable->klass;
1608 ret += 3; /* space for the NULL delimiters */
1609 socks = mono_array_new_full (mono_domain_get (), sock_arr_class, (guint32*)&ret, NULL);
1610 ret -= 3;
1611 mode = idx = 0;
1612 for (i = 0; i < count && ret > 0; i++) {
1613 mono_pollfd *pfd;
1615 obj = mono_array_get (*sockets, MonoObject *, i);
1616 if (obj == NULL) {
1617 mode++;
1618 idx++;
1619 continue;
1622 pfd = &pfds [i - mode];
1623 if (pfd->revents == 0)
1624 continue;
1626 ret--;
1627 if (mode == 0 && (pfd->revents & (MONO_POLLIN | POLL_ERRORS)) != 0) {
1628 mono_array_setref (socks, idx++, obj);
1629 } else if (mode == 1 && (pfd->revents & (MONO_POLLOUT | POLL_ERRORS)) != 0) {
1630 mono_array_setref (socks, idx++, obj);
1631 } else if ((pfd->revents & POLL_ERRORS) != 0) {
1632 mono_array_setref (socks, idx++, obj);
1636 *sockets = socks;
1637 g_free (pfds);
1640 static MonoObject* int_to_object (MonoDomain *domain, int val)
1642 return mono_value_box (domain, mono_get_int32_class (), &val);
1646 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_obj_internal(SOCKET sock, gint32 level, gint32 name, MonoObject **obj_val, gint32 *error)
1648 int system_level;
1649 int system_name;
1650 int ret;
1651 int val;
1652 socklen_t valsize=sizeof(val);
1653 struct linger linger;
1654 socklen_t lingersize=sizeof(linger);
1655 int time_ms = 0;
1656 socklen_t time_ms_size = sizeof (time_ms);
1657 #ifdef SO_PEERCRED
1658 struct ucred cred;
1659 socklen_t credsize = sizeof(cred);
1660 #endif
1661 MonoDomain *domain=mono_domain_get();
1662 MonoObject *obj;
1663 MonoClass *obj_class;
1664 MonoClassField *field;
1666 MONO_ARCH_SAVE_REGS;
1668 *error = 0;
1670 ret=convert_sockopt_level_and_name(level, name, &system_level,
1671 &system_name);
1672 if(ret==-1) {
1673 *error = WSAENOPROTOOPT;
1674 return;
1676 if (ret == -2)
1677 return;
1679 /* No need to deal with MulticastOption names here, because
1680 * you cant getsockopt AddMembership or DropMembership (the
1681 * int getsockopt will error, causing an exception)
1683 switch(name) {
1684 case SocketOptionName_Linger:
1685 case SocketOptionName_DontLinger:
1686 ret = _wapi_getsockopt(sock, system_level, system_name, &linger,
1687 &lingersize);
1688 break;
1690 case SocketOptionName_SendTimeout:
1691 case SocketOptionName_ReceiveTimeout:
1692 ret = _wapi_getsockopt (sock, system_level, system_name, (char *) &time_ms, &time_ms_size);
1693 break;
1695 #ifdef SO_PEERCRED
1696 case SocketOptionName_PeerCred:
1697 ret = _wapi_getsockopt (sock, system_level, system_name, &cred,
1698 &credsize);
1699 break;
1700 #endif
1702 default:
1703 ret = _wapi_getsockopt (sock, system_level, system_name, &val,
1704 &valsize);
1707 if(ret==SOCKET_ERROR) {
1708 *error = WSAGetLastError ();
1709 return;
1712 switch(name) {
1713 case SocketOptionName_Linger:
1714 /* build a System.Net.Sockets.LingerOption */
1715 obj_class=mono_class_from_name(system_assembly,
1716 "System.Net.Sockets",
1717 "LingerOption");
1718 obj=mono_object_new(domain, obj_class);
1720 /* Locate and set the fields "bool enabled" and "int
1721 * seconds"
1723 field=mono_class_get_field_from_name(obj_class, "enabled");
1724 *(guint8 *)(((char *)obj)+field->offset)=linger.l_onoff;
1726 field=mono_class_get_field_from_name(obj_class, "seconds");
1727 *(guint32 *)(((char *)obj)+field->offset)=linger.l_linger;
1729 break;
1731 case SocketOptionName_DontLinger:
1732 /* construct a bool int in val - true if linger is off */
1733 obj = int_to_object (domain, !linger.l_onoff);
1734 break;
1736 case SocketOptionName_SendTimeout:
1737 case SocketOptionName_ReceiveTimeout:
1738 obj = int_to_object (domain, time_ms);
1739 break;
1741 #ifdef SO_PEERCRED
1742 case SocketOptionName_PeerCred:
1744 /* build a Mono.Posix.PeerCred+PeerCredData if
1745 * possible
1747 static MonoImage *mono_posix_image = NULL;
1748 MonoPeerCredData *cred_data;
1750 if (mono_posix_image == NULL) {
1751 mono_posix_image=mono_image_loaded ("Mono.Posix");
1752 if (!mono_posix_image) {
1753 MonoAssembly *sa = mono_assembly_open ("Mono.Posix.dll", NULL);
1754 if (!sa) {
1755 *error = WSAENOPROTOOPT;
1756 return;
1757 } else {
1758 mono_posix_image = mono_assembly_get_image (sa);
1763 obj_class = mono_class_from_name(mono_posix_image,
1764 "Mono.Posix",
1765 "PeerCredData");
1766 obj = mono_object_new(domain, obj_class);
1767 cred_data = (MonoPeerCredData *)obj;
1768 cred_data->pid = cred.pid;
1769 cred_data->uid = cred.uid;
1770 cred_data->gid = cred.gid;
1771 break;
1773 #endif
1775 default:
1776 obj = int_to_object (domain, val);
1779 *obj_val=obj;
1782 void ves_icall_System_Net_Sockets_Socket_GetSocketOption_arr_internal(SOCKET sock, gint32 level, gint32 name, MonoArray **byte_val, gint32 *error)
1784 int system_level;
1785 int system_name;
1786 int ret;
1787 guchar *buf;
1788 socklen_t valsize;
1790 MONO_ARCH_SAVE_REGS;
1792 *error = 0;
1794 ret=convert_sockopt_level_and_name(level, name, &system_level,
1795 &system_name);
1796 if(ret==-1) {
1797 *error = WSAENOPROTOOPT;
1798 return;
1800 if(ret==-2)
1801 return;
1803 valsize=mono_array_length(*byte_val);
1804 buf=mono_array_addr(*byte_val, guchar, 0);
1806 ret = _wapi_getsockopt (sock, system_level, system_name, buf, &valsize);
1807 if(ret==SOCKET_ERROR) {
1808 *error = WSAGetLastError ();
1812 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1813 static struct in_addr ipaddress_to_struct_in_addr(MonoObject *ipaddr)
1815 struct in_addr inaddr;
1816 MonoClassField *field;
1818 field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Address");
1820 /* No idea why .net uses a 64bit type to hold a 32bit value...
1822 * Internal value of IPAddess is in Network Order, there is no need
1823 * to call htonl here.
1825 inaddr.s_addr=(guint32)*(guint64 *)(((char *)ipaddr)+field->offset);
1827 return(inaddr);
1829 #endif
1831 #ifdef AF_INET6
1832 static struct in6_addr ipaddress_to_struct_in6_addr(MonoObject *ipaddr)
1834 struct in6_addr in6addr;
1835 MonoClassField *field;
1836 MonoArray *data;
1837 int i;
1839 field=mono_class_get_field_from_name(ipaddr->vtable->klass, "m_Numbers");
1840 data=*(MonoArray **)(((char *)ipaddr) + field->offset);
1842 /* Solaris has only the 8 bit version. */
1843 #ifndef s6_addr16
1844 for(i=0; i<8; i++) {
1845 guint16 s = mono_array_get (data, guint16, i);
1846 in6addr.s6_addr[2 * i] = (s >> 8) & 0xff;
1847 in6addr.s6_addr[2 * i + 1] = s & 0xff;
1849 #else
1850 for(i=0; i<8; i++)
1851 in6addr.s6_addr16[i] = mono_array_get (data, guint16, i);
1852 #endif
1853 return(in6addr);
1855 #endif /* AF_INET6 */
1857 void ves_icall_System_Net_Sockets_Socket_SetSocketOption_internal(SOCKET sock, gint32 level, gint32 name, MonoObject *obj_val, MonoArray *byte_val, gint32 int_val, gint32 *error)
1859 int system_level;
1860 int system_name;
1861 int ret;
1862 #ifdef AF_INET6
1863 int sol_ip;
1864 int sol_ipv6;
1866 *error = 0;
1868 #ifdef HAVE_SOL_IPV6
1869 sol_ipv6 = SOL_IPV6;
1870 #else
1872 struct protoent *pent;
1873 pent = getprotobyname ("ipv6");
1874 sol_ipv6 = (pent != NULL) ? pent->p_proto : 41;
1876 #endif
1878 #ifdef HAVE_SOL_IP
1879 sol_ip = SOL_IP;
1880 #else
1882 struct protoent *pent;
1883 pent = getprotobyname ("ip");
1884 sol_ip = (pent != NULL) ? pent->p_proto : 0;
1886 #endif
1887 #endif /* AF_INET6 */
1889 MONO_ARCH_SAVE_REGS;
1891 ret=convert_sockopt_level_and_name(level, name, &system_level,
1892 &system_name);
1893 if(ret==-1) {
1894 *error = WSAENOPROTOOPT;
1895 return;
1897 if(ret==-2){
1898 return;
1901 /* Only one of obj_val, byte_val or int_val has data */
1902 if(obj_val!=NULL) {
1903 MonoClassField *field;
1904 struct linger linger;
1905 int valsize;
1907 switch(name) {
1908 case SocketOptionName_DontLinger:
1909 linger.l_onoff=0;
1910 linger.l_linger=0;
1911 valsize=sizeof(linger);
1912 ret = _wapi_setsockopt (sock, system_level,
1913 system_name, &linger, valsize);
1914 break;
1916 case SocketOptionName_Linger:
1917 /* Dig out "bool enabled" and "int seconds"
1918 * fields
1920 field=mono_class_get_field_from_name(obj_val->vtable->klass, "enabled");
1921 linger.l_onoff=*(guint8 *)(((char *)obj_val)+field->offset);
1922 field=mono_class_get_field_from_name(obj_val->vtable->klass, "seconds");
1923 linger.l_linger=*(guint32 *)(((char *)obj_val)+field->offset);
1925 valsize=sizeof(linger);
1926 ret = _wapi_setsockopt (sock, system_level,
1927 system_name, &linger, valsize);
1928 break;
1929 case SocketOptionName_AddMembership:
1930 case SocketOptionName_DropMembership:
1931 #if defined(HAVE_STRUCT_IP_MREQN) || defined(HAVE_STRUCT_IP_MREQ)
1933 MonoObject *address = NULL;
1935 #ifdef AF_INET6
1936 if(system_level == sol_ipv6) {
1937 struct ipv6_mreq mreq6;
1940 * Get group address
1942 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1943 address = *(gpointer *)(((char *)obj_val) + field->offset);
1945 if(address) {
1946 mreq6.ipv6mr_multiaddr = ipaddress_to_struct_in6_addr (address);
1949 field=mono_class_get_field_from_name(obj_val->vtable->klass, "ifIndex");
1950 mreq6.ipv6mr_interface =*(guint64 *)(((char *)obj_val)+field->offset);
1952 ret = _wapi_setsockopt (sock, system_level,
1953 system_name, &mreq6,
1954 sizeof (mreq6));
1955 } else if(system_level == sol_ip)
1956 #endif /* AF_INET6 */
1958 #ifdef HAVE_STRUCT_IP_MREQN
1959 struct ip_mreqn mreq = {{0}};
1960 #else
1961 struct ip_mreq mreq = {{0}};
1962 #endif /* HAVE_STRUCT_IP_MREQN */
1964 /* pain! MulticastOption holds two IPAddress
1965 * members, so I have to dig the value out of
1966 * those :-(
1968 field = mono_class_get_field_from_name (obj_val->vtable->klass, "group");
1969 address = *(gpointer *)(((char *)obj_val) + field->offset);
1971 /* address might not be defined and if so, set the address to ADDR_ANY.
1973 if(address) {
1974 mreq.imr_multiaddr = ipaddress_to_struct_in_addr (address);
1977 field = mono_class_get_field_from_name (obj_val->vtable->klass, "local");
1978 address = *(gpointer *)(((char *)obj_val) + field->offset);
1980 #ifdef HAVE_STRUCT_IP_MREQN
1981 if(address) {
1982 mreq.imr_address = ipaddress_to_struct_in_addr (address);
1984 #else
1985 if(address) {
1986 mreq.imr_interface = ipaddress_to_struct_in_addr (address);
1988 #endif /* HAVE_STRUCT_IP_MREQN */
1990 ret = _wapi_setsockopt (sock, system_level,
1991 system_name, &mreq,
1992 sizeof (mreq));
1994 break;
1996 #endif /* HAVE_STRUCT_IP_MREQN || HAVE_STRUCT_IP_MREQ */
1997 default:
1998 /* Cause an exception to be thrown */
1999 *error = WSAEINVAL;
2000 return;
2002 } else if (byte_val!=NULL) {
2003 int valsize=mono_array_length(byte_val);
2004 guchar *buf=mono_array_addr(byte_val, guchar, 0);
2006 ret = _wapi_setsockopt (sock, system_level, system_name, buf, valsize);
2007 if(ret==SOCKET_ERROR) {
2008 *error = WSAGetLastError ();
2009 return;
2011 } else {
2012 /* ReceiveTimeout/SendTimeout get here */
2013 switch(name) {
2014 case SocketOptionName_DontFragment:
2015 #ifdef HAVE_IP_MTU_DISCOVER
2016 /* Fiddle with the value slightly if we're
2017 * turning DF on
2019 if (int_val == 1) {
2020 int_val = IP_PMTUDISC_DO;
2022 /* Fall through */
2023 #endif
2025 default:
2026 ret = _wapi_setsockopt (sock, system_level, system_name, (char *) &int_val, sizeof (int_val));
2030 if(ret==SOCKET_ERROR) {
2031 *error = WSAGetLastError ();
2035 void ves_icall_System_Net_Sockets_Socket_Shutdown_internal(SOCKET sock,
2036 gint32 how,
2037 gint32 *error)
2039 int ret;
2041 MONO_ARCH_SAVE_REGS;
2043 *error = 0;
2045 /* Currently, the values for how (recv=0, send=1, both=2) match
2046 * the BSD API
2048 ret = _wapi_shutdown (sock, how);
2049 if(ret==SOCKET_ERROR) {
2050 *error = WSAGetLastError ();
2054 gint
2055 ves_icall_System_Net_Sockets_Socket_WSAIoctl (SOCKET sock, gint32 code,
2056 MonoArray *input,
2057 MonoArray *output, gint32 *error)
2059 glong output_bytes = 0;
2060 gchar *i_buffer, *o_buffer;
2061 gint i_len, o_len;
2062 gint ret;
2064 MONO_ARCH_SAVE_REGS;
2066 *error = 0;
2068 if (code == FIONBIO) {
2069 /* Invalid command. Must use Socket.Blocking */
2070 return -1;
2073 if (input == NULL) {
2074 i_buffer = NULL;
2075 i_len = 0;
2076 } else {
2077 i_buffer = mono_array_addr (input, gchar, 0);
2078 i_len = mono_array_length (input);
2081 if (output == NULL) {
2082 o_buffer = NULL;
2083 o_len = 0;
2084 } else {
2085 o_buffer = mono_array_addr (output, gchar, 0);
2086 o_len = mono_array_length (output);
2089 ret = WSAIoctl (sock, code, i_buffer, i_len, o_buffer, o_len, &output_bytes, NULL, NULL);
2090 if (ret == SOCKET_ERROR) {
2091 *error = WSAGetLastError ();
2092 return(-1);
2095 return (gint) output_bytes;
2098 #ifdef HAVE_SIOCGIFCONF
2099 static gboolean
2100 is_loopback (int family, void *ad)
2102 char *ptr = (char *) ad;
2104 if (family == AF_INET) {
2105 return (ptr [0] == 127);
2107 #ifdef AF_INET6
2108 else {
2109 return (IN6_IS_ADDR_LOOPBACK ((struct in6_addr *) ptr));
2111 #endif
2112 return FALSE;
2115 static void *
2116 get_local_ips (int family, int *nips)
2118 int addr_size, offset, fd, i, count;
2119 int max_ifaces = 50; /* 50 interfaces should be enough... */
2120 struct ifconf ifc;
2121 struct ifreq *ifr;
2122 struct ifreq iflags;
2123 char *result, *tmp_ptr;
2124 gboolean ignore_loopback = FALSE;
2126 *nips = 0;
2127 if (family == AF_INET) {
2128 addr_size = sizeof (struct in_addr);
2129 offset = G_STRUCT_OFFSET (struct sockaddr_in, sin_addr);
2130 #ifdef AF_INET6
2131 } else if (family == AF_INET6) {
2132 addr_size = sizeof (struct in6_addr);
2133 offset = G_STRUCT_OFFSET (struct sockaddr_in6, sin6_addr);
2134 #endif
2135 } else {
2136 return NULL;
2139 fd = socket (family, SOCK_STREAM, 0);
2141 ifc.ifc_len = max_ifaces * sizeof (struct ifreq);
2142 ifc.ifc_buf = g_malloc (ifc.ifc_len);
2143 if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
2144 close (fd);
2145 g_free (ifc.ifc_buf);
2146 return NULL;
2149 count = ifc.ifc_len / sizeof (struct ifreq);
2150 *nips = count;
2151 if (count == 0) {
2152 g_free (ifc.ifc_buf);
2153 close (fd);
2154 return NULL;
2157 for (i = 0, ifr = ifc.ifc_req; i < *nips; i++, ifr++) {
2158 strcpy (iflags.ifr_name, ifr->ifr_name);
2159 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
2160 continue;
2163 if ((iflags.ifr_flags & IFF_UP) == 0) {
2164 ifr->ifr_name [0] = '\0';
2165 continue;
2168 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
2169 ignore_loopback = TRUE;
2173 close (fd);
2174 result = g_malloc (addr_size * count);
2175 tmp_ptr = result;
2176 for (i = 0, ifr = ifc.ifc_req; i < count; i++, ifr++) {
2177 if (ifr->ifr_name [0] == '\0') {
2178 (*nips)--;
2179 continue;
2182 if (ignore_loopback && is_loopback (family, ((char *) &ifr->ifr_addr) + offset)) {
2183 (*nips)--;
2184 continue;
2187 memcpy (tmp_ptr, ((char *) &ifr->ifr_addr) + offset, addr_size);
2188 tmp_ptr += addr_size;
2191 g_free (ifc.ifc_buf);
2192 return result;
2194 #else
2195 static void *
2196 get_local_ips (int family, int *nips)
2198 *nips = 0;
2199 return NULL;
2202 #endif /* HAVE_SIOCGIFCONF */
2204 #ifndef AF_INET6
2205 static gboolean hostent_to_IPHostEntry(struct hostent *he, MonoString **h_name,
2206 MonoArray **h_aliases,
2207 MonoArray **h_addr_list,
2208 gboolean add_local_ips)
2210 MonoDomain *domain = mono_domain_get ();
2211 int i;
2212 struct in_addr *local_in = NULL;
2213 int nlocal_in = 0;
2215 if(he->h_length!=4 || he->h_addrtype!=AF_INET) {
2216 return(FALSE);
2219 *h_name=mono_string_new(domain, he->h_name);
2221 i=0;
2222 while(he->h_aliases[i]!=NULL) {
2223 i++;
2226 *h_aliases=mono_array_new(domain, mono_get_string_class (), i);
2227 i=0;
2228 while(he->h_aliases[i]!=NULL) {
2229 MonoString *alias;
2231 alias=mono_string_new(domain, he->h_aliases[i]);
2232 mono_array_setref (*h_aliases, i, alias);
2233 i++;
2236 if (add_local_ips) {
2237 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2238 if (nlocal_in) {
2239 *h_addr_list = mono_array_new(domain, mono_get_string_class (), nlocal_in);
2240 for (i = 0; i < nlocal_in; i++) {
2241 MonoString *addr_string;
2242 char addr [16], *ptr;
2244 ptr = (char *) &local_in [i];
2245 g_snprintf(addr, 16, "%u.%u.%u.%u",
2246 (unsigned char) ptr [0],
2247 (unsigned char) ptr [1],
2248 (unsigned char) ptr [2],
2249 (unsigned char) ptr [3]);
2251 addr_string = mono_string_new (domain, addr);
2252 mono_array_setref (*h_addr_list, i, addr_string);
2253 i++;
2256 g_free (local_in);
2260 if (nlocal_in == 0) {
2261 i = 0;
2262 while (he->h_addr_list[i]!=NULL) {
2263 i++;
2266 *h_addr_list=mono_array_new(domain, mono_get_string_class (), i);
2267 i=0;
2268 while(he->h_addr_list[i]!=NULL) {
2269 MonoString *addr_string;
2270 char addr[16];
2272 g_snprintf(addr, 16, "%u.%u.%u.%u",
2273 (unsigned char)he->h_addr_list[i][0],
2274 (unsigned char)he->h_addr_list[i][1],
2275 (unsigned char)he->h_addr_list[i][2],
2276 (unsigned char)he->h_addr_list[i][3]);
2278 addr_string=mono_string_new(domain, addr);
2279 mono_array_setref (*h_addr_list, i, addr_string);
2280 i++;
2284 return(TRUE);
2287 static gboolean ipaddr_to_IPHostEntry(const char *addr, MonoString **h_name,
2288 MonoArray **h_aliases,
2289 MonoArray **h_addr_list)
2291 MonoDomain *domain = mono_domain_get ();
2293 *h_name=mono_string_new(domain, addr);
2294 *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2295 *h_addr_list=mono_array_new(domain, mono_get_string_class (), 1);
2296 mono_array_setref (*h_addr_list, 0, *h_name);
2298 return(TRUE);
2300 #endif
2302 #if defined(AF_INET6) && defined(HAVE_GETHOSTBYNAME2_R)
2303 static gboolean hostent_to_IPHostEntry2(struct hostent *he1,struct hostent *he2, MonoString **h_name,
2304 MonoArray **h_aliases, MonoArray **h_addr_list, gboolean add_local_ips)
2306 MonoDomain *domain = mono_domain_get ();
2307 int i, host_count, host_index, family_hint;
2308 struct in_addr *local_in = NULL;
2309 int nlocal_in = 0;
2310 struct in6_addr *local_in6 = NULL;
2311 int nlocal_in6 = 0;
2312 gboolean from_local = FALSE;
2314 family_hint = get_family_hint ();
2316 if(he1 == NULL && he2 == NULL) {
2317 return(FALSE);
2321 * Check if address length and family are correct
2323 if (he1 != NULL && (he1->h_length!=4 || he1->h_addrtype!=AF_INET)) {
2324 return(FALSE);
2327 if (he2 != NULL && (he2->h_length!=16 || he2->h_addrtype!=AF_INET6)) {
2328 return(FALSE);
2332 * Get the aliases and host name from he1 or he2 whichever is
2333 * not null, if he1 is not null then take aliases from he1
2335 if (he1 != NULL && (family_hint == PF_UNSPEC ||
2336 family_hint == PF_INET)) {
2337 *h_name=mono_string_new (domain, he1->h_name);
2339 i=0;
2340 while(he1->h_aliases[i]!=NULL) {
2341 i++;
2344 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2346 i=0;
2347 while(he1->h_aliases[i]!=NULL) {
2348 MonoString *alias;
2350 alias=mono_string_new (domain, he1->h_aliases[i]);
2351 mono_array_setref (*h_aliases, i, alias);
2352 i++;
2354 } else if (he2 != NULL && (family_hint == PF_UNSPEC ||
2355 family_hint == PF_INET6)) {
2356 *h_name=mono_string_new (domain, he2->h_name);
2358 i=0;
2359 while(he2->h_aliases [i] != NULL) {
2360 i++;
2363 *h_aliases=mono_array_new (domain, mono_get_string_class (),
2365 i=0;
2366 while(he2->h_aliases[i]!=NULL) {
2367 MonoString *alias;
2369 alias=mono_string_new (domain, he2->h_aliases[i]);
2370 mono_array_setref (*h_aliases, i, alias);
2371 i++;
2373 } else {
2374 return(FALSE);
2378 * Count the number of addresses in he1 + he2
2380 host_count = 0;
2381 if (he1 != NULL && (family_hint == PF_UNSPEC ||
2382 family_hint == PF_INET)) {
2383 i=0;
2384 while(he1->h_addr_list[i]!=NULL) {
2385 i++;
2386 host_count++;
2390 if (he2 != NULL && (family_hint == PF_UNSPEC ||
2391 family_hint == PF_INET6)) {
2392 i=0;
2393 while(he2->h_addr_list[i]!=NULL) {
2394 i++;
2395 host_count++;
2400 * Fills the array
2402 host_index = 0;
2403 if (add_local_ips) {
2404 if (family_hint == PF_UNSPEC || family_hint == PF_INET)
2405 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2407 if (family_hint == PF_UNSPEC || family_hint == PF_INET6)
2408 local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2410 if (nlocal_in || nlocal_in6) {
2411 from_local = TRUE;
2412 *h_addr_list = mono_array_new (domain, mono_get_string_class (),
2413 nlocal_in + nlocal_in6);
2415 if (nlocal_in6) {
2416 int n;
2417 for (n = 0; n < nlocal_in6; n++) {
2418 MonoString *addr_string;
2419 const char *ret;
2420 char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes with the trailing NULL */
2422 ret = inet_ntop (AF_INET6, &local_in6 [n], addr, sizeof(addr));
2424 if (ret != NULL) {
2425 addr_string = mono_string_new (domain, addr);
2426 mono_array_setref (*h_addr_list, host_index, addr_string);
2427 host_index++;
2432 if (nlocal_in) {
2433 int n;
2434 for (n = 0; n < nlocal_in; n++) {
2435 MonoString *addr_string;
2436 const char *ret;
2437 char addr[16]; /* INET_ADDRSTRLEN == 16 */
2439 ret = inet_ntop (AF_INET, &local_in [n], addr, sizeof(addr));
2441 if (ret != NULL) {
2442 addr_string = mono_string_new (domain, addr);
2443 mono_array_setref (*h_addr_list, host_index, addr_string);
2444 host_index++;
2448 g_free (local_in);
2449 g_free (local_in6);
2450 return TRUE;
2453 g_free (local_in);
2454 g_free (local_in6);
2457 *h_addr_list=mono_array_new (domain, mono_get_string_class (), host_count);
2459 if (he2 != NULL && (family_hint == PF_UNSPEC ||
2460 family_hint == PF_INET6)) {
2461 i = 0;
2462 while(he2->h_addr_list[i] != NULL) {
2463 MonoString *addr_string;
2464 const char *ret;
2465 char addr[48]; /* INET6_ADDRSTRLEN == 46, but IPv6 addresses can be 48 bytes long with the trailing NULL */
2467 ret = inet_ntop (AF_INET6, he2->h_addr_list[i], addr,
2468 sizeof(addr));
2470 if (ret != NULL) {
2471 addr_string = mono_string_new (domain, addr);
2472 mono_array_setref (*h_addr_list, host_index, addr_string);
2473 i++;
2474 host_index++;
2479 if (he1 != NULL && (family_hint == PF_UNSPEC ||
2480 family_hint == PF_INET)) {
2481 i=0;
2482 while(he1->h_addr_list[i] != NULL) {
2483 MonoString *addr_string;
2484 const char *ret;
2485 char addr[16]; /* INET_ADDRSTRLEN == 16 */
2487 ret = inet_ntop (AF_INET, he1->h_addr_list[i], addr,
2488 sizeof(addr));
2490 if (ret != NULL) {
2491 addr_string=mono_string_new (domain, addr);
2492 mono_array_setref (*h_addr_list, host_index, addr_string);
2493 i++;
2494 host_index++;
2499 return(TRUE);
2501 #endif
2503 #if defined(AF_INET6)
2504 static gboolean
2505 addrinfo_to_IPHostEntry(struct addrinfo *info, MonoString **h_name,
2506 MonoArray **h_aliases,
2507 MonoArray **h_addr_list,
2508 gboolean add_local_ips)
2510 gint32 count, i;
2511 struct addrinfo *ai = NULL;
2512 struct in_addr *local_in = NULL;
2513 int nlocal_in = 0;
2514 struct in6_addr *local_in6 = NULL;
2515 int nlocal_in6 = 0;
2516 int addr_index;
2518 MonoDomain *domain = mono_domain_get ();
2520 addr_index = 0;
2521 *h_aliases=mono_array_new(domain, mono_get_string_class (), 0);
2522 if (add_local_ips) {
2523 local_in = (struct in_addr *) get_local_ips (AF_INET, &nlocal_in);
2524 local_in6 = (struct in6_addr *) get_local_ips (AF_INET6, &nlocal_in6);
2525 if (nlocal_in || nlocal_in6) {
2526 *h_addr_list=mono_array_new(domain, mono_get_string_class (), nlocal_in + nlocal_in6);
2527 if (nlocal_in) {
2528 MonoString *addr_string;
2529 char addr [16];
2530 int i;
2532 for (i = 0; i < nlocal_in; i++) {
2533 inet_ntop (AF_INET, &local_in [i], addr, sizeof (addr));
2534 addr_string = mono_string_new (domain, addr);
2535 mono_array_setref (*h_addr_list, addr_index, addr_string);
2536 addr_index++;
2540 if (nlocal_in6) {
2541 MonoString *addr_string;
2542 const char *ret;
2543 char addr [48];
2544 int i;
2546 for (i = 0; i < nlocal_in6; i++) {
2547 ret = inet_ntop (AF_INET6, &local_in6 [i], addr, sizeof (addr));
2548 if (ret != NULL) {
2549 addr_string = mono_string_new (domain, addr);
2550 mono_array_setref (*h_addr_list, addr_index, addr_string);
2551 addr_index++;
2556 g_free (local_in);
2557 g_free (local_in6);
2558 if (info) {
2559 freeaddrinfo (info);
2561 return TRUE;
2564 g_free (local_in);
2565 g_free (local_in6);
2568 for (count=0, ai=info; ai!=NULL; ai=ai->ai_next) {
2569 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
2570 continue;
2572 count++;
2575 *h_addr_list=mono_array_new(domain, mono_get_string_class (), count);
2577 for (ai=info, i=0; ai!=NULL; ai=ai->ai_next) {
2578 MonoString *addr_string;
2579 const char *ret;
2580 char buffer [48]; /* Max. size for IPv6 */
2582 if((ai->ai_family != PF_INET) && (ai->ai_family != PF_INET6)) {
2583 continue;
2586 if(ai->ai_family == PF_INET) {
2587 ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in*)ai->ai_addr)->sin_addr), buffer, 16);
2588 } else {
2589 ret = inet_ntop(ai->ai_family, (void*)&(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr), buffer, 48);
2592 if(ret) {
2593 addr_string=mono_string_new(domain, buffer);
2594 } else {
2595 addr_string=mono_string_new(domain, "");
2598 mono_array_setref (*h_addr_list, addr_index, addr_string);
2600 if(!i && ai->ai_canonname != NULL) {
2601 *h_name=mono_string_new(domain, ai->ai_canonname);
2604 addr_index++;
2607 if(info) {
2608 freeaddrinfo(info);
2611 return(TRUE);
2613 #endif
2615 #ifdef AF_INET6
2616 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2618 gboolean add_local_ips = FALSE;
2619 #ifdef HAVE_SIOCGIFCONF
2620 gchar this_hostname [256];
2621 #endif
2622 #if !defined(HAVE_GETHOSTBYNAME2_R)
2623 struct addrinfo *info = NULL, hints;
2624 char *hostname;
2626 MONO_ARCH_SAVE_REGS;
2628 hostname=mono_string_to_utf8 (host);
2629 #ifdef HAVE_SIOCGIFCONF
2630 if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2631 if (!strcmp (hostname, this_hostname))
2632 add_local_ips = TRUE;
2634 #endif
2636 memset(&hints, 0, sizeof(hints));
2637 hints.ai_family = get_family_hint ();
2638 hints.ai_socktype = SOCK_STREAM;
2639 hints.ai_flags = AI_CANONNAME;
2641 if (getaddrinfo(hostname, NULL, &hints, &info) == -1) {
2642 return(FALSE);
2645 g_free(hostname);
2647 return(addrinfo_to_IPHostEntry(info, h_name, h_aliases, h_addr_list, add_local_ips));
2648 #else
2649 struct hostent he1,*hp1, he2, *hp2;
2650 int buffer_size1, buffer_size2;
2651 char *buffer1, *buffer2;
2652 int herr;
2653 gboolean return_value;
2654 char *hostname;
2656 MONO_ARCH_SAVE_REGS;
2658 hostname=mono_string_to_utf8 (host);
2660 #ifdef HAVE_SIOCGIFCONF
2661 if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2662 if (!strcmp (hostname, this_hostname))
2663 add_local_ips = TRUE;
2665 #endif
2667 buffer_size1 = 512;
2668 buffer_size2 = 512;
2669 buffer1 = g_malloc0(buffer_size1);
2670 buffer2 = g_malloc0(buffer_size2);
2672 while (gethostbyname2_r(hostname, AF_INET, &he1, buffer1, buffer_size1,
2673 &hp1, &herr) == ERANGE) {
2674 buffer_size1 *= 2;
2675 buffer1 = g_realloc(buffer1, buffer_size1);
2678 if (hp1 == NULL)
2680 while (gethostbyname2_r(hostname, AF_INET6, &he2, buffer2,
2681 buffer_size2, &hp2, &herr) == ERANGE) {
2682 buffer_size2 *= 2;
2683 buffer2 = g_realloc(buffer2, buffer_size2);
2686 else
2687 hp2 = NULL;
2689 return_value = hostent_to_IPHostEntry2(hp1, hp2, h_name, h_aliases,
2690 h_addr_list, add_local_ips);
2692 g_free(buffer1);
2693 g_free(buffer2);
2694 g_free(hostname);
2696 return(return_value);
2697 #endif /* HAVE_GETHOSTBYNAME2_R */
2699 #else /* AF_INET6 */
2700 MonoBoolean ves_icall_System_Net_Dns_GetHostByName_internal(MonoString *host, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2702 struct hostent *he;
2703 char *hostname;
2704 gboolean add_local_ips = FALSE;
2705 #ifdef HAVE_SIOCGIFCONF
2706 gchar this_hostname [256];
2707 #endif
2709 MONO_ARCH_SAVE_REGS;
2711 hostname=mono_string_to_utf8(host);
2712 #ifdef HAVE_SIOCGIFCONF
2713 if (gethostname (this_hostname, sizeof (this_hostname)) != -1) {
2714 if (!strcmp (hostname, this_hostname))
2715 add_local_ips = TRUE;
2717 #endif
2719 he = _wapi_gethostbyname (hostname);
2720 g_free(hostname);
2722 if(he==NULL) {
2723 return(FALSE);
2726 return(hostent_to_IPHostEntry(he, h_name, h_aliases, h_addr_list, add_local_ips));
2728 #endif /* AF_INET6 */
2730 #ifndef HAVE_INET_PTON
2731 static int
2732 inet_pton (int family, const char *address, void *inaddrp)
2734 if (family == AF_INET) {
2735 #ifdef HAVE_INET_ATON
2736 struct in_addr inaddr;
2738 if (!inet_aton (address, &inaddr))
2739 return 0;
2741 memcpy (inaddrp, &inaddr, sizeof (struct in_addr));
2742 return 1;
2743 #else
2744 /* assume the system has inet_addr(), if it doesn't
2745 have that we're pretty much screwed... */
2746 guint32 inaddr;
2748 if (!strcmp (address, "255.255.255.255")) {
2749 /* special-case hack */
2750 inaddr = 0xffffffff;
2751 } else {
2752 inaddr = inet_addr (address);
2753 #ifndef INADDR_NONE
2754 #define INADDR_NONE ((in_addr_t) -1)
2755 #endif
2756 if (inaddr == INADDR_NONE)
2757 return 0;
2760 memcpy (inaddrp, &inaddr, sizeof (guint32));
2761 return 1;
2762 #endif /* HAVE_INET_ATON */
2765 return -1;
2767 #endif /* !HAVE_INET_PTON */
2769 extern MonoBoolean ves_icall_System_Net_Dns_GetHostByAddr_internal(MonoString *addr, MonoString **h_name, MonoArray **h_aliases, MonoArray **h_addr_list)
2771 char *address;
2772 const char *version;
2773 gboolean v1;
2775 #ifdef AF_INET6
2776 struct sockaddr_in saddr;
2777 struct sockaddr_in6 saddr6;
2778 struct addrinfo *info = NULL, hints;
2779 gint32 family;
2780 char hostname[1024] = {0};
2781 int flags = 0;
2782 #else
2783 struct in_addr inaddr;
2784 struct hostent *he;
2785 gboolean ret;
2786 #endif
2788 MONO_ARCH_SAVE_REGS;
2790 version = mono_get_runtime_info ()->framework_version;
2791 v1 = (version[0] == '1');
2793 address = mono_string_to_utf8 (addr);
2795 #ifdef AF_INET6
2796 if (inet_pton (AF_INET, address, &saddr.sin_addr ) <= 0) {
2797 /* Maybe an ipv6 address */
2798 if (inet_pton (AF_INET6, address, &saddr6.sin6_addr) <= 0) {
2799 g_free (address);
2800 return FALSE;
2802 else {
2803 family = AF_INET6;
2804 saddr6.sin6_family = AF_INET6;
2807 else {
2808 family = AF_INET;
2809 saddr.sin_family = AF_INET;
2811 g_free(address);
2813 if (v1) {
2814 flags = NI_NAMEREQD;
2817 if(family == AF_INET) {
2818 if(getnameinfo ((struct sockaddr*)&saddr, sizeof(saddr),
2819 hostname, sizeof(hostname), NULL, 0,
2820 flags) != 0) {
2821 return(FALSE);
2823 } else if(family == AF_INET6) {
2824 if(getnameinfo ((struct sockaddr*)&saddr6, sizeof(saddr6),
2825 hostname, sizeof(hostname), NULL, 0,
2826 flags) != 0) {
2827 return(FALSE);
2831 memset (&hints, 0, sizeof(hints));
2832 hints.ai_family = get_family_hint ();
2833 hints.ai_socktype = SOCK_STREAM;
2834 hints.ai_flags = AI_CANONNAME;
2836 if( getaddrinfo (hostname, NULL, &hints, &info) == -1 ) {
2837 return(FALSE);
2840 return(addrinfo_to_IPHostEntry (info, h_name, h_aliases, h_addr_list, FALSE));
2841 #else
2842 if (inet_pton (AF_INET, address, &inaddr) <= 0) {
2843 g_free (address);
2844 return(FALSE);
2847 if ((he = gethostbyaddr ((char *) &inaddr, sizeof (inaddr), AF_INET)) == NULL) {
2848 if (v1) {
2849 ret = FALSE;
2850 } else {
2851 ret = ipaddr_to_IPHostEntry (address, h_name,
2852 h_aliases, h_addr_list);
2854 } else {
2855 ret = hostent_to_IPHostEntry (he, h_name, h_aliases,
2856 h_addr_list, FALSE);
2859 g_free (address);
2860 return(ret);
2861 #endif
2864 extern MonoBoolean ves_icall_System_Net_Dns_GetHostName_internal(MonoString **h_name)
2866 gchar hostname[256];
2867 int ret;
2869 MONO_ARCH_SAVE_REGS;
2871 ret = gethostname (hostname, sizeof (hostname));
2872 if(ret==-1) {
2873 return(FALSE);
2876 *h_name=mono_string_new(mono_domain_get (), hostname);
2878 return(TRUE);
2881 void mono_network_init(void)
2883 WSADATA wsadata;
2884 int err;
2886 err=WSAStartup(MAKEWORD(2,0), &wsadata);
2887 if(err!=0) {
2888 g_error(G_GNUC_PRETTY_FUNCTION ": Couldn't initialise networking");
2889 exit(-1);
2892 #ifdef DEBUG
2893 g_message(G_GNUC_PRETTY_FUNCTION ": Using socket library: %s", wsadata.szDescription);
2894 g_message(G_GNUC_PRETTY_FUNCTION ": Socket system status: %s", wsadata.szSystemStatus);
2895 #endif
2898 void mono_network_cleanup(void)
2900 WSACleanup();