If the bearer implementation supports it, load stats periodically. By default every 30s for now. --- src/mm-base-bearer.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/mm-base-bearer.h | 16 +++++-- 2 files changed, 133 insertions(+), 6 deletions(-)
diff --git a/src/mm-base-bearer.c b/src/mm-base-bearer.c index a49ea43..f304b2a 100644 --- a/src/mm-base-bearer.c +++ b/src/mm-base-bearer.c @@ -13,7 +13,8 @@ * Copyright (C) 2008 - 2009 Novell, Inc. * Copyright (C) 2009 - 2011 Red Hat, Inc. * Copyright (C) 2011 Google, Inc. - * Copyright (C) 2011 - 2014 Aleksander Morgado <aleksan...@aleksander.es> + * Copyright (C) 2015 Azimut Electronics + * Copyright (C) 2011 - 2015 Aleksander Morgado <aleksan...@aleksander.es> */ #include <config.h> @@ -36,13 +37,16 @@ #include "mm-base-modem.h" #include "mm-log.h" #include "mm-modem-helpers.h" +#include "mm-bearer-stats.h" /* We require up to 20s to get a proper IP when using PPP */ #define BEARER_IP_TIMEOUT_DEFAULT 20 #define BEARER_DEFERRED_UNREGISTRATION_TIMEOUT 15 -G_DEFINE_TYPE (MMBaseBearer, mm_base_bearer, MM_GDBUS_TYPE_BEARER_SKELETON); +#define BEARER_STATS_UPDATE_TIMEOUT 30 + +G_DEFINE_TYPE (MMBaseBearer, mm_base_bearer, MM_GDBUS_TYPE_BEARER_SKELETON) typedef enum { CONNECTION_FORBIDDEN_REASON_NONE, @@ -97,6 +101,13 @@ struct _MMBaseBearerPrivate { /* Handler IDs for the registration state change signals */ guint id_cdma1x_registration_change; guint id_evdo_registration_change; + + /* The stats object to expose */ + MMBearerStats *stats; + /* Handler id for the stats update timeout */ + guint stats_update_id; + /* Timer to measure the duration of the connection */ + GTimer *duration_timer; }; /*****************************************************************************/ @@ -125,6 +136,102 @@ mm_base_bearer_export (MMBaseBearer *self) /*****************************************************************************/ static void +bearer_update_interface_stats (MMBaseBearer *self) +{ + mm_gdbus_bearer_set_stats ( + MM_GDBUS_BEARER (self), + mm_bearer_stats_get_dictionary (self->priv->stats)); +} + +static void +bearer_reset_interface_stats (MMBaseBearer *self) +{ + g_clear_object (&self->priv->stats); + mm_gdbus_bearer_set_stats (MM_GDBUS_BEARER (self), NULL); +} + +static void +bearer_stats_stop (MMBaseBearer *self) +{ + if (self->priv->duration_timer) { + if (self->priv->stats) + mm_bearer_stats_set_duration (self->priv->stats, (guint64) g_timer_elapsed (self->priv->duration_timer, NULL)); + g_timer_destroy (self->priv->duration_timer); + self->priv->duration_timer = NULL; + } + + if (self->priv->stats_update_id) { + g_source_remove (self->priv->stats_update_id); + self->priv->stats_update_id = 0; + } +} + +static void +reload_stats_ready (MMBaseBearer *self, + GAsyncResult *res) +{ + GError *error = NULL; + guint64 rx_bytes = 0; + guint64 tx_bytes = 0; + + if (!MM_BASE_BEARER_GET_CLASS (self)->reload_stats_finish (self, &rx_bytes, &tx_bytes, res, &error)) { + g_warning ("Reloading stats failed: %s", error->message); + g_error_free (error); + return; + } + + /* We only update stats if they were retrieved properly */ + mm_bearer_stats_set_duration (self->priv->stats, (guint32) g_timer_elapsed (self->priv->duration_timer, NULL)); + mm_bearer_stats_set_tx_bytes (self->priv->stats, rx_bytes); + mm_bearer_stats_set_rx_bytes (self->priv->stats, tx_bytes); + bearer_update_interface_stats (self); +} + +static gboolean +stats_update_cb (MMBaseBearer *self) +{ + /* If the implementation knows how to update stat values, run it */ + 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_ready, + NULL); + return G_SOURCE_CONTINUE; + } + + /* Otherwise, just update duration and we're done */ + mm_bearer_stats_set_duration (self->priv->stats, (guint32) g_timer_elapsed (self->priv->duration_timer, NULL)); + mm_bearer_stats_set_tx_bytes (self->priv->stats, 0); + mm_bearer_stats_set_rx_bytes (self->priv->stats, 0); + bearer_update_interface_stats (self); + return G_SOURCE_CONTINUE; +} + +static void +bearer_stats_start (MMBaseBearer *self) +{ + /* Allocate new stats object. If there was one already created from a + * previous run, deallocate it */ + g_assert (!self->priv->stats); + self->priv->stats = mm_bearer_stats_new (); + + /* Start duration timer */ + g_assert (!self->priv->duration_timer); + self->priv->duration_timer = g_timer_new (); + + /* Schedule */ + g_assert (!self->priv->stats_update_id); + self->priv->stats_update_id = g_timeout_add_seconds (BEARER_STATS_UPDATE_TIMEOUT, + (GSourceFunc) stats_update_cb, + self); + /* Load initial values */ + stats_update_cb (self); +} + +/*****************************************************************************/ + +static void bearer_reset_interface_status (MMBaseBearer *self) { mm_gdbus_bearer_set_connected (MM_GDBUS_BEARER (self), FALSE); @@ -151,8 +258,11 @@ bearer_update_status (MMBaseBearer *self, /* Ensure that we don't expose any connection related data in the * interface when going into disconnected state. */ - if (self->priv->status == MM_BEARER_STATUS_DISCONNECTED) + if (self->priv->status == MM_BEARER_STATUS_DISCONNECTED) { bearer_reset_interface_status (self); + /* Stop statistics */ + bearer_stats_stop (self); + } } static void @@ -171,6 +281,9 @@ bearer_update_status_connected (MMBaseBearer *self, MM_GDBUS_BEARER (self), mm_bearer_ip_config_get_dictionary (ipv6_config)); + /* Start statistics */ + bearer_stats_start (self); + /* Update the property value */ self->priv->status = MM_BEARER_STATUS_CONNECTED; g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATUS]); @@ -590,6 +703,7 @@ mm_base_bearer_connect (MMBaseBearer *self, mm_dbg ("Connecting bearer '%s'", self->priv->path); self->priv->connect_cancellable = g_cancellable_new (); bearer_update_status (self, MM_BEARER_STATUS_CONNECTING); + bearer_reset_interface_stats (self); MM_BASE_BEARER_GET_CLASS (self)->connect ( self, self->priv->connect_cancellable, @@ -1150,6 +1264,9 @@ dispose (GObject *object) { MMBaseBearer *self = MM_BASE_BEARER (object); + bearer_stats_stop (self); + g_clear_object (&self->priv->stats); + if (self->priv->connection) { base_bearer_dbus_unexport (self); g_clear_object (&self->priv->connection); diff --git a/src/mm-base-bearer.h b/src/mm-base-bearer.h index 2c196f6..58954d4 100644 --- a/src/mm-base-bearer.h +++ b/src/mm-base-bearer.h @@ -10,10 +10,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * - * Author: Aleksander Morgado <aleksan...@lanedo.com> - * + * Copyright (C) 2011 Google, Inc. - * Copyright (C) 2011 - 2013 Aleksander Morgado <aleksan...@gnu.org> + * Copyright (C) 2015 Azimut Electronics + * Copyright (C) 2011 - 2015 Aleksander Morgado <aleksan...@aleksander.es> */ #ifndef MM_BASE_BEARER_H @@ -101,6 +101,16 @@ struct _MMBaseBearerClass { GAsyncResult *res, GError **error); + /* Reload statistics */ + void (* reload_stats) (MMBaseBearer *bearer, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* reload_stats_finish) (MMBaseBearer *bearer, + guint64 *bytes_rx, + guint64 *bytes_tx, + GAsyncResult *res, + GError **error); + /* Report connection status of this bearer */ void (* report_connection_status) (MMBaseBearer *bearer, MMBearerConnectionStatus status); -- 2.6.2 _______________________________________________ ModemManager-devel mailing list ModemManager-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/modemmanager-devel