Merge all static runtime libs into libmono-static.
[mono.git] / mono / utils / networking-posix.c
1 /**
2  * \file
3  * Modern posix networking code
4  *
5  * Author:
6  *      Rodrigo Kumpera (kumpera@gmail.com)
7  *
8  * (C) 2015 Xamarin
9  */
10
11 #include <config.h>
12 #include <glib.h>
13
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_NET_IF_H
21 #include <net/if.h>
22 #endif
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_GETIFADDRS
27 #include <ifaddrs.h>
28 #endif
29
30 #include <mono/utils/networking.h>
31 #include <mono/utils/mono-threads-coop.h>
32
33 static void*
34 get_address_from_sockaddr (struct sockaddr *sa)
35 {
36         switch (sa->sa_family) {
37         case AF_INET:
38                 return &((struct sockaddr_in*)sa)->sin_addr;
39         case AF_INET6:
40                 return &((struct sockaddr_in6*)sa)->sin6_addr;
41         }
42         return NULL;
43 }
44
45 #ifdef HAVE_GETADDRINFO
46
47 int
48 mono_get_address_info (const char *hostname, int port, int flags, MonoAddressInfo **result)
49 {
50         char service_name [16];
51         struct addrinfo hints, *res = NULL, *info;
52         MonoAddressEntry *cur = NULL, *prev = NULL;
53         MonoAddressInfo *addr_info;
54         int ret;
55
56         memset (&hints, 0, sizeof (struct addrinfo));
57         *result = NULL;
58
59         hints.ai_family = PF_UNSPEC;
60         if (flags & MONO_HINT_IPV4)
61                 hints.ai_family = PF_INET;
62         else if (flags & MONO_HINT_IPV6)
63                 hints.ai_family = PF_INET6;
64
65         hints.ai_socktype = SOCK_STREAM;
66
67         if (flags & MONO_HINT_CANONICAL_NAME)
68                 hints.ai_flags = AI_CANONNAME;
69
70 /* Some ancient libc don't define AI_ADDRCONFIG */
71 #ifdef AI_ADDRCONFIG
72         if (flags & MONO_HINT_CONFIGURED_ONLY)
73                 hints.ai_flags = AI_ADDRCONFIG;
74 #endif
75         sprintf (service_name, "%d", port);
76
77         MONO_ENTER_GC_SAFE;
78         ret = getaddrinfo (hostname, service_name, &hints, &info);
79         MONO_EXIT_GC_SAFE;
80
81         if (ret)
82                 return 1; /* FIXME propagate the error */
83
84         res = info;
85         *result = addr_info = g_new0 (MonoAddressInfo, 1);
86
87         while (res) {
88                 cur = g_new0 (MonoAddressEntry, 1);
89                 cur->family = res->ai_family;
90                 cur->socktype = res->ai_socktype;
91                 cur->protocol = res->ai_protocol;
92                 if (cur->family == PF_INET) {
93                         cur->address_len = sizeof (struct in_addr);
94                         cur->address.v4 = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
95                 } else if (cur->family == PF_INET6) {
96                         cur->address_len = sizeof (struct in6_addr);
97                         cur->address.v6 = ((struct sockaddr_in6*)res->ai_addr)->sin6_addr;
98                 } else {
99                         g_warning ("Cannot handle address family %d", cur->family);
100                         res = res->ai_next;
101                         g_free (cur);
102                         continue;
103                 }
104
105                 if (res->ai_canonname)
106                         cur->canonical_name = g_strdup (res->ai_canonname);
107
108                 if (prev)
109                         prev->next = cur;
110                 else
111                         addr_info->entries = cur;
112                         
113                 prev = cur;
114                 res = res->ai_next;
115         }
116
117         freeaddrinfo (info);
118         return 0;
119 }
120
121 #endif
122
123 #ifdef HAVE_GETPROTOBYNAME
124
125 static int
126 fetch_protocol (const char *proto_name, int *cache, int *proto, int default_val)
127 {
128         if (!*cache) {
129                 struct protoent *pent;
130
131                 pent = getprotobyname (proto_name);
132                 *proto = pent ? pent->p_proto : default_val;
133                 *cache = 1;
134         }
135         return *proto;
136 }
137
138 int
139 mono_networking_get_tcp_protocol (void)
140 {
141         static int cache, proto;
142         return fetch_protocol ("tcp", &cache, &proto, 6); //6 is SOL_TCP on linux
143 }
144
145 int
146 mono_networking_get_ip_protocol (void)
147 {
148         static int cache, proto;
149         return fetch_protocol ("ip", &cache, &proto, 0); //0 is SOL_IP on linux
150 }
151
152 int
153 mono_networking_get_ipv6_protocol (void)
154 {
155         static int cache, proto;
156         return fetch_protocol ("ipv6", &cache, &proto, 41); //41 is SOL_IPV6 on linux
157 }
158
159 #endif
160
161 #if defined (HAVE_SIOCGIFCONF)
162
163 #define IFCONF_BUFF_SIZE 1024
164 #ifndef _SIZEOF_ADDR_IFREQ
165 #define _SIZEOF_ADDR_IFREQ(ifr) (sizeof (struct ifreq))
166 #endif
167
168 #define FOREACH_IFR(IFR, IFC) \
169         for (IFR = (IFC).ifc_req;       \
170         ifr < (struct ifreq*)((char*)(IFC).ifc_req + (IFC).ifc_len); \
171         ifr = (struct ifreq*)((char*)(IFR) + _SIZEOF_ADDR_IFREQ (*(IFR))))
172
173 void *
174 mono_get_local_interfaces (int family, int *interface_count)
175 {
176         int fd;
177         struct ifconf ifc;
178         struct ifreq *ifr;
179         int if_count = 0;
180         gboolean ignore_loopback = FALSE;
181         void *result = NULL;
182         char *result_ptr;
183
184         *interface_count = 0;
185
186         if (!mono_address_size_for_family (family))
187                 return NULL;
188
189         fd = socket (family, SOCK_STREAM, 0);
190         if (fd == -1)
191                 return NULL;
192
193         memset (&ifc, 0, sizeof (ifc));
194         ifc.ifc_len = IFCONF_BUFF_SIZE;
195         ifc.ifc_buf = (char *)g_malloc (IFCONF_BUFF_SIZE); /* We can't have such huge buffers on the stack. */
196         if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
197                 goto done;
198
199         FOREACH_IFR (ifr, ifc) {
200                 struct ifreq iflags;
201
202                 //only return addresses of the same type as @family
203                 if (ifr->ifr_addr.sa_family != family) {
204                         ifr->ifr_name [0] = '\0';
205                         continue;
206                 }
207
208                 strcpy (iflags.ifr_name, ifr->ifr_name);
209
210                 //ignore interfaces we can't get props for
211                 if (ioctl (fd, SIOCGIFFLAGS, &iflags) < 0) {
212                         ifr->ifr_name [0] = '\0';
213                         continue;
214                 }
215
216                 //ignore interfaces that are down
217                 if ((iflags.ifr_flags & IFF_UP) == 0) {
218                         ifr->ifr_name [0] = '\0';
219                         continue;
220                 }
221
222                 //If we have a non-loopback iface, don't return any loopback
223                 if ((iflags.ifr_flags & IFF_LOOPBACK) == 0) {
224                         ignore_loopback = TRUE;
225                         ifr->ifr_name [0] = 1;//1 means non-loopback
226                 } else {
227                         ifr->ifr_name [0] = 2; //2 means loopback
228                 }
229                 ++if_count;
230         }
231
232         result = (char *)g_malloc (if_count * mono_address_size_for_family (family));
233         result_ptr = (char *)result;
234         FOREACH_IFR (ifr, ifc) {
235                 if (ifr->ifr_name [0] == '\0')
236                         continue;
237
238                 if (ignore_loopback && ifr->ifr_name [0] == 2) {
239                         --if_count;
240                         continue;
241                 }
242
243                 memcpy (result_ptr, get_address_from_sockaddr (&ifr->ifr_addr), mono_address_size_for_family (family));
244                 result_ptr += mono_address_size_for_family (family);
245         }
246         g_assert (result_ptr <= (char*)result + if_count * mono_address_size_for_family (family));
247
248 done:
249         *interface_count = if_count;
250         g_free (ifc.ifc_buf);
251         close (fd);
252         return result;
253 }
254
255 #elif defined(HAVE_GETIFADDRS)
256
257 void *
258 mono_get_local_interfaces (int family, int *interface_count)
259 {
260         struct ifaddrs *ifap = NULL, *cur;
261         int if_count = 0;
262         gboolean ignore_loopback = FALSE;
263         void *result;
264         char *result_ptr;
265
266         *interface_count = 0;
267
268         if (!mono_address_size_for_family (family))
269                 return NULL;
270
271         if (getifaddrs (&ifap))
272                 return NULL;
273
274         for (cur = ifap; cur; cur = cur->ifa_next) {
275                 //ignore interfaces with no address assigned
276                 if (!cur->ifa_addr)
277                         continue;
278
279                 //ignore interfaces that don't belong to @family
280                 if (cur->ifa_addr->sa_family != family)
281                         continue;
282
283                 //ignore interfaces that are down
284                 if ((cur->ifa_flags & IFF_UP) == 0)
285                         continue;
286
287                 //If we have a non-loopback iface, don't return any loopback
288                 if ((cur->ifa_flags & IFF_LOOPBACK) == 0)
289                         ignore_loopback = TRUE;
290
291                 if_count++;
292         }
293
294         result_ptr = result = g_malloc (if_count * mono_address_size_for_family (family));
295         for (cur = ifap; cur; cur = cur->ifa_next) {
296                 if (!cur->ifa_addr)
297                         continue;
298                 if (cur->ifa_addr->sa_family != family)
299                         continue;
300                 if ((cur->ifa_flags & IFF_UP) == 0)
301                         continue;
302
303                 //we decrement if_count because it did not on the previous loop.
304                 if (ignore_loopback && (cur->ifa_flags & IFF_LOOPBACK)) {
305                         --if_count;
306                         continue;
307                 }
308
309                 memcpy (result_ptr, get_address_from_sockaddr (cur->ifa_addr), mono_address_size_for_family (family));
310                 result_ptr += mono_address_size_for_family (family);
311         }
312         g_assert (result_ptr <= (char*)result + if_count * mono_address_size_for_family (family));
313
314         freeifaddrs (ifap);
315         *interface_count = if_count;
316         return result;
317 }
318
319 #endif
320
321 #ifdef HAVE_GETNAMEINFO
322
323 gboolean
324 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
325 {
326         MonoSocketAddress saddr;
327         socklen_t len;
328         mono_socket_address_init (&saddr, &len, address->family, &address->addr, 0);
329
330         return getnameinfo (&saddr.addr, len, buffer, buflen, NULL, 0, NI_NUMERICHOST) == 0;
331 }
332
333 #elif HAVE_INET_NTOP
334
335 gboolean
336 mono_networking_addr_to_str (MonoAddress *address, char *buffer, socklen_t buflen)
337 {
338         return inet_ntop (address->family, &address->addr, buffer, buflen) != NULL;
339 }
340
341 #endif
342
343 #ifndef _WIN32
344 // These are already defined in networking-windows.c for Windows
345 void
346 mono_networking_init (void)
347 {
348         //nothing really
349 }
350
351 void
352 mono_networking_shutdown (void)
353 {
354         //nothing really
355 }
356 #endif