Add a statistic property to Service. Currently it shows how
many bytes where transfered with this Service beeing online.
The information is stored into the profile file. 

---
Just an update on the stuff I'm working on. 

This patch relies on the "Use only one counter update handler"
patch I send early today. 

Have nice weekend!

v1: - track online time
    - fix byte counting. overflow and reseting are handled
    - update statistics without relying on Counter object 
    - added Statistics dictionary to servicy property
v0: - initial version

 bootstrap-configure   |    2 
 doc/service-api.txt   |   18 ++++
 include/ipconfig.h    |    2 
 src/ipconfig.c        |    6 +
 src/service.c         |  201 +++++++++++++++++++++++++++++++++++++++++++++++--
 test/get-services     |    2 
 test/list-services    |    2 
 test/monitor-services |    2 
 8 files changed, 222 insertions(+), 13 deletions(-)

diff --git a/doc/service-api.txt b/doc/service-api.txt
index 79ac93c..037c3ee 100644
--- a/doc/service-api.txt
+++ b/doc/service-api.txt
@@ -104,6 +104,10 @@ Methods            dict GetProperties()
 
                        Possible Errors: [service].Error.InvalidArguments
 
+               void ResetStatistics()
+
+                       Reset all statistics values.
+
 Signals                PropertyChanged(string name, variant value)
 
                        This signal indicates a changed value of the given
@@ -398,3 +402,17 @@ Properties string State [readonly]
 
                                This information might not always be
                                available.
+
+               dict Statistics [readonly]
+
+                       TR.Bytes
+
+                               Number of bytes receivced.
+
+                       TX.Bytes
+
+                               Number of transmited bytes.
+
+                       Time
+
+                               The amount of time online in seconds.
diff --git a/include/ipconfig.h b/include/ipconfig.h
index 0b70252..61757f4 100644
--- a/include/ipconfig.h
+++ b/include/ipconfig.h
@@ -71,6 +71,8 @@ struct connman_ipconfig_ops {
        void (*lower_down) (struct connman_ipconfig *ipconfig);
        void (*ip_bound) (struct connman_ipconfig *ipconfig);
        void (*ip_release) (struct connman_ipconfig *ipconfig);
+       void (*stats_update) (struct connman_ipconfig *ipconfig,
+                       unsigned int rx_bytes, unsigned int tx_bytes);
 };
 
 struct connman_ipconfig *connman_ipconfig_create(int index);
diff --git a/src/ipconfig.c b/src/ipconfig.c
index 5af7c9c..45a15d6 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -369,6 +369,12 @@ static void update_stats(struct connman_ipdevice *ipdevice,
 
        __connman_counter_notify(ipdevice->ifname,
                                ipdevice->rx_bytes, ipdevice->tx_bytes);
+
+       if (ipdevice->config->ops != NULL &&
+                       ipdevice->config->ops->stats_update != NULL)
+               ipdevice->config->ops->stats_update(
+                               ipdevice->config,
+                               ipdevice->rx_bytes, ipdevice->tx_bytes);
 }
 
 void __connman_ipconfig_newlink(int index, unsigned short type,
diff --git a/src/service.c b/src/service.c
index d9d3faf..d813da3 100644
--- a/src/service.c
+++ b/src/service.c
@@ -79,6 +79,15 @@ struct connman_service {
        DBusMessage *pending;
        guint timeout;
        struct connman_location *location;
+       /* Statistics */
+       connman_bool_t stats_valid;
+       uint32_t stats_rx_bytes_last;
+       uint32_t stats_tx_bytes_last;
+       uint32_t stats_rx_bytes;
+       uint32_t stats_tx_bytes;
+       uint32_t stats_time_start;
+       uint32_t stats_time;
+       GTimer *stats_timer;
 };
 
 static void append_path(gpointer value, gpointer user_data)
@@ -349,6 +358,106 @@ void __connman_service_remove_nameserver(struct 
connman_service *service,
        update_nameservers(service);
 }
 
+static void __connman_service_stats_timer_update(struct connman_service 
*service)
+{
+       uint32_t seconds;
+
+       DBG("service %p", service);
+
+       if (service->stats_timer == NULL)
+               return;
+
+       if (is_connected(service) == FALSE)
+               return;
+
+       seconds = (uint32_t)g_timer_elapsed(service->stats_timer, NULL);
+       service->stats_time = service->stats_time_start + seconds;
+}
+
+static void __connman_service_stats_timer_start(struct connman_service 
*service)
+{
+       DBG("service %p", service);
+
+       if (service->stats_timer == NULL)
+               return;
+
+       service->stats_time_start = service->stats_time;
+
+       g_timer_start(service->stats_timer);
+       __connman_rtnl_update_interval_add(10);
+}
+
+static void __connman_service_stats_timer_stop(struct connman_service *service)
+{
+       uint32_t seconds;
+
+       DBG("service %p", service);
+
+       if (service->stats_timer == NULL)
+               return;
+
+       __connman_rtnl_update_interval_remove(10);
+       g_timer_stop(service->stats_timer);
+
+       seconds = (uint32_t)g_timer_elapsed(service->stats_timer, NULL);
+       service->stats_time = service->stats_time_start + seconds;
+}
+
+static int __connman_service_stats_load(struct connman_service *service,
+               GKeyFile *keyfile, const char *identifier, const char *prefix)
+{
+       char *key;
+
+       key = g_strdup_printf("%srx_bytes", prefix);
+       service->stats_rx_bytes = g_key_file_get_integer(keyfile,
+                               identifier, key, NULL);
+       g_free(key);
+
+       key = g_strdup_printf("%stx_bytes", prefix);
+       service->stats_tx_bytes = g_key_file_get_integer(keyfile,
+                               identifier, key, NULL);
+       g_free(key);
+
+       key = g_strdup_printf("%stime", prefix);
+       service->stats_time = g_key_file_get_integer(keyfile,
+                               identifier, key, NULL);
+       g_free(key);
+
+       return 0;
+}
+
+static int __connman_service_stats_save(struct connman_service *service,
+               GKeyFile *keyfile, const char *identifier, const char *prefix)
+{
+       char *key;
+
+       key = g_strdup_printf("%srx_bytes", prefix);
+       g_key_file_set_integer(keyfile, identifier, key, 
+                       service->stats_rx_bytes);
+       g_free(key);
+
+       key = g_strdup_printf("%stx_bytes", prefix);
+       g_key_file_set_integer(keyfile, identifier, key, 
+                       service->stats_tx_bytes);
+       g_free(key);
+
+       key = g_strdup_printf("%stime", prefix);
+       g_key_file_set_integer(keyfile, identifier, key, 
+                       service->stats_time);
+       g_free(key);
+
+       return 0;
+}
+
+static void __connman_service_reset_stats(struct connman_service *service)
+{
+       service->stats_valid = FALSE;
+       service->stats_rx_bytes = 0;
+       service->stats_tx_bytes = 0;
+       service->stats_time = 0;
+       service->stats_time_start = 0;
+}
+
 static struct connman_service *get_default(void)
 {
        struct connman_service *service;
@@ -625,6 +734,23 @@ static void append_proxy(DBusMessageIter *iter, void 
*user_data)
                __connman_ipconfig_append_proxy(service->ipconfig, iter);
 }
 
+static void append_stats(DBusMessageIter *iter, void *user_data)
+{
+       struct connman_service *service = user_data;
+
+
+       connman_dbus_dict_append_basic(iter, "RX.Bytes", DBUS_TYPE_UINT32,
+                               &service->stats_rx_bytes);
+
+       connman_dbus_dict_append_basic(iter, "TX.Bytes", DBUS_TYPE_UINT32,
+                               &service->stats_tx_bytes);
+
+       /* XXX Where should the update triggered, e.g. 
g_timeout_add_seconds(5,...)? */
+       __connman_service_stats_timer_update(service);
+       connman_dbus_dict_append_basic(iter, "Time", DBUS_TYPE_UINT32,
+                               &service->stats_time);
+}
+
 static void settings_changed(struct connman_service *service)
 {
        connman_dbus_property_changed_dict(service->path,
@@ -812,6 +938,8 @@ static void append_properties(DBusMessageIter *dict, 
dbus_bool_t limited,
                                DBUS_TYPE_STRING, append_domainconfig, service);
 
        connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
+
+       connman_dbus_dict_append_dict(dict, "Statistics", append_stats, 
service);
 }
 
 static void append_struct(gpointer value, gpointer user_data)
@@ -1518,16 +1646,29 @@ static DBusMessage *move_after(DBusConnection *conn,
        return move_service(conn, msg, user_data, FALSE);
 }
 
+static DBusMessage *reset_stats(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct connman_service *service = user_data;
+
+       DBG("service %p", service);
+
+       __connman_service_reset_stats(service);
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
 static GDBusMethodTable service_methods[] = {
-       { "GetProperties", "",   "a{sv}", get_properties     },
-       { "SetProperty",   "sv", "",      set_property       },
-       { "ClearProperty", "s",  "",      clear_property     },
-       { "Connect",       "",   "",      connect_service,
+       { "GetProperties",   "",   "a{sv}", get_properties     },
+       { "SetProperty",     "sv", "",      set_property       },
+       { "ClearProperty",   "s",  "",      clear_property     },
+       { "Connect",         "",   "",      connect_service,
                                                G_DBUS_METHOD_FLAG_ASYNC },
-       { "Disconnect",    "",   "",      disconnect_service },
-       { "Remove",        "",   "",      remove_service     },
-       { "MoveBefore",    "o",  "",      move_before        },
-       { "MoveAfter",     "o",  "",      move_after         },
+       { "Disconnect",      "",   "",      disconnect_service },
+       { "Remove",          "",   "",      remove_service     },
+       { "MoveBefore",      "o",  "",      move_before        },
+       { "MoveAfter",       "o",  "",      move_after         },
+       { "ResetStatistics", "",   "",      reset_stats        },
        { },
 };
 
@@ -1588,6 +1729,10 @@ static void service_free(gpointer user_data)
        g_free(service->private_key_file);
        g_free(service->private_key_passphrase);
        g_free(service->phase2);
+
+       if (service->stats_timer != NULL)
+               g_timer_destroy(service->stats_timer);
+
        g_free(service);
 }
 
@@ -1636,6 +1781,9 @@ static void __connman_service_initialize(struct 
connman_service *service)
        service->userconnect = FALSE;
 
        service->order = 0;
+
+       service->stats_valid = FALSE;
+       service->stats_timer = g_timer_new();
 }
 
 /**
@@ -1926,6 +2074,8 @@ int __connman_service_indicate_state(struct 
connman_service *service,
 
                __connman_notifier_connect(service->type);
 
+               __connman_service_stats_timer_start(service);
+
                default_changed();
        } else if (state == CONNMAN_SERVICE_STATE_DISCONNECT) {
                __connman_location_finish(service);
@@ -1936,6 +2086,9 @@ int __connman_service_indicate_state(struct 
connman_service *service,
                dns_changed(service);
 
                __connman_notifier_disconnect(service->type);
+
+               __connman_service_stats_timer_stop(service);
+               __connman_storage_save_service(service);
        }
 
        if (state == CONNMAN_SERVICE_STATE_FAILURE) {
@@ -2484,7 +2637,11 @@ static int service_register(struct connman_service 
*service)
 
 static void service_up(struct connman_ipconfig *ipconfig)
 {
+       struct connman_service *service = connman_ipconfig_get_data(ipconfig);
+
        connman_info("%s up", connman_ipconfig_get_ifname(ipconfig));
+
+       service->stats_valid = FALSE;
 }
 
 static void service_down(struct connman_ipconfig *ipconfig)
@@ -2520,6 +2677,28 @@ static void service_ip_release(struct connman_ipconfig 
*ipconfig)
        settings_changed(service);
 }
 
+static void service_stats_update(struct connman_ipconfig *ipconfig,
+                               unsigned int rx_bytes, unsigned int tx_bytes)
+{
+       struct connman_service *service = connman_ipconfig_get_data(ipconfig);
+       const char *ifname = connman_ipconfig_get_ifname(service->ipconfig);
+
+       if (ifname == NULL)
+               return;
+
+       DBG("service %p interface %s\n", service, ifname);
+
+       if (service->stats_valid == TRUE) {
+               service->stats_rx_bytes += rx_bytes - 
service->stats_rx_bytes_last;
+               service->stats_tx_bytes += tx_bytes - 
service->stats_tx_bytes_last;
+       } else {
+               service->stats_valid = TRUE;
+       }
+
+       service->stats_rx_bytes_last = rx_bytes;
+       service->stats_tx_bytes_last = tx_bytes;
+}
+
 static const struct connman_ipconfig_ops service_ops = {
        .up             = service_up,
        .down           = service_down,
@@ -2527,6 +2706,7 @@ static const struct connman_ipconfig_ops service_ops = {
        .lower_down     = service_lower_down,
        .ip_bound       = service_ip_bound,
        .ip_release     = service_ip_release,
+       .stats_update   = service_stats_update,
 };
 
 static void setup_ipconfig(struct connman_service *service, int index)
@@ -3069,6 +3249,8 @@ static int service_load(struct connman_service *service)
                service->domains = NULL;
        }
 
+       __connman_service_stats_load(service, keyfile,
+                               service->identifier, "Stats.");
 done:
        g_key_file_free(keyfile);
 
@@ -3222,6 +3404,9 @@ update:
                g_key_file_remove_key(keyfile, service->identifier,
                                                        "Domains", NULL);
 
+       __connman_service_stats_save(service, keyfile,
+                               service->identifier, "Stats.");
+
        data = g_key_file_to_data(keyfile, &length, NULL);
 
        if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
diff --git a/test/get-services b/test/get-services
index 1afebc5..e0669b4 100755
--- a/test/get-services
+++ b/test/get-services
@@ -31,7 +31,7 @@ for entry in services:
        print "[ %s ]" % (path)
 
        for key in properties.keys():
-               if key in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet"]:
+               if key in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet", 
"Statistics"]:
                        val = extract_values(properties[key])
                elif key in ["Nameservers", "Nameservers.Configuration",
                                        "Domains", "Domains.Configuration"]:
diff --git a/test/list-services b/test/list-services
index abe8420..53d0718 100755
--- a/test/list-services
+++ b/test/list-services
@@ -33,7 +33,7 @@ for path in properties["Services"]:
        print "[ %s ]" % (path)
 
        for key in properties.keys():
-               if key in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet"]:
+               if key in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet", 
"Statistics"]:
                        val = extract_values(properties[key])
                elif key in ["Nameservers", "Nameservers.Configuration",
                                        "Domains", "Domains.Configuration"]:
diff --git a/test/monitor-services b/test/monitor-services
index 93fd758..40d2494 100755
--- a/test/monitor-services
+++ b/test/monitor-services
@@ -28,7 +28,7 @@ def property_changed(name, value, path):
                for i in value:
                        val = val + " " + i[i.rfind("/") + 1:]
                val = val + " ]"
-       elif name in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet"]:
+       elif name in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet", 
"Statistics"]:
                val = extract_values(value)
        elif name in ["Nameservers", "Nameservers.Configuration",
                                        "Domains", "Domains.Configuration"]:


_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman

Reply via email to