From c4cbc7282aa97965555eec80697ebf2f26a91f71 Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Sat, 10 Sep 2011 20:33:50 +0300 Subject: [PATCH 07/18] IdleConnection: Handle connecting -> disconnected correctly In case an error is encountered while trying to connect, it is reported using tp_base_connection_disconnect_with_dbus_error, which changes the state of the parent TpBaseConnection from TP_CONNECTION_STATUS_CONNECTING to TP_CONNECTION_STATUS_DISCONNECTED. Hence this should not be done again in sconn_status_changed_cb. It is to be noted that when the Disconnect method is called, the parent's status is immediately set to disconnected, and when the underlying network connection finally disconnects and emits "status-changed" we still need to finish shutting down the connection in the callback. This leads to a situation where it may appear that the state is changing from disconnected to disconnected, but it is actually not so. Also, until the underlying network connection is successfully made, priv->conn does not point to a valid IdleServerConnection. Therefore the disconnect method should not be called on the underlying network connection before that. Fixes: https://bugs.freedesktop.org/37145 --- src/idle-connection.c | 24 ++++++++++++++---------- 1 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/idle-connection.c b/src/idle-connection.c index 0080706..24ad75b 100644 --- a/src/idle-connection.c +++ b/src/idle-connection.c @@ -554,7 +554,8 @@ static void _iface_disconnected(TpBaseConnection *self) { IdleConnectionPrivate *priv = IDLE_CONNECTION_GET_PRIVATE(conn); /* we never got around to actually creating the connection - * iface object, so don't try to send any traffic down it */ + * iface object because we were still trying to connect, so + * don't try to send any traffic down it */ if (priv->conn == NULL) { return; } @@ -576,11 +577,14 @@ static void _iface_shut_down(TpBaseConnection *self) { if (priv->quitting) return; - if (priv->sconn_status != SERVER_CONNECTION_STATE_NOT_CONNECTED) { + /* we never got around to actually creating the connection + * iface object because we were still trying to connect, so + * don't try to send any traffic down it */ + if (priv->conn == NULL) { + g_idle_add(_finish_shutdown_idle_func, self);; + } else { if (!idle_server_connection_disconnect(priv->conn, &error)) g_error_free(error); - } else { - g_idle_add(_finish_shutdown_idle_func, self);; } } @@ -738,13 +742,13 @@ static void sconn_status_changed_cb(IdleServerConnection *sconn, IdleServerConne switch (state) { case SERVER_CONNECTION_STATE_NOT_CONNECTED: - if (conn->parent.status == TP_CONNECTION_STATUS_CONNECTING) { - connection_connect_cb(conn, FALSE, TP_CONNECTION_STATUS_REASON_NETWORK_ERROR); - connection_disconnect_cb(conn, tp_reason); - } - else { + /* when the Disconnect method is called, the parent's status is + * immediately set to disconnected, and when the underlying network + * connection finally disconnects and triggers this callback + * we need to finish shutting down the connection -- so we can only + * ignore the case where the parent's status is connecting */ + if (conn->parent.status != TP_CONNECTION_STATUS_CONNECTING) connection_disconnect_cb(conn, tp_reason); - } break; case SERVER_CONNECTION_STATE_CONNECTING: -- 1.7.6.2