Reduce TLS accesses. (#11487)
[mono-project.git] / mono / metadata / mono-route.c
blobdefd245c593557b462c63fb20144866c0cdf0ab9
1 /**
2 * \file
3 * Read the network routing tables using sysctl(3) calls
4 * Required for Unix-like systems that don't have Linux's /proc/net/route
6 * Author:
7 * Ben Woods (woodsb02@gmail.com)
8 */
10 #include <config.h>
12 #include <mono/metadata/object.h>
13 #include <mono/metadata/mono-route.h>
15 #if defined(HOST_DARWIN) || defined(HOST_BSD)
16 #include <sys/socket.h>
17 #include <net/if.h>
18 #include <net/if_dl.h>
19 #include <netinet/in.h>
20 #include <sys/param.h>
21 #include <sys/sysctl.h>
22 #include <stdlib.h>
23 #include <string.h>
25 extern MonoBoolean ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo_internal(MonoString *iface, MonoArray **gw_addr_list)
27 ERROR_DECL (error);
28 size_t needed;
29 in_addr_t in;
30 int mib[6];
31 int num_gws=0, gwnum=0;
32 unsigned int ifindex = 0;
33 char *buf, *next, *lim, *ifacename;
34 struct rt_msghdr *rtm;
36 MonoDomain *domain = mono_domain_get ();
38 ifacename = mono_string_to_utf8_checked_internal (iface, error);
39 if (mono_error_set_pending_exception (error))
40 return FALSE;
42 if ((ifindex = if_nametoindex(ifacename)) == 0)
43 return FALSE;
44 g_free(ifacename);
46 // MIB array defining data to read from sysctl
47 mib[0] = CTL_NET; // Networking
48 mib[1] = PF_ROUTE; // Routing messages
49 mib[2] = 0; // Protocol number (always zero)
50 mib[3] = AF_INET; // Address family (IPv4)
51 mib[4] = NET_RT_DUMP; // Dump routing table
52 mib[5] = 0; //
54 // First sysctl call with oldp set to NULL to determine size of available data
55 if (sysctl(mib, G_N_ELEMENTS(mib), NULL, &needed, NULL, 0) < 0)
56 return FALSE;
58 // Allocate suffcient memory for available data based on the previous sysctl call
59 if ((buf = g_malloc (needed)) == NULL)
60 return FALSE;
62 // Second sysctl call to retrieve data into appropriately sized buffer
63 if (sysctl(mib, G_N_ELEMENTS(mib), buf, &needed, NULL, 0) < 0) {
64 g_free (buf);
65 return FALSE;
68 lim = buf + needed;
69 for (next = buf; next < lim; next += rtm->rtm_msglen) {
70 rtm = (struct rt_msghdr *)next;
71 if (rtm->rtm_version != RTM_VERSION)
72 continue;
73 if (rtm->rtm_index != ifindex)
74 continue;
75 if((in = gateway_from_rtm(rtm)) == 0)
76 continue;
77 num_gws++;
80 *gw_addr_list = mono_array_new_checked (domain, mono_get_string_class (), num_gws, error);
81 goto_if_nok (error, leave);
83 for (next = buf; next < lim; next += rtm->rtm_msglen) {
84 rtm = (struct rt_msghdr *)next;
85 if (rtm->rtm_version != RTM_VERSION)
86 continue;
87 if (rtm->rtm_index != ifindex)
88 continue;
89 if ((in = gateway_from_rtm(rtm)) == 0)
90 continue;
92 MonoString *addr_string;
93 char addr [16], *ptr;
94 int len;
96 ptr = (char *) &in;
97 len = snprintf(addr, sizeof(addr), "%u.%u.%u.%u",
98 (unsigned char) ptr [0],
99 (unsigned char) ptr [1],
100 (unsigned char) ptr [2],
101 (unsigned char) ptr [3]);
103 if ((len >= sizeof(addr)) || (len < 0))
104 // snprintf output truncated
105 continue;
107 addr_string = mono_string_new_checked (domain, addr, error);
108 goto_if_nok (error, leave);
109 mono_array_setref_internal (*gw_addr_list, gwnum, addr_string);
110 gwnum++;
112 leave:
113 g_free (buf);
114 return is_ok (error);
117 in_addr_t gateway_from_rtm(struct rt_msghdr *rtm)
119 struct sockaddr *gw;
120 unsigned int l;
122 struct sockaddr *addr = (struct sockaddr *)(rtm + 1);
123 l = roundup(addr->sa_len, sizeof(long)); \
124 gw = (struct sockaddr *)((char *) addr + l); \
126 if (rtm->rtm_addrs & RTA_GATEWAY) {
127 if(gw->sa_family == AF_INET) {
128 struct sockaddr_in *sockin = (struct sockaddr_in *)gw;
129 return(sockin->sin_addr.s_addr);
133 return 0;
136 #else
138 MonoBoolean
139 ves_icall_System_Net_NetworkInformation_MacOsIPInterfaceProperties_ParseRouteInfo_internal(MonoString *iface, MonoArray **gw_addr_list)
141 g_assert_not_reached ();
142 return FALSE;
145 #endif /* #if defined(HOST_DARWIN) || defined(HOST_BSD) */