/pidgin/main: e55133eaa11a: HTTP: queuing requests for Keep-Aliv...

Tomasz Wasilczyk tomkiewicz at cpw.pidgin.im
Tue Jul 23 06:55:40 EDT 2013


Changeset: e55133eaa11a46c9e7e545667c631808209447da
Author:	 Tomasz Wasilczyk <tomkiewicz at cpw.pidgin.im>
Date:	 2013-07-23 12:55 +0200
Branch:	 default
URL: https://hg.pidgin.im/pidgin/main/rev/e55133eaa11a

Description:

HTTP: queuing requests for Keep-Alive connections

diffstat:

 libpurple/http.c |  329 +++++++++++++++++++++++++++++++++++++++++-------------
 libpurple/http.h |   27 ++++-
 2 files changed, 270 insertions(+), 86 deletions(-)

diffs (truncated from 557 to 300 lines):

diff --git a/libpurple/http.c b/libpurple/http.c
--- a/libpurple/http.c
+++ b/libpurple/http.c
@@ -44,6 +44,10 @@ typedef struct _PurpleHttpSocket PurpleH
 
 typedef struct _PurpleHttpHeaders PurpleHttpHeaders;
 
+typedef struct _PurpleHttpKeepaliveHost PurpleHttpKeepaliveHost;
+
+typedef struct _PurpleHttpKeepaliveRequest PurpleHttpKeepaliveRequest;
+
 typedef void (*PurpleHttpSocketConnectCb)(PurpleHttpSocket *hs,
 	const gchar *error, gpointer user_data);
 
@@ -52,8 +56,7 @@ struct _PurpleHttpSocket
 	gboolean is_ssl;
 	gboolean is_busy;
 	uint use_count;
-	PurpleHttpKeepalivePool *pool;
-	gchar *hash;
+	PurpleHttpKeepaliveHost *host;
 
 	PurpleSslConnection *ssl_connection;
 	PurpleProxyConnectData *raw_connection;
@@ -94,11 +97,13 @@ struct _PurpleHttpConnection
 	gpointer user_data;
 	gboolean is_reading;
 	gboolean is_keepalive;
+	gboolean is_cancelling;
 
 	PurpleHttpURL *url;
 	PurpleHttpRequest *request;
 	PurpleHttpResponse *response;
 
+	PurpleHttpKeepaliveRequest *socket_request;
 	PurpleHttpSocket *socket;
 	GString *request_header;
 	int request_header_written, request_contents_written;
@@ -166,11 +171,39 @@ struct _PurpleHttpCookieJar
 	GHashTable *tab;
 };
 
+struct _PurpleHttpKeepaliveRequest
+{
+	PurpleConnection *gc;
+	PurpleHttpSocketConnectCb cb;
+	gpointer user_data;
+
+	PurpleHttpKeepaliveHost *host;
+	PurpleHttpSocket *hs;
+};
+
+struct _PurpleHttpKeepaliveHost
+{
+	PurpleHttpKeepalivePool *pool;
+
+	gchar *host;
+	int port;
+	gboolean is_ssl;
+
+	GSList *sockets; /* list of PurpleHttpSocket */
+
+	GSList *queue; /* list of PurpleHttpKeepaliveRequest */
+	guint process_queue_timeout;
+};
+
 struct _PurpleHttpKeepalivePool
 {
+	gboolean is_destroying;
+
 	int ref_count;
 
-	/* key: purple_http_socket_hash, value: GSList of PurpleHttpSocket */
+	guint limit_per_host;
+
+	/* key: purple_http_socket_hash, value: PurpleHttpKeepaliveHost */
 	GHashTable *by_hash;
 };
 
@@ -194,11 +227,13 @@ static void purple_http_cookie_jar_parse
 static gchar * purple_http_cookie_jar_gen(PurpleHttpCookieJar *cookie_jar);
 gchar * purple_http_cookie_jar_dump(PurpleHttpCookieJar *cjar);
 
-static PurpleHttpSocket *
+static PurpleHttpKeepaliveRequest *
 purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
 	PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
 	PurpleHttpSocketConnectCb cb, gpointer user_data);
 static void
+purple_http_keepalive_pool_request_cancel(PurpleHttpKeepaliveRequest *req);
+static void
 purple_http_keepalive_pool_release(PurpleHttpSocket *hs, gboolean invalidate);
 
 static GRegex *purple_http_re_url, *purple_http_re_url_host,
@@ -229,23 +264,6 @@ static GHashTable *purple_http_hc_by_ptr
 
 /*** Helper functions *********************************************************/
 
-/* destroys the key and steals the value */
-static void
-g_hash_table_steal_value(GHashTable *hash_table, const gpointer key,
-	GDestroyNotify key_destroy_func)
-{
-	gpointer orig_key;
-
-	g_return_if_fail(hash_table != NULL);
-
-	if (!g_hash_table_lookup_extended(hash_table, key, &orig_key, NULL))
-		return;
-
-	g_hash_table_steal(hash_table, key);
-
-	key_destroy_func(orig_key);
-}
-
 static time_t purple_http_rfc1123_to_time(const gchar *str)
 {
 	static const gchar *months[13] = {"jan", "feb", "mar", "apr", "may", "jun",
@@ -358,7 +376,6 @@ purple_http_socket_connect_new(PurpleCon
 	hs->connect_cb = cb;
 	hs->cb_data = user_data;
 	hs->fd = -1;
-	hs->hash = purple_http_socket_hash(host, port, is_ssl);
 
 	if (is_ssl) {
 		if (!purple_ssl_is_supported()) {
@@ -480,7 +497,6 @@ purple_http_socket_close_free(PurpleHttp
 			close(hs->fd);
 	}
 
-	g_free(hs->hash);
 	g_free(hs);
 }
 
@@ -1313,19 +1329,27 @@ static void _purple_http_disconnect(Purp
 		g_string_free(hc->response_buffer, TRUE);
 	hc->response_buffer = NULL;
 
-	purple_http_keepalive_pool_release(hc->socket, !is_graceful);
-	hc->socket = NULL;
+	if (hc->socket_request)
+		purple_http_keepalive_pool_request_cancel(hc->socket_request);
+	else {
+		purple_http_keepalive_pool_release(hc->socket, !is_graceful);
+		hc->socket = NULL;
+	}
 }
 
 static void  _purple_http_connected(PurpleHttpSocket *hs, const gchar *error, gpointer _hc)
 {
 	PurpleHttpConnection *hc = _hc;
 
+	hc->socket_request = NULL;
+	hc->socket = hs;
+
 	if (error != NULL) {
 		_purple_http_error(hc, _("Unable to connect to %s: %s"),
 			hc->url->host, error);
 		return;
 	}
+
 	purple_http_socket_watch(hs, PURPLE_INPUT_WRITE, _purple_http_send, hc);
 }
 
@@ -1368,11 +1392,16 @@ static gboolean _purple_http_reconnect(P
 		return FALSE;
 	}
 
-	hc->socket = purple_http_keepalive_pool_request(
-		hc->request->keepalive_pool, hc->gc, url->host,
-		url->port, is_ssl, _purple_http_connected, hc);
-
-	if (hc->socket == NULL) {
+	if (hc->request->keepalive_pool != NULL) {
+		hc->socket_request = purple_http_keepalive_pool_request(
+			hc->request->keepalive_pool, hc->gc, url->host,
+			url->port, is_ssl, _purple_http_connected, hc);
+	} else {
+		hc->socket = purple_http_socket_connect_new(hc->gc, url->host,
+			url->port, is_ssl, _purple_http_connected, hc);
+	}
+
+	if (hc->socket_request == NULL && hc->socket == NULL) {
 		_purple_http_error(hc, _("Unable to connect to %s"), url->host);
 		return FALSE;
 	}
@@ -1577,6 +1606,10 @@ void purple_http_conn_cancel(PurpleHttpC
 	if (http_conn == NULL)
 		return;
 
+	if (http_conn->is_cancelling)
+		return;
+	http_conn->is_cancelling = TRUE;
+
 	if (purple_debug_is_verbose()) {
 		purple_debug_misc("http", "Cancelling connection %p...\n",
 			http_conn);
@@ -1927,10 +1960,26 @@ gboolean purple_http_cookie_jar_is_empty
 /*** HTTP Keep-Alive pool API *************************************************/
 
 static void
-purple_http_keepalive_pool_socketlist_free(gpointer socketlist)
+purple_http_keepalive_host_process_queue(PurpleHttpKeepaliveHost *host);
+
+static void
+purple_http_keepalive_host_free(gpointer _host)
 {
-	g_slist_free_full(socketlist,
+	PurpleHttpKeepaliveHost *host = _host;
+
+	if (host->process_queue_timeout > 0) {
+		purple_timeout_remove(host->process_queue_timeout);
+		host->process_queue_timeout = 0;
+	}
+
+	g_free(host->host);
+
+	g_slist_free_full(host->queue,
+		(GDestroyNotify)purple_http_keepalive_pool_request_cancel);
+	g_slist_free_full(host->sockets,
 		(GDestroyNotify)purple_http_socket_close_free);
+
+	g_free(host);
 }
 
 PurpleHttpKeepalivePool *
@@ -1940,7 +1989,7 @@ purple_http_keepalive_pool_new(void)
 
 	pool->ref_count = 1;
 	pool->by_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
-		purple_http_keepalive_pool_socketlist_free);
+		purple_http_keepalive_host_free);
 
 	return pool;
 }
@@ -1950,6 +1999,9 @@ purple_http_keepalive_pool_free(PurpleHt
 {
 	g_return_if_fail(pool != NULL);
 
+	if (pool->is_destroying)
+		return;
+	pool->is_destroying = TRUE;
 	g_hash_table_destroy(pool->by_hash);
 	g_free(pool);
 }
@@ -1978,32 +2030,87 @@ purple_http_keepalive_pool_unref(PurpleH
 	return NULL;
 }
 
-static PurpleHttpSocket *
+static PurpleHttpKeepaliveRequest *
 purple_http_keepalive_pool_request(PurpleHttpKeepalivePool *pool,
 	PurpleConnection *gc, const gchar *host, int port, gboolean is_ssl,
 	PurpleHttpSocketConnectCb cb, gpointer user_data)
 {
-	GSList *sockets, *it;
+	PurpleHttpKeepaliveRequest *req;
+	PurpleHttpKeepaliveHost *kahost;
 	gchar *hash;
+
+	g_return_val_if_fail(pool != NULL, NULL);
+	g_return_val_if_fail(host != NULL, NULL);
+
+	if (pool->is_destroying) {
+		purple_debug_error("http", "pool is destroying\n");
+		return NULL;
+	}
+
+	hash = purple_http_socket_hash(host, port, is_ssl);
+	kahost = g_hash_table_lookup(pool->by_hash, hash);
+
+	if (kahost == NULL) {
+		kahost = g_new0(PurpleHttpKeepaliveHost, 1);
+		kahost->pool = pool;
+		kahost->host = g_strdup(host);
+		kahost->port = port;
+		kahost->is_ssl = is_ssl;
+
+		g_hash_table_insert(pool->by_hash, g_strdup(hash), kahost);
+	}
+
+	g_free(hash);
+
+	req = g_new0(PurpleHttpKeepaliveRequest, 1);
+	req->gc = gc;
+	req->cb = cb;
+	req->user_data = user_data;
+	req->host = kahost;
+
+	kahost->queue = g_slist_append(kahost->queue, req);
+
+	purple_http_keepalive_host_process_queue(kahost);
+
+	return req;
+}
+
+static void
+_purple_http_keepalive_socket_connected(PurpleHttpSocket *hs,
+	const gchar *error, gpointer _req)
+{



More information about the Commits mailing list