3 * Modern posix networking code
6 * Rodrigo Kumpera (kumpera@gmail.com)
17 #ifdef HAVE_SYS_IOCTL_H
18 #include <sys/ioctl.h>
20 #ifdef HAVE_SYS_SOCKET_H
21 #include <sys/socket.h>
29 #ifdef HAVE_GETIFADDRS
32 #ifdef HAVE_QP2GETIFADDRS
33 /* Bizarrely, IBM i implements this, but AIX doesn't, so on i, it has a different name... */
34 #include <as400_types.h>
35 #include <as400_protos.h>
36 /* Defines to just reuse ifaddrs code */
37 #define ifaddrs ifaddrs_pase
38 #define freeifaddrs Qp2freeifaddrs
39 #define getifaddrs Qp2getifaddrs
42 #include <mono/utils/networking.h>
43 #include <mono/utils/mono-threads-coop.h>
45 #if HAVE_SIOCGIFCONF || HAVE_GETIFADDRS
48 get_address_from_sockaddr (struct sockaddr
*sa
)
50 switch (sa
->sa_family
) {
52 return &((struct sockaddr_in
*)sa
)->sin_addr
;
53 #ifdef HAVE_STRUCT_SOCKADDR_IN6
55 return &((struct sockaddr_in6
*)sa
)->sin6_addr
;
63 #ifdef HAVE_GETADDRINFO
66 mono_get_address_info (const char *hostname
, int port
, int flags
, MonoAddressInfo
**result
)
68 char service_name
[16];
69 struct addrinfo hints
, *res
= NULL
, *info
;
70 MonoAddressEntry
*cur
= NULL
, *prev
= NULL
;
71 MonoAddressInfo
*addr_info
;
74 memset (&hints
, 0, sizeof (struct addrinfo
));
77 hints
.ai_family
= PF_UNSPEC
;
78 if (flags
& MONO_HINT_IPV4
)
79 hints
.ai_family
= PF_INET
;
80 else if (flags
& MONO_HINT_IPV6
)
81 hints
.ai_family
= PF_INET6
;
83 hints
.ai_socktype
= SOCK_STREAM
;
85 if (flags
& MONO_HINT_CANONICAL_NAME
)
86 hints
.ai_flags
= AI_CANONNAME
;
87 if (flags
& MONO_HINT_NUMERIC_HOST
)
88 hints
.ai_flags
|= AI_NUMERICHOST
;
90 /* Some ancient libc don't define AI_ADDRCONFIG */
92 if (flags
& MONO_HINT_CONFIGURED_ONLY
)
93 hints
.ai_flags
|= AI_ADDRCONFIG
;
95 sprintf (service_name
, "%d", port
);
98 ret
= getaddrinfo (hostname
, service_name
, &hints
, &info
);
102 return 1; /* FIXME propagate the error */
105 *result
= addr_info
= g_new0 (MonoAddressInfo
, 1);
108 cur
= g_new0 (MonoAddressEntry
, 1);
109 cur
->family
= res
->ai_family
;
110 cur
->socktype
= res
->ai_socktype
;
111 cur
->protocol
= res
->ai_protocol
;
112 if (cur
->family
== PF_INET
) {
113 cur
->address_len
= sizeof (struct in_addr
);
114 cur
->address
.v4
= ((struct sockaddr_in
*)res
->ai_addr
)->sin_addr
;
115 #ifdef HAVE_STRUCT_SOCKADDR_IN6
116 } else if (cur
->family
== PF_INET6
) {
117 cur
->address_len
= sizeof (struct in6_addr
);
118 cur
->address
.v6
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
121 g_warning ("Cannot handle address family %d", cur
->family
);
127 if (res
->ai_canonname
)
128 cur
->canonical_name
= g_strdup (res
->ai_canonname
);
133 addr_info
->entries
= cur
;
145 #if defined(__linux__) && defined(HAVE_GETPROTOBYNAME_R)
148 fetch_protocol (const char *proto_name
, int *cache
, int *proto
, int default_val
)
151 struct protoent protoent_buf
= { 0 };
152 struct protoent
*pent
= NULL
;
155 getprotobyname_r (proto_name
, &protoent_buf
, buf
, 1024, &pent
);
156 *proto
= pent
? pent
->p_proto
: default_val
;
162 #elif HAVE_GETPROTOBYNAME
165 fetch_protocol (const char *proto_name
, int *cache
, int *proto
, int default_val
)
168 struct protoent
*pent
;
170 pent
= getprotobyname (proto_name
);
171 *proto
= pent
? pent
->p_proto
: default_val
;
180 mono_networking_get_tcp_protocol (void)
182 static int cache
, proto
;
183 return fetch_protocol ("tcp", &cache
, &proto
, 6); //6 is SOL_TCP on linux
187 mono_networking_get_ip_protocol (void)
189 static int cache
, proto
;
190 return fetch_protocol ("ip", &cache
, &proto
, 0); //0 is SOL_IP on linux
194 mono_networking_get_ipv6_protocol (void)
196 static int cache
, proto
;
197 return fetch_protocol ("ipv6", &cache
, &proto
, 41); //41 is SOL_IPV6 on linux
200 #if defined (HAVE_SIOCGIFCONF)
202 #define IFCONF_BUFF_SIZE 1024
203 #ifndef _SIZEOF_ADDR_IFREQ
204 #define _SIZEOF_ADDR_IFREQ(ifr) (sizeof (struct ifreq))
207 #define FOREACH_IFR(IFR, IFC) \
208 for (IFR = (IFC).ifc_req; \
209 ifr < (struct ifreq*)((char*)(IFC).ifc_req + (IFC).ifc_len); \
210 ifr = (struct ifreq*)((char*)(IFR) + _SIZEOF_ADDR_IFREQ (*(IFR))))
213 mono_get_local_interfaces (int family
, int *interface_count
)
219 gboolean ignore_loopback
= FALSE
;
223 *interface_count
= 0;
225 if (!mono_address_size_for_family (family
))
228 fd
= socket (family
, SOCK_STREAM
, 0);
232 memset (&ifc
, 0, sizeof (ifc
));
233 ifc
.ifc_len
= IFCONF_BUFF_SIZE
;
234 ifc
.ifc_buf
= (char *)g_malloc (IFCONF_BUFF_SIZE
); /* We can't have such huge buffers on the stack. */
235 if (ioctl (fd
, SIOCGIFCONF
, &ifc
) < 0)
238 FOREACH_IFR (ifr
, ifc
) {
241 //only return addresses of the same type as @family
242 if (ifr
->ifr_addr
.sa_family
!= family
) {
243 ifr
->ifr_name
[0] = '\0';
247 strcpy (iflags
.ifr_name
, ifr
->ifr_name
);
249 //ignore interfaces we can't get props for
250 if (ioctl (fd
, SIOCGIFFLAGS
, &iflags
) < 0) {
251 ifr
->ifr_name
[0] = '\0';
255 //ignore interfaces that are down
256 if ((iflags
.ifr_flags
& IFF_UP
) == 0) {
257 ifr
->ifr_name
[0] = '\0';
261 //If we have a non-loopback iface, don't return any loopback
262 if ((iflags
.ifr_flags
& IFF_LOOPBACK
) == 0) {
263 ignore_loopback
= TRUE
;
264 ifr
->ifr_name
[0] = 1;//1 means non-loopback
266 ifr
->ifr_name
[0] = 2; //2 means loopback
271 result
= (char *)g_malloc (if_count
* mono_address_size_for_family (family
));
272 result_ptr
= (char *)result
;
273 FOREACH_IFR (ifr
, ifc
) {
274 if (ifr
->ifr_name
[0] == '\0')
277 if (ignore_loopback
&& ifr
->ifr_name
[0] == 2) {
282 memcpy (result_ptr
, get_address_from_sockaddr (&ifr
->ifr_addr
), mono_address_size_for_family (family
));
283 result_ptr
+= mono_address_size_for_family (family
);
285 g_assert (result_ptr
<= (char*)result
+ if_count
* mono_address_size_for_family (family
));
288 *interface_count
= if_count
;
289 g_free (ifc
.ifc_buf
);
294 #elif defined(HAVE_GETIFADDRS) || defined(HAVE_QP2GETIFADDRS)
297 mono_get_local_interfaces (int family
, int *interface_count
)
299 struct ifaddrs
*ifap
= NULL
, *cur
;
301 gboolean ignore_loopback
= FALSE
;
305 *interface_count
= 0;
307 if (!mono_address_size_for_family (family
))
310 if (getifaddrs (&ifap
))
313 for (cur
= ifap
; cur
; cur
= cur
->ifa_next
) {
314 //ignore interfaces with no address assigned
318 //ignore interfaces that don't belong to @family
319 if (cur
->ifa_addr
->sa_family
!= family
)
322 //ignore interfaces that are down
323 if ((cur
->ifa_flags
& IFF_UP
) == 0)
326 //If we have a non-loopback iface, don't return any loopback
327 if ((cur
->ifa_flags
& IFF_LOOPBACK
) == 0)
328 ignore_loopback
= TRUE
;
333 result_ptr
= result
= g_malloc (if_count
* mono_address_size_for_family (family
));
334 for (cur
= ifap
; cur
; cur
= cur
->ifa_next
) {
337 if (cur
->ifa_addr
->sa_family
!= family
)
339 if ((cur
->ifa_flags
& IFF_UP
) == 0)
342 //we decrement if_count because it did not on the previous loop.
343 if (ignore_loopback
&& (cur
->ifa_flags
& IFF_LOOPBACK
)) {
348 memcpy (result_ptr
, get_address_from_sockaddr (cur
->ifa_addr
), mono_address_size_for_family (family
));
349 result_ptr
+= mono_address_size_for_family (family
);
351 g_assert (result_ptr
<= (char*)result
+ if_count
* mono_address_size_for_family (family
));
354 *interface_count
= if_count
;
360 #ifdef HAVE_GETNAMEINFO
363 mono_networking_addr_to_str (MonoAddress
*address
, char *buffer
, socklen_t buflen
)
365 MonoSocketAddress saddr
;
367 mono_socket_address_init (&saddr
, &len
, address
->family
, &address
->addr
, 0);
369 return getnameinfo (&saddr
.addr
, len
, buffer
, buflen
, NULL
, 0, NI_NUMERICHOST
) == 0;
375 mono_networking_addr_to_str (MonoAddress
*address
, char *buffer
, socklen_t buflen
)
377 return inet_ntop (address
->family
, &address
->addr
, buffer
, buflen
) != NULL
;
383 // These are already defined in networking-windows.c for Windows
385 mono_networking_init (void)
391 mono_networking_shutdown (void)