aboutsummaryrefslogtreecommitdiff
path: root/libmm-glib
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2021-05-17 21:33:32 +0200
committerAleksander Morgado <aleksander@aleksander.es>2021-05-23 01:22:07 +0200
commitde6b1324cb80413e552806f75c70be72cc41e933 (patch)
tree8f20a6bfc9a1ae4f4288e11a77aa54d1d178d8ce /libmm-glib
parentff45d292ee75b0e49c3de3677211218445659884 (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.c119
-rw-r--r--libmm-glib/mm-bearer.h3
-rw-r--r--libmm-glib/mm-common-helpers.c50
-rw-r--r--libmm-glib/mm-common-helpers.h5
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 */