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