From b80deba63f3fafb46cfaa65a661f9929b5c1063b Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 30 Apr 2013 16:59:22 +0100 Subject: Connection: cancel connect_async when Disconnect() is called --- src/idle-connection.c | 12 +++++++-- src/idle-server-connection.c | 3 +-- tests/twisted/Makefile.am | 1 + .../connect/disconnect-before-socket-connected.py | 31 ++++++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 tests/twisted/connect/disconnect-before-socket-connected.py diff --git a/src/idle-connection.c b/src/idle-connection.c index b881295..182108e 100644 --- a/src/idle-connection.c +++ b/src/idle-connection.c @@ -152,6 +152,9 @@ struct _IdleConnectionPrivate { */ gboolean sconn_connected; + /* Used for idle_server_connection_connect_async(). */ + GCancellable *connect_cancellable; + /* When we sent a PING to the server which it hasn't PONGed for yet, or 0 if * there isn't a PING outstanding. */ @@ -408,6 +411,8 @@ static void idle_connection_dispose (GObject *object) { priv->conn = NULL; } + g_clear_object (&priv->connect_cancellable); + if (priv->queued_aliases_owners) tp_handle_set_destroy(priv->queued_aliases_owners); @@ -620,7 +625,8 @@ static void _iface_shut_down(TpBaseConnection *base) { if (priv->conn == NULL) { g_idle_add(_finish_shutdown_idle_func, self); } else if (!priv->sconn_connected) { - IDLE_DEBUG("TODO: cancel connecting"); + IDLE_DEBUG("cancelling connection"); + g_cancellable_cancel (priv->connect_cancellable); } else { idle_server_connection_disconnect_async(priv->conn, NULL, NULL, NULL); } @@ -762,7 +768,9 @@ static void _start_connecting_continue(IdleConnection *conn) { g_signal_connect(sconn, "disconnected", (GCallback)(sconn_disconnected_cb), conn); priv->conn = sconn; - idle_server_connection_connect_async(sconn, NULL, _connection_connect_ready, conn); + g_warn_if_fail (priv->connect_cancellable == NULL); + priv->connect_cancellable = g_cancellable_new (); + idle_server_connection_connect_async(sconn, priv->connect_cancellable, _connection_connect_ready, conn); } static gboolean keepalive_timeout_cb(gpointer user_data); diff --git a/src/idle-server-connection.c b/src/idle-server-connection.c index f1c7ce1..bc7a972 100644 --- a/src/idle-server-connection.c +++ b/src/idle-server-connection.c @@ -431,8 +431,7 @@ void idle_server_connection_connect_async(IdleServerConnection *conn, GCancellab result = g_simple_async_result_new(G_OBJECT(conn), callback, user_data, idle_server_connection_connect_async); - task = g_task_new (conn, cancellable, - _connect_to_host_ready, result); + task = g_task_new (conn, cancellable, _connect_to_host_ready, result); g_task_run_in_thread (task, _connect_in_thread); change_state(conn, SERVER_CONNECTION_STATE_CONNECTING, SERVER_CONNECTION_STATE_REASON_REQUESTED); diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am index 6063454..764f074 100644 --- a/tests/twisted/Makefile.am +++ b/tests/twisted/Makefile.am @@ -6,6 +6,7 @@ TWISTED_TESTS = \ connect/connect-reject-ssl.py \ connect/connect-fail.py \ connect/connect-fail-ssl.py \ + connect/disconnect-before-socket-connected.py \ connect/disconnect-during-cert-verification.py \ connect/ping.py \ connect/server-quit-ignore.py \ diff --git a/tests/twisted/connect/disconnect-before-socket-connected.py b/tests/twisted/connect/disconnect-before-socket-connected.py new file mode 100644 index 0000000..8fc89e0 --- /dev/null +++ b/tests/twisted/connect/disconnect-before-socket-connected.py @@ -0,0 +1,31 @@ +""" +Test disconnecting before the TCP session is established. +""" + +from idletest import exec_test +from servicetest import call_async + +def test(q, bus, conn, stream): + conn.Connect() + q.expect('dbus-signal', signal='StatusChanged', args=[1, 1]) + + # We want the call to Disconnect to reach Idle before the call to + # g_socket_client_connect_to_host(), which connects to this Python process, + # completes. I tried making the Twisted infrastructure stop calling + # .accept() but that doesn't seem to have any effect. + # + # But! All is not lost! Making a blocking call to Disconnect() does the + # job, because we block in libdbus and Twisted doesn't get a chance to poll + # the listening socket until Disconnect() returns. + conn.Disconnect() + + # The bug was that Idle would not try to cancel the in-progress connection + # attempt. It worked when the connection was blocked on TLS verification + # (see disconnect-during-cert-verification.py) because closing that channel + # (as a side-effect of disconnecting) caused the TCP connection attempt to + # fail, but didn't work in this case. + q.expect('dbus-signal', signal='StatusChanged', args=[2, 1]) + +if __name__ == '__main__': + exec_test(test) + -- cgit v1.2.3