Merged in rw_grim/pidgin (pull request #3)
Replace custom DNS code with GResolver
--- a/configure.ac Wed Dec 23 22:13:29 2015 -0600
+++ b/configure.ac Wed Dec 23 22:32:36 2015 -0600
@@ -477,13 +477,13 @@
AM_CONDITIONAL(INSTALL_I18N, test "x$enable_i18n" = "xyes")
dnl #######################################################################
-dnl # Check for GLib 2.20 (required)
+dnl # Check for GLib 2.34 (required) dnl #######################################################################
-PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28.0 gio-2.0 gobject-2.0 gthread-2.0], , [
+PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.34.0 gio-2.0 gobject-2.0 gthread-2.0], , [ -You must have GLib 2.20.0 or newer development headers installed to build.
+You must have GLib 2.34.0 or newer development headers installed to build. If you have these installed already you may need to install pkg-config so
--- a/libpurple/Makefile.am Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/Makefile.am Wed Dec 23 22:32:36 2015 -0600
@@ -106,8 +106,6 @@
@@ -187,8 +185,6 @@
--- a/libpurple/core.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/core.c Wed Dec 23 22:32:36 2015 -0600
@@ -26,7 +26,6 @@
#include "conversation.h"
@@ -200,7 +199,6 @@
- purple_dnsquery_init();
@@ -276,7 +274,6 @@
- purple_dnsquery_uninit();
_purple_image_store_uninit();
--- a/libpurple/dnsquery.c Wed Dec 23 22:13:29 2015 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1080 +0,0 @@
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#define _PURPLE_DNSQUERY_C_
-#define MAX_ADDR_RESPONSE_LEN 1048576
-#if (defined(__APPLE__) || defined (__unix__)) && !defined(__osf__)
-#define PURPLE_DNSQUERY_USE_FORK
-/**************************************************************************
- **************************************************************************/
-static PurpleDnsQueryUiOps *dns_query_ui_ops = NULL;
-typedef struct _PurpleDnsQueryResolverProcess PurpleDnsQueryResolverProcess;
-struct _PurpleDnsQueryData {
- PurpleDnsQueryConnectFunction callback;
- PurpleAccount *account;
-#if defined(PURPLE_DNSQUERY_USE_FORK)
- PurpleDnsQueryResolverProcess *resolver;
-#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK */
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-#define MAX_DNS_CHILDREN 4
- * This structure keeps a reference to a child resolver process.
-struct _PurpleDnsQueryResolverProcess {
-static GSList *free_dns_children = NULL;
-static GQueue *queued_requests = NULL;
-static int number_of_dns_children = 0;
- * This is a convenience struct used to pass data to
- * the child resolver process.
-#endif /* end PURPLE_DNSQUERY_USE_FORK */
-purple_dnsquery_resolved(PurpleDnsQueryData *query_data, GSList *hosts)
- purple_debug_info("dnsquery", "IP resolved for %s\n", query_data->hostname);
- if (query_data->callback != NULL)
- query_data->callback(hosts, query_data->data, NULL);
- * Callback is a required parameter, but it can get set to
- * NULL if we cancel a thread-based DNS lookup. So we need
- hosts = g_slist_remove(hosts, hosts->data);
- hosts = g_slist_remove(hosts, hosts->data);
-#ifdef PURPLE_DNSQUERY_USE_FORK
- * Add the resolver to the list of available resolvers, and set it
- * to NULL so that it doesn't get destroyed along with the query_data
- if (query_data->resolver)
- free_dns_children = g_slist_prepend(free_dns_children, query_data->resolver);
- query_data->resolver = NULL;
-#endif /* PURPLE_DNSQUERY_USE_FORK */
- purple_dnsquery_destroy(query_data);
-purple_dnsquery_failed(PurpleDnsQueryData *query_data, const gchar *error_message)
- purple_debug_error("dnsquery", "%s\n", error_message);
- if (query_data->callback != NULL)
- query_data->callback(NULL, query_data->data, error_message);
- purple_dnsquery_destroy(query_data);
-purple_dnsquery_ui_resolve(PurpleDnsQueryData *query_data)
- PurpleDnsQueryUiOps *ops = purple_dnsquery_get_ui_ops();
- if (ops && ops->resolve_host)
- return ops->resolve_host(query_data, purple_dnsquery_resolved, purple_dnsquery_failed);
-resolve_ip(PurpleDnsQueryData *query_data)
-#if defined(HAVE_GETADDRINFO) && defined(AI_NUMERICHOST)
- struct addrinfo hints, *res;
- g_snprintf(servname, sizeof(servname), "%d", query_data->port);
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_flags |= AI_NUMERICHOST;
- if (0 == getaddrinfo(query_data->hostname, servname, &hints, &res))
- hosts = g_slist_append(hosts, GINT_TO_POINTER(res->ai_addrlen));
- hosts = g_slist_append(hosts, g_memdup(res->ai_addr, res->ai_addrlen));
- purple_dnsquery_resolved(query_data, hosts);
-#else /* defined(HAVE_GETADDRINFO) && defined(AI_NUMERICHOST) */
- struct sockaddr_in sin;
- if (inet_aton(query_data->hostname, &sin.sin_addr))
- * The given "hostname" is actually an IP address, so we
- * don't need to do anything.
- sin.sin_family = AF_INET;
- sin.sin_port = htons(query_data->port);
- hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
- hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
- purple_dnsquery_resolved(query_data, hosts);
-dns_str_is_ascii(const char *name)
- for (c = (guchar *)name; c && *c; ++c) {
-#if defined(PURPLE_DNSQUERY_USE_FORK)
- * Begin the DNS resolver child process functions.
-G_GNUC_NORETURN static void
- "Purple's DNS child got a SIGTRAP signal.\n"
- "This can be caused by trying to run purple inside gdb.\n"
- "There is a known gdb bug which prevents this. Supposedly purple\n"
- "should have detected you were using gdb and used an ugly hack,\n"
- "check cope_with_gdb_brokenness() in dnsquery.c.\n\n"
- "For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n";
- fputs("\n* * *\n",stderr);
- fputs("* * *\n\n",stderr);
- execlp("xmessage","xmessage","-center", message, NULL);
-write_to_parent(int fd, const void *buf, size_t count)
- written = write(fd, buf, count);
- if (written < 0 || (gsize)written != count) {
- fprintf(stderr, "dns[%d]: Error writing data to "
- "parent: %s\n", getpid(), strerror(errno));
- fprintf(stderr, "dns[%d]: Error: Tried to write %"
- G_GSIZE_FORMAT " bytes to parent but instead "
- "wrote %" G_GSIZE_FORMAT " bytes\n",
- getpid(), count, written);
-G_GNUC_NORETURN static void
-purple_dnsquery_resolver_run(int child_out, int child_in, gboolean show_debug)
- dns_params_t dns_params;
- struct addrinfo hints, *res, *tmp;
- struct sockaddr_in sin;
- const size_t addrlen = sizeof(sin);
- purple_restore_default_signal_handlers();
- signal(SIGTRAP, trap_gdb_bug);
- * We resolve 1 host name for each iteration of this
- * The top half of this reads in the hostname and port
- * number from the socket with our parent. The bottom
- * half of this resolves the IP (blocking) and sends
- * the result back to our parent, when finished.
- struct timeval tv = { .tv_sec = 20, .tv_usec = 0 };
- FD_SET(child_in, &fds);
- rc = select(child_in + 1, &fds, NULL, NULL, &tv);
- printf("dns[%d]: nobody needs me... =(\n", getpid());
- rc = read(child_in, &dns_params, sizeof(dns_params_t));
- if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
- fprintf(stderr, "dns[%d]: Error: Could not read dns_params: "
- "%s\n", getpid(), strerror(errno));
- printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid());
- if (dns_params.hostname[0] == '\0') {
- fprintf(stderr, "dns[%d]: Error: Parent requested resolution "
- "of an empty hostname (port = %d)!!!\n", getpid(),
- if (!dns_str_is_ascii(dns_params.hostname)) {
- rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname);
- write_to_parent(child_out, &rc, sizeof(rc));
- fprintf(stderr, "dns[%d] Error: IDN conversion returned "
- dns_params.hostname[0] = '\0';
- } else /* intentional to execute the g_strdup */
- hostname = g_strdup(dns_params.hostname);
- /* We have the hostname and port, now resolve the IP */
- g_snprintf(servname, sizeof(servname), "%d", dns_params.port);
- memset(&hints, 0, sizeof(hints));
- /* This is only used to convert a service
- * name to a port number. As we know we are
- * passing a number already, we know this
- * value will not be really used by the C
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags |= AI_ADDRCONFIG;
-#endif /* AI_ADDRCONFIG */
- rc = getaddrinfo(hostname, servname, &hints, &res);
- write_to_parent(child_out, &rc, sizeof(rc));
- printf("dns[%d] Error: getaddrinfo returned %d\n",
- dns_params.hostname[0] = '\0';
- size_t ai_addrlen = res->ai_addrlen;
- write_to_parent(child_out, &ai_addrlen, sizeof(ai_addrlen));
- write_to_parent(child_out, res->ai_addr, res->ai_addrlen);
- if (!(hp = gethostbyname(hostname))) {
- write_to_parent(child_out, &h_errno, sizeof(int));
- printf("DNS Error: %d\n", h_errno);
- memset(&sin, 0, sizeof(struct sockaddr_in));
- memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
- sin.sin_family = hp->h_addrtype;
- sin.sin_port = htons(dns_params.port);
- write_to_parent(child_out, &rc, sizeof(rc));
- write_to_parent(child_out, &addrlen, sizeof(addrlen));
- write_to_parent(child_out, &sin, addrlen);
- write_to_parent(child_out, &zero, sizeof(zero));
- dns_params.hostname[0] = '\0';
- * End the DNS resolver child process functions.
- * Begin the functions for dealing with the DNS child processes.
-cope_with_gdb_brokenness(void)
- static gboolean already_done = FALSE;
- g_snprintf(s, sizeof(s), "/proc/%d/exe", ppid);
- n = readlink(s, e, sizeof(e));
- e[MIN((gsize)n,sizeof(e)-1)] = '\0';
- purple_debug_info("dns",
- "Debugger detected, performing useless query...\n");
- gethostbyname("x.x.x.x.x");
-purple_dnsquery_resolver_destroy(PurpleDnsQueryResolverProcess *resolver)
- g_return_if_fail(resolver != NULL);
- /* Keep this before the kill() call below. */
- if (resolver->inpa != 0) {
- purple_input_remove(resolver->inpa);
- * We might as well attempt to kill our child process. It really
- * doesn't matter if this fails, because children will expire on
- * their own after a few seconds.
- if (resolver->dns_pid > 0)
- kill(resolver->dns_pid, SIGKILL);
- close(resolver->fd_in);
- close(resolver->fd_out);
- number_of_dns_children--;
-static PurpleDnsQueryResolverProcess *
-purple_dnsquery_resolver_new(gboolean show_debug)
- PurpleDnsQueryResolverProcess *resolver;
- int child_out[2], child_in[2];
- /* Create pipes for communicating with the child process */
- if (pipe(child_out) || pipe(child_in)) {
- purple_debug_error("dns",
- "Could not create pipes: %s\n", g_strerror(errno));
- resolver = g_new(PurpleDnsQueryResolverProcess, 1);
- cope_with_gdb_brokenness();
- /* "Go fork and multiply." --Tommy Caldwell (Emily's dad, not the climber) */
- resolver->dns_pid = fork();
- /* If we are the child process... */
- if (resolver->dns_pid == 0) {
- /* We should not access the parent's side of the pipes, so close them */
- purple_dnsquery_resolver_run(child_out[1], child_in[0], show_debug);
- /* The thread calls _exit() rather than returning, so we never get here */
- /* We should not access the child's side of the pipes, so close them */
- if (resolver->dns_pid == -1) {
- purple_debug_error("dns",
- "Could not create child process for DNS: %s\n",
- purple_dnsquery_resolver_destroy(resolver);
- resolver->fd_out = child_out[0];
- resolver->fd_in = child_in[1];
- number_of_dns_children++;
- purple_debug_info("dns",
- "Created new DNS child %d, there are now %d children.\n",
- resolver->dns_pid, number_of_dns_children);
- * send_dns_request_to_child:
- * Returns: TRUE if the request was sent succesfully. FALSE
- * if the request could not be sent. This isn't
- * necessarily an error. If the child has expired,
- * for example, we won't be able to send the message.
-send_dns_request_to_child(PurpleDnsQueryData *query_data,
- PurpleDnsQueryResolverProcess *resolver)
- dns_params_t dns_params;
- /* This waitpid might return the child's PID if it has recently
- * exited, or it might return an error if it exited "long
- * enough" ago that it has already been reaped; in either
- * instance, we can't use it. */
- pid = waitpid(resolver->dns_pid, NULL, WNOHANG);
- purple_debug_info("dns", "DNS child %d no longer exists\n",
- purple_dnsquery_resolver_destroy(resolver);
- purple_debug_info("dns", "Wait for DNS child %d failed: %s\n",
- resolver->dns_pid, g_strerror(errno));
- purple_dnsquery_resolver_destroy(resolver);
- /* Copy the hostname and port into a single data structure */
- strncpy(dns_params.hostname, query_data->hostname, sizeof(dns_params.hostname) - 1);
- dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0';
- dns_params.port = query_data->port;
- /* Send the data structure to the child */
- rc = write(resolver->fd_in, &dns_params, sizeof(dns_params));
- purple_debug_error("dns", "Unable to write to DNS child %d: %s\n",
- resolver->dns_pid, g_strerror(errno));
- purple_dnsquery_resolver_destroy(resolver);
- if ((gsize)rc < sizeof(dns_params)) {
- purple_debug_error("dns", "Tried to write %" G_GSSIZE_FORMAT
- " bytes to child but only wrote %" G_GSSIZE_FORMAT "\n",
- sizeof(dns_params), rc);
- purple_dnsquery_resolver_destroy(resolver);
- purple_debug_info("dns",
- "Successfully sent DNS request to child %d\n",
- query_data->resolver = resolver;
-static void host_resolved(gpointer data, gint source, PurpleInputCondition cond);
-handle_next_queued_request(void)
- PurpleDnsQueryData *query_data;
- PurpleDnsQueryResolverProcess *resolver;
- if (g_queue_is_empty(queued_requests))
- /* No more DNS queries, yay! */
- query_data = g_queue_pop_head(queued_requests);
- * If we have any children, attempt to have them perform the DNS
- * query. If we're able to send the query then resolver will be
- * set to the PurpleDnsQueryResolverProcess. Otherwise, resolver
- * will be NULL and we'll need to create a new DNS request child.
- while (free_dns_children != NULL)
- resolver = free_dns_children->data;
- free_dns_children = g_slist_remove(free_dns_children, resolver);
- if (send_dns_request_to_child(query_data, resolver))
- /* We found an acceptable child, yay */
- /* We need to create a new DNS request child */
- if (query_data->resolver == NULL)
- if (number_of_dns_children >= MAX_DNS_CHILDREN)
- /* Apparently all our children are busy */
- g_queue_push_head(queued_requests, query_data);
- resolver = purple_dnsquery_resolver_new(purple_debug_is_enabled());
- purple_dnsquery_failed(query_data, _("Unable to create new resolver process\n"));
- if (!send_dns_request_to_child(query_data, resolver))
- purple_dnsquery_failed(query_data, _("Unable to send request to resolver process\n"));
- query_data->resolver->inpa = purple_input_add(query_data->resolver->fd_out,
- PURPLE_INPUT_READ, host_resolved, query_data);
- * End the functions for dealing with the DNS child processes.
-host_resolved(gpointer data, gint source, PurpleInputCondition cond)
- PurpleDnsQueryData *query_data;
- struct sockaddr *addr = NULL;
- purple_debug_info("dns", "Got response for '%s'\n", query_data->hostname);
- purple_input_remove(query_data->resolver->inpa);
- query_data->resolver->inpa = 0;
- rc = read(query_data->resolver->fd_out, &err, sizeof(err));
- if ((rc == 4) && (err != 0))
- g_snprintf(message, sizeof(message), _("Error resolving %s:\n%s"),
- query_data->hostname, purple_gai_strerror(err));
- g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
- query_data->hostname, err);
- /* Re-read resolv.conf and friends in case DNS servers have changed */
- purple_dnsquery_failed(query_data, message);
- rc = read(query_data->resolver->fd_out, &addrlen, sizeof(addrlen));
- if (rc > 0 && addrlen > 0 && addrlen < MAX_ADDR_RESPONSE_LEN) {
- addr = g_malloc(addrlen);
- rc = read(query_data->resolver->fd_out, addr, addrlen);
- hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen));
- hosts = g_slist_append(hosts, addr);
- /* wait4(resolver->dns_pid, NULL, WNOHANG, NULL); */
- purple_dnsquery_resolved(query_data, hosts);
- g_snprintf(message, sizeof(message), _("Error reading from resolver process:\n%s"), g_strerror(errno));
- purple_dnsquery_failed(query_data, message);
- g_snprintf(message, sizeof(message), _("Resolver process exited without answering our request"));
- purple_dnsquery_failed(query_data, message);
- handle_next_queued_request();
-resolve_host(PurpleDnsQueryData *query_data)
- g_queue_push_tail(queued_requests, query_data);
- handle_next_queued_request();
-#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK */
-dns_main_thread_cb(gpointer data)
- PurpleDnsQueryData *query_data = data;
- /* We're done, so purple_dnsquery_destroy() shouldn't think it is canceling an in-progress lookup */
- query_data->resolver = NULL;
- if (query_data->error_message != NULL)
- purple_dnsquery_failed(query_data, query_data->error_message);
- /* We don't want purple_dns_query_resolved() to free(hosts) */
- hosts = query_data->hosts;
- query_data->hosts = NULL;
- purple_dnsquery_resolved(query_data, hosts);
-dns_thread(gpointer data)
- PurpleDnsQueryData *query_data;
-#if defined(HAVE_GETADDRINFO) || defined(USE_IDN)
- struct addrinfo hints, *res, *tmp;
- struct sockaddr_in sin;
- if (!dns_str_is_ascii(query_data->hostname)) {
- rc = purple_network_convert_idn_to_ascii(query_data->hostname, &hostname);
- query_data->error_message = g_strdup_printf(_("Error converting %s "
- "to punycode: %d"), query_data->hostname, rc);
- /* back to main thread */
- purple_timeout_add(0, dns_main_thread_cb, query_data);
- } else /* intentional fallthru */
- hostname = g_strdup(query_data->hostname);
- g_snprintf(servname, sizeof(servname), "%d", query_data->port);
- memset(&hints,0,sizeof(hints));
- * This is only used to convert a service
- * name to a port number. As we know we are
- * passing a number already, we know this
- * value will not be really used by the C
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags |= AI_ADDRCONFIG;
-#endif /* AI_ADDRCONFIG */
- if ((rc = getaddrinfo(hostname, servname, &hints, &res)) == 0) {
- query_data->hosts = g_slist_append(query_data->hosts,
- GSIZE_TO_POINTER(res->ai_addrlen));
- query_data->hosts = g_slist_append(query_data->hosts,
- g_memdup(res->ai_addr, res->ai_addrlen));
- query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), query_data->hostname, purple_gai_strerror(rc));
- if ((hp = gethostbyname(hostname))) {
- memset(&sin, 0, sizeof(struct sockaddr_in));
- memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
- sin.sin_family = hp->h_addrtype;
- sin.sin_port = htons(query_data->port);
- query_data->hosts = g_slist_append(query_data->hosts,
- GSIZE_TO_POINTER(sizeof(sin)));
- query_data->hosts = g_slist_append(query_data->hosts,
- g_memdup(&sin, sizeof(sin)));
- query_data->error_message = g_strdup_printf(_("Error resolving %s: %d"), query_data->hostname, h_errno);
- /* back to main thread */
- purple_timeout_add(0, dns_main_thread_cb, query_data);
-resolve_host(PurpleDnsQueryData *query_data)
- * Spin off a separate thread to perform the DNS lookup so
- * that we don't block the UI.
- query_data->resolver = g_thread_try_new("dnsquery resolver", dns_thread,
- if (query_data->resolver == NULL)
- g_snprintf(message, sizeof(message), _("Thread creation failure: %s"),
- (err && err->message) ? err->message : _("Unknown reason"));
- purple_dnsquery_failed(query_data, message);
- g_thread_unref(query_data->resolver);
-#else /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
- * We weren't able to do anything fancier above, so use the
- * fail-safe name resolution code, which is blocking.
-resolve_host(PurpleDnsQueryData *query_data)
- struct sockaddr_in sin;
- if (!dns_str_is_ascii(query_data->hostname)) {
- int ret = purple_network_convert_idn_to_ascii(query_data->hostname,
- g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
- query_data->hostname, ret);
- purple_dnsquery_failed(query_data, message);
- } else /* fallthrough is intentional to the g_strdup */
- hostname = g_strdup(query_data->hostname);
- if(!(hp = gethostbyname(hostname))) {
- g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
- query_data->hostname, h_errno);
- purple_dnsquery_failed(query_data, message);
- memset(&sin, 0, sizeof(struct sockaddr_in));
- memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
- sin.sin_family = hp->h_addrtype;
- sin.sin_port = htons(query_data->port);
- hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
- hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
- purple_dnsquery_resolved(query_data, hosts);
-#endif /* not PURPLE_DNSQUERY_USE_FORK or _WIN32 */
-initiate_resolving(gpointer data)
- PurpleDnsQueryData *query_data;
- PurpleProxyType proxy_type;
- query_data->timeout = 0;
- if (resolve_ip(query_data))
- /* resolve_ip calls purple_dnsquery_resolved */
- proxy_type = purple_proxy_info_get_proxy_type(
- purple_proxy_get_setup(query_data->account));
- if (proxy_type == PURPLE_PROXY_TOR) {
- purple_dnsquery_failed(query_data,
- _("Aborting DNS lookup in Tor Proxy mode."));
- if (purple_dnsquery_ui_resolve(query_data))
- /* The UI is handling the resolve; we're done */
- resolve_host(query_data);
-purple_dnsquery_a(PurpleAccount *account, const char *hostname, int port,
- PurpleDnsQueryConnectFunction callback, gpointer data)
- PurpleDnsQueryData *query_data;
- g_return_val_if_fail(hostname != NULL, NULL);
- g_return_val_if_fail(port != 0, NULL);
- g_return_val_if_fail(callback != NULL, NULL);
- purple_debug_info("dnsquery", "Performing DNS lookup for %s\n", hostname);
- query_data = g_new0(PurpleDnsQueryData, 1);
- query_data->hostname = g_strdup(hostname);
- g_strstrip(query_data->hostname);
- query_data->port = port;
- query_data->callback = callback;
- query_data->data = data;
- query_data->account = account;
- if (*query_data->hostname == '\0')
- purple_dnsquery_destroy(query_data);
- g_return_val_if_reached(NULL);
- query_data->timeout = purple_timeout_add(0, initiate_resolving, query_data);
-purple_dnsquery_destroy(PurpleDnsQueryData *query_data)
- PurpleDnsQueryUiOps *ops = purple_dnsquery_get_ui_ops();
- if (ops && ops->destroy)
- ops->destroy(query_data);
-#if defined(PURPLE_DNSQUERY_USE_FORK)
- g_queue_remove(queued_requests, query_data);
- if (query_data->resolver != NULL)
- * This is only non-NULL when we're cancelling an in-progress
- * query. Ideally we would tell our resolver child to stop
- * resolving shit and then we would add it back to the
- * free_dns_children linked list. However, it's hard to tell
- * children stuff, they just don't listen. So we'll just
- * kill the process and allow a new child to be started if we
- * have more stuff to resolve.
- purple_dnsquery_resolver_destroy(query_data->resolver);
-#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK */
- if (query_data->resolver != NULL)
- * It's not really possible to kill a thread. So instead we
- * just set the callback to NULL and let the DNS lookup
- query_data->callback = NULL;
- while (query_data->hosts != NULL)
- /* Discard the length... */
- query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
- /* Free the address... */
- g_free(query_data->hosts->data);
- query_data->hosts = g_slist_remove(query_data->hosts, query_data->hosts->data);
- g_free(query_data->error_message);
- if (query_data->timeout > 0)
- purple_timeout_remove(query_data->timeout);
- g_free(query_data->hostname);
-purple_dnsquery_get_host(PurpleDnsQueryData *query_data)
- g_return_val_if_fail(query_data != NULL, NULL);
- return query_data->hostname;
-purple_dnsquery_get_port(PurpleDnsQueryData *query_data)
- g_return_val_if_fail(query_data != NULL, 0);
- return query_data->port;
-static PurpleDnsQueryUiOps *
-purple_dnsquery_ui_ops_copy(PurpleDnsQueryUiOps *ops)
- PurpleDnsQueryUiOps *ops_new;
- g_return_val_if_fail(ops != NULL, NULL);
- ops_new = g_new(PurpleDnsQueryUiOps, 1);
-purple_dnsquery_ui_ops_get_type(void)
- type = g_boxed_type_register_static("PurpleDnsQueryUiOps",
- (GBoxedCopyFunc)purple_dnsquery_ui_ops_copy,
- (GBoxedFreeFunc)g_free);
-purple_dnsquery_set_ui_ops(PurpleDnsQueryUiOps *ops)
- dns_query_ui_ops = ops;
-purple_dnsquery_get_ui_ops(void)
- /* It is perfectly acceptable for dns_query_ui_ops to be NULL; this just
- * means that the default platform-specific implementation will be used.
- return dns_query_ui_ops;
-purple_dnsquery_init(void)
-#if defined(PURPLE_DNSQUERY_USE_FORK)
- queued_requests = g_queue_new();
-purple_dnsquery_uninit(void)
-#if defined(PURPLE_DNSQUERY_USE_FORK)
- while (free_dns_children != NULL)
- purple_dnsquery_resolver_destroy(free_dns_children->data);
- free_dns_children = g_slist_remove(free_dns_children, free_dns_children->data);
- g_queue_free(queued_requests);
- queued_requests = NULL;
-#endif /* end PURPLE_DNSQUERY_USE_FORK */
--- a/libpurple/dnsquery.h Wed Dec 23 22:13:29 2015 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#ifndef _PURPLE_DNSQUERY_H_
-#define _PURPLE_DNSQUERY_H_
- * @section_id: libpurple-dnsquery
- * @short_description: <filename>dnsquery.h</filename>
- * @title: DNS Query API
-#define PURPLE_TYPE_DNSQUERY_UI_OPS (purple_dnsquery_ui_ops_get_type())
- * An opaque structure representing a DNS query. The hostname and port
- * associated with the query can be retrieved using
- * purple_dnsquery_get_host() and purple_dnsquery_get_port().
-typedef struct _PurpleDnsQueryData PurpleDnsQueryData;
-typedef struct _PurpleDnsQueryUiOps PurpleDnsQueryUiOps;
- * PurpleDnsQueryConnectFunction:
- * The "hosts" parameter is a linked list containing pairs of
- * one size_t addrlen and one struct sockaddr *addr. It should
- * be free'd by the callback function.
-typedef void (*PurpleDnsQueryConnectFunction)(GSList *hosts, gpointer data, const char *error_message);
- * PurpleDnsQueryResolvedCallback:
- * DNS query resolved callback used by the UI if it handles resolving DNS
-typedef void (*PurpleDnsQueryResolvedCallback) (PurpleDnsQueryData *query_data, GSList *hosts);
- * PurpleDnsQueryFailedCallback:
- * DNS query failed callback used by the UI if it handles resolving DNS
-typedef void (*PurpleDnsQueryFailedCallback) (PurpleDnsQueryData *query_data, const gchar *error_message);
- * @resolve_host: If implemented, return %TRUE if the UI takes responsibility
- * for DNS queries. When returning %FALSE, the standard
- * implementation is used.
- * @destroy: Called just before @query_data is freed; this should cancel
- * any further use of @query_data the UI would make. Unneeded if
- * @resolve_host is not implemented.
- * DNS Request UI operations; UIs should implement this if they want to do DNS
- * lookups themselves, rather than relying on the core.
- * See <link linkend="chapter-ui-ops">List of <literal>UiOps</literal>
-struct _PurpleDnsQueryUiOps
- gboolean (*resolve_host)(PurpleDnsQueryData *query_data,
- PurpleDnsQueryResolvedCallback resolved_cb,
- PurpleDnsQueryFailedCallback failed_cb);
- void (*destroy)(PurpleDnsQueryData *query_data);
- void (*_purple_reserved1)(void);
- void (*_purple_reserved2)(void);
- void (*_purple_reserved3)(void);
- void (*_purple_reserved4)(void);
-/**************************************************************************/
-/**************************************************************************/
- * purple_dnsquery_ui_ops_get_type:
- * Returns: The #GType for the #PurpleDnsQueryUiOps boxed structure.
-GType purple_dnsquery_ui_ops_get_type(void);
- * @account: The account that the query is being done for (or NULL)
- * @hostname: The hostname to resolve.
- * @port: A port number which is stored in the struct sockaddr.
- * @callback: (scope call): The callback function to call after resolving.
- * @data: Extra data to pass to the callback function.
- * Perform an asynchronous DNS query.
- * Returns: NULL if there was an error, otherwise return a reference to
- * a data structure that can be used to cancel the pending
- * DNS query, if needed.
-PurpleDnsQueryData *purple_dnsquery_a(PurpleAccount *account, const char *hostname, int port, PurpleDnsQueryConnectFunction callback, gpointer data);
- * purple_dnsquery_destroy:
- * @query_data: The DNS query to cancel. This data structure
- * is freed by this function.
- * Cancel a DNS query and destroy the associated data structure.
-void purple_dnsquery_destroy(PurpleDnsQueryData *query_data);
- * purple_dnsquery_set_ui_ops:
- * @ops: The UI operations structure.
- * Sets the UI operations structure to be used when doing a DNS
- * resolve. The UI operations need only be set if the UI wants to
- * handle the resolve itself; otherwise, leave it as NULL.
-void purple_dnsquery_set_ui_ops(PurpleDnsQueryUiOps *ops);
- * purple_dnsquery_get_ui_ops:
- * Returns the UI operations structure to be used when doing a DNS
- * Returns: The UI operations structure.
-PurpleDnsQueryUiOps *purple_dnsquery_get_ui_ops(void);
- * purple_dnsquery_get_host:
- * @query_data: The DNS query
- * Get the host associated with a PurpleDnsQueryData
-char *purple_dnsquery_get_host(PurpleDnsQueryData *query_data);
- * purple_dnsquery_get_port:
- * @query_data: The DNS query
- * Get the port associated with a PurpleDnsQueryData
-unsigned short purple_dnsquery_get_port(PurpleDnsQueryData *query_data);
- * purple_dnsquery_init:
- * Initializes the DNS query subsystem.
-void purple_dnsquery_init(void);
- * purple_dnsquery_uninit:
- * Uninitializes the DNS query subsystem.
-void purple_dnsquery_uninit(void);
-#endif /* _PURPLE_DNSQUERY_H_ */
--- a/libpurple/dnssrv.c Wed Dec 23 22:13:29 2015 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1163 +0,0 @@
- * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#define _PURPLE_DNSSRV_C_
-#include <arpa/nameser.h>
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-#include <arpa/nameser_compat.h>
-/* Missing from the mingw headers */
-# define DNS_TYPE_SRV PurpleDnsTypeSrv
-# define DNS_TYPE_TXT PurpleDnsTypeTxt
-#define T_SRV PurpleDnsTypeSrv
-#define T_TXT PurpleDnsTypeTxt
-#define MAX_ADDR_RESPONSE_LEN 1048576
-static PurpleSrvTxtQueryUiOps *srv_txt_query_ui_ops = NULL;
-struct _PurpleSrvTxtQueryData {
-typedef struct _PurpleSrvInternalQuery {
-} PurpleSrvInternalQuery;
-typedef struct _PurpleSrvResponseContainer {
- PurpleSrvResponse *response;
-} PurpleSrvResponseContainer;
-static gboolean purple_srv_txt_query_ui_resolve(PurpleSrvTxtQueryData *query_data);
- * Sort by priority, then by weight. Strictly numerically--no
- * randomness. Technically we only need to sort by pref and then
- * make sure any records with weight 0 are at the beginning of
- * their group, but it's just as easy to sort by weight.
-responsecompare(gconstpointer ar, gconstpointer br)
- PurpleSrvResponse *a = (PurpleSrvResponse*)ar;
- PurpleSrvResponse *b = (PurpleSrvResponse*)br;
- if(a->pref == b->pref) {
- if(a->weight == b->weight)
- if(a->weight < b->weight)
- * select_random_response:
- * @list: The list of PurpleSrvResponseContainer. This function
- * removes a node from this list and returns the new list.
- * @container_ptr: The PurpleSrvResponseContainer that was chosen
- * will be returned here.
- * Iterate over a list of PurpleSrvResponseContainer making the sum
- * the running total of the sums. Select a random integer in the range
- * (1, sum+1), then find the first element greater than or equal to the
- * number selected. From RFC 2782.
-select_random_response(GList *list, PurpleSrvResponseContainer **container_ptr)
- g_return_val_if_fail(list != NULL, NULL);
- PurpleSrvResponseContainer *container = cur->data;
- runningtotal += container->response->weight;
- container->sum = runningtotal;
- * If the running total is greater than 0, pick a number between
- * 1 and the runningtotal inclusive. (This is not precisely what
- * the RFC algorithm describes, but we wish to deal with integers
- * and avoid floats. This is functionally equivalent.)
- * If running total is 0, then choose r = 0.
- r = runningtotal ? g_random_int_range(1, runningtotal + 1) : 0;
- while (r > ((PurpleSrvResponseContainer *)cur->data)->sum) {
- if (G_UNLIKELY(!cur->next))
- /* Set the return parameter and remove cur from the list */
- *container_ptr = cur->data;
- return g_list_delete_link(list, cur);
- * Reorder a GList of PurpleSrvResponses that have the same priority
-srv_reorder(GList *list, int num)
- GList *cur, *container_list = NULL;
- PurpleSrvResponseContainer *container;
- g_return_if_fail(list != NULL);
- /* First build a list of container structs */
- for (i = 0, cur = list; i < num; i++, cur = cur->next) {
- container = g_new(PurpleSrvResponseContainer, 1);
- container->response = cur->data;
- container_list = g_list_prepend(container_list, container);
- container_list = g_list_reverse(container_list);
- * Re-order the list that was passed in as a parameter. We leave
- * the list nodes in place, but replace their data pointers.
- while (container_list) {
- container_list = select_random_response(container_list, &container);
- cur->data = container->response;
- * @list: The original list, resorted
- * Sorts a GList of PurpleSrvResponses according to the
- * algorithm described in RFC 2782.
- * Returns: GList of PurpleSrvResponse's
-purple_srv_sort(GList *list)
- if (!list || !list->next) {
- list = g_list_sort(list, responsecompare);
- PurpleSrvResponse *next_response;
- g_return_val_if_fail(cur->data, list);
- pref = ((PurpleSrvResponse *)cur->data)->pref;
- next_response = cur->next ? cur->next->data : NULL;
- if (!next_response || next_response->pref != pref) {
- * The 'count' records starting at 'start' all have the same
- * priority. Sort them by weight.
- srv_reorder(start, count);
-static PurpleSrvTxtQueryData *
-query_data_new(int type, gchar *query, gpointer extradata)
- PurpleSrvTxtQueryData *query_data = g_new0(PurpleSrvTxtQueryData, 1);
- query_data->type = type;
- query_data->extradata = extradata;
- query_data->query = query;
- query_data->fd_in = -1;
- query_data->fd_out = -1;
-purple_srv_txt_query_destroy(PurpleSrvTxtQueryData *query_data)
- PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
- if (ops && ops->destroy)
- ops->destroy(query_data);
- if (query_data->handle > 0)
- purple_input_remove(query_data->handle);
- if (query_data->resolver != NULL)
- * It's not really possible to kill a thread. So instead we
- * just set the callback to NULL and let the DNS lookup
- query_data->cb.srv = NULL;
- g_free(query_data->error_message);
- if (query_data->fd_out != -1)
- close(query_data->fd_out);
- if (query_data->fd_in != -1)
- close(query_data->fd_in);
- g_free(query_data->query);
-dns_str_is_ascii(const char *name)
- for (c = (guchar *)name; c && *c; ++c) {
-write_to_parent(int in, int out, gconstpointer data, gsize size)
- const guchar *buf = data;
- w = write(out, buf, size);
- } else if (w < 0 && errno == EINTR) {
- /* Let's try some more; */
- } while (size > 0 && w > 0);
- /* An error occurred */
-/* Read size bytes to data. Dies if an error occurs. */
-read_from_parent(int in, int out, gpointer data, gsize size)
- r = read(in, data, size);
- } else if (r < 0 && errno == EINTR) {
- /* Let's try some more; */
- } while (size > 0 && r > 0);
- /* An error occurred */
-G_GNUC_NORETURN static void
-resolve(int in, int out)
- PurpleSrvResponse *srvres;
- PurpleTxtResponse *txtres;
- int size, qdcount, ancount;
- guint16 type, dlen, pref, weight, port;
- PurpleSrvInternalQuery query;
- purple_restore_default_signal_handlers();
- read_from_parent(in, out, &query, sizeof(query));
- size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer));
- write_to_parent(in, out, &(query.type), sizeof(query.type));
- write_to_parent(in, out, &size, sizeof(size));
- qdcount = ntohs(answer.hdr.qdcount);
- ancount = ntohs(answer.hdr.ancount);
- cp = (guchar*)&answer + sizeof(HEADER);
- end = (guchar*)&answer + size;
- /* skip over unwanted stuff */
- while (qdcount-- > 0 && cp < end) {
- size = dn_expand( (unsigned char*)&answer, end, cp, name, 256);
- while (ancount-- > 0 && cp < end) {
- size = dn_expand((unsigned char*)&answer, end, cp, name, 256);
- /* skip ttl and class since we already know it */
- size = dn_expand( (unsigned char*)&answer, end, cp, name, 256);
- srvres = g_new0(PurpleSrvResponse, 1);
- if (strlen(name) > sizeof(srvres->hostname) - 1) {
- purple_debug_error("dnssrv", "hostname is "
- "longer than available buffer ('%s', %"
- G_GSIZE_FORMAT " bytes)!",
- g_strlcpy(srvres->hostname, name, sizeof(srvres->hostname));
- srvres->weight = weight;
- ret = g_list_prepend(ret, srvres);
- } else if (type == T_TXT) {
- txtres = g_new0(PurpleTxtResponse, 1);
- txtres->content = g_strndup((gchar*)(++cp), dlen-1);
- ret = g_list_append(ret, txtres);
- size = g_list_length(ret);
- if (query.type == T_SRV)
- ret = purple_srv_sort(ret);
- write_to_parent(in, out, &(query.type), sizeof(query.type));
- write_to_parent(in, out, &size, sizeof(size));
- if (query.type == T_SRV)
- write_to_parent(in, out, ret->data, sizeof(PurpleSrvResponse));
- if (query.type == T_TXT) {
- PurpleTxtResponse *response = ret->data;
- gsize l = strlen(response->content) + 1 /* null byte */;
- write_to_parent(in, out, &l, sizeof(l));
- write_to_parent(in, out, response->content, l);
- ret = g_list_remove(ret, ret->data);
-resolved(gpointer data, gint source, PurpleInputCondition cond)
- PurpleSrvTxtQueryData *query_data = (PurpleSrvTxtQueryData*)data;
- if (read(source, &type, sizeof(type)) == sizeof(type)) {
- if (read(source, &size, sizeof(size)) == sizeof(size)) {
- if (size < -1 || size > MAX_ADDR_RESPONSE_LEN) {
- purple_debug_warning("dnssrv", "res_query returned invalid number\n");
- if (size == -1 || size == 0) {
- purple_debug_warning("dnssrv", "res_query returned an error\n");
- /* Re-read resolv.conf and friends in case DNS servers have changed */
- purple_debug_info("dnssrv", "Found 0 entries, errno is %i\n", errno);
- PurpleSrvCallback cb = query_data->cb.srv;
- cb(NULL, 0, query_data->extradata);
- } else if (type == T_TXT) {
- PurpleTxtCallback cb = query_data->cb.txt;
- cb(NULL, query_data->extradata);
- purple_debug_error("dnssrv", "type unknown of DNS result entry; errno is %i\n", errno);
- PurpleSrvResponse *res;
- PurpleSrvResponse *tmp;
- PurpleSrvCallback cb = query_data->cb.srv;
- purple_debug_info("dnssrv","found %d SRV entries\n", size);
- tmp = res = g_new0(PurpleSrvResponse, size);
- for (i = 0; i < size; i++) {
- red = read(source, tmp++, sizeof(PurpleSrvResponse));
- if (red != sizeof(PurpleSrvResponse)) {
- purple_debug_error("dnssrv","unable to read srv "
- "response: %s\n", g_strerror(errno));
- cb(res, size, query_data->extradata);
- } else if (type == T_TXT) {
- GList *responses = NULL;
- PurpleTxtResponse *res;
- PurpleTxtCallback cb = query_data->cb.txt;
- purple_debug_info("dnssrv","found %d TXT entries\n", size);
- for (i = 0; i < size; i++) {
- red = read(source, &len, sizeof(len));
- if (red != sizeof(len)) {
- purple_debug_error("dnssrv","unable to read txt "
- "response length: %s\n", g_strerror(errno));
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
- if (len > MAX_ADDR_RESPONSE_LEN) {
- purple_debug_error("dnssrv", "we've read invalid number\n");
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
- res = g_new0(PurpleTxtResponse, 1);
- res->content = g_new0(gchar, len);
- red = read(source, res->content, len);
- if (red < 0 || (gsize)red != len) {
- purple_debug_error("dnssrv","unable to read txt "
- "response: %s\n", g_strerror(errno));
- purple_txt_response_destroy(res);
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
- responses = g_list_prepend(responses, res);
- responses = g_list_reverse(responses);
- cb(responses, query_data->extradata);
- purple_debug_error("dnssrv", "type unknown of DNS result entry; errno is %i\n", errno);
- waitpid(query_data->pid, &status, 0);
- purple_srv_txt_query_destroy(query_data);
-/* The Jabber Server code was inspiration for parts of this. */
-res_main_thread_cb(gpointer data)
- PurpleSrvResponse *srvres = NULL;
- PurpleSrvTxtQueryData *query_data = data;
- if(query_data->error_message != NULL) {
- purple_debug_error("dnssrv", "%s", query_data->error_message);
- if (query_data->type == DNS_TYPE_SRV) {
- if (query_data->cb.srv)
- query_data->cb.srv(srvres, 0, query_data->extradata);
- } else if (query_data->type == DNS_TYPE_TXT) {
- if (query_data->cb.txt)
- query_data->cb.txt(NULL, query_data->extradata);
- if (query_data->type == DNS_TYPE_SRV) {
- PurpleSrvResponse *srvres_tmp = NULL;
- GList *lst = query_data->results;
- int size = g_list_length(lst);
- if(query_data->cb.srv && size > 0)
- srvres_tmp = srvres = g_new0(PurpleSrvResponse, size);
- PurpleSrvResponse *lstdata = lst->data;
- lst = g_list_delete_link(lst, lst);
- memcpy(srvres_tmp++, lstdata, sizeof(PurpleSrvResponse));
- query_data->results = NULL;
- purple_debug_info("dnssrv", "found %d SRV entries\n", size);
- if(query_data->cb.srv) query_data->cb.srv(srvres, size, query_data->extradata);
- } else if (query_data->type == DNS_TYPE_TXT) {
- GList *lst = query_data->results;
- purple_debug_info("dnssrv", "found %d TXT entries\n", g_list_length(lst));
- if (query_data->cb.txt) {
- query_data->results = NULL;
- query_data->cb.txt(lst, query_data->extradata);
- purple_debug_error("dnssrv", "unknown query type");
- query_data->resolver = NULL;
- query_data->handle = 0;
- purple_srv_txt_query_destroy(query_data);
-res_thread(gpointer data)
- PurpleSrvTxtQueryData *query_data = data;
- type = query_data->type;
- ds = DnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL);
- if (ds != ERROR_SUCCESS) {
- gchar *msg = g_win32_error_message(ds);
- if (type == DNS_TYPE_SRV) {
- query_data->error_message = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds);
- } else if (type == DNS_TYPE_TXT) {
- query_data->error_message = g_strdup_printf("Couldn't look up TXT record. %s (%lu).\n", msg, ds);
- if (type == DNS_TYPE_SRV) {
- DNS_SRV_DATA *srv_data;
- PurpleSrvResponse *srvres;
- for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) {
- /* Discard any incorrect entries. I'm not sure if this is necessary */
- if (dr_tmp->wType != type || strcmp(dr_tmp->pName, query_data->query) != 0) {
- srv_data = &dr_tmp->Data.SRV;
- srvres = g_new0(PurpleSrvResponse, 1);
- strncpy(srvres->hostname, srv_data->pNameTarget, 255);
- srvres->hostname[255] = '\0';
- srvres->pref = srv_data->wPriority;
- srvres->port = srv_data->wPort;
- srvres->weight = srv_data->wWeight;
- lst = g_list_prepend(lst, srvres);
- DnsRecordListFree(dr, DnsFreeRecordList);
- query_data->results = purple_srv_sort(lst);
- } else if (type == DNS_TYPE_TXT) {
- DNS_TXT_DATA *txt_data;
- PurpleTxtResponse *txtres;
- for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) {
- /* Discard any incorrect entries. I'm not sure if this is necessary */
- if (dr_tmp->wType != type || strcmp(dr_tmp->pName, query_data->query) != 0) {
- txt_data = &dr_tmp->Data.TXT;
- txtres = g_new0(PurpleTxtResponse, 1);
- for (i = 0; i < (int)txt_data->dwStringCount; ++i)
- s = g_string_append(s, txt_data->pStringArray[i]);
- txtres->content = g_string_free(s, FALSE);
- lst = g_list_append(lst, txtres);
- DnsRecordListFree(dr, DnsFreeRecordList);
- query_data->results = lst;
- /* back to main thread */
- /* Note: this should *not* be attached to query_data->handle - it will cause leakage */
- purple_timeout_add(0, res_main_thread_cb, query_data);
-purple_srv_resolve(PurpleAccount *account, const char *protocol,
- const char *transport, const char *domain, PurpleSrvCallback cb,
- PurpleSrvTxtQueryData *query_data;
- PurpleProxyType proxy_type;
- PurpleSrvInternalQuery internal_query;
- if (!protocol || !*protocol || !transport || !*transport || !domain || !*domain) {
- purple_debug_error("dnssrv", "Wrong arguments\n");
- cb(NULL, 0, extradata);
- g_return_val_if_reached(NULL);
- proxy_type = purple_proxy_info_get_proxy_type(
- purple_proxy_get_setup(account));
- if (proxy_type == PURPLE_PROXY_TOR) {
- purple_debug_info("dnssrv", "Aborting SRV lookup in Tor Proxy mode.\n");
- cb(NULL, 0, extradata);
- if (!dns_str_is_ascii(domain)) {
- int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
- purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
- cb(NULL, 0, extradata);
- } else /* Fallthru is intentional */
- hostname = g_strdup(domain);
- query = g_strdup_printf("_%s._%s.%s", protocol, transport, hostname);
- purple_debug_info("dnssrv","querying SRV record for %s: %s\n", domain,
- query_data = query_data_new(PurpleDnsTypeSrv, query, extradata);
- query_data->cb.srv = cb;
- if (purple_srv_txt_query_ui_resolve(query_data))
- if(pipe(in) || pipe(out)) {
- purple_debug_error("dnssrv", "Could not create pipe\n");
- cb(NULL, 0, extradata);
- * TODO: We should put a cap on the number of forked processes that we
- * allow at any given time. If we get too many requests they
- * should be put into a queue and handled later. (This is what
- * we do for A record lookups.)
- purple_debug_error("dnssrv", "Could not create process!\n");
- cb(NULL, 0, extradata);
- resolve(in[0], out[1]);
- /* resolve() does not return */
- internal_query.type = T_SRV;
- strncpy(internal_query.query, query, 255);
- internal_query.query[255] = '\0';
- if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
- purple_debug_error("dnssrv", "Could not write to SRV resolver\n");
- query_data->fd_out = out[0];
- query_data->fd_in = in[1];
- query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
- query_data->resolver = g_thread_try_new("dnssrv srv resolver", res_thread, query_data, &err);
- if (query_data->resolver == NULL) {
- query_data->error_message = g_strdup_printf("SRV thread create failure: %s\n", (err && err->message) ? err->message : "");
- g_thread_unref(query_data->resolver);
- /* The query isn't going to happen, so finish the SRV lookup now.
- * Asynchronously call the callback since stuff may not expect
- * the callback to be called before this returns */
- if (query_data->error_message != NULL)
- query_data->handle = purple_timeout_add(0, res_main_thread_cb, query_data);
-PurpleSrvTxtQueryData *purple_txt_resolve(PurpleAccount *account,
- const char *owner, const char *domain, PurpleTxtCallback cb,
- PurpleSrvTxtQueryData *query_data;
- PurpleProxyType proxy_type;
- PurpleSrvInternalQuery internal_query;
- proxy_type = purple_proxy_info_get_proxy_type(
- purple_proxy_get_setup(account));
- if (proxy_type == PURPLE_PROXY_TOR) {
- purple_debug_info("dnssrv", "Aborting TXT lookup in Tor Proxy mode.\n");
- if (!dns_str_is_ascii(domain)) {
- int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
- purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
- } else /* fallthru is intentional */
- hostname = g_strdup(domain);
- query = g_strdup_printf("%s.%s", owner, hostname);
- purple_debug_info("dnssrv","querying TXT record for %s: %s\n", domain,
- query_data = query_data_new(PurpleDnsTypeTxt, query, extradata);
- query_data->cb.txt = cb;
- if (purple_srv_txt_query_ui_resolve(query_data)) {
- /* query intentionally not freed
- if(pipe(in) || pipe(out)) {
- purple_debug_error("dnssrv", "Could not create pipe\n");
- * TODO: We should put a cap on the number of forked processes that we
- * allow at any given time. If we get too many requests they
- * should be put into a queue and handled later. (This is what
- * we do for A record lookups.)
- purple_debug_error("dnssrv", "Could not create process!\n");
- resolve(in[0], out[1]);
- /* resolve() does not return */
- internal_query.type = T_TXT;
- strncpy(internal_query.query, query, 255);
- internal_query.query[255] = '\0';
- if (write(in[1], &internal_query, sizeof(internal_query)) < 0)
- purple_debug_error("dnssrv", "Could not write to TXT resolver\n");
- query_data->fd_out = out[0];
- query_data->fd_in = in[1];
- query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data);
- query_data->resolver = g_thread_try_new("dnssrv srv resolver", res_thread, query_data, &err);
- if (query_data->resolver == NULL) {
- query_data->error_message = g_strdup_printf("TXT thread create failure: %s\n", (err && err->message) ? err->message : "");
- g_thread_unref(query_data->resolver);
- /* The query isn't going to happen, so finish the TXT lookup now.
- * Asynchronously call the callback since stuff may not expect
- * the callback to be called before this returns */
- if (query_data->error_message != NULL)
- query_data->handle = purple_timeout_add(0, res_main_thread_cb, query_data);
-purple_txt_response_get_content(PurpleTxtResponse *resp)
- g_return_val_if_fail(resp != NULL, NULL);
-void purple_txt_response_destroy(PurpleTxtResponse *resp)
- g_return_if_fail(resp != NULL);
- * Only used as the callback for the ui ops.
-purple_srv_query_resolved(PurpleSrvTxtQueryData *query_data, GList *records)
- PurpleSrvResponse *records_array;
- g_return_if_fail(records != NULL);
- if (query_data->cb.srv == NULL) {
- purple_srv_txt_query_destroy(query_data);
- records = g_list_delete_link(records, records);
- records = purple_srv_sort(records);
- length = g_list_length(records);
- purple_debug_info("dnssrv", "SRV records resolved for %s, count: %d\n",
- query_data->query, length);
- records_array = g_new(PurpleSrvResponse, length);
- for (l = records; l; l = l->next, i++) {
- records_array[i] = *(PurpleSrvResponse *)l->data;
- query_data->cb.srv(records_array, length, query_data->extradata);
- purple_srv_txt_query_destroy(query_data);
- records = g_list_delete_link(records, records);
- * Only used as the callback for the ui ops.
-purple_txt_query_resolved(PurpleSrvTxtQueryData *query_data, GList *entries)
- g_return_if_fail(entries != NULL);
- purple_debug_info("dnssrv", "TXT entries resolved for %s, count: %d\n", query_data->query, g_list_length(entries));
- /* the callback should g_free the entries.
- if (query_data->cb.txt != NULL)
- query_data->cb.txt(entries, query_data->extradata);
- entries = g_list_delete_link(entries, entries);
- purple_srv_txt_query_destroy(query_data);
-purple_srv_query_failed(PurpleSrvTxtQueryData *query_data, const gchar *error_message)
- purple_debug_error("dnssrv", "%s\n", error_message);
- if (query_data->cb.srv != NULL)
- query_data->cb.srv(NULL, 0, query_data->extradata);
- purple_srv_txt_query_destroy(query_data);
-purple_srv_txt_query_ui_resolve(PurpleSrvTxtQueryData *query_data)
- PurpleSrvTxtQueryUiOps *ops = purple_srv_txt_query_get_ui_ops();
- if (ops && ops->resolve)
- return ops->resolve(query_data, (query_data->type == T_SRV ? purple_srv_query_resolved : purple_txt_query_resolved), purple_srv_query_failed);
-purple_srv_txt_query_set_ui_ops(PurpleSrvTxtQueryUiOps *ops)
- srv_txt_query_ui_ops = ops;
-PurpleSrvTxtQueryUiOps *
-purple_srv_txt_query_get_ui_ops(void)
- /* It is perfectly acceptable for srv_txt_query_ui_ops to be NULL; this just
- * means that the default platform-specific implementation will be used.
- return srv_txt_query_ui_ops;
-purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data)
- g_return_val_if_fail(query_data != NULL, NULL);
- return query_data->query;
-purple_srv_txt_query_get_query_type(PurpleSrvTxtQueryData *query_data)
- g_return_val_if_fail(query_data != NULL, 0);
- return query_data->type;
-/**************************************************************************
- **************************************************************************/
-static PurpleSrvTxtQueryUiOps *
-purple_srv_txt_query_ui_ops_copy(PurpleSrvTxtQueryUiOps *ops)
- PurpleSrvTxtQueryUiOps *ops_new;
- g_return_val_if_fail(ops != NULL, NULL);
- ops_new = g_new(PurpleSrvTxtQueryUiOps, 1);
-purple_srv_txt_query_ui_ops_get_type(void)
- type = g_boxed_type_register_static("PurpleSrvTxtQueryUiOps",
- (GBoxedCopyFunc)purple_srv_txt_query_ui_ops_copy,
- (GBoxedFreeFunc)g_free);
--- a/libpurple/dnssrv.h Wed Dec 23 22:13:29 2015 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
- * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de>
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#ifndef _PURPLE_DNSSRV_H
-#define _PURPLE_DNSSRV_H
- * @section_id: libpurple-dnssrv
- * @short_description: <filename>dnssrv.h</filename>
- * @title: DNS SRV Utilities
-#define PURPLE_TYPE_SRV_TXT_QUERY_UI_OPS (purple_srv_txt_query_ui_ops_get_type())
-typedef struct _PurpleSrvTxtQueryData PurpleSrvTxtQueryData;
-typedef struct _PurpleSrvResponse PurpleSrvResponse;
-typedef struct _PurpleTxtResponse PurpleTxtResponse;
-typedef struct _PurpleSrvTxtQueryUiOps PurpleSrvTxtQueryUiOps;
-#include <glib-object.h>
-struct _PurpleSrvResponse {
-struct _PurpleTxtResponse {
-typedef void (*PurpleSrvTxtQueryResolvedCallback) (PurpleSrvTxtQueryData *query_data, GList *records);
-typedef void (*PurpleSrvTxtQueryFailedCallback) (PurpleSrvTxtQueryData *query_data, const gchar *error_message);
- * PurpleSrvTxtQueryUiOps:
- * @resolve: implemented, return %TRUE if the UI takes responsibility for SRV
- * queries. When returning %FALSE, the standard implementation is
- * used. These callbacks <emphasis>MUST</emphasis> be called
- * @destroy: Called just before @query_data is freed; this should cancel any
- * further use of @query_data the UI would make. Unneeded if @resolve
- * SRV Request UI operations; UIs should implement this if they want to do SRV
- * lookups themselves, rather than relying on the core.
- * See <link linkend="chapter-ui-ops">List of <literal>UiOps</literal> Structures</link>
-struct _PurpleSrvTxtQueryUiOps
- gboolean (*resolve)(PurpleSrvTxtQueryData *query_data,
- PurpleSrvTxtQueryResolvedCallback resolved_cb,
- PurpleSrvTxtQueryFailedCallback failed_cb);
- void (*destroy)(PurpleSrvTxtQueryData *query_data);
- void (*_purple_reserved1)(void);
- void (*_purple_reserved2)(void);
- void (*_purple_reserved3)(void);
- void (*_purple_reserved4)(void);
- * @resp: An array of PurpleSrvResponse of size results. The array
- * is sorted based on the order described in the DNS SRV RFC.
- * Users of this API should try each record in resp in order,
- * starting at the beginning.
-typedef void (*PurpleSrvCallback)(PurpleSrvResponse *resp, int results, gpointer data);
- * @responses: A GList of PurpleTxtResponse objects.
- * @data: The extra data passed to purple_txt_resolve.
- * Callback that returns the data retrieved from a DNS TXT lookup.
-typedef void (*PurpleTxtCallback)(GList *responses, gpointer data);
- * purple_srv_txt_query_ui_ops_get_type:
- * Returns: The #GType for the #PurpleSrvTxtQueryUiOps boxed structure.
-GType purple_srv_txt_query_ui_ops_get_type(void);
- * @account: The account that the query is being done for (or %NULL)
- * @protocol: Name of the protocol (e.g. "sip")
- * @transport: Name of the transport ("tcp" or "udp")
- * @domain: Domain name to query (e.g. "blubb.com")
- * @cb: (scope call): A callback which will be called with the results
- * @extradata: Extra data to be passed to the callback
- * Queries an SRV record.
- * Returns: %NULL if there was an error, otherwise return a reference to
- * a data structure that can be used to cancel the pending
- * DNS query, if needed.
-PurpleSrvTxtQueryData *purple_srv_resolve(PurpleAccount *account, const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata);
- * @account: The account that the query is being done for (or %NULL)
- * @owner: Name of the protocol (e.g. "_xmppconnect")
- * @domain: Domain name to query (e.g. "blubb.com")
- * @cb: (scope call): A callback which will be called with the results
- * @extradata: Extra data to be passed to the callback
- * Queries an TXT record.
- * Returns: %NULL if there was an error, otherwise return a reference to
- * a data structure that can be used to cancel the pending
- * DNS query, if needed.
-PurpleSrvTxtQueryData *purple_txt_resolve(PurpleAccount *account, const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata);
- * purple_txt_response_get_content:
- * @response: The TXT response record
- * Get the value of the current TXT record.
- * Returns: The value of the current TXT record.
-const gchar *purple_txt_response_get_content(PurpleTxtResponse *response);
- * purple_txt_response_destroy:
- * @response: The PurpleTxtResponse to destroy.
- * Destroy a TXT DNS response object.
-void purple_txt_response_destroy(PurpleTxtResponse *response);
- * purple_srv_txt_query_destroy:
- * @query_data: The SRV/TXT query to cancel. This data structure
- * is freed by this function.
- * Cancel a SRV/TXT query and destroy the associated data structure.
-void purple_srv_txt_query_destroy(PurpleSrvTxtQueryData *query_data);
- * purple_srv_txt_query_set_ui_ops:
- * @ops: The UI operations structure.
- * Sets the UI operations structure to be used when doing a SRV/TXT
- * resolve. The UI operations need only be set if the UI wants to
- * handle the resolve itself; otherwise, leave it as NULL.
-void purple_srv_txt_query_set_ui_ops(PurpleSrvTxtQueryUiOps *ops);
- * purple_srv_txt_query_get_ui_ops:
- * Returns the UI operations structure to be used when doing a SRV/TXT
- * Returns: The UI operations structure.
-PurpleSrvTxtQueryUiOps *purple_srv_txt_query_get_ui_ops(void);
- * purple_srv_txt_query_get_query:
- * @query_data: The SRV/TXT query
- * Get the query from a PurpleSrvTxtQueryData
-char *purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data);
- * purple_srv_txt_query_get_query_type:
- * @query_data: The query
- * Get the type from a PurpleSrvTxtQueryData (TXT or SRV)
- * Returns: The query type.
-int purple_srv_txt_query_get_query_type(PurpleSrvTxtQueryData *query_data);
-#endif /* _PURPLE_DNSSRV_H */
--- a/libpurple/glibcompat.h Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/glibcompat.h Wed Dec 23 22:32:36 2015 -0600
@@ -61,65 +61,6 @@
-#if !GLIB_CHECK_VERSION(2, 32, 0)
-#include <glib-object.h>
-#define G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-#define G_GNUC_END_IGNORE_DEPRECATIONS
-#define G_SOURCE_REMOVE FALSE
-#define G_SOURCE_CONTINUE TRUE
-#define g_signal_handlers_disconnect_by_data(instance, data) \
- g_signal_handlers_disconnect_matched((instance), G_SIGNAL_MATCH_DATA, \
- 0, 0, NULL, NULL, (data))
-static inline GByteArray * g_byte_array_new_take(guint8 *data, gsize len)
- array = g_byte_array_new();
- g_byte_array_append(array, data, len);
-static inline void g_queue_free_full(GQueue *queue, GDestroyNotify free_func)
- g_queue_foreach(queue, (GFunc)free_func, NULL);
-static inline GThread * g_thread_try_new(const gchar *name, GThreadFunc func,
- gpointer data, GError **error)
- return g_thread_create(func, data, TRUE, error);
-#if !GLIB_CHECK_VERSION(2, 30, 0)
-#define G_VALUE_INIT {0, {{0}}}
-static inline gchar *g_utf8_substring(const gchar *str, glong start_pos,
- gchar *start = g_utf8_offset_to_pointer(str, start_pos);
- gchar *end = g_utf8_offset_to_pointer(start, end_pos - start_pos);
- gchar *out = g_malloc(end - start + 1);
- memcpy(out, start, end - start);
--- a/libpurple/network.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/network.c Wed Dec 23 22:32:36 2015 -0600
@@ -21,6 +21,8 @@
#include <arpa/nameser.h>
@@ -46,7 +48,6 @@
@@ -977,40 +978,26 @@
-purple_network_ip_lookup_cb(GSList *hosts, gpointer data,
- const char *error_message)
- const gchar **ip = (const gchar **) data;
+purple_network_ip_lookup_cb(GObject *sender, GAsyncResult *result, gpointer data) { + GList *addresses = NULL; + GInetAddress *address = NULL; + const gchar **ip_address = (const gchar **)data;
- purple_debug_error("network", "lookup of IP address failed: %s\n",
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error); + purple_debug_info("network", "lookup of IP address failed: %s\n", error->message); - if (hosts && g_slist_next(hosts)) {
- common_sockaddr_t *addr = g_slist_next(hosts)->data;
- char dst[INET6_ADDRSTRLEN];
+ address = G_INET_ADDRESS(addresses->data); - if (addr->sa.sa_family == AF_INET6) {
- inet_ntop(addr->sa.sa_family, &addr->in6.sin6_addr,
- inet_ntop(addr->sa.sa_family, &addr->in.sin_addr,
+ *ip_address = g_inet_address_to_string(address);
- purple_debug_info("network", "set IP address: %s\n", *ip);
- while (hosts != NULL) {
- hosts = g_slist_delete_link(hosts, hosts);
- hosts = g_slist_delete_link(hosts, hosts);
+ g_resolver_free_addresses(addresses); @@ -1018,9 +1005,11 @@
if (stun_server && stun_server[0] != '\0') {
if (purple_network_is_available()) {
- purple_debug_info("network", "running DNS query for STUN server\n");
- purple_dnsquery_a(NULL, stun_server, 3478, purple_network_ip_lookup_cb,
+ g_resolver_lookup_by_name_async(g_resolver_get_default(), + purple_network_ip_lookup_cb, purple_debug_info("network",
"network is unavailable, don't try to update STUN IP");
@@ -1036,10 +1025,11 @@
if (turn_server && turn_server[0] != '\0') {
if (purple_network_is_available()) {
- purple_debug_info("network", "running DNS query for TURN server\n");
- purple_dnsquery_a(NULL, turn_server,
- purple_prefs_get_int("/purple/network/turn_port"),
- purple_network_ip_lookup_cb, &turn_ip);
+ g_resolver_lookup_by_name_async(g_resolver_get_default(), + purple_network_ip_lookup_cb, purple_debug_info("network",
"network is unavailable, don't try to update TURN IP");
--- a/libpurple/protocols/gg/resolver-purple.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/gg/resolver-purple.c Wed Dec 23 22:32:36 2015 -0600
@@ -29,22 +29,22 @@
#include "resolver-purple.h"
static int ggp_resolver_purple_start(int *fd, void **private_data,
static void ggp_resolver_purple_cleanup(void **private_data, int force);
-static void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata,
- const char *error_message);
+static void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer data); - PurpleDnsQueryData *purpleQuery;
+ GCancellable *cancellable; @@ -64,67 +64,72 @@
-void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata,
- const char *error_message)
+void ggp_resolver_purple_cb(GObject *sender, GAsyncResult *res, gpointer cbdata) { + GList *addresses = NULL, *in_addrs = NULL, *l = NULL; + gsize native_size = 0; /* this is kind of dirty, but it'll be initialized before we use it */ ggp_resolver_purple_data *data = (ggp_resolver_purple_data*)cbdata;
const int fd = data->pipes[1];
- int ipv4_count, all_count, write_size;
- struct in_addr *addresses;
- purple_debug_misc("gg", "ggp_resolver_purple_cb(%p, %p, \"%s\")\n",
- hosts, cbdata, error_message);
- data->purpleQuery = NULL;
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error); + if(addresses == NULL) { + purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n",
- purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n",
+ purple_debug_misc("gg", "ggp_resolver_purple_cb succeeded: (%p, %p)\n", - all_count = g_slist_length(hosts);
- g_assert(all_count % 2 == 0);
- addresses = malloc((all_count + 1) * sizeof(struct in_addr));
+ g_object_unref(G_OBJECT(data->cancellable)); + data->cancellable = NULL;
- while (hosts && (hosts = g_slist_delete_link(hosts, hosts))) {
- common_sockaddr_t addr;
- char dst[INET6_ADDRSTRLEN];
+ for(l = addresses; l; l = l->next) { + GInetAddress *inet_address = G_INET_ADDRESS(l->data); + GSocketFamily family = G_SOCKET_FAMILY_INVALID; + gchar *ip_address = g_inet_address_to_string(inet_address); - memcpy(&addr, hosts->data, sizeof(addr));
+ family = g_inet_address_get_family(inet_address); + case G_SOCKET_FAMILY_IPV4: + purple_debug_misc("gg", "ggp_resolver_purple_cb " + "ipv4: %s\n", ip_address); - if (addr.sa.sa_family == AF_INET6) {
- inet_ntop(addr.sa.sa_family, &addr.in6.sin6_addr,
- purple_debug_misc("gg", "ggp_resolver_purple_cb "
- "ipv6 (ignore): %s\n", dst);
- } else if (addr.sa.sa_family == AF_INET) {
- inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
- purple_debug_misc("gg", "ggp_resolver_purple_cb "
+ native_size = g_inet_address_get_native_size(inet_address); + in_addrs = g_list_append(in_addrs, g_memdup(g_inet_address_to_bytes(inet_address), native_size)); + case G_SOCKET_FAMILY_IPV6: + purple_debug_misc("gg", "ggp_resolver_purple_cb " + "ipv6 (ignore): %s\n", ip_address); - g_assert(ipv4_count < all_count);
- addresses[ipv4_count++] = addr.in.sin_addr;
- purple_debug_warning("gg", "ggp_resolver_purple_cb "
- "unexpected sa_family: %d\n",
+ purple_debug_warning("gg", "ggp_resolver_purple_cb " + "unexpected sa_family: %d\n",
- hosts = g_slist_delete_link(hosts, hosts);
- addresses[ipv4_count].s_addr = INADDR_NONE;
+ for(l = in_addrs; l; l = l->next) { + gint write_size = native_size; + if(write(fd, l->data, write_size) != write_size) { + purple_debug_error("gg", + "ggp_resolver_purple_cb write error on %p\n", l->data); - write_size = (ipv4_count + 1) * sizeof(struct in_addr);
- if (write(fd, addresses, write_size) != write_size) {
- purple_debug_error("gg",
- "ggp_resolver_purple_cb write error\n");
+ g_resolver_free_addresses(addresses); int ggp_resolver_purple_start(int *fd, void **private_data,
@@ -136,7 +141,7 @@
data = malloc(sizeof(ggp_resolver_purple_data));
*private_data = (void*)data;
- data->purpleQuery = NULL;
+ data->cancellable = NULL; @@ -150,10 +155,15 @@
/* account and port is unknown in this context */
- data->purpleQuery = purple_dnsquery_a(NULL, hostname, 80,
- ggp_resolver_purple_cb, (gpointer)data);
+ data->cancellable = g_cancellable_new(); - if (!data->purpleQuery) {
+ g_resolver_lookup_by_name_async(g_resolver_get_default(), + ggp_resolver_purple_cb, + if (!data->cancellable) { purple_debug_error("gg", "ggp_resolver_purple_start: "
"unable to call purple_dnsquery_a\n");
ggp_resolver_purple_cleanup(private_data, 0);
@@ -175,8 +185,12 @@
- purple_dnsquery_destroy(data->purpleQuery);
+ if (G_IS_CANCELLABLE(data->cancellable)) { + g_cancellable_cancel(data->cancellable); + g_object_unref(G_OBJECT(data->cancellable)); --- a/libpurple/protocols/jabber/disco.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/jabber/disco.c Wed Dec 23 22:32:36 2015 -0600
@@ -419,76 +419,39 @@
-/* should probably share this code with google.c, or maybe from 2.7.0
- introduce an abstracted hostname -> IP function in dns.c */
-jabber_disco_stun_lookup_cb(GSList *hosts, gpointer data,
- const char *error_message)
+jabber_disco_stun_srv_resolve_cb(GObject *sender, GAsyncResult *result, gpointer data) { + GList *services = NULL; JabberStream *js = (JabberStream *) data;
- purple_debug_error("jabber", "STUN lookup failed: %s\n",
+ services = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error); + purple_debug_info("jabber", "Failed to look up a STUN record : %s\n", error->message); - if (hosts && g_slist_next(hosts)) {
- common_sockaddr_t addr;
- char dst[INET6_ADDRSTRLEN];
+ results = g_list_length(services); - memcpy(&addr, g_slist_next(hosts)->data, sizeof(addr));
+ purple_debug_info("jabber", "got %d SRV responses for STUN.\n", results); - if (addr.sa.sa_family == AF_INET6) {
- inet_ntop(addr.sa.sa_family, &addr.in6.sin6_addr,
- port = ntohs(addr.in6.sin6_port);
- inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
- port = ntohs(addr.in.sin_port);
+ GSrvTarget *target = (GSrvTarget *)services->data; + const gchar *hostname = g_srv_target_get_hostname(target);
- js->stun_ip = g_strdup(dst);
+ js->stun_ip = g_strdup(hostname); + js->stun_port = g_srv_target_get_port(target); - purple_debug_info("jabber", "set STUN IP/port address: "
- /* unmark ongoing query */
+ purple_debug_info("jabber", "set stun address to %s:%d\n", + hostname, js->stun_port); - while (hosts != NULL) {
- hosts = g_slist_delete_link(hosts, hosts);
- hosts = g_slist_delete_link(hosts, hosts);
-jabber_disco_stun_srv_resolve_cb(PurpleSrvResponse *resp, int results, gpointer data)
- JabberStream *js = (JabberStream *) data;
- purple_debug_info("jabber", "got %d SRV responses for STUN.\n", results);
- js->srv_query_data = NULL;
- PurpleAccount *account;
- purple_debug_info("jabber", "looking up IP for %s:%d\n",
- resp[0].hostname, resp[0].port);
- account = purple_connection_get_account(js->gc);
- purple_dnsquery_a(account, resp[0].hostname, resp[0].port,
- jabber_disco_stun_lookup_cb, js);
+ g_resolver_free_targets(services); @@ -552,11 +515,14 @@
} else if (purple_network_get_stun_ip() == NULL ||
purple_strequal(purple_network_get_stun_ip(), "")) {
- purple_connection_get_account(js->gc), "stun", "udp",
- jabber_disco_stun_srv_resolve_cb, js);
+ g_resolver_lookup_service_async(g_resolver_get_default(), + jabber_disco_stun_srv_resolve_cb, /* TODO: add TURN support later... */
--- a/libpurple/protocols/jabber/google/jingleinfo.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/jabber/google/jingleinfo.c Wed Dec 23 22:32:36 2015 -0600
@@ -22,54 +22,36 @@
-jabber_google_stun_lookup_cb(GSList *hosts, gpointer data,
- const char *error_message)
+jabber_google_stun_lookup_cb(GObject *sender, GAsyncResult *result, gpointer data) { + GList *addresses = NULL; JabberStream *js = (JabberStream *) data;
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error); purple_debug_error("jabber", "Google STUN lookup failed: %s\n",
- if (hosts && g_slist_next(hosts)) {
- common_sockaddr_t addr;
- char dst[INET6_ADDRSTRLEN];
- memcpy(&addr, g_slist_next(hosts)->data, sizeof(addr));
- if (addr.sa.sa_family == AF_INET6) {
- inet_ntop(addr.sa.sa_family, &addr.in6.sin6_addr,
- port = ntohs(addr.in6.sin6_port);
- inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
- port = ntohs(addr.in.sin_port);
+ if(g_list_length(addresses) > 0) { + GInetAddress *inet_address = G_INET_ADDRESS(addresses->data); - js->stun_ip = g_strdup(dst);
+ js->stun_ip = g_inet_address_to_string(inet_address); purple_debug_info("jabber", "set Google STUN IP/port address: "
- /* unmark ongoing query */
+ "%s:%d\n", js->stun_ip, js->stun_port); - while (hosts != NULL) {
- hosts = g_slist_delete_link(hosts, hosts);
- hosts = g_slist_delete_link(hosts, hosts);
+ g_resolver_free_addresses(addresses); @@ -110,16 +92,13 @@
const gchar *udp = purple_xmlnode_get_attrib(server, "udp");
- PurpleAccount *account;
- /* if there, would already be an ongoing query,
- purple_dnsquery_destroy(js->stun_query);
+ js->stun_port = atoi(udp); - account = purple_connection_get_account(js->gc);
- js->stun_query = purple_dnsquery_a(account, host, port,
- jabber_google_stun_lookup_cb, js);
+ g_resolver_lookup_by_name_async(g_resolver_get_default(), + jabber_google_stun_lookup_cb, --- a/libpurple/protocols/jabber/jabber.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/jabber/jabber.c Wed Dec 23 22:32:36 2015 -0600
@@ -30,7 +30,6 @@
#include "conversation.h"
@@ -95,7 +94,6 @@
static gint plugin_ref = 0;
static void jabber_unregister_account_cb(JabberStream *js);
-static void try_srv_connect(JabberStream *js);
static void jabber_stream_init(JabberStream *js)
@@ -758,28 +756,54 @@
-txt_resolved_cb(GList *responses, gpointer data)
+txt_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data) + GList *records = NULL, *l = NULL; - js->srv_query_data = NULL;
- PurpleTxtResponse *resp = responses->data;
- token = g_strsplit(purple_txt_response_get_content(resp), "=", 2);
- if (!strcmp(token[0], "_xmpp-client-xbosh")) {
- purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]);
- js->bosh = jabber_bosh_connection_new(js, token[1]);
+ records = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error); + purple_debug_warning("jabber", "Unable to find alternative XMPP connection " + "methods after failing to connect directly. : %s\n", + purple_connection_error(js->gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Unable to connect")); + for(l = records; l; l = l->next) { + GVariantIter *iter = NULL; + g_variant_get((GVariant *)l->data, "(as)", &iter); + while(g_variant_iter_loop(iter, "s", &str)) { + gchar **token = g_strsplit(str, "=", 2); + if(!g_ascii_strcasecmp(token[0], "_xmpp-client-xbosh")) { + purple_debug_info("jabber","Found alternative connection method using %s at %s.\n", token[0], token[1]); + js->bosh = jabber_bosh_connection_new(js, token[1]);
- purple_txt_response_destroy(resp);
- responses = g_list_delete_link(responses, responses);
+ g_variant_iter_free(iter); + g_list_free_full(records, (GDestroyNotify)g_variant_unref); @@ -791,11 +815,6 @@
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
@@ -805,21 +824,21 @@
JabberStream *js = purple_connection_get_protocol_data(gc);
- if (js->srv_rec != NULL) {
- purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record or connecting directly.\n", error);
- purple_debug_info("jabber","Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain);
- js->srv_query_data = purple_txt_resolve(
- purple_connection_get_account(gc), "_xmppconnect",
- js->user->domain, txt_resolved_cb, js);
+ gchar *name = g_strdup_printf("_xmppconnect.%s", js->user->domain); + purple_debug_info("jabber", "Couldn't connect directly to %s. Trying to find alternative connection methods, like BOSH.\n", js->user->domain); + g_resolver_lookup_records_async(g_resolver_get_default(),
if(js->state == JABBER_STREAM_CONNECTING)
@@ -881,37 +900,43 @@
-static void try_srv_connect(JabberStream *js)
+srv_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data) - while (js->srv_rec != NULL && js->srv_rec_idx < js->max_srv_rec_idx) {
- PurpleSrvResponse *tmp_resp = js->srv_rec + (js->srv_rec_idx++);
- if (jabber_login_connect(js, tmp_resp->hostname, tmp_resp->hostname, tmp_resp->port, FALSE))
- /* Fall back to the defaults (I'm not sure if we should actually do this) */
- jabber_login_connect(js, js->user->domain, js->user->domain,
- purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
-static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data)
+ GList *targets = NULL, *l = NULL; - js->srv_query_data = NULL;
- js->max_srv_rec_idx = results;
+ targets = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error); + purple_debug_warning("jabber", + "SRV lookup failed, proceeding with normal connection : %s", jabber_login_connect(js, js->user->domain, js->user->domain,
purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
+ for(l = targets; l; l = l->next) { + GSrvTarget *target = (GSrvTarget *)l->data; + const gchar *hostname = g_srv_target_get_hostname(target); + guint port = g_srv_target_get_port(target); + if(jabber_login_connect(js, hostname, hostname, port, FALSE)) { + g_resolver_free_targets(targets); + g_resolver_free_targets(targets); + jabber_login_connect(js, js->user->domain, js->user->domain, + purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222), @@ -930,6 +955,9 @@
js->http_conns = purple_http_connection_set_new();
+ /* we might want to expose this at some point */ + js->cancellable = g_cancellable_new(); user = g_strdup(purple_account_get_username(account));
/* jabber_id_new doesn't accept "user@domain/" as valid */
slash = strchr(user, '/');
@@ -1000,7 +1028,6 @@
js->google_relay_token = NULL;
js->google_relay_host = NULL;
@@ -1062,8 +1089,13 @@
jabber_login_connect(js, js->user->domain, connect_server,
purple_account_get_int(account, "port", 5222), TRUE);
- js->srv_query_data = purple_srv_resolve(account, "xmpp-client",
- "tcp", js->user->domain, srv_resolved_cb, js);
+ g_resolver_lookup_service_async(g_resolver_get_default(), @@ -1595,9 +1627,6 @@
} else if ((js->gsc && js->gsc->fd > 0) || js->fd > 0)
jabber_send_raw(js, "</stream:stream>", -1);
- if (js->srv_query_data)
- purple_srv_txt_query_destroy(js->srv_query_data);
purple_ssl_close(js->gsc);
@@ -1693,17 +1722,10 @@
if (js->conn_close_timeout != 0)
purple_timeout_remove(js->conn_close_timeout);
+ g_cancellable_cancel(js->cancellable); + g_object_unref(G_OBJECT(js->cancellable));
- /* cancel DNS query for STUN, if one is ongoing */
- purple_dnsquery_destroy(js->stun_query);
/* remove Google relay-related stuff */
g_free(js->google_relay_token);
--- a/libpurple/protocols/jabber/jabber.h Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/jabber/jabber.h Wed Dec 23 22:32:36 2015 -0600
@@ -57,10 +57,10 @@
#include <libxml/parser.h>
#include "circularbuffer.h"
#include "mediamanager.h"
@@ -120,7 +120,7 @@
- PurpleSrvTxtQueryData *srv_query_data;
+ GCancellable *cancellable; @@ -277,10 +277,6 @@
guint conn_close_timeout;
- PurpleSrvResponse *srv_rec;
PurpleJabberBOSHConnection *bosh;
PurpleHttpConnectionSet *http_conns;
@@ -291,7 +287,6 @@
/* maybe this should only be present when USE_VV? */
- PurpleDnsQueryData *stun_query;
/* stuff for Google's relay handling */
gchar *google_relay_token;
--- a/libpurple/protocols/simple/simple.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/simple/simple.c Wed Dec 23 22:32:36 2015 -0600
@@ -29,7 +29,6 @@
#include "conversation.h"
@@ -41,7 +40,6 @@
static PurpleProtocol *my_protocol = NULL;
@@ -1801,29 +1799,41 @@
-static void simple_udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) {
+simple_udp_host_resolved(GObject *sender, GAsyncResult *result, gpointer data) { + GList *addresses = NULL; + GInetAddress *inet_address = NULL; + GSocketAddress *socket_address = NULL; struct simple_account_data *sip = (struct simple_account_data*) data;
- sip->query_data = NULL;
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error); + gchar *msg = g_strdup_printf(_("Unable to resolve hostname : %s"), - if (!hosts || !hosts->data) {
purple_connection_error(sip->gc,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unable to resolve hostname"));
- addr_size = GPOINTER_TO_INT(hosts->data);
- hosts = g_slist_remove(hosts, hosts->data);
- memcpy(&(sip->serveraddr), hosts->data, addr_size);
- hosts = g_slist_remove(hosts, hosts->data);
- hosts = g_slist_remove(hosts, hosts->data);
- hosts = g_slist_remove(hosts, hosts->data);
+ inet_address = G_INET_ADDRESS(addresses->data); + socket_address = g_inet_socket_address_new(inet_address, sip->realport); + g_object_unref(G_OBJECT(inet_address)); + g_socket_address_to_native(socket_address, + g_socket_address_get_native_size(socket_address), + g_object_unref(G_OBJECT(socket_address)); + g_resolver_free_addresses(addresses); /* create socket for incoming connections */
sip->listen_data = purple_network_listen_range(5060, 5160, AF_UNSPEC, SOCK_DGRAM, TRUE,
@@ -1865,33 +1875,44 @@
-static void srvresolved(PurpleSrvResponse *resp, int results, gpointer data) {
+srvresolved(GObject *sender, GAsyncResult *result, gpointer data) { struct simple_account_data *sip;
- sip->srv_query_data = NULL;
- port = purple_account_get_int(sip->account, "port", 0);
- /* find the host to connect to */
- hostname = g_strdup(resp->hostname);
+ targets = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error); + purple_debug_info("simple", + "srv lookup failed, continuing with configured settings : %s", if(!purple_account_get_bool(sip->account, "useproxy", FALSE)) {
hostname = g_strdup(sip->servername);
hostname = g_strdup(purple_account_get_string(sip->account, "proxy", sip->servername));
+ port = purple_account_get_int(sip->account, "port", 0); + GSrvTarget *target = (GSrvTarget *)targets->data; + hostname = g_strdup(g_srv_target_get_hostname(target)); + port = g_srv_target_get_port(target); + g_resolver_free_targets(targets); sip->realhostname = hostname;
- if(!sip->realport) sip->realport = 5060;
@@ -1907,13 +1928,11 @@
purple_debug_info("simple", "using udp with server %s and port %d\n", hostname, port);
- sip->query_data = purple_dnsquery_a(sip->account, hostname,
- port, simple_udp_host_resolved, sip);
- if (sip->query_data == NULL) {
- purple_connection_error(sip->gc,
- PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unable to resolve hostname"));
+ g_resolver_lookup_by_name_async(g_resolver_get_default(), + simple_udp_host_resolved, @@ -1975,8 +1994,13 @@
hosttoconnect = purple_account_get_string(account, "proxy", sip->servername);
- sip->srv_query_data = purple_srv_resolve(account, "sip",
- sip->udp ? "udp" : "tcp", hosttoconnect, srvresolved, sip);
+ g_resolver_lookup_service_async(g_resolver_get_default(), + sip->udp ? "udp" : "tcp", static void simple_close(PurpleConnection *gc)
@@ -2008,11 +2032,9 @@
purple_timeout_remove(sip->resendtimeout);
if (sip->registertimeout)
purple_timeout_remove(sip->registertimeout);
- if (sip->query_data != NULL)
- purple_dnsquery_destroy(sip->query_data);
- if (sip->srv_query_data != NULL)
- purple_srv_txt_query_destroy(sip->srv_query_data);
+ g_cancellable_cancel(sip->cancellable); + g_object_unref(G_OBJECT(sip->cancellable)); if (sip->listen_data != NULL)
purple_network_listen_cancel(sip->listen_data);
--- a/libpurple/protocols/simple/simple.h Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/simple/simple.h Wed Dec 23 22:32:36 2015 -0600
@@ -25,12 +25,11 @@
#include "circularbuffer.h"
@@ -100,8 +99,7 @@
- PurpleDnsQueryData *query_data;
- PurpleSrvTxtQueryData *srv_query_data;
+ GCancellable *cancellable; PurpleNetworkListenData *listen_data;
--- a/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/protocols/yahoo/yahoo_filexfer.c Wed Dec 23 22:32:36 2015 -0600
@@ -23,7 +23,6 @@
/* TODO: it needs further refactoring */
@@ -39,6 +38,8 @@
#include "yahoo_doodle.h"
#include "yahoo_friend.h"
@@ -498,14 +499,15 @@
-static void yahoo_xfer_dns_connected_15(GSList *hosts, gpointer data, const char *error_message)
+yahoo_xfer_dns_connected_15(GObject *sender, GAsyncResult *result, gpointer data) + GList *addresses = NULL; + GInetAddress *inet_address = NULL; struct yahoo_xfer_data *xd;
- struct sockaddr_in *addr;
struct yahoo_packet *pkt;
@@ -519,47 +521,22 @@
account = purple_connection_get_account(gc);
yd = purple_connection_get_protocol_data(gc);
- purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
- purple_xfer_cancel_remote(xfer);
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error); + purple_debug_error("yahoo", + "Unable to find an IP address for relay.msg.yahoo.com : %s\n", - /* Discard the length... */
- hosts = g_slist_remove(hosts, hosts->data);
- purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
purple_xfer_cancel_remote(xfer);
- /* TODO:actually, u must try with addr no.1 , if its not working addr no.2 ..... */
- actaddr = addr->sin_addr.s_addr;
- xd->host = g_strdup_printf("%u.%u.%u.%u", d, c, b, a);
+ inet_address = G_INET_ADDRESS(addresses->data); + xd->host = g_inet_address_to_string(inet_address); - /* Free the address... */
- hosts = g_slist_remove(hosts, hosts->data);
- /* Discard the length... */
- hosts = g_slist_remove(hosts, hosts->data);
- /* Free the address... */
- hosts = g_slist_remove(hosts, hosts->data);
+ g_resolver_free_addresses(addresses); pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANS_INFO_15, YAHOO_STATUS_AVAILABLE, yd->session_id);
filename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
@@ -700,7 +677,6 @@
- PurpleAccount *account;
struct yahoo_xfer_data *xd;
xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
@@ -726,10 +702,12 @@
- account = purple_connection_get_account(gc);
- purple_dnsquery_a(account, YAHOO_XFER_RELAY_HOST,
- yahoo_xfer_dns_connected_15, xfer);
+ g_resolver_lookup_by_name_async(g_resolver_get_default(), + yahoo_xfer_dns_connected_15, --- a/libpurple/proxy.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/proxy.c Wed Dec 23 22:32:36 2015 -0600
@@ -1,4 +1,4 @@
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
@@ -29,7 +29,6 @@
#include "ciphers/md5hash.h"
@@ -37,6 +36,8 @@
PurpleProxyType type; /* The proxy type. */
@@ -57,13 +58,14 @@
- PurpleDnsQueryData *query_data;
+ GCancellable *cancellable; - * This contains alternating length/char* values. The char*
- * values need to be freed when removed from the linked list.
+ * This list contains GInetAddress and they should be freed with + * g_resolver_free_addresses when done with.
PurpleProxyConnectData *child;
@@ -574,18 +576,16 @@
handles = g_slist_remove(handles, connect_data);
- if (connect_data->query_data != NULL)
- purple_dnsquery_destroy(connect_data->query_data);
- while (connect_data->hosts != NULL)
- /* Discard the length... */
- connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
- /* Free the address... */
- g_free(connect_data->hosts->data);
- connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
+ if(G_IS_CANCELLABLE(connect_data->cancellable)) { + g_cancellable_cancel(connect_data->cancellable); + g_object_unref(G_OBJECT(connect_data->cancellable)); + connect_data->cancellable = NULL; + g_resolver_free_addresses(connect_data->hosts); g_free(connect_data->host);
@@ -1307,16 +1307,31 @@
-s4_host_resolved(GSList *hosts, gpointer data, const char *error_message)
+s4_host_resolved(GObject *source_object, GAsyncResult *res, gpointer data) + GResolver *resolver = NULL; + GInetAddress *address = NULL; + GList *hosts = NULL, *l = NULL; PurpleProxyConnectData *connect_data = data;
- common_sockaddr_t *addr;
- connect_data->query_data = NULL;
- if (error_message != NULL) {
- purple_proxy_connect_data_disconnect(connect_data, error_message);
+ if(G_IS_CANCELLABLE(connect_data->cancellable)) { + g_object_unref(G_OBJECT(connect_data->cancellable)); + connect_data->cancellable = NULL; + resolver = g_resolver_get_default(); + hosts = g_resolver_lookup_by_name_finish(resolver, res, &error); + g_object_unref(G_OBJECT(resolver)); + if (error->message != NULL) { + purple_proxy_connect_data_disconnect(connect_data, error->message); @@ -1326,37 +1341,37 @@
- /* Discard the length... */
- hosts = g_slist_delete_link(hosts, hosts);
- hosts = g_slist_delete_link(hosts, hosts);
- packet[2] = connect_data->port >> 8;
- packet[3] = connect_data->port & 0xff;
- memcpy(packet + 4, &addr->in.sin_addr.s_addr, 4);
- /* We could try the other hosts, but hopefully that shouldn't be necessary */
- while (hosts != NULL) {
- /* Discard the length... */
- hosts = g_slist_delete_link(hosts, hosts);
- /* Free the address... */
- hosts = g_slist_delete_link(hosts, hosts);
+ for(l = hosts; l; l = l->next) { + address = G_INET_ADDRESS(l->data); + if(!g_inet_address_get_is_loopback(address) && !g_inet_address_get_is_link_local(address)) - connect_data->write_buffer = g_memdup(packet, sizeof(packet));
- connect_data->write_buf_len = sizeof(packet);
- connect_data->written_len = 0;
- connect_data->read_cb = s4_canread;
- connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data);
- proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
+ packet[2] = connect_data->port >> 8; + packet[3] = connect_data->port & 0xff; + memcpy(packet + 4, g_inet_address_to_bytes(address), 4); + connect_data->write_buffer = g_memdup(packet, sizeof(packet)); + connect_data->write_buf_len = sizeof(packet); + connect_data->written_len = 0; + connect_data->read_cb = s4_canread; + connect_data->inpa = purple_input_add(connect_data->fd, PURPLE_INPUT_WRITE, proxy_do_write, connect_data); + proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE); + purple_proxy_connect_data_disconnect_formatted(connect_data, + _("Error resolving %s"), connect_data->host); + g_resolver_free_addresses(hosts); @@ -1416,11 +1431,21 @@
proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
- connect_data->query_data = purple_dnsquery_a(
- connect_data->account, connect_data->host,
- connect_data->port, s4_host_resolved, connect_data);
- if (connect_data->query_data == NULL) {
+ GResolver *resolver = NULL; + connect_data->cancellable = g_cancellable_new(); + resolver = g_resolver_get_default(); + g_resolver_lookup_by_name_async(resolver, + connect_data->cancellable, + g_object_unref(G_OBJECT(resolver)); + if (connect_data->cancellable == NULL) { purple_debug_error("proxy", "dns query failed unexpectedly.\n");
purple_proxy_connect_data_destroy(connect_data);
@@ -2134,83 +2159,98 @@
static void try_connect(PurpleProxyConnectData *connect_data)
- common_sockaddr_t *addr;
- char ipaddr[INET6_ADDRSTRLEN];
- addrlen = GPOINTER_TO_INT(connect_data->hosts->data);
- connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
- addr = connect_data->hosts->data;
- connect_data->hosts = g_slist_remove(connect_data->hosts, connect_data->hosts->data);
- if (addr->sa.sa_family == AF_INET)
- inet_ntop(addr->sa.sa_family, &addr->in.sin_addr,
- ipaddr, sizeof(ipaddr));
- else if (addr->sa.sa_family == AF_INET6)
- inet_ntop(addr->sa.sa_family, &addr->in6.sin6_addr,
- ipaddr, sizeof(ipaddr));
- memcpy(ipaddr, inet_ntoa(addr->in.sin_addr), sizeof(ipaddr));
+ GInetAddress *address = NULL; + GSocketAddress *socket_address = NULL; + common_sockaddr_t addr; + address = G_INET_ADDRESS(connect_data->hosts->data); + ipaddr = g_inet_address_to_string(address); purple_debug_info("proxy", "Attempting connection to %s\n", ipaddr);
+ socket_address = g_inet_socket_address_new(address, connect_data->port); + addrlen = g_socket_address_get_native_size(socket_address); + g_socket_address_to_native(socket_address, &addr, addrlen, &error); + purple_debug_info("proxy", "failed connnection : %s\n", error->message); if (connect_data->socket_type == SOCK_DGRAM) {
- proxy_connect_udp_none(connect_data, addr, addrlen);
+ proxy_connect_udp_none(connect_data, &addr, addrlen); switch (purple_proxy_info_get_proxy_type(connect_data->gpi)) {
- proxy_connect_none(connect_data, addr, addrlen);
+ proxy_connect_none(connect_data, &addr, addrlen); - proxy_connect_http(connect_data, addr, addrlen);
+ proxy_connect_http(connect_data, &addr, addrlen); case PURPLE_PROXY_SOCKS4:
- proxy_connect_socks4(connect_data, addr, addrlen);
+ proxy_connect_socks4(connect_data, &addr, addrlen); case PURPLE_PROXY_SOCKS5:
- proxy_connect_socks5(connect_data, addr, addrlen);
+ proxy_connect_socks5(connect_data, &addr, addrlen); case PURPLE_PROXY_USE_ENVVAR:
- proxy_connect_http(connect_data, addr, addrlen);
+ proxy_connect_http(connect_data, &addr, addrlen);
+ g_object_unref(G_OBJECT(socket_address)); -connection_host_resolved(GSList *hosts, gpointer data,
- const char *error_message)
- PurpleProxyConnectData *connect_data;
- connect_data->query_data = NULL;
- if (error_message != NULL)
- purple_proxy_connect_data_disconnect(connect_data, error_message);
+connection_host_resolved(GObject *source, GAsyncResult *res, gpointer data) { + PurpleProxyConnectData *connect_data = (PurpleProxyConnectData *)data; + GList *addresses = NULL; + addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error); + if(G_IS_CANCELLABLE(connect_data->cancellable)) { + g_object_unref(G_OBJECT(connect_data->cancellable)); + connect_data->cancellable = NULL; + purple_proxy_connect_data_disconnect(connect_data, error->message); + g_resolver_free_addresses(addresses);
+ if (addresses == NULL) { purple_proxy_connect_data_disconnect(connect_data, _("Unable to resolve hostname"));
- connect_data->hosts = hosts;
+ connect_data->hosts = addresses; try_connect(connect_data);
@@ -2349,9 +2389,15 @@
- connect_data->query_data = purple_dnsquery_a(account, connecthost,
- connectport, connection_host_resolved, connect_data);
- if (connect_data->query_data == NULL)
+ connect_data->cancellable = g_cancellable_new(); + g_resolver_lookup_by_name_async(g_resolver_get_default(), + connect_data->cancellable, + connection_host_resolved, + if (connect_data->cancellable == NULL) purple_debug_error("proxy", "dns query failed unexpectedly.\n");
purple_proxy_connect_data_destroy(connect_data);
@@ -2420,10 +2466,15 @@
- connect_data->query_data = purple_dnsquery_a(account, connecthost,
- connectport, connection_host_resolved, connect_data);
- if (connect_data->query_data == NULL)
+ connect_data->cancellable = g_cancellable_new(); + g_resolver_lookup_by_name_async(g_resolver_get_default(), + connect_data->cancellable, + connection_host_resolved, + if (connect_data->cancellable == NULL) { purple_proxy_connect_data_destroy(connect_data);
--- a/libpurple/purple.h.in Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/purple.h.in Wed Dec 23 22:32:36 2015 -0600
@@ -62,8 +62,6 @@
--- a/libpurple/stun.c Wed Dec 23 22:13:29 2015 -0600
+++ b/libpurple/stun.c Wed Dec 23 22:32:36 2015 -0600
@@ -29,6 +29,8 @@
#if defined (__SVR4) && defined (__sun)
@@ -36,8 +38,6 @@
@@ -82,6 +82,11 @@
static PurpleStunNatDiscovery nattype = {
PURPLE_STUN_STATUS_UNDISCOVERED,
PURPLE_STUN_NAT_TYPE_PUBLIC_IP,
@@ -283,8 +288,11 @@
-static void hbn_listen_cb(int fd, gpointer data) {
+hbn_listen_cb(int fd, gpointer data) { + StunHBNListenData *ld = (StunHBNListenData *)data; + GInetAddress *address = NULL; + GSocketAddress *socket_address = NULL; static struct stun_header hdr_data;
@@ -304,15 +312,15 @@
sc->incb = purple_input_add(fd, PURPLE_INPUT_READ, reply_cb, sc);
- hosts = g_slist_delete_link(hosts, hosts);
- memcpy(&(sc->addr), hosts->data, sizeof(struct sockaddr_in));
- hosts = g_slist_delete_link(hosts, hosts);
- hosts = g_slist_delete_link(hosts, hosts);
- hosts = g_slist_delete_link(hosts, hosts);
+ address = G_INET_ADDRESS(ld->addresses->data); + socket_address = g_inet_socket_address_new(address, ld->port); + g_socket_address_to_native(socket_address, &(sc->addr), g_socket_address_get_native_size(socket_address), NULL); + g_object_unref(G_OBJECT(address)); + g_object_unref(G_OBJECT(socket_address)); + g_resolver_free_addresses(ld->addresses); hdr_data.type = htons(MSGTYPE_BINDINGREQUEST);
@@ -336,44 +344,60 @@
sc->timeout = purple_timeout_add(500, (GSourceFunc) timeoutfunc, sc);
-static void hbn_cb(GSList *hosts, gpointer data, const char *error_message) {
+hbn_cb(GObject *sender, GAsyncResult *res, gpointer data) { + StunHBNListenData *ld = NULL; - if(!hosts || !hosts->data) {
+ ld = g_new0(StunHBNListenData, 1); + ld->addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error); nattype.status = PURPLE_STUN_STATUS_UNDISCOVERED;
nattype.lookup_time = time(NULL);
- if (!purple_network_listen_range(12108, 12208, AF_UNSPEC, SOCK_DGRAM, TRUE, hbn_listen_cb, hosts)) {
- hosts = g_slist_delete_link(hosts, hosts);
- hosts = g_slist_delete_link(hosts, hosts);
+ ld->port = GPOINTER_TO_INT(data); + if (!purple_network_listen_range(12108, 12208, AF_UNSPEC, SOCK_DGRAM, TRUE, hbn_listen_cb, ld)) { nattype.status = PURPLE_STUN_STATUS_UNKNOWN;
nattype.lookup_time = time(NULL);
+do_test1(GObject *sender, GAsyncResult *res, gpointer data) { + GList *services = NULL; + const char *servername = data; + services = g_resolver_lookup_service_finish(g_resolver_get_default(), res, &error); + purple_debug_info("stun", "Failed to look up srv record : %s\n", error->message); + servername = g_srv_target_get_hostname((GSrvTarget *)services->data); + port = g_srv_target_get_port((GSrvTarget *)services->data);
-static void do_test1(PurpleSrvResponse *resp, int results, gpointer sdata) {
- const char *servername = sdata;
+ purple_debug_info("stun", "connecting to %s:%d\n", servername, port);
- servername = resp[0].hostname;
- purple_debug_info("stun", "got %d SRV responses, server: %s, port: %d\n",
- results, servername, port);
+ g_resolver_lookup_by_name_async(g_resolver_get_default(), + GINT_TO_POINTER(port)); - purple_dnsquery_a(NULL, servername, port, hbn_cb, NULL);
+ g_resolver_free_targets(services); static gboolean call_callback(gpointer data) {
@@ -431,8 +455,14 @@
nattype.servername = g_strdup(servername);
callbacks = g_slist_append(callbacks, cb);
- purple_srv_resolve(NULL, "stun", "udp", servername, do_test1,
- (gpointer) servername);
+ g_resolver_lookup_service_async(g_resolver_get_default(),