From 260c2e955c64a57eab727dafddd25683b77e972e Mon Sep 17 00:00:00 2001 From: "Ruslan N. Marchenko" Date: Wed, 16 Dec 2020 16:15:18 +0100 Subject: [PATCH] Initial SM support: handle reconnection --- src/connection.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/connection.c b/src/connection.c index 597442b48..2a59bd954 100644 --- a/src/connection.c +++ b/src/connection.c @@ -79,6 +79,7 @@ #endif static guint disco_reply_timeout = 5; +static GHashTable *connector_stash = NULL; #define DISCONNECT_TIMEOUT 5 @@ -1309,6 +1310,10 @@ gabble_connection_class_init (GabbleConnectionClass *gabble_connection_class) conn_contact_info_class_init (gabble_connection_class); tp_base_contact_list_mixin_class_init (parent_class); + + /* another static per-process leak */ + connector_stash = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_object_unref); } static void @@ -1943,6 +1948,63 @@ next_fallback_server (GabbleConnection *self, return TRUE; } +static gboolean +resuming_cb (WockyPorter *porter, + WockyStanza *resume, + GabbleConnection *self) +{ + TpBaseConnection *base = TP_BASE_CONNECTION (self); + DEBUG (""); + /* signal state change */ + tp_svc_connection_emit_status_changed (base, + TP_CONNECTION_STATUS_CONNECTING, TP_CONNECTION_STATUS_REASON_NETWORK_ERROR); + /* we want auto-resumption */ + return TRUE; +} + +static void +resumed_cb (WockyPorter *porter, + GabbleConnection *self) +{ + TpBaseConnection *base = TP_BASE_CONNECTION (self); + DEBUG (""); + tp_svc_connection_emit_status_changed (base, + TP_CONNECTION_STATUS_CONNECTED, TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED); +} + +static void +resume_done_cb (WockyPorter *porter, + GabbleConnection *self) +{ + DEBUG (""); +} + +static gboolean +resume_failed_cb (WockyPorter *porter, + GabbleConnection *self) +{ + WockyConnector *connector = NULL; + GError e = { TP_ERROR, TP_ERROR_CONNECTION_LOST, + "Connection resumption not possible, creating new connection" }; + + DEBUG ("Connection resumption not possible, stealing connector and closing"); + g_object_get (G_OBJECT (porter), + "connector", &connector, + NULL); + g_hash_table_insert (connector_stash, + g_strdup (conn_util_get_bare_self_jid (self)), connector); + /* We're gonna die soon, need to break ties with the world of livings */ + g_signal_handlers_disconnect_by_data (porter, self); + + /* Changing the state to Disconnect will call connection_shut_down which + * will properly close the porter. */ + gabble_connection_disconnect_with_tp_error (self, &e, + TP_CONNECTION_STATUS_REASON_NETWORK_ERROR); + + /* we want auto-reconnection to be confirmed by the new connection object */ + return FALSE; +} + /** * connector_connected * @@ -2026,6 +2088,20 @@ connector_connected (GabbleConnection *self, G_CALLBACK (remote_closed_cb), self); g_signal_connect (priv->porter, "remote-error", G_CALLBACK (remote_error_cb), self); +#if WOCKY_API_VERSION >= G_ENCODE_VERSION(0,2) + DEBUG (""); + /* SM events - happy path */ + g_signal_connect (priv->porter, "resuming", + G_CALLBACK (resuming_cb), self); + g_signal_connect (priv->porter, "resumed", + G_CALLBACK (resumed_cb), self); + g_signal_connect (priv->porter, "resume-done", + G_CALLBACK (resume_done_cb), self); + /* SM events - failure path, we need one of `resume-failed` and `reconnected` + */ + g_signal_connect (priv->porter, "resume-failed", + G_CALLBACK (resume_failed_cb), self); +#endif /* WOCKY_API_VERSION >= 0.2 */ g_signal_emit_by_name (self, "porter-available", priv->porter); connect_iq_callbacks (self); @@ -2253,6 +2329,19 @@ _gabble_connection_connect (TpBaseConnection *base, g_assert (priv->resource != NULL); jid = gabble_encode_jid (priv->username, priv->stream_server, NULL); + priv->connector = g_hash_table_lookup (connector_stash, jid); + if (priv->connector != NULL) + { + g_hash_table_remove (connector_stash, jid); + /* fast lane is ready */ + DEBUG ("Continue with existing connector"); + priv->cancellable = g_cancellable_new (); + wocky_connector_continue_async (priv->connector, priv->cancellable, + connector_connect_cb, conn); + g_free (jid); + return TRUE; + } + tls_handler = WOCKY_TLS_HANDLER (priv->server_tls_manager); priv->connector = wocky_connector_new (jid, priv->password, priv->resource, WOCKY_AUTH_REGISTRY (priv->auth_manager),