pidgin/pidgin

7acd79998245
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], , [
AC_MSG_RESULT(no)
AC_MSG_ERROR([
-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
I can find them.
--- 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 @@
smiley-parser.c \
smiley-theme.c \
smiley.c \
- dnsquery.c \
- dnssrv.c\
status.c \
stringref.c \
stun.c \
@@ -187,8 +185,6 @@
smiley-parser.h \
smiley-theme.h \
smiley.h \
- dnsquery.h \
- dnssrv.h \
status.h \
stringref.h \
stun.h \
--- 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"
#include "core.h"
#include "debug.h"
-#include "dnsquery.h"
#include "xfer.h"
#include "glibcompat.h"
#include "http.h"
@@ -200,7 +199,6 @@
purple_pounces_init();
_purple_socket_init();
purple_proxy_init();
- purple_dnsquery_init();
purple_sound_init();
purple_ssl_init();
purple_stun_init();
@@ -276,7 +274,6 @@
purple_xfers_uninit();
purple_proxy_uninit();
_purple_socket_uninit();
- purple_dnsquery_uninit();
_purple_image_store_uninit();
purple_network_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
- *
- * 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
- * source distribution.
- *
- * 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_
-
-#include "internal.h"
-#include "debug.h"
-#include "dnsquery.h"
-#include "network.h"
-#include "notify.h"
-#include "prefs.h"
-#include "util.h"
-
-#ifndef _WIN32
-#include <resolv.h>
-#endif
-
-#define MAX_ADDR_RESPONSE_LEN 1048576
-
-#if (defined(__APPLE__) || defined (__unix__)) && !defined(__osf__)
-#define PURPLE_DNSQUERY_USE_FORK
-#endif
-/**************************************************************************
- * DNS query API
- **************************************************************************/
-
-static PurpleDnsQueryUiOps *dns_query_ui_ops = NULL;
-
-typedef struct _PurpleDnsQueryResolverProcess PurpleDnsQueryResolverProcess;
-
-struct _PurpleDnsQueryData {
- char *hostname;
- int port;
- PurpleDnsQueryConnectFunction callback;
- gpointer data;
- guint timeout;
- PurpleAccount *account;
-
-#if defined(PURPLE_DNSQUERY_USE_FORK)
- PurpleDnsQueryResolverProcess *resolver;
-#elif defined _WIN32 /* end PURPLE_DNSQUERY_USE_FORK */
- GThread *resolver;
- GSList *hosts;
- gchar *error_message;
-#endif
-};
-
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-
-#define MAX_DNS_CHILDREN 4
-
-/*
- * This structure keeps a reference to a child resolver process.
- */
-struct _PurpleDnsQueryResolverProcess {
- guint inpa;
- int fd_in, fd_out;
- pid_t dns_pid;
-};
-
-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.
- */
-typedef struct {
- char hostname[512];
- int port;
-} dns_params_t;
-#endif /* end PURPLE_DNSQUERY_USE_FORK */
-
-static void
-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);
- else
- {
- /*
- * Callback is a required parameter, but it can get set to
- * NULL if we cancel a thread-based DNS lookup. So we need
- * to free hosts.
- */
- while (hosts != NULL)
- {
- hosts = g_slist_remove(hosts, hosts->data);
- g_free(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);
-}
-
-static void
-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);
-}
-
-static gboolean
-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);
-
- return FALSE;
-}
-
-static gboolean
-resolve_ip(PurpleDnsQueryData *query_data)
-{
-#if defined(HAVE_GETADDRINFO) && defined(AI_NUMERICHOST)
- struct addrinfo hints, *res;
- char servname[20];
-
- 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))
- {
- GSList *hosts = NULL;
- 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);
-
- freeaddrinfo(res);
- return TRUE;
- }
-#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.
- */
- GSList *hosts = NULL;
- 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);
-
- return TRUE;
- }
-#endif
-
- return FALSE;
-}
-
-#ifdef USE_IDN
-static gboolean
-dns_str_is_ascii(const char *name)
-{
- guchar *c;
- for (c = (guchar *)name; c && *c; ++c) {
- if (*c > 0x7f)
- return FALSE;
- }
-
- return TRUE;
-}
-#endif
-
-#if defined(PURPLE_DNSQUERY_USE_FORK)
-
-/*
- * Unix!
- */
-
-/*
- * Begin the DNS resolver child process functions.
- */
-#ifdef HAVE_SIGNAL_H
-G_GNUC_NORETURN static void
-trap_gdb_bug(int sig)
-{
- const char *message =
- "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(message,stderr);
- fputs("* * *\n\n",stderr);
- execlp("xmessage","xmessage","-center", message, NULL);
- _exit(1);
-}
-#endif
-
-static void
-write_to_parent(int fd, const void *buf, size_t count)
-{
- ssize_t written;
-
- written = write(fd, buf, count);
- if (written < 0 || (gsize)written != count) {
- if (written < 0)
- fprintf(stderr, "dns[%d]: Error writing data to "
- "parent: %s\n", getpid(), strerror(errno));
- else
- 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;
- const size_t zero = 0;
- int rc;
-#ifdef HAVE_GETADDRINFO
- struct addrinfo hints, *res, *tmp;
- char servname[20];
-#else
- struct sockaddr_in sin;
- const size_t addrlen = sizeof(sin);
-#endif
- char *hostname;
-
-#ifdef HAVE_SIGNAL_H
- purple_restore_default_signal_handlers();
- signal(SIGTRAP, trap_gdb_bug);
-#endif
-
- /*
- * We resolve 1 host name for each iteration of this
- * while loop.
- *
- * 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.
- */
- while (1) {
- fd_set fds;
- struct timeval tv = { .tv_sec = 20, .tv_usec = 0 };
- FD_ZERO(&fds);
- FD_SET(child_in, &fds);
- rc = select(child_in + 1, &fds, NULL, NULL, &tv);
- if (!rc) {
- if (show_debug)
- printf("dns[%d]: nobody needs me... =(\n", getpid());
- break;
- }
- rc = read(child_in, &dns_params, sizeof(dns_params_t));
- if (rc < 0) {
- if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
- /* Try again */
- continue;
- }
- fprintf(stderr, "dns[%d]: Error: Could not read dns_params: "
- "%s\n", getpid(), strerror(errno));
- break;
- }
- if (rc == 0) {
- if (show_debug)
- printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid());
- _exit(0);
- }
- if (dns_params.hostname[0] == '\0') {
- fprintf(stderr, "dns[%d]: Error: Parent requested resolution "
- "of an empty hostname (port = %d)!!!\n", getpid(),
- dns_params.port);
- _exit(1);
- }
-
-#ifdef USE_IDN
- if (!dns_str_is_ascii(dns_params.hostname)) {
- rc = purple_network_convert_idn_to_ascii(dns_params.hostname, &hostname);
- if (rc != 0) {
- write_to_parent(child_out, &rc, sizeof(rc));
- if (show_debug)
- fprintf(stderr, "dns[%d] Error: IDN conversion returned "
- "%d\n", getpid(), rc);
- dns_params.hostname[0] = '\0';
- break;
- }
- } else /* intentional to execute the g_strdup */
-#endif
- hostname = g_strdup(dns_params.hostname);
-
- /* We have the hostname and port, now resolve the IP */
-
-#ifdef HAVE_GETADDRINFO
- 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
- * library.
- */
- hints.ai_socktype = SOCK_STREAM;
-#ifdef AI_ADDRCONFIG
- hints.ai_flags |= AI_ADDRCONFIG;
-#endif /* AI_ADDRCONFIG */
- rc = getaddrinfo(hostname, servname, &hints, &res);
- write_to_parent(child_out, &rc, sizeof(rc));
- if (rc != 0) {
- if (show_debug)
- printf("dns[%d] Error: getaddrinfo returned %d\n",
- getpid(), rc);
- dns_params.hostname[0] = '\0';
- g_free(hostname);
- hostname = NULL;
- break;
- }
- tmp = res;
- while (res) {
- 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);
- res = res->ai_next;
- }
- freeaddrinfo(tmp);
-#else
- struct hostent *hp;
- if (!(hp = gethostbyname(hostname))) {
- write_to_parent(child_out, &h_errno, sizeof(int));
- close(child_out);
- if (show_debug)
- printf("DNS Error: %d\n", h_errno);
- _exit(0);
- }
- 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);
- rc = 0;
- write_to_parent(child_out, &rc, sizeof(rc));
- write_to_parent(child_out, &addrlen, sizeof(addrlen));
- write_to_parent(child_out, &sin, addrlen);
-#endif
- write_to_parent(child_out, &zero, sizeof(zero));
- dns_params.hostname[0] = '\0';
-
- g_free(hostname);
- hostname = NULL;
- }
-
- close(child_out);
- close(child_in);
-
- _exit(0);
-}
-/*
- * End the DNS resolver child process functions.
- */
-
-/*
- * Begin the functions for dealing with the DNS child processes.
- */
-static void
-cope_with_gdb_brokenness(void)
-{
-#ifdef __linux__
- static gboolean already_done = FALSE;
- char s[256], e[512];
- int n;
- pid_t ppid;
-
- if(already_done)
- return;
- already_done = TRUE;
- ppid = getppid();
- g_snprintf(s, sizeof(s), "/proc/%d/exe", ppid);
- n = readlink(s, e, sizeof(e));
- if(n < 0)
- return;
-
- e[MIN((gsize)n,sizeof(e)-1)] = '\0';
-
- if(strstr(e,"gdb")) {
- purple_debug_info("dns",
- "Debugger detected, performing useless query...\n");
- gethostbyname("x.x.x.x.x");
- }
-#endif
-}
-
-static void
-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);
- resolver->inpa = 0;
- }
-
- /*
- * 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);
-
- g_free(resolver);
-
- 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));
- return NULL;
- }
-
- resolver = g_new(PurpleDnsQueryResolverProcess, 1);
- resolver->inpa = 0;
-
- 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 */
- close(child_out[0]);
- close(child_in[1]);
-
- 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 */
- close(child_out[1]);
- close(child_in[0]);
- if (resolver->dns_pid == -1) {
- purple_debug_error("dns",
- "Could not create child process for DNS: %s\n",
- g_strerror(errno));
- purple_dnsquery_resolver_destroy(resolver);
- return NULL;
- }
-
- 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);
-
- return resolver;
-}
-
-/*
- * 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.
- */
-static gboolean
-send_dns_request_to_child(PurpleDnsQueryData *query_data,
- PurpleDnsQueryResolverProcess *resolver)
-{
- pid_t pid;
- dns_params_t dns_params;
- ssize_t rc;
-
- /* 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);
- if (pid > 0) {
- purple_debug_info("dns", "DNS child %d no longer exists\n",
- resolver->dns_pid);
- purple_dnsquery_resolver_destroy(resolver);
- return FALSE;
- } else if (pid < 0) {
- purple_debug_info("dns", "Wait for DNS child %d failed: %s\n",
- resolver->dns_pid, g_strerror(errno));
- purple_dnsquery_resolver_destroy(resolver);
- return FALSE;
- }
-
- /* 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));
- if (rc < 0) {
- purple_debug_error("dns", "Unable to write to DNS child %d: %s\n",
- resolver->dns_pid, g_strerror(errno));
- purple_dnsquery_resolver_destroy(resolver);
- return FALSE;
- }
- 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);
- return FALSE;
- }
-
- purple_debug_info("dns",
- "Successfully sent DNS request to child %d\n",
- resolver->dns_pid);
-
- query_data->resolver = resolver;
-
- return TRUE;
-}
-
-static void host_resolved(gpointer data, gint source, PurpleInputCondition cond);
-
-static void
-handle_next_queued_request(void)
-{
- PurpleDnsQueryData *query_data;
- PurpleDnsQueryResolverProcess *resolver;
-
- if (g_queue_is_empty(queued_requests))
- /* No more DNS queries, yay! */
- return;
-
- 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 */
- break;
- }
-
- /* 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);
- return;
- }
-
- resolver = purple_dnsquery_resolver_new(purple_debug_is_enabled());
- if (resolver == NULL)
- {
- purple_dnsquery_failed(query_data, _("Unable to create new resolver process\n"));
- return;
- }
- if (!send_dns_request_to_child(query_data, resolver))
- {
- purple_dnsquery_failed(query_data, _("Unable to send request to resolver process\n"));
- return;
- }
- }
-
- 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.
- */
-
-static void
-host_resolved(gpointer data, gint source, PurpleInputCondition cond)
-{
- PurpleDnsQueryData *query_data;
- int rc, err;
- GSList *hosts = NULL;
- struct sockaddr *addr = NULL;
- size_t addrlen;
- char message[1024];
-
- query_data = data;
-
- 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))
- {
-#ifdef HAVE_GETADDRINFO
- g_snprintf(message, sizeof(message), _("Error resolving %s:\n%s"),
- query_data->hostname, purple_gai_strerror(err));
-#else
- g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
- query_data->hostname, err);
-#endif
- /* Re-read resolv.conf and friends in case DNS servers have changed */
- res_init();
-
- purple_dnsquery_failed(query_data, message);
- } else if (rc > 0) {
- /* Success! */
- while (rc > 0) {
- 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);
- } else {
- break;
- }
- }
- /* wait4(resolver->dns_pid, NULL, WNOHANG, NULL); */
- purple_dnsquery_resolved(query_data, hosts);
-
- } else if (rc == -1) {
- g_snprintf(message, sizeof(message), _("Error reading from resolver process:\n%s"), g_strerror(errno));
- purple_dnsquery_failed(query_data, message);
-
- } else if (rc == 0) {
- g_snprintf(message, sizeof(message), _("Resolver process exited without answering our request"));
- purple_dnsquery_failed(query_data, message);
- }
-
- handle_next_queued_request();
-}
-
-static void
-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 */
-
-/*
- * Windows!
- */
-
-static gboolean
-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);
- else
- {
- GSList *hosts;
-
- /* 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);
- }
-
- return FALSE;
-}
-
-static gpointer
-dns_thread(gpointer data)
-{
- PurpleDnsQueryData *query_data;
-#if defined(HAVE_GETADDRINFO) || defined(USE_IDN)
- int rc;
-#endif
-#ifdef HAVE_GETADDRINFO
- struct addrinfo hints, *res, *tmp;
- char servname[20];
-#else
- struct sockaddr_in sin;
- struct hostent *hp;
-#endif
- char *hostname;
-
- query_data = data;
-
-#ifdef USE_IDN
- if (!dns_str_is_ascii(query_data->hostname)) {
- rc = purple_network_convert_idn_to_ascii(query_data->hostname, &hostname);
- if (rc != 0) {
- 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);
- return 0;
- }
- } else /* intentional fallthru */
-#endif
- hostname = g_strdup(query_data->hostname);
-
-#ifdef HAVE_GETADDRINFO
- 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
- * library.
- */
- hints.ai_socktype = SOCK_STREAM;
-#ifdef AI_ADDRCONFIG
- hints.ai_flags |= AI_ADDRCONFIG;
-#endif /* AI_ADDRCONFIG */
- if ((rc = getaddrinfo(hostname, servname, &hints, &res)) == 0) {
- tmp = res;
- while(res) {
- 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));
- res = res->ai_next;
- }
- freeaddrinfo(tmp);
- } else {
- query_data->error_message = g_strdup_printf(_("Error resolving %s:\n%s"), query_data->hostname, purple_gai_strerror(rc));
- }
-#else
- 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)));
- } else {
- query_data->error_message = g_strdup_printf(_("Error resolving %s: %d"), query_data->hostname, h_errno);
- }
-#endif
- g_free(hostname);
-
- /* back to main thread */
- purple_timeout_add(0, dns_main_thread_cb, query_data);
-
- return 0;
-}
-
-static void
-resolve_host(PurpleDnsQueryData *query_data)
-{
- GError *err = NULL;
-
- /*
- * 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,
- query_data, &err);
- if (query_data->resolver == NULL)
- {
- char message[1024];
- g_snprintf(message, sizeof(message), _("Thread creation failure: %s"),
- (err && err->message) ? err->message : _("Unknown reason"));
- g_error_free(err);
- purple_dnsquery_failed(query_data, message);
- }
- else
- 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.
- */
-
-static void
-resolve_host(PurpleDnsQueryData *query_data)
-{
- struct sockaddr_in sin;
- GSList *hosts = NULL;
- struct hostent *hp;
- gchar *hostname;
-#ifdef USE_IDN
- if (!dns_str_is_ascii(query_data->hostname)) {
- int ret = purple_network_convert_idn_to_ascii(query_data->hostname,
- &hostname);
- if (ret != 0) {
- char message[1024];
- g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
- query_data->hostname, ret);
- purple_dnsquery_failed(query_data, message);
- return;
- }
- } else /* fallthrough is intentional to the g_strdup */
-#endif
- hostname = g_strdup(query_data->hostname);
-
- if(!(hp = gethostbyname(hostname))) {
- char message[1024];
- g_snprintf(message, sizeof(message), _("Error resolving %s: %d"),
- query_data->hostname, h_errno);
- purple_dnsquery_failed(query_data, message);
- g_free(hostname);
- return;
- }
- 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;
- g_free(hostname);
- 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 */
-
-static gboolean
-initiate_resolving(gpointer data)
-{
- PurpleDnsQueryData *query_data;
- PurpleProxyType proxy_type;
-
- query_data = data;
- query_data->timeout = 0;
-
- if (resolve_ip(query_data))
- /* resolve_ip calls purple_dnsquery_resolved */
- return FALSE;
-
- 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."));
- return FALSE;
- }
-
- if (purple_dnsquery_ui_resolve(query_data))
- /* The UI is handling the resolve; we're done */
- return FALSE;
-
- resolve_host(query_data);
-
- return FALSE;
-}
-
-PurpleDnsQueryData *
-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);
-
- return query_data;
-}
-
-void
-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
- * finish.
- */
- query_data->callback = NULL;
- return;
- }
-
- 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);
-#endif /* end _WIN32 */
-
- if (query_data->timeout > 0)
- purple_timeout_remove(query_data->timeout);
-
- g_free(query_data->hostname);
- g_free(query_data);
-}
-
-char *
-purple_dnsquery_get_host(PurpleDnsQueryData *query_data)
-{
- g_return_val_if_fail(query_data != NULL, NULL);
-
- return query_data->hostname;
-}
-
-unsigned short
-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);
- *ops_new = *ops;
-
- return ops_new;
-}
-
-GType
-purple_dnsquery_ui_ops_get_type(void)
-{
- static GType type = 0;
-
- if (type == 0) {
- type = g_boxed_type_register_static("PurpleDnsQueryUiOps",
- (GBoxedCopyFunc)purple_dnsquery_ui_ops_copy,
- (GBoxedFreeFunc)g_free);
- }
-
- return type;
-}
-
-void
-purple_dnsquery_set_ui_ops(PurpleDnsQueryUiOps *ops)
-{
- dns_query_ui_ops = ops;
-}
-
-PurpleDnsQueryUiOps *
-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;
-}
-
-void
-purple_dnsquery_init(void)
-{
-#if defined(PURPLE_DNSQUERY_USE_FORK)
- queued_requests = g_queue_new();
-#endif
-}
-
-void
-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
- *
- * 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
- * source distribution.
- *
- * 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:dnsquery
- * @section_id: libpurple-dnsquery
- * @short_description: <filename>dnsquery.h</filename>
- * @title: DNS Query API
- */
-
-#include <glib.h>
-#include "eventloop.h"
-#include "account.h"
-
-#define PURPLE_TYPE_DNSQUERY_UI_OPS (purple_dnsquery_ui_ops_get_type())
-
-/**
- * PurpleDnsQueryData:
- *
- * 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);
-
-/**
- * PurpleDnsQueryUiOps:
- * @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>
- * Structures</link>
- */
-struct _PurpleDnsQueryUiOps
-{
- gboolean (*resolve_host)(PurpleDnsQueryData *query_data,
- PurpleDnsQueryResolvedCallback resolved_cb,
- PurpleDnsQueryFailedCallback failed_cb);
-
- void (*destroy)(PurpleDnsQueryData *query_data);
-
- /*< private >*/
- void (*_purple_reserved1)(void);
- void (*_purple_reserved2)(void);
- void (*_purple_reserved3)(void);
- void (*_purple_reserved4)(void);
-};
-
-G_BEGIN_DECLS
-
-/**************************************************************************/
-/* DNS query API */
-/**************************************************************************/
-
-/**
- * purple_dnsquery_ui_ops_get_type:
- *
- * Returns: The #GType for the #PurpleDnsQueryUiOps boxed structure.
- */
-GType purple_dnsquery_ui_ops_get_type(void);
-
-/**
- * purple_dnsquery_a:
- * @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
- * resolve.
- *
- * 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
- *
- * Returns: The host.
- */
-char *purple_dnsquery_get_host(PurpleDnsQueryData *query_data);
-
-/**
- * purple_dnsquery_get_port:
- * @query_data: The DNS query
- *
- * Get the port associated with a PurpleDnsQueryData
- *
- * Returns: The port.
- */
-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);
-
-G_END_DECLS
-
-#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 @@
-/* purple
- *
- * 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 "internal.h"
-#include "util.h"
-
-#ifndef _WIN32
-#include <arpa/nameser.h>
-#include <resolv.h>
-#ifdef HAVE_ARPA_NAMESER_COMPAT_H
-#include <arpa/nameser_compat.h>
-#endif
-#else /* WIN32 */
-#include <windns.h>
-/* Missing from the mingw headers */
-#ifndef DNS_TYPE_SRV
-# define DNS_TYPE_SRV PurpleDnsTypeSrv
-#endif
-#ifndef DNS_TYPE_TXT
-# define DNS_TYPE_TXT PurpleDnsTypeTxt
-#endif
-#endif
-
-#ifndef T_SRV
-#define T_SRV PurpleDnsTypeSrv
-#endif
-#ifndef T_TXT
-#define T_TXT PurpleDnsTypeTxt
-#endif
-
-#define MAX_ADDR_RESPONSE_LEN 1048576
-
-#include "debug.h"
-#include "dnssrv.h"
-#include "eventloop.h"
-#include "network.h"
-
-static PurpleSrvTxtQueryUiOps *srv_txt_query_ui_ops = NULL;
-
-#ifndef _WIN32
-typedef union {
- HEADER hdr;
- u_char buf[1024];
-} queryans;
-#endif
-
-enum PurpleDnsType {
- PurpleDnsTypeTxt = 16,
- PurpleDnsTypeSrv = 33
-};
-
-struct _PurpleSrvTxtQueryData {
- union {
- PurpleSrvCallback srv;
- PurpleTxtCallback txt;
- } cb;
-
- gpointer extradata;
- guint handle;
- int type;
- char *query;
-#ifdef _WIN32
- GThread *resolver;
- char *error_message;
- GList *results;
-#else
- int fd_in, fd_out;
- pid_t pid;
-#endif
-};
-
-typedef struct _PurpleSrvInternalQuery {
- int type;
- char query[256];
-} PurpleSrvInternalQuery;
-
-typedef struct _PurpleSrvResponseContainer {
- PurpleSrvResponse *response;
- int sum;
-} 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.
- */
-static gint
-responsecompare(gconstpointer ar, gconstpointer br)
-{
- PurpleSrvResponse *a = (PurpleSrvResponse*)ar;
- PurpleSrvResponse *b = (PurpleSrvResponse*)br;
-
- if(a->pref == b->pref) {
- if(a->weight == b->weight)
- return 0;
- if(a->weight < b->weight)
- return -1;
- return 1;
- }
- if(a->pref < b->pref)
- return -1;
- return 1;
-}
-
-/*
- * 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.
- */
-static GList *
-select_random_response(GList *list, PurpleSrvResponseContainer **container_ptr)
-{
- GList *cur;
- size_t runningtotal;
- int r;
-
- g_return_val_if_fail(list != NULL, NULL);
-
- runningtotal = 0;
- cur = list;
-
- while (cur) {
- PurpleSrvResponseContainer *container = cur->data;
- runningtotal += container->response->weight;
- container->sum = runningtotal;
- cur = cur->next;
- }
-
- /*
- * 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;
- cur = list;
- while (r > ((PurpleSrvResponseContainer *)cur->data)->sum) {
- if (G_UNLIKELY(!cur->next))
- break;
- cur = 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
- * (aka "pref").
- */
-static void
-srv_reorder(GList *list, int num)
-{
- int i;
- GList *cur, *container_list = NULL;
- PurpleSrvResponseContainer *container;
-
- if (num < 2)
- /* Nothing to sort */
- return;
-
- 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.
- */
- cur = list;
- while (container_list) {
- g_return_if_fail(cur);
- container_list = select_random_response(container_list, &container);
- cur->data = container->response;
- g_free(container);
- cur = cur->next;
- }
-}
-
-/*
- * purple_srv_sort:
- * @list: The original list, resorted
- *
- * Sorts a GList of PurpleSrvResponses according to the
- * algorithm described in RFC 2782.
- *
- * Returns: GList of PurpleSrvResponse's
- */
-static GList *
-purple_srv_sort(GList *list)
-{
- int pref, count;
- GList *cur, *start;
-
- if (!list || !list->next) {
- /* Nothing to sort */
- return list;
- }
-
- list = g_list_sort(list, responsecompare);
-
- start = cur = list;
- count = 1;
- while (cur) {
- 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);
- start = cur->next;
- count = 0;
- }
- count++;
- cur = cur->next;
- }
-
- return list;
-}
-
-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;
-#ifndef _WIN32
- query_data->fd_in = -1;
- query_data->fd_out = -1;
-#endif
- return query_data;
-}
-
-void
-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);
-#ifdef _WIN32
- 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
- * finish.
- */
- query_data->cb.srv = NULL;
- return;
- }
- g_free(query_data->error_message);
-#else
- if (query_data->fd_out != -1)
- close(query_data->fd_out);
- if (query_data->fd_in != -1)
- close(query_data->fd_in);
-#endif
- g_free(query_data->query);
- g_free(query_data);
-}
-
-#ifdef USE_IDN
-static gboolean
-dns_str_is_ascii(const char *name)
-{
- guchar *c;
- for (c = (guchar *)name; c && *c; ++c) {
- if (*c > 0x7f)
- return FALSE;
- }
-
- return TRUE;
-}
-#endif
-
-#ifndef _WIN32
-static void
-write_to_parent(int in, int out, gconstpointer data, gsize size)
-{
- const guchar *buf = data;
- gssize w;
-
- do {
- w = write(out, buf, size);
- if (w > 0) {
- buf += w;
- size -= w;
- } else if (w < 0 && errno == EINTR) {
- /* Let's try some more; */
- w = 1;
- }
- } while (size > 0 && w > 0);
-
- if (size != 0) {
- /* An error occurred */
- close(out);
- close(in);
- _exit(0);
- }
-}
-
-/* Read size bytes to data. Dies if an error occurs. */
-static void
-read_from_parent(int in, int out, gpointer data, gsize size)
-{
- guchar *buf = data;
- gssize r;
-
- do {
- r = read(in, data, size);
- if (r > 0) {
- buf += r;
- size -= r;
- } else if (r < 0 && errno == EINTR) {
- /* Let's try some more; */
- r = 1;
- }
- } while (size > 0 && r > 0);
-
- if (size != 0) {
- /* An error occurred */
- close(out);
- close(in);
- _exit(0);
- }
-}
-
-
-G_GNUC_NORETURN static void
-resolve(int in, int out)
-{
- GList *ret = NULL;
- PurpleSrvResponse *srvres;
- PurpleTxtResponse *txtres;
- queryans answer;
- int size, qdcount, ancount;
- guchar *end, *cp;
- gchar name[256];
- guint16 type, dlen, pref, weight, port;
- PurpleSrvInternalQuery query;
-
-#ifdef HAVE_SIGNAL_H
- purple_restore_default_signal_handlers();
-#endif
-
- read_from_parent(in, out, &query, sizeof(query));
-
- size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer));
- if (size == -1) {
- write_to_parent(in, out, &(query.type), sizeof(query.type));
- write_to_parent(in, out, &size, sizeof(size));
- close(out);
- close(in);
- _exit(0);
- }
-
- 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);
- if(size < 0) goto end;
- cp += size + QFIXEDSZ;
- }
-
- while (ancount-- > 0 && cp < end) {
- size = dn_expand((unsigned char*)&answer, end, cp, name, 256);
- if(size < 0)
- goto end;
- cp += size;
- GETSHORT(type,cp);
-
- /* skip ttl and class since we already know it */
- cp += 6;
-
- GETSHORT(dlen,cp);
- if (type == T_SRV) {
- GETSHORT(pref,cp);
-
- GETSHORT(weight,cp);
-
- GETSHORT(port,cp);
-
- size = dn_expand( (unsigned char*)&answer, end, cp, name, 256);
- if(size < 0 )
- goto end;
-
- cp += size;
-
- 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)!",
- name, strlen(name));
- }
- g_strlcpy(srvres->hostname, name, sizeof(srvres->hostname));
- srvres->pref = pref;
- srvres->port = port;
- 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);
- cp += dlen - 1;
- } else {
- cp += dlen;
- }
- }
-
-end:
- 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));
- while (ret != NULL)
- {
- 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);
- }
-
- g_free(ret->data);
- ret = g_list_remove(ret, ret->data);
- }
-
- close(out);
- close(in);
-
- _exit(0);
-}
-
-static void
-resolved(gpointer data, gint source, PurpleInputCondition cond)
-{
- int size;
- int type;
- PurpleSrvTxtQueryData *query_data = (PurpleSrvTxtQueryData*)data;
- int i;
- int status;
-
- 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");
- size = 0;
- }
- if (size == -1 || size == 0) {
- if (size == -1) {
- purple_debug_warning("dnssrv", "res_query returned an error\n");
- /* Re-read resolv.conf and friends in case DNS servers have changed */
- res_init();
- } else
- purple_debug_info("dnssrv", "Found 0 entries, errno is %i\n", errno);
-
- if (type == T_SRV) {
- 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);
- } else {
- purple_debug_error("dnssrv", "type unknown of DNS result entry; errno is %i\n", errno);
- }
-
- } else if (size) {
- if (type == T_SRV) {
- PurpleSrvResponse *res;
- PurpleSrvResponse *tmp;
- PurpleSrvCallback cb = query_data->cb.srv;
- ssize_t red;
- 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));
- size = 0;
- g_free(res);
- res = NULL;
- }
- }
-
- cb(res, size, query_data->extradata);
- } else if (type == T_TXT) {
- GList *responses = NULL;
- PurpleTxtResponse *res;
- PurpleTxtCallback cb = query_data->cb.txt;
- ssize_t red;
- purple_debug_info("dnssrv","found %d TXT entries\n", size);
- for (i = 0; i < size; i++) {
- gsize len;
-
- 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));
- size = 0;
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
- responses = NULL;
- break;
- }
- if (len > MAX_ADDR_RESPONSE_LEN) {
- purple_debug_error("dnssrv", "we've read invalid number\n");
- size = 0;
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
- responses = NULL;
- break;
- }
-
- 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));
- size = 0;
- purple_txt_response_destroy(res);
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
- responses = NULL;
- break;
- }
- responses = g_list_prepend(responses, res);
- }
-
- responses = g_list_reverse(responses);
- cb(responses, query_data->extradata);
- } else {
- 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);
-}
-
-#else /* _WIN32 */
-
-/* The Jabber Server code was inspiration for parts of this. */
-
-static gboolean
-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);
- }
- } else {
- 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);
- while (lst) {
- PurpleSrvResponse *lstdata = lst->data;
- lst = g_list_delete_link(lst, lst);
-
- if(query_data->cb.srv)
- memcpy(srvres_tmp++, lstdata, sizeof(PurpleSrvResponse));
- g_free(lstdata);
- }
-
- 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);
- }
- } else {
- purple_debug_error("dnssrv", "unknown query type");
- }
- }
-
- query_data->resolver = NULL;
- query_data->handle = 0;
-
- purple_srv_txt_query_destroy(query_data);
-
- return FALSE;
-}
-
-static gpointer
-res_thread(gpointer data)
-{
- PDNS_RECORD dr = NULL;
- int type;
- DNS_STATUS ds;
- 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);
- }
- g_free(msg);
- } else {
- if (type == DNS_TYPE_SRV) {
- PDNS_RECORD dr_tmp;
- GList *lst = NULL;
- 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) {
- continue;
- }
-
- 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) {
- PDNS_RECORD dr_tmp;
- GList *lst = NULL;
- DNS_TXT_DATA *txt_data;
- PurpleTxtResponse *txtres;
-
- for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) {
- GString *s;
- int i;
-
- /* 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) {
- continue;
- }
-
- txt_data = &dr_tmp->Data.TXT;
- txtres = g_new0(PurpleTxtResponse, 1);
-
- s = g_string_new("");
- 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;
- } else {
-
- }
- }
-
- /* 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);
-
- g_thread_exit(NULL);
- return NULL;
-}
-
-#endif
-
-PurpleSrvTxtQueryData *
-purple_srv_resolve(PurpleAccount *account, const char *protocol,
- const char *transport, const char *domain, PurpleSrvCallback cb,
- gpointer extradata)
-{
- char *query;
- char *hostname;
- PurpleSrvTxtQueryData *query_data;
- PurpleProxyType proxy_type;
-#ifndef _WIN32
- PurpleSrvInternalQuery internal_query;
- int in[2], out[2];
- int pid;
-#else
- GError* err = NULL;
-#endif
-
- 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);
- return NULL;
- }
-
-#ifdef USE_IDN
- if (!dns_str_is_ascii(domain)) {
- int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
- if (ret != 0) {
- purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
- cb(NULL, 0, extradata);
- return NULL;
- }
- } else /* Fallthru is intentional */
-#endif
- 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);
- g_free(hostname);
-
- query_data = query_data_new(PurpleDnsTypeSrv, query, extradata);
- query_data->cb.srv = cb;
-
- if (purple_srv_txt_query_ui_resolve(query_data))
- {
- return query_data;
- }
-
-#ifndef _WIN32
- if(pipe(in) || pipe(out)) {
- purple_debug_error("dnssrv", "Could not create pipe\n");
- g_free(query);
- g_free(query_data);
- cb(NULL, 0, extradata);
- return NULL;
- }
-
- /*
- * 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.)
- */
- pid = fork();
- if (pid == -1) {
- purple_debug_error("dnssrv", "Could not create process!\n");
- g_free(query);
- g_free(query_data);
- cb(NULL, 0, extradata);
- return NULL;
- }
-
- /* Child */
- if (pid == 0)
- {
- g_free(query);
- g_free(query_data);
-
- close(out[0]);
- close(in[1]);
- resolve(in[0], out[1]);
- /* resolve() does not return */
- }
-
- close(out[1]);
- close(in[0]);
-
- 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->pid = pid;
- 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);
-
- return query_data;
-#else
- 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_error_free(err);
- }
- else
- 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);
-
- return query_data;
-#endif
-}
-
-PurpleSrvTxtQueryData *purple_txt_resolve(PurpleAccount *account,
- const char *owner, const char *domain, PurpleTxtCallback cb,
- gpointer extradata)
-{
- char *query;
- char *hostname;
- PurpleSrvTxtQueryData *query_data;
- PurpleProxyType proxy_type;
-#ifndef _WIN32
- PurpleSrvInternalQuery internal_query;
- int in[2], out[2];
- int pid;
-#else
- GError* err = NULL;
-#endif
-
- 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");
- cb(NULL, extradata);
- return NULL;
- }
-
-#ifdef USE_IDN
- if (!dns_str_is_ascii(domain)) {
- int ret = purple_network_convert_idn_to_ascii(domain, &hostname);
- if (ret != 0) {
- purple_debug_error("dnssrv", "IDNA ToASCII failed\n");
- cb(NULL, extradata);
- return NULL;
- }
- } else /* fallthru is intentional */
-#endif
- 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);
- g_free(hostname);
-
- 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
- */
- return query_data;
- }
-
-#ifndef _WIN32
- if(pipe(in) || pipe(out)) {
- purple_debug_error("dnssrv", "Could not create pipe\n");
- g_free(query);
- g_free(query_data);
- cb(NULL, extradata);
- return NULL;
- }
-
- /*
- * 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.)
- */
- pid = fork();
- if (pid == -1) {
- purple_debug_error("dnssrv", "Could not create process!\n");
- g_free(query);
- g_free(query_data);
- cb(NULL, extradata);
- return NULL;
- }
-
- /* Child */
- if (pid == 0)
- {
- g_free(query);
- g_free(query_data);
-
- close(out[0]);
- close(in[1]);
- resolve(in[0], out[1]);
- /* resolve() does not return */
- }
-
- close(out[1]);
- close(in[0]);
-
- 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->pid = pid;
- 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);
-
- return query_data;
-#else
- 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_error_free(err);
- }
- else
- 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);
-
- return query_data;
-#endif
-}
-
-const gchar *
-purple_txt_response_get_content(PurpleTxtResponse *resp)
-{
- g_return_val_if_fail(resp != NULL, NULL);
-
- return resp->content;
-}
-
-void purple_txt_response_destroy(PurpleTxtResponse *resp)
-{
- g_return_if_fail(resp != NULL);
-
- g_free(resp->content);
- g_free(resp);
-}
-
-/*
- * Only used as the callback for the ui ops.
- */
-static void
-purple_srv_query_resolved(PurpleSrvTxtQueryData *query_data, GList *records)
-{
- GList *l;
- PurpleSrvResponse *records_array;
- int i = 0, length;
-
- g_return_if_fail(records != NULL);
-
- if (query_data->cb.srv == NULL) {
- purple_srv_txt_query_destroy(query_data);
-
- while (records) {
- g_free(records->data);
- records = g_list_delete_link(records, records);
- }
- return;
- }
-
- 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);
-
- while (records) {
- g_free(records->data);
- records = g_list_delete_link(records, records);
- }
-}
-
-/*
- * Only used as the callback for the ui ops.
- */
-static void
-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);
- else {
- while (entries) {
- g_free(entries->data);
- entries = g_list_delete_link(entries, entries);
- }
- }
-
- purple_srv_txt_query_destroy(query_data);
-}
-
-static void
-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);
-}
-
-static gboolean
-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);
-
- return FALSE;
-}
-
-void
-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;
-}
-
-char *
-purple_srv_txt_query_get_query(PurpleSrvTxtQueryData *query_data)
-{
- g_return_val_if_fail(query_data != NULL, NULL);
-
- return query_data->query;
-}
-
-
-int
-purple_srv_txt_query_get_query_type(PurpleSrvTxtQueryData *query_data)
-{
- g_return_val_if_fail(query_data != NULL, 0);
-
- return query_data->type;
-}
-
-/**************************************************************************
- * GBoxed code
- **************************************************************************/
-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);
- *ops_new = *ops;
-
- return ops_new;
-}
-
-GType
-purple_srv_txt_query_ui_ops_get_type(void)
-{
- static GType type = 0;
-
- if (type == 0) {
- type = g_boxed_type_register_static("PurpleSrvTxtQueryUiOps",
- (GBoxedCopyFunc)purple_srv_txt_query_ui_ops_copy,
- (GBoxedFreeFunc)g_free);
- }
-
- return type;
-}
--- 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 @@
-/* purple
- *
- * 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:dnssrv
- * @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.h>
-#include <glib-object.h>
-
-struct _PurpleSrvResponse {
- char hostname[256];
- int port;
- int weight;
- int pref;
-};
-
-struct _PurpleTxtResponse {
- char *content;
-};
-
-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
- * asynchronously.
- * @destroy: Called just before @query_data is freed; this should cancel any
- * further use of @query_data the UI would make. Unneeded if @resolve
- * is not implemented.
- *
- * 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);
-
- /*< private >*/
- void (*_purple_reserved1)(void);
- void (*_purple_reserved2)(void);
- void (*_purple_reserved3)(void);
- void (*_purple_reserved4)(void);
-};
-
-/**
- * PurpleSrvCallback:
- * @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);
-
-/**
- * PurpleTxtCallback:
- * @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);
-
-G_BEGIN_DECLS
-
-/**
- * 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);
-
-/**
- * purple_srv_resolve:
- * @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);
-
-/**
- * purple_txt_resolve:
- * @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
- * resolve.
- *
- * 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
- *
- * Returns: The query.
- */
-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);
-
-G_END_DECLS
-
-#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 @@
return FALSE;
}
-#if !GLIB_CHECK_VERSION(2, 32, 0)
-
-#include <glib-object.h>
-#include <string.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)
-{
- GByteArray *array;
-
- array = g_byte_array_new();
- g_byte_array_append(array, data, len);
- g_free(data);
-
- return array;
-}
-
-static inline void g_queue_free_full(GQueue *queue, GDestroyNotify free_func)
-{
- g_queue_foreach(queue, (GFunc)free_func, NULL);
- g_queue_free(queue);
-}
-
-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,
- glong end_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);
- out[end - start] = 0;
-
- return out;
-}
-
-#endif /* < 2.30.0 */
-
-#endif /* < 2.32.0 */
-
#endif /* < 2.36.0 */
--- 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 "internal.h"
+#include <gio/gio.h>
+
#ifndef _WIN32
#include <arpa/nameser.h>
#include <resolv.h>
@@ -46,7 +48,6 @@
#include "prefs.h"
#include "stun.h"
#include "upnp.h"
-#include "dnsquery.h"
#ifdef USE_IDN
#include <idna.h>
@@ -977,40 +978,26 @@
#endif
static void
-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) {
+ GError *error = NULL;
+ GList *addresses = NULL;
+ GInetAddress *address = NULL;
+ const gchar **ip_address = (const gchar **)data;
- if (error_message) {
- purple_debug_error("network", "lookup of IP address failed: %s\n",
- error_message);
- g_slist_free(hosts);
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+ if(error) {
+ purple_debug_info("network", "lookup of IP address failed: %s\n", error->message);
+
+ g_error_free(error);
+
return;
}
- 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,
- dst, sizeof(dst));
- } else {
- inet_ntop(addr->sa.sa_family, &addr->in.sin_addr,
- dst, sizeof(dst));
- }
+ *ip_address = g_inet_address_to_string(address);
- *ip = g_strdup(dst);
- purple_debug_info("network", "set IP address: %s\n", *ip);
- }
-
- while (hosts != NULL) {
- hosts = g_slist_delete_link(hosts, hosts);
- /* Free the address */
- g_free(hosts->data);
- hosts = g_slist_delete_link(hosts, hosts);
- }
+ g_resolver_free_addresses(addresses);
}
void
@@ -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,
- &stun_ip);
+ g_resolver_lookup_by_name_async(g_resolver_get_default(),
+ stun_server,
+ NULL,
+ purple_network_ip_lookup_cb,
+ &stun_ip);
} else {
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(),
+ turn_server,
+ NULL,
+ purple_network_ip_lookup_cb,
+ &turn_server);
} else {
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 <internal.h>
#include <debug.h>
-#include <dnsquery.h>
#include <libgadu.h>
#include "resolver-purple.h"
+#include <gio/gio.h>
+
static int ggp_resolver_purple_start(int *fd, void **private_data,
const char *hostname);
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);
typedef struct
{
- PurpleDnsQueryData *purpleQuery;
+ GCancellable *cancellable;
/**
* File descriptors:
@@ -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;
+ GError *error = 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",
+ error->message);
- if (error_message) {
- purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n",
- error_message);
+ g_error_free(error);
+ } else {
+ purple_debug_misc("gg", "ggp_resolver_purple_cb succeeded: (%p, %p)\n",
+ addresses, cbdata);
}
- all_count = g_slist_length(hosts);
- g_assert(all_count % 2 == 0);
- all_count /= 2;
- addresses = malloc((all_count + 1) * sizeof(struct in_addr));
+ g_object_unref(G_OBJECT(data->cancellable));
+ data->cancellable = NULL;
- ipv4_count = 0;
- 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);
+
+ switch(family) {
+ 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,
- dst, sizeof(dst));
- 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,
- dst, sizeof(dst));
- purple_debug_misc("gg", "ggp_resolver_purple_cb "
- "ipv4: %s\n", dst);
+ 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));
+
+ break;
+ 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;
- } else {
- purple_debug_warning("gg", "ggp_resolver_purple_cb "
- "unexpected sa_family: %d\n",
- addr.sa.sa_family);
+ break;
+ default:
+ purple_debug_warning("gg", "ggp_resolver_purple_cb "
+ "unexpected sa_family: %d\n",
+ family);
+
+ break;
}
- g_free(hosts->data);
- hosts = g_slist_delete_link(hosts, hosts);
+ g_free(ip_address);
}
- 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_free(l->data);
}
- free(addresses);
+
+ g_list_free(in_addrs);
+ 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;
data->pipes[0] = 0;
data->pipes[1] = 0;
@@ -150,10 +155,15 @@
*fd = data->pipes[0];
/* 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(),
+ hostname,
+ data->cancellable,
+ ggp_resolver_purple_cb,
+ (gpointer)data);
+
+ 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 @@
return;
*private_data = NULL;
- if (data->purpleQuery)
- purple_dnsquery_destroy(data->purpleQuery);
+ if (G_IS_CANCELLABLE(data->cancellable)) {
+ g_cancellable_cancel(data->cancellable);
+
+ g_object_unref(G_OBJECT(data->cancellable));
+ }
+
if (data->pipes[0])
close(data->pipes[0]);
if (data->pipes[1])
--- 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 */
static void
-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) {
+ GError *error = NULL;
+ GList *services = NULL;
JabberStream *js = (JabberStream *) data;
+ gint results = 0;
- if (error_message) {
- purple_debug_error("jabber", "STUN lookup failed: %s\n",
- error_message);
- g_slist_free(hosts);
- js->stun_query = NULL;
+ services = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
+
+ if(error != NULL) {
+ purple_debug_info("jabber", "Failed to look up a STUN record : %s\n", error->message);
+
+ g_error_free(error);
+
return;
}
- if (hosts && g_slist_next(hosts)) {
- common_sockaddr_t addr;
- char dst[INET6_ADDRSTRLEN];
- int port;
+ 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,
- dst, sizeof(dst));
- port = ntohs(addr.in6.sin6_port);
- } else {
- inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
- dst, sizeof(dst));
- port = ntohs(addr.in.sin_port);
- }
+ if (results > 0) {
+ GSrvTarget *target = (GSrvTarget *)services->data;
+ const gchar *hostname = g_srv_target_get_hostname(target);
- g_free(js->stun_ip);
- js->stun_ip = g_strdup(dst);
- js->stun_port = port;
+ js->stun_ip = g_strdup(hostname);
+ js->stun_port = g_srv_target_get_port(target);
- purple_debug_info("jabber", "set STUN IP/port address: "
- "%s:%d\n", dst, port);
-
- /* unmark ongoing query */
- js->stun_query = NULL;
+ 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);
- /* Free the address */
- g_free(hosts->data);
- hosts = g_slist_delete_link(hosts, hosts);
- }
-}
-
-
-static void
-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;
-
- if (results > 0) {
- 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);
- js->stun_query =
- 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(), "")) {
- js->srv_query_data =
- purple_srv_resolve(
- purple_connection_get_account(js->gc), "stun", "udp",
- js->user->domain,
- jabber_disco_stun_srv_resolve_cb, js);
+
+ g_resolver_lookup_service_async(g_resolver_get_default(),
+ "stun",
+ "udp",
+ js->user->domain,
+ NULL,
+ jabber_disco_stun_srv_resolve_cb,
+ js);
/* 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 @@
#include "debug.h"
#include "jingleinfo.h"
+#include <gio/gio.h>
+
static void
-jabber_google_stun_lookup_cb(GSList *hosts, gpointer data,
- const char *error_message)
-{
+jabber_google_stun_lookup_cb(GObject *sender, GAsyncResult *result, gpointer data) {
+ GError *error = NULL;
+ GList *addresses = NULL;
JabberStream *js = (JabberStream *) data;
- if (error_message) {
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+
+ if(error) {
purple_debug_error("jabber", "Google STUN lookup failed: %s\n",
- error_message);
- g_slist_free(hosts);
- js->stun_query = NULL;
+ error->message);
+
+ g_error_free(error);
+
return;
}
- if (hosts && g_slist_next(hosts)) {
- common_sockaddr_t addr;
- char dst[INET6_ADDRSTRLEN];
- int port;
-
- 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,
- dst, sizeof(dst));
- port = ntohs(addr.in6.sin6_port);
- } else {
- inet_ntop(addr.sa.sa_family, &addr.in.sin_addr,
- dst, sizeof(dst));
- port = ntohs(addr.in.sin_port);
- }
+ if(g_list_length(addresses) > 0) {
+ GInetAddress *inet_address = G_INET_ADDRESS(addresses->data);
g_free(js->stun_ip);
- js->stun_ip = g_strdup(dst);
- js->stun_port = port;
+ js->stun_ip = g_inet_address_to_string(inet_address);
purple_debug_info("jabber", "set Google STUN IP/port address: "
- "%s:%d\n", dst, port);
-
- /* unmark ongoing query */
- js->stun_query = NULL;
+ "%s:%d\n", js->stun_ip, js->stun_port);
}
- while (hosts != NULL) {
- hosts = g_slist_delete_link(hosts, hosts);
- /* Free the address */
- g_free(hosts->data);
- hosts = g_slist_delete_link(hosts, hosts);
- }
+ g_resolver_free_addresses(addresses);
}
static void
@@ -110,16 +92,13 @@
const gchar *udp = purple_xmlnode_get_attrib(server, "udp");
if (host && udp) {
- PurpleAccount *account;
- int port = atoi(udp);
- /* if there, would already be an ongoing query,
- cancel it */
- if (js->stun_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(),
+ host,
+ NULL,
+ jabber_google_stun_lookup_cb,
+ js);
}
}
}
--- 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 "connection.h"
#include "conversation.h"
#include "debug.h"
-#include "dnssrv.h"
#include "http.h"
#include "message.h"
#include "notify.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 @@
}
static void
-txt_resolved_cb(GList *responses, gpointer data)
+txt_resolved_cb(GObject *sender, GAsyncResult *result, gpointer data)
{
+ GError *error = NULL;
+ GList *records = NULL, *l = NULL;
JabberStream *js = data;
gboolean found = FALSE;
- js->srv_query_data = NULL;
-
- while (responses) {
- PurpleTxtResponse *resp = responses->data;
- gchar **token;
- 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);
+ if(error) {
+ purple_debug_warning("jabber", "Unable to find alternative XMPP connection "
+ "methods after failing to connect directly. : %s\n",
+ error->message);
+
+ purple_connection_error(js->gc,
+ PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+ _("Unable to connect"));
+
+ g_error_free(error);
+
+ return;
+ }
+
+ for(l = records; l; l = l->next) {
+ GVariantIter *iter = NULL;
+ gchar *str = 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]);
+
+ g_strfreev(token);
+
+ break;
+ }
+
g_strfreev(token);
- break;
}
- g_strfreev(token);
- 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);
+
if (js->bosh)
found = TRUE;
@@ -791,11 +815,6 @@
_("Unable to connect"));
return;
}
-
- if (responses) {
- g_list_foreach(responses, (GFunc)purple_txt_response_destroy, NULL);
- g_list_free(responses);
- }
}
static void
@@ -805,21 +824,21 @@
JabberStream *js = purple_connection_get_protocol_data(gc);
if (source < 0) {
- if (js->srv_rec != NULL) {
- purple_debug_error("jabber", "Unable to connect to server: %s. Trying next SRV record or connecting directly.\n", error);
- try_srv_connect(js);
- } else {
- 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(),
+ name,
+ G_RESOLVER_RECORD_TXT,
+ js->cancellable,
+ txt_resolved_cb,
+ js);
+ g_free(name);
+
return;
}
- g_free(js->srv_rec);
- js->srv_rec = NULL;
-
js->fd = source;
if(js->state == JABBER_STREAM_CONNECTING)
@@ -881,37 +900,43 @@
return TRUE;
}
-static void try_srv_connect(JabberStream *js)
+static void
+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))
- return;
- }
-
- g_free(js->srv_rec);
- js->srv_rec = NULL;
-
- /* 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),
- TRUE);
-}
-
-static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data)
-{
+ GError *error = NULL;
+ GList *targets = NULL, *l = NULL;
JabberStream *js = data;
- js->srv_query_data = NULL;
-
- if(results) {
- js->srv_rec = resp;
- js->srv_rec_idx = 0;
- js->max_srv_rec_idx = results;
- try_srv_connect(js);
- } else {
+
+ targets = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
+ if(error) {
+ purple_debug_warning("jabber",
+ "SRV lookup failed, proceeding with normal connection : %s",
+ error->message);
+
+ g_error_free(error);
+
jabber_login_connect(js, js->user->domain, js->user->domain,
purple_account_get_int(purple_connection_get_account(js->gc), "port", 5222),
TRUE);
+
+ } else {
+ 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);
+
+ return;
+ }
+ }
+
+ 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),
+ TRUE);
}
}
@@ -930,6 +955,9 @@
js->fd = -1;
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->sessions = NULL;
js->stun_ip = NULL;
js->stun_port = 0;
- js->stun_query = NULL;
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);
} else {
- 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(),
+ "xmpp-client",
+ "tcp",
+ js->user->domain,
+ js->cancellable,
+ srv_resolved_cb,
+ js);
}
}
@@ -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);
-
if(js->gsc) {
purple_ssl_close(js->gsc);
} else if (js->fd > 0) {
@@ -1693,17 +1722,10 @@
if (js->conn_close_timeout != 0)
purple_timeout_remove(js->conn_close_timeout);
- g_free(js->srv_rec);
- js->srv_rec = NULL;
+ g_cancellable_cancel(js->cancellable);
+ g_object_unref(G_OBJECT(js->cancellable));
g_free(js->stun_ip);
- js->stun_ip = NULL;
-
- /* cancel DNS query for STUN, if one is ongoing */
- if (js->stun_query) {
- purple_dnsquery_destroy(js->stun_query);
- js->stun_query = NULL;
- }
/* 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 <glib.h>
#include <gmodule.h>
+#include <gio/gio.h>
+
#include "circularbuffer.h"
#include "connection.h"
-#include "dnsquery.h"
-#include "dnssrv.h"
#include "http.h"
#include "media.h"
#include "mediamanager.h"
@@ -120,7 +120,7 @@
int fd;
guint inpa;
- PurpleSrvTxtQueryData *srv_query_data;
+ GCancellable *cancellable;
xmlParserCtxt *context;
PurpleXmlNode *current;
@@ -277,10 +277,6 @@
guint inactivity_timer;
guint conn_close_timeout;
- PurpleSrvResponse *srv_rec;
- guint srv_rec_idx;
- guint max_srv_rec_idx;
-
PurpleJabberBOSHConnection *bosh;
PurpleHttpConnectionSet *http_conns;
@@ -291,7 +287,6 @@
/* maybe this should only be present when USE_VV? */
gchar *stun_ip;
int stun_port;
- 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 "accountopt.h"
#include "buddylist.h"
#include "conversation.h"
-#include "dnsquery.h"
#include "debug.h"
#include "notify.h"
#include "protocol.h"
@@ -41,7 +40,6 @@
#include "simple.h"
#include "sipmsg.h"
-#include "dnssrv.h"
#include "ntlm.h"
static PurpleProtocol *my_protocol = NULL;
@@ -1801,29 +1799,41 @@
do_register(sip);
}
-static void simple_udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) {
+static void
+simple_udp_host_resolved(GObject *sender, GAsyncResult *result, gpointer data) {
+ GError *error = NULL;
+ GList *addresses = NULL;
+ GInetAddress *inet_address = NULL;
+ GSocketAddress *socket_address = NULL;
struct simple_account_data *sip = (struct simple_account_data*) data;
- int addr_size;
- sip->query_data = NULL;
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+ if(error) {
+ gchar *msg = g_strdup_printf(_("Unable to resolve hostname : %s"),
+ error->message);
- if (!hosts || !hosts->data) {
purple_connection_error(sip->gc,
PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
- _("Unable to resolve hostname"));
+ msg
+ );
+
+ g_error_free(error);
+
return;
}
- addr_size = GPOINTER_TO_INT(hosts->data);
- hosts = g_slist_remove(hosts, hosts->data);
- memcpy(&(sip->serveraddr), hosts->data, addr_size);
- g_free(hosts->data);
- hosts = g_slist_remove(hosts, hosts->data);
- while(hosts) {
- hosts = g_slist_remove(hosts, hosts->data);
- g_free(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,
+ &(sip->serveraddr),
+ g_socket_address_get_native_size(socket_address),
+ NULL);
+
+ 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) {
+static void
+srvresolved(GObject *sender, GAsyncResult *result, gpointer data) {
+ GError *error = NULL;
+ GList *targets = NULL;
struct simple_account_data *sip;
gchar *hostname;
int port;
sip = data;
- sip->srv_query_data = NULL;
-
- port = purple_account_get_int(sip->account, "port", 0);
- /* find the host to connect to */
- if(results) {
- hostname = g_strdup(resp->hostname);
- if(!port)
- port = resp->port;
- g_free(resp);
- } else {
+ targets = g_resolver_lookup_service_finish(g_resolver_get_default(), result, &error);
+ if(error) {
+ purple_debug_info("simple",
+ "srv lookup failed, continuing with configured settings : %s",
+ error->message);
+
+ g_error_free(error);
+
if(!purple_account_get_bool(sip->account, "useproxy", FALSE)) {
hostname = g_strdup(sip->servername);
} else {
hostname = g_strdup(purple_account_get_string(sip->account, "proxy", sip->servername));
- }
+ }
+ port = purple_account_get_int(sip->account, "port", 0);
+ } else {
+ 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;
sip->realport = port;
- if(!sip->realport) sip->realport = 5060;
+
+ if(!sip->realport)
+ sip->realport = 5060;
/* TCP case */
if(!sip->udp) {
@@ -1907,13 +1928,11 @@
} else { /* UDP */
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(),
+ sip->realhostname,
+ sip->cancellable,
+ simple_udp_host_resolved,
+ sip);
}
}
@@ -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",
+ sip->udp ? "udp" : "tcp",
+ hosttoconnect,
+ sip->cancellable,
+ srvresolved,
+ sip);
}
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 <glib.h>
#include <gmodule.h>
+#include <gio/gio.h>
#include <time.h>
#include "cipher.h"
#include "circularbuffer.h"
-#include "dnsquery.h"
-#include "dnssrv.h"
#include "network.h"
#include "proxy.h"
#include "protocol.h"
@@ -100,8 +99,7 @@
gchar *servername;
gchar *username;
gchar *password;
- PurpleDnsQueryData *query_data;
- PurpleSrvTxtQueryData *srv_query_data;
+ GCancellable *cancellable;
PurpleNetworkListenData *listen_data;
int fd;
int cseq;
--- 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 */
#include "internal.h"
-#include "dnsquery.h"
#include "protocol.h"
#include "util.h"
@@ -39,6 +38,8 @@
#include "yahoo_doodle.h"
#include "yahoo_friend.h"
+#include <gio/gio.h>
+
struct yahoo_xfer_data {
gchar *url;
gboolean is_relay;
@@ -498,14 +499,15 @@
return ans;
}
-static void yahoo_xfer_dns_connected_15(GSList *hosts, gpointer data, const char *error_message)
+static void
+yahoo_xfer_dns_connected_15(GObject *sender, GAsyncResult *result, gpointer data)
{
+ GError *error = NULL;
+ GList *addresses = NULL;
+ GInetAddress *inet_address = NULL;
PurpleXfer *xfer;
struct yahoo_xfer_data *xd;
- struct sockaddr_in *addr;
struct yahoo_packet *pkt;
- unsigned long actaddr;
- unsigned char a,b,c,d;
PurpleConnection *gc;
PurpleAccount *account;
YahooData *yd;
@@ -519,47 +521,22 @@
account = purple_connection_get_account(gc);
yd = purple_connection_get_protocol_data(gc);
- if(!hosts)
- {
- purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
- purple_xfer_cancel_remote(xfer);
- return;
- }
+ addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), result, &error);
+ if(error) {
+ purple_debug_error("yahoo",
+ "Unable to find an IP address for relay.msg.yahoo.com : %s\n",
+ error->message);
- /* Discard the length... */
- hosts = g_slist_remove(hosts, hosts->data);
- if(!hosts)
- {
- purple_debug_error("yahoo", "Unable to find an IP address for relay.msg.yahoo.com\n");
purple_xfer_cancel_remote(xfer);
+ g_error_free(error);
+
return;
}
- /* TODO:actually, u must try with addr no.1 , if its not working addr no.2 ..... */
- addr = hosts->data;
- actaddr = addr->sin_addr.s_addr;
- d = actaddr & 0xff;
- actaddr >>= 8;
- c = actaddr & 0xff;
- actaddr >>= 8;
- b = actaddr & 0xff;
- actaddr >>= 8;
- a = actaddr & 0xff;
-
- 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... */
- g_free(hosts->data);
- hosts = g_slist_remove(hosts, hosts->data);
- addr = NULL;
- while (hosts != NULL)
- {
- /* Discard the length... */
- hosts = g_slist_remove(hosts, hosts->data);
- /* Free the address... */
- g_free(hosts->data);
- 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 @@
}
if(val_222 == 3)
{
- PurpleAccount *account;
struct yahoo_xfer_data *xd;
xfer = g_hash_table_lookup(yd->xfer_peer_idstring_map,
@@ -726,10 +702,12 @@
}
xd->is_relay = TRUE;
- account = purple_connection_get_account(gc);
- purple_dnsquery_a(account, YAHOO_XFER_RELAY_HOST,
- YAHOO_XFER_RELAY_PORT,
- yahoo_xfer_dns_connected_15, xfer);
+ g_resolver_lookup_by_name_async(g_resolver_get_default(),
+ YAHOO_XFER_RELAY_HOST,
+ NULL,
+ yahoo_xfer_dns_connected_15,
+ xfer);
+
return;
}
--- 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
+ /* purple
*
* 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 "internal.h"
#include "ciphers/md5hash.h"
#include "debug.h"
-#include "dnsquery.h"
#include "http.h"
#include "notify.h"
#include "ntlm.h"
@@ -37,6 +36,8 @@
#include "proxy.h"
#include "util.h"
+#include <gio/gio.h>
+
struct _PurpleProxyInfo
{
PurpleProxyType type; /* The proxy type. */
@@ -57,13 +58,14 @@
int socket_type;
guint inpa;
PurpleProxyInfo *gpi;
- 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.
*/
- GSList *hosts;
+ GList *hosts;
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);
g_free(connect_data);
}
@@ -1307,16 +1307,31 @@
}
static void
-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;
+ GError *error = NULL;
+ GList *hosts = NULL, *l = NULL;
PurpleProxyConnectData *connect_data = data;
unsigned char packet[9];
- 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);
+
+ g_error_free(error);
+
return;
}
@@ -1326,37 +1341,37 @@
return;
}
- /* Discard the length... */
- hosts = g_slist_delete_link(hosts, hosts);
- addr = hosts->data;
- hosts = g_slist_delete_link(hosts, hosts);
-
- packet[0] = 0x04;
- packet[1] = 0x01;
- packet[2] = connect_data->port >> 8;
- packet[3] = connect_data->port & 0xff;
- memcpy(packet + 4, &addr->in.sin_addr.s_addr, 4);
- packet[8] = 0x00;
-
- g_free(addr);
-
- /* 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... */
- g_free(hosts->data);
- 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))
+ break;
+
+ address = NULL;
}
- 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);
+ if(address != NULL) {
+ packet[0] = 0x04;
+ packet[1] = 0x01;
+ packet[2] = connect_data->port >> 8;
+ packet[3] = connect_data->port & 0xff;
+ memcpy(packet + 4, g_inet_address_to_bytes(address), 4);
+ packet[8] = 0x00;
+
+ 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);
+ } else {
+ purple_proxy_connect_data_disconnect_formatted(connect_data,
+ _("Error resolving %s"), connect_data->host);
+ }
+
+ g_resolver_free_addresses(hosts);
}
static void
@@ -1416,11 +1431,21 @@
proxy_do_write(connect_data, connect_data->fd, PURPLE_INPUT_WRITE);
} else {
- 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->host,
+ connect_data->cancellable,
+ s4_host_resolved,
+ connect_data);
+
+ 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)
{
- socklen_t addrlen;
- 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);
-#ifdef HAVE_INET_NTOP
- 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));
-#else
- memcpy(ipaddr, inet_ntoa(addr->in.sin_addr), sizeof(ipaddr));
-#endif
+ GInetAddress *address = NULL;
+ GSocketAddress *socket_address = NULL;
+ GError *error = NULL;
+ char *ipaddr;
+
+ common_sockaddr_t addr;
+ socklen_t addrlen = 0;
+
+ 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);
+ g_free(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);
+ if(error != NULL) {
+ purple_debug_info("proxy", "failed connnection : %s\n", error->message);
+
+ g_error_free(error);
+
+ return;
+ }
if (connect_data->socket_type == SOCK_DGRAM) {
- proxy_connect_udp_none(connect_data, addr, addrlen);
- g_free(addr);
+ proxy_connect_udp_none(connect_data, &addr, addrlen);
+
return;
}
switch (purple_proxy_info_get_proxy_type(connect_data->gpi)) {
case PURPLE_PROXY_NONE:
- proxy_connect_none(connect_data, addr, addrlen);
+ proxy_connect_none(connect_data, &addr, addrlen);
break;
case PURPLE_PROXY_HTTP:
- proxy_connect_http(connect_data, addr, addrlen);
+ proxy_connect_http(connect_data, &addr, addrlen);
break;
case PURPLE_PROXY_SOCKS4:
- proxy_connect_socks4(connect_data, addr, addrlen);
+ proxy_connect_socks4(connect_data, &addr, addrlen);
break;
case PURPLE_PROXY_SOCKS5:
case PURPLE_PROXY_TOR:
- proxy_connect_socks5(connect_data, addr, addrlen);
+ proxy_connect_socks5(connect_data, &addr, addrlen);
break;
case PURPLE_PROXY_USE_ENVVAR:
- proxy_connect_http(connect_data, addr, addrlen);
+ proxy_connect_http(connect_data, &addr, addrlen);
break;
default:
break;
}
- g_free(addr);
+ g_object_unref(G_OBJECT(socket_address));
}
static void
-connection_host_resolved(GSList *hosts, gpointer data,
- const char *error_message)
-{
- PurpleProxyConnectData *connect_data;
-
- connect_data = 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;
+ GError *error = NULL;
+ 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;
+ }
+
+ if (error != NULL) {
+ purple_proxy_connect_data_disconnect(connect_data, error->message);
+
+ g_error_free(error);
+
+ g_resolver_free_addresses(addresses);
+
return;
}
- if (hosts == NULL)
- {
+ if (addresses == NULL) {
purple_proxy_connect_data_disconnect(connect_data, _("Unable to resolve hostname"));
+
return;
}
- connect_data->hosts = hosts;
+ connect_data->hosts = addresses;
try_connect(connect_data);
}
@@ -2349,9 +2389,15 @@
return NULL;
}
- 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(),
+ connecthost,
+ connect_data->cancellable,
+ connection_host_resolved,
+ connect_data);
+
+ 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 @@
return NULL;
}
- 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(),
+ connecthost,
+ connect_data->cancellable,
+ connection_host_resolved,
+ connect_data);
+
+ if (connect_data->cancellable == NULL) {
purple_proxy_connect_data_destroy(connect_data);
return NULL;
}
--- 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 @@
#include <core.h>
#include <debug.h>
#include <desktopitem.h>
-#include <dnsquery.h>
-#include <dnssrv.h>
#include <enums.h>
#include <eventloop.h>
#include <idle.h>
--- 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 @@
#include <sys/ioctl.h>
#endif
+#include <gio/gio.h>
+
/* Solaris */
#if defined (__SVR4) && defined (__sun)
#include <sys/sockio.h>
@@ -36,8 +38,6 @@
#include "debug.h"
#include "account.h"
-#include "dnsquery.h"
-#include "dnssrv.h"
#include "network.h"
#include "proxy.h"
#include "stun.h"
@@ -82,6 +82,11 @@
size_t packetsize;
};
+typedef struct {
+ gint port;
+ GList *addresses;
+} StunHBNListenData;
+
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) {
- GSList *hosts = data;
+static void
+hbn_listen_cb(int fd, gpointer data) {
+ StunHBNListenData *ld = (StunHBNListenData *)data;
+ GInetAddress *address = NULL;
+ GSocketAddress *socket_address = NULL;
struct stun_conn *sc;
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));
- g_free(hosts->data);
- hosts = g_slist_delete_link(hosts, hosts);
- while (hosts) {
- hosts = g_slist_delete_link(hosts, hosts);
- g_free(hosts->data);
- 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);
+ g_free(ld);
hdr_data.type = htons(MSGTYPE_BINDINGREQUEST);
hdr_data.len = 0;
@@ -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) {
+static void
+hbn_cb(GObject *sender, GAsyncResult *res, gpointer data) {
+ StunHBNListenData *ld = NULL;
+ GError *error = NULL;
- if(!hosts || !hosts->data) {
+ ld = g_new0(StunHBNListenData, 1);
+
+ ld->addresses = g_resolver_lookup_by_name_finish(g_resolver_get_default(), res, &error);
+ if(error != NULL) {
nattype.status = PURPLE_STUN_STATUS_UNDISCOVERED;
nattype.lookup_time = time(NULL);
+
do_callbacks();
+
return;
}
- if (!purple_network_listen_range(12108, 12208, AF_UNSPEC, SOCK_DGRAM, TRUE, hbn_listen_cb, hosts)) {
- while (hosts) {
- hosts = g_slist_delete_link(hosts, hosts);
- g_free(hosts->data);
- 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_callbacks();
+
return;
}
+}
+
+static void
+do_test1(GObject *sender, GAsyncResult *res, gpointer data) {
+ GList *services = NULL;
+ GError *error = NULL;
+ const char *servername = data;
+ int port = 3478;
+
+ services = g_resolver_lookup_service_finish(g_resolver_get_default(), res, &error);
+ if(error != NULL) {
+ purple_debug_info("stun", "Failed to look up srv record : %s\n", error->message);
+
+ g_error_free(error);
+ } else {
+ 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;
- int port = 3478;
+ purple_debug_info("stun", "connecting to %s:%d\n", servername, port);
- if(results) {
- servername = resp[0].hostname;
- port = resp[0].port;
- }
- 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(),
+ servername,
+ NULL,
+ hbn_cb,
+ GINT_TO_POINTER(port));
- purple_dnsquery_a(NULL, servername, port, hbn_cb, NULL);
- g_free(resp);
+ 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(),
+ "stun",
+ "udp",
+ servername,
+ NULL,
+ do_test1,
+ (gpointer)servername);
return &nattype;
}