2 * networking-posix.c: Modern posix networking code
5 * Rodrigo Kumpera (kumpera@gmail.com)
10 #include <mono/utils/networking.h>
16 #ifdef HAVE_SYS_IOCTL_H
17 #include <sys/ioctl.h>
25 #ifdef HAVE_GETIFADDRS
30 get_address_from_sockaddr (struct sockaddr
*sa
)
32 switch (sa
->sa_family
) {
34 return &((struct sockaddr_in
*)sa
)->sin_addr
;
36 return &((struct sockaddr_in6
*)sa
)->sin6_addr
;
41 #ifdef HAVE_GETADDRINFO
44 mono_get_address_info (const char *hostname
, int port
, int flags
, MonoAddressInfo
**result
)
46 char service_name
[16];
47 struct addrinfo hints
, *res
= NULL
, *info
;
48 MonoAddressEntry
*cur
= NULL
, *prev
= NULL
;
49 MonoAddressInfo
*addr_info
;
51 memset (&hints
, 0, sizeof (struct addrinfo
));
54 hints
.ai_family
= PF_UNSPEC
;
55 if (flags
& MONO_HINT_IPV4
)
56 hints
.ai_family
= PF_INET
;
57 else if (flags
& MONO_HINT_IPV6
)
58 hints
.ai_family
= PF_INET6
;
60 hints
.ai_socktype
= SOCK_STREAM
;
62 if (flags
& MONO_HINT_CANONICAL_NAME
)
63 hints
.ai_flags
= AI_CANONNAME
;
65 /* Some ancient libc don't define AI_ADDRCONFIG */
67 if (flags
& MONO_HINT_CONFIGURED_ONLY
)
68 hints
.ai_flags
= AI_ADDRCONFIG
;
70 sprintf (service_name
, "%d", port
);
71 if (getaddrinfo (hostname
, service_name
, &hints
, &info
))
72 return 1; /* FIXME propagate the error */
75 *result
= addr_info
= g_new0 (MonoAddressInfo
, 1);
78 cur
= g_new0 (MonoAddressEntry
, 1);
82 addr_info
->entries
= cur
;
84 cur
->family
= res
->ai_family
;
85 cur
->socktype
= res
->ai_socktype
;
86 cur
->protocol
= res
->ai_protocol
;
87 if (cur
->family
== PF_INET
) {
88 cur
->address_len
= sizeof (struct in_addr
);
89 cur
->address
.v4
= ((struct sockaddr_in
*)res
->ai_addr
)->sin_addr
;
90 } else if (cur
->family
== PF_INET6
) {
91 cur
->address_len
= sizeof (struct in6_addr
);
92 cur
->address
.v6
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
94 g_error ("Cannot handle address family %d", cur
->family
);
97 if (res
->ai_canonname
)
98 cur
->canonical_name
= g_strdup (res
->ai_canonname
);
110 #ifdef HAVE_GETPROTOBYNAME
113 fetch_protocol (const char *proto_name
, int *cache
, int *proto
, int default_val
)
116 struct protoent
*pent
;
118 pent
= getprotobyname (proto_name
);
119 *proto
= pent
? pent
->p_proto
: default_val
;
126 mono_networking_get_tcp_protocol (void)
128 static int cache
, proto
;
129 return fetch_protocol ("tcp", &cache
, &proto
, 6); //6 is SOL_TCP on linux
133 mono_networking_get_ip_protocol (void)
135 static int cache
, proto
;
136 return fetch_protocol ("ip", &cache
, &proto
, 0); //0 is SOL_IP on linux
140 mono_networking_get_ipv6_protocol (void)
142 static int cache
, proto
;
143 return fetch_protocol ("ipv6", &cache
, &proto
, 41); //41 is SOL_IPV6 on linux
148 #if defined (HAVE_SIOCGIFCONF)
150 #define IFCONF_BUFF_SIZE 1024
151 #ifndef _SIZEOF_ADDR_IFREQ
152 #define _SIZEOF_ADDR_IFREQ(ifr) (sizeof (struct ifreq))
155 #define FOREACH_IFR(IFR, IFC) \
156 for (IFR = (IFC).ifc_req; \
157 ifr < (struct ifreq*)((char*)(IFC).ifc_req + (IFC).ifc_len); \
158 ifr = (struct ifreq*)((char*)(IFR) + _SIZEOF_ADDR_IFREQ (*(IFR))))
161 mono_get_local_interfaces (int family
, int *interface_count
)
167 gboolean ignore_loopback
= FALSE
;
171 *interface_count
= 0;
173 if (!mono_address_size_for_family (family
))
176 fd
= socket (family
, SOCK_STREAM
, 0);
180 memset (&ifc
, 0, sizeof (ifc
));
181 ifc
.ifc_len
= IFCONF_BUFF_SIZE
;
182 ifc
.ifc_buf
= g_malloc (IFCONF_BUFF_SIZE
); /* We can't have such huge buffers on the stack. */
183 if (ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0)
186 FOREACH_IFR (ifr
, ifc
) {
189 //only return addresses of the same type as @family
190 if (ifr
->ifr_addr
.sa_family
!= family
) {
191 ifr
->ifr_name
[0] = '\0';
195 strcpy (iflags
.ifr_name
, ifr
->ifr_name
);
197 //ignore interfaces we can't get props for
198 if (ioctl (fd
, SIOCGIFFLAGS
, &iflags
) < 0) {
199 ifr
->ifr_name
[0] = '\0';
203 //ignore interfaces that are down
204 if ((iflags
.ifr_flags
& IFF_UP
) == 0) {
205 ifr
->ifr_name
[0] = '\0';
209 //If we have a non-loopback iface, don't return any loopback
210 if ((iflags
.ifr_flags
& IFF_LOOPBACK
) == 0) {
211 ignore_loopback
= TRUE
;
212 ifr
->ifr_name
[0] = 1;//1 means non-loopback
214 ifr
->ifr_name
[0] = 2; //2 means loopback
219 result_ptr
= result
= g_malloc (if_count
* mono_address_size_for_family (family
));
220 FOREACH_IFR (ifr
, ifc
) {
221 if (ifr
->ifr_name
[0] == '\0')
224 if (ignore_loopback
&& ifr
->ifr_name
[0] == 2) {
229 memcpy (result_ptr
, get_address_from_sockaddr (&ifr
->ifr_addr
), mono_address_size_for_family (family
));
230 result_ptr
+= mono_address_size_for_family (family
);
232 g_assert (result_ptr
<= (char*)result
+ if_count
* mono_address_size_for_family (family
));
235 *interface_count
= if_count
;
236 g_free (ifc
.ifc_buf
);
241 #elif defined(HAVE_GETIFADDRS)
244 mono_get_local_interfaces (int family
, int *interface_count
)
246 struct ifaddrs
*ifap
= NULL
, *cur
;
248 gboolean ignore_loopback
= FALSE
;
252 *interface_count
= 0;
254 if (!mono_address_size_for_family (family
))
257 if (getifaddrs (&ifap
))
260 for (cur
= ifap
; cur
; cur
= cur
->ifa_next
) {
261 //ignore interfaces with no address assigned
265 //ignore interfaces that don't belong to @family
266 if (cur
->ifa_addr
->sa_family
!= family
)
269 //ignore interfaces that are down
270 if ((cur
->ifa_flags
& IFF_UP
) == 0)
273 //If we have a non-loopback iface, don't return any loopback
274 if ((cur
->ifa_flags
& IFF_LOOPBACK
) == 0)
275 ignore_loopback
= TRUE
;
280 result_ptr
= result
= g_malloc (if_count
* mono_address_size_for_family (family
));
281 for (cur
= ifap
; cur
; cur
= cur
->ifa_next
) {
284 if (cur
->ifa_addr
->sa_family
!= family
)
286 if ((cur
->ifa_flags
& IFF_UP
) == 0)
289 //we decrement if_count because it did not on the previous loop.
290 if (ignore_loopback
&& (cur
->ifa_flags
& IFF_LOOPBACK
)) {
295 memcpy (result_ptr
, get_address_from_sockaddr (cur
->ifa_addr
), mono_address_size_for_family (family
));
296 result_ptr
+= mono_address_size_for_family (family
);
298 g_assert (result_ptr
<= (char*)result
+ if_count
* mono_address_size_for_family (family
));
301 *interface_count
= if_count
;
307 #ifdef HAVE_GETNAMEINFO
310 mono_networking_addr_to_str (MonoAddress
*address
, char *buffer
, socklen_t buflen
)
312 MonoSocketAddress saddr
;
314 mono_socket_address_init (&saddr
, &len
, address
->family
, &address
->addr
, 0);
316 return getnameinfo (&saddr
.addr
, len
, buffer
, buflen
, NULL
, 0, NI_NUMERICHOST
) == 0;
322 mono_networking_addr_to_str (MonoAddress
*address
, char *buffer
, socklen_t buflen
)
324 return inet_ntop (address
->family
, &address
->addr
, buffer
, buflen
) != NULL
;
330 // These are already defined in networking-windows.c for Windows
332 mono_networking_init (void)
338 mono_networking_shutdown (void)