diff options
author | Philip Withnall <pwithnall@endlessos.org> | 2023-03-29 17:13:49 +0100 |
---|---|---|
committer | Philip Withnall <pwithnall@endlessos.org> | 2023-04-27 12:23:25 +0100 |
commit | bf92bae481be3619c8102340bdf8402f4827586d (patch) | |
tree | 3bafcae6775167be9fd01d189dc1105c23c61390 /gio | |
parent | c256af1c2d87afaa24c17ada66a4452ab48fa945 (diff) | |
download | glib-bf92bae481be3619c8102340bdf8402f4827586d.tar.gz |
gresolver: Add GResolver:timeout property
Without a timeout, some lookup requests can go on forever, typically due
to bugs in underlying systems.
This can have particularly significant effects on the Happy Eyeballs
algorithm in `GSocketClient`, which relies on multiple name lookups as
its first step.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2866
Diffstat (limited to 'gio')
-rw-r--r-- | gio/gresolver.c | 116 | ||||
-rw-r--r-- | gio/gresolver.h | 5 |
2 files changed, 119 insertions, 2 deletions
diff --git a/gio/gresolver.c b/gio/gresolver.c index 6a735e8d9..ac6fa4f7a 100644 --- a/gio/gresolver.c +++ b/gio/gresolver.c @@ -57,6 +57,12 @@ * making it easy to connect to a remote host/service. */ +typedef enum { + PROP_TIMEOUT = 1, +} GResolverProperty; + +static GParamSpec *props[PROP_TIMEOUT + 1] = { NULL, }; + enum { RELOAD, LAST_SIGNAL @@ -65,11 +71,11 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; struct _GResolverPrivate { + unsigned timeout_ms; + #ifdef G_OS_UNIX GMutex mutex; time_t resolv_conf_timestamp; /* protected by @mutex */ -#else - int dummy; #endif }; @@ -152,6 +158,42 @@ g_resolver_real_lookup_service_finish (GResolver *resolver, } static void +g_resolver_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GResolver *self = G_RESOLVER (object); + + switch ((GResolverProperty) prop_id) + { + case PROP_TIMEOUT: + g_value_set_uint (value, g_resolver_get_timeout (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_resolver_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GResolver *self = G_RESOLVER (object); + + switch ((GResolverProperty) prop_id) + { + case PROP_TIMEOUT: + g_resolver_set_timeout (self, g_value_get_uint (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void g_resolver_finalize (GObject *object) { #ifdef G_OS_UNIX @@ -168,6 +210,8 @@ g_resolver_class_init (GResolverClass *resolver_class) { GObjectClass *object_class = G_OBJECT_CLASS (resolver_class); + object_class->get_property = g_resolver_get_property; + object_class->set_property = g_resolver_set_property; object_class->finalize = g_resolver_finalize; /* Automatically pass these over to the lookup_records methods */ @@ -176,6 +220,31 @@ g_resolver_class_init (GResolverClass *resolver_class) resolver_class->lookup_service_finish = g_resolver_real_lookup_service_finish; /** + * GResolver:timeout: + * + * The timeout applied to all resolver lookups, in milliseconds. + * + * This may be changed through the lifetime of the #GResolver. The new value + * will apply to any lookups started after the change, but not to any + * already-ongoing lookups. + * + * If this is `0`, no timeout is applied to lookups. + * + * No timeout was applied to lookups before this property was added in + * GLib 2.78. + * + * Since: 2.78 + */ + props[PROP_TIMEOUT] = + g_param_spec_uint ("timeout", + P_("Timeout"), + P_("Timeout (ms) applied to all resolver lookups"), + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, G_N_ELEMENTS (props), props); + + /** * GResolver::reload: * @resolver: a #GResolver * @@ -1245,6 +1314,49 @@ g_resolver_get_serial (GResolver *resolver) } /** + * g_resolver_get_timeout: + * @resolver: a #GResolver + * + * Get the timeout applied to all resolver lookups. See #GResolver:timeout. + * + * Returns: the resolver timeout, in milliseconds, or `0` for no timeout + * Since: 2.78 + */ +unsigned +g_resolver_get_timeout (GResolver *resolver) +{ + GResolverPrivate *priv = g_resolver_get_instance_private (resolver); + + g_return_val_if_fail (G_IS_RESOLVER (resolver), 0); + + return priv->timeout_ms; +} + +/** + * g_resolver_set_timeout: + * @resolver: a #GResolver + * @timeout_ms: timeout in milliseconds, or `0` for no timeouts + * + * Set the timeout applied to all resolver lookups. See #GResolver:timeout. + * + * Since: 2.78 + */ +void +g_resolver_set_timeout (GResolver *resolver, + unsigned timeout_ms) +{ + GResolverPrivate *priv = g_resolver_get_instance_private (resolver); + + g_return_if_fail (G_IS_RESOLVER (resolver)); + + if (priv->timeout_ms == timeout_ms) + return; + + priv->timeout_ms = timeout_ms; + g_object_notify_by_pspec (G_OBJECT (resolver), props[PROP_TIMEOUT]); +} + +/** * g_resolver_error_quark: * * Gets the #GResolver Error Quark. diff --git a/gio/gresolver.h b/gio/gresolver.h index 2dffeadbf..9b9a8a81a 100644 --- a/gio/gresolver.h +++ b/gio/gresolver.h @@ -277,6 +277,11 @@ GList *g_resolver_lookup_records_finish (GResolver GIO_AVAILABLE_IN_ALL void g_resolver_free_targets (GList *targets); +GIO_AVAILABLE_IN_2_78 +unsigned g_resolver_get_timeout (GResolver *resolver); +GIO_AVAILABLE_IN_2_78 +void g_resolver_set_timeout (GResolver *resolver, + unsigned timeout_ms); /** * G_RESOLVER_ERROR: |