[evolution-data-server/evolution-data-server-3-12] [IMAPx] Automatically limit maximum number of concurrent connections
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/evolution-data-server-3-12] [IMAPx] Automatically limit maximum number of concurrent connections
- Date: Thu, 17 Apr 2014 16:38:24 +0000 (UTC)
commit ddfe83e7d68912faa0f8c21f78cc9e9037d3c0e6
Author: Milan Crha <mcrha redhat com>
Date: Thu Apr 17 18:34:00 2014 +0200
[IMAPx] Automatically limit maximum number of concurrent connections
In case a user has set more connections than the server has allowed,
the IMAPx may limit the connection count automatically, instead of
panic and close already established connections.
camel/providers/imapx/camel-imapx-conn-manager.c | 43 +++++++++++++++++++---
camel/providers/imapx/camel-imapx-server.c | 25 ++++++++++++-
camel/providers/imapx/camel-imapx-server.h | 8 ++++
camel/providers/imapx/camel-imapx-store.c | 22 +++++++++++-
camel/providers/imapx/camel-imapx-store.h | 5 ++-
5 files changed, 94 insertions(+), 9 deletions(-)
---
diff --git a/camel/providers/imapx/camel-imapx-conn-manager.c
b/camel/providers/imapx/camel-imapx-conn-manager.c
index 0980c2e..a83cacf 100644
--- a/camel/providers/imapx/camel-imapx-conn-manager.c
+++ b/camel/providers/imapx/camel-imapx-conn-manager.c
@@ -46,6 +46,7 @@ struct _CamelIMAPXConnManagerPrivate {
GList *connections;
GWeakRef store;
GRWLock rw_lock;
+ guint limit_max_connections;
};
struct _ConnectionInfo {
@@ -577,6 +578,10 @@ imapx_find_connection_unlocked (CamelIMAPXConnManager *con_man,
camel_imapx_settings_get_concurrent_connections (
CAMEL_IMAPX_SETTINGS (settings));
+ if (con_man->priv->limit_max_connections > 0 &&
+ con_man->priv->limit_max_connections < concurrent_connections)
+ concurrent_connections = con_man->priv->limit_max_connections;
+
g_object_unref (settings);
/* XXX Have a dedicated connection for INBOX ? */
@@ -757,9 +762,9 @@ imapx_create_new_connection_unlocked (CamelIMAPXConnManager *con_man,
* we should not have multiple IMAPX connections trying to
* authenticate at once, so this should be thread-safe.
*/
- camel_imapx_store_set_connecting_server (imapx_store, is);
+ camel_imapx_store_set_connecting_server (imapx_store, is, con_man->priv->connections != NULL);
success = camel_imapx_server_connect (is, cancellable, error);
- camel_imapx_store_set_connecting_server (imapx_store, NULL);
+ camel_imapx_store_set_connecting_server (imapx_store, NULL, FALSE);
if (!success) {
g_clear_object (&is);
@@ -843,9 +848,35 @@ camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
/* Check if we got cancelled while waiting for the lock. */
if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
is = imapx_find_connection_unlocked (con_man, folder_name, for_expensive_job);
- if (is == NULL)
- is = imapx_create_new_connection_unlocked (
- con_man, folder_name, cancellable, error);
+ if (is == NULL) {
+ GError *local_error = NULL;
+
+ is = imapx_create_new_connection_unlocked (con_man, folder_name, cancellable,
&local_error);
+
+ if (!is) {
+ gboolean limit_connections =
+ g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
+ CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
+ con_man->priv->connections;
+
+ c ('*', "Failed to open a new connection, while having %d opened, with error:
%s; will limit connections: %s\n",
+ g_list_length (con_man->priv->connections),
+ local_error ? local_error->message : "Unknown error",
+ limit_connections ? "yes" : "no");
+
+ if (limit_connections) {
+ /* limit to one-less than current connection count - be nice to the
server */
+ con_man->priv->limit_max_connections = g_list_length
(con_man->priv->connections) - 1;
+ if (!con_man->priv->limit_max_connections)
+ con_man->priv->limit_max_connections = 1;
+
+ g_clear_error (&local_error);
+ is = imapx_find_connection_unlocked (con_man, folder_name,
for_expensive_job);
+ } else {
+ g_propagate_error (error, local_error);
+ }
+ }
+ }
}
CON_WRITE_UNLOCK (con_man);
@@ -930,6 +961,8 @@ camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man)
CON_WRITE_LOCK (con_man);
+ c('*', "Closing all %d connections\n", g_list_length (con_man->priv->connections));
+
g_list_free_full (
con_man->priv->connections,
(GDestroyNotify) connection_info_cancel_and_unref);
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 45e3e77..2c39f26 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -82,6 +82,8 @@
#define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
#endif
+G_DEFINE_QUARK (camel-imapx-server-error-quark, camel_imapx_server_error)
+
extern gint camel_application_is_exiting;
/* Job-specific structs */
@@ -5015,8 +5017,27 @@ camel_imapx_server_authenticate (CamelIMAPXServer *is,
result = CAMEL_AUTHENTICATION_ERROR;
else if (ic->status->result == IMAPX_OK)
result = CAMEL_AUTHENTICATION_ACCEPTED;
- else
- result = CAMEL_AUTHENTICATION_REJECTED;
+ else if (ic->status->result == IMAPX_NO) {
+ if (camel_imapx_store_is_connecting_concurrent_connection (store)) {
+ /* At least one connection succeeded, probably max connection limit
+ set on the server had been reached, thus use special error code
+ for it, to instruct the connection manager to decrease the limit
+ and use already created connection. */
+ g_set_error_literal (
+ error, CAMEL_IMAPX_SERVER_ERROR,
+ CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED,
+ ic->status->text ? ic->status->text : _("Unknown error"));
+ result = CAMEL_AUTHENTICATION_ERROR;
+ } else {
+ result = CAMEL_AUTHENTICATION_REJECTED;
+ }
+ } else {
+ g_set_error_literal (
+ error, CAMEL_SERVICE_ERROR,
+ CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+ ic->status->text ? ic->status->text : _("Unknown error"));
+ result = CAMEL_AUTHENTICATION_ERROR;
+ }
/* Forget old capabilities after login. */
if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
diff --git a/camel/providers/imapx/camel-imapx-server.h b/camel/providers/imapx/camel-imapx-server.h
index 3842b33..1bc4c22 100644
--- a/camel/providers/imapx/camel-imapx-server.h
+++ b/camel/providers/imapx/camel-imapx-server.h
@@ -44,8 +44,16 @@
(G_TYPE_INSTANCE_GET_CLASS \
((obj), CAMEL_TYPE_IMAPX_SERVER, CamelIMAPXServerClass))
+#define CAMEL_IMAPX_SERVER_ERROR (camel_imapx_server_error_quark ())
+
G_BEGIN_DECLS
+typedef enum {
+ CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED
+} CamelIMAPXServerError;
+
+GQuark camel_imapx_server_error_quark (void) G_GNUC_CONST;
+
/* Avoid a circular reference. */
struct _CamelIMAPXStore;
struct _CamelIMAPXSettings;
diff --git a/camel/providers/imapx/camel-imapx-store.c b/camel/providers/imapx/camel-imapx-store.c
index b69ed0f..eb7c25f 100644
--- a/camel/providers/imapx/camel-imapx-store.c
+++ b/camel/providers/imapx/camel-imapx-store.c
@@ -57,7 +57,10 @@
struct _CamelIMAPXStorePrivate {
CamelIMAPXConnManager *con_man;
+
CamelIMAPXServer *connecting_server;
+ gboolean is_concurrent_connection;
+
gulong mailbox_created_handler_id;
gulong mailbox_renamed_handler_id;
gulong mailbox_updated_handler_id;
@@ -2496,7 +2499,8 @@ camel_imapx_store_ref_server (CamelIMAPXStore *store,
/* The caller should hold the store->priv->server_lock already, when calling this */
void
camel_imapx_store_set_connecting_server (CamelIMAPXStore *store,
- CamelIMAPXServer *server)
+ CamelIMAPXServer *server,
+ gboolean is_concurrent_connection)
{
g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
@@ -2511,9 +2515,25 @@ camel_imapx_store_set_connecting_server (CamelIMAPXStore *store,
store->priv->connecting_server = g_object_ref (server);
}
+ store->priv->is_concurrent_connection = is_concurrent_connection;
+
g_mutex_unlock (&store->priv->server_lock);
}
+gboolean
+camel_imapx_store_is_connecting_concurrent_connection (CamelIMAPXStore *imapx_store)
+{
+ gboolean res;
+
+ g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store), FALSE);
+
+ g_mutex_lock (&imapx_store->priv->server_lock);
+ res = imapx_store->priv->is_concurrent_connection;
+ g_mutex_unlock (&imapx_store->priv->server_lock);
+
+ return res;
+}
+
void
camel_imapx_store_folder_op_done (CamelIMAPXStore *store,
CamelIMAPXServer *server,
diff --git a/camel/providers/imapx/camel-imapx-store.h b/camel/providers/imapx/camel-imapx-store.h
index 8ef34ba..80cde3c 100644
--- a/camel/providers/imapx/camel-imapx-store.h
+++ b/camel/providers/imapx/camel-imapx-store.h
@@ -71,7 +71,10 @@ CamelIMAPXServer *
GError **error);
void camel_imapx_store_set_connecting_server
(CamelIMAPXStore *store,
- CamelIMAPXServer *server);
+ CamelIMAPXServer *server,
+ gboolean is_concurrent_connection);
+gboolean camel_imapx_store_is_connecting_concurrent_connection
+ (CamelIMAPXStore *imapx_store);
void camel_imapx_store_folder_op_done
(CamelIMAPXStore *store,
CamelIMAPXServer *server,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]