[telepathy-mission-control/telepathy-mission-control-5.2] McdConnection: if dropped (connected -> disconnected) more than 3 times in 2 minutes, stop reconnecting

Simon McVittie simon.mcvittie at collabora.co.uk
Thu Sep 17 09:15:20 PDT 2009


Also apply exponential backoff to reconnects within the first 2 minutes.

Previously, if connecting to a server that allowed us to connect but then
immediately dropped us again, we'd go into a tight loop, without the
benefit of the usual backoff algorithm.
---
 src/mcd-connection.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/src/mcd-connection.c b/src/mcd-connection.c
index 0862611..81f55d1 100644
--- a/src/mcd-connection.c
+++ b/src/mcd-connection.c
@@ -105,6 +105,8 @@ struct _McdConnectionPrivate
 
     guint reconnect_timer; 	/* timer for reconnection */
     guint reconnect_interval;
+    guint probation_timer;      /* for mcd_connection_probation_ended_cb */
+    guint probation_drop_count;
 
     /* Supported presences (values are McdPresenceInfo structs) */
     GHashTable *recognized_presences;
@@ -128,6 +130,9 @@ struct _McdConnectionPrivate
     /* FALSE until we got the first PresencesChanged for the self handle */
     guint got_presences_changed : 1;
 
+    /* TRUE if the last status change was to CONNECTED */
+    guint connected : 1;
+
     /* FALSE until mcd_connection_close() is called */
     guint closed : 1;
 
@@ -980,6 +985,30 @@ mcd_connection_reconnect (McdConnection *connection)
     return FALSE;
 }
 
+/* Number of seconds after which to assume the connection is basically stable.
+ * If we have too many disconnections within this time, assume something
+ * serious is wrong, and stop reconnecting. */
+#define PROBATION_SEC 120
+/* Maximum number of dropped connections within PROBATION_SEC. Connections
+ * that never reached CONNECTED state don't count towards this limit, so we'll
+ * keep retrying indefinitely for those (with exponential back-off). */
+#define PROBATION_MAX_DROPPED 3
+
+static gboolean
+mcd_connection_probation_ended_cb (gpointer user_data)
+{
+    McdConnection *self = user_data;
+
+    /* We've been connected for PROBATION_SEC seconds. We can probably now
+     * assume that the connection is stable */
+    DEBUG ("probation finished, assuming connection is stable: %s",
+           tp_proxy_get_object_path (self->priv->tp_conn));
+    self->priv->probation_timer = 0;
+    self->priv->probation_drop_count = 0;
+    self->priv->reconnect_interval = INITIAL_RECONNECTION_TIME;
+    return FALSE;
+}
+
 static void
 on_connection_status_changed (TpConnection *tp_conn, GParamSpec *pspec,
 			      McdConnection *connection)
@@ -1000,13 +1029,24 @@ on_connection_status_changed (TpConnection *tp_conn, GParamSpec *pspec,
         g_signal_emit (connection, signals[CONNECTION_STATUS_CHANGED], 0,
                        conn_status, conn_reason);
         priv->abort_reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
+        priv->connected = FALSE;
         break;
 
     case TP_CONNECTION_STATUS_CONNECTED:
         {
             g_signal_emit (connection, signals[CONNECTION_STATUS_CHANGED], 0,
                            conn_status, conn_reason);
-            priv->reconnect_interval = INITIAL_RECONNECTION_TIME;
+
+            if (priv->probation_timer == 0)
+            {
+                DEBUG ("setting probation timer (%d) seconds, for %s",
+                       PROBATION_SEC, tp_proxy_get_object_path (tp_conn));
+                priv->probation_timer = g_timeout_add_seconds (PROBATION_SEC,
+                    mcd_connection_probation_ended_cb, connection);
+                priv->probation_drop_count = 0;
+            }
+
+            priv->connected = TRUE;
         }
         break;
 
@@ -1018,6 +1058,8 @@ on_connection_status_changed (TpConnection *tp_conn, GParamSpec *pspec,
 	 * will hold a temporary ref to it.
 	 */
 	priv->abort_reason = conn_reason;
+        /* priv->connected will be reset to FALSE in the invalidated
+         * callback */
 	break;
 
     default:
@@ -1033,12 +1075,30 @@ mcd_connection_invalidated_cb (TpConnection *tp_conn,
                                McdConnection *connection)
 {
     McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
+
     DEBUG ("Proxy destroyed (%s)!", message);
 
     _mcd_connection_release_tp_connection (connection);
 
-    if (priv->abort_reason == TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED ||
-        priv->abort_reason == TP_CONNECTION_STATUS_REASON_NETWORK_ERROR)
+    if (priv->connected &&
+        priv->abort_reason != TP_CONNECTION_STATUS_REASON_REQUESTED &&
+        priv->probation_timer != 0)
+    {
+        DEBUG ("connection dropped while on probation: %s",
+               tp_proxy_get_object_path (tp_conn));
+
+        if (++priv->probation_drop_count > PROBATION_MAX_DROPPED)
+        {
+            DEBUG ("connection dropped too many times, will stop "
+                   "reconnecting");
+        }
+    }
+
+    priv->connected = FALSE;
+
+    if ((priv->abort_reason == TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED ||
+         priv->abort_reason == TP_CONNECTION_STATUS_REASON_NETWORK_ERROR) &&
+        priv->probation_drop_count <= PROBATION_MAX_DROPPED)
     {
         /* we were disconnected by a network error or by a connection manager
          * crash (in the latter case, we get NoneSpecified as a reason): don't
-- 
1.5.6.5




More information about the telepathy-commits mailing list