base-bearer: make sure 'ReloadStatsSupported' is set before transitioning to 'Connected'

By the time we report the bearer as 'Connected', the DBus client
should also be able to know right away the value of
'ReloadStatsSupported', instead of needing to wait for it to be
updated asynchronously.

This logic adds one additional step in the generic connection
sequence for this purpose, which is run after the modem is connected
but before we report the state change via DBus.
This commit is contained in:
Aleksander Morgado
2021-12-11 15:06:42 +01:00
parent 9fc3d15d29
commit 029ea68ce4
2 changed files with 120 additions and 92 deletions

View File

@@ -381,7 +381,15 @@
<!--
ReloadStatsSupported:
Indicates whether or not the bearer support getting rx and tx bytes statistics.
Indicates whether reloading ongoing statistics is supported or not.
This property applies exclusively to the statistics that are queried from
the modem periodically; i.e. "rx-bytes", "tx-bytes", "uplink-speed" and
"downlink-speed".
The property is initialized to a fixed value as soon as the first
connection attempt has successfully finished. Reading this value before
the first successful connection attempt will always report %FALSE.
Since: 1.20
-->

View File

@@ -389,25 +389,6 @@ bearer_stats_stop (MMBaseBearer *self)
}
}
static void
reload_stats_supported_ready (MMBaseBearer *self,
GAsyncResult *res)
{
GError *error = NULL;
guint64 rx_bytes = 0;
guint64 tx_bytes = 0;
MM_BASE_BEARER_GET_CLASS (self)->reload_stats_finish (self, &rx_bytes, &tx_bytes, res, &error);
if (!error) {
mm_obj_info (self, "reloading stats is supported by the device");
self->priv->reload_stats_supported = TRUE;
mm_gdbus_bearer_set_reload_stats_supported (MM_GDBUS_BEARER (self), self->priv->reload_stats_supported);
} else {
mm_obj_info (self, "reloading stats is not supported by the device");
g_clear_error (&error);
}
}
static void
reload_stats_ready (MMBaseBearer *self,
GAsyncResult *res)
@@ -589,15 +570,6 @@ bearer_update_status_connected (MMBaseBearer *self,
self->priv->status = MM_BEARER_STATUS_CONNECTED;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATUS]);
/* Check that reload statistics is supported by the device */
if (MM_BASE_BEARER_GET_CLASS (self)->reload_stats &&
MM_BASE_BEARER_GET_CLASS (self)->reload_stats_finish) {
MM_BASE_BEARER_GET_CLASS (self)->reload_stats (
self,
(GAsyncReadyCallback)reload_stats_supported_ready,
NULL);
}
/* Start statistics */
bearer_stats_start (self, uplink_speed, downlink_speed);
@@ -871,16 +843,39 @@ mm_base_bearer_connect_finish (MMBaseBearer *self,
return g_task_propagate_boolean (G_TASK (res), error);
}
static void
connect_succeeded (MMBaseBearer *self,
GTask *task)
{
MMBearerConnectResult *result;
result = g_task_get_task_data (task);
/* Update bearer and interface status */
bearer_update_status_connected (
self,
mm_port_get_device (mm_bearer_connect_result_peek_data (result)),
mm_bearer_connect_result_get_multiplexed (result),
mm_bearer_connect_result_get_profile_id (result),
mm_bearer_connect_result_peek_ipv4_config (result),
mm_bearer_connect_result_peek_ipv6_config (result),
mm_bearer_connect_result_get_uplink_speed (result),
mm_bearer_connect_result_get_downlink_speed (result));
g_clear_object (&self->priv->connect_cancellable);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
static void
disconnect_after_cancel_ready (MMBaseBearer *self,
GAsyncResult *res)
{
GError *error = NULL;
g_autoptr(GError) error = NULL;
if (!MM_BASE_BEARER_GET_CLASS (self)->disconnect_finish (self, res, &error)) {
if (!MM_BASE_BEARER_GET_CLASS (self)->disconnect_finish (self, res, &error))
mm_obj_warn (self, "error disconnecting: %s; will assume disconnected anyway", error->message);
g_error_free (error);
}
else
mm_obj_dbg (self, "disconnected bearer '%s'", self->priv->path);
@@ -892,14 +887,73 @@ disconnect_after_cancel_ready (MMBaseBearer *self,
mm_base_bearer_report_connection_status (self, MM_BEARER_CONNECTION_STATUS_DISCONNECTED);
}
static void
connect_failed (MMBaseBearer *self,
GTask *task,
GError *error)
{
/* Update failed attempts */
mm_bearer_stats_set_failed_attempts (self->priv->stats,
mm_bearer_stats_get_failed_attempts (self->priv->stats) + 1);
bearer_update_interface_stats (self);
/* Update reported connection error before the status update */
bearer_update_connection_error (self, error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
bearer_update_status (self, MM_BEARER_STATUS_DISCONNECTING);
MM_BASE_BEARER_GET_CLASS (self)->disconnect (self,
(GAsyncReadyCallback)disconnect_after_cancel_ready,
NULL);
} else
bearer_update_status (self, MM_BEARER_STATUS_DISCONNECTED);
g_clear_object (&self->priv->connect_cancellable);
g_task_return_error (task, error);
g_object_unref (task);
}
static gboolean
connect_check_cancel (MMBaseBearer *self,
GTask *task)
{
GError *error = NULL;
if (!g_cancellable_is_cancelled (self->priv->connect_cancellable))
return FALSE;
mm_obj_dbg (self, "connected, but need to disconnect");
error = g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Bearer got connected, but had to disconnect after cancellation request");
connect_failed (self, task, error);
return TRUE;
}
static void
reload_stats_supported_ready (MMBaseBearer *self,
GAsyncResult *res,
GTask *task)
{
if (MM_BASE_BEARER_GET_CLASS (self)->reload_stats_finish (self, NULL, NULL, res, NULL)) {
mm_obj_info (self, "reloading stats is supported by the device");
self->priv->reload_stats_supported = TRUE;
mm_gdbus_bearer_set_reload_stats_supported (MM_GDBUS_BEARER (self), self->priv->reload_stats_supported);
} else
mm_obj_info (self, "reloading stats is not supported by the device");
if (connect_check_cancel (self, task))
return;
connect_succeeded (self, task);
}
static void
connect_ready (MMBaseBearer *self,
GAsyncResult *res,
GTask *task)
{
GError *error = NULL;
gboolean launch_disconnect = FALSE;
MMBearerConnectResult *result;
g_autoptr(MMBearerConnectResult) result = NULL;
/* NOTE: connect() implementations *MUST* handle cancellations themselves */
result = MM_BASE_BEARER_GET_CLASS (self)->connect_finish (self, res, &error);
@@ -907,63 +961,29 @@ connect_ready (MMBaseBearer *self,
mm_obj_warn (self, "connection attempt #%u failed: %s",
mm_bearer_stats_get_attempts (self->priv->stats),
error->message);
/* Update failed attempts */
mm_bearer_stats_set_failed_attempts (self->priv->stats,
mm_bearer_stats_get_failed_attempts (self->priv->stats) + 1);
bearer_update_interface_stats (self);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
/* Will launch disconnection */
launch_disconnect = TRUE;
} else {
/* Update reported connection error before the status update */
bearer_update_connection_error (self, error);
bearer_update_status (self, MM_BEARER_STATUS_DISCONNECTED);
}
connect_failed (self, task, error);
return;
}
/* Handle cancellations detected after successful connection */
else if (g_cancellable_is_cancelled (self->priv->connect_cancellable)) {
mm_obj_dbg (self, "connected, but need to disconnect");
mm_bearer_connect_result_unref (result);
error = g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED,
"Bearer got connected, but had to disconnect after cancellation request");
launch_disconnect = TRUE;
}
else {
if (connect_check_cancel (self, task))
return;
mm_obj_dbg (self, "connected");
g_task_set_task_data (task, g_steal_pointer (&result), (GDestroyNotify)mm_bearer_connect_result_unref);
/* Update bearer and interface status */
bearer_update_status_connected (
/* Check that reload statistics is supported by the device; we can only do this while
* connected. */
if (MM_BASE_BEARER_GET_CLASS (self)->reload_stats &&
MM_BASE_BEARER_GET_CLASS (self)->reload_stats_finish) {
MM_BASE_BEARER_GET_CLASS (self)->reload_stats (
self,
mm_port_get_device (mm_bearer_connect_result_peek_data (result)),
mm_bearer_connect_result_get_multiplexed (result),
mm_bearer_connect_result_get_profile_id (result),
mm_bearer_connect_result_peek_ipv4_config (result),
mm_bearer_connect_result_peek_ipv6_config (result),
mm_bearer_connect_result_get_uplink_speed (result),
mm_bearer_connect_result_get_downlink_speed (result));
mm_bearer_connect_result_unref (result);
(GAsyncReadyCallback)reload_stats_supported_ready,
task);
return;
}
if (launch_disconnect) {
/* Update reported connection error before the status update */
bearer_update_connection_error (self, error);
bearer_update_status (self, MM_BEARER_STATUS_DISCONNECTING);
MM_BASE_BEARER_GET_CLASS (self)->disconnect (
self,
(GAsyncReadyCallback)disconnect_after_cancel_ready,
NULL);
}
g_clear_object (&self->priv->connect_cancellable);
if (error)
g_task_return_error (task, error);
else
g_task_return_boolean (task, TRUE);
g_object_unref (task);
connect_succeeded (self, task);
}
void