Mercurial > pidgin.yaz
changeset 29495:02f6f49da454
Add a function to enumerate all local IPs
Adapted the XMPP prpl to include all local IPs as local streamhosts.
I haven't had the chance to test if this actually works using a "non-default"
interface, such as a VPN connection...
Refs #10160
author | Marcus Lundblad <ml@update.uu.se> |
---|---|
date | Wed, 09 Sep 2009 19:01:03 +0000 |
parents | d6dff41a6d4c |
children | f1aa01ff26dd |
files | ChangeLog.API libpurple/network.c libpurple/network.h libpurple/protocols/jabber/si.c |
diffstat | 4 files changed, 104 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog.API Fri Sep 04 03:04:33 2009 +0000 +++ b/ChangeLog.API Wed Sep 09 19:01:03 2009 +0000 @@ -1,6 +1,9 @@ Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul version 2.7.0 (??/??/????): + libpurple: + Added: + * purple_network_get_all_local_system_ips version 2.6.1 (08/18/2009): No changes
--- a/libpurple/network.c Fri Sep 04 03:04:33 2009 +0000 +++ b/libpurple/network.c Wed Sep 09 19:01:03 2009 +0000 @@ -200,6 +200,82 @@ return "0.0.0.0"; } +GList * +purple_network_get_all_local_system_ips(int fd) +{ + GList *result = NULL; + int source = fd; + char buffer[1024]; + char *tmp; + struct ifconf ifc; + struct ifreq *ifr; + + if (fd < 0) + source = socket(PF_INET,SOCK_STREAM, 0); + + ifc.ifc_len = sizeof(buffer); + ifc.ifc_req = (struct ifreq *)buffer; + ioctl(source, SIOCGIFCONF, &ifc); + + if (fd < 0) + close(source); + + /* enumerate the interfaces on IPv4 (or from source given by fd) */ + tmp = buffer; + while (tmp < buffer + ifc.ifc_len) { + char dst[INET6_ADDRSTRLEN]; + + ifr = (struct ifreq *)tmp; + tmp += HX_SIZE_OF_IFREQ(*ifr); + + if (ifr->ifr_addr.sa_family == AF_INET) { + struct sockaddr_in *sinptr = (struct sockaddr_in *)&ifr->ifr_addr; + + inet_ntop(AF_INET, &sinptr->sin_addr, dst, + sizeof(dst)); + purple_debug_info("network", + "found local i/f with address %s on IPv4\n", dst); + if (!purple_strequal(dst, "127.0.0.1")) { + result = g_list_append(result, g_strdup(dst)); + } + } + } + + /* enumerate IPv6 interfaces (done when NOT specifying an fd, + in that case use it (see above)) */ + if (fd < 0) { + source = socket(PF_INET6, SOCK_STREAM, 0); + + ifc.ifc_len = sizeof(buffer); + ifc.ifc_req = (struct ifreq *)buffer; + ioctl(source, SIOCGIFCONF, &ifc); + + close(source); + + tmp = buffer; + while (tmp < buffer + ifc.ifc_len) { + char dst[INET6_ADDRSTRLEN]; + + ifr = (struct ifreq *)tmp; + tmp += HX_SIZE_OF_IFREQ(*ifr); + + if (ifr->ifr_addr.sa_family == AF_INET6) { + struct sockaddr_in6 *sinptr = + (struct sockaddr_in6 *)&ifr->ifr_addr; + + inet_ntop(AF_INET6, &sinptr->sin6_addr, dst, sizeof(dst)); + purple_debug_info("network", + "found local i/f with address %s on IPv4\n", dst); + if (!purple_strequal(dst, "::1")) { + result = g_list_append(result, g_strdup(dst)); + } + } + } + } + + return result; +} + const char * purple_network_get_my_ip(int fd) {
--- a/libpurple/network.h Fri Sep 04 03:04:33 2009 +0000 +++ b/libpurple/network.h Wed Sep 09 19:01:03 2009 +0000 @@ -88,6 +88,16 @@ const char *purple_network_get_local_system_ip(int fd); /** + * Returns all IP addresses of the local system. + * + * @note The caller must free this list + * + * @param fd The fd to use to help figure out the IPs, or else -1. + * @return A list of local IP addresses. + */ +GList *purple_network_get_all_local_system_ips(int fd); + +/** * Returns the IP address that should be used anywhere a * public IP addresses is needed (listening for an incoming * file transfer, etc).
--- a/libpurple/protocols/jabber/si.c Fri Sep 04 03:04:33 2009 +0000 +++ b/libpurple/protocols/jabber/si.c Wed Sep 09 19:01:03 2009 +0000 @@ -853,8 +853,11 @@ /* If we successfully started listening locally */ if (sock >= 0) { gchar *jid; - const char *local_ip, *public_ip; - + GList *local_ips = + purple_network_get_all_local_system_ips(jsx->js->fd); + const char *public_ip; + gboolean has_public_ip = FALSE; + jsx->local_streamhost_fd = sock; jid = g_strdup_printf("%s@%s/%s", jsx->js->user->node, @@ -862,19 +865,24 @@ xfer->local_port = purple_network_get_port_from_fd(sock); g_snprintf(port, sizeof(port), "%hu", xfer->local_port); - /* Include the localhost's IP (for in-network transfers) */ - local_ip = purple_network_get_local_system_ip(jsx->js->fd); - if (strcmp(local_ip, "0.0.0.0") != 0) { + public_ip = purple_network_get_my_ip(jsx->js->fd); + + /* Include the localhost's IPs (for in-network transfers) */ + while (local_ips) { + gchar *local_ip = local_ips->data; streamhost_count++; streamhost = xmlnode_new_child(query, "streamhost"); xmlnode_set_attrib(streamhost, "jid", jid); xmlnode_set_attrib(streamhost, "host", local_ip); xmlnode_set_attrib(streamhost, "port", port); + if (purple_strequal(local_ip, public_ip)) + has_public_ip = TRUE; + g_free(local_ip); + local_ips = g_list_delete_link(local_ips, local_ips); } /* Include the public IP (assuming that there is a port mapped somehow) */ - public_ip = purple_network_get_my_ip(jsx->js->fd); - if (strcmp(public_ip, local_ip) != 0 && strcmp(public_ip, "0.0.0.0") != 0) { + if (!has_public_ip && strcmp(public_ip, "0.0.0.0") != 0) { streamhost_count++; streamhost = xmlnode_new_child(query, "streamhost"); xmlnode_set_attrib(streamhost, "jid", jid);