/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