2 * networking-posix.c: Modern posix networking code
5 * Rodrigo Kumpera (kumpera@gmail.com)
16 #ifdef HAVE_SYS_IOCTL_H
17 #include <sys/ioctl.h>
25 #ifdef HAVE_GETIFADDRS
29 #include <mono/utils/networking.h>
30 #include <mono/utils/mono-threads-coop.h>
33 get_address_from_sockaddr (struct sockaddr *sa)
35 switch (sa->sa_family) {
37 return &((struct sockaddr_in*)sa)->sin_addr;
39 return &((struct sockaddr_in6*)sa)->sin6_addr;
44 #ifdef HAVE_GETADDRINFO
47 mono_get_address_info (const char *hostname, int port, int flags, MonoAddressInfo **result)
49 char service_name [16];
50 struct addrinfo hints, *res = NULL, *info;
51 MonoAddressEntry *cur = NULL, *prev = NULL;
52 MonoAddressInfo *addr_info;
55 memset (&hints, 0, sizeof (struct addrinfo));
58 hints.ai_family = PF_UNSPEC;
59 if (flags & MONO_HINT_IPV4)
60 hints.ai_family = PF_INET;
61 else if (flags & MONO_HINT_IPV6)
62 hints.ai_family = PF_INET6;
64 hints.ai_socktype = SOCK_STREAM;
66 if (flags & MONO_HINT_CANONICAL_NAME)
67 hints.ai_flags = AI_CANONNAME;
69 /* Some ancient libc don't define AI_ADDRCONFIG */
71 if (flags & MONO_HINT_CONFIGURED_ONLY)
72 hints.ai_flags = AI_ADDRCONFIG;
74 sprintf (service_name, "%d", port);
77 ret = getaddrinfo (hostname, service_name, &hints, &info);
81 return 1; /* FIXME propagate the error */
84 *result = addr_info = g_new0 (MonoAddressInfo, 1);
87 cur = g_new0 (MonoAddressEntry, 1);
88 cur->family = res->ai_family;
89 cur->socktype = res->ai_socktype;
90 cur->protocol = res->ai_protocol;
91 if (cur->family == PF_INET) {
92 cur->address_len = sizeof (struct in_addr);
93 cur->address.v4 = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
94 } else if (cur->family == PF_INET6) {
95 cur->address_len = sizeof (struct in6_addr);
96 cur->address.v6 = ((struct sockaddr_in6*)res->ai_addr)->sin6_addr;
98 g_warning ("Cannot handle address family %d", cur->family);
104 if (res->ai_canonname)
105 cur->canonical_name = g_strdup (res->ai_canonname);
110 addr_info->entries = cur;
122 #ifdef HAVE_GETPROTOBYNAME
125 fetch_protocol (const char *proto_name, int *cache, int *proto, int default_val)
128 struct protoent *pent;
130 pent = getprotobyname (proto_name);
131 *proto = pent ? pent->p_proto : default_val;
138 mono_networking_get_tcp_protocol (void)
140 static int cache, proto;
141 return fetch_protocol ("tcp", &cache, &proto, 6); //6 is SOL_TCP on linux
145 mono_networking_get_ip_protocol (void)
147 static int cache, proto;
148 return fetch_protocol ("ip", &cache, &proto, 0); //0 is SOL_IP on linux
152 mono_networking_get_ipv6_protocol (void)
154 static int cache, proto;
155 return fetch_protocol ("ipv6", &cache, &proto, 41); //41 is SOL_IPV6 on linux
160 #if defined (HAVE_SIOCGIFCONF)
162 #define IFCONF_BUFF_SIZE 1024
163 #ifndef _SIZEOF_ADDR_IFREQ
164 #define _SIZEOF_ADDR_IFREQ(ifr) (sizeof (struct ifreq))
167 #define FOREACH_IFR(IFR, IFC) \
168 for (IFR = (IFC).ifc_req; \
169 ifr < (struct ifreq*)((char*)(IFC).ifc_req + (IFC).ifc_len); \
170 ifr = (struct ifreq*)((char*)(IFR) + _SIZEOF_ADDR_IFREQ (*(IFR))))
173 mono_get_local_interfaces (int family, int *interface_count)
179 gboolean ignore_loopback = FALSE;
183 *interface_count = 0;
185 if (!mono_address_size_for_family (family))
188 fd = socket (family, SOCK_STREAM, 0);
192 memset (&ifc, 0, sizeof (ifc));
193 ifc.ifc_len = IFCONF_BUFF_SIZE;
194 ifc.ifc_buf = (char *)g_malloc (IFCONF_BUFF_SIZE); /* We can't have such huge buffers on the stack. */
195 if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
198 FOREACH_IFR (ifr, ifc) {
201 //only return addresses of the same type as @family
202 if (ifr->ifr_addr.sa_family != family) {
203 ifr->ifr_name [0] = '\0';
207 strcpy (iflags.ifr_name, ifr->ifr_name);
209 //ignore interfaces we can't get props for
210 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
211 ifr->ifr_name [0] = '\0';
215 //ignore interfaces that are down
216 if ((iflags.ifr_flags & IFF_UP) == 0) {
217 ifr->ifr_name [0] = '\0';
221 //If we have a non-loopback iface, don't return any loopback
222 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
223 ignore_loopback = TRUE;
224 ifr->ifr_name [0] = 1;//1 means non-loopback
226 ifr->ifr_name [0] = 2; //2 means loopback
231 result = (char *)g_malloc (if_count * mono_address_size_for_family (family));
232 result_ptr = (char *)result;
233 FOREACH_IFR (ifr, ifc) {
234 if (ifr->ifr_name [0] == '\0')
237 if (ignore_loopback && ifr->ifr_name [0] == 2) {
242 memcpy (result_ptr, get_address_from_sockaddr (&ifr->ifr_addr), mono_address_size_for_family (family));
243 result_ptr += mono_address_size_for_family (family);
245 g_assert (result_ptr <= (char*)result + if_count * mono_address_size_for_family (family));
248 *interface_count = if_count;
249 g_free (ifc.ifc_buf);
254 #elif defined(HAVE_GETIFADDRS)
257 mono_get_local_interfaces (int family, int *interface_count)
259 struct ifaddrs *ifap = NULL, *cur;
261 gboolean ignore_loopback = FALSE;
265 *interface_count = 0;
267 if (!mono_address_size_for_family (family))
270 if (getifaddrs (&ifap))
273 for (cur = ifap; cur; cur = cur->ifa_next) {
274 //ignore interfaces with no address assigned
278 //ignore interfaces that don't belong to @family
279 if (cur->ifa_addr->sa_family != family)
282 //ignore interfaces that are down
283 if ((cur->ifa_flags & IFF_UP) == 0)
286 //If we have a non-loopback iface, don't return any loopback
287 if ((cur->ifa_flags & IFF_LOOPBACK) == 0)
288 ignore_loopback = TRUE;
293 result_ptr = result = g_malloc (if_count * mono_address_size_for_family (family));
294 for (cur = ifap; cur; cur = cur->ifa_next) {
297 if (cur->ifa_addr->sa_family != family)
299 if ((cur->ifa_flags & IFF_UP) == 0)
302 //we decrement if_count because it did not on the previous loop.
303 if (ignore_loopback && (cur->ifa_flags & IFF_LOOPBACK)) {
308 memcpy (result_ptr, get_address_from_sockaddr (cur->ifa_addr), mono_address_size_for_family (family));
309 result_ptr += mono_address_size_for_family (family);
311 g_assert (result_ptr <= (char*)result + if_count * mono_address_size_for_family (family));
314 *interface_count = if_count;
320 #ifdef HAVE_GETNAMEINFO
323 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
325 MonoSocketAddress saddr;
327 mono_socket_address_init (&saddr, &len, address->family, &address->addr, 0);
329 return getnameinfo (&saddr.addr, len, buffer, buflen, NULL, 0, NI_NUMERICHOST) == 0;
335 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
337 return inet_ntop (address->family, &address->addr, buffer, buflen) != NULL;
343 // These are already defined in networking-windows.c for Windows
345 mono_networking_init (void)
351 mono_networking_shutdown (void)