Mercurial > pidgin
changeset 29751:2b294edceaed
merge of '229f226a4d7937c46842e33328e05fc827bf3573'
and '56dbb07bba4460522cb38830486f96c1d361d78b'
author | Elliott Sales de Andrade <qulogic@pidgin.im> |
---|---|
date | Sat, 17 Apr 2010 22:22:21 +0000 |
parents | 4aa17d7c4e0a (diff) e7b9a5ba3777 (current diff) |
children | e59f29a9dbf1 |
files | |
diffstat | 6 files changed, 193 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog.API Sat Apr 17 22:21:17 2010 +0000 +++ b/ChangeLog.API Sat Apr 17 22:22:21 2010 +0000 @@ -17,11 +17,20 @@ * purple_media_codec_copy * purple_media_manager_get_backend_type * purple_media_manager_set_backend_type - * purple_network_get_all_local_system_ips, which returns all local - IPs on the system. On systems with the getifaddrs() function, - this will return both IPv4 and IPv6 addresses (excluding link-local - and loopback addresses). On others, it returns just IPv4 addresses. + * purple_network_get_all_local_system_ips, which returns all + local IPs on the system. On systems with the getifaddrs() + function, this will return both IPv4 and IPv6 addresses + (excluding link-local and loopback addresses). On others, + it returns just IPv4 addresses. + * purple_network_listen_family and + purple_network_listen_range_family. These will replace the + versions without _family in 3.0.0 and allow the caller to + specifically request either an IPv4 or IPv6 socket. IPv6 is + only supported if the getaddrinfo() function is available + at build-time (not the case on Windows, currently). * purple_prpl_got_media_caps + * purple_socket_get_family + * purple_socket_speaks_ipv4 * purple_unescape_text * purple_uuid_random * media_caps to the PurpleBuddy struct @@ -30,9 +39,9 @@ * sent-attention conversation signal * got-attention conversation signal * PurpleMood struct in status.h - * purple_certificates_import for importing multiple certificates from - a single file (and corresponding import_certificates member of - PurpleCertificateScheme struct) + * purple_certificates_import for importing multiple + certificates from a single file (and corresponding + import_certificates member of PurpleCertificateScheme struct) Pidgin: Added:
--- a/configure.ac Sat Apr 17 22:21:17 2010 +0000 +++ b/configure.ac Sat Apr 17 22:22:21 2010 +0000 @@ -184,6 +184,12 @@ [Define if struct sockaddr has an sa_len member])],[:], [#include <sys/socket.h>]) +dnl Check for v6-only sockets +AC_CHECK_DECL([IPV6_V6ONLY], + [AC_DEFINE([HAVE_IPV6_V6ONLY],[1], + [Define if the IPV6_V6ONLY setsockopt option exists])], + [], [#include <netinet/in.h>]) + dnl to prevent the g_stat()/g_unlink() crash, dnl (09:50:07) Robot101: LSchiere2: it's easy. +LC_SYS_LARGEFILE somewhere in configure.ac AC_SYS_LARGEFILE
--- a/libpurple/network.c Sat Apr 17 22:21:17 2010 +0000 +++ b/libpurple/network.c Sat Apr 17 22:22:21 2010 +0000 @@ -394,7 +394,7 @@ } static PurpleNetworkListenData * -purple_network_do_listen(unsigned short port, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data) +purple_network_do_listen(unsigned short port, int socket_family, int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data) { int listenfd = -1; int flags; @@ -412,7 +412,7 @@ g_snprintf(serv, sizeof(serv), "%hu", port); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; - hints.ai_family = AF_UNSPEC; + hints.ai_family = socket_family; hints.ai_socktype = socket_type; errnum = getaddrinfo(NULL /* any IP */, serv, &hints, &res); if (errnum != 0) { @@ -436,7 +436,7 @@ if (listenfd < 0) continue; if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) - purple_debug_warning("network", "setsockopt: %s\n", g_strerror(errno)); + purple_debug_warning("network", "setsockopt(SO_REUSEADDR): %s\n", g_strerror(errno)); if (bind(listenfd, next->ai_addr, next->ai_addrlen) == 0) break; /* success */ /* XXX - It is unclear to me (datallah) whether we need to be @@ -451,6 +451,13 @@ #else struct sockaddr_in sockin; + if (socket_family != AF_INET && socket_family != AF_UNSPEC) { + purple_debug_warning("network", "Address family %d only " + "supported when built with getaddrinfo() " + "support\n", socket_family); + return NULL; + } + if ((listenfd = socket(AF_INET, socket_type, 0)) < 0) { purple_debug_warning("network", "socket: %s\n", g_strerror(errno)); return NULL; @@ -492,7 +499,8 @@ listen_data->cb_data = cb_data; listen_data->socket_type = socket_type; - if (!listen_map_external || !purple_prefs_get_bool("/purple/network/map_ports")) + if (!purple_socket_speaks_ipv4(listenfd) || !listen_map_external || + !purple_prefs_get_bool("/purple/network/map_ports")) { purple_debug_info("network", "Skipping external port mapping.\n"); /* The pmp_map_cb does what we want to do */ @@ -519,17 +527,29 @@ } PurpleNetworkListenData * -purple_network_listen(unsigned short port, int socket_type, - PurpleNetworkListenCallback cb, gpointer cb_data) +purple_network_listen_family(unsigned short port, int socket_family, + int socket_type, PurpleNetworkListenCallback cb, + gpointer cb_data) { g_return_val_if_fail(port != 0, NULL); - return purple_network_do_listen(port, socket_type, cb, cb_data); + return purple_network_do_listen(port, socket_family, socket_type, + cb, cb_data); } PurpleNetworkListenData * -purple_network_listen_range(unsigned short start, unsigned short end, - int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data) +purple_network_listen(unsigned short port, int socket_type, + PurpleNetworkListenCallback cb, gpointer cb_data) +{ + return purple_network_listen_family(port, AF_UNSPEC, socket_type, + cb, cb_data); +} + +PurpleNetworkListenData * +purple_network_listen_range_family(unsigned short start, unsigned short end, + int socket_family, int socket_type, + PurpleNetworkListenCallback cb, + gpointer cb_data) { PurpleNetworkListenData *ret = NULL; @@ -542,7 +562,7 @@ } for (; start <= end; start++) { - ret = purple_network_do_listen(start, socket_type, cb, cb_data); + ret = purple_network_do_listen(start, AF_UNSPEC, socket_type, cb, cb_data); if (ret != NULL) break; } @@ -550,6 +570,15 @@ return ret; } +PurpleNetworkListenData * +purple_network_listen_range(unsigned short start, unsigned short end, + int socket_type, PurpleNetworkListenCallback cb, + gpointer cb_data) +{ + return purple_network_listen_range_family(start, end, AF_UNSPEC, + socket_type, cb, cb_data); +} + void purple_network_listen_cancel(PurpleNetworkListenData *listen_data) { if (listen_data->mapping_data != NULL)
--- a/libpurple/network.h Sat Apr 17 22:21:17 2010 +0000 +++ b/libpurple/network.h Sat Apr 17 22:22:21 2010 +0000 @@ -138,8 +138,8 @@ * * This opens a listening port. The caller will want to set up a watcher * of type PURPLE_INPUT_READ on the fd returned in cb. It will probably call - * accept in the watcher callback, and then possibly remove the watcher and close - * the listening socket, and add a new watcher on the new socket accept + * accept in the watcher callback, and then possibly remove the watcher and + * close the listening socket, and add a new watcher on the new socket accept * returned. * * @param port The port number to bind to. Must be greater than 0. @@ -158,6 +158,27 @@ int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data); /** + * \copydoc purple_network_listen + * + * Libpurple does not currently do any port mapping (stateful firewall hole + * poking) for IPv6-only listeners (if an IPv6 socket supports v4-mapped + * addresses, a mapping is done). + * + * @param socket_family The protocol family of the socket. This should be + * AF_INET for IPv4 or AF_INET6 for IPv6. IPv6 sockets + * may or may not be able to accept IPv4 connections + * based on the system configuration (use + * purple_socket_speaks_ipv4 to check). If an IPv6 + * socket doesn't accept V4-mapped addresses, you will + * need a second listener to support both v4 and v6. + * @since 2.7.0 + * @deprecated This function will be renamed to purple_network_listen in 3.0.0. + */ +PurpleNetworkListenData *purple_network_listen_family(unsigned short port, + int socket_family, int socket_type, PurpleNetworkListenCallback cb, + gpointer cb_data); + +/** * Opens a listening port selected from a range of ports. The range of * ports used is chosen in the following manner: * If a range is specified in preferences, these values are used. @@ -192,6 +213,28 @@ PurpleNetworkListenCallback cb, gpointer cb_data); /** + * \copydoc purple_network_listen_range + * + * Libpurple does not currently do any port mapping (stateful firewall hole + * poking) for IPv6-only listeners (if an IPv6 socket supports v4-mapped + * addresses, a mapping is done). + * + * @param socket_family The protocol family of the socket. This should be + * AF_INET for IPv4 or AF_INET6 for IPv6. IPv6 sockets + * may or may not be able to accept IPv4 connections + * based on the system configuration (use + * purple_socket_speaks_ipv4 to check). If an IPv6 + * socket doesn't accept V4-mapped addresses, you will + * need a second listener to support both v4 and v6. + * @since 2.7.0 + * @deprecated This function will be renamed to purple_network_listen_range + * in 3.0.0. + */ +PurpleNetworkListenData *purple_network_listen_range_family( + unsigned short start, unsigned short end, int socket_family, + int socket_type, PurpleNetworkListenCallback cb, gpointer cb_data); + +/** * This can be used to cancel any in-progress listener connection * by passing in the return value from either purple_network_listen() * or purple_network_listen_range().
--- a/libpurple/util.c Sat Apr 17 22:21:17 2010 +0000 +++ b/libpurple/util.c Sat Apr 17 22:22:21 2010 +0000 @@ -2972,19 +2972,78 @@ char * purple_fd_get_ip(int fd) { - struct sockaddr addr; + struct sockaddr_storage addr; socklen_t namelen = sizeof(addr); - struct in_addr in; + int family; g_return_val_if_fail(fd != 0, NULL); - if (getsockname(fd, &addr, &namelen)) + if (getsockname(fd, (struct sockaddr *)&addr, &namelen)) return NULL; - in = ((struct sockaddr_in *)&addr)->sin_addr; - return g_strdup(inet_ntoa(in)); + family = ((struct sockaddr *)&addr)->sa_family; + + if (family == AF_INET) { + struct sockaddr_in *ipv4 = (struct sockaddr_in *)&addr; + struct in_addr addr = ipv4->sin_addr; + return g_strdup(inet_ntoa(addr)); + } +#if defined(AF_INET6) && defined(HAVE_INET_NTOP) + else if (family == AF_INET6) { + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&addr; + struct in6_addr addr = ipv6->sin6_addr; + char host[INET6_ADDRSTRLEN]; + const char *tmp; + + tmp = inet_ntop(family, &addr, host, sizeof(host)); + return g_strdup(tmp); + } +#endif + + return NULL; } +int +purple_socket_get_family(int fd) +{ + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); + + g_return_val_if_fail(fd >= 0, -1); + + if (getsockname(fd, (struct sockaddr *)&addr, &len)) + return -1; + + return ((struct sockaddr *)&addr)->sa_family; +} + +gboolean +purple_socket_speaks_ipv4(int fd) +{ + int family; + + g_return_val_if_fail(fd >= 0, FALSE); + + family = purple_socket_get_family(fd); + + switch (family) { + case AF_INET: + return TRUE; +#if defined(IPV6_V6ONLY) + case AF_INET6: + { + int val = 0; + guint len = sizeof(val); + + if (getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, &len) != 0) + return FALSE; + return !val; + } +#endif + default: + return FALSE; + } +} /************************************************************************** * String Functions
--- a/libpurple/util.h Sat Apr 17 22:21:17 2010 +0000 +++ b/libpurple/util.h Sat Apr 17 22:22:21 2010 +0000 @@ -819,6 +819,29 @@ */ char *purple_fd_get_ip(int fd); +/** + * Returns the address family of a socket. + * + * @param fd The socket file descriptor. + * + * @return The address family of the socket (AF_INET, AF_INET6, etc) or -1 + * on error. + * @since 2.7.0 + */ +int purple_socket_get_family(int fd); + +/** + * Returns TRUE if a socket is capable of speaking IPv4. + * + * This is the case for IPv4 sockets and, on some systems, IPv6 sockets + * (due to the IPv4-mapped address functionality). + * + * @param fd The socket file descriptor + * @return TRUE if a socket can speak IPv4. + * @since 2.7.0 + */ +gboolean purple_socket_speaks_ipv4(int fd); + /*@}*/