diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2021-05-17 21:33:32 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2021-05-23 01:22:07 +0200 |
commit | de6b1324cb80413e552806f75c70be72cc41e933 (patch) | |
tree | 8f20a6bfc9a1ae4f4288e11a77aa54d1d178d8ce /libmm-glib | |
parent | ff45d292ee75b0e49c3de3677211218445659884 (diff) |
api,bearer: new 'ConnectionError' property
This new property will provide detailed information about the failed
connection attempt, or about the network initiated disconnection. The
property will be cleared only if a new connection attempt is
triggered, and so it can be used to investigate why a given attempt
failed without needing to be the one who triggered the attempt (e.g.
so that failures in NetworkManager-triggered connection attempts can
be investigated looking at the DBus API).
The property is built as a (ss) tuple, but the libmm-glib interface
provides methods to read this property as a GError.
Diffstat (limited to 'libmm-glib')
-rw-r--r-- | libmm-glib/mm-bearer.c | 119 | ||||
-rw-r--r-- | libmm-glib/mm-bearer.h | 3 | ||||
-rw-r--r-- | libmm-glib/mm-common-helpers.c | 50 | ||||
-rw-r--r-- | libmm-glib/mm-common-helpers.h | 5 |
4 files changed, 176 insertions, 1 deletions
diff --git a/libmm-glib/mm-bearer.c b/libmm-glib/mm-bearer.c index 1c6a1cdd..cc50244c 100644 --- a/libmm-glib/mm-bearer.c +++ b/libmm-glib/mm-bearer.c @@ -22,6 +22,7 @@ */ #include "mm-helpers.h" +#include "mm-common-helpers.h" #include "mm-bearer.h" /** @@ -58,6 +59,11 @@ struct _MMBearerPrivate { GMutex stats_mutex; guint stats_id; MMBearerStats *stats; + + /* Connection error */ + GMutex connection_error_mutex; + guint connection_error_id; + GError *connection_error; }; /*****************************************************************************/ @@ -757,6 +763,116 @@ mm_bearer_peek_stats (MMBearer *self) /*****************************************************************************/ +static void +connection_error_updated (MMBearer *self, + GParamSpec *pspec) +{ + g_mutex_lock (&self->priv->connection_error_mutex); + { + GVariant *tuple; + + g_clear_error (&self->priv->connection_error); + + tuple = mm_gdbus_bearer_get_connection_error (MM_GDBUS_BEARER (self)); + if (tuple) { + g_autoptr(GError) error = NULL; + + self->priv->connection_error = mm_common_error_from_tuple (tuple, &error); + if (error) + g_warning ("Invalid bearer connection error update received: %s", error->message); + } + } + g_mutex_unlock (&self->priv->connection_error_mutex); +} + +static void +ensure_internal_connection_error (MMBearer *self, + GError **dup) +{ + g_mutex_lock (&self->priv->connection_error_mutex); + { + /* If this is the first time ever asking for the object, setup the + * update listener and the initial object, if any. */ + if (!self->priv->connection_error_id) { + g_autoptr(GVariant) tuple = NULL; + + tuple = mm_gdbus_bearer_dup_connection_error (MM_GDBUS_BEARER (self)); + if (tuple) { + g_autoptr(GError) error = NULL; + + self->priv->connection_error = mm_common_error_from_tuple (tuple, &error); + if (error) + g_warning ("Invalid bearer connection error: %s", error->message); + } + + /* No need to clear this signal connection when freeing self */ + self->priv->connection_error_id = + g_signal_connect (self, + "notify::connection-error", + G_CALLBACK (connection_error_updated), + NULL); + } + + if (dup && self->priv->connection_error) + *dup = g_error_copy (self->priv->connection_error); + } + g_mutex_unlock (&self->priv->connection_error_mutex); +} + +/** + * mm_bearer_get_connection_error: + * @self: A #MMBearer. + * + * Gets a #GError specifying the connection error details, if any. + * + * <warning>The values reported by @self are not updated when the values in the + * interface change. Instead, the client is expected to call + * mm_bearer_get_connection_error() again to get a new #GError with the + * new values.</warning> + * + * Returns: (transfer full): A #GError that must be freed with + * g_error_free() or %NULL if none. + * + * Since: 1.18 + */ +GError * +mm_bearer_get_connection_error (MMBearer *self) +{ + GError *error = NULL; + + g_return_val_if_fail (MM_IS_BEARER (self), NULL); + + ensure_internal_connection_error (self, &error); + return error; +} + +/** + * mm_bearer_peek_connection_error: + * @self: A #MMBearer. + * + * Gets a #GError specifying the connection error details, if any. + * + * <warning>The returned value is only valid until the property changes so + * it is only safe to use this function on the thread where + * @self was constructed. Use mm_bearer_get_connection_error() if on another + * thread.</warning> + * + * Returns: (transfer none): A #GError, or %NULL if none. Do not + * free the returned value, it belongs to @self. + * + * Since: 1.18 + */ +GError * +mm_bearer_peek_connection_error (MMBearer *self) +{ + g_return_val_if_fail (MM_IS_BEARER (self), NULL); + + ensure_internal_connection_error (self, NULL); + return self->priv->connection_error; +} + +/*****************************************************************************/ + /** * mm_bearer_connect_finish: * @self: A #MMBearer. @@ -932,6 +1048,7 @@ mm_bearer_init (MMBearer *self) g_mutex_init (&self->priv->ipv6_config_mutex); g_mutex_init (&self->priv->properties_mutex); g_mutex_init (&self->priv->stats_mutex); + g_mutex_init (&self->priv->connection_error_mutex); } static void @@ -943,6 +1060,7 @@ finalize (GObject *object) g_mutex_clear (&self->priv->ipv6_config_mutex); g_mutex_clear (&self->priv->properties_mutex); g_mutex_clear (&self->priv->stats_mutex); + g_mutex_clear (&self->priv->connection_error_mutex); G_OBJECT_CLASS (mm_bearer_parent_class)->finalize (object); } @@ -956,6 +1074,7 @@ dispose (GObject *object) g_clear_object (&self->priv->ipv6_config); g_clear_object (&self->priv->properties); g_clear_object (&self->priv->stats); + g_clear_error (&self->priv->connection_error); G_OBJECT_CLASS (mm_bearer_parent_class)->dispose (object); } diff --git a/libmm-glib/mm-bearer.h b/libmm-glib/mm-bearer.h index 9f15e926..2240d7a2 100644 --- a/libmm-glib/mm-bearer.h +++ b/libmm-glib/mm-bearer.h @@ -120,6 +120,9 @@ MMBearerIpConfig *mm_bearer_peek_ipv6_config (MMBearer *self); MMBearerStats *mm_bearer_get_stats (MMBearer *self); MMBearerStats *mm_bearer_peek_stats (MMBearer *self); +GError *mm_bearer_get_connection_error (MMBearer *self); +GError *mm_bearer_peek_connection_error (MMBearer *self); + G_END_DECLS #endif /* _MM_BEARER_H_ */ diff --git a/libmm-glib/mm-common-helpers.c b/libmm-glib/mm-common-helpers.c index 50c4c830..fdd72a3b 100644 --- a/libmm-glib/mm-common-helpers.c +++ b/libmm-glib/mm-common-helpers.c @@ -1911,3 +1911,53 @@ mm_common_register_errors (void) return TRUE; } + +GError * +mm_common_error_from_tuple (GVariant *tuple, + GError **error) +{ + g_autoptr(GError) dbus_error = NULL; + g_autofree gchar *error_name = NULL; + g_autofree gchar *error_message = NULL; + + mm_common_register_errors (); + + if (!g_variant_is_of_type (tuple, G_VARIANT_TYPE ("(ss)"))) { + g_set_error (error, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Cannot create error from tuple: " + "invalid variant type received"); + return NULL; + } + + g_variant_get (tuple, "(ss)", &error_name, &error_message); + if (!error_name || !error_name[0]) + return NULL; + + /* We convert the error name into a proper GError (domain+code), but we + * don't attempt to give the error message to new_for_dbus_error() as that + * would generate a string we don't want (e.g. instead of just "Unknown + * Error" we would get "GDBus.Error:org.freedesktop.ModemManager1.Error.MobileEquipment.Unknown: Unknown error" + */ + dbus_error = g_dbus_error_new_for_dbus_error (error_name, ""); + + /* And now we build a new GError with same domain+code but with the received + * error message */ + return g_error_new (dbus_error->domain, dbus_error->code, "%s", error_message); +} + +GVariant * +mm_common_error_to_tuple (const GError *error) +{ + g_autofree gchar *error_name = NULL; + GVariant *tuple[2]; + + mm_common_register_errors (); + + error_name = g_dbus_error_encode_gerror (error); + tuple[0] = g_variant_new_string (error_name); + tuple[1] = g_variant_new_string (error->message); + + return g_variant_ref_sink (g_variant_new_tuple (tuple, 2)); +} diff --git a/libmm-glib/mm-common-helpers.h b/libmm-glib/mm-common-helpers.h index a0037cd0..1e778b30 100644 --- a/libmm-glib/mm-common-helpers.h +++ b/libmm-glib/mm-common-helpers.h @@ -202,6 +202,9 @@ gboolean mm_utils_ishexstr (const gchar *hex); gboolean mm_utils_check_for_single_value (guint32 value); /* DBus error handling */ -gboolean mm_common_register_errors (void); +gboolean mm_common_register_errors (void); +GError *mm_common_error_from_tuple (GVariant *tuple, + GError **error); +GVariant *mm_common_error_to_tuple (const GError *error); #endif /* MM_COMMON_HELPERS_H */ |