discovery: Remove useless checks from discovery_add_peer_reflexive_candidate
[sipe-libnice.git] / agent / interfaces.c
blob12f15eff10eb195d6212db70d4cc0532711ce984
1 /*
2 * interfaces.c - Source for interface discovery code
4 * Copyright (C) 2006 Youness Alaoui <kakaroto@kakaroto.homelinux.net>
5 * Copyright (C) 2007 Collabora, Nokia
6 * Contact: Youness Alaoui
7 * Copyright (C) 2008 Haakon Sporsheim <haakon.sporsheim@tandberg.com>
8 * @author: Youness Alaoui <kakaroto@kakaroto.homelinux.net>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include "interfaces.h"
30 #include "debug.h"
32 #ifdef G_OS_UNIX
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <sys/ioctl.h>
40 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
45 #ifdef HAVE_GETIFADDRS
46 #include <ifaddrs.h>
47 #endif
49 #include <net/if.h>
50 #include <net/if_arp.h>
51 #include <arpa/inet.h>
53 #ifdef HAVE_GETIFADDRS
55 GList *
56 nice_interfaces_get_local_interfaces (void)
58 GList *interfaces = NULL;
59 struct ifaddrs *ifa, *results;
61 if (getifaddrs (&results) < 0) {
62 return NULL;
65 /* Loop and get each interface the system has, one by one... */
66 for (ifa = results; ifa; ifa = ifa->ifa_next) {
67 /* no ip address from interface that is down */
68 if ((ifa->ifa_flags & IFF_UP) == 0)
69 continue;
71 if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
72 continue;
74 nice_debug ("Found interface : %s", ifa->ifa_name);
75 interfaces = g_list_prepend (interfaces, g_strdup (ifa->ifa_name));
78 freeifaddrs (results);
80 return interfaces;
83 #else /* ! HAVE_GETIFADDRS */
85 GList *
86 nice_interfaces_get_local_interfaces (void)
88 GList *interfaces = NULL;
89 gint sockfd;
90 gint size = 0;
91 struct ifreq *ifr;
92 struct ifconf ifc;
94 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
95 nice_debug ("error : Cannot open socket to retreive interface list");
96 return NULL;
99 ifc.ifc_len = 0;
100 ifc.ifc_req = NULL;
102 /* Loop and get each interface the system has, one by one... */
103 do {
104 size += sizeof (struct ifreq);
105 /* realloc buffer size until no overflow occurs */
106 if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) {
107 nice_debug ("Error : Out of memory while allocation interface"
108 "configuration structure");
109 close (sockfd);
110 return NULL;
112 ifc.ifc_len = size;
114 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
115 perror ("ioctl SIOCFIFCONF");
116 close (sockfd);
117 free (ifc.ifc_req);
118 return NULL;
120 } while (size <= ifc.ifc_len);
123 /* Loop throught the interface list and get the IP address of each IF */
124 for (ifr = ifc.ifc_req;
125 (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len;
126 ++ifr) {
127 nice_debug ("Found interface : %s", ifr->ifr_name);
128 interfaces = g_list_prepend (interfaces, g_strdup (ifr->ifr_name));
131 free (ifc.ifc_req);
132 close (sockfd);
134 return interfaces;
136 #endif /* HAVE_GETIFADDRS */
139 static gboolean
140 nice_interfaces_is_private_ip (const struct in_addr in)
142 /* 10.x.x.x/8 */
143 if (in.s_addr >> 24 == 0x0A)
144 return TRUE;
146 /* 172.16.0.0 - 172.31.255.255 = 172.16.0.0/10 */
147 if (in.s_addr >> 20 == 0xAC1)
148 return TRUE;
150 /* 192.168.x.x/16 */
151 if (in.s_addr >> 16 == 0xC0A8)
152 return TRUE;
154 /* 169.254.x.x/16 (for APIPA) */
155 if (in.s_addr >> 16 == 0xA9FE)
156 return TRUE;
158 return FALSE;
161 #ifdef HAVE_GETIFADDRS
163 GList *
164 nice_interfaces_get_local_ips (gboolean include_loopback)
166 GList *ips = NULL;
167 struct sockaddr_in *sa;
168 struct ifaddrs *ifa, *results;
169 gchar *loopback = NULL;
172 if (getifaddrs (&results) < 0)
173 return NULL;
175 /* Loop through the interface list and get the IP address of each IF */
176 for (ifa = results; ifa; ifa = ifa->ifa_next) {
177 /* no ip address from interface that is down */
178 if ((ifa->ifa_flags & IFF_UP) == 0)
179 continue;
181 if (ifa->ifa_addr == NULL || ifa->ifa_addr->sa_family != AF_INET)
182 continue;
184 sa = (struct sockaddr_in *) ifa->ifa_addr;
186 nice_debug ("Interface: %s", ifa->ifa_name);
187 nice_debug ("IP Address: %s", inet_ntoa (sa->sin_addr));
188 if ((ifa->ifa_flags & IFF_LOOPBACK) == IFF_LOOPBACK) {
189 if (include_loopback)
190 loopback = g_strdup (inet_ntoa (sa->sin_addr));
191 else
192 nice_debug ("Ignoring loopback interface");
193 } else {
194 if (nice_interfaces_is_private_ip (sa->sin_addr))
195 ips = g_list_append (ips, g_strdup (inet_ntoa (sa->sin_addr)));
196 else
197 ips = g_list_prepend (ips, g_strdup (inet_ntoa (sa->sin_addr)));
201 freeifaddrs (results);
203 if (loopback)
204 ips = g_list_append (ips, loopback);
206 return ips;
209 #else /* ! HAVE_GETIFADDRS */
211 GList *
212 nice_interfaces_get_local_ips (gboolean include_loopback)
214 GList *ips = NULL;
215 gint sockfd;
216 gint size = 0;
217 struct ifreq *ifr;
218 struct ifconf ifc;
219 struct sockaddr_in *sa;
220 gchar *loopback = NULL;
222 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
223 nice_debug ("Error : Cannot open socket to retreive interface list");
224 return NULL;
227 ifc.ifc_len = 0;
228 ifc.ifc_req = NULL;
230 /* Loop and get each interface the system has, one by one... */
231 do {
232 size += sizeof (struct ifreq);
233 /* realloc buffer size until no overflow occurs */
234 if (NULL == (ifc.ifc_req = realloc (ifc.ifc_req, size))) {
235 nice_debug ("Error : Out of memory while allocation interface"
236 " configuration structure");
237 close (sockfd);
238 return NULL;
240 ifc.ifc_len = size;
242 if (ioctl (sockfd, SIOCGIFCONF, &ifc)) {
243 perror ("ioctl SIOCFIFCONF");
244 close (sockfd);
245 free (ifc.ifc_req);
246 return NULL;
248 } while (size <= ifc.ifc_len);
251 /* Loop throught the interface list and get the IP address of each IF */
252 for (ifr = ifc.ifc_req;
253 (gchar *) ifr < (gchar *) ifc.ifc_req + ifc.ifc_len;
254 ++ifr) {
256 if (ioctl (sockfd, SIOCGIFFLAGS, ifr)) {
257 nice_debug ("Error : Unable to get IP information for interface %s."
258 " Skipping...", ifr->ifr_name);
259 continue; /* failed to get flags, skip it */
261 sa = (struct sockaddr_in *) &ifr->ifr_addr;
262 nice_debug ("Interface: %s", ifr->ifr_name);
263 nice_debug ("IP Address: %s", inet_ntoa (sa->sin_addr));
264 if ((ifr->ifr_flags & IFF_LOOPBACK) == IFF_LOOPBACK){
265 if (include_loopback)
266 loopback = g_strdup (inet_ntoa (sa->sin_addr));
267 else
268 nice_debug ("Ignoring loopback interface");
269 } else {
270 if (nice_interfaces_is_private_ip (sa->sin_addr)) {
271 ips = g_list_append (ips, g_strdup (inet_ntoa (sa->sin_addr)));
272 } else {
273 ips = g_list_prepend (ips, g_strdup (inet_ntoa (sa->sin_addr)));
278 close (sockfd);
279 free (ifc.ifc_req);
281 if (loopback)
282 ips = g_list_append (ips, loopback);
284 return ips;
287 #endif /* HAVE_GETIFADDRS */
289 gchar *
290 nice_interfaces_get_ip_for_interface (gchar *interface_name)
292 struct ifreq ifr;
293 struct sockaddr_in *sa;
294 gint sockfd;
297 ifr.ifr_addr.sa_family = AF_INET;
298 memset (ifr.ifr_name, 0, sizeof (ifr.ifr_name));
299 g_strlcpy (ifr.ifr_name, interface_name, sizeof (ifr.ifr_name));
301 if ((sockfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
302 nice_debug ("Error : Cannot open socket to retreive interface list");
303 return NULL;
306 if (ioctl (sockfd, SIOCGIFADDR, &ifr) < 0) {
307 nice_debug ("Error : Unable to get IP information for interface %s",
308 interface_name);
309 close (sockfd);
310 return NULL;
313 close (sockfd);
314 sa = (struct sockaddr_in *) &ifr.ifr_addr;
315 nice_debug ("Address for %s: %s", interface_name, inet_ntoa (sa->sin_addr));
316 return g_strdup (inet_ntoa (sa->sin_addr));
319 #else /* G_OS_UNIX */
320 #ifdef G_OS_WIN32
322 #include <winsock2.h>
323 #include <Iphlpapi.h>
325 static gboolean started_wsa_engine = FALSE;
328 * private function that initializes the WinSock engine and
329 * returns a prebuilt socket
331 SOCKET nice_interfaces_get_WSA_socket ()
333 WORD wVersionRequested;
334 WSADATA wsaData;
335 int err;
336 SOCKET sock;
338 if (started_wsa_engine == FALSE) {
339 wVersionRequested = MAKEWORD ( 2, 0 );
341 err = WSAStartup ( wVersionRequested, &wsaData );
342 if ( err != 0 ) {
343 nice_debug ("Error : Could not start the winsocket engine");
344 return INVALID_SOCKET;
346 started_wsa_engine = TRUE;
350 if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
351 nice_debug ("Error : Could not open socket to retreive interface list,"
352 " error no : %d", WSAGetLastError ());
353 return INVALID_SOCKET;
356 return sock;
359 GList * nice_interfaces_get_local_interfaces ()
361 ULONG size = 0;
362 PMIB_IFTABLE if_table;
363 GList * ret = NULL;
365 GetIfTable(NULL, &size, TRUE);
367 if (!size)
368 return NULL;
370 if_table = (PMIB_IFTABLE)g_malloc0(size);
372 if (GetIfTable(if_table, &size, TRUE) == ERROR_SUCCESS) {
373 DWORD i;
374 for (i = 0; i < if_table->dwNumEntries; i++) {
375 ret = g_list_prepend (ret, g_strdup ((gchar*)if_table->table[i].bDescr));
379 g_free(if_table);
381 return ret;
384 GList * nice_interfaces_get_local_ips (gboolean include_loopback)
386 ULONG size = 0;
387 DWORD pref = 0;
388 PMIB_IPADDRTABLE ip_table;
389 GList * ret = NULL;
391 GetIpAddrTable (NULL, &size, TRUE);
393 if (!size)
394 return NULL;
397 * Get the best interface for transport to 0.0.0.0.
398 * This interface should be first in list!
400 if (GetBestInterface (0, &pref) != NO_ERROR)
401 pref = 0;
403 ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size);
405 if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) {
406 DWORD i;
407 for (i = 0; i < ip_table->dwNumEntries; i++) {
408 gchar * ipstr;
409 PMIB_IPADDRROW ipaddr = &ip_table->table[i];
411 if (!(ipaddr->wType & (MIB_IPADDR_DISCONNECTED | MIB_IPADDR_DELETED)) &&
412 ipaddr->dwAddr) {
413 if (!include_loopback) {
414 DWORD type = 0;
415 PMIB_IFROW ifr = (PMIB_IFROW)g_malloc0 (sizeof (MIB_IFROW));
416 ifr->dwIndex = ipaddr->dwIndex;
417 if (GetIfEntry (ifr) == NO_ERROR)
418 type = ifr->dwType;
419 g_free (ifr);
421 if (type == IF_TYPE_SOFTWARE_LOOPBACK)
422 continue;
425 ipstr = g_strdup_printf ("%d.%d.%d.%d",
426 (ipaddr->dwAddr ) & 0xFF,
427 (ipaddr->dwAddr >> 8) & 0xFF,
428 (ipaddr->dwAddr >> 16) & 0xFF,
429 (ipaddr->dwAddr >> 24) & 0xFF);
430 if (ipaddr->dwIndex == pref)
431 ret = g_list_prepend (ret, ipstr);
432 else
433 ret = g_list_append (ret, ipstr);
438 g_free(ip_table);
440 return ret;
444 * returns ip address as an utf8 string
446 static gchar *
447 win32_get_ip_for_interface (IF_INDEX idx)
449 ULONG size = 0;
450 PMIB_IPADDRTABLE ip_table;
451 gchar * ret = NULL;
453 GetIpAddrTable (NULL, &size, TRUE);
455 if (!size)
456 return NULL;
458 ip_table = (PMIB_IPADDRTABLE)g_malloc0 (size);
460 if (GetIpAddrTable (ip_table, &size, TRUE) == ERROR_SUCCESS) {
461 DWORD i;
462 for (i = 0; i < ip_table->dwNumEntries; i++) {
463 PMIB_IPADDRROW ipaddr = &ip_table->table[i];
464 if (ipaddr->dwIndex == idx &&
465 !(ipaddr->wType & (MIB_IPADDR_DISCONNECTED | MIB_IPADDR_DELETED))) {
466 ret = g_strdup_printf ("%d.%d.%d.%d",
467 (ipaddr->dwAddr ) & 0xFF,
468 (ipaddr->dwAddr >> 8) & 0xFF,
469 (ipaddr->dwAddr >> 16) & 0xFF,
470 (ipaddr->dwAddr >> 24) & 0xFF);
471 break;
476 g_free (ip_table);
477 return ret;
480 gchar * nice_interfaces_get_ip_for_interface (gchar *interface_name)
482 ULONG size = 0;
483 PMIB_IFTABLE if_table;
484 gchar * ret = NULL;
486 GetIfTable (NULL, &size, TRUE);
488 if (!size)
489 return NULL;
491 if_table = (PMIB_IFTABLE)g_malloc0 (size);
493 if (GetIfTable (if_table, &size, TRUE) == ERROR_SUCCESS) {
494 DWORD i;
495 gchar * tmp_str;
496 for (i = 0; i < if_table->dwNumEntries; i++) {
497 tmp_str = g_utf16_to_utf8 (
498 if_table->table[i].wszName, MAX_INTERFACE_NAME_LEN,
499 NULL, NULL, NULL);
501 if (strlen (interface_name) == strlen (tmp_str) &&
502 g_ascii_strncasecmp (interface_name, tmp_str, strlen (interface_name)) == 0) {
503 ret = win32_get_ip_for_interface (if_table->table[i].dwIndex);
504 g_free (tmp_str);
505 break;
508 g_free (tmp_str);
512 g_free (if_table);
514 return ret;
518 #else /* G_OS_WIN32 */
519 #error Can not use this method for retreiving ip list from OS other than unix or windows
520 #endif /* G_OS_WIN32 */
521 #endif /* G_OS_UNIX */