More disambiguation of Python in makefiles (#18284)
[mono-project.git] / mono / utils / networking-posix.c
blobe307a728fa36d6beb752599682d247b98967b0a5
1 /**
2 * \file
3 * Modern posix networking code
5 * Author:
6 * Rodrigo Kumpera (kumpera@gmail.com)
8 * (C) 2015 Xamarin
9 */
11 #include <config.h>
12 #include <glib.h>
14 #ifdef HAVE_NETDB_H
15 #include <netdb.h>
16 #endif
17 #ifdef HAVE_SYS_IOCTL_H
18 #include <sys/ioctl.h>
19 #endif
20 #ifdef HAVE_SYS_SOCKET_H
21 #include <sys/socket.h>
22 #endif
23 #ifdef HAVE_NET_IF_H
24 #include <net/if.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_GETIFADDRS
30 #include <ifaddrs.h>
31 #endif
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
40 #endif
42 #include <mono/utils/networking.h>
43 #include <mono/utils/mono-threads-coop.h>
45 #if HAVE_SIOCGIFCONF || HAVE_GETIFADDRS
47 static void*
48 get_address_from_sockaddr (struct sockaddr *sa)
50 switch (sa->sa_family) {
51 case AF_INET:
52 return &((struct sockaddr_in*)sa)->sin_addr;
53 #ifdef HAVE_STRUCT_SOCKADDR_IN6
54 case AF_INET6:
55 return &((struct sockaddr_in6*)sa)->sin6_addr;
56 #endif
58 return NULL;
61 #endif
63 #ifdef HAVE_GETADDRINFO
65 int
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;
72 int ret;
74 memset (&hints, 0, sizeof (struct addrinfo));
75 *result = NULL;
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 */
91 #ifdef AI_ADDRCONFIG
92 if (flags & MONO_HINT_CONFIGURED_ONLY)
93 hints.ai_flags |= AI_ADDRCONFIG;
94 #endif
95 sprintf (service_name, "%d", port);
97 MONO_ENTER_GC_SAFE;
98 ret = getaddrinfo (hostname, service_name, &hints, &info);
99 MONO_EXIT_GC_SAFE;
101 if (ret)
102 return 1; /* FIXME propagate the error */
104 res = info;
105 *result = addr_info = g_new0 (MonoAddressInfo, 1);
107 while (res) {
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;
119 #endif
120 } else {
121 g_warning ("Cannot handle address family %d", cur->family);
122 res = res->ai_next;
123 g_free (cur);
124 continue;
127 if (res->ai_canonname)
128 cur->canonical_name = g_strdup (res->ai_canonname);
130 if (prev)
131 prev->next = cur;
132 else
133 addr_info->entries = cur;
135 prev = cur;
136 res = res->ai_next;
139 freeaddrinfo (info);
140 return 0;
143 #endif
145 #if defined(__linux__) && defined(HAVE_GETPROTOBYNAME_R)
147 static int
148 fetch_protocol (const char *proto_name, int *cache, int *proto, int default_val)
150 if (!*cache) {
151 struct protoent protoent_buf = { 0 };
152 struct protoent *pent = NULL;
153 char buf[1024];
155 getprotobyname_r (proto_name, &protoent_buf, buf, 1024, &pent);
156 *proto = pent ? pent->p_proto : default_val;
157 *cache = 1;
159 return *proto;
162 #elif HAVE_GETPROTOBYNAME
164 static int
165 fetch_protocol (const char *proto_name, int *cache, int *proto, int default_val)
167 if (!*cache) {
168 struct protoent *pent;
170 pent = getprotobyname (proto_name);
171 *proto = pent ? pent->p_proto : default_val;
172 *cache = 1;
174 return *proto;
177 #endif
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))
205 #endif
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))))
212 void *
213 mono_get_local_interfaces (int family, int *interface_count)
215 int fd;
216 struct ifconf ifc;
217 struct ifreq *ifr;
218 int if_count = 0;
219 gboolean ignore_loopback = FALSE;
220 void *result = NULL;
221 char *result_ptr;
223 *interface_count = 0;
225 if (!mono_address_size_for_family (family))
226 return NULL;
228 fd = socket (family, SOCK_STREAM, 0);
229 if (fd == -1)
230 return NULL;
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)
236 goto done;
238 FOREACH_IFR (ifr, ifc) {
239 struct ifreq iflags;
241 //only return addresses of the same type as @family
242 if (ifr->ifr_addr.sa_family != family) {
243 ifr->ifr_name [0] = '\0';
244 continue;
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';
252 continue;
255 //ignore interfaces that are down
256 if ((iflags.ifr_flags & IFF_UP) == 0) {
257 ifr->ifr_name [0] = '\0';
258 continue;
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
265 } else {
266 ifr->ifr_name [0] = 2; //2 means loopback
268 ++if_count;
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')
275 continue;
277 if (ignore_loopback && ifr->ifr_name [0] == 2) {
278 --if_count;
279 continue;
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));
287 done:
288 *interface_count = if_count;
289 g_free (ifc.ifc_buf);
290 close (fd);
291 return result;
294 #elif defined(HAVE_GETIFADDRS) || defined(HAVE_QP2GETIFADDRS)
296 void *
297 mono_get_local_interfaces (int family, int *interface_count)
299 struct ifaddrs *ifap = NULL, *cur;
300 int if_count = 0;
301 gboolean ignore_loopback = FALSE;
302 void *result;
303 char *result_ptr;
305 *interface_count = 0;
307 if (!mono_address_size_for_family (family))
308 return NULL;
310 if (getifaddrs (&ifap))
311 return NULL;
313 for (cur = ifap; cur; cur = cur->ifa_next) {
314 //ignore interfaces with no address assigned
315 if (!cur->ifa_addr)
316 continue;
318 //ignore interfaces that don't belong to @family
319 if (cur->ifa_addr->sa_family != family)
320 continue;
322 //ignore interfaces that are down
323 if ((cur->ifa_flags & IFF_UP) == 0)
324 continue;
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;
330 if_count++;
333 result_ptr = result = g_malloc (if_count * mono_address_size_for_family (family));
334 for (cur = ifap; cur; cur = cur->ifa_next) {
335 if (!cur->ifa_addr)
336 continue;
337 if (cur->ifa_addr->sa_family != family)
338 continue;
339 if ((cur->ifa_flags & IFF_UP) == 0)
340 continue;
342 //we decrement if_count because it did not on the previous loop.
343 if (ignore_loopback && (cur->ifa_flags & IFF_LOOPBACK)) {
344 --if_count;
345 continue;
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));
353 freeifaddrs (ifap);
354 *interface_count = if_count;
355 return result;
358 #endif
360 #ifdef HAVE_GETNAMEINFO
362 gboolean
363 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
365 MonoSocketAddress saddr;
366 socklen_t len;
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;
372 #elif HAVE_INET_NTOP
374 gboolean
375 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
377 return inet_ntop (address->family, &address->addr, buffer, buflen) != NULL;
380 #endif
382 #ifndef _WIN32
383 // These are already defined in networking-windows.c for Windows
384 void
385 mono_networking_init (void)
387 //nothing really
390 void
391 mono_networking_shutdown (void)
393 //nothing really
395 #endif