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.
This commit is contained in:
@@ -133,10 +133,11 @@ mmcli_bearer_shutdown (void)
|
|||||||
static void
|
static void
|
||||||
print_bearer_info (MMBearer *bearer)
|
print_bearer_info (MMBearer *bearer)
|
||||||
{
|
{
|
||||||
MMBearerIpConfig *ipv4_config;
|
g_autoptr(MMBearerIpConfig) ipv4_config = NULL;
|
||||||
MMBearerIpConfig *ipv6_config;
|
g_autoptr(MMBearerIpConfig) ipv6_config = NULL;
|
||||||
MMBearerProperties *properties;
|
g_autoptr(MMBearerProperties) properties = NULL;
|
||||||
MMBearerStats *stats;
|
g_autoptr(MMBearerStats) stats = NULL;
|
||||||
|
g_autoptr(GError) connection_error = NULL;
|
||||||
gint profile_id;
|
gint profile_id;
|
||||||
gchar *profile_id_str;
|
gchar *profile_id_str;
|
||||||
|
|
||||||
@@ -145,6 +146,7 @@ print_bearer_info (MMBearer *bearer)
|
|||||||
properties = mm_bearer_get_properties (bearer);
|
properties = mm_bearer_get_properties (bearer);
|
||||||
stats = mm_bearer_get_stats (bearer);
|
stats = mm_bearer_get_stats (bearer);
|
||||||
profile_id = mm_bearer_get_profile_id (bearer);
|
profile_id = mm_bearer_get_profile_id (bearer);
|
||||||
|
connection_error = mm_bearer_get_connection_error (bearer);
|
||||||
|
|
||||||
profile_id_str = (profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) ? g_strdup_printf ("%d", profile_id) : NULL;
|
profile_id_str = (profile_id != MM_3GPP_PROFILE_ID_UNKNOWN) ? g_strdup_printf ("%d", profile_id) : NULL;
|
||||||
|
|
||||||
@@ -152,6 +154,8 @@ print_bearer_info (MMBearer *bearer)
|
|||||||
mmcli_output_string (MMC_F_BEARER_GENERAL_TYPE, mm_bearer_type_get_string (mm_bearer_get_bearer_type (bearer)));
|
mmcli_output_string (MMC_F_BEARER_GENERAL_TYPE, mm_bearer_type_get_string (mm_bearer_get_bearer_type (bearer)));
|
||||||
|
|
||||||
mmcli_output_string (MMC_F_BEARER_STATUS_CONNECTED, mm_bearer_get_connected (bearer) ? "yes" : "no");
|
mmcli_output_string (MMC_F_BEARER_STATUS_CONNECTED, mm_bearer_get_connected (bearer) ? "yes" : "no");
|
||||||
|
mmcli_output_string_take (MMC_F_BEARER_STATUS_CONNECTION_ERROR_NAME, connection_error ? g_dbus_error_encode_gerror (connection_error) : NULL);
|
||||||
|
mmcli_output_string (MMC_F_BEARER_STATUS_CONNECTION_ERROR_MESSAGE, connection_error ? connection_error->message : NULL);
|
||||||
mmcli_output_string (MMC_F_BEARER_STATUS_SUSPENDED, mm_bearer_get_suspended (bearer) ? "yes" : "no");
|
mmcli_output_string (MMC_F_BEARER_STATUS_SUSPENDED, mm_bearer_get_suspended (bearer) ? "yes" : "no");
|
||||||
mmcli_output_string (MMC_F_BEARER_STATUS_MULTIPLEXED, mm_bearer_get_multiplexed (bearer) ? "yes" : "no");
|
mmcli_output_string (MMC_F_BEARER_STATUS_MULTIPLEXED, mm_bearer_get_multiplexed (bearer) ? "yes" : "no");
|
||||||
mmcli_output_string (MMC_F_BEARER_STATUS_INTERFACE, mm_bearer_get_interface (bearer));
|
mmcli_output_string (MMC_F_BEARER_STATUS_INTERFACE, mm_bearer_get_interface (bearer));
|
||||||
@@ -315,11 +319,6 @@ print_bearer_info (MMBearer *bearer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
mmcli_output_dump ();
|
mmcli_output_dump ();
|
||||||
|
|
||||||
g_clear_object (&stats);
|
|
||||||
g_clear_object (&properties);
|
|
||||||
g_clear_object (&ipv4_config);
|
|
||||||
g_clear_object (&ipv6_config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@@ -210,6 +210,8 @@ static FieldInfo field_infos[] = {
|
|||||||
[MMC_F_BEARER_GENERAL_DBUS_PATH] = { "bearer.dbus-path", "path", MMC_S_BEARER_GENERAL, },
|
[MMC_F_BEARER_GENERAL_DBUS_PATH] = { "bearer.dbus-path", "path", MMC_S_BEARER_GENERAL, },
|
||||||
[MMC_F_BEARER_GENERAL_TYPE] = { "bearer.type", "type", MMC_S_BEARER_GENERAL, },
|
[MMC_F_BEARER_GENERAL_TYPE] = { "bearer.type", "type", MMC_S_BEARER_GENERAL, },
|
||||||
[MMC_F_BEARER_STATUS_CONNECTED] = { "bearer.status.connected", "connected", MMC_S_BEARER_STATUS, },
|
[MMC_F_BEARER_STATUS_CONNECTED] = { "bearer.status.connected", "connected", MMC_S_BEARER_STATUS, },
|
||||||
|
[MMC_F_BEARER_STATUS_CONNECTION_ERROR_NAME] = { "bearer.status.connection-error.name", "connection error name", MMC_S_BEARER_STATUS, },
|
||||||
|
[MMC_F_BEARER_STATUS_CONNECTION_ERROR_MESSAGE] = { "bearer.status.connection-error.message", "connection error message", MMC_S_BEARER_STATUS, },
|
||||||
[MMC_F_BEARER_STATUS_SUSPENDED] = { "bearer.status.suspended", "suspended", MMC_S_BEARER_STATUS, },
|
[MMC_F_BEARER_STATUS_SUSPENDED] = { "bearer.status.suspended", "suspended", MMC_S_BEARER_STATUS, },
|
||||||
[MMC_F_BEARER_STATUS_MULTIPLEXED] = { "bearer.status.multiplexed", "multiplexed", MMC_S_BEARER_STATUS, },
|
[MMC_F_BEARER_STATUS_MULTIPLEXED] = { "bearer.status.multiplexed", "multiplexed", MMC_S_BEARER_STATUS, },
|
||||||
[MMC_F_BEARER_STATUS_INTERFACE] = { "bearer.status.interface", "interface", MMC_S_BEARER_STATUS, },
|
[MMC_F_BEARER_STATUS_INTERFACE] = { "bearer.status.interface", "interface", MMC_S_BEARER_STATUS, },
|
||||||
|
@@ -227,6 +227,8 @@ typedef enum {
|
|||||||
MMC_F_BEARER_GENERAL_TYPE,
|
MMC_F_BEARER_GENERAL_TYPE,
|
||||||
/* Bearer status section */
|
/* Bearer status section */
|
||||||
MMC_F_BEARER_STATUS_CONNECTED,
|
MMC_F_BEARER_STATUS_CONNECTED,
|
||||||
|
MMC_F_BEARER_STATUS_CONNECTION_ERROR_NAME,
|
||||||
|
MMC_F_BEARER_STATUS_CONNECTION_ERROR_MESSAGE,
|
||||||
MMC_F_BEARER_STATUS_SUSPENDED,
|
MMC_F_BEARER_STATUS_SUSPENDED,
|
||||||
MMC_F_BEARER_STATUS_MULTIPLEXED,
|
MMC_F_BEARER_STATUS_MULTIPLEXED,
|
||||||
MMC_F_BEARER_STATUS_INTERFACE,
|
MMC_F_BEARER_STATUS_INTERFACE,
|
||||||
|
@@ -1091,6 +1091,8 @@ mm_bearer_peek_properties
|
|||||||
mm_bearer_get_properties
|
mm_bearer_get_properties
|
||||||
mm_bearer_peek_stats
|
mm_bearer_peek_stats
|
||||||
mm_bearer_get_stats
|
mm_bearer_get_stats
|
||||||
|
mm_bearer_get_connection_error
|
||||||
|
mm_bearer_peek_connection_error
|
||||||
<SUBSECTION Methods>
|
<SUBSECTION Methods>
|
||||||
mm_bearer_connect
|
mm_bearer_connect
|
||||||
mm_bearer_connect_finish
|
mm_bearer_connect_finish
|
||||||
@@ -1835,6 +1837,8 @@ mm_gdbus_bearer_get_ip_timeout
|
|||||||
mm_gdbus_bearer_get_properties
|
mm_gdbus_bearer_get_properties
|
||||||
mm_gdbus_bearer_dup_properties
|
mm_gdbus_bearer_dup_properties
|
||||||
mm_gdbus_bearer_get_connected
|
mm_gdbus_bearer_get_connected
|
||||||
|
mm_gdbus_bearer_get_connection_error
|
||||||
|
mm_gdbus_bearer_dup_connection_error
|
||||||
mm_gdbus_bearer_get_suspended
|
mm_gdbus_bearer_get_suspended
|
||||||
mm_gdbus_bearer_get_multiplexed
|
mm_gdbus_bearer_get_multiplexed
|
||||||
mm_gdbus_bearer_get_bearer_type
|
mm_gdbus_bearer_get_bearer_type
|
||||||
@@ -1851,6 +1855,7 @@ mm_gdbus_bearer_call_disconnect_sync
|
|||||||
<SUBSECTION Private>
|
<SUBSECTION Private>
|
||||||
mm_gdbus_bearer_interface_info
|
mm_gdbus_bearer_interface_info
|
||||||
mm_gdbus_bearer_set_connected
|
mm_gdbus_bearer_set_connected
|
||||||
|
mm_gdbus_bearer_set_connection_error
|
||||||
mm_gdbus_bearer_set_interface
|
mm_gdbus_bearer_set_interface
|
||||||
mm_gdbus_bearer_set_ip4_config
|
mm_gdbus_bearer_set_ip4_config
|
||||||
mm_gdbus_bearer_set_ip6_config
|
mm_gdbus_bearer_set_ip6_config
|
||||||
|
@@ -101,6 +101,20 @@
|
|||||||
-->
|
-->
|
||||||
<property name="Connected" type="b" access="read" />
|
<property name="Connected" type="b" access="read" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
ConnectionError:
|
||||||
|
|
||||||
|
Provides additional information specifying the reason why the modem is
|
||||||
|
not connected (either due to a failed connection attempt, or due to a
|
||||||
|
a network initiated disconnection).
|
||||||
|
|
||||||
|
The value is composed of two strings: the registered DBus error name,
|
||||||
|
and an optional error message.
|
||||||
|
|
||||||
|
Since: 1.18
|
||||||
|
-->
|
||||||
|
<property name="ConnectionError" type="(ss)" access="read" />
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Suspended:
|
Suspended:
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mm-helpers.h"
|
#include "mm-helpers.h"
|
||||||
|
#include "mm-common-helpers.h"
|
||||||
#include "mm-bearer.h"
|
#include "mm-bearer.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,6 +59,11 @@ struct _MMBearerPrivate {
|
|||||||
GMutex stats_mutex;
|
GMutex stats_mutex;
|
||||||
guint stats_id;
|
guint stats_id;
|
||||||
MMBearerStats *stats;
|
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:
|
* mm_bearer_connect_finish:
|
||||||
* @self: A #MMBearer.
|
* @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->ipv6_config_mutex);
|
||||||
g_mutex_init (&self->priv->properties_mutex);
|
g_mutex_init (&self->priv->properties_mutex);
|
||||||
g_mutex_init (&self->priv->stats_mutex);
|
g_mutex_init (&self->priv->stats_mutex);
|
||||||
|
g_mutex_init (&self->priv->connection_error_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -943,6 +1060,7 @@ finalize (GObject *object)
|
|||||||
g_mutex_clear (&self->priv->ipv6_config_mutex);
|
g_mutex_clear (&self->priv->ipv6_config_mutex);
|
||||||
g_mutex_clear (&self->priv->properties_mutex);
|
g_mutex_clear (&self->priv->properties_mutex);
|
||||||
g_mutex_clear (&self->priv->stats_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);
|
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->ipv6_config);
|
||||||
g_clear_object (&self->priv->properties);
|
g_clear_object (&self->priv->properties);
|
||||||
g_clear_object (&self->priv->stats);
|
g_clear_object (&self->priv->stats);
|
||||||
|
g_clear_error (&self->priv->connection_error);
|
||||||
|
|
||||||
G_OBJECT_CLASS (mm_bearer_parent_class)->dispose (object);
|
G_OBJECT_CLASS (mm_bearer_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
@@ -120,6 +120,9 @@ MMBearerIpConfig *mm_bearer_peek_ipv6_config (MMBearer *self);
|
|||||||
MMBearerStats *mm_bearer_get_stats (MMBearer *self);
|
MMBearerStats *mm_bearer_get_stats (MMBearer *self);
|
||||||
MMBearerStats *mm_bearer_peek_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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* _MM_BEARER_H_ */
|
#endif /* _MM_BEARER_H_ */
|
||||||
|
@@ -1911,3 +1911,53 @@ mm_common_register_errors (void)
|
|||||||
|
|
||||||
return TRUE;
|
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));
|
||||||
|
}
|
||||||
|
@@ -203,5 +203,8 @@ gboolean mm_utils_check_for_single_value (guint32 value);
|
|||||||
|
|
||||||
/* DBus error handling */
|
/* 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 */
|
#endif /* MM_COMMON_HELPERS_H */
|
||||||
|
Reference in New Issue
Block a user