diff libpurple/protocols/gg/lib/http.c @ 29938:6359fde67f4c

Update our internal libgadu to 1.9.0-rc2. This does not yet build on Windows. Refs #10542. The Windows build errors are the only reason this isn't on `im.pidgin.pidgin` already.
author John Bailey <rekkanoryo@rekkanoryo.org>
date Sun, 21 Feb 2010 16:52:42 +0000
parents 259bbfb423d4
children db6735e579f8
line wrap: on
line diff
--- a/libpurple/protocols/gg/lib/http.c	Sun Feb 21 00:11:56 2010 +0000
+++ b/libpurple/protocols/gg/lib/http.c	Sun Feb 21 16:52:42 2010 +0000
@@ -1,4 +1,4 @@
-/* $Id: http.c 16856 2006-08-19 01:13:25Z evands $ */
+/* $Id: http.c 833 2009-10-01 20:48:01Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
@@ -14,52 +14,60 @@
  *
  *  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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301,
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
  *  USA.
  */
 
-#include "libgadu.h"
+/**
+ * \file http.c
+ *
+ * \brief Obsługa połączeń HTTP
+ */
 
 #include <sys/types.h>
-#ifndef _WIN32
-#include <sys/wait.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-#endif
 
-#include "libgadu-config.h"
+#include "compat.h"
+#include "libgadu.h"
+#include "resolver.h"
 
 #include <ctype.h>
 #include <errno.h>
-#ifndef _WIN32
 #include <netdb.h>
-#endif
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-#  include <pthread.h>
-#endif
+#include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#include "compat.h"
-
-/*
- * gg_http_connect() // funkcja pomocnicza
+/**
+ * Rozpoczyna połączenie HTTP.
  *
- * rozpoczyna po³±czenie po http.
+ * Funkcja przeprowadza połączenie HTTP przy połączeniu synchronicznym,
+ * zwracając wynik w polach struktury \c gg_http, lub błąd, gdy sesja się
+ * nie powiedzie.
+ *
+ * Przy połączeniu asynchronicznym, funkcja rozpoczyna połączenie, a dalsze
+ * etapy będą przeprowadzane po wykryciu zmian (\c watch) na obserwowanym
+ * deskryptorze (\c fd) i wywołaniu funkcji \c gg_http_watch_fd().
  *
- *  - hostname - adres serwera
- *  - port - port serwera
- *  - async - asynchroniczne po³±czenie
- *  - method - metoda http (GET, POST, cokolwiek)
- *  - path - ¶cie¿ka do zasobu (musi byæ poprzedzona ,,/'')
- *  - header - nag³ówek zapytania plus ewentualne dane dla POST
+ * Po zakończeniu, należy zwolnić strukturę za pomocą funkcji
+ * \c gg_http_free(). Połączenie asynchroniczne można zatrzymać w każdej
+ * chwili za pomocÄ… \c gg_http_stop().
  *
- * zaalokowana struct gg_http, któr± po¼niej nale¿y
- * zwolniæ funkcj± gg_http_free(), albo NULL je¶li wyst±pi³ b³±d.
+ * \param hostname Adres serwera
+ * \param port Port serwera
+ * \param async Flaga asynchronicznego połączenia
+ * \param method Metoda HTTP
+ * \param path Ścieżka do zasobu (musi być poprzedzona znakiem '/')
+ * \param header Nagłówek zapytania plus ewentualne dane dla POST
+ *
+ * \return Zaalokowana struktura \c gg_http lub NULL, jeśli wystąpił błąd.
+ *
+ * \ingroup http
  */
 struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header)
 {
@@ -70,7 +78,7 @@
 		errno = EFAULT;
 		return NULL;
 	}
-	
+
 	if (!(h = malloc(sizeof(*h))))
 		return NULL;
 	memset(h, 0, sizeof(*h));
@@ -80,6 +88,8 @@
 	h->fd = -1;
 	h->type = GG_SESSION_HTTP;
 
+	gg_http_set_resolver(h, GG_RESOLVER_DEFAULT);
+
 	if (gg_proxy_enabled) {
 		char *auth = gg_proxy_auth();
 
@@ -88,9 +98,8 @@
 				"", header);
 		hostname = gg_proxy_host;
 		h->port = port = gg_proxy_port;
+		free(auth);
 
-		if (auth)
-			free(auth);
 	} else {
 		h->query = gg_saprintf("%s %s HTTP/1.0\r\n%s",
 				method, path, header);
@@ -102,17 +111,11 @@
 		errno = ENOMEM;
 		return NULL;
 	}
-	
+
 	gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query);
 
 	if (async) {
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-		if (gg_resolve_pthread(&h->fd, &h->resolver, hostname)) {
-#elif defined _WIN32
-		if (gg_resolve_win32thread(&h->fd, &h->resolver, hostname)) {
-#else
-		if (gg_resolve(&h->fd, &h->pid, hostname)) {
-#endif
+		if (h->resolver_start(&h->fd, &h->resolver, hostname) == -1) {
 			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n");
 			gg_http_free(h);
 			errno = ENOENT;
@@ -125,19 +128,16 @@
 		h->check = GG_CHECK_READ;
 		h->timeout = GG_DEFAULT_TIMEOUT;
 	} else {
-		struct in_addr *hn, a;
+		struct in_addr addr;
 
-		if (!(hn = gg_gethostbyname(hostname))) {
+		if (gg_gethostbyname_real(hostname, &addr, 0) == -1) {
 			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n");
 			gg_http_free(h);
 			errno = ENOENT;
 			return NULL;
-		} else {
-			a.s_addr = hn->s_addr;
-			free(hn);
 		}
 
-		if (!(h->fd = gg_connect(&a, port, 0)) == -1) {
+		if ((h->fd = gg_connect(&addr, port, 0)) == -1) {
 			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno));
 			gg_http_free(h);
 			return NULL;
@@ -159,10 +159,12 @@
 
 	h->callback = gg_http_watch_fd;
 	h->destroy = gg_http_free;
-	
+
 	return h;
 }
 
+#ifndef DOXYGEN
+
 #define gg_http_error(x) \
 	close(h->fd); \
 	h->fd = -1; \
@@ -170,17 +172,22 @@
 	h->error = x; \
 	return 0;
 
-/*
- * gg_http_watch_fd()
- *
- * przy asynchronicznej obs³udze HTTP funkcjê t± nale¿y wywo³aæ, je¶li
- * zmieni³o siê co¶ na obserwowanym deskryptorze.
+#endif /* DOXYGEN */
+
+/**
+ * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
  *
- *  - h - struktura opisuj±ca po³±czenie
+ * Operacja będzie zakończona, gdy pole \c state będzie równe
+ * \c GG_STATE_PARSING. W tym miejscu działanie przejmuje zwykle funkcja
+ * korzystająca z \c gg_http_watch_fd(). W przypadku błędu połączenia,
+ * pole \c state będzie równe \c GG_STATE_ERROR, a kod błędu znajdzie się
+ * w polu \c error.
  *
- * je¶li wszystko posz³o dobrze to 0, inaczej -1. po³±czenie bêdzie
- * zakoñczone, je¶li h->state == GG_STATE_PARSING. je¶li wyst±pi jaki¶
- * b³±d, to bêdzie tam GG_STATE_ERROR i odpowiedni kod b³êdu w h->error.
+ * \param h Struktura połączenia
+ *
+ * \return \return 0 jeśli się powiodło, -1 w przypadku błędu
+ *
+ * \ingroup http
  */
 int gg_http_watch_fd(struct gg_http *h)
 {
@@ -205,22 +212,7 @@
 		close(h->fd);
 		h->fd = -1;
 
-#ifdef __GG_LIBGADU_HAVE_PTHREAD
-		if (h->resolver) {
-			pthread_cancel(*((pthread_t *) h->resolver));
-			free(h->resolver);
-			h->resolver = NULL;
-		}
-#elif defined _WIN32
-		if (h->resolver) {
-			HANDLE hnd = h->resolver;
-			TerminateThread(hnd, 0);
-			CloseHandle(hnd);
-			h->resolver = NULL;
-		}
-#else
-		waitpid(h->pid, NULL, 0);
-#endif
+		h->resolver_cleanup(&h->resolver, 0);
 
 		gg_debug(GG_DEBUG_MISC, "=> http, connecting to %s:%d\n", inet_ntoa(a), h->port);
 
@@ -238,7 +230,7 @@
 
 	if (h->state == GG_STATE_CONNECTING) {
 		int res = 0;
-		socklen_t res_size = sizeof(res);
+		unsigned int res_size = sizeof(res);
 
 		if (h->async && (getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
 			gg_debug(GG_DEBUG_MISC, "=> http, async connection failed (errno=%d, %s)\n", (res) ? res : errno , strerror((res) ? res : errno));
@@ -257,14 +249,14 @@
 	}
 
 	if (h->state == GG_STATE_SENDING_QUERY) {
-		ssize_t res;
+		int res;
 
 		if ((res = write(h->fd, h->query, strlen(h->query))) < 1) {
 			gg_debug(GG_DEBUG_MISC, "=> http, write() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno);
 			gg_http_error(GG_ERROR_WRITING);
 		}
 
-		if (res < 0 || (size_t)res < strlen(h->query)) {
+		if (res < strlen(h->query)) {
 			gg_debug(GG_DEBUG_MISC, "=> http, partial header sent (led=%d, sent=%d)\n", strlen(h->query), res);
 
 			memmove(h->query, h->query + res, strlen(h->query) - res + 1);
@@ -346,7 +338,7 @@
 			h->body_size = 0;
 			line = h->header;
 			*tmp = 0;
-                        
+
 			gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);
 
 			while (line) {
@@ -449,7 +441,7 @@
 
 		return 0;
 	}
-	
+
 	if (h->fd != -1)
 		close(h->fd);
 
@@ -460,14 +452,14 @@
 	return -1;
 }
 
-#undef gg_http_error
-
-/*
- * gg_http_stop()
+/**
+ * Kończy asynchroniczne połączenie HTTP.
  *
- * je¶li po³±czenie jest w trakcie, przerywa je. nie zwalnia h->data.
- * 
- *  - h - struktura opisuj±ca po³±czenie
+ * Po zatrzymaniu należy zwolnić zasoby funkcją \c gg_http_free().
+ *
+ * \param h Struktura połączenia
+ *
+ * \ingroup http
  */
 void gg_http_stop(struct gg_http *h)
 {
@@ -477,15 +469,20 @@
 	if (h->state == GG_STATE_ERROR || h->state == GG_STATE_DONE)
 		return;
 
-	if (h->fd != -1)
+	if (h->fd != -1) {
 		close(h->fd);
-	h->fd = -1;
+		h->fd = -1;
+	}
+
+	h->resolver_cleanup(&h->resolver, 1);
 }
 
-/*
- * gg_http_free_fields() // funkcja wewnêtrzna
+/**
+ * \internal Zwalnia pola struktury \c gg_http.
  *
- * zwalnia pola struct gg_http, ale nie zwalnia samej struktury.
+ * Funkcja zwalnia same pola, nie zwalnia struktury.
+ *
+ * \param h Struktura połączenia
  */
 void gg_http_free_fields(struct gg_http *h)
 {
@@ -501,19 +498,21 @@
 		free(h->query);
 		h->query = NULL;
 	}
-	
+
 	if (h->header) {
 		free(h->header);
 		h->header = NULL;
 	}
 }
 
-/*
- * gg_http_free()
+/**
+ * Zwalnia zasoby po połączeniu HTTP.
  *
- * próbuje zamkn±æ po³±czenie i zwalnia pamiêæ po nim.
+ * Jeśli połączenie nie zostało jeszcze zakończone, jest przerywane.
  *
- *  - h - struktura, któr± nale¿y zlikwidowaæ
+ * \param h Struktura połączenia
+ *
+ * \ingroup http
  */
 void gg_http_free(struct gg_http *h)
 {