pidgin.next.minor: a3f7a4c3: Add a function to enumerate all local IP...

malu at pidgin.im malu at pidgin.im
Wed Sep 9 15:06:36 EDT 2009


-----------------------------------------------------------------
Revision: a3f7a4c3280716f828ba129e718bbf16b1a691f4
Ancestor: 0e7acf32357c38a563c6428eee1e27fbb39caccc
Author: malu at pidgin.im
Date: 2009-09-09T19:01:03
Branch: im.pidgin.pidgin.next.minor
URL: http://d.pidgin.im/viewmtn/revision/info/a3f7a4c3280716f828ba129e718bbf16b1a691f4

Modified files:
        ChangeLog.API libpurple/network.c libpurple/network.h
        libpurple/protocols/jabber/si.c

ChangeLog: 

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

-------------- next part --------------
============================================================
--- ChangeLog.API	99ecc5217e0f0affec5666271ccad30b52c1d4ab
+++ ChangeLog.API	21d058413be3a081ed5824f03180a72fe6493bfe
@@ -1,6 +1,9 @@ version 2.7.0 (??/??/????):
 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
============================================================
--- libpurple/network.c	14ce71dc03dff47e6c4a2d6efc9642c4299eeb13
+++ libpurple/network.c	6e231d9f4e9f0dc2f86d417d2c9db4e6e9beb8b2
@@ -200,6 +200,82 @@ purple_network_get_local_system_ip(int f
 	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)
 {
============================================================
--- libpurple/network.h	d0f48ebf86652fe313c6459f130f886c3b663461
+++ libpurple/network.h	0692729dcd6a63f697121778e64901d8b8595670
@@ -88,6 +88,16 @@ const char *purple_network_get_local_sys
 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).
============================================================
--- libpurple/protocols/jabber/si.c	90609b8a58493beeea0b2b02ec3648f8d0a9a075
+++ libpurple/protocols/jabber/si.c	95f735f395ac622f9a5d33f549b84fe1c20d1c00
@@ -853,8 +853,11 @@ jabber_si_xfer_bytestreams_listen_cb(int
 	/* 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 @@ jabber_si_xfer_bytestreams_listen_cb(int
 		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);


More information about the Commits mailing list