Add support for roaming/home network statistic
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Wed, 18 Aug 2010 15:56:06 +0000 (17:56 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Wed, 18 Aug 2010 17:08:54 +0000 (19:08 +0200)
Currently connman only has one set of counters for
collecting statistics on online time and
the amount of transfered bytes.

For 3G connections we should destinguish between
home network and roaming. This patch introduces
two sets of counter values for home network
and roaming network.

Changing from Home to Roaming counters relies on
connman_network_set_roaming being called. Currently,
this is only done in the ofono plugin. Getting Wifi
'Hot-Spot Provider' Roaming (e.g.  T-Mobile Germany
to T-Mobile USA) is not yet working.

src/connman.h
src/counter.c
src/service.c
test/test-counter

index b1502ad..fb9433e 100644 (file)
@@ -505,16 +505,10 @@ const char *__connman_service_get_nameserver(struct connman_service *service);
 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
                                                        const char *url);
 
-unsigned long __connman_service_stats_get_rx_packets(struct connman_service *service);
-unsigned long __connman_service_stats_get_tx_packets(struct connman_service *service);
-unsigned long __connman_service_stats_get_rx_bytes(struct connman_service *service);
-unsigned long __connman_service_stats_get_tx_bytes(struct connman_service *service);
-unsigned long __connman_service_stats_get_rx_errors(struct connman_service *service);
-unsigned long __connman_service_stats_get_tx_errors(struct connman_service *service);
-unsigned long __connman_service_stats_get_rx_dropped(struct connman_service *service);
-unsigned long __connman_service_stats_get_tx_dropped(struct connman_service *service);
-unsigned long __connman_service_stats_get_time(struct connman_service *service);
-void __connman_service_stats_update(struct connman_service *service,
+void __connman_service_stats_append(struct connman_service *service,
+                                               DBusMessage *msg,
+                                               connman_bool_t append_all);
+connman_bool_t __connman_service_stats_update(struct connman_service *service,
                                unsigned int rx_packets, unsigned int tx_packets,
                                unsigned int rx_bytes, unsigned int tx_bytes,
                                unsigned int rx_error, unsigned int tx_error,
index 27898c5..19171e5 100644 (file)
@@ -38,10 +38,6 @@ struct connman_counter {
        char *path;
        unsigned int interval;
        guint watch;
-};
-
-struct counter_data {
-       struct connman_service *service;
        connman_bool_t first_update;
 };
 
@@ -61,13 +57,6 @@ static void remove_counter(gpointer user_data)
        g_free(counter);
 }
 
-static void remove_data(gpointer user_data)
-{
-       struct counter_data *data = user_data;
-
-       g_free(data);
-}
-
 static void owner_disconnect(DBusConnection *connection, void *user_data)
 {
        struct connman_counter *counter = user_data;
@@ -95,6 +84,7 @@ int __connman_counter_register(const char *owner, const char *path,
 
        counter->owner = g_strdup(owner);
        counter->path = g_strdup(path);
+       counter->first_update = TRUE;
 
        g_hash_table_replace(counter_table, counter->path, counter);
        g_hash_table_replace(owner_mapping, counter->owner, counter);
@@ -131,17 +121,7 @@ static void send_usage(struct connman_counter *counter,
                                struct connman_service *service)
 {
        DBusMessage *message;
-       DBusMessageIter array, dict;
        const char *service_path;
-       unsigned long rx_packets;
-       unsigned long tx_packets;
-       unsigned long rx_bytes;
-       unsigned long tx_bytes;
-       unsigned long rx_errors;
-       unsigned long tx_errors;
-       unsigned long rx_dropped;
-       unsigned long tx_dropped;
-       unsigned long time;
 
        message = dbus_message_new_method_call(counter->owner, counter->path,
                                        CONNMAN_COUNTER_INTERFACE, "Usage");
@@ -154,46 +134,9 @@ static void send_usage(struct connman_counter *counter,
        dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH,
                                        &service_path, DBUS_TYPE_INVALID);
 
-       dbus_message_iter_init_append(message, &array);
-
-       /* home counter */
-       connman_dbus_dict_open(&array, &dict);
-
-       rx_packets = __connman_service_stats_get_rx_packets(service);
-       tx_packets = __connman_service_stats_get_tx_packets(service);
-       rx_bytes = __connman_service_stats_get_rx_bytes(service);
-       tx_bytes = __connman_service_stats_get_tx_bytes(service);
-       rx_errors = __connman_service_stats_get_rx_errors(service);
-       tx_errors = __connman_service_stats_get_tx_errors(service);
-       rx_dropped = __connman_service_stats_get_rx_dropped(service);
-       tx_dropped = __connman_service_stats_get_tx_dropped(service);
-       time = __connman_service_stats_get_time(service);
-
-       connman_dbus_dict_append_basic(&dict, "RX.Packets", DBUS_TYPE_UINT32,
-                               &rx_packets);
-       connman_dbus_dict_append_basic(&dict, "TX.Packets", DBUS_TYPE_UINT32,
-                               &tx_packets);
-       connman_dbus_dict_append_basic(&dict, "RX.Bytes", DBUS_TYPE_UINT32,
-                               &rx_bytes);
-       connman_dbus_dict_append_basic(&dict, "TX.Bytes", DBUS_TYPE_UINT32,
-                               &tx_bytes);
-       connman_dbus_dict_append_basic(&dict, "RX.Errors", DBUS_TYPE_UINT32,
-                               &rx_errors);
-       connman_dbus_dict_append_basic(&dict, "TX.Errors", DBUS_TYPE_UINT32,
-                               &tx_errors);
-       connman_dbus_dict_append_basic(&dict, "RX.Dropped", DBUS_TYPE_UINT32,
-                               &rx_dropped);
-       connman_dbus_dict_append_basic(&dict, "TX.Dropped", DBUS_TYPE_UINT32,
-                               &tx_dropped);
-       connman_dbus_dict_append_basic(&dict, "Time", DBUS_TYPE_UINT32,
-                               &time);
-
-       connman_dbus_dict_close(&array, &dict);
-
-       /* roaming counter */
-       connman_dbus_dict_open(&array, &dict);
-
-       connman_dbus_dict_close(&array, &dict);
+       __connman_service_stats_append(service, message, counter->first_update);
+
+       counter->first_update = FALSE;
 
        g_dbus_send_message(connection, message);
 }
@@ -204,22 +147,20 @@ void __connman_counter_notify(struct connman_ipconfig *config,
                        unsigned int rx_errors, unsigned int tx_errors,
                        unsigned int rx_dropped, unsigned int tx_dropped)
 {
-       struct counter_data *data;
+       struct connman_service *service;
        GHashTableIter iter;
        gpointer key, value;
 
-       data = g_hash_table_lookup(stats_table, config);
-       if (data == NULL)
+       service = g_hash_table_lookup(stats_table, config);
+       if (service == NULL)
                return;
 
-       __connman_service_stats_update(data->service,
+       if (__connman_service_stats_update(service,
                                rx_packets, tx_packets,
                                rx_bytes, tx_bytes,
                                rx_errors, tx_errors,
-                               rx_dropped, tx_dropped);
-
-       if (data->first_update == TRUE) {
-               data->first_update = FALSE;
+                               rx_dropped, tx_dropped) == FALSE) {
+               /* first update, counters are now initialized */
                return;
        }
 
@@ -227,7 +168,7 @@ void __connman_counter_notify(struct connman_ipconfig *config,
        while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
                struct connman_counter *counter = value;
 
-               send_usage(counter, data->service);
+               send_usage(counter, service);
        }
 }
 
@@ -251,17 +192,9 @@ static void release_counter(gpointer key, gpointer value, gpointer user_data)
 int __connman_counter_add_service(struct connman_service *service)
 {
        struct connman_ipconfig *config;
-       struct counter_data *data;
-
-       data = g_try_new0(struct counter_data, 1);
-       if (data == NULL)
-               return -ENOMEM;
-
-       data->service = service;
-       data->first_update = TRUE;
 
        config = __connman_service_get_ipconfig(service);
-       g_hash_table_replace(stats_table, config, data);
+       g_hash_table_replace(stats_table, config, service);
 
        /*
         * Trigger a first update to intialize the offset counters
@@ -289,7 +222,7 @@ int __connman_counter_init(void)
                return -1;
 
        stats_table = g_hash_table_new_full(g_direct_hash, g_str_equal,
-                                                       NULL, remove_data);
+                                                       NULL, NULL);
 
        counter_table = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                        NULL, remove_counter);
index 893ccba..0a5bed0 100644 (file)
@@ -39,23 +39,32 @@ static GHashTable *service_hash = NULL;
 struct connman_stats {
        connman_bool_t valid;
        connman_bool_t enabled;
+       unsigned int rx_packets_update;
+       unsigned int tx_packets_update;
        unsigned int rx_packets_last;
        unsigned int tx_packets_last;
        unsigned int rx_packets;
        unsigned int tx_packets;
+       unsigned int rx_bytes_update;
+       unsigned int tx_bytes_update;
        unsigned int rx_bytes_last;
        unsigned int tx_bytes_last;
        unsigned int rx_bytes;
        unsigned int tx_bytes;
+       unsigned int rx_errors_update;
+       unsigned int tx_errors_update;
        unsigned int rx_errors_last;
        unsigned int tx_errors_last;
        unsigned int rx_errors;
        unsigned int tx_errors;
+       unsigned int rx_dropped_update;
+       unsigned int tx_dropped_update;
        unsigned int rx_dropped_last;
        unsigned int tx_dropped_last;
        unsigned int rx_dropped;
        unsigned int tx_dropped;
        unsigned int time_start;
+       unsigned int time_update;
        unsigned int time;
        GTimer *timer;
 };
@@ -107,6 +116,7 @@ struct connman_service {
        guint timeout;
        struct connman_location *location;
        struct connman_stats stats;
+       struct connman_stats stats_roaming;
 };
 
 static void append_path(gpointer value, gpointer user_data)
@@ -430,90 +440,147 @@ void __connman_service_nameserver_del_routes(struct connman_service *service)
        }
 }
 
+static struct connman_stats *stats_get(struct connman_service *service)
+{
+       if (service->roaming == TRUE)
+               return &service->stats_roaming;
+       else
+               return &service->stats;
+}
+
+static connman_bool_t stats_enabled(struct connman_service *service)
+{
+       struct connman_stats *stats = stats_get(service);
+
+       return stats->enabled;
+}
+
 static void stats_start(struct connman_service *service)
 {
+       struct connman_stats *stats = stats_get(service);
+
        DBG("service %p", service);
 
-       if (service->stats.timer == NULL)
+       if (stats->timer == NULL)
                return;
 
-       service->stats.enabled = TRUE;
-
-       service->stats.time_start = service->stats.time;
+       stats->enabled = TRUE;
+       stats->time_start = stats->time;
 
-       g_timer_start(service->stats.timer);
+       g_timer_start(stats->timer);
 
        __connman_counter_add_service(service);
 }
 
 static void stats_stop(struct connman_service *service)
 {
+       struct connman_stats *stats = stats_get(service);
        unsigned int seconds;
 
        DBG("service %p", service);
 
-       if (service->stats.timer == NULL)
+       if (stats->timer == NULL)
                return;
 
-       if (service->stats.enabled == FALSE)
+       if (stats->enabled == FALSE)
                return;
 
        __connman_counter_remove_service(service);
 
-       g_timer_stop(service->stats.timer);
+       g_timer_stop(stats->timer);
 
-       seconds = g_timer_elapsed(service->stats.timer, NULL);
-       service->stats.time = service->stats.time_start + seconds;
+       seconds = g_timer_elapsed(stats->timer, NULL);
+       stats->time = stats->time_start + seconds;
 
-       service->stats.enabled = FALSE;
+       stats->enabled = FALSE;
 }
 
-static int stats_load(struct connman_service *service,
-               GKeyFile *keyfile, const char *identifier)
+static int stats_load(struct connman_service *service, GKeyFile *keyfile)
 {
+       /* home */
        service->stats.rx_packets = g_key_file_get_integer(keyfile,
-                               identifier, "rx_packets", NULL);
+                       service->identifier, "Home.rx_packets", NULL);
        service->stats.tx_packets = g_key_file_get_integer(keyfile,
-                               identifier, "tx_packets", NULL);
+                       service->identifier, "Home.tx_packets", NULL);
        service->stats.rx_bytes = g_key_file_get_integer(keyfile,
-                               identifier, "rx_bytes", NULL);
+                       service->identifier, "Home.rx_bytes", NULL);
        service->stats.tx_bytes = g_key_file_get_integer(keyfile,
-                               identifier, "tx_bytes", NULL);
+                       service->identifier, "Home.tx_bytes", NULL);
        service->stats.rx_errors = g_key_file_get_integer(keyfile,
-                               identifier, "rx_errors", NULL);
+                       service->identifier, "Home.rx_errors", NULL);
        service->stats.tx_errors = g_key_file_get_integer(keyfile,
-                               identifier, "tx_errors", NULL);
+                       service->identifier, "Home.tx_errors", NULL);
        service->stats.rx_dropped = g_key_file_get_integer(keyfile,
-                               identifier, "rx_dropped", NULL);
+                       service->identifier, "Home.rx_dropped", NULL);
        service->stats.tx_dropped = g_key_file_get_integer(keyfile,
-                               identifier, "tx_dropped", NULL);
+                       service->identifier, "Home.tx_dropped", NULL);
        service->stats.time = g_key_file_get_integer(keyfile,
-                               identifier, "time", NULL);
+                       service->identifier, "Home.time", NULL);
+
+       /* roaming */
+       service->stats_roaming.rx_packets = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.rx_packets", NULL);
+       service->stats_roaming.tx_packets = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.tx_packets", NULL);
+       service->stats_roaming.rx_bytes = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.rx_bytes", NULL);
+       service->stats_roaming.tx_bytes = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.tx_bytes", NULL);
+       service->stats_roaming.rx_errors = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.rx_errors", NULL);
+       service->stats_roaming.tx_errors = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.tx_errors", NULL);
+       service->stats_roaming.rx_dropped = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.rx_dropped", NULL);
+       service->stats_roaming.tx_dropped = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.tx_dropped", NULL);
+       service->stats_roaming.time = g_key_file_get_integer(keyfile,
+                       service->identifier, "Roaming.time", NULL);
 
        return 0;
 }
 
-static int stats_save(struct connman_service *service,
-               GKeyFile *keyfile, const char *identifier)
-{
-       g_key_file_set_integer(keyfile, identifier, "rx_packets",
-                       service->stats.rx_packets);
-       g_key_file_set_integer(keyfile, identifier, "tx_packets",
-                       service->stats.tx_packets);
-       g_key_file_set_integer(keyfile, identifier, "rx_bytes",
-                       service->stats.rx_bytes);
-       g_key_file_set_integer(keyfile, identifier, "tx_bytes",
-                       service->stats.tx_bytes);
-       g_key_file_set_integer(keyfile, identifier, "rx_errors",
-                       service->stats.rx_errors);
-       g_key_file_set_integer(keyfile, identifier, "tx_errors",
-                       service->stats.tx_errors);
-       g_key_file_set_integer(keyfile, identifier, "rx_dropped",
-                       service->stats.rx_dropped);
-       g_key_file_set_integer(keyfile, identifier, "tx_dropped",
-                       service->stats.tx_dropped);
-       g_key_file_set_integer(keyfile, identifier, "time",
-                       service->stats.time);
+static int stats_save(struct connman_service *service, GKeyFile *keyfile)
+{
+       /* home */
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.rx_packets", service->stats.rx_packets);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.tx_packets", service->stats.tx_packets);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.rx_bytes", service->stats.rx_bytes);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.tx_bytes", service->stats.tx_bytes);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.rx_errors", service->stats.rx_errors);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.tx_errors", service->stats.tx_errors);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.rx_dropped", service->stats.rx_dropped);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.tx_dropped", service->stats.tx_dropped);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Home.time", service->stats.time);
+
+       /* roaming */
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.rx_packets", service->stats_roaming.rx_packets);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.tx_packets", service->stats_roaming.tx_packets);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.rx_bytes", service->stats_roaming.rx_bytes);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.tx_bytes", service->stats_roaming.tx_bytes);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.rx_errors", service->stats_roaming.rx_errors);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.tx_errors", service->stats_roaming.tx_errors);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.rx_dropped", service->stats_roaming.rx_dropped);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.tx_dropped", service->stats_roaming.tx_dropped);
+       g_key_file_set_integer(keyfile, service->identifier,
+               "Roaming.time", service->stats_roaming.time);
 
        return 0;
 }
@@ -522,7 +589,9 @@ static void reset_stats(struct connman_service *service)
 {
        DBG("service %p", service);
 
+       /* home */
        service->stats.valid = FALSE;
+
        service->stats.rx_packets = 0;
        service->stats.tx_packets = 0;
        service->stats.rx_bytes = 0;
@@ -533,53 +602,44 @@ static void reset_stats(struct connman_service *service)
        service->stats.tx_dropped = 0;
        service->stats.time = 0;
        service->stats.time_start = 0;
-       g_timer_reset(service->stats.timer);
-
-}
-
-unsigned long __connman_service_stats_get_rx_packets(struct connman_service *service)
-{
-       return service->stats.rx_packets;
-}
-
-unsigned long __connman_service_stats_get_tx_packets(struct connman_service *service)
-{
-       return service->stats.tx_packets;
-}
-
-unsigned long __connman_service_stats_get_rx_bytes(struct connman_service *service)
-{
-       return service->stats.rx_bytes;
-}
-
-unsigned long __connman_service_stats_get_tx_bytes(struct connman_service *service)
-{
-       return service->stats.tx_bytes;
-}
-
-unsigned long __connman_service_stats_get_rx_errors(struct connman_service *service)
-{
-       return service->stats.rx_errors;
-}
 
-unsigned long __connman_service_stats_get_tx_errors(struct connman_service *service)
-{
-       return service->stats.tx_errors;
-}
+       service->stats.rx_packets_update = 0;
+       service->stats.tx_packets_update = 0;
+       service->stats.rx_bytes_update = 0;
+       service->stats.tx_bytes_update = 0;
+       service->stats.rx_errors_update = 0;
+       service->stats.tx_errors_update = 0;
+       service->stats.rx_dropped_update = 0;
+       service->stats.tx_dropped_update = 0;
+       service->stats.time_update = 0;
 
-unsigned long __connman_service_stats_get_rx_dropped(struct connman_service *service)
-{
-       return service->stats.rx_dropped;
-}
+       g_timer_reset(service->stats.timer);
 
-unsigned long __connman_service_stats_get_tx_dropped(struct connman_service *service)
-{
-       return service->stats.tx_dropped;
-}
-
-unsigned long __connman_service_stats_get_time(struct connman_service *service)
-{
-       return service->stats.time;
+       /* roaming */
+       service->stats_roaming.valid = FALSE;
+
+       service->stats_roaming.rx_packets = 0;
+       service->stats_roaming.tx_packets = 0;
+       service->stats_roaming.rx_bytes = 0;
+       service->stats_roaming.tx_bytes = 0;
+       service->stats_roaming.rx_errors = 0;
+       service->stats_roaming.tx_errors = 0;
+       service->stats_roaming.rx_dropped = 0;
+       service->stats_roaming.tx_dropped = 0;
+       service->stats_roaming.time = 0;
+       service->stats_roaming.time_start = 0;
+
+       service->stats_roaming.rx_packets_update = 0;
+       service->stats_roaming.tx_packets_update = 0;
+       service->stats_roaming.rx_bytes_update = 0;
+       service->stats_roaming.tx_bytes_update = 0;
+       service->stats_roaming.rx_errors_update = 0;
+       service->stats_roaming.tx_errors_update = 0;
+       service->stats_roaming.rx_dropped_update = 0;
+       service->stats_roaming.tx_dropped_update = 0;
+       service->stats_roaming.time_update = 0;
+
+       g_timer_reset(service->stats_roaming.timer);
 }
 
 static struct connman_service *get_default(void)
@@ -991,6 +1051,88 @@ static void proxy_changed(struct connman_service *service)
                                                        append_proxy, service);
 }
 
+static void stats_append(DBusMessageIter *dict,
+                       struct connman_stats *stats,
+                       connman_bool_t append_all)
+{
+       if (stats->rx_packets_update != stats->rx_packets || append_all) {
+               stats->rx_packets_update = stats->rx_packets;
+               connman_dbus_dict_append_basic(dict, "RX.Packets",
+                                       DBUS_TYPE_UINT32, &stats->rx_packets);
+       }
+
+       if (stats->tx_packets_update != stats->tx_packets || append_all) {
+               stats->tx_packets_update = stats->tx_packets;
+               connman_dbus_dict_append_basic(dict, "TX.Packets",
+                                       DBUS_TYPE_UINT32, &stats->tx_packets);
+       }
+
+       if (stats->rx_bytes_update != stats->rx_bytes || append_all) {
+               stats->rx_bytes_update = stats->rx_bytes;
+               connman_dbus_dict_append_basic(dict, "RX.Bytes",
+                                       DBUS_TYPE_UINT32, &stats->rx_bytes);
+       }
+
+       if (stats->tx_bytes_update != stats->tx_bytes || append_all) {
+               stats->tx_bytes_update = stats->tx_bytes;
+               connman_dbus_dict_append_basic(dict, "TX.Bytes",
+                                       DBUS_TYPE_UINT32, &stats->tx_bytes);
+       }
+
+       if (stats->rx_errors_update != stats->rx_errors || append_all) {
+               stats->rx_errors_update = stats->rx_errors;
+               connman_dbus_dict_append_basic(dict, "RX.Errors",
+                                       DBUS_TYPE_UINT32, &stats->rx_errors);
+       }
+
+       if (stats->tx_errors_update != stats->tx_errors || append_all) {
+               stats->tx_errors_update = stats->tx_errors;
+               connman_dbus_dict_append_basic(dict, "TX.Errors",
+                                       DBUS_TYPE_UINT32, &stats->tx_errors);
+       }
+
+       if (stats->rx_dropped_update != stats->rx_dropped || append_all) {
+               stats->rx_dropped_update = stats->rx_dropped;
+               connman_dbus_dict_append_basic(dict, "RX.Dropped",
+                                       DBUS_TYPE_UINT32, &stats->rx_dropped);
+       }
+
+       if (stats->tx_dropped_update != stats->tx_dropped || append_all) {
+               stats->tx_dropped_update = stats->tx_dropped;
+               connman_dbus_dict_append_basic(dict, "TX.Dropped",
+                                       DBUS_TYPE_UINT32, &stats->tx_dropped);
+       }
+
+       if (stats->time_update != stats->time || append_all) {
+               stats->time_update = stats->time;
+               connman_dbus_dict_append_basic(dict, "Time",
+                                       DBUS_TYPE_UINT32, &stats->time);
+       }
+}
+
+void __connman_service_stats_append(struct connman_service *service,
+                                               DBusMessage *msg,
+                                               connman_bool_t append_all)
+{
+       DBusMessageIter array, dict;
+
+       dbus_message_iter_init_append(msg, &array);
+
+       /* home counter */
+       connman_dbus_dict_open(&array, &dict);
+
+       stats_append(&dict, &service->stats, append_all);
+
+       connman_dbus_dict_close(&array, &dict);
+
+       /* roaming counter */
+       connman_dbus_dict_open(&array, &dict);
+
+       stats_append(&dict, &service->stats_roaming, append_all);
+
+       connman_dbus_dict_close(&array, &dict);
+}
+
 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
                                        struct connman_service *service)
 {
@@ -2046,6 +2188,8 @@ static void service_free(gpointer user_data)
 
        if (service->stats.timer != NULL)
                g_timer_destroy(service->stats.timer);
+       if (service->stats_roaming.timer != NULL)
+               g_timer_destroy(service->stats_roaming.timer);
 
        g_free(service);
 }
@@ -2075,6 +2219,19 @@ void __connman_service_put(struct connman_service *service)
        }
 }
 
+static void stats_init(struct connman_service *service)
+{
+       /* home */
+       service->stats.valid = FALSE;
+       service->stats.enabled = FALSE;
+       service->stats.timer = g_timer_new();
+
+       /* roaming */
+       service->stats_roaming.valid = FALSE;
+       service->stats_roaming.enabled = FALSE;
+       service->stats_roaming.timer = g_timer_new();
+}
+
 static void service_initialize(struct connman_service *service)
 {
        DBG("service %p", service);
@@ -2096,9 +2253,7 @@ static void service_initialize(struct connman_service *service)
 
        service->order = 0;
 
-       service->stats.valid = FALSE;
-       service->stats.enabled = FALSE;
-       service->stats.timer = g_timer_new();
+       stats_init(service);
 
        service->provider = NULL;
 }
@@ -2991,6 +3146,7 @@ static void service_up(struct connman_ipconfig *ipconfig)
        connman_info("%s up", connman_ipconfig_get_ifname(ipconfig));
 
        service->stats.valid = FALSE;
+       service->stats_roaming.valid = FALSE;
 }
 
 static void service_down(struct connman_ipconfig *ipconfig)
@@ -3376,6 +3532,7 @@ void __connman_service_update_from_network(struct connman_network *network)
        connman_bool_t roaming;
        GSequenceIter *iter;
        const char *name;
+       connman_bool_t stats_enable;
 
        DBG("network %p", network);
 
@@ -3408,8 +3565,15 @@ roaming:
        if (roaming == service->roaming)
                goto done;
 
+       stats_enable = stats_enabled(service);
+       if (stats_enable == TRUE)
+               stats_stop(service);
+
        service->roaming = roaming;
 
+       if (stats_enable == TRUE)
+               stats_start(service);
+
        roaming_changed(service);
 
        iter = g_hash_table_lookup(service_hash, service->identifier);
@@ -3506,21 +3670,22 @@ __connman_service_create_from_provider(struct connman_provider *provider)
        return service;
 }
 
-void __connman_service_stats_update(struct connman_service *service,
+connman_bool_t __connman_service_stats_update(struct connman_service *service,
                                unsigned int rx_packets, unsigned int tx_packets,
                                unsigned int rx_bytes, unsigned int tx_bytes,
                                unsigned int rx_errors, unsigned int tx_errors,
                                unsigned int rx_dropped, unsigned int tx_dropped)
 {
        unsigned int seconds;
-       struct connman_stats *stats = &service->stats;
+       struct connman_stats *stats = stats_get(service);
+       gboolean valid = stats->valid;
 
        DBG("service %p", service);
 
        if (is_connected(service) == FALSE)
-               return;
+               return valid;
 
-       if (stats->valid == TRUE) {
+       if (valid == TRUE) {
                stats->rx_packets +=
                        rx_packets - stats->rx_packets_last;
                stats->tx_packets +=
@@ -3552,6 +3717,8 @@ void __connman_service_stats_update(struct connman_service *service,
 
        seconds = g_timer_elapsed(stats->timer, NULL);
        stats->time = stats->time_start + seconds;
+
+       return valid;
 }
 
 static int service_load(struct connman_service *service)
@@ -3720,7 +3887,7 @@ static int service_load(struct connman_service *service)
                service->domains = NULL;
        }
 
-       stats_load(service, keyfile, service->identifier);
+       stats_load(service, keyfile);
 done:
        g_key_file_free(keyfile);
 
@@ -3882,7 +4049,7 @@ update:
                g_key_file_remove_key(keyfile, service->identifier,
                                                        "Domains", NULL);
 
-       stats_save(service, keyfile, service->identifier);
+       stats_save(service, keyfile);
 
        data = g_key_file_to_data(keyfile, &length, NULL);
 
index 8b3062c..c05449a 100755 (executable)
@@ -29,7 +29,7 @@ def print_stats(stats):
 
        for key in keys:
                val = int(stats[key])
-               str = "  %s = %s" % (key, val)
+               str = "    %s = %s" % (key, val)
 
                if key in ["RX.Bytes", "TX.Bytes"]:
                        hstr = make_bytes_readable(val)
@@ -49,8 +49,13 @@ class Counter(dbus.service.Object):
                                in_signature='oa{sv}a{sv}', out_signature='')
        def Usage(self, path, home, roaming):
                print "%s" % (path)
-               print_stats(home)
-               print_stats(roaming)
+
+               if len(home) > 0:
+                       print "  Home"
+                       print_stats(home)
+               if len(roaming) > 0:
+                       print "  Roaming"
+                       print_stats(roaming)
 
 if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)