gthreadedresolver: Centralise GTask return handling in worker threads

This will make it simpler to handle timeouts and cancellation in future,
as all the logic for working out whether to return will all be in one
place, and all the lookup-specific code is now implemented in simple
sync functions which don’t need to care about `GTask`s.

This commit introduces no functional changes, it’s just setting up for
the following commit.

Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
This commit is contained in:
Philip Withnall 2023-03-30 13:42:19 +01:00
parent 694394207c
commit 84074ce757

View File

@ -45,6 +45,11 @@ struct _GThreadedResolver
G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER) G_DEFINE_TYPE (GThreadedResolver, g_threaded_resolver, G_TYPE_RESOLVER)
static void threaded_resolver_worker_cb (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable);
static void static void
g_threaded_resolver_init (GThreadedResolver *gtr) g_threaded_resolver_init (GThreadedResolver *gtr)
{ {
@ -143,14 +148,12 @@ lookup_data_free (LookupData *data)
g_free (data); g_free (data);
} }
static void static GList *
do_lookup_by_name (GTask *task, do_lookup_by_name (const gchar *hostname,
gpointer source_object, int address_family,
gpointer task_data, GCancellable *cancellable,
GCancellable *cancellable) GError **error)
{ {
LookupData *lookup_data = task_data;
const char *hostname = lookup_data->lookup_by_name.hostname;
struct addrinfo *res = NULL; struct addrinfo *res = NULL;
GList *addresses; GList *addresses;
gint retval; gint retval;
@ -166,7 +169,7 @@ do_lookup_by_name (GTask *task,
addrinfo_hints.ai_socktype = SOCK_STREAM; addrinfo_hints.ai_socktype = SOCK_STREAM;
addrinfo_hints.ai_protocol = IPPROTO_TCP; addrinfo_hints.ai_protocol = IPPROTO_TCP;
addrinfo_hints.ai_family = lookup_data->lookup_by_name.address_family; addrinfo_hints.ai_family = address_family;
retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res); retval = getaddrinfo (hostname, NULL, &addrinfo_hints, &res);
if (retval == 0) if (retval == 0)
@ -192,21 +195,23 @@ do_lookup_by_name (GTask *task,
g_object_unref (sockaddr); g_object_unref (sockaddr);
} }
g_clear_pointer (&res, freeaddrinfo);
if (addresses != NULL) if (addresses != NULL)
{ {
addresses = g_list_reverse (addresses); addresses = g_list_reverse (addresses);
g_task_return_pointer (task, addresses, return g_steal_pointer (&addresses);
(GDestroyNotify)g_resolver_free_addresses);
} }
else else
{ {
/* All addresses failed to be converted to GSocketAddresses. */ /* All addresses failed to be converted to GSocketAddresses. */
g_task_return_new_error (task, g_set_error (error,
G_RESOLVER_ERROR, G_RESOLVER_ERROR,
G_RESOLVER_ERROR_NOT_FOUND, G_RESOLVER_ERROR_NOT_FOUND,
_("Error resolving “%s”: %s"), _("Error resolving “%s”: %s"),
hostname, hostname,
_("No valid addresses were found")); _("No valid addresses were found"));
return NULL;
} }
} }
else else
@ -219,16 +224,17 @@ do_lookup_by_name (GTask *task,
error_message = g_strdup ("[Invalid UTF-8]"); error_message = g_strdup ("[Invalid UTF-8]");
#endif #endif
g_task_return_new_error (task, g_clear_pointer (&res, freeaddrinfo);
g_set_error (error,
G_RESOLVER_ERROR, G_RESOLVER_ERROR,
g_resolver_error_from_addrinfo_error (retval), g_resolver_error_from_addrinfo_error (retval),
_("Error resolving “%s”: %s"), _("Error resolving “%s”: %s"),
hostname, error_message); hostname, error_message);
g_free (error_message); g_free (error_message);
}
if (res) return NULL;
freeaddrinfo (res); }
} }
static GList * static GList *
@ -247,7 +253,7 @@ lookup_by_name (GResolver *resolver,
g_task_set_name (task, "[gio] resolver lookup"); g_task_set_name (task, "[gio] resolver lookup");
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free);
g_task_set_return_on_cancel (task, TRUE); g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread_sync (task, do_lookup_by_name); g_task_run_in_thread_sync (task, threaded_resolver_worker_cb);
addresses = g_task_propagate_pointer (task, error); addresses = g_task_propagate_pointer (task, error);
g_object_unref (task); g_object_unref (task);
@ -289,7 +295,7 @@ lookup_by_name_with_flags (GResolver *resolver,
g_task_set_name (task, "[gio] resolver lookup"); g_task_set_name (task, "[gio] resolver lookup");
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free);
g_task_set_return_on_cancel (task, TRUE); g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread_sync (task, do_lookup_by_name); g_task_run_in_thread_sync (task, threaded_resolver_worker_cb);
addresses = g_task_propagate_pointer (task, error); addresses = g_task_propagate_pointer (task, error);
g_object_unref (task); g_object_unref (task);
@ -317,7 +323,7 @@ lookup_by_name_with_flags_async (GResolver *resolver,
g_task_set_name (task, "[gio] resolver lookup"); g_task_set_name (task, "[gio] resolver lookup");
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free);
g_task_set_return_on_cancel (task, TRUE); g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, do_lookup_by_name); g_task_run_in_thread (task, threaded_resolver_worker_cb);
g_object_unref (task); g_object_unref (task);
} }
@ -356,14 +362,11 @@ lookup_by_name_with_flags_finish (GResolver *resolver,
return g_task_propagate_pointer (G_TASK (result), error); return g_task_propagate_pointer (G_TASK (result), error);
} }
static void static gchar *
do_lookup_by_address (GTask *task, do_lookup_by_address (GInetAddress *address,
gpointer source_object, GCancellable *cancellable,
gpointer task_data, GError **error)
GCancellable *cancellable)
{ {
LookupData *data = task_data;
GInetAddress *address = data->lookup_by_address.address;
struct sockaddr_storage sockaddr_address; struct sockaddr_storage sockaddr_address;
gsize sockaddr_address_size; gsize sockaddr_address_size;
GSocketAddress *gsockaddr; GSocketAddress *gsockaddr;
@ -379,7 +382,7 @@ do_lookup_by_address (GTask *task,
retval = getnameinfo ((struct sockaddr *) &sockaddr_address, sockaddr_address_size, retval = getnameinfo ((struct sockaddr *) &sockaddr_address, sockaddr_address_size,
name, sizeof (name), NULL, 0, NI_NAMEREQD); name, sizeof (name), NULL, 0, NI_NAMEREQD);
if (retval == 0) if (retval == 0)
g_task_return_pointer (task, g_strdup (name), g_free); return g_strdup (name);
else else
{ {
gchar *phys; gchar *phys;
@ -393,7 +396,7 @@ do_lookup_by_address (GTask *task,
#endif #endif
phys = g_inet_address_to_string (address); phys = g_inet_address_to_string (address);
g_task_return_new_error (task, g_set_error (error,
G_RESOLVER_ERROR, G_RESOLVER_ERROR,
g_resolver_error_from_addrinfo_error (retval), g_resolver_error_from_addrinfo_error (retval),
_("Error reverse-resolving “%s”: %s"), _("Error reverse-resolving “%s”: %s"),
@ -401,6 +404,8 @@ do_lookup_by_address (GTask *task,
error_message); error_message);
g_free (phys); g_free (phys);
g_free (error_message); g_free (error_message);
return NULL;
} }
} }
@ -420,7 +425,7 @@ lookup_by_address (GResolver *resolver,
g_task_set_name (task, "[gio] resolver lookup"); g_task_set_name (task, "[gio] resolver lookup");
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free);
g_task_set_return_on_cancel (task, TRUE); g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread_sync (task, do_lookup_by_address); g_task_run_in_thread_sync (task, threaded_resolver_worker_cb);
name = g_task_propagate_pointer (task, error); name = g_task_propagate_pointer (task, error);
g_object_unref (task); g_object_unref (task);
@ -443,7 +448,7 @@ lookup_by_address_async (GResolver *resolver,
g_task_set_name (task, "[gio] resolver lookup"); g_task_set_name (task, "[gio] resolver lookup");
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free);
g_task_set_return_on_cancel (task, TRUE); g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, do_lookup_by_address); g_task_run_in_thread (task, threaded_resolver_worker_cb);
g_object_unref (task); g_object_unref (task);
} }
@ -1145,17 +1150,13 @@ int res_query(const char *, int, int, u_char *, int);
#endif #endif
#endif #endif
static void static GList *
do_lookup_records (GTask *task, do_lookup_records (const gchar *rrname,
gpointer source_object, GResolverRecordType record_type,
gpointer task_data, GCancellable *cancellable,
GCancellable *cancellable) GError **error)
{ {
LookupData *data = task_data;
const gchar *rrname = data->lookup_records.rrname;
GResolverRecordType record_type = data->lookup_records.record_type;
GList *records; GList *records;
GError *error = NULL;
#if defined(G_OS_UNIX) #if defined(G_OS_UNIX)
gint len = 512; gint len = 512;
@ -1179,9 +1180,9 @@ do_lookup_records (GTask *task,
struct __res_state res = { 0, }; struct __res_state res = { 0, };
if (res_ninit (&res) != 0) if (res_ninit (&res) != 0)
{ {
g_task_return_new_error (task, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL, g_set_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_INTERNAL,
_("Error resolving “%s”"), rrname); _("Error resolving “%s”"), rrname);
return; return NULL;
} }
#endif #endif
@ -1207,7 +1208,7 @@ do_lookup_records (GTask *task,
} }
herr = h_errno; herr = h_errno;
records = g_resolver_records_from_res_query (rrname, rrtype, answer->data, len, herr, &error); records = g_resolver_records_from_res_query (rrname, rrtype, answer->data, len, herr, error);
g_byte_array_free (answer, TRUE); g_byte_array_free (answer, TRUE);
#ifdef HAVE_RES_NQUERY #ifdef HAVE_RES_NQUERY
@ -1230,16 +1231,13 @@ do_lookup_records (GTask *task,
dnstype = g_resolver_record_type_to_dnstype (record_type); dnstype = g_resolver_record_type_to_dnstype (record_type);
status = DnsQuery_A (rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL); status = DnsQuery_A (rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL);
records = g_resolver_records_from_DnsQuery (rrname, dnstype, status, results, &error); records = g_resolver_records_from_DnsQuery (rrname, dnstype, status, results, error);
if (results != NULL) if (results != NULL)
DnsRecordListFree (results, DnsFreeRecordList); DnsRecordListFree (results, DnsFreeRecordList);
#endif #endif
if (records) return g_steal_pointer (&records);
g_task_return_pointer (task, records, (GDestroyNotify) free_records);
else
g_task_return_error (task, error);
} }
static GList * static GList *
@ -1261,7 +1259,7 @@ lookup_records (GResolver *resolver,
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free);
g_task_set_return_on_cancel (task, TRUE); g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread_sync (task, do_lookup_records); g_task_run_in_thread_sync (task, threaded_resolver_worker_cb);
records = g_task_propagate_pointer (task, error); records = g_task_propagate_pointer (task, error);
g_object_unref (task); g_object_unref (task);
@ -1287,7 +1285,7 @@ lookup_records_async (GResolver *resolver,
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free); g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) lookup_data_free);
g_task_set_return_on_cancel (task, TRUE); g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, do_lookup_records); g_task_run_in_thread (task, threaded_resolver_worker_cb);
g_object_unref (task); g_object_unref (task);
} }
@ -1301,6 +1299,58 @@ lookup_records_finish (GResolver *resolver,
return g_task_propagate_pointer (G_TASK (result), error); return g_task_propagate_pointer (G_TASK (result), error);
} }
static void
threaded_resolver_worker_cb (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
LookupData *data = task_data;
GError *local_error = NULL;
switch (data->lookup_type) {
case LOOKUP_BY_NAME:
{
GList *addresses = do_lookup_by_name (data->lookup_by_name.hostname,
data->lookup_by_name.address_family,
cancellable,
&local_error);
if (addresses != NULL)
g_task_return_pointer (task, g_steal_pointer (&addresses), (GDestroyNotify) g_resolver_free_addresses);
else
g_task_return_error (task, g_steal_pointer (&local_error));
}
break;
case LOOKUP_BY_ADDRESS:
{
gchar *name = do_lookup_by_address (data->lookup_by_address.address,
cancellable,
&local_error);
if (name != NULL)
g_task_return_pointer (task, g_steal_pointer (&name), g_free);
else
g_task_return_error (task, g_steal_pointer (&local_error));
}
break;
case LOOKUP_RECORDS:
{
GList *records = do_lookup_records (data->lookup_records.rrname,
data->lookup_records.record_type,
cancellable,
&local_error);
if (records != NULL)
g_task_return_pointer (task, g_steal_pointer (&records), (GDestroyNotify) free_records);
else
g_task_return_error (task, g_steal_pointer (&local_error));
}
break;
default:
g_assert_not_reached ();
}
}
static void static void
g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class) g_threaded_resolver_class_init (GThreadedResolverClass *threaded_class)