soc.2012.gg: 2b9913aa: New custom resolver, that uses libpurple...

tomkiewicz at cpw.pidgin.im tomkiewicz at cpw.pidgin.im
Thu Jun 7 06:51:58 EDT 2012


----------------------------------------------------------------------
Revision: 2b9913aaf462a241a7d454bf9ea96f156daf76da
Parent:   95b990bae7d439afac6bc95905b0026e52b003c2
Author:   tomkiewicz at cpw.pidgin.im
Date:     06/07/12 06:47:50
Branch:   im.pidgin.soc.2012.gg
URL: http://d.pidgin.im/viewmtn/revision/info/2b9913aaf462a241a7d454bf9ea96f156daf76da

Changelog: 

New custom resolver, that uses libpurple for DNS queries. Get rid of old win32 resolver. Refs#343. Fixes #6263

Changes against parent 95b990bae7d439afac6bc95905b0026e52b003c2

  dropped  libpurple/protocols/gg/win32-resolver.c
  dropped  libpurple/protocols/gg/win32-resolver.h
  added    libpurple/protocols/gg/resolver-purple.c
  added    libpurple/protocols/gg/resolver-purple.h
  patched  libpurple/eventloop.c
  patched  libpurple/eventloop.h
  patched  libpurple/protocols/gg/Makefile.am
  patched  libpurple/protocols/gg/Makefile.mingw
  patched  libpurple/protocols/gg/gg.c
  patched  libpurple/win32/win32dep.c
  patched  libpurple/win32/win32dep.h

-------------- next part --------------
============================================================
--- libpurple/protocols/gg/Makefile.am	52056a4431bbd8d71e1e3c3b26a4183e10f4886d
+++ libpurple/protocols/gg/Makefile.am	92f14838ba026d32c3b88e65f34e5ddb5fea37ed
@@ -1,7 +1,7 @@ EXTRA_DIST = \
 EXTRA_DIST = \
 	Makefile.mingw \
-	win32-resolver.c \
-	win32-resolver.h \
+	resolver-purple.c \
+	resolver-purple.h \
 	lib/common.c \
 	lib/compat.h \
 	lib/COPYING \
@@ -81,7 +81,9 @@ GGSOURCES = \
 	buddylist.h \
 	buddylist.c \
 	gg.h \
-	gg.c
+	gg.c \
+	resolver-purple.h \
+	resolver-purple.c
 
 AM_CFLAGS = $(st)
 
============================================================
--- libpurple/protocols/gg/gg.c	5f171159d2f69d8f0607310d2516c47ff357dae1
+++ libpurple/protocols/gg/gg.c	ce72c0ebf7addc72304d660d17ce2f0c3c8f481d
@@ -44,11 +44,8 @@
 #include "search.h"
 #include "buddylist.h"
 #include "gg-utils.h"
+#include "resolver-purple.h"
 
-#ifdef _WIN32
-#  include "win32-resolver.h"
-#endif
-
 /* Prototypes */
 static void ggp_set_status(PurpleAccount *account, PurpleStatus *status);
 static int ggp_to_gg_status(PurpleStatus *status, char **msg);
@@ -3005,10 +3002,7 @@ static void init_plugin(PurplePlugin *pl
 
 	gg_debug_handler = purple_gg_debug_handler;
 	
-#ifdef _WIN32
-	gg_global_set_custom_resolver(ggp_resolver_win32thread_start,
-		ggp_resolver_win32thread_cleanup);
-#endif
+	ggp_resolver_purple_setup();
 }
 
 PURPLE_INIT_PLUGIN(gg, init_plugin, info);
============================================================
--- libpurple/protocols/gg/Makefile.mingw	fb7eb47e39a124fb8c47c34856471d014f66eda2
+++ libpurple/protocols/gg/Makefile.mingw	1064e02bc4246a61fcc307b327440e93603f69f1
@@ -24,14 +24,14 @@ endif
 ##
 ## INCLUDE PATHS
 ##
-INCLUDE_PATHS +=	-I. \
+INCLUDE_PATHS +=\
+			-I$(PIDGIN_TREE_TOP) \
+			-I$(PURPLE_TOP) \
+			-I$(PURPLE_TOP)/win32 \
 			-I./lib \
 			-I$(GTK_TOP)/include \
 			-I$(GTK_TOP)/include/glib-2.0 \
-			-I$(GTK_TOP)/lib/glib-2.0/include \
-			-I$(PURPLE_TOP) \
-			-I$(PURPLE_TOP)/win32 \
-			-I$(PIDGIN_TREE_TOP)
+			-I$(GTK_TOP)/lib/glib-2.0/include
 
 LIB_PATHS +=		-L$(GTK_TOP)/lib \
 			-L$(PURPLE_TOP) \
@@ -61,7 +61,7 @@ C_SRC =	\
 	gg.c \
 	search.c \
 	gg-utils.c \
-	win32-resolver.c
+	resolver-purple.c
 
 OBJECTS = $(C_SRC:%.c=%.o)
 
============================================================
--- libpurple/win32/win32dep.c	d62e125b1de03235763e5f361b9a93c2d504fa6a
+++ libpurple/win32/win32dep.c	ac957dfa5f6088924232369334dd02f346bb94a3
@@ -328,6 +328,111 @@ char *wpurple_read_reg_string(HKEY rootk
 	return result;
 }
 
+int wpurple_input_pipe(int pipefd[2])
+{
+	SOCKET sock_server, sock_client, sock_server_established;
+	struct sockaddr_in saddr_in;
+	struct sockaddr * const saddr_p = (struct sockaddr *)&saddr_in;
+	int saddr_len = sizeof(struct sockaddr_in);
+	u_long arg;
+	fd_set select_set;
+	char succ = 1;
+
+	sock_server = sock_client = sock_server_established = INVALID_SOCKET;
+
+	purple_debug_misc("wpurple", "wpurple_input_pipe(0x%x[%d,%d])\n",
+		(unsigned int)pipefd, pipefd[0], pipefd[1]);
+
+	/* create client and passive server sockets */
+	sock_server = socket(AF_INET, SOCK_STREAM, 0);
+	sock_client = socket(AF_INET, SOCK_STREAM, 0);
+	succ = (sock_server != INVALID_SOCKET || sock_client != INVALID_SOCKET);
+
+	/* set created sockets into nonblocking mode */
+	arg = 1;
+	succ = (succ &&
+		ioctlsocket(sock_server, FIONBIO, &arg) != SOCKET_ERROR);
+	arg = 1;
+	succ = (succ &&
+		ioctlsocket(sock_client, FIONBIO, &arg) != SOCKET_ERROR);
+
+	/* listen on server socket */
+	memset(&saddr_in, 0, saddr_len);
+	saddr_in.sin_family = AF_INET;
+	saddr_in.sin_port = 0;
+	saddr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	succ = (succ &&
+		bind(sock_server, saddr_p, saddr_len) != SOCKET_ERROR &&
+		listen(sock_server, 1) != SOCKET_ERROR &&
+		getsockname(sock_server, saddr_p, &saddr_len) != SOCKET_ERROR);
+
+	/* request a connection from client to server socket */
+	succ = (succ &&
+		connect(sock_client, saddr_p, saddr_len) == SOCKET_ERROR &&
+		WSAGetLastError() == WSAEWOULDBLOCK);
+
+	/* ensure, that server socket is readable */
+	if (succ)
+	{
+		FD_ZERO(&select_set);
+		FD_SET(sock_server, &select_set);
+	}
+	succ = (succ &&
+		select(0, &select_set, NULL, NULL, NULL) != SOCKET_ERROR &&
+		FD_ISSET(sock_server, &select_set));
+
+	/* accept (establish) connection from client socket */
+	if (succ)
+	{
+		sock_server_established =
+			accept(sock_server, saddr_p, &saddr_len);
+		succ = (sock_server_established != INVALID_SOCKET);
+	}
+
+	/* ensure, that client socket is writable */
+	if (succ)
+	{
+		FD_ZERO(&select_set);
+		FD_SET(sock_client, &select_set);
+	}
+	succ = (succ &&
+		select(0, NULL, &select_set, NULL, NULL) != SOCKET_ERROR &&
+		FD_ISSET(sock_client, &select_set));
+
+	/* set sockets into blocking mode */
+	arg = 0;
+	succ = (succ &&
+		ioctlsocket(sock_client, FIONBIO, &arg) != SOCKET_ERROR);
+	arg = 0;
+	succ = (succ &&
+		ioctlsocket(sock_server_established, FIONBIO, &arg)
+			!= SOCKET_ERROR);
+
+	/* we don't need (passive) server socket anymore */
+	if (sock_server != INVALID_SOCKET)
+		closesocket(sock_server);
+
+	if (succ)
+	{
+		purple_debug_misc("wpurple",
+			"wpurple_input_pipe created pipe [%d,%d]\n",
+			sock_client, sock_server_established);
+		pipefd[0] = sock_client; /* for reading */
+		pipefd[1] = sock_server_established; /* for writing */
+		return 0;
+	}
+	else
+	{
+		purple_debug_error("wpurple", "wpurple_input_pipe failed\n");
+		if (sock_client != INVALID_SOCKET)
+			closesocket(sock_client);
+		if (sock_server_established != INVALID_SOCKET)
+			closesocket(sock_server_established);
+		errno = EMFILE;
+		return -1;
+	}
+}
+
 void wpurple_init(void) {
 	WORD wVersionRequested;
 	WSADATA wsaData;
============================================================
--- libpurple/win32/win32dep.h	9ba1b08f050adbe2485bca2b040c67c48b9fd982
+++ libpurple/win32/win32dep.h	84d8f2de37a7e519b7923167cb9afff73693126e
@@ -60,6 +60,9 @@ GIOChannel *wpurple_g_io_channel_win32_n
 char *wpurple_escape_dirsep(const char *filename); /* needs to be g_free'd */
 GIOChannel *wpurple_g_io_channel_win32_new_socket(int socket); /* Until we get the post-2.8 glib win32 giochannel implementation working, use the thread-based one */
 
+/* Simulate unix pipes by creating a pair of connected sockets */
+int wpurple_input_pipe(int pipefd[2]);
+
 /* Determine Purple paths */
 gchar *wpurple_get_special_folder(int folder_type); /* needs to be g_free'd */
 const char *wpurple_install_dir(void);
============================================================
--- libpurple/eventloop.c	d98b9ac615593ed9c4394b7a2e30d1192146c21a
+++ libpurple/eventloop.c	1caf2445b114fa66eed2876f6670cf0857dee088
@@ -91,6 +91,16 @@ purple_input_get_error(int fd, int *erro
 	}
 }
 
+int
+purple_input_pipe(int pipefd[2])
+{
+#ifdef _WIN32
+	return wpurple_input_pipe(pipefd);
+#else
+	return pipe(pipefd);
+#endif
+}
+
 void
 purple_eventloop_set_ui_ops(PurpleEventLoopUiOps *ops)
 {
============================================================
--- libpurple/eventloop.h	0eb5204960bacae171ba2fb9f5d9ce2f06d526f3
+++ libpurple/eventloop.h	77e014b87bce6f6794e0c0bad63a4991b7bc0a2b
@@ -240,7 +240,25 @@ purple_input_get_error(int fd, int *erro
 int
 purple_input_get_error(int fd, int *error);
 
+/**
+ * Creates a pipe - an unidirectional data channel that can be used for
+ * interprocess communication.
+ *
+ * File descriptors for both ends of pipe will be written into provided array.
+ * The first one (pipefd[0]) can be used for reading, the second one (pipefd[1])
+ * for writing.
+ *
+ * On Windows it's simulated by creating a pair of connected sockets, on other
+ * systems pipe() is used.
+ *
+ * @param pipefd Array used to return file descriptors for both ends of pipe.
+ *
+ * @return @c 0 on success, @c -1 on error.
+ */
+int
+purple_input_pipe(int pipefd[2]);
 
+
 /*@}*/
 
 
============================================================
--- libpurple/protocols/gg/win32-resolver.c	7df67382fa43098342cd3091b7a1e15a4954f509
+++ /dev/null	
@@ -1,322 +0,0 @@
-/**
- * @file win32-resolver.c
- *
- * purple
- *
- * 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
- */
-
-#include "win32-resolver.h"
-
-#include <errno.h>
-#include <resolver.h>
-#include "debug.h"
-
-#ifndef _WIN32
-#error "win32thread resolver is not supported on current platform"
-#endif
-
-/**
- * Deal with the fact that you can't select() on a win32 file fd.
- * This makes it practically impossible to tie into purple's event loop.
- *
- * -This is thanks to Tor Lillqvist.
- */
-static int ggp_resolver_win32thread_socket_pipe(int *fds)
-{
-	SOCKET temp, socket1 = -1, socket2 = -1;
-	struct sockaddr_in saddr;
-	int len;
-	u_long arg;
-	fd_set read_set, write_set;
-	struct timeval tv;
-
-	purple_debug_misc("gg", "ggp_resolver_win32thread_socket_pipe(&%d)\n",
-		*fds);
-
-	temp = socket(AF_INET, SOCK_STREAM, 0);
-
-	if (temp == INVALID_SOCKET) {
-		goto out0;
-	}
-
-	arg = 1;
-	if (ioctlsocket(temp, FIONBIO, &arg) == SOCKET_ERROR) {
-		goto out0;
-	}
-
-	memset(&saddr, 0, sizeof(saddr));
-	saddr.sin_family = AF_INET;
-	saddr.sin_port = 0;
-	saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
-	if (bind(temp, (struct sockaddr *)&saddr, sizeof (saddr))) {
-		goto out0;
-	}
-
-	if (listen(temp, 1) == SOCKET_ERROR) {
-		goto out0;
-	}
-
-	len = sizeof(saddr);
-	if (getsockname(temp, (struct sockaddr *)&saddr, &len)) {
-		goto out0;
-	}
-
-	socket1 = socket(AF_INET, SOCK_STREAM, 0);
-
-	if (socket1 == INVALID_SOCKET) {
-		goto out0;
-	}
-
-	arg = 1;
-	if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) {
-		goto out1;
-	}
-
-	if (connect(socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR ||
-			WSAGetLastError() != WSAEWOULDBLOCK) {
-		goto out1;
-	}
-
-	FD_ZERO(&read_set);
-	FD_SET(temp, &read_set);
-
-	tv.tv_sec = 0;
-	tv.tv_usec = 0;
-
-	if (select(0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) {
-		goto out1;
-	}
-
-	if (!FD_ISSET(temp, &read_set)) {
-		goto out1;
-	}
-
-	socket2 = accept(temp, (struct sockaddr *) &saddr, &len);
-	if (socket2 == INVALID_SOCKET) {
-		goto out1;
-	}
-
-	FD_ZERO(&write_set);
-	FD_SET(socket1, &write_set);
-
-	tv.tv_sec = 0;
-	tv.tv_usec = 0;
-
-	if (select(0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) {
-		goto out2;
-	}
-
-	if (!FD_ISSET(socket1, &write_set)) {
-		goto out2;
-	}
-
-	arg = 0;
-	if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) {
-		goto out2;
-	}
-
-	arg = 0;
-	if (ioctlsocket(socket2, FIONBIO, &arg) == SOCKET_ERROR) {
-		goto out2;
-	}
-
-	fds[0] = socket1;
-	fds[1] = socket2;
-
-	closesocket (temp);
-
-	return 0;
-
-out2:
-	closesocket (socket2);
-out1:
-	closesocket (socket1);
-out0:
-	closesocket (temp);
-	errno = EIO; /* XXX */
-
-	return -1;
-}
-
-struct ggp_resolver_win32thread_data {
-	char *hostname;
-	int fd;
-};
-
-/**
- * Copy-paste from gg_resolver_run().
- */
-static DWORD WINAPI ggp_resolver_win32thread_thread(LPVOID arg)
-{
-	struct ggp_resolver_win32thread_data *data = arg;
-	struct in_addr addr_ip[2], *addr_list;
-	int addr_count;
-
-	purple_debug_info("gg", "ggp_resolver_win32thread_thread() host: %s, "
-		"fd: %i called\n", data->hostname, data->fd);
-
-	if ((addr_ip[0].s_addr = inet_addr(data->hostname)) == INADDR_NONE) {
-		if (gg_gethostbyname_real(data->hostname, &addr_list,
-			&addr_count, 0) == -1) {
-			addr_list = addr_ip;
-			/* addr_ip[0] ju? zawiera INADDR_NONE */
-		}
-	} else {
-		addr_list = addr_ip;
-		addr_ip[1].s_addr = INADDR_NONE;
-		addr_count = 1;
-	}
-
-	purple_debug_misc("gg", "ggp_resolver_win32thread_thread() "
-		"count = %d\n", addr_count);
-
-	write(data->fd, addr_list, (addr_count + 1) * sizeof(struct in_addr));
-	close(data->fd);
-
-	free(data->hostname);
-	data->hostname = NULL;
-
-	free(data);
-
-	if (addr_list != addr_ip)
-		free(addr_list);
-
-	purple_debug_misc("gg", "ggp_resolver_win32thread_thread() done\n");
-
-	return 0;
-}
-
-
-int ggp_resolver_win32thread_start(int *fd, void **private_data,
-	const char *hostname)
-{
-	struct ggp_resolver_win32thread_data *data = NULL;
-	HANDLE h;
-	DWORD dwTId;
-	int pipes[2], new_errno;
-
-	purple_debug_info("gg", "ggp_resolver_win32thread_start(%p, %p, "
-		"\"%s\");\n", fd, private_data, hostname);
-
-	if (!private_data || !fd || !hostname) {
-		purple_debug_error("gg", "ggp_resolver_win32thread_start() "
-			"invalid arguments\n");
-		errno = EFAULT;
-		return -1;
-	}
-
-	purple_debug_misc("gg", "ggp_resolver_win32thread_start() creating "
-		"pipes...\n");
-
-	if (ggp_resolver_win32thread_socket_pipe(pipes) == -1) {
-		purple_debug_error("gg", "ggp_resolver_win32thread_start() "
-			"unable to create pipes (errno=%d, %s)\n",
-			errno, strerror(errno));
-		return -1;
-	}
-
-	if (!(data = malloc(sizeof(*data)))) {
-		purple_debug_error("gg", "ggp_resolver_win32thread_start() out "
-			"of memory\n");
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	data->hostname = NULL;
-
-	if (!(data->hostname = strdup(hostname))) {
-		purple_debug_error("gg", "ggp_resolver_win32thread_start() out "
-			"of memory\n");
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	data->fd = pipes[1];
-
-	purple_debug_misc("gg", "ggp_resolver_win32thread_start() creating "
-		"thread...\n");
-
-	h = CreateThread(NULL, 0, ggp_resolver_win32thread_thread, data, 0,
-		&dwTId);
-
-	if (h == NULL) {
-		purple_debug_error("gg", "ggp_resolver_win32thread_start() "
-			"unable to create thread\n");
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	*private_data = h;
-	*fd = pipes[0];
-
-	purple_debug_misc("gg", "ggp_resolver_win32thread_start() done\n");
-
-	return 0;
-
-cleanup:
-	if (data) {
-		free(data->hostname);
-		free(data);
-	}
-
-	close(pipes[0]);
-	close(pipes[1]);
-
-	errno = new_errno;
-
-	return -1;
-
-}
-
-void ggp_resolver_win32thread_cleanup(void **private_data, int force)
-{
-	struct ggp_resolver_win32thread_data *data;
-
-	purple_debug_info("gg", "ggp_resolver_win32thread_cleanup() force: %i "
-		"called\n", force);
-
-	if (private_data == NULL || *private_data == NULL) {
-		purple_debug_error("gg", "ggp_resolver_win32thread_cleanup() "
-			"private_data: NULL\n");
-		return;
-	}
-	return; /* XXX */
-
-	data = (struct ggp_resolver_win32thread_data*) *private_data;
-	purple_debug_misc("gg", "ggp_resolver_win32thread_cleanup() data: "
-		"%s called\n", data->hostname);
-	*private_data = NULL;
-
-	if (force) {
-		purple_debug_misc("gg", "ggp_resolver_win32thread_cleanup() "
-			"force called\n");
-		//pthread_cancel(data->thread);
-		//pthread_join(data->thread, NULL);
-	}
-
-	free(data->hostname);
-	data->hostname = NULL;
-
-	if (data->fd != -1) {
-		close(data->fd);
-		data->fd = -1;
-	}
-	purple_debug_info("gg", "ggp_resolver_win32thread_cleanup() done\n");
-	free(data);
-}
-
-/* vim: set ts=8 sts=0 sw=8 noet: */
============================================================
--- libpurple/protocols/gg/win32-resolver.h	3d15a404efa96c7cc0826559c6bb7519495f46be
+++ /dev/null	
@@ -1,46 +0,0 @@
-/**
- * @file win32-resolver.h
- *
- * purple
- *
- * 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_GG_WIN32_RESOLVER
-#define _PURPLE_GG_WIN32_RESOLVER
-
-/**
- * Starts hostname resolving in new win32 thread.
- *
- * @param fd           Pointer to variable, where pipe descriptor will be saved.
- * @param private_data Pointer to variable, where pointer to private data will
- *                     be saved.
- * @param hostname     Hostname to resolve.
- */
-int ggp_resolver_win32thread_start(int *fd, void **private_data,
-	const char *hostname);
-
-/**
- * Cleans up resources after hostname resolving.
- *
- * @param private_data Pointer to variable storing pointer to private data.
- * @param force        TRUE, if resources should be cleaned up even, if
- *                     resolving process didn't finished.
- */
-void ggp_resolver_win32thread_cleanup(void **private_data, int force);
-
-#endif /* _PURPLE_GG_WIN32_RESOLVER */
-
-/* vim: set ts=8 sts=0 sw=8 noet: */
============================================================
--- /dev/null	
+++ libpurple/protocols/gg/resolver-purple.c	a6386d0d59219b5f96b1af56568d4a0dac6f6083
@@ -0,0 +1,161 @@
+#include <internal.h>
+#include <debug.h>
+#include <dnsquery.h>
+
+#include <libgadu.h>
+#include "resolver-purple.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);
+
+typedef struct
+{
+	PurpleDnsQueryData *purpleQuery;
+	
+	/**
+	 * File descriptors:
+	 *  pipes[0] - for reading
+	 *  pipes[1] - for writing
+	 */
+	int pipes[2];
+} ggp_resolver_purple_data;
+
+
+extern void ggp_resolver_purple_setup(void)
+{
+	purple_debug_info("gg", "setting up custom resolver\n");
+	gg_global_set_custom_resolver(ggp_resolver_purple_start,
+		ggp_resolver_purple_cleanup);
+}
+
+void ggp_resolver_purple_cb(GSList *hosts, gpointer cbdata,
+	const char *error_message)
+{
+	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(%x, %x, \"%s\")\n",
+		(unsigned int)hosts, (unsigned int)cbdata, error_message);
+	
+	if (error_message)
+	{
+		purple_debug_error("gg", "ggp_resolver_purple_cb failed: %s\n",
+			error_message);
+	}
+	
+	all_count = g_slist_length(hosts);
+	g_assert(all_count % 2 == 0);
+	all_count /= 2;
+	addresses = malloc((all_count + 1) * sizeof(struct in_addr));
+	
+	ipv4_count = 0;
+	while (hosts && (hosts = g_slist_delete_link(hosts, hosts)))
+	{
+		const struct sockaddr *addr = hosts->data;
+		char dst[INET6_ADDRSTRLEN];
+		
+		if (addr->sa_family == AF_INET6)
+		{
+			inet_ntop(addr->sa_family,
+				&((struct sockaddr_in6 *) addr)->sin6_addr,
+				dst, sizeof(dst));
+			purple_debug_misc("gg", "ggp_resolver_purple_cb "
+				"ipv6 (ignore): %s\n", dst);
+		}
+		else if (addr->sa_family == AF_INET)
+		{
+			const struct in_addr addr_ipv4 =
+				((struct sockaddr_in *) addr)->sin_addr;
+			inet_ntop(addr->sa_family, &addr_ipv4,
+				dst, sizeof(dst));
+			purple_debug_misc("gg", "ggp_resolver_purple_cb "
+				"ipv4: %s\n", dst);
+			
+			g_assert(ipv4_count < all_count);
+			addresses[ipv4_count++] = addr_ipv4;
+		}
+		else
+		{
+			purple_debug_warning("gg", "ggp_resolver_purple_cb "
+				"unexpected sa_family: %d\n", addr->sa_family);
+		}
+		
+		g_free(hosts->data);
+		hosts = g_slist_delete_link(hosts, hosts);
+	}
+	
+	addresses[ipv4_count].s_addr = INADDR_NONE;
+	
+	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");
+	}
+	free(addresses);
+}
+
+int ggp_resolver_purple_start(int *fd, void **private_data,
+	const char *hostname)
+{
+	ggp_resolver_purple_data *data;
+	purple_debug_misc("gg", "ggp_resolver_purple_start(%x, %x, \"%s\")\n",
+		(unsigned int)fd, (unsigned int)private_data, hostname);
+	
+	data = malloc(sizeof(ggp_resolver_purple_data));
+	*private_data = (void*)data;
+	data->purpleQuery = NULL;
+	data->pipes[0] = 0;
+	data->pipes[1] = 0;
+	
+	if (purple_input_pipe(data->pipes) != 0)
+	{
+		purple_debug_error("gg", "ggp_resolver_purple_start: "
+			"unable to create pipe\n");
+		ggp_resolver_purple_cleanup(private_data, 0);
+		return -1;
+	}
+	
+	*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);
+
+	if (!data->purpleQuery)
+	{
+		purple_debug_error("gg", "ggp_resolver_purple_start: "
+			"unable to call purple_dnsquery_a\n");
+		ggp_resolver_purple_cleanup(private_data, 0);
+		return -1;
+	}
+	
+	return 0;
+}
+
+void ggp_resolver_purple_cleanup(void **private_data, int force)
+{
+	ggp_resolver_purple_data *data =
+		(ggp_resolver_purple_data*)(*private_data);
+	
+	purple_debug_misc("gg", "ggp_resolver_purple_cleanup(%x, %d)\n",
+		(unsigned int)private_data, force);
+	
+	if (!data)
+		return;
+	*private_data = NULL;
+	
+	if (data->pipes[0])
+		close(data->pipes[0]);
+	if (data->pipes[1])
+		close(data->pipes[1]);
+	
+	free(data);
+}
============================================================
--- /dev/null	
+++ libpurple/protocols/gg/resolver-purple.h	e281062cd6f356435dac622a2558fc4db80d2b70
@@ -0,0 +1,9 @@
+#ifndef _PURPLE_GG_RESOLVER_PURPLE
+#define _PURPLE_GG_RESOLVER_PURPLE
+
+/**
+ * Registers custom resolver for libgadu, that uses libpurple for DNS queries.
+ */
+void ggp_resolver_purple_setup(void);
+
+#endif /* _PURPLE_GG_RESOLVER_PURPLE */


More information about the Commits mailing list