Mercurial > pidgin
comparison libpurple/network.c @ 29372:529233281dfe
network: Use getifaddrs() to enumerate local interfaces/IPs if available.
On Linux, it seems SIOCGIFCONF just doesn't support IPv6, and various
systems have getifaddrs(), so here we are. Fixes #10160.
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Tue, 16 Feb 2010 02:21:33 +0000 |
parents | ecd1aa92fd57 |
children | ce3f4bd8939b |
comparison
equal
deleted
inserted
replaced
29371:667806b1f359 | 29372:529233281dfe |
---|---|
30 #include <arpa/nameser.h> | 30 #include <arpa/nameser.h> |
31 #include <resolv.h> | 31 #include <resolv.h> |
32 #include <netinet/in.h> | 32 #include <netinet/in.h> |
33 #include <net/if.h> | 33 #include <net/if.h> |
34 #include <sys/ioctl.h> | 34 #include <sys/ioctl.h> |
35 #ifdef HAVE_GETIFADDRS | |
36 #include <ifaddrs.h> | |
37 #endif | |
35 #else | 38 #else |
36 #include <nspapi.h> | 39 #include <nspapi.h> |
37 #endif | 40 #endif |
38 | 41 |
39 /* Solaris */ | 42 /* Solaris */ |
201 } | 204 } |
202 | 205 |
203 GList * | 206 GList * |
204 purple_network_get_all_local_system_ips(void) | 207 purple_network_get_all_local_system_ips(void) |
205 { | 208 { |
209 #ifdef HAVE_GETIFADDRS | |
210 GList *result = NULL; | |
211 struct ifaddrs *start, *ifa; | |
212 int ret; | |
213 | |
214 ret = getifaddrs(&start); | |
215 if (ret < 0) { | |
216 purple_debug_warning("network", | |
217 "getifaddrs() failed: %s\n", g_strerror(errno)); | |
218 return NULL; | |
219 } | |
220 | |
221 for (ifa = start; ifa; ifa = ifa->ifa_next) { | |
222 int family = ifa->ifa_addr ? ifa->ifa_addr->sa_family : AF_UNSPEC; | |
223 char host[INET6_ADDRSTRLEN]; | |
224 const char *tmp = NULL; | |
225 | |
226 if ((family != AF_INET && family != AF_INET6) || ifa->ifa_flags & IFF_LOOPBACK) | |
227 continue; | |
228 | |
229 if (family == AF_INET) | |
230 tmp = inet_ntop(family, &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr, host, sizeof(host)); | |
231 else { | |
232 struct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)ifa->ifa_addr; | |
233 /* Peer-peer link-local communication is a big TODO. I am not sure | |
234 * how communicating link-local addresses is supposed to work, and | |
235 * it seems like it would require attempting the cartesian product | |
236 * of the local and remote interfaces to see if any match (eww). | |
237 */ | |
238 if (!IN6_IS_ADDR_LINKLOCAL(&sockaddr->sin6_addr)) | |
239 tmp = inet_ntop(family, &sockaddr->sin6_addr, host, sizeof(host)); | |
240 } | |
241 if (tmp != NULL) | |
242 result = g_list_prepend(result, g_strdup(tmp)); | |
243 } | |
244 | |
245 freeifaddrs(start); | |
246 | |
247 return g_list_reverse(result); | |
248 #else /* HAVE_GETIFADDRS */ | |
206 GList *result = NULL; | 249 GList *result = NULL; |
207 int source = socket(PF_INET,SOCK_STREAM, 0); | 250 int source = socket(PF_INET,SOCK_STREAM, 0); |
208 char buffer[1024]; | 251 char buffer[1024]; |
209 char *tmp; | 252 char *tmp; |
210 struct ifconf ifc; | 253 struct ifconf ifc; |
220 char dst[INET_ADDRSTRLEN]; | 263 char dst[INET_ADDRSTRLEN]; |
221 | 264 |
222 ifr = (struct ifreq *)tmp; | 265 ifr = (struct ifreq *)tmp; |
223 tmp += HX_SIZE_OF_IFREQ(*ifr); | 266 tmp += HX_SIZE_OF_IFREQ(*ifr); |
224 | 267 |
225 /* TODO: handle IPv6 */ | |
226 if (ifr->ifr_addr.sa_family == AF_INET) { | 268 if (ifr->ifr_addr.sa_family == AF_INET) { |
227 struct sockaddr_in *sinptr = (struct sockaddr_in *)&ifr->ifr_addr; | 269 struct sockaddr_in *sinptr = (struct sockaddr_in *)&ifr->ifr_addr; |
228 | 270 |
229 inet_ntop(AF_INET, &sinptr->sin_addr, dst, | 271 inet_ntop(AF_INET, &sinptr->sin_addr, dst, |
230 sizeof(dst)); | 272 sizeof(dst)); |
235 } | 277 } |
236 } | 278 } |
237 } | 279 } |
238 | 280 |
239 return result; | 281 return result; |
282 #endif /* HAVE_GETIFADDRS */ | |
240 } | 283 } |
241 | 284 |
242 const char * | 285 const char * |
243 purple_network_get_my_ip(int fd) | 286 purple_network_get_my_ip(int fd) |
244 { | 287 { |