From 09adf1aeb7c1521fc35238489dddd29f13ef4357 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 9 Dec 2013 12:16:05 +0100 Subject: 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.) --- libsoup/Makefile.am | 2 + libsoup/soup-connection.c | 1 - libsoup/soup-misc-private.h | 4 + libsoup/soup-misc.c | 17 ++- libsoup/soup-session-host.c | 249 +++++++++++++++++++++++++++++++++++++++++ libsoup/soup-session-host.h | 57 ++++++++++ libsoup/soup-session-private.h | 2 + libsoup/soup-session.c | 220 ++++++++++-------------------------- 8 files changed, 387 insertions(+), 165 deletions(-) create mode 100644 libsoup/soup-session-host.c create mode 100644 libsoup/soup-session-host.h diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am index ddf52425..d95e5a54 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 48df8e3c..b9e73c55 100644 --- a/libsoup/soup-connection.c +++ b/libsoup/soup-connection.c @@ -99,7 +99,6 @@ soup_connection_set_property (GObject *object, guint prop_id, else priv->ssl = FALSE; break; - break; case PROP_SSL_FALLBACK: priv->ssl_fallback = g_value_get_boolean (value); break; diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h index 78265330..3a6cf12b 100644 --- a/libsoup/soup-misc-private.h +++ b/libsoup/soup-misc-private.h @@ -33,6 +33,10 @@ gboolean soup_uri_is_https (SoupURI *uri, char **aliases); 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..ff45a12f --- /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 +#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-private.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 7da6781d..d50dc5c0 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 */ SoupMessageQueueItem *soup_session_lookup_queue_item (SoupSession *session, SoupMessage *msg); diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c index 05bd5c86..d5c8a404 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-private.h" -#define HOST_KEEP_ALIVE 5 * 60 * 1000 /* 5 min in msecs */ - /** * SECTION:soup-session * @short_description: Soup session state object @@ -84,22 +83,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; @@ -157,7 +143,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); @@ -198,6 +183,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, + PROP_SOCKET_PROPERTIES, PROP_PROXY_URI, PROP_PROXY_RESOLVER, PROP_MAX_CONNS, @@ -239,10 +225,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; @@ -812,6 +798,10 @@ soup_session_get_property (GObject *object, guint prop_id, GTlsDatabase *tlsdb; switch (prop_id) { + case PROP_SOCKET_PROPERTIES: + ensure_socket_props (session); + g_value_set_boxed (value, priv->socket_props); + break; case PROP_LOCAL_ADDRESS: g_value_set_object (value, priv->local_addr); break; @@ -987,35 +977,6 @@ 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) @@ -1043,9 +1004,11 @@ get_host_for_uri (SoupSession *session, SoupURI *uri) soup_uri_free (uri_tmp); if (https) - g_hash_table_insert (priv->https_hosts, host->uri, host); + 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; } @@ -1057,21 +1020,6 @@ get_host_for_message (SoupSession *session, SoupMessage *msg) return get_host_for_uri (session, soup_message_get_uri (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, @@ -1293,7 +1241,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)) { @@ -1385,32 +1333,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 @@ -1422,26 +1370,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); @@ -1511,7 +1441,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); @@ -1600,8 +1530,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; @@ -1801,74 +1731,35 @@ get_connection_for_host (SoupSession *session, { SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); SoupConnection *conn; - GSList *conns; - int num_pending = 0; 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; - } - - ensure_socket_props (session); - conn = g_object_new (SOUP_TYPE_CONNECTION, - SOUP_CONNECTION_REMOTE_URI, host->uri, - SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback, - SOUP_CONNECTION_SOCKET_PROPERTIES, priv->socket_props, - NULL); - - 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; @@ -2544,7 +2435,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, @@ -3154,6 +3045,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: * -- cgit v1.2.1