[glib/wip/tingping/gsocketclient-criticals] gsocketclient: Fix criticals
- From: Patrick Griffis <pgriffis src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/tingping/gsocketclient-criticals] gsocketclient: Fix criticals
- Date: Tue, 29 Jan 2019 15:14:26 +0000 (UTC)
commit 577aeedade4bc76d9d40ef0f374be2ea056fc744
Author: Patrick Griffis <pgriffis igalia com>
Date: Tue Jan 29 10:07:06 2019 -0500
gsocketclient: Fix criticals
This ensures the parent GTask is kept alive as long as an enumeration
is running and trying to connect.
Closes #1646
Closes #1649
gio/gsocketclient.c | 61 +++++++++++++++++++++++++++---------------
gio/tests/gsocketclient-slow.c | 54 ++++++++++++++++++++++++++++++++++++-
2 files changed, 92 insertions(+), 23 deletions(-)
---
diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c
index 5c6513c3d..57ebc8240 100644
--- a/gio/gsocketclient.c
+++ b/gio/gsocketclient.c
@@ -1327,7 +1327,7 @@ g_socket_client_connect_to_uri (GSocketClient *client,
typedef struct
{
- GTask *task;
+ GTask *task; /* unowned */
GSocketClient *client;
GSocketConnectable *connectable;
@@ -1345,6 +1345,7 @@ static void connection_attempt_unref (gpointer attempt);
static void
g_socket_client_async_connect_data_free (GSocketClientAsyncConnectData *data)
{
+ data->task = NULL;
g_clear_object (&data->connectable);
g_clear_object (&data->enumerator);
g_clear_object (&data->proxy_addr);
@@ -1444,13 +1445,19 @@ set_last_error (GSocketClientAsyncConnectData *data,
}
static void
-enumerator_next_async (GSocketClientAsyncConnectData *data)
+enumerator_next_async (GSocketClientAsyncConnectData *data,
+ gboolean add_task_ref)
{
/* We need to cleanup the state */
g_clear_object (&data->socket);
g_clear_object (&data->proxy_addr);
g_clear_object (&data->connection);
+ /* Each enumeration takes a ref. This arg just avoids repeated unrefs when
+ an enumeration starts another enumeration */
+ if (add_task_ref)
+ g_object_ref (data->task);
+
g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVING, data->connectable, NULL);
g_socket_address_enumerator_next_async (data->enumerator,
g_task_get_cancellable (data->task),
@@ -1478,7 +1485,7 @@ g_socket_client_tls_handshake_callback (GObject *object,
else
{
g_object_unref (object);
- enumerator_next_async (data);
+ enumerator_next_async (data, FALSE);
}
}
@@ -1509,7 +1516,7 @@ g_socket_client_tls_handshake (GSocketClientAsyncConnectData *data)
}
else
{
- enumerator_next_async (data);
+ enumerator_next_async (data, FALSE);
}
}
@@ -1530,13 +1537,24 @@ g_socket_client_proxy_connect_callback (GObject *object,
}
else
{
- enumerator_next_async (data);
+ enumerator_next_async (data, FALSE);
return;
}
g_socket_client_tls_handshake (data);
}
+static gboolean
+task_completed_or_cancelled (GTask *task)
+{
+ if (g_task_get_completed (task))
+ return TRUE;
+ else if (g_task_return_error_if_cancelled (task))
+ return TRUE;
+ else
+ return FALSE;
+}
+
static void
g_socket_client_connected_callback (GObject *source,
GAsyncResult *result,
@@ -1549,8 +1567,7 @@ g_socket_client_connected_callback (GObject *source,
GProxy *proxy;
const gchar *protocol;
- /* data is NULL once the task is completed */
- if (data && g_task_return_error_if_cancelled (data->task))
+ if (g_cancellable_is_cancelled (attempt->cancellable) || task_completed_or_cancelled (data->task))
{
g_object_unref (data->task);
connection_attempt_unref (attempt);
@@ -1570,17 +1587,15 @@ g_socket_client_connected_callback (GObject *source,
{
clarify_connect_error (error, data->connectable, attempt->address);
set_last_error (data, error);
+ connection_attempt_remove (attempt);
+ enumerator_next_async (data, FALSE);
}
else
- g_clear_error (&error);
-
- if (data)
{
- connection_attempt_remove (attempt);
- enumerator_next_async (data);
+ g_clear_error (&error);
+ g_object_unref (data->task);
+ connection_attempt_unref (attempt);
}
- else
- connection_attempt_unref (attempt);
return;
}
@@ -1592,7 +1607,6 @@ g_socket_client_connected_callback (GObject *source,
{
ConnectionAttempt *attempt_entry = l->data;
g_cancellable_cancel (attempt_entry->cancellable);
- attempt_entry->data = NULL;
connection_attempt_unref (attempt_entry);
}
g_slist_free (data->connection_attempts);
@@ -1625,7 +1639,7 @@ g_socket_client_connected_callback (GObject *source,
G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("Proxying over a non-TCP connection is not supported."));
- enumerator_next_async (data);
+ enumerator_next_async (data, FALSE);
}
else if (g_hash_table_contains (data->client->priv->app_proxies, protocol))
{
@@ -1652,7 +1666,7 @@ g_socket_client_connected_callback (GObject *source,
_("Proxy protocol ā%sā is not supported."),
protocol);
- enumerator_next_async (data);
+ enumerator_next_async (data, FALSE);
}
}
@@ -1661,7 +1675,7 @@ on_connection_attempt_timeout (gpointer data)
{
ConnectionAttempt *attempt = data;
- enumerator_next_async (attempt->data);
+ enumerator_next_async (attempt->data, TRUE);
g_clear_pointer (&attempt->timeout_source, g_source_unref);
return G_SOURCE_REMOVE;
@@ -1687,7 +1701,7 @@ g_socket_client_enumerator_callback (GObject *object,
ConnectionAttempt *attempt;
GError *error = NULL;
- if (g_task_return_error_if_cancelled (data->task))
+ if (task_completed_or_cancelled (data->task))
{
g_object_unref (data->task);
return;
@@ -1698,7 +1712,10 @@ g_socket_client_enumerator_callback (GObject *object,
if (address == NULL)
{
if (data->connection_attempts)
- return;
+ {
+ g_object_unref (data->task);
+ return;
+ }
g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, NULL);
if (!error)
@@ -1732,7 +1749,7 @@ g_socket_client_enumerator_callback (GObject *object,
if (socket == NULL)
{
g_object_unref (address);
- enumerator_next_async (data);
+ enumerator_next_async (data, FALSE);
return;
}
@@ -1808,7 +1825,7 @@ g_socket_client_connect_async (GSocketClient *client,
g_task_set_source_tag (data->task, g_socket_client_connect_async);
g_task_set_task_data (data->task, data, (GDestroyNotify)g_socket_client_async_connect_data_free);
- enumerator_next_async (data);
+ enumerator_next_async (data, FALSE);
}
/**
diff --git a/gio/tests/gsocketclient-slow.c b/gio/tests/gsocketclient-slow.c
index bc7d02772..463d3185e 100644
--- a/gio/tests/gsocketclient-slow.c
+++ b/gio/tests/gsocketclient-slow.c
@@ -63,12 +63,64 @@ test_happy_eyeballs (void)
g_object_unref (client);
}
+static void
+on_connected_cancelled (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GSocketConnection *conn;
+ GError *error = NULL;
+
+ conn = g_socket_client_connect_to_uri_finish (G_SOCKET_CLIENT (source_object), result, &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_assert_null (conn);
+
+ g_main_loop_quit (user_data);
+}
+
+static int
+on_timer (GCancellable *cancel)
+{
+ g_cancellable_cancel (cancel);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+test_happy_eyeballs_cancel (void)
+{
+ GSocketClient *client;
+ GSocketService *service;
+ GError *error = NULL;
+ guint16 port;
+ GMainLoop *loop;
+ GCancellable *cancel;
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ service = g_socket_service_new ();
+ port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL, &error);
+ g_assert_no_error (error);
+ g_socket_service_start (service);
+
+ client = g_socket_client_new ();
+ cancel = g_cancellable_new ();
+ g_socket_client_connect_to_host_async (client, "localhost", port, cancel, on_connected_cancelled, loop);
+ g_timeout_add (1, (GSourceFunc) on_timer, cancel);
+ g_main_loop_run (loop);
+
+ g_main_loop_unref (loop);
+ g_object_unref (service);
+ g_object_unref (client);
+ g_object_unref (cancel);
+}
+
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
- g_test_add_func ("/socket-client/happy-eyeballs", test_happy_eyeballs);
+ g_test_add_func ("/socket-client/happy-eyeballs/slow", test_happy_eyeballs);
+ g_test_add_func ("/socket-client/happy-eyeballs/cancellation", test_happy_eyeballs_cancel);
return g_test_run ();
}
\ No newline at end of file
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]