[utils] Explicitly check if the system has mincore instead of relying on mmap been...
[mono-project.git] / mono / metadata / mono-route.c
blob4b5ca588056df60fcb60404b58fee9d8bd18fd79
1 /*
2 * mono-route.c: Read the network routing tables using sysctl(3) calls
3 * Required for Unix-like systems that don't have Linux's /proc/net/route
5 * Author:
6 * Ben Woods (woodsb02@gmail.com)
7 */
9 #if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD)
11 #include <sys/socket.h>
12 #include <net/if.h>
13 #include <net/if_dl.h>
14 #include <netinet/in.h>
15 #include <sys/param.h>
16 #include <sys/sysctl.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/mono-route.h>
22 extern MonoBoolean ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo_internal(MonoString *iface, MonoArray **gw_addr_list)
24 size_t needed;
25 in_addr_t in;
26 int mib[6];
27 int num_gws=0, gwnum=0;
28 unsigned int ifindex = 0;
29 char *buf, *next, *lim, *ifacename;
30 struct rt_msghdr *rtm;
32 MonoDomain *domain = mono_domain_get ();
34 ifacename = mono_string_to_utf8(iface);
35 if ((ifindex = if_nametoindex(ifacename)) == 0)
36 return FALSE;
37 g_free(ifacename);
39 // MIB array defining data to read from sysctl
40 mib[0] = CTL_NET; // Networking
41 mib[1] = PF_ROUTE; // Routing messages
42 mib[2] = 0; // Protocol number (always zero)
43 mib[3] = AF_INET; // Address family (IPv4)
44 mib[4] = NET_RT_DUMP; // Dump routing table
45 mib[5] = 0; //
47 // First sysctl call with oldp set to NULL to determine size of available data
48 if (sysctl(mib, G_N_ELEMENTS(mib), NULL, &needed, NULL, 0) < 0)
49 return FALSE;
51 // Allocate suffcient memory for available data based on the previous sysctl call
52 if ((buf = malloc(needed)) == NULL)
53 return FALSE;
55 // Second sysctl call to retrieve data into appropriately sized buffer
56 if (sysctl(mib, G_N_ELEMENTS(mib), buf, &needed, NULL, 0) < 0)
57 return FALSE;
59 lim = buf + needed;
60 for (next = buf; next < lim; next += rtm->rtm_msglen) {
61 rtm = (struct rt_msghdr *)next;
62 if (rtm->rtm_version != RTM_VERSION)
63 continue;
64 if (rtm->rtm_index != ifindex)
65 continue;
66 if((in = gateway_from_rtm(rtm)) == 0)
67 continue;
68 num_gws++;
71 *gw_addr_list = mono_array_new(domain, mono_get_string_class (), num_gws);
73 for (next = buf; next < lim; next += rtm->rtm_msglen) {
74 rtm = (struct rt_msghdr *)next;
75 if (rtm->rtm_version != RTM_VERSION)
76 continue;
77 if (rtm->rtm_index != ifindex)
78 continue;
79 if ((in = gateway_from_rtm(rtm)) == 0)
80 continue;
82 MonoString *addr_string;
83 char addr [16], *ptr;
84 int len;
86 ptr = (char *) &in;
87 len = snprintf(addr, sizeof(addr), "%u.%u.%u.%u",
88 (unsigned char) ptr [0],
89 (unsigned char) ptr [1],
90 (unsigned char) ptr [2],
91 (unsigned char) ptr [3]);
93 if ((len >= sizeof(addr)) || (len < 0))
94 // snprintf output truncated
95 continue;
97 addr_string = mono_string_new (domain, addr);
98 mono_array_setref (*gw_addr_list, gwnum, addr_string);
99 gwnum++;
101 free(buf);
102 return TRUE;
105 in_addr_t gateway_from_rtm(struct rt_msghdr *rtm)
107 struct sockaddr *gw;
108 unsigned int l;
110 struct sockaddr *addr = (struct sockaddr *)(rtm + 1);
111 l = roundup(addr->sa_len, sizeof(long)); \
112 gw = (struct sockaddr *)((char *) addr + l); \
114 if (rtm->rtm_addrs & RTA_GATEWAY) {
115 if(gw->sa_family == AF_INET) {
116 struct sockaddr_in *sockin = (struct sockaddr_in *)gw;
117 return(sockin->sin_addr.s_addr);
121 return 0;
124 #endif /* #if defined(PLATFORM_MACOSX) || defined(PLATFORM_BSD) */