[MonoDataSqlite] Add test for Xamarin.iOS specific bug 27864
[mono-project.git] / mono / utils / networking-posix.c
blob2fe8da9d9f8fa855d4ba6b1dfbdc189f9d8709a4
1 /*
2 * networking-posix.c: Modern posix networking code
4 * Author:
5 * Rodrigo Kumpera (kumpera@gmail.com)
7 * (C) 2015 Xamarin
8 */
10 #include <mono/utils/networking.h>
11 #include <glib.h>
13 #ifdef HAVE_NETDB_H
14 #include <netdb.h>
15 #endif
16 #ifdef HAVE_SYS_IOCTL_H
17 #include <sys/ioctl.h>
18 #endif
19 #ifdef HAVE_NET_IF_H
20 #include <net/if.h>
21 #endif
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 #ifdef HAVE_GETIFADDRS
26 #include <ifaddrs.h>
27 #endif
29 static void*
30 get_address_from_sockaddr (struct sockaddr *sa)
32 switch (sa->sa_family) {
33 case AF_INET:
34 return &((struct sockaddr_in*)sa)->sin_addr;
35 case AF_INET6:
36 return &((struct sockaddr_in6*)sa)->sin6_addr;
38 return NULL;
41 #ifdef HAVE_GETADDRINFO
43 int
44 mono_get_address_info (const char *hostname, int port, int flags, MonoAddressInfo **result)
46 char service_name [16];
47 struct addrinfo hints, *res = NULL, *info;
48 MonoAddressEntry *cur = NULL, *prev = NULL;
49 MonoAddressInfo *addr_info;
51 memset (&hints, 0, sizeof (struct addrinfo));
52 *result = NULL;
54 hints.ai_family = PF_UNSPEC;
55 if (flags & MONO_HINT_IPV4)
56 hints.ai_family = PF_INET;
57 else if (flags & MONO_HINT_IPV6)
58 hints.ai_family = PF_INET6;
60 hints.ai_socktype = SOCK_STREAM;
62 if (flags & MONO_HINT_CANONICAL_NAME)
63 hints.ai_flags = AI_CANONNAME;
65 /* Some ancient libc don't define AI_ADDRCONFIG */
66 #ifdef AI_ADDRCONFIG
67 if (flags & MONO_HINT_CONFIGURED_ONLY)
68 hints.ai_flags = AI_ADDRCONFIG;
69 #endif
70 sprintf (service_name, "%d", port);
71 if (getaddrinfo (hostname, service_name, &hints, &info))
72 return 1; /* FIXME propagate the error */
74 res = info;
75 *result = addr_info = g_new0 (MonoAddressInfo, 1);
77 while (res) {
78 cur = g_new0 (MonoAddressEntry, 1);
79 if (prev)
80 prev->next = cur;
81 else
82 addr_info->entries = cur;
84 cur->family = res->ai_family;
85 cur->socktype = res->ai_socktype;
86 cur->protocol = res->ai_protocol;
87 if (cur->family == PF_INET) {
88 cur->address_len = sizeof (struct in_addr);
89 cur->address.v4 = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
90 } else if (cur->family == PF_INET6) {
91 cur->address_len = sizeof (struct in6_addr);
92 cur->address.v6 = ((struct sockaddr_in6*)res->ai_addr)->sin6_addr;
93 } else {
94 g_error ("Cannot handle address family %d", cur->family);
97 if (res->ai_canonname)
98 cur->canonical_name = g_strdup (res->ai_canonname);
100 prev = cur;
101 res = res->ai_next;
104 freeaddrinfo (info);
105 return 0;
108 #endif
110 #ifdef HAVE_GETPROTOBYNAME
112 static int
113 fetch_protocol (const char *proto_name, int *cache, int *proto, int default_val)
115 if (!*cache) {
116 struct protoent *pent;
118 pent = getprotobyname (proto_name);
119 *proto = pent ? pent->p_proto : default_val;
120 *cache = 1;
122 return *proto;
126 mono_networking_get_tcp_protocol (void)
128 static int cache, proto;
129 return fetch_protocol ("tcp", &cache, &proto, 6); //6 is SOL_TCP on linux
133 mono_networking_get_ip_protocol (void)
135 static int cache, proto;
136 return fetch_protocol ("ip", &cache, &proto, 0); //0 is SOL_IP on linux
140 mono_networking_get_ipv6_protocol (void)
142 static int cache, proto;
143 return fetch_protocol ("ipv6", &cache, &proto, 41); //41 is SOL_IPV6 on linux
146 #endif
148 #if defined (HAVE_SIOCGIFCONF)
150 #define IFCONF_BUFF_SIZE 1024
151 #ifndef _SIZEOF_ADDR_IFREQ
152 #define _SIZEOF_ADDR_IFREQ(ifr) (sizeof (struct ifreq))
153 #endif
155 #define FOREACH_IFR(IFR, IFC) \
156 for (IFR = (IFC).ifc_req; \
157 ifr < (struct ifreq*)((char*)(IFC).ifc_req + (IFC).ifc_len); \
158 ifr = (struct ifreq*)((char*)(IFR) + _SIZEOF_ADDR_IFREQ (*(IFR))))
160 void *
161 mono_get_local_interfaces (int family, int *interface_count)
163 int fd;
164 struct ifconf ifc;
165 struct ifreq *ifr;
166 int if_count = 0;
167 gboolean ignore_loopback = FALSE;
168 void *result = NULL;
169 char *result_ptr;
171 *interface_count = 0;
173 if (!mono_address_size_for_family (family))
174 return NULL;
176 fd = socket (family, SOCK_STREAM, 0);
177 if (fd == -1)
178 return NULL;
180 memset (&ifc, 0, sizeof (ifc));
181 ifc.ifc_len = IFCONF_BUFF_SIZE;
182 ifc.ifc_buf = g_malloc (IFCONF_BUFF_SIZE); /* We can't have such huge buffers on the stack. */
183 if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
184 goto done;
186 FOREACH_IFR (ifr, ifc) {
187 struct ifreq iflags;
189 //only return addresses of the same type as @family
190 if (ifr->ifr_addr.sa_family != family) {
191 ifr->ifr_name [0] = '\0';
192 continue;
195 strcpy (iflags.ifr_name, ifr->ifr_name);
197 //ignore interfaces we can't get props for
198 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
199 ifr->ifr_name [0] = '\0';
200 continue;
203 //ignore interfaces that are down
204 if ((iflags.ifr_flags & IFF_UP) == 0) {
205 ifr->ifr_name [0] = '\0';
206 continue;
209 //If we have a non-loopback iface, don't return any loopback
210 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
211 ignore_loopback = TRUE;
212 ifr->ifr_name [0] = 1;//1 means non-loopback
213 } else {
214 ifr->ifr_name [0] = 2; //2 means loopback
216 ++if_count;
219 result_ptr = result = g_malloc (if_count * mono_address_size_for_family (family));
220 FOREACH_IFR (ifr, ifc) {
221 if (ifr->ifr_name [0] == '\0')
222 continue;
224 if (ignore_loopback && ifr->ifr_name [0] == 2) {
225 --if_count;
226 continue;
229 memcpy (result_ptr, get_address_from_sockaddr (&ifr->ifr_addr), mono_address_size_for_family (family));
230 result_ptr += mono_address_size_for_family (family);
232 g_assert (result_ptr <= (char*)result + if_count * mono_address_size_for_family (family));
234 done:
235 *interface_count = if_count;
236 g_free (ifc.ifc_buf);
237 close (fd);
238 return result;
241 #elif defined(HAVE_GETIFADDRS)
243 void *
244 mono_get_local_interfaces (int family, int *interface_count)
246 struct ifaddrs *ifap = NULL, *cur;
247 int if_count = 0;
248 gboolean ignore_loopback = FALSE;
249 void *result;
250 char *result_ptr;
252 *interface_count = 0;
254 if (!mono_address_size_for_family (family))
255 return NULL;
257 if (getifaddrs (&ifap))
258 return NULL;
260 for (cur = ifap; cur; cur = cur->ifa_next) {
261 //ignore interfaces with no address assigned
262 if (!cur->ifa_addr)
263 continue;
265 //ignore interfaces that don't belong to @family
266 if (cur->ifa_addr->sa_family != family)
267 continue;
269 //ignore interfaces that are down
270 if ((cur->ifa_flags & IFF_UP) == 0)
271 continue;
273 //If we have a non-loopback iface, don't return any loopback
274 if ((cur->ifa_flags & IFF_LOOPBACK) == 0)
275 ignore_loopback = TRUE;
277 if_count++;
280 result_ptr = result = g_malloc (if_count * mono_address_size_for_family (family));
281 for (cur = ifap; cur; cur = cur->ifa_next) {
282 if (!cur->ifa_addr)
283 continue;
284 if (cur->ifa_addr->sa_family != family)
285 continue;
286 if ((cur->ifa_flags & IFF_UP) == 0)
287 continue;
289 //we decrement if_count because it did not on the previous loop.
290 if (ignore_loopback && (cur->ifa_flags & IFF_LOOPBACK)) {
291 --if_count;
292 continue;
295 memcpy (result_ptr, get_address_from_sockaddr (cur->ifa_addr), mono_address_size_for_family (family));
296 result_ptr += mono_address_size_for_family (family);
298 g_assert (result_ptr <= (char*)result + if_count * mono_address_size_for_family (family));
300 freeifaddrs (ifap);
301 *interface_count = if_count;
302 return result;
305 #endif
307 #ifdef HAVE_GETNAMEINFO
309 gboolean
310 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
312 MonoSocketAddress saddr;
313 socklen_t len;
314 mono_socket_address_init (&saddr, &len, address->family, &address->addr, 0);
316 return getnameinfo (&saddr.addr, len, buffer, buflen, NULL, 0, NI_NUMERICHOST) == 0;
319 #elif HAVE_INET_NTOP
321 gboolean
322 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
324 return inet_ntop (address->family, &address->addr, buffer, buflen) != NULL;
327 #endif
329 #ifndef _WIN32
330 // These are already defined in networking-windows.c for Windows
331 void
332 mono_networking_init (void)
334 //nothing really
337 void
338 mono_networking_shutdown (void)
340 //nothing really
342 #endif