libpurple/protocols/gg/lib/resolver.c

changeset 38067
3c2c551feeb9
parent 38066
2e94b6fa06a0
child 38068
fd6805c0df15
--- a/libpurple/protocols/gg/lib/resolver.c	Wed Sep 28 09:32:19 2016 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1132 +0,0 @@
-/*
- *  (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl>
- *                          Robert J. Woźny <speedy@ziew.org>
- *                          Arkadiusz Miśkiewicz <arekm@pld-linux.org>
- *                          Tomasz Chiliński <chilek@chilan.com>
- *                          Adam Wysocki <gophi@ekg.chmurka.net>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU Lesser General Public License Version
- *  2.1 as published by the Free Software Foundation.
- *
- *  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 Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
- *  USA.
- */
-
-/**
- * \file resolver.c
- *
- * \brief Funkcje rozwiązywania nazw
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "strman.h"
-#include "network.h"
-#include "config.h"
-#include "libgadu.h"
-#include "resolver.h"
-#include "session.h"
-
-#ifdef GG_CONFIG_HAVE_FORK
-#include <sys/wait.h>
-#include <signal.h>
-#endif
-
-/** Sposób rozwiązywania nazw serwerów */
-static gg_resolver_t gg_global_resolver_type = GG_RESOLVER_DEFAULT;
-
-/** Funkcja rozpoczynająca rozwiązywanie nazwy */
-static int (*gg_global_resolver_start)(int *fd, void **private_data, const char *hostname);
-
-/** Funkcja zwalniająca zasoby po rozwiązaniu nazwy */
-static void (*gg_global_resolver_cleanup)(void **private_data, int force);
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-
-#include <pthread.h>
-
-/**
- * \internal Funkcja pomocnicza zwalniająca zasoby po rozwiązywaniu nazwy
- * w wątku.
- *
- * \note Funkcja nie powinna być statyczna, ponieważ zostanie potraktowana
- * jako inline i kompilator może "zoptymalizować" jej wywołanie w funkcji
- * pthread_cleanup_pop().
- *
- * \param data Wskaźnik na wskaźnik bufora zaalokowanego w wątku
- */
-void gg_resolver_cleaner(void *data)
-{
-	void **buf_ptr = (void **) data;
-
-	if (buf_ptr != NULL) {
-		free(*buf_ptr);
-		*buf_ptr = NULL;
-	}
-}
-
-#endif /* GG_CONFIG_HAVE_PTHREAD */
-
-/**
- * \internal Odpowiednik \c gethostbyname zapewniający współbieżność.
- *
- * Jeśli dany system dostarcza \c gethostbyname_r, używa się tej wersji, jeśli
- * nie, to zwykłej \c gethostbyname. Wynikiem jest tablica adresów zakończona
- * wartością INADDR_NONE, którą należy zwolnić po użyciu.
- *
- * \param hostname Nazwa serwera
- * \param result Wskaźnik na wskaźnik z tablicą adresów zakończoną INADDR_NONE
- * \param count Wskaźnik na zmienną, do ktorej zapisze się liczbę wyników
- * \param pthread Flaga blokowania unicestwiania wątku podczas alokacji pamięci
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-int gg_gethostbyname_real(const char *hostname, struct in_addr **result, unsigned int *count, int pthread)
-{
-#ifdef GG_CONFIG_HAVE_GETHOSTBYNAME_R
-	char *buf = NULL;
-	char *new_buf = NULL;
-	struct hostent he;
-	struct hostent *he_ptr = NULL;
-	size_t buf_len = 1024;
-	int res = -1;
-	int h_errnop;
-	int ret = 0;
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	int old_state;
-#endif
-
-	if (result == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	pthread_cleanup_push(gg_resolver_cleaner, &buf);
-
-	if (pthread)
-		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
-#endif
-
-	buf = malloc(buf_len);
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	if (pthread)
-		pthread_setcancelstate(old_state, NULL);
-#endif
-
-	if (buf != NULL) {
-		while (1) {
-#ifndef sun
-			ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop);
-			if (ret != ERANGE)
-				break;
-#else
-			he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop);
-			if (he_ptr != NULL || errno != ERANGE)
-				break;
-#endif
-
-			buf_len *= 2;
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-			if (pthread)
-				pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
-#endif
-
-			new_buf = realloc(buf, buf_len);
-
-			if (new_buf != NULL)
-				buf = new_buf;
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-			if (pthread)
-				pthread_setcancelstate(old_state, NULL);
-#endif
-
-			if (new_buf == NULL) {
-				ret = ENOMEM;
-				break;
-			}
-		}
-
-		if (ret == 0 && he_ptr != NULL && he_ptr->h_addr_list[0] != NULL) {
-			int i;
-
-			/* Policz liczbę adresów */
-
-			for (i = 0; he_ptr->h_addr_list[i] != NULL; i++);
-
-			/* Zaalokuj */
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-			if (pthread)
-				pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
-#endif
-
-			*result = malloc((i + 1) * sizeof(struct in_addr));
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-			if (pthread)
-				pthread_setcancelstate(old_state, NULL);
-#endif
-
-			if (*result != NULL) {
-				/* Kopiuj */
-
-				for (i = 0; he_ptr->h_addr_list[i] != NULL; i++)
-					memcpy(&((*result)[i]), he_ptr->h_addr_list[i], sizeof(struct in_addr));
-
-				(*result)[i].s_addr = INADDR_NONE;
-
-				*count = i;
-
-				res = 0;
-			} else
-				res = -1;
-		}
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-		if (pthread)
-			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
-#endif
-
-		free(buf);
-		buf = NULL;
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-		if (pthread)
-			pthread_setcancelstate(old_state, NULL);
-#endif
-	}
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	pthread_cleanup_pop(0);
-#endif
-
-	return res;
-#else /* GG_CONFIG_HAVE_GETHOSTBYNAME_R */
-	struct hostent *he;
-	int i;
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	int old_state;
-#endif
-
-	if (result == NULL || count == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	he = gethostbyname(hostname);
-
-	if (he == NULL || he->h_addr_list[0] == NULL)
-		return -1;
-
-	/* Policz liczbę adresów */
-
-	for (i = 0; he->h_addr_list[i] != NULL; i++);
-
-	/* Zaalokuj */
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	if (pthread)
-		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
-#endif
-
-	*result = malloc((i + 1) * sizeof(struct in_addr));
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	if (pthread)
-		pthread_setcancelstate(old_state, NULL);
-#endif
-
-	if (*result == NULL)
-		return -1;
-
-	/* Kopiuj */
-
-	for (i = 0; he->h_addr_list[i] != NULL; i++)
-		memcpy(&((*result)[i]), he->h_addr_list[i], sizeof(struct in_addr));
-
-	(*result)[i].s_addr = INADDR_NONE;
-
-	*count = i;
-
-	return 0;
-#endif /* GG_CONFIG_HAVE_GETHOSTBYNAME_R */
-}
-
-/**
- * \internal Rozwiązuje nazwę i zapisuje wynik do podanego gniazda.
- *
- * \note Użycie logowania w tej funkcji może mieć negatywny wpływ na
- * aplikacje jednowątkowe korzystające.
- *
- * \param fd Deskryptor gniazda
- * \param hostname Nazwa serwera
- * \param pthread Flaga blokowania unicestwiania wątku podczas alokacji pamięci
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-static int gg_resolver_run(int fd, const char *hostname, int pthread)
-{
-	struct in_addr addr_ip[2], *addr_list = NULL;
-	unsigned int addr_count;
-	int res = 0;
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	int old_state;
-#endif
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	pthread_cleanup_push(gg_resolver_cleaner, &addr_list);
-#endif
-
-	if ((addr_ip[0].s_addr = inet_addr(hostname)) == INADDR_NONE) {
-		if (gg_gethostbyname_real(hostname, &addr_list, &addr_count, pthread) == -1) {
-#ifdef GG_CONFIG_HAVE_PTHREAD
-			if (pthread)
-				pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
-#endif
-
-			free(addr_list);
-			addr_list = NULL;
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-			if (pthread)
-				pthread_setcancelstate(old_state, NULL);
-#endif
-
-			addr_count = 0;
-			/* addr_ip[0] już zawiera INADDR_NONE */
-		}
-	} else {
-		addr_ip[1].s_addr = INADDR_NONE;
-		addr_count = 1;
-	}
-
-	if (send(fd, addr_list != NULL ? addr_list : addr_ip,
-		(addr_count + 1) * sizeof(struct in_addr), 0) !=
-		(int)((addr_count + 1) * sizeof(struct in_addr)))
-	{
-		res = -1;
-	}
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	if (pthread)
-		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
-#endif
-
-	free(addr_list);
-	addr_list = NULL;
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-	if (pthread)
-		pthread_setcancelstate(old_state, NULL);
-
-	pthread_cleanup_pop(0);
-#endif
-
-	return res;
-}
-
-/**
- * \internal Odpowiednik \c gethostbyname zapewniający współbieżność.
- *
- * Jeśli dany system dostarcza \c gethostbyname_r, używa się tej wersji, jeśli
- * nie, to zwykłej \c gethostbyname. Funkcja służy do zachowania zgodności
- * ABI i służy do pobierania tylko pierwszego adresu -- pozostałe mogą
- * zostać zignorowane przez aplikację.
- *
- * \param hostname Nazwa serwera
- *
- * \return Zaalokowana struktura \c in_addr lub NULL w przypadku błędu.
- */
-struct in_addr *gg_gethostbyname(const char *hostname)
-{
-	struct in_addr *result;
-	unsigned int count;
-
-	if (gg_gethostbyname_real(hostname, &result, &count, 0) == -1)
-		return NULL;
-
-	return result;
-}
-
-#ifdef GG_CONFIG_HAVE_FORK
-
-/**
- * \internal Struktura przekazywana do wątku rozwiązującego nazwę.
- */
-struct gg_resolver_fork_data {
-	int pid;		/*< Identyfikator procesu */
-};
-
-/**
- * \internal Rozwiązuje nazwę serwera w osobnym procesie.
- *
- * Połączenia asynchroniczne nie mogą blokować procesu w trakcie rozwiązywania
- * nazwy serwera. W tym celu tworzona jest para gniazd, nowy proces i dopiero
- * w nim przeprowadzane jest rozwiązywanie nazwy. Deskryptor gniazda do odczytu
- * zapisuje się w strukturze sieci i czeka na dane w postaci struktury
- * \c in_addr. Jeśli nie znaleziono nazwy, zwracana jest \c INADDR_NONE.
- *
- * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda
- * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik
- *                  do numeru procesu potomnego rozwiązującego nazwę
- * \param hostname Nazwa serwera do rozwiązania
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-static int gg_resolver_fork_start(int *fd, void **priv_data, const char *hostname)
-{
-	struct gg_resolver_fork_data *data = NULL;
-	int pipes[2], new_errno;
-
-	gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_fork_start(%p, %p, \"%s\");\n", fd, priv_data, hostname);
-
-	if (fd == NULL || priv_data == NULL || hostname == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() invalid arguments\n");
-		errno = EFAULT;
-		return -1;
-	}
-
-	data = malloc(sizeof(struct gg_resolver_fork_data));
-
-	if (data == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() out of memory for resolver data\n");
-		return -1;
-	}
-
-	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() unable "
-			"to create pipes (errno=%d, %s)\n",
-			errno, strerror(errno));
-		free(data);
-		return -1;
-	}
-
-	data->pid = fork();
-
-	if (data->pid == -1) {
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	if (data->pid == 0) {
-		int status;
-
-		close(pipes[0]);
-
-		status = (gg_resolver_run(pipes[1], hostname, 0) == -1) ? 1 : 0;
-
-#ifdef HAVE__EXIT
-		_exit(status);
-#else
-		exit(status);
-#endif
-	}
-
-	close(pipes[1]);
-
-	gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() %p\n", data);
-
-	*fd = pipes[0];
-	*priv_data = data;
-
-	return 0;
-
-cleanup:
-	free(data);
-	close(pipes[0]);
-	close(pipes[1]);
-
-	errno = new_errno;
-
-	return -1;
-}
-
-/**
- * \internal Usuwanie zasobów po procesie rozwiązywaniu nazwy.
- *
- * Funkcja wywoływana po zakończeniu rozwiązanywania nazwy lub przy zwalnianiu
- * zasobów sesji podczas rozwiązywania nazwy.
- *
- * \param priv_data Wskaźnik na zmienną przechowującą wskaźnik do prywatnych
- *                  danych
- * \param force Flaga usuwania zasobów przed zakończeniem działania
- */
-static void gg_resolver_fork_cleanup(void **priv_data, int force)
-{
-	struct gg_resolver_fork_data *data;
-
-	if (priv_data == NULL || *priv_data == NULL)
-		return;
-
-	data = (struct gg_resolver_fork_data*) *priv_data;
-	*priv_data = NULL;
-
-	if (force)
-		kill(data->pid, SIGKILL);
-
-	/* we don't care about child's exit status, just want to clean it up */
-	(void)waitpid(data->pid, NULL, WNOHANG);
-
-	free(data);
-}
-
-#endif /* GG_CONFIG_HAVE_FORK */
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-
-/**
- * \internal Struktura przekazywana do wątku rozwiązującego nazwę.
- */
-struct gg_resolver_pthread_data {
-	pthread_t thread;	/*< Identyfikator wątku */
-	char *hostname;		/*< Nazwa serwera */
-	int wfd;		/*< Deskryptor do zapisu */
-};
-
-/**
- * \internal Usuwanie zasobów po wątku rozwiązywaniu nazwy.
- *
- * Funkcja wywoływana po zakończeniu rozwiązanywania nazwy lub przy zwalnianiu
- * zasobów sesji podczas rozwiązywania nazwy.
- *
- * \param priv_data Wskaźnik na zmienną przechowującą wskaźnik do prywatnych
- *                  danych
- * \param force Flaga usuwania zasobów przed zakończeniem działania
- */
-static void gg_resolver_pthread_cleanup(void **priv_data, int force)
-{
-	struct gg_resolver_pthread_data *data;
-
-	if (priv_data == NULL || *priv_data == NULL)
-		return;
-
-	data = (struct gg_resolver_pthread_data *) *priv_data;
-	*priv_data = NULL;
-
-	if (force)
-		pthread_cancel(data->thread);
-
-	pthread_join(data->thread, NULL);
-
-	close(data->wfd);
-	free(data->hostname);
-	free(data);
-}
-
-/**
- * \internal Wątek rozwiązujący nazwę.
- *
- * \param arg Wskaźnik na strukturę \c gg_resolver_pthread_data
- */
-static void *gg_resolver_pthread_thread(void *arg)
-{
-	struct gg_resolver_pthread_data *data = arg;
-
-	if (gg_resolver_run(data->wfd, data->hostname, 1) == -1)
-		pthread_exit((void*) -1);
-	else
-		pthread_exit(NULL);
-
-	return NULL;	/* żeby kompilator nie marudził */
-}
-
-/**
- * \internal Rozwiązuje nazwę serwera w osobnym wątku.
- *
- * Funkcja działa analogicznie do \c gg_resolver_fork_start(), z tą różnicą,
- * że działa na wątkach, nie procesach. Jest dostępna wyłącznie gdy podczas
- * kompilacji włączono odpowiednią opcję.
- *
- * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda
- * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik
- *                  do prywatnych danych wątku rozwiązującego nazwę
- * \param hostname Nazwa serwera do rozwiązania
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-static int gg_resolver_pthread_start(int *fd, void **priv_data, const char *hostname)
-{
-	struct gg_resolver_pthread_data *data = NULL;
-	int pipes[2], new_errno;
-
-	gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_pthread_start(%p, %p, \"%s\");\n", fd, priv_data, hostname);
-
-	if (fd == NULL || priv_data == NULL || hostname == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() invalid arguments\n");
-		errno = EFAULT;
-		return -1;
-	}
-
-	data = malloc(sizeof(struct gg_resolver_pthread_data));
-
-	if (data == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory for resolver data\n");
-		return -1;
-	}
-
-	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable "
-			"to create pipes (errno=%d, %s)\n",
-			errno, strerror(errno));
-		free(data);
-		return -1;
-	}
-
-	data->hostname = strdup(hostname);
-
-	if (data->hostname == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory\n");
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	data->wfd = pipes[1];
-
-	if (pthread_create(&data->thread, NULL, gg_resolver_pthread_thread, data)) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable to create thread\n");
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() %p\n", data);
-
-	*fd = pipes[0];
-	*priv_data = data;
-
-	return 0;
-
-cleanup:
-	if (data != NULL)
-		free(data->hostname);
-
-	free(data);
-
-	close(pipes[0]);
-	close(pipes[1]);
-
-	errno = new_errno;
-
-	return -1;
-}
-
-#endif /* GG_CONFIG_HAVE_PTHREAD */
-
-#ifdef _WIN32
-
-/**
- * \internal Struktura przekazywana do wątku rozwiązującego nazwę.
- */
-struct gg_resolver_win32_data {
-	HANDLE thread;		/*< Uchwyt wątku */
-	CRITICAL_SECTION mutex;	/*< Semafor wątku */
-	char *hostname;		/*< Nazwa serwera */
-	int wfd;		/*< Deskryptor do zapisu */
-	int orphan;		/*< Wątek powinien sam po sobie posprzątać */
-	int finished;		/*< Wątek już skończył pracę */
-};
-
-/**
- * \internal Wątek rozwiązujący nazwę.
- *
- * \param arg Wskaźnik na strukturę \c gg_resolver_win32_data
- */
-static DWORD WINAPI gg_resolver_win32_thread(void *arg)
-{
-	struct gg_resolver_win32_data *data = arg;
-	int result, is_orphan;
-
-	result = gg_resolver_run(data->wfd, data->hostname, 0);
-
-	EnterCriticalSection(&data->mutex);
-	is_orphan = data->orphan;
-	data->finished = 1;
-	LeaveCriticalSection(&data->mutex);
-
-	if (is_orphan) {
-		CloseHandle(data->thread);
-		DeleteCriticalSection(&data->mutex);
-		close(data->wfd);
-		free(data->hostname);
-		free(data);
-	}
-
-	ExitThread(result);
-	return 0; /* żeby kompilator nie marudził */
-}
-
-/**
- * \internal Rozwiązuje nazwę serwera w osobnym wątku.
- *
- * Funkcja działa analogicznie do \c gg_resolver_pthread_start(), z tą różnicą,
- * że działa na wątkach Win32. Jest dostępna wyłącznie przy kompilacji dla
- * systemu Windows.
- *
- * \param fd Wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda
- * \param priv_data Wskaźnik na zmienną, gdzie zostanie umieszczony wskaźnik
- *                  do prywatnych danych wątku rozwiązującego nazwę
- * \param hostname Nazwa serwera do rozwiązania
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-static int gg_resolver_win32_start(int *fd, void **priv_data, const char *hostname)
-{
-	struct gg_resolver_win32_data *data = NULL;
-	int pipes[2], new_errno;
-	CRITICAL_SECTION *mutex = NULL;
-
-	gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_win32_start(%p, %p, \"%s\");\n", fd, priv_data, hostname);
-
-	if (fd == NULL || priv_data == NULL || hostname == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() invalid arguments\n");
-		errno = EFAULT;
-		return -1;
-	}
-
-	data = malloc(sizeof(struct gg_resolver_win32_data));
-
-	if (data == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() out of memory for resolver data\n");
-		return -1;
-	}
-
-	data->orphan = 0;
-	data->finished = 0;
-
-	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, pipes) == -1) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to "
-			"create pipes (errno=%d, %s)\n",
-			errno, strerror(errno));
-		free(data);
-		return -1;
-	}
-
-	data->hostname = strdup(hostname);
-
-	if (data->hostname == NULL) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() out of memory\n");
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	data->wfd = pipes[1];
-
-	mutex = &data->mutex;
-	InitializeCriticalSection(mutex);
-
-	data->thread = CreateThread(NULL, 0, gg_resolver_win32_thread, data, 0, NULL);
-	if (!data->thread) {
-		gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() unable to create thread\n");
-		new_errno = errno;
-		goto cleanup;
-	}
-
-	gg_debug(GG_DEBUG_MISC, "// gg_resolver_win32_start() %p\n", data);
-
-	*fd = pipes[0];
-	*priv_data = data;
-
-	return 0;
-
-cleanup:
-	if (data) {
-		free(data->hostname);
-		free(data);
-	}
-
-	close(pipes[0]);
-	close(pipes[1]);
-
-	if (mutex)
-		DeleteCriticalSection(mutex);
-
-	errno = new_errno;
-
-	return -1;
-}
-
-/**
- * \internal Usuwanie zasobów po wątku rozwiązywaniu nazwy.
- *
- * Funkcja wywoływana po zakończeniu rozwiązanywania nazwy lub przy zwalnianiu
- * zasobów sesji podczas rozwiązywania nazwy.
- *
- * \param priv_data Wskaźnik na zmienną przechowującą wskaźnik do prywatnych
- *                  danych
- * \param force Flaga usuwania zasobów przed zakończeniem działania
- */
-static void gg_resolver_win32_cleanup(void **priv_data, int force)
-{
-	struct gg_resolver_win32_data *data;
-
-	if (priv_data == NULL || *priv_data == NULL)
-		return;
-
-	data = (struct gg_resolver_win32_data *) *priv_data;
-	*priv_data = NULL;
-
-	if (WaitForSingleObject(data->thread, 0) == WAIT_TIMEOUT) {
-		int finished;
-		/* We cannot call TerminateThread here - it doesn't
-		 * release critical section locks (see MSDN docs).
-		 * if (force) TerminateThread(data->thread, 0);
-		 */
-		EnterCriticalSection(&data->mutex);
-		finished = data->finished;
-		if (!finished)
-			data->orphan = 1;
-		LeaveCriticalSection(&data->mutex);
-		if (!finished)
-			return;
-	}
-
-	CloseHandle(data->thread);
-	DeleteCriticalSection(&data->mutex);
-	close(data->wfd);
-	free(data->hostname);
-	free(data);
-}
-
-#endif /* _WIN32 */
-
-/**
- * Ustawia sposób rozwiązywania nazw w sesji.
- *
- * \param gs Struktura sesji
- * \param type Sposób rozwiązywania nazw (patrz \ref build-resolver)
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type)
-{
-	GG_SESSION_CHECK(gs, -1);
-
-	if (type == GG_RESOLVER_DEFAULT) {
-		if (gg_global_resolver_type != GG_RESOLVER_DEFAULT) {
-			gs->resolver_type = gg_global_resolver_type;
-			gs->resolver_start = gg_global_resolver_start;
-			gs->resolver_cleanup = gg_global_resolver_cleanup;
-			return 0;
-		}
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-		type = GG_RESOLVER_PTHREAD;
-#elif defined(_WIN32)
-		type = GG_RESOLVER_WIN32;
-#elif defined(GG_CONFIG_HAVE_FORK)
-		type = GG_RESOLVER_FORK;
-#endif
-	}
-
-	switch (type) {
-#ifdef GG_CONFIG_HAVE_FORK
-		case GG_RESOLVER_FORK:
-			gs->resolver_type = type;
-			gs->resolver_start = gg_resolver_fork_start;
-			gs->resolver_cleanup = gg_resolver_fork_cleanup;
-			return 0;
-#endif
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-		case GG_RESOLVER_PTHREAD:
-			gs->resolver_type = type;
-			gs->resolver_start = gg_resolver_pthread_start;
-			gs->resolver_cleanup = gg_resolver_pthread_cleanup;
-			return 0;
-#endif
-
-#ifdef _WIN32
-		case GG_RESOLVER_WIN32:
-			gs->resolver_type = type;
-			gs->resolver_start = gg_resolver_win32_start;
-			gs->resolver_cleanup = gg_resolver_win32_cleanup;
-			return 0;
-#endif
-
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-}
-
-/**
- * Zwraca sposób rozwiązywania nazw w sesji.
- *
- * \param gs Struktura sesji
- *
- * \return Sposób rozwiązywania nazw
- */
-gg_resolver_t gg_session_get_resolver(struct gg_session *gs)
-{
-	GG_SESSION_CHECK(gs, (gg_resolver_t) -1);
-
-	return gs->resolver_type;
-}
-
-/**
- * Ustawia własny sposób rozwiązywania nazw w sesji.
- *
- * \param gs Struktura sesji
- * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy
- * \param resolver_cleanup Funkcja zwalniająca zasoby
- *
- * Parametry funkcji rozpoczynającej rozwiązywanie nazwy wyglądają następująco:
- *  - \c "int *fd" &mdash; wskaźnik na zmienną, gdzie zostanie umieszczony deskryptor gniazda
- *  - \c "void **priv_data" &mdash; wskaźnik na zmienną, gdzie można umieścić
- *    wskaźnik do prywatnych danych na potrzeby rozwiązywania nazwy
- *  - \c "const char *name" &mdash; nazwa serwera do rozwiązania
- *
- * Parametry funkcji zwalniającej zasoby wyglądają następująco:
- *  - \c "void **priv_data" &mdash; wskaźnik na zmienną przechowującą wskaźnik
- *    do prywatnych danych, należy go ustawić na \c NULL po zakończeniu
- *  - \c "int force" &mdash; flaga mówiąca o tym, że zasoby są zwalniane przed
- *    zakończeniem rozwiązywania nazwy, np. z powodu zamknięcia sesji.
- *
- * Własny kod rozwiązywania nazwy powinien stworzyć potok, parę gniazd lub
- * inny deskryptor pozwalający na co najmniej odbiór danych i przekazać go
- * w parametrze \c fd. Na platformie Windows możliwe jest przekazanie jedynie
- * deskryptora gniazda. Po zakończeniu rozwiązywania nazwy powinien wysłać
- * otrzymany adres IP w postaci sieciowej (big-endian) do deskryptora. Jeśli
- * rozwiązywanie nazwy się nie powiedzie, należy wysłać \c INADDR_NONE.
- * Następnie zostanie wywołana funkcja zwalniająca zasoby z parametrem
- * \c force równym \c 0. Gdyby sesja została zakończona przed rozwiązaniem
- * nazwy, np. za pomocą funkcji \c gg_logoff(), funkcja zwalniająca zasoby
- * zostanie wywołana z parametrem \c force równym \c 1.
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-int gg_session_set_custom_resolver(struct gg_session *gs,
-	int (*resolver_start)(int*, void**, const char*),
-	void (*resolver_cleanup)(void**, int))
-{
-	GG_SESSION_CHECK(gs, -1);
-
-	if (resolver_start == NULL || resolver_cleanup == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	gs->resolver_type = GG_RESOLVER_CUSTOM;
-	gs->resolver_start = resolver_start;
-	gs->resolver_cleanup = resolver_cleanup;
-
-	return 0;
-}
-
-/**
- * Ustawia sposób rozwiązywania nazw połączenia HTTP.
- *
- * \param gh Struktura połączenia
- * \param type Sposób rozwiązywania nazw (patrz \ref build-resolver)
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-int gg_http_set_resolver(struct gg_http *gh, gg_resolver_t type)
-{
-	if (gh == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	if (type == GG_RESOLVER_DEFAULT) {
-		if (gg_global_resolver_type != GG_RESOLVER_DEFAULT) {
-			gh->resolver_type = gg_global_resolver_type;
-			gh->resolver_start = gg_global_resolver_start;
-			gh->resolver_cleanup = gg_global_resolver_cleanup;
-			return 0;
-		}
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-		type = GG_RESOLVER_PTHREAD;
-#elif defined(_WIN32)
-		type = GG_RESOLVER_WIN32;
-#elif defined(GG_CONFIG_HAVE_FORK)
-		type = GG_RESOLVER_FORK;
-#endif
-	}
-
-	switch (type) {
-#ifdef GG_CONFIG_HAVE_FORK
-		case GG_RESOLVER_FORK:
-			gh->resolver_type = type;
-			gh->resolver_start = gg_resolver_fork_start;
-			gh->resolver_cleanup = gg_resolver_fork_cleanup;
-			return 0;
-#endif
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-		case GG_RESOLVER_PTHREAD:
-			gh->resolver_type = type;
-			gh->resolver_start = gg_resolver_pthread_start;
-			gh->resolver_cleanup = gg_resolver_pthread_cleanup;
-			return 0;
-#endif
-
-#ifdef _WIN32
-		case GG_RESOLVER_WIN32:
-			gh->resolver_type = type;
-			gh->resolver_start = gg_resolver_win32_start;
-			gh->resolver_cleanup = gg_resolver_win32_cleanup;
-			return 0;
-#endif
-
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-}
-
-/**
- * Zwraca sposób rozwiązywania nazw połączenia HTTP.
- *
- * \param gh Struktura połączenia
- *
- * \return Sposób rozwiązywania nazw
- */
-gg_resolver_t gg_http_get_resolver(struct gg_http *gh)
-{
-	if (gh == NULL) {
-		errno = EINVAL;
-		return GG_RESOLVER_INVALID;
-	}
-
-	return gh->resolver_type;
-}
-
-/**
- * Ustawia własny sposób rozwiązywania nazw połączenia HTTP.
- *
- * \param gh Struktura sesji
- * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy
- * \param resolver_cleanup Funkcja zwalniająca zasoby
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-int gg_http_set_custom_resolver(struct gg_http *gh,
-	int (*resolver_start)(int*, void**, const char*),
-	void (*resolver_cleanup)(void**, int))
-{
-	if (gh == NULL || resolver_start == NULL || resolver_cleanup == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	gh->resolver_type = GG_RESOLVER_CUSTOM;
-	gh->resolver_start = resolver_start;
-	gh->resolver_cleanup = resolver_cleanup;
-
-	return 0;
-}
-
-/**
- * Ustawia sposób rozwiązywania nazw globalnie dla biblioteki.
- *
- * \param type Sposób rozwiązywania nazw (patrz \ref build-resolver)
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-int gg_global_set_resolver(gg_resolver_t type)
-{
-	switch (type) {
-		case GG_RESOLVER_DEFAULT:
-			gg_global_resolver_type = type;
-			gg_global_resolver_start = NULL;
-			gg_global_resolver_cleanup = NULL;
-			return 0;
-
-#ifdef GG_CONFIG_HAVE_FORK
-		case GG_RESOLVER_FORK:
-			gg_global_resolver_type = type;
-			gg_global_resolver_start = gg_resolver_fork_start;
-			gg_global_resolver_cleanup = gg_resolver_fork_cleanup;
-			return 0;
-#endif
-
-#ifdef GG_CONFIG_HAVE_PTHREAD
-		case GG_RESOLVER_PTHREAD:
-			gg_global_resolver_type = type;
-			gg_global_resolver_start = gg_resolver_pthread_start;
-			gg_global_resolver_cleanup = gg_resolver_pthread_cleanup;
-			return 0;
-#endif
-
-#ifdef _WIN32
-		case GG_RESOLVER_WIN32:
-			gg_global_resolver_type = type;
-			gg_global_resolver_start = gg_resolver_win32_start;
-			gg_global_resolver_cleanup = gg_resolver_win32_cleanup;
-			return 0;
-#endif
-
-		default:
-			errno = EINVAL;
-			return -1;
-	}
-}
-
-/**
- * Zwraca sposób rozwiązywania nazw globalnie dla biblioteki.
- *
- * \return Sposób rozwiązywania nazw
- */
-gg_resolver_t gg_global_get_resolver(void)
-{
-	return gg_global_resolver_type;
-}
-
-/**
- * Ustawia własny sposób rozwiązywania nazw globalnie dla biblioteki.
- *
- * \param resolver_start Funkcja rozpoczynająca rozwiązywanie nazwy
- * \param resolver_cleanup Funkcja zwalniająca zasoby
- *
- * Patrz \ref gg_session_set_custom_resolver.
- *
- * \return 0 jeśli się powiodło, -1 w przypadku błędu
- */
-int gg_global_set_custom_resolver(
-	int (*resolver_start)(int*, void**, const char*),
-	void (*resolver_cleanup)(void**, int))
-{
-	if (resolver_start == NULL || resolver_cleanup == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-
-	gg_global_resolver_type = GG_RESOLVER_CUSTOM;
-	gg_global_resolver_start = resolver_start;
-	gg_global_resolver_cleanup = resolver_cleanup;
-
-	return 0;
-}
-
-/**
- * Odczytuje dane z procesu/wątku rozwiązywania nazw.
- *
- * \param fd Deskryptor
- * \param buf Wskaźnik na bufor
- * \param len Długość bufora
- *
- * \return Patrz recv() i read().
- */
-int gg_resolver_recv(int fd, void *buf, size_t len)
-{
-#ifndef _WIN32
-	return read(fd, buf, len);
-#else
-	return recv(fd, buf, len, 0);
-#endif
-}

mercurial