diff options
author | Dan Winship <danw@gnome.org> | 2013-12-09 12:16:05 +0100 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2013-12-09 14:51:51 +0100 |
commit | 3f8e0d45cdf97f999c3f9362578b2ff0871021f2 (patch) | |
tree | d0fcb7c37663459b61ea0ae8eaf0df690e3beab7 | |
parent | 229569ec354c498efdaca430856fe48b3c4c273d (diff) | |
download | libsoup-3f8e0d45cdf97f999c3f9362578b2ff0871021f2.tar.gz |
SoupSessionHost: split from SoupSession
HTTP/2.0 will need to do connection management differently, so let's
split SoupSessionHost out of soup-session.c in preparation for making
it more complicated.
(The split is a little bit awkward at the moment but will hopefully be
cleaned up some.)
-rw-r--r-- | libsoup/Makefile.am | 2 | ||||
-rw-r--r-- | libsoup/soup-connection.c | 8 | ||||
-rw-r--r-- | libsoup/soup-connection.h | 1 | ||||
-rw-r--r-- | libsoup/soup-misc-private.h | 4 | ||||
-rw-r--r-- | libsoup/soup-misc.c | 17 | ||||
-rw-r--r-- | libsoup/soup-session-host.c | 249 | ||||
-rw-r--r-- | libsoup/soup-session-host.h | 57 | ||||
-rw-r--r-- | libsoup/soup-session-private.h | 2 | ||||
-rw-r--r-- | libsoup/soup-session.c | 259 |
9 files changed, 409 insertions, 190 deletions
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am index 32502df6..73b4fb53 100644 --- a/libsoup/Makefile.am +++ b/libsoup/Makefile.am @@ -181,6 +181,8 @@ libsoup_2_4_la_SOURCES = \ soup-session.c \ soup-session-async.c \ soup-session-feature.c \ + soup-session-host.c \ + soup-session-host.h \ soup-session-private.h \ soup-session-sync.c \ soup-socket.c \ diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c index 32a52c06..f59a9f85 100644 --- a/libsoup/soup-connection.c +++ b/libsoup/soup-connection.c @@ -44,7 +44,6 @@ enum { PROP_0, PROP_REMOTE_URI, - PROP_SSL, PROP_SSL_FALLBACK, PROP_SOCKET_PROPERTIES, PROP_STATE, @@ -101,9 +100,7 @@ soup_connection_set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_REMOTE_URI: priv->remote_uri = g_value_dup_boxed (value); - break; - case PROP_SSL: - priv->ssl = g_value_get_boolean (value); + priv->ssl = (priv->remote_uri->scheme == SOUP_URI_SCHEME_HTTPS); break; case PROP_SSL_FALLBACK: priv->ssl_fallback = g_value_get_boolean (value); @@ -130,9 +127,6 @@ soup_connection_get_property (GObject *object, guint prop_id, case PROP_REMOTE_URI: g_value_set_boxed (value, priv->remote_uri); break; - case PROP_SSL: - g_value_set_boolean (value, priv->ssl); - break; case PROP_SSL_FALLBACK: g_value_set_boolean (value, priv->ssl_fallback); break; diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h index 3fd6721f..8df61129 100644 --- a/libsoup/soup-connection.h +++ b/libsoup/soup-connection.h @@ -36,7 +36,6 @@ GType soup_connection_get_type (void); #define SOUP_CONNECTION_REMOTE_URI "remote-uri" -#define SOUP_CONNECTION_SSL "ssl" #define SOUP_CONNECTION_SSL_FALLBACK "ssl-fallback" #define SOUP_CONNECTION_SOCKET_PROPERTIES "socket-properties" #define SOUP_CONNECTION_STATE "state" diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h index 52b815e3..01253c75 100644 --- a/libsoup/soup-misc-private.h +++ b/libsoup/soup-misc-private.h @@ -66,6 +66,10 @@ SoupURI *soup_socket_get_http_proxy_uri (SoupSocket *sock); GSource *soup_add_completion_reffed (GMainContext *async_context, GSourceFunc function, gpointer data); +GSource *soup_add_timeout_reffed (GMainContext *async_context, + guint interval, + GSourceFunc function, + gpointer data); guint soup_message_headers_get_ranges_internal (SoupMessageHeaders *hdrs, goffset total_length, diff --git a/libsoup/soup-misc.c b/libsoup/soup-misc.c index 325b5872..747a5d44 100644 --- a/libsoup/soup-misc.c +++ b/libsoup/soup-misc.c @@ -153,6 +153,17 @@ soup_add_completion (GMainContext *async_context, return source; } +GSource * +soup_add_timeout_reffed (GMainContext *async_context, + guint interval, + GSourceFunc function, gpointer data) +{ + GSource *source = g_timeout_source_new (interval); + g_source_set_callback (source, function, data, NULL); + g_source_attach (source, async_context); + return source; +} + /** * soup_add_timeout: (skip) * @async_context: (allow-none): the #GMainContext to dispatch the I/O @@ -172,9 +183,9 @@ soup_add_timeout (GMainContext *async_context, guint interval, GSourceFunc function, gpointer data) { - GSource *source = g_timeout_source_new (interval); - g_source_set_callback (source, function, data, NULL); - g_source_attach (source, async_context); + GSource *source; + + source = soup_add_timeout_reffed (async_context, interval, function, data); g_source_unref (source); return source; } diff --git a/libsoup/soup-session-host.c b/libsoup/soup-session-host.c new file mode 100644 index 00000000..ba3e7f62 --- /dev/null +++ b/libsoup/soup-session-host.c @@ -0,0 +1,249 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * soup-session-host.c + * + * Copyright 2013 Red Hat, Inc. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "soup-session-host.h" +#include "soup.h" +#include "soup-connection.h" +#include "soup-misc-private.h" +#include "soup-session-private.h" +#include "soup-socket-properties.h" + +G_DEFINE_TYPE (SoupSessionHost, soup_session_host, G_TYPE_OBJECT) + +typedef struct { + SoupURI *uri; + SoupAddress *addr; + + GSList *connections; /* CONTAINS: SoupConnection */ + guint num_conns; + guint max_conns; + + guint num_messages; + + gboolean ssl_fallback; + + GSource *keep_alive_src; + SoupSession *session; +} SoupSessionHostPrivate; +#define SOUP_SESSION_HOST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION_HOST, SoupSessionHostPrivate)) + +enum { + UNUSED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +#define HOST_KEEP_ALIVE 5 * 60 * 1000 /* 5 min in msecs */ + +static void +soup_session_host_init (SoupSessionHost *host) +{ +} + +static void +soup_session_host_finalize (GObject *object) +{ + SoupSessionHostPrivate *priv = SOUP_SESSION_HOST_GET_PRIVATE (object); + + g_warn_if_fail (priv->connections == NULL); + + if (priv->keep_alive_src) { + g_source_destroy (priv->keep_alive_src); + g_source_unref (priv->keep_alive_src); + } + + soup_uri_free (priv->uri); + g_object_unref (priv->addr); + + G_OBJECT_CLASS (soup_session_host_parent_class)->finalize (object); +} + +static void +soup_session_host_class_init (SoupSessionHostClass *host_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (host_class); + + g_type_class_add_private (host_class, sizeof (SoupSessionHostClass)); + + object_class->finalize = soup_session_host_finalize; + + signals[UNUSED] = + g_signal_new ("unused", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + +} + +SoupSessionHost * +soup_session_host_new (SoupSession *session, + SoupURI *uri) +{ + SoupSessionHost *host; + SoupSessionHostPrivate *priv; + + host = g_object_new (SOUP_TYPE_SESSION_HOST, NULL); + priv = SOUP_SESSION_HOST_GET_PRIVATE (host); + + priv->uri = soup_uri_copy_host (uri); + priv->addr = g_object_new (SOUP_TYPE_ADDRESS, + SOUP_ADDRESS_NAME, priv->uri->host, + SOUP_ADDRESS_PORT, priv->uri->port, + SOUP_ADDRESS_PROTOCOL, priv->uri->scheme, + NULL); + priv->keep_alive_src = NULL; + priv->session = session; + + g_object_get (G_OBJECT (session), + SOUP_SESSION_MAX_CONNS_PER_HOST, &priv->max_conns, + NULL); + + return host; +} + +SoupURI * +soup_session_host_get_uri (SoupSessionHost *host) +{ + return SOUP_SESSION_HOST_GET_PRIVATE (host)->uri; +} + +SoupAddress * +soup_session_host_get_address (SoupSessionHost *host) +{ + return SOUP_SESSION_HOST_GET_PRIVATE (host)->addr; +} + +void +soup_session_host_add_message (SoupSessionHost *host, + SoupMessage *msg) +{ + SOUP_SESSION_HOST_GET_PRIVATE (host)->num_messages++; +} + +void +soup_session_host_remove_message (SoupSessionHost *host, + SoupMessage *msg) +{ + SOUP_SESSION_HOST_GET_PRIVATE (host)->num_messages--; +} + +static gboolean +emit_unused (gpointer host) +{ + g_signal_emit (host, signals[UNUSED], 0); + return FALSE; +} + +SoupConnection * +soup_session_host_get_connection (SoupSessionHost *host, + gboolean need_new_connection, + gboolean at_max_conns, + gboolean *try_cleanup) +{ + SoupSessionHostPrivate *priv = SOUP_SESSION_HOST_GET_PRIVATE (host); + SoupConnection *conn; + GSList *conns; + int num_pending = 0; + SoupSocketProperties *socket_props; + + for (conns = priv->connections; conns; conns = conns->next) { + conn = conns->data; + + if (!need_new_connection && soup_connection_get_state (conn) == SOUP_CONNECTION_IDLE) { + soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE); + return conn; + } else if (soup_connection_get_state (conn) == SOUP_CONNECTION_CONNECTING) + num_pending++; + } + + /* Limit the number of pending connections; num_messages / 2 + * is somewhat arbitrary... + */ + if (num_pending > priv->num_messages / 2) + return NULL; + + if (priv->num_conns >= priv->max_conns) { + if (need_new_connection) + *try_cleanup = TRUE; + return NULL; + } + + if (at_max_conns) { + *try_cleanup = TRUE; + return NULL; + } + + g_object_get (G_OBJECT (priv->session), + SOUP_SESSION_SOCKET_PROPERTIES, &socket_props, + NULL); + conn = g_object_new (SOUP_TYPE_CONNECTION, + SOUP_CONNECTION_REMOTE_URI, priv->uri, + SOUP_CONNECTION_SSL_FALLBACK, priv->ssl_fallback, + SOUP_CONNECTION_SOCKET_PROPERTIES, socket_props, + NULL); + soup_socket_properties_unref (socket_props); + + priv->num_conns++; + priv->connections = g_slist_prepend (priv->connections, conn); + + if (priv->keep_alive_src) { + g_source_destroy (priv->keep_alive_src); + g_source_unref (priv->keep_alive_src); + priv->keep_alive_src = NULL; + } + + return conn; +} + +void +soup_session_host_remove_connection (SoupSessionHost *host, + SoupConnection *conn) +{ + SoupSessionHostPrivate *priv = SOUP_SESSION_HOST_GET_PRIVATE (host); + + if (soup_connection_get_ssl_fallback (conn)) + priv->ssl_fallback = TRUE; + + priv->connections = g_slist_remove (priv->connections, conn); + priv->num_conns--; + + if (priv->num_conns == 0) { + g_assert (priv->keep_alive_src == NULL); + priv->keep_alive_src = soup_add_timeout_reffed (soup_session_get_async_context (priv->session), + HOST_KEEP_ALIVE, + emit_unused, + host); + } +} + +int +soup_session_host_get_num_connections (SoupSessionHost *host) +{ + return SOUP_SESSION_HOST_GET_PRIVATE (host)->num_conns; +} + +gboolean +soup_session_host_get_ssl_fallback (SoupSessionHost *host) +{ + return SOUP_SESSION_HOST_GET_PRIVATE (host)->ssl_fallback; +} + +void +soup_session_host_set_ssl_fallback (SoupSessionHost *host, + gboolean ssl_fallback) +{ + SOUP_SESSION_HOST_GET_PRIVATE (host)->ssl_fallback = ssl_fallback; +} + diff --git a/libsoup/soup-session-host.h b/libsoup/soup-session-host.h new file mode 100644 index 00000000..fecd5d23 --- /dev/null +++ b/libsoup/soup-session-host.h @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright 2013 Red Hat, Inc. + */ + +#ifndef SOUP_SESSION_HOST_H +#define SOUP_SESSION_HOST_H 1 + +#include "soup-types.h" + +G_BEGIN_DECLS + +#define SOUP_TYPE_SESSION_HOST (soup_session_host_get_type ()) +#define SOUP_SESSION_HOST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SESSION_HOST, SoupSessionHost)) +#define SOUP_SESSION_HOST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_SESSION_HOST, SoupSessionHostClass)) +#define SOUP_IS_SESSION_HOST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_SESSION_HOST)) +#define SOUP_IS_SESSION_HOST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_SESSION_HOST)) +#define SOUP_SESSION_HOST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_SESSION_HOST, SoupSessionHostClass)) + +typedef struct { + GObject parent; + +} SoupSessionHost; + +typedef struct { + GObjectClass parent_class; + +} SoupSessionHostClass; + +GType soup_session_host_get_type (void); + +SoupSessionHost *soup_session_host_new (SoupSession *session, + SoupURI *uri); + +SoupURI *soup_session_host_get_uri (SoupSessionHost *host); +SoupAddress *soup_session_host_get_address (SoupSessionHost *host); + +void soup_session_host_add_message (SoupSessionHost *host, + SoupMessage *msg); +void soup_session_host_remove_message (SoupSessionHost *host, + SoupMessage *msg); + +SoupConnection *soup_session_host_get_connection (SoupSessionHost *host, + gboolean need_new_connection, + gboolean at_max_conns, + gboolean *try_cleanup); +void soup_session_host_remove_connection (SoupSessionHost *host, + SoupConnection *conn); +int soup_session_host_get_num_connections (SoupSessionHost *host); + +gboolean soup_session_host_get_ssl_fallback (SoupSessionHost *host); +void soup_session_host_set_ssl_fallback (SoupSessionHost *host, + gboolean ssl_fallback); + +G_END_DECLS + +#endif /* SOUP_SESSION_HOST_H */ diff --git a/libsoup/soup-session-private.h b/libsoup/soup-session-private.h index dc4d300b..b769e9d8 100644 --- a/libsoup/soup-session-private.h +++ b/libsoup/soup-session-private.h @@ -12,6 +12,8 @@ G_BEGIN_DECLS +#define SOUP_SESSION_SOCKET_PROPERTIES "socket-properties" + /* "protected" methods for subclasses */ SoupMessageQueue *soup_session_get_queue (SoupSession *session); diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c index 9f0c2cd0..03af7cd4 100644 --- a/libsoup/soup-session.c +++ b/libsoup/soup-session.c @@ -20,11 +20,10 @@ #include "soup-misc-private.h" #include "soup-message-queue.h" #include "soup-proxy-resolver-wrapper.h" +#include "soup-session-host.h" #include "soup-session-private.h" #include "soup-socket-properties.h" -#define HOST_KEEP_ALIVE 5 * 60 * 1000 /* 5 min in msecs */ - /** * SECTION:soup-session * @short_description: Soup session state object @@ -65,22 +64,9 @@ soup_init (void) #endif } -typedef struct { - SoupURI *uri; - SoupAddress *addr; - - GSList *connections; /* CONTAINS: SoupConnection */ - guint num_conns; - - guint num_messages; - - gboolean ssl_fallback; - - GSource *keep_alive_src; - SoupSession *session; -} SoupSessionHost; static guint soup_host_uri_hash (gconstpointer key); static gboolean soup_host_uri_equal (gconstpointer v1, gconstpointer v2); +static void free_unused_host (SoupSessionHost *host, gpointer session); typedef struct { SoupSession *session; @@ -135,7 +121,6 @@ typedef struct { #define SOUP_IS_PLAIN_SESSION(o) (G_TYPE_FROM_INSTANCE (o) == SOUP_TYPE_SESSION) -static void free_host (SoupSessionHost *host); static void connection_state_changed (GObject *object, GParamSpec *param, gpointer user_data); static void connection_disconnected (SoupConnection *conn, gpointer user_data); @@ -176,6 +161,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, + PROP_SOCKET_PROPERTIES, PROP_PROXY_URI, PROP_PROXY_RESOLVER, PROP_MAX_CONNS, @@ -216,10 +202,10 @@ soup_session_init (SoupSession *session) g_cond_init (&priv->conn_cond); priv->http_hosts = g_hash_table_new_full (soup_host_uri_hash, soup_host_uri_equal, - NULL, (GDestroyNotify)free_host); + NULL, g_object_unref); priv->https_hosts = g_hash_table_new_full (soup_host_uri_hash, soup_host_uri_equal, - NULL, (GDestroyNotify)free_host); + NULL, g_object_unref); priv->conns = g_hash_table_new (NULL, NULL); priv->max_conns = SOUP_SESSION_MAX_CONNS_DEFAULT; @@ -754,8 +740,21 @@ soup_session_get_property (GObject *object, guint prop_id, SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); SoupSessionFeature *feature; GTlsDatabase *tlsdb; + SoupSocketProperties *props; switch (prop_id) { + case PROP_SOCKET_PROPERTIES: + tlsdb = get_tls_database (session); + props = soup_socket_properties_new (priv->async_context, + priv->use_thread_context, + get_proxy_resolver (session), + priv->local_addr, + tlsdb, + priv->ssl_strict && (tlsdb != NULL || SOUP_IS_PLAIN_SESSION (priv->session)), + priv->io_timeout, + priv->idle_timeout); + g_value_take_boxed (value, props); + break; case PROP_LOCAL_ADDRESS: g_value_set_object (value, priv->local_addr); break; @@ -925,55 +924,38 @@ soup_host_uri_equal (gconstpointer v1, gconstpointer v2) return g_ascii_strcasecmp (one->host, two->host) == 0; } - -static SoupSessionHost * -soup_session_host_new (SoupSession *session, SoupURI *uri) -{ - SoupSessionHost *host; - - host = g_slice_new0 (SoupSessionHost); - host->uri = soup_uri_copy_host (uri); - if (host->uri->scheme != SOUP_URI_SCHEME_HTTP && - host->uri->scheme != SOUP_URI_SCHEME_HTTPS) { - SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); - - if (soup_uri_is_https (host->uri, priv->https_aliases)) - host->uri->scheme = SOUP_URI_SCHEME_HTTPS; - else - host->uri->scheme = SOUP_URI_SCHEME_HTTP; - } - - host->addr = g_object_new (SOUP_TYPE_ADDRESS, - SOUP_ADDRESS_NAME, host->uri->host, - SOUP_ADDRESS_PORT, host->uri->port, - SOUP_ADDRESS_PROTOCOL, host->uri->scheme, - NULL); - host->keep_alive_src = NULL; - host->session = session; - - return host; -} - /* Requires conn_lock to be locked */ static SoupSessionHost * get_host_for_uri (SoupSession *session, SoupURI *uri) { SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); SoupSessionHost *host; + gboolean https; + SoupURI *uri_tmp = NULL; - if (soup_uri_is_https (uri, priv->https_aliases)) + https = soup_uri_is_https (uri, priv->https_aliases); + if (https) host = g_hash_table_lookup (priv->https_hosts, uri); else host = g_hash_table_lookup (priv->http_hosts, uri); if (host) return host; + if (uri->scheme != SOUP_URI_SCHEME_HTTP && + uri->scheme != SOUP_URI_SCHEME_HTTPS) { + uri = uri_tmp = soup_uri_copy (uri); + uri->scheme = https ? SOUP_URI_SCHEME_HTTPS : SOUP_URI_SCHEME_HTTP; + } host = soup_session_host_new (session, uri); + if (uri_tmp) + soup_uri_free (uri_tmp); - if (soup_uri_is_https (uri, priv->https_aliases)) - g_hash_table_insert (priv->https_hosts, host->uri, host); + if (https) + g_hash_table_insert (priv->https_hosts, soup_session_host_get_uri (host), host); else - g_hash_table_insert (priv->http_hosts, host->uri, host); + g_hash_table_insert (priv->http_hosts, soup_session_host_get_uri (host), host); + + g_signal_connect (host, "unused", G_CALLBACK (free_unused_host), session); return host; } @@ -986,21 +968,6 @@ get_host_for_message (SoupSession *session, SoupMessage *msg) } static void -free_host (SoupSessionHost *host) -{ - g_warn_if_fail (host->connections == NULL); - - if (host->keep_alive_src) { - g_source_destroy (host->keep_alive_src); - g_source_unref (host->keep_alive_src); - } - - soup_uri_free (host->uri); - g_object_unref (host->addr); - g_slice_free (SoupSessionHost, host); -} - -static void auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer session) @@ -1221,7 +1188,7 @@ soup_session_append_queue_item (SoupSession *session, SoupMessage *msg, g_mutex_lock (&priv->conn_lock); host = get_host_for_message (session, item->msg); - host->num_messages++; + soup_session_host_add_message (host, msg); g_mutex_unlock (&priv->conn_lock); if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT)) { @@ -1313,32 +1280,32 @@ soup_session_cleanup_connections (SoupSession *session, return TRUE; } -static gboolean -free_unused_host (gpointer user_data) +static void +free_unused_host (SoupSessionHost *host, + gpointer session) { - SoupSessionHost *host = (SoupSessionHost *) user_data; - SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (host->session); + SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); + SoupURI *uri; g_mutex_lock (&priv->conn_lock); /* In a multithreaded session, a connection might have been * added while we were waiting for conn_lock. */ - if (host->connections) { + if (soup_session_host_get_num_connections (host)) { g_mutex_unlock (&priv->conn_lock); - return FALSE; + return; } /* This will free the host in addition to removing it from the * hash table */ - if (host->uri->scheme == SOUP_URI_SCHEME_HTTPS) - g_hash_table_remove (priv->https_hosts, host->uri); + uri = soup_session_host_get_uri (host); + if (uri->scheme == SOUP_URI_SCHEME_HTTPS) + g_hash_table_remove (priv->https_hosts, uri); else - g_hash_table_remove (priv->http_hosts, host->uri); + g_hash_table_remove (priv->http_hosts, uri); g_mutex_unlock (&priv->conn_lock); - - return FALSE; } static void @@ -1350,26 +1317,8 @@ drop_connection (SoupSession *session, SoupSessionHost *host, SoupConnection *co * from priv->conns itself. */ - if (host) { - host->connections = g_slist_remove (host->connections, conn); - host->num_conns--; - - /* Free the SoupHost (and its SoupAddress) if there - * has not been any new connection to the host during - * the last HOST_KEEP_ALIVE msecs. - */ - if (host->num_conns == 0) { - g_assert (host->keep_alive_src == NULL); - host->keep_alive_src = soup_add_timeout (priv->async_context, - HOST_KEEP_ALIVE, - free_unused_host, - host); - host->keep_alive_src = g_source_ref (host->keep_alive_src); - } - - if (soup_connection_get_ssl_fallback (conn)) - host->ssl_fallback = TRUE; - } + if (host) + soup_session_host_remove_connection (host, conn); g_signal_handlers_disconnect_by_func (conn, connection_disconnected, session); g_signal_handlers_disconnect_by_func (conn, connection_state_changed, session); @@ -1438,7 +1387,7 @@ soup_session_unqueue_item (SoupSession *session, g_mutex_lock (&priv->conn_lock); host = get_host_for_message (session, item->msg); - host->num_messages--; + soup_session_host_remove_message (host, item->msg); g_cond_broadcast (&priv->conn_cond); g_mutex_unlock (&priv->conn_lock); @@ -1527,8 +1476,8 @@ status_from_connect_error (SoupMessageQueueItem *item, GError *error) g_mutex_lock (&priv->conn_lock); host = get_host_for_message (item->session, item->msg); - if (!host->ssl_fallback) { - host->ssl_fallback = TRUE; + if (!soup_session_host_get_ssl_fallback (host)) { + soup_session_host_set_ssl_fallback (host, TRUE); status = SOUP_STATUS_TRY_AGAIN; } else status = SOUP_STATUS_SSL_FAILED; @@ -1728,90 +1677,35 @@ get_connection_for_host (SoupSession *session, { SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); SoupConnection *conn; - GSList *conns; - int num_pending = 0; - GTlsDatabase *tlsdb; - gboolean ssl_strict; - SoupSocketProperties *socket_props; if (priv->disposed) - return FALSE; + return NULL; if (item->conn) { - g_return_val_if_fail (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED, FALSE); + g_return_val_if_fail (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED, NULL); return item->conn; } - for (conns = host->connections; conns; conns = conns->next) { - conn = conns->data; - - if (!need_new_connection && soup_connection_get_state (conn) == SOUP_CONNECTION_IDLE) { - soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE); - return conn; - } else if (soup_connection_get_state (conn) == SOUP_CONNECTION_CONNECTING) - num_pending++; - } - - /* Limit the number of pending connections; num_messages / 2 - * is somewhat arbitrary... - */ - if (num_pending > host->num_messages / 2) - return NULL; - - if (host->num_conns >= priv->max_conns_per_host) { - if (need_new_connection) - *try_cleanup = TRUE; - return NULL; - } - - if (priv->num_conns >= priv->max_conns) { - *try_cleanup = TRUE; - return NULL; - } - - tlsdb = get_tls_database (session); - ssl_strict = priv->ssl_strict && (tlsdb != NULL || SOUP_IS_PLAIN_SESSION (priv->session)); - socket_props = soup_socket_properties_new (priv->async_context, - priv->use_thread_context, - get_proxy_resolver (session), - priv->local_addr, - tlsdb, - ssl_strict, - priv->io_timeout, - priv->idle_timeout); - - conn = g_object_new ( - SOUP_TYPE_CONNECTION, - SOUP_CONNECTION_REMOTE_URI, host->uri, - SOUP_CONNECTION_SSL, soup_uri_is_https (soup_message_get_uri (item->msg), priv->https_aliases), - SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback, - SOUP_CONNECTION_SOCKET_PROPERTIES, socket_props, - NULL); - soup_socket_properties_unref (socket_props); - - g_signal_connect (conn, "disconnected", - G_CALLBACK (connection_disconnected), - session); - g_signal_connect (conn, "notify::state", - G_CALLBACK (connection_state_changed), - session); - - /* This is a debugging-related signal, and so can ignore the - * usual rule about not emitting signals while holding - * conn_lock. - */ - g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn); - - g_hash_table_insert (priv->conns, conn, host); - - priv->num_conns++; - host->num_conns++; - host->connections = g_slist_prepend (host->connections, conn); + conn = soup_session_host_get_connection (host, need_new_connection, + priv->num_conns >= priv->max_conns, + try_cleanup); + + if (conn && soup_connection_get_state (conn) == SOUP_CONNECTION_NEW) { + g_signal_connect (conn, "disconnected", + G_CALLBACK (connection_disconnected), + session); + g_signal_connect (conn, "notify::state", + G_CALLBACK (connection_state_changed), + session); + + /* This is a debugging-related signal, and so can ignore the + * usual rule about not emitting signals while holding + * conn_lock. + */ + g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn); - if (host->keep_alive_src) { - g_source_destroy (host->keep_alive_src); - g_source_unref (host->keep_alive_src); - host->keep_alive_src = NULL; + g_hash_table_insert (priv->conns, conn, host); + priv->num_conns++; } return conn; @@ -2488,7 +2382,7 @@ prefetch_uri (SoupSession *session, SoupURI *uri, g_mutex_lock (&priv->conn_lock); host = get_host_for_uri (session, uri); - addr = g_object_ref (host->addr); + addr = g_object_ref (soup_session_host_get_address (host)); g_mutex_unlock (&priv->conn_lock); soup_address_resolve_async (addr, @@ -3098,6 +2992,13 @@ soup_session_class_init (SoupSessionClass *session_class) /* properties */ + g_object_class_install_property ( + object_class, PROP_SOCKET_PROPERTIES, + g_param_spec_boxed (SOUP_SESSION_SOCKET_PROPERTIES, + "Socket properties", + "Socket properties", + SOUP_TYPE_SOCKET_PROPERTIES, + G_PARAM_READABLE)); /** * SoupSession:proxy-uri: * |