2 * networking-posix.c: Modern posix networking code
5 * Rodrigo Kumpera (kumpera@gmail.com)
11 #include <mono/utils/networking.h>
17 #ifdef HAVE_SYS_IOCTL_H
18 #include <sys/ioctl.h>
23 #ifdef HAVE_SYS_SOCKIO_H
24 #include <sys/sockio.h>
29 #ifdef HAVE_GETIFADDRS
35 get_address_size_by_family (int family
)
39 return sizeof (struct in_addr
);
41 return sizeof (struct in6_addr
);
47 get_address_from_sockaddr (struct sockaddr
*sa
)
49 switch (sa
->sa_family
) {
51 return &((struct sockaddr_in
*)sa
)->sin_addr
;
53 return &((struct sockaddr_in6
*)sa
)->sin6_addr
;
58 #ifdef HAVE_GETADDRINFO
61 mono_get_address_info (const char *hostname
, int port
, int flags
, MonoAddressInfo
**result
)
63 char service_name
[16];
64 struct addrinfo hints
, *res
= NULL
, *info
;
65 MonoAddressEntry
*cur
= NULL
, *prev
= NULL
;
66 MonoAddressInfo
*addr_info
;
68 memset (&hints
, 0, sizeof (struct addrinfo
));
71 hints
.ai_family
= PF_UNSPEC
;
72 if (flags
& MONO_HINT_IPV4
)
73 hints
.ai_family
= PF_INET
;
74 else if (flags
& MONO_HINT_IPV6
)
75 hints
.ai_family
= PF_INET6
;
77 hints
.ai_socktype
= SOCK_STREAM
;
79 if (flags
& MONO_HINT_CANONICAL_NAME
)
80 hints
.ai_flags
= AI_CANONNAME
;
82 /* Some ancient libc don't define AI_ADDRCONFIG */
84 if (flags
& MONO_HINT_CONFIGURED_ONLY
)
85 hints
.ai_flags
= AI_ADDRCONFIG
;
87 sprintf (service_name
, "%d", port
);
88 if (getaddrinfo (hostname
, service_name
, &hints
, &info
))
89 return 1; /* FIXME propagate the error */
92 *result
= addr_info
= g_new0 (MonoAddressInfo
, 1);
95 cur
= g_new0 (MonoAddressEntry
, 1);
99 addr_info
->entries
= cur
;
101 cur
->family
= res
->ai_family
;
102 cur
->socktype
= res
->ai_socktype
;
103 cur
->protocol
= res
->ai_protocol
;
104 if (cur
->family
== PF_INET
) {
105 cur
->address_len
= sizeof (struct in_addr
);
106 cur
->address
.v4
= ((struct sockaddr_in
*)res
->ai_addr
)->sin_addr
;
107 } else if (cur
->family
== PF_INET6
) {
108 cur
->address_len
= sizeof (struct in6_addr
);
109 cur
->address
.v6
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
111 g_error ("Cannot handle address family %d", cur
->family
);
114 if (res
->ai_canonname
)
115 cur
->canonical_name
= g_strdup (res
->ai_canonname
);
127 #ifdef HAVE_GETPROTOBYNAME
130 fetch_protocol (const char *proto_name
, int *cache
, int *proto
, int default_val
)
133 struct protoent
*pent
;
135 pent
= getprotobyname (proto_name
);
136 *proto
= pent
? pent
->p_proto
: default_val
;
143 mono_networking_get_tcp_protocol (void)
145 static int cache
, proto
;
146 return fetch_protocol ("tcp", &cache
, &proto
, 6); //6 is SOL_TCP on linux
150 mono_networking_get_ip_protocol (void)
152 static int cache
, proto
;
153 return fetch_protocol ("ip", &cache
, &proto
, 0); //0 is SOL_IP on linux
157 mono_networking_get_ipv6_protocol (void)
159 static int cache
, proto
;
160 return fetch_protocol ("ipv6", &cache
, &proto
, 41); //41 is SOL_IPV6 on linux
165 #if defined (HAVE_SIOCGIFCONF)
167 #define IFCONF_BUFF_SIZE 1024
168 #ifndef _SIZEOF_ADDR_IFREQ
169 #define _SIZEOF_ADDR_IFREQ(ifr) (sizeof (struct ifreq))
172 #define FOREACH_IFR(IFR, IFC) \
173 for (IFR = (IFC).ifc_req; \
174 ifr < (struct ifreq*)((char*)(IFC).ifc_req + (IFC).ifc_len); \
175 ifr = (struct ifreq*)((char*)(IFR) + _SIZEOF_ADDR_IFREQ (*(IFR))))
178 mono_get_local_interfaces (int family
, int *interface_count
)
184 gboolean ignore_loopback
= FALSE
;
188 *interface_count
= 0;
190 if (!get_address_size_by_family (family
))
193 fd
= socket (family
, SOCK_STREAM
, 0);
197 memset (&ifc
, 0, sizeof (ifc
));
198 ifc
.ifc_len
= IFCONF_BUFF_SIZE
;
199 ifc
.ifc_buf
= g_malloc (IFCONF_BUFF_SIZE
); /* We can't have such huge buffers on the stack. */
200 if (ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0)
203 FOREACH_IFR (ifr
, ifc
) {
206 //only return addresses of the same type as @family
207 if (ifr
->ifr_addr
.sa_family
!= family
) {
208 ifr
->ifr_name
[0] = '\0';
212 strcpy (iflags
.ifr_name
, ifr
->ifr_name
);
214 //ignore interfaces we can't get props for
215 if (ioctl (fd
, SIOCGIFFLAGS
, &iflags
) < 0) {
216 ifr
->ifr_name
[0] = '\0';
220 //ignore interfaces that are down
221 if ((iflags
.ifr_flags
& IFF_UP
) == 0) {
222 ifr
->ifr_name
[0] = '\0';
226 //If we have a non-loopback iface, don't return any loopback
227 if ((iflags
.ifr_flags
& IFF_LOOPBACK
) == 0) {
228 ignore_loopback
= TRUE
;
229 ifr
->ifr_name
[0] = 1;//1 means non-loopback
231 ifr
->ifr_name
[0] = 2; //2 means loopback
236 result_ptr
= result
= g_malloc (if_count
* get_address_size_by_family (family
));
237 FOREACH_IFR (ifr
, ifc
) {
238 if (ifr
->ifr_name
[0] == '\0')
241 if (ignore_loopback
&& ifr
->ifr_name
[0] == 2) {
246 memcpy (result_ptr
, get_address_from_sockaddr (&ifr
->ifr_addr
), get_address_size_by_family (family
));
247 result_ptr
+= get_address_size_by_family (family
);
249 g_assert (result_ptr
<= (char*)result
+ if_count
* get_address_size_by_family (family
));
252 *interface_count
= if_count
;
253 g_free (ifc
.ifc_buf
);
258 #elif defined(HAVE_GETIFADDRS)
261 mono_get_local_interfaces (int family
, int *interface_count
)
263 struct ifaddrs
*ifap
= NULL
, *cur
;
265 gboolean ignore_loopback
= FALSE
;
269 *interface_count
= 0;
271 if (!get_address_size_by_family (family
))
274 if (getifaddrs (&ifap
))
277 for (cur
= ifap
; cur
; cur
= cur
->ifa_next
) {
278 //ignore interfaces with no address assigned
282 //ignore interfaces that don't belong to @family
283 if (cur
->ifa_addr
->sa_family
!= family
)
286 //ignore interfaces that are down
287 if ((cur
->ifa_flags
& IFF_UP
) == 0)
290 //If we have a non-loopback iface, don't return any loopback
291 if ((cur
->ifa_flags
& IFF_LOOPBACK
) == 0)
292 ignore_loopback
= TRUE
;
297 result_ptr
= result
= g_malloc (if_count
* get_address_size_by_family (family
));
298 for (cur
= ifap
; cur
; cur
= cur
->ifa_next
) {
301 if (cur
->ifa_addr
->sa_family
!= family
)
303 if ((cur
->ifa_flags
& IFF_UP
) == 0)
306 //we decrement if_count because it did not on the previous loop.
307 if (ignore_loopback
&& (cur
->ifa_flags
& IFF_LOOPBACK
)) {
312 memcpy (result_ptr
, get_address_from_sockaddr (cur
->ifa_addr
), get_address_size_by_family (family
));
313 result_ptr
+= get_address_size_by_family (family
);
315 g_assert (result_ptr
<= (char*)result
+ if_count
* get_address_size_by_family (family
));
318 *interface_count
= if_count
;