From: Daniel Wagner <[email protected]>
When the ring buffer (.data file) is full
or timeout is reached (e.g. 1 day) then
summize the contains into a .info file.
---
This is a rough version of this new feature. I've played a bit around
with different solutions and ended up with this one. The simple ringbuffer
dump tool is able to create stats file. Those file can then be used to
create the history file.
[w...@candlejack tools]$ ./stats-tool -h
Usage:
stats-tool [OPTION...]
Help Options:
-h, --help Show help options
Application Options:
-c, --create=NR Create a .data file with NR faked entries
-i, --interval=INTERVAL Interval in seconds (used with create)
-d, --dump Dump contents of .data file
-s, --summary Summary of .data file
-f, --info .info file name
-t, --startts=TS Set start time for creating .data file (example
2010-11-05T23:00:12Z)
-l, --last Start values from last .data file
[w...@candlejack tools]$ ./stats-tool -c 1000 -i 1000 -t 2010-11-10T11:11:11Z
demo1.data
[w...@candlejack tools]$ ./stats-tool -c 1000 -i 1000 -l demo1.data demo2.data
[w...@candlejack tools]$ ./stats-tool -s demo1.data
Data Structure Sizes
sizeof header 20/0x14
sizeof entry 48/030
File
addr 0x7fb9b4740000
len 49152
max nr entries 1023
nr entries 1000
Header
magic 0xfa00b916
begin [0] 0x00000014
end [1000] 0x0000bb94
home [-1431655766] 0x00000000
roaming [-1431655766] 0x00000000
Pointers
hdr 0x7fb9b4740000
begin 0x7fb9b4740014
end 0x7fb9b474bb94
home 0x7fb9b4740000
romaing 0x7fb9b4740000
first 0x7fb9b4740014
last 0x7fb9b474bfb4
(begin + 1)
[0001] 0x7fb9b4740044 1289387854 10-11-2010 11:17:34 0 0 0 0 0 0 0 0 0
383
end
[1000] 0x7fb9b474bb94 1289881412 16-11-2010 04:23:32 0 640 609 489389
444440 0 0 0 0 493941
home
rx_packets: 0
tx_packets: 0
rx_bytes: 1289387471
tx_bytes: 0
rx_errors: 0
tx_errors: 0
rx_dropped: 0
tx_dropped: 0
time: -383
[w...@candlejack tools]$ ./stats-tool -s demo2.data
Data Structure Sizes
sizeof header 20/0x14
sizeof entry 48/030
File
addr 0x7f9de67a5000
len 49152
max nr entries 1023
nr entries 1000
Header
magic 0xfa00b916
begin [0] 0x00000014
end [1000] 0x0000bb94
home [-1431655766] 0x00000000
roaming [-1431655766] 0x00000000
Pointers
hdr 0x7f9de67a5000
begin 0x7f9de67a5014
end 0x7f9de67b0b94
home 0x7f9de67a5000
romaing 0x7f9de67a5000
first 0x7f9de67a5014
last 0x7f9de67b0fb4
(begin + 1)
[0001] 0x7f9de67a5044 1289881795 16-11-2010 04:29:55 0 640 609 489389
444440 0 0 0 0 494324
end
[1000] 0x7f9de67b0b94 1290375353 21-11-2010 21:35:53 0 1280 1218 978778
888880 0 0 0 0 987882
home
rx_packets: -640
tx_packets: -609
rx_bytes: 1289392023
tx_bytes: -444440
rx_errors: 0
tx_errors: 640
rx_dropped: 609
tx_dropped: 489389
time: -49884
[w...@candlejack tools]$ ./stats-tool demo1.data -f demo.info
Data Structure Sizes
sizeof header 20/0x14
sizeof entry 48/030
File
addr 0x7fa1ab2e5000
len 49152
max nr entries 1023
nr entries 1000
Header
magic 0xfa00b916
begin [0] 0x00000014
end [1000] 0x0000bb94
home [-1431655766] 0x00000000
roaming [-1431655766] 0x00000000
Pointers
hdr 0x7fa1ab2e5000
begin 0x7fa1ab2e5014
end 0x7fa1ab2f0b94
home 0x7fa1ab2e5000
romaing 0x7fa1ab2e5000
first 0x7fa1ab2e5014
last 0x7fa1ab2f0fb4
write todays records
process older records
0x7fa1ab2f0b94 1289881412 16-11-2010 04:23:32 0 640 609 489389 444440 0
0 0 0 493941
process period: 18.11.2010 - 18.11.2010
process period: 17.11.2010 - 17.11.2010
process period: 16.11.2010 - 16.11.2010
0x7fa1ab2f0b94 1289881412 16-11-2010 04:23:32 0 640 609 489389 444440 0
0 0 0 493941
0x7fa1ab2f0594 1289866171 16-11-2010 00:09:31 0 622 599 479954 435412 0
0 0 0 478700
process period: 15.11.2010 - 15.11.2010
0x7fa1ab2f0564 1289865502 15-11-2010 23:58:22 0 622 599 479954 435412 0
0 0 0 478031
0x7fa1ab2ee6d4 1289780012 15-11-2010 00:13:32 0 518 495 407308 365592 0
0 0 0 392541
process period: 14.11.2010 - 14.11.2010
0x7fa1ab2ee6a4 1289779087 14-11-2010 23:58:07 0 518 495 407308 365592 0
0 0 0 391616
0x7fa1ab2ec334 1289693049 14-11-2010 00:04:09 0 415 377 338364 282658 0
0 0 0 305578
process period: 13.11.2010 - 13.11.2010
0x7fa1ab2ec304 1289692694 13-11-2010 23:58:14 0 415 374 338364 279232 0
0 0 0 305223
0x7fa1ab2ea234 1289606513 13-11-2010 00:01:53 0 297 268 245794 198085 0
0 0 0 219042
process period: 12.11.2010 - 12.11.2010
0x7fa1ab2ea204 1289606043 12-11-2010 23:54:03 0 295 264 244234 193953 0
0 0 0 218572
0x7fa1ab2e8194 1289520464 12-11-2010 00:07:44 0 179 155 139096 113166 0
0 0 0 132993
process period: 11.11.2010 - 11.11.2010
0x7fa1ab2e8164 1289519488 11-11-2010 23:51:28 0 179 155 139096 113166 0
0 0 0 132017
0x7fa1ab2e6124 1289433722 11-11-2010 00:02:02 0 50 57 42257 40387 0 0 0
0 46251
process period: 10.11.2010 - 10.11.2010
0x7fa1ab2e60f4 1289432862 10-11-2010 23:47:42 0 50 57 42257 40387 0 0 0
0 45391
0x7fa1ab2e5044 1289387854 10-11-2010 11:17:34 0 0 0 0 0 0 0 0 0 383
[w...@candlejack tools]$ cat demo.info
20101116,20101116,18,10,9435,9028,0,0,0,0,15241,2010-11-16T00:09:31Z,0,622,599,479954,435412,0,0,0,0,478700
20101115,20101115,104,104,72646,69820,0,0,0,0,85490,2010-11-15T00:13:32Z,0,518,495,407308,365592,0,0,0,0,392541
20101114,20101114,103,118,68944,82934,0,0,0,0,86038,2010-11-14T00:04:09Z,0,415,377,338364,282658,0,0,0,0,305578
20101113,20101113,118,106,92570,81147,0,0,0,0,86181,2010-11-13T00:01:53Z,0,297,268,245794,198085,0,0,0,0,219042
20101112,20101112,116,109,105138,80787,0,0,0,0,85579,2010-11-12T00:07:44Z,0,179,155,139096,113166,0,0,0,0,132993
20101111,20101111,129,98,96839,72779,0,0,0,0,85766,2010-11-11T00:02:02Z,0,50,57,42257,40387,0,0,0,0,46251
20101110,20101110,50,57,42257,40387,0,0,0,0,45008,2010-11-10T11:17:34Z,0,0,0,0,0,0,0,0,0,383
[w...@candlejack tools]$ ./stats-tool demo2.data -f demo.info
Data Structure Sizes
sizeof header 20/0x14
sizeof entry 48/030
File
addr 0x7fc65e9f1000
len 49152
max nr entries 1023
nr entries 1000
Header
magic 0xfa00b916
begin [0] 0x00000014
end [1000] 0x0000bb94
home [-1431655766] 0x00000000
roaming [-1431655766] 0x00000000
Pointers
hdr 0x7fc65e9f1000
begin 0x7fc65e9f1014
end 0x7fc65e9fcb94
home 0x7fc65e9f1000
romaing 0x7fc65e9f1000
first 0x7fc65e9f1014
last 0x7fc65e9fcfb4
invalid line found ''
write todays records
process older records
0x7fc65e9f6ad4 1290123897 18-11-2010 23:44:57 0 970 895 762649 654417 0
0 0 0 736426
process period: 18.11.2010 - 18.11.2010
0x7fc65e9f6ad4 1290123897 18-11-2010 23:44:57 0 970 895 762649 654417 0
0 0 0 736426
0x7fc65e9f4b54 1290039174 18-11-2010 00:12:54 0 855 791 657848 571831 0
0 0 0 651703
process period: 17.11.2010 - 17.11.2010
0x7fc65e9f4b24 1290038249 17-11-2010 23:57:29 0 855 791 657848 571831 0
0 0 0 650778
0x7fc65e9f2a84 1289952462 17-11-2010 00:07:42 0 744 691 563367 501977 0
0 0 0 564991
process period: 16.11.2010 - 16.11.2010
0x7fc65e9f2a54 1289951969 16-11-2010 23:59:29 0 744 691 563367 501977 0
0 0 0 564498
0x7fc65e9ef044 1289866171 16-11-2010 00:09:31 0 622 599 479954 435412 0
0 0 0 478700
process period: 15.11.2010 - 15.11.2010
0x7fc65e9ef074 1289780012 15-11-2010 00:13:32 0 518 495 407308 365592 0
0 0 0 392541
0x7fc65e9ef074 1289780012 15-11-2010 00:13:32 0 518 495 407308 365592 0
0 0 0 392541
process period: 14.11.2010 - 14.11.2010
0x7fc65e9ef0a4 1289693049 14-11-2010 00:04:09 0 415 377 338364 282658 0
0 0 0 305578
0x7fc65e9ef0a4 1289693049 14-11-2010 00:04:09 0 415 377 338364 282658 0
0 0 0 305578
process period: 13.11.2010 - 13.11.2010
0x7fc65e9ef0d4 1289606513 13-11-2010 00:01:53 0 297 268 245794 198085 0
0 0 0 219042
0x7fc65e9ef0d4 1289606513 13-11-2010 00:01:53 0 297 268 245794 198085 0
0 0 0 219042
process period: 12.11.2010 - 12.11.2010
0x7fc65e9ef104 1289520464 12-11-2010 00:07:44 0 179 155 139096 113166 0
0 0 0 132993
0x7fc65e9ef104 1289520464 12-11-2010 00:07:44 0 179 155 139096 113166 0
0 0 0 132993
process period: 11.11.2010 - 11.11.2010
0x7fc65e9ef134 1289433722 11-11-2010 00:02:02 0 50 57 42257 40387 0 0 0
0 46251
0x7fc65e9ef134 1289433722 11-11-2010 00:02:02 0 50 57 42257 40387 0 0 0
0 46251
process period: 10.11.2010 - 10.11.2010
0x7fc65e9ef164 1289387854 10-11-2010 11:17:34 0 0 0 0 0 0 0 0 0 383
0x7fc65e9ef164 1289387854 10-11-2010 11:17:34 0 0 0 0 0 0 0 0 0 383
[w...@candlejack tools]$ cat demo.info
20101121,20101121,0,0,0,0,0,0,0,0,0,2010-11-21T21:35:53Z,0,1280,1218,978778,888880,0,0,0,0,987882
20101121,20101121,0,0,0,0,0,0,0,0,0,2010-11-21T21:23:50Z,0,1280,1218,978778,888880,0,0,0,0,987159
20101121,20101121,0,0,0,0,0,0,0,0,0,2010-11-21T21:08:32Z,0,1280,1216,978778,886522,0,0,0,0,986241
[...]
20101119,20101119,0,0,0,0,0,0,0,0,0,2010-11-19T00:33:18Z,0,973,900,765796,658768,0,0,0,0,739327
20101119,20101119,0,0,0,0,0,0,0,0,0,2010-11-19T00:30:04Z,0,973,900,765796,658768,0,0,0,0,739133
20101119,20101119,0,0,0,0,0,0,0,0,0,2010-11-19T00:17:18Z,0,973,900,765796,658768,0,0,0,0,738367
20101119,20101119,0,0,0,0,0,0,0,0,0,2010-11-19T00:08:30Z,0,973,899,765796,658205,0,0,0,0,737839
20101119,20101119,0,0,0,0,0,0,0,0,0,2010-11-19T00:04:41Z,0,970,899,762649,658205,0,0,0,0,737610
20101119,20101119,0,0,0,0,0,0,0,0,0,2010-11-19T00:00:46Z,0,970,895,762649,654417,0,0,0,0,737375
20101118,20101118,115,104,104801,82586,0,0,0,0,84723,2010-11-18T00:12:54Z,0,855,791,657848,571831,0,0,0,0,651703
20101117,20101117,111,100,94481,69854,0,0,0,0,85787,2010-11-17T00:07:42Z,0,744,691,563367,501977,0,0,0,0,564991
20101116,20101116,122,92,83413,66565,0,0,0,0,85798,2010-11-16T00:09:31Z,0,622,599,479954,435412,0,0,0,0,478700
20101115,20101115,518,495,407308,365592,0,0,0,0,392541,2010-11-15T00:13:32Z,0,518,495,407308,365592,0,0,0,0,392541
20101114,20101114,415,377,338364,282658,0,0,0,0,305578,2010-11-14T00:04:09Z,0,415,377,338364,282658,0,0,0,0,305578
20101113,20101113,297,268,245794,198085,0,0,0,0,219042,2010-11-13T00:01:53Z,0,297,268,245794,198085,0,0,0,0,219042
20101112,20101112,179,155,139096,113166,0,0,0,0,132993,2010-11-12T00:07:44Z,0,179,155,139096,113166,0,0,0,0,132993
20101111,20101111,50,57,42257,40387,0,0,0,0,46251,2010-11-11T00:02:02Z,0,50,57,42257,40387,0,0,0,0,46251
20101110,20101110,0,0,0,0,0,0,0,0,383,2010-11-10T11:17:34Z,0,0,0,0,0,0,0,0,0,383
Makefile.am | 4 +-
tools/stats-ringbuffer-dump.c | 408 --------------
tools/stats-tool.c | 1209 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 1212 insertions(+), 409 deletions(-)
delete mode 100644 tools/stats-ringbuffer-dump.c
create mode 100644 tools/stats-tool.c
diff --git a/Makefile.am b/Makefile.am
index cba6b9c..ccb7c28 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -132,7 +132,7 @@ noinst_PROGRAMS += tools/wispr tools/wifi-scan
tools/supplicant-test \
tools/addr-test tools/web-test tools/resolv-test \
tools/dbus-test tools/polkit-test \
tools/iptables-test tools/tap-test tools/wpad-test \
- tools/stats-ringbuffer-dump
+ tools/stats-tool
tools_wispr_SOURCES = $(gweb_sources) tools/wispr.c
tools_wispr_LDADD = @GLIB_LIBS@ @GNUTLS_LIBS@ -lresolv
@@ -164,6 +164,8 @@ tools_dbus_test_LDADD = @GLIB_LIBS@ @DBUS_LIBS@
tools_polkit_test_LDADD = @DBUS_LIBS@
+tools_stats_tool_LDADD = @GLIB_LIBS@
+
tools_iptables_test_LDADD = @GLIB_LIBS@ @XTABLES_LIBS@
if DHCLIENT
diff --git a/tools/stats-ringbuffer-dump.c b/tools/stats-ringbuffer-dump.c
deleted file mode 100644
index d4eb711..0000000
--- a/tools/stats-ringbuffer-dump.c
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2010 BMW Car IT GmbH. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <limits.h>
-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#define MAGIC 0xFA00B916
-
-struct connman_stats_data {
- 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 time;
-};
-
-struct stats_file_header {
- unsigned int magic;
- unsigned int begin;
- unsigned int end;
- unsigned int home;
- unsigned int roaming;
-};
-
-struct stats_record {
- time_t ts;
- unsigned int roaming;
- struct connman_stats_data data;
-};
-
-struct stats_file {
- int fd;
- char *name;
- char *addr;
- size_t len;
-
- /* cached values */
- int max_nr;
- int nr;
- struct stats_record *first;
- struct stats_record *last;
- struct stats_record *home_first;
- struct stats_record *roaming_first;
-};
-
-static struct stats_file_header *get_hdr(struct stats_file *file)
-{
- return (struct stats_file_header *)file->addr;
-}
-
-static struct stats_record *get_begin(struct stats_file *file)
-{
- unsigned int off = get_hdr(file)->begin;
-
- return (struct stats_record *)(file->addr + off);
-}
-
-static struct stats_record *get_end(struct stats_file *file)
-{
- unsigned int off = get_hdr(file)->end;
-
- return (struct stats_record *)(file->addr + off);
-}
-
-static struct stats_record *get_home(struct stats_file *file)
-{
- struct stats_file_header *hdr;
-
- hdr = get_hdr(file);
-
- if (hdr->home == UINT_MAX)
- return NULL;
-
- return (struct stats_record *)(file->addr + hdr->home);
-}
-
-static struct stats_record *get_roaming(struct stats_file *file)
-{
- struct stats_file_header *hdr;
-
- hdr = get_hdr(file);
-
- if (hdr->roaming == UINT_MAX)
- return NULL;
-
- return (struct stats_record *)(file->addr + hdr->roaming);
-}
-
-static struct stats_record *get_next(struct stats_file *file,
- struct stats_record *cur)
-{
- cur++;
-
- if (cur > file->last)
- cur = file->first;
-
- return cur;
-}
-
-static int get_index(struct stats_file *file, struct stats_record *rec)
-{
- return rec - file->first;
-}
-
-static void stats_print_record(struct stats_record *rec)
-{
- char buffer[30];
-
- strftime(buffer, 30, "%d-%m-%Y %T", localtime(&rec->ts));
- printf("%p %s %01d %d %d %d %d %d %d %d %d %d\n", rec, buffer,
- rec->roaming,
- rec->data.rx_packets,
- rec->data.tx_packets,
- rec->data.rx_bytes,
- rec->data.tx_bytes,
- rec->data.rx_errors,
- rec->data.tx_errors,
- rec->data.rx_dropped,
- rec->data.tx_dropped,
- rec->data.time);
-}
-
-static void stats_hdr_info(struct stats_file *file)
-{
- struct stats_file_header *hdr;
- struct stats_record *begin, *end, *home, *roaming;
- unsigned int home_idx, roaming_idx;
-
- hdr = get_hdr(file);
- begin = get_begin(file);
- end = get_end(file);
-
- home = get_home(file);
- if (home == NULL)
- home_idx = UINT_MAX;
- else
- home_idx = get_index(file, home);
-
- roaming = get_roaming(file);
- if (roaming == NULL)
- roaming_idx = UINT_MAX;
- else
- roaming_idx = get_index(file, roaming);
-
- printf("Data Structure Sizes\n");
- printf(" sizeof header %zd/0x%02zx\n",
- sizeof(struct stats_file_header),
- sizeof(struct stats_file_header));
- printf(" sizeof entry %zd/0%02zx\n\n",
- sizeof(struct stats_record),
- sizeof(struct stats_record));
-
- printf("File\n");
- printf(" addr %p\n", file->addr);
- printf(" len %zd\n", file->len);
-
- printf(" max nr entries %d\n", file->max_nr);
- printf(" nr entries %d\n\n", file->nr);
-
- printf("Header\n");
- printf(" magic 0x%08x\n", hdr->magic);
- printf(" begin [%d] 0x%08x\n",
- get_index(file, begin), hdr->begin);
- printf(" end [%d] 0x%08x\n",
- get_index(file, end), hdr->end);
- printf(" home [%d] 0x%08x\n",
- home_idx, hdr->home);
- printf(" roaming [%d] 0x%08x\n\n",
- roaming_idx, hdr->roaming);
-
-
- printf("Pointers\n");
- printf(" hdr %p\n", hdr);
- printf(" begin %p\n", begin);
- printf(" end %p\n", end);
- printf(" home %p\n", home);
- printf(" romaing %p\n", roaming);
- printf(" first %p\n", file->first);
- printf(" last %p\n\n", file->last);
-}
-
-static void stats_print_entries(struct stats_file *file)
-{
- struct stats_record *it;
- int i;
-
- printf("[ idx] ptr ts roaming rx_packets tx_packets rx_bytes "
- "tx_bytes rx_errors tx_errors rx_dropped tx_dropped time\n\n");
-
- for (i = 0, it = file->first; it <= file->last; it++, i++) {
- printf("[%04d] ", i);
- stats_print_record(it);
- }
-}
-
-static void stats_print_rec_diff(struct stats_record *begin,
- struct stats_record *end)
-{
- printf("\trx_packets: %d\n",
- end->data.rx_packets - begin->data.rx_packets);
- printf("\ttx_packets: %d\n",
- end->data.tx_packets - begin->data.tx_packets);
- printf("\trx_bytes: %d\n",
- end->data.rx_bytes - begin->data.rx_bytes);
- printf("\ttx_bytes: %d\n",
- end->data.tx_bytes - begin->data.tx_bytes);
- printf("\trx_errors: %d\n",
- end->data.rx_errors - begin->data.rx_errors);
- printf("\ttx_errors: %d\n",
- end->data.tx_errors - begin->data.tx_errors);
- printf("\trx_dropped: %d\n",
- end->data.rx_dropped - begin->data.rx_dropped);
- printf("\ttx_dropped: %d\n",
- end->data.tx_dropped - begin->data.tx_dropped);
- printf("\ttime: %d\n",
- end->data.time - begin->data.time);
-}
-
-static void stats_print_diff(struct stats_file *file)
-{
- struct stats_record *begin, *end;
-
- begin = get_begin(file);
- begin = get_next(file, begin);
- end = get_end(file);
-
- printf("\n(begin + 1)\n");
- printf("\t[%04d] ", get_index(file, begin));
- stats_print_record(begin);
- printf("end\n");
- printf("\t[%04d] ", get_index(file, end));
- stats_print_record(end);
-
- if (file->home_first) {
- printf("\nhome\n");
- stats_print_rec_diff(file->home_first, get_home(file));
- }
-
- if (file->roaming_first) {
- printf("\roaming\n");
- stats_print_rec_diff(file->roaming_first, get_roaming(file));
- }
-}
-
-static void update_max_nr_entries(struct stats_file *file)
-{
- file->max_nr = (file->len - sizeof(struct stats_file_header)) /
- sizeof(struct stats_record);
-}
-
-static void update_nr_entries(struct stats_file *file)
-{
- struct stats_record *begin, *end;
- int nr;
-
- begin = get_begin(file);
- end = get_end(file);
-
- nr = get_index(file, end) - get_index(file, begin);
-
- if (nr < 0)
- nr += file->max_nr;
-
- file->nr = nr;
-}
-
-static void update_first(struct stats_file *file)
-{
- file->first = (struct stats_record *)(file->addr +
- sizeof(struct stats_file_header));
-}
-
-static void update_last(struct stats_file *file)
-{
- struct stats_record *last;
-
- last = file->first;
- last += file->max_nr - 1;
-
- file->last = last;
-}
-
-static int stats_file_update_cache(struct stats_file *file)
-{
- struct stats_record *it;
-
- update_max_nr_entries(file);
- update_nr_entries(file);
- update_first(file);
- update_last(file);
-
- for (it = file->first; it <= file->last &&
- (file->home_first == NULL ||
- file->roaming_first == NULL); it++) {
- if (file->home_first == NULL && it->roaming == 0)
- file->home_first = it;
-
- if (file->roaming_first == NULL && it->roaming == 1)
- file->roaming_first = it;
- }
- return 0;
-}
-
-static int stats_file_mmap(struct stats_file *file, size_t size)
-{
- size_t page_size;
-
- page_size = sysconf(_SC_PAGESIZE);
- file->len = (size + page_size - 1) & ~(page_size - 1);
-
- file->addr = mmap(NULL, file->len, PROT_READ,
- MAP_SHARED, file->fd, 0);
-
- if (file->addr == MAP_FAILED) {
- fprintf(stderr, "mmap error %s for %s\n",
- strerror(errno), file->name);
- return -errno;
- }
-
- stats_file_update_cache(file);
-
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- struct stats_file _file, *file;
- struct stat stat;
- int err;
-
- if (argc < 2) {
- printf("Usage: %s [STATS_FILENAME]\n", argv[0]);
- exit(0);
- }
-
- file = &_file;
- bzero(file, sizeof(struct stats_file));
-
- file->name = argv[1];
-
- file->fd = open(file->name, O_RDONLY, 0644);
- if (file->fd == -1) {
- fprintf(stderr, "open error %s for %s\n",
- strerror(errno), file->name);
- exit(1);
- }
-
- err = fstat(file->fd, &stat);
- if (err < 0) {
- fprintf(stderr, "fstat error %s for %s\n",
- strerror(errno), file->name);
- exit(1);
- }
-
- err = stats_file_mmap(file, stat.st_size);
- if (err < 0)
- exit(1);
-
- if (get_hdr(file)->magic != MAGIC) {
- /* not fatal */
- printf("No valid magic found\n");
- }
-
- stats_hdr_info(file);
- stats_print_entries(file);
- stats_print_diff(file);
-
- munmap(file->addr, file->len);
- close(file->fd);
-
- return 0;
-}
diff --git a/tools/stats-tool.c b/tools/stats-tool.c
new file mode 100644
index 0000000..458b5b5
--- /dev/null
+++ b/tools/stats-tool.c
@@ -0,0 +1,1209 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2010 BMW Car IT GmbH. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#ifdef TEMP_FAILURE_RETRY
+#define TFR TEMP_FAILURE_RETRY
+#else
+#define TFR
+#endif
+
+#define MAGIC 0xFA00B916
+
+struct connman_stats_data {
+ 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 time;
+};
+
+struct stats_file_header {
+ unsigned int magic;
+ unsigned int begin;
+ unsigned int end;
+ unsigned int home;
+ unsigned int roaming;
+};
+
+struct stats_record {
+ time_t ts;
+ unsigned int roaming;
+ struct connman_stats_data data;
+};
+
+struct stats_file {
+ int fd;
+ char *name;
+ char *addr;
+ size_t len;
+ size_t max_len;
+
+ /* cached values */
+ int max_nr;
+ int nr;
+ struct stats_record *first;
+ struct stats_record *last;
+ struct stats_record *home_first;
+ struct stats_record *roaming_first;
+};
+
+struct info_record {
+ /* period */
+ GDate start;
+ GDate end;
+ struct connman_stats_data diff; /* diff values, */
+
+ time_t ts;
+ unsigned int roaming;
+ struct connman_stats_data data;
+};
+
+struct info_file {
+ int fd;
+ char *name;
+ char *buf;
+ size_t len;
+
+ GList *entries;
+};
+
+static gint option_create = 0;
+static gint option_interval = 3;
+static gboolean option_dump = FALSE;
+static gboolean option_summary = FALSE;
+static char *option_info_file_name = NULL;
+static time_t option_start_ts = -1;
+static char *option_last_file_name = NULL;
+
+static gboolean parse_start_ts(const char *key, const char *value,
+ gpointer user_data, GError **error)
+{
+ GTimeVal time_val;
+
+ if (g_time_val_from_iso8601(value, &time_val) == FALSE)
+ return FALSE;
+
+ option_start_ts = time_val.tv_sec;
+
+ return TRUE;
+}
+
+
+static GOptionEntry options[] = {
+ { "create", 'c', 0, G_OPTION_ARG_INT, &option_create,
+ "Create a .data file with NR faked entries", "NR" },
+ { "interval", 'i', 0, G_OPTION_ARG_INT, &option_interval,
+ "Interval in seconds (used with create)", "INTERVAL" },
+ { "dump", 'd', 0, G_OPTION_ARG_NONE, &option_dump,
+ "Dump contents of .data file" },
+ { "summary", 's', 0, G_OPTION_ARG_NONE, &option_summary,
+ "Summary of .data file" },
+ { "info", 'f', 0, G_OPTION_ARG_FILENAME, &option_info_file_name,
+ ".info file name" },
+ { "startts", 't', 0, G_OPTION_ARG_CALLBACK, parse_start_ts,
+ "Set start time for creating .data file "
+ "(example 2010-11-05T23:00:12Z)", "TS"},
+ { "last", 'l', 0, G_OPTION_ARG_FILENAME, &option_last_file_name,
+ "Start values from last .data file" },
+ { NULL },
+};
+
+static struct stats_file_header *get_hdr(struct stats_file *file)
+{
+ return (struct stats_file_header *)file->addr;
+}
+
+static struct stats_record *get_begin(struct stats_file *file)
+{
+ unsigned int off = get_hdr(file)->begin;
+
+ return (struct stats_record *)(file->addr + off);
+}
+
+static struct stats_record *get_end(struct stats_file *file)
+{
+ unsigned int off = get_hdr(file)->end;
+
+ return (struct stats_record *)(file->addr + off);
+}
+
+static struct stats_record *get_home(struct stats_file *file)
+{
+ struct stats_file_header *hdr;
+
+ hdr = get_hdr(file);
+
+ if (hdr->home == UINT_MAX)
+ return NULL;
+
+ return (struct stats_record *)(file->addr + hdr->home);
+}
+
+static struct stats_record *get_roaming(struct stats_file *file)
+{
+ struct stats_file_header *hdr;
+
+ hdr = get_hdr(file);
+
+ if (hdr->roaming == UINT_MAX)
+ return NULL;
+
+ return (struct stats_record *)(file->addr + hdr->roaming);
+}
+
+static void set_end(struct stats_file *file, struct stats_record *end)
+{
+ struct stats_file_header *hdr;
+
+ hdr = get_hdr(file);
+ hdr->end = (char *)end - file->addr;
+}
+
+static int get_index(struct stats_file *file, struct stats_record *rec)
+{
+ return rec - file->first;
+}
+
+static void set_home(struct stats_file *file, struct stats_record *home)
+{
+ struct stats_file_header *hdr;
+
+ hdr = get_hdr(file);
+ hdr->home = (char *)home - file->addr;
+}
+
+static void set_roaming(struct stats_file *file, struct stats_record *roaming)
+{
+ struct stats_file_header *hdr;
+
+ hdr = get_hdr(file);
+ hdr->roaming = (char *)roaming - file->addr;
+}
+
+static struct stats_record *get_next(struct stats_file *file,
+ struct stats_record *cur)
+{
+ cur++;
+
+ if (cur > file->last)
+ cur = file->first;
+
+ return cur;
+}
+
+static struct stats_record *get_prev(struct stats_file *file,
+ struct stats_record *cur)
+{
+ cur--;
+
+ if (cur < file->first)
+ cur = file->last;
+
+ return cur;
+}
+
+static struct stats_record *get_iterator_begin(struct stats_file *file)
+{
+ return get_next(file, get_begin(file));
+}
+
+static struct stats_record *get_iterator_end(struct stats_file *file)
+{
+ return get_next(file, get_end(file));
+}
+
+static struct stats_record *get_reverse_iterator_begin(struct stats_file *file)
+{
+ return get_end(file);
+}
+
+static struct stats_record *get_reverse_iterator_end(struct stats_file *file)
+{
+ return get_begin(file);
+}
+
+static void stats_print_record(struct stats_record *rec)
+{
+ char buffer[30];
+
+ strftime(buffer, 30, "%d-%m-%Y %T", localtime(&rec->ts));
+ printf("%p %zd %s %01d %d %d %d %d %d %d %d %d %d\n",
+ rec, rec->ts, buffer,
+ rec->roaming,
+ rec->data.rx_packets,
+ rec->data.tx_packets,
+ rec->data.rx_bytes,
+ rec->data.tx_bytes,
+ rec->data.rx_errors,
+ rec->data.tx_errors,
+ rec->data.rx_dropped,
+ rec->data.tx_dropped,
+ rec->data.time);
+}
+
+static void stats_hdr_info(struct stats_file *file)
+{
+ struct stats_file_header *hdr;
+ struct stats_record *begin, *end, *home, *roaming;
+ unsigned int home_idx, roaming_idx;
+
+ hdr = get_hdr(file);
+ begin = get_begin(file);
+ end = get_end(file);
+
+ home = get_home(file);
+ if (home == NULL)
+ home_idx = UINT_MAX;
+ else
+ home_idx = get_index(file, home);
+
+ roaming = get_roaming(file);
+ if (roaming == NULL)
+ roaming_idx = UINT_MAX;
+ else
+ roaming_idx = get_index(file, roaming);
+
+ printf("Data Structure Sizes\n");
+ printf(" sizeof header %zd/0x%02zx\n",
+ sizeof(struct stats_file_header),
+ sizeof(struct stats_file_header));
+ printf(" sizeof entry %zd/0%02zx\n\n",
+ sizeof(struct stats_record),
+ sizeof(struct stats_record));
+
+ printf("File\n");
+ printf(" addr %p\n", file->addr);
+ printf(" len %zd\n", file->len);
+
+ printf(" max nr entries %d\n", file->max_nr);
+ printf(" nr entries %d\n\n", file->nr);
+
+ printf("Header\n");
+ printf(" magic 0x%08x\n", hdr->magic);
+ printf(" begin [%d] 0x%08x\n",
+ get_index(file, begin), hdr->begin);
+ printf(" end [%d] 0x%08x\n",
+ get_index(file, end), hdr->end);
+ printf(" home [%d] 0x%08x\n",
+ home_idx, hdr->home);
+ printf(" roaming [%d] 0x%08x\n\n",
+ roaming_idx, hdr->roaming);
+
+
+ printf("Pointers\n");
+ printf(" hdr %p\n", hdr);
+ printf(" begin %p\n", begin);
+ printf(" end %p\n", end);
+ printf(" home %p\n", home);
+ printf(" romaing %p\n", roaming);
+ printf(" first %p\n", file->first);
+ printf(" last %p\n\n", file->last);
+}
+
+static void stats_print_entries(struct stats_file *file)
+{
+ struct stats_record *it;
+ int i;
+
+ printf("[ idx] ptr ts ts rx_packets tx_packets rx_bytes "
+ "tx_bytes rx_errors tx_errors rx_dropped tx_dropped time\n\n");
+
+ for (i = 0, it = file->first; it <= file->last; it++, i++) {
+ printf("[%04d] ", i);
+ stats_print_record(it);
+ }
+}
+
+static void stats_print_rec_diff(struct stats_record *begin,
+ struct stats_record *end)
+{
+ printf("\trx_packets: %d\n",
+ end->data.rx_packets - begin->data.rx_packets);
+ printf("\ttx_packets: %d\n",
+ end->data.tx_packets - begin->data.tx_packets);
+ printf("\trx_bytes: %d\n",
+ end->data.rx_bytes - begin->data.rx_bytes);
+ printf("\ttx_bytes: %d\n",
+ end->data.tx_bytes - begin->data.tx_bytes);
+ printf("\trx_errors: %d\n",
+ end->data.rx_errors - begin->data.rx_errors);
+ printf("\ttx_errors: %d\n",
+ end->data.tx_errors - begin->data.tx_errors);
+ printf("\trx_dropped: %d\n",
+ end->data.rx_dropped - begin->data.rx_dropped);
+ printf("\ttx_dropped: %d\n",
+ end->data.tx_dropped - begin->data.tx_dropped);
+ printf("\ttime: %d\n",
+ end->data.time - begin->data.time);
+}
+
+static void stats_print_diff(struct stats_file *file)
+{
+ struct stats_record *begin, *end;
+
+ begin = get_begin(file);
+ begin = get_next(file, begin);
+ end = get_end(file);
+
+ printf("\n(begin + 1)\n");
+ printf("\t[%04d] ", get_index(file, begin));
+ stats_print_record(begin);
+ printf("end\n");
+ printf("\t[%04d] ", get_index(file, end));
+ stats_print_record(end);
+
+ if (file->home_first) {
+ printf("\nhome\n");
+ stats_print_rec_diff(file->home_first, get_home(file));
+ }
+
+ if (file->roaming_first) {
+ printf("\roaming\n");
+ stats_print_rec_diff(file->roaming_first, get_roaming(file));
+ }
+}
+
+static void stats_print_summary(struct stats_file *file)
+{
+ stats_print_diff(file);
+}
+
+static void update_max_nr_entries(struct stats_file *file)
+{
+ file->max_nr = (file->len - sizeof(struct stats_file_header)) /
+ sizeof(struct stats_record);
+}
+
+static void update_nr_entries(struct stats_file *file)
+{
+ struct stats_record *begin, *end;
+ int nr;
+
+ begin = get_begin(file);
+ end = get_end(file);
+
+ nr = get_index(file, end) - get_index(file, begin);
+
+ if (nr < 0)
+ nr += file->max_nr;
+
+ file->nr = nr;
+}
+
+static void update_first(struct stats_file *file)
+{
+ file->first = (struct stats_record *)(file->addr +
+ sizeof(struct stats_file_header));
+}
+
+static void update_last(struct stats_file *file)
+{
+ struct stats_record *last;
+
+ last = file->first;
+ last += file->max_nr - 1;
+
+ file->last = last;
+}
+
+static int stats_file_update_cache(struct stats_file *file)
+{
+ struct stats_record *it, *end;
+
+ update_max_nr_entries(file);
+ update_nr_entries(file);
+ update_first(file);
+ update_last(file);
+ file->home_first = NULL;
+ file->roaming_first = NULL;
+
+ end = get_iterator_end(file);
+ for (it = get_iterator_begin(file);
+ it != end;
+ it = get_next(file, it)) {
+
+
+ if (file->home_first == NULL && it->roaming == 0)
+ file->home_first = it;
+
+ if (file->roaming_first == NULL && it->roaming == 1)
+ file->roaming_first = it;
+
+ if (file->home_first != NULL && file->roaming_first != NULL)
+ break;
+ }
+
+ return 0;
+}
+
+static int stats_file_remap(struct stats_file *file, size_t size)
+{
+ size_t page_size, new_size;
+ void *addr;
+ int err;
+
+ page_size = sysconf(_SC_PAGESIZE);
+ new_size = (size + page_size - 1) & ~(page_size - 1);
+
+ err = ftruncate(file->fd, new_size);
+ if (err < 0) {
+ fprintf(stderr, "ftrunctate error %s for %s",
+ strerror(errno), file->name);
+ return -errno;
+ }
+
+ if (file->addr == NULL) {
+ addr = mmap(NULL, new_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, file->fd, 0);
+ } else {
+ addr = mremap(file->addr, file->len, new_size, MREMAP_MAYMOVE);
+ }
+
+ if (addr == MAP_FAILED) {
+ fprintf(stderr, "mmap error %s for %s\n",
+ strerror(errno), file->name);
+ return -errno;
+ }
+
+ file->addr = addr;
+ file->len = new_size;
+ file->max_len = new_size;
+
+ return 0;
+}
+
+static int stats_open(struct stats_file *file, const char *name)
+{
+ struct stat stat;
+ int err;
+ size_t size;
+
+ bzero(file, sizeof(struct stats_file));
+ file->name = g_strdup(name);
+
+ file->fd = TFR(open(file->name, O_RDWR | O_CREAT, 0644));
+ if (file->fd == -1) {
+ fprintf(stderr, "open error %s for %s\n",
+ strerror(errno), file->name);
+ return -errno;
+ }
+
+ err = fstat(file->fd, &stat);
+ if (err < 0) {
+ fprintf(stderr, "fstat error %s for %s\n",
+ strerror(errno), file->name);
+ return err;
+ }
+
+ if (stat.st_size < sysconf(_SC_PAGESIZE))
+ size = sysconf(_SC_PAGESIZE);
+ else
+ size = (size_t)stat.st_size;
+
+ err = stats_file_remap(file, size);
+ if (err < 0) {
+ fprintf(stderr, "remap failed\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static void stats_close(struct stats_file *file)
+{
+ munmap(file->addr, file->len);
+ close(file->fd);
+ g_free(file->name);
+}
+
+static int stats_create(struct stats_file *file, unsigned int nr,
+ unsigned int interval, time_t start_ts,
+ struct stats_record *start)
+{
+ unsigned int i;
+ int err;
+ struct stats_record *cur, *next;
+ struct stats_file_header *hdr;
+ unsigned int pkt;
+ unsigned int step_ts;
+
+ hdr = get_hdr(file);
+
+ hdr->magic = MAGIC;
+ hdr->begin = sizeof(struct stats_file_header);
+ hdr->end = sizeof(struct stats_file_header);
+
+ stats_file_update_cache(file);
+
+ if (start != NULL) {
+ struct stats_record *rec;
+
+ rec = get_end(file);
+ memcpy(rec, start, sizeof(struct stats_record));
+ } else {
+ get_end(file)->ts = start_ts;
+ }
+
+ for (i = 0; i < nr; i++) {
+ if (file->last == get_end(file)) {
+ err = stats_file_remap(file, file->len +
+ sysconf(_SC_PAGESIZE));
+ if (err < 0)
+ return err;
+
+ stats_file_update_cache(file);
+ }
+ cur = get_end(file);
+ next = get_next(file, cur);
+
+ step_ts = (rand() % interval);
+ if (step_ts == 0)
+ step_ts = 1;
+
+ next->ts = cur->ts + step_ts;
+ next->data.time = cur->data.time + step_ts;
+
+ next->data.rx_packets = cur->data.rx_packets;
+ next->data.rx_bytes = cur->data.rx_bytes;
+
+ if (rand() % 3 == 0) {
+ pkt = rand() % 5;
+ next->data.rx_packets += pkt;
+ next->data.rx_bytes += pkt * (rand() % 1500);
+ }
+
+ next->data.tx_packets = cur->data.tx_packets;
+ next->data.tx_bytes = cur->data.tx_bytes;
+
+ if (rand() % 3 == 0) {
+ pkt = rand() % 5;
+ next->data.tx_packets += pkt;
+ next->data.tx_bytes += pkt * (rand() % 1500);
+ }
+
+ set_end(file, next);
+ }
+
+ return 0;
+}
+
+
+static int parse_value(const char *str, unsigned int *val)
+{
+ char *tail;
+
+ if (str == NULL)
+ return FALSE;
+
+ errno = 0;
+ *val = strtol(str, &tail, 0);
+ if (errno != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void write_info_line(GString *buf, struct info_record *info)
+{
+ GTimeVal time_val;
+ char *ts;
+ char *str_period_start, *str_period_end;
+
+ str_period_start = g_strdup_printf("%4d%02d%02d",
+ g_date_get_year(&info->start),
+ g_date_get_month(&info->start),
+ g_date_get_day(&info->start));
+ str_period_end = g_strdup_printf("%4d%02d%02d",
+ g_date_get_year(&info->end),
+ g_date_get_month(&info->end),
+ g_date_get_day(&info->end));
+
+ time_val.tv_sec = info->ts;
+ time_val.tv_usec = 0;
+ ts = g_time_val_to_iso8601(&time_val);
+
+ g_string_append_printf(buf, "%s,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%s,"
+ "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
+ str_period_start,
+ str_period_end,
+ info->diff.rx_packets,
+ info->diff.tx_packets,
+ info->diff.rx_bytes,
+ info->diff.tx_bytes,
+ info->diff.rx_errors,
+ info->diff.tx_errors,
+ info->diff.rx_dropped,
+ info->diff.tx_dropped,
+ info->diff.time,
+ ts,
+ info->roaming,
+ info->data.rx_packets,
+ info->data.tx_packets,
+ info->data.rx_bytes,
+ info->data.tx_bytes,
+ info->data.rx_errors,
+ info->data.tx_errors,
+ info->data.rx_dropped,
+ info->data.tx_dropped,
+ info->data.time);
+
+ g_free(ts);
+ g_free(str_period_end);
+ g_free(str_period_start);
+}
+
+static struct stats_record *get_next_record(struct stats_file *new_file,
+ struct stats_record
*new_it_begin,
+ struct stats_record *new_it_end,
+ struct stats_record **new_it,
+ struct stats_file *his_file,
+ struct stats_record
*his_it_begin,
+ struct stats_record *his_it_end,
+ struct stats_record **his_it)
+{
+ struct stats_record *tmp;
+
+ if (*new_it != new_it_end) {
+ tmp = *new_it;
+ *new_it = get_prev(new_file, *new_it);
+
+ return tmp;
+ } else if (*his_it != NULL &&
+ *his_it != his_it_end) {
+ tmp = *his_it;
+ *his_it = get_next(his_file, *his_it);
+
+ return tmp;
+ }
+
+ return NULL;
+}
+
+static int summerize(struct stats_file *new_file,
+ struct stats_file *his_file, int fd)
+{
+ struct stats_record *cur, *next;
+ GDate today;
+ GDate period_start, period_end;
+ GString *buf;
+ int i;
+
+ struct stats_record *new_it, *his_it;
+
+ struct stats_record *new_it_begin, *new_it_end;
+ struct stats_record *his_it_begin, *his_it_end;
+
+ g_date_set_time_t(&today, time(NULL));
+ period_end = today;
+ period_start = today;
+
+ if (his_file != NULL) {
+ his_it_begin = get_iterator_begin(his_file);
+ his_it_end = get_iterator_end(his_file);
+
+ /*
+ * Move start point of new file iterator _after_ the last entry
+ * from the history file.
+ */
+ cur = get_iterator_begin(new_file);
+ new_it_end = get_iterator_end(new_file);
+
+ while (cur != new_it_end &&
+ cur->ts <= his_it_begin->ts) {
+ cur = get_next(new_file, cur);
+ }
+
+ new_it_begin = get_reverse_iterator_begin(new_file);
+ new_it_end = cur;
+ } else {
+ his_it_begin = NULL;
+ his_it_end = NULL;
+
+ new_it_begin = get_reverse_iterator_begin(new_file);
+ new_it_end = get_reverse_iterator_end(new_file);
+ }
+
+ new_it = new_it_begin;
+ his_it = his_it_begin;
+
+ cur = get_next_record(new_file, new_it_begin, new_it_end, &new_it,
his_file, his_it_begin, his_it_end, &his_it);
+ if (cur == NULL)
+ return 0;
+ next = get_next_record(new_file, new_it_begin, new_it_end, &new_it,
his_file, his_it_begin, his_it_end, &his_it);
+
+ buf = g_string_new(NULL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ printf("write todays records\n");
+ /*
+ * First write all entries out which are from today, so we
+ * don't sum them up yet.
+ */
+ while (cur != NULL) {
+ GDate date;
+ struct info_record info;
+
+ g_date_set_time_t(&date, cur->ts);
+
+ if (g_date_compare(&date, &today) < 0) {
+ /*
+ * This one is not from today, let's go to the
+ * next step in this algorithm.
+ */
+ break;
+ }
+
+ bzero(&info, sizeof(struct info_record));
+ info.start = date;
+ info.end = date;
+ info.ts = cur->ts;
+ info.roaming = cur->roaming;
+ memcpy(&info.data, &cur->data,
+ sizeof(struct connman_stats_data));
+
+ write_info_line(buf, &info);
+
+ cur = next;
+ next = get_next_record(new_file, new_it_begin, new_it_end,
&new_it, his_file, his_it_begin, his_it_end, &his_it);
+ }
+
+ if (cur != NULL) {
+ printf("process older records\n\t");
+ stats_print_record(cur);
+ }
+
+ /*
+ * Now process only elements which are not from today and we
+ * now summizie them up.
+ */
+ for (i = 0; cur != NULL && i < 20; i++) {
+ GDate date;
+ struct info_record info;
+ struct stats_record *youngest;
+
+ g_date_subtract_days(&period_end, 1);
+ g_date_subtract_days(&period_start, 1);
+
+ printf("process period: %02d.%02d.%04d - %02d.%02d.%04d\n",
+ g_date_get_day(&period_start),
+ g_date_get_month(&period_start),
+ g_date_get_year(&period_start),
+ g_date_get_day(&period_end),
+ g_date_get_month(&period_end),
+ g_date_get_year(&period_end));
+
+ g_date_set_time_t(&date, cur->ts);
+ if (g_date_compare(&date, &period_start) < 0) {
+ /*
+ * The current entry is older then the current
+ * period so move this period one back.
+ */
+ continue;
+ }
+
+ /*
+ * So this entry is the possible last entry (maybe the
+ * only entry) which is in the period. Let's find the
+ * first entry in this period (or the next which is not
+ * anymore) so we can calc the diff.
+ */
+ youngest = cur;
+ if (next != NULL) {
+ g_date_set_time_t(&date, next->ts);
+ while (g_date_compare(&date, &period_start) >= 0) {
+ cur = next;
+ next = get_next_record(new_file, new_it_begin,
new_it_end, &new_it, his_file, his_it_begin, his_it_end, &his_it);
+ if (next == NULL)
+ break;
+ g_date_set_time_t(&date, next->ts);
+ }
+ }
+
+ info.start = period_start;
+ info.end = period_end;
+
+ printf("\t");
+ stats_print_record(youngest);
+ printf("\t");
+ stats_print_record(cur);
+
+ if (youngest != cur) {
+ info.diff.rx_packets = youngest->data.rx_packets -
cur->data.rx_packets;
+ info.diff.tx_packets = youngest->data.tx_packets -
cur->data.tx_packets;
+ info.diff.rx_bytes = youngest->data.rx_bytes -
cur->data.rx_bytes;
+ info.diff.tx_bytes = youngest->data.tx_bytes -
cur->data.tx_bytes;
+ info.diff.rx_errors = youngest->data.rx_errors -
cur->data.rx_errors;
+ info.diff.tx_errors = youngest->data.tx_errors -
cur->data.tx_errors;
+ info.diff.rx_dropped = youngest->data.rx_dropped -
cur->data.rx_dropped;
+ info.diff.tx_dropped = youngest->data.tx_dropped -
cur->data.tx_dropped;
+ info.diff.time = youngest->data.time - cur->data.time;
+ } else {
+ /* No more entries available */
+ memcpy(&info.diff, &cur->data,
+ sizeof(struct connman_stats_data));
+ }
+
+ info.ts = cur->ts;
+ info.roaming = cur->roaming; /* XXX have to filter */
+ memcpy(&info.data, &cur->data,
+ sizeof(struct connman_stats_data));
+
+ write_info_line(buf, &info);
+
+ cur = next;
+ next = get_next_record(new_file, new_it_begin, new_it_end,
&new_it, his_file, his_it_begin, his_it_end, &his_it);
+ }
+
+ TFR(write(fd, buf->str, buf->len + 1));
+ g_string_free(buf, TRUE);
+
+ return 0;
+}
+
+static int create_info_file(struct stats_file *data_file,
+ struct stats_file *old_file,
+ const char *info_file_name)
+{
+ char *tmp_path;
+ int fd;
+ int err;
+
+ tmp_path = g_strdup_printf("%s.XXXXXX.tmp", info_file_name);
+
+ err = -EINVAL;
+ fd = g_mkstemp_full(tmp_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1)
+ goto out;
+
+ err = summerize(data_file, old_file, fd);
+ if (err < 0)
+ goto out;
+
+ TFR(close(fd));
+ unlink(info_file_name);
+
+ err = link(tmp_path, info_file_name);
+out:
+ unlink(tmp_path);
+ g_free(tmp_path);
+
+ return err;
+}
+
+static void close_temp_stats_file(struct stats_file *file)
+{
+ if (file == NULL)
+ return;
+
+ if (file->fd != -1)
+ TFR(close(file->fd));
+
+ if (file->name) {
+ unlink(file->name);
+ g_free(file->name);
+ }
+
+ g_free(file);
+}
+
+static struct stats_file *create_temp_stats_file(size_t size)
+{
+ struct stats_file *file;
+ struct stats_file_header *hdr;
+ size_t page_size, new_size;
+
+ file = g_try_new0(struct stats_file, 1);
+ if (file == NULL)
+ return NULL;
+
+ file->name = g_strdup("stats.XXXXXX.tmp");
+ file->fd = g_mkstemp_full(file->name, O_RDWR | O_CREAT, 0644);
+ if (file->fd == -1)
+ goto err;
+
+ page_size = sysconf(_SC_PAGESIZE);
+ new_size = (size + page_size - 1) & ~(page_size - 1);
+
+ if (ftruncate(file->fd, new_size) < 0)
+ goto err;
+
+ if (stats_file_remap(file, new_size) < 0)
+ goto err;
+
+ hdr = get_hdr(file);
+
+ hdr->magic = MAGIC;
+ hdr->begin = sizeof(struct stats_file_header);
+ hdr->end = sizeof(struct stats_file_header);
+ hdr->home = UINT_MAX;
+ hdr->roaming = UINT_MAX;
+
+ stats_file_update_cache(file);
+
+ return file;
+
+err:
+ close_temp_stats_file(file);
+ return NULL;
+}
+
+static struct stats_file *parse_info_file(const char *file_name)
+{
+ struct stats_file *file;
+ char *line;
+ gsize length;
+ gsize term_pos;
+ GError *error = NULL;
+ GIOStatus status;
+ char **tokens;
+ GIOChannel *channel;
+ struct stat st;
+
+ if (stat(file_name, &st) < 0)
+ return NULL;
+
+ channel = g_io_channel_new_file(file_name, "r", &error);
+ if (channel == NULL)
+ return NULL;
+
+ file = create_temp_stats_file(st.st_size);
+ if (file == NULL) {
+ g_io_channel_unref(channel);
+ return NULL;
+ }
+
+ while ((status = g_io_channel_read_line(
+ channel, &line,
+ &length, &term_pos, &error)) ==
+ G_IO_STATUS_NORMAL) {
+ GTimeVal time_val;
+ struct stats_record *rec;
+
+ if (file->last == get_end(file)) {
+ if (stats_file_remap(file, file->len +
+ sysconf(_SC_PAGESIZE)) < 0) {
+ fprintf(stderr, "remap failed\n");
+
+ goto err;
+ }
+
+ stats_file_update_cache(file);
+ }
+ rec = get_next(file, get_end(file));
+
+ line[term_pos] = '\0';
+ g_strstrip(line);
+ tokens = g_strsplit(line, ",", 0);
+
+ if (g_strv_length(tokens) < 22) {
+ fprintf(stderr, "invalid line found '%s'\n", line);
+
+ g_free(line);
+ g_strfreev(tokens);
+ continue;
+ }
+
+ if (g_time_val_from_iso8601(tokens[11], &time_val) == FALSE) {
+ fprintf(stderr, "invalid line found '%s'\n", line);
+
+ g_free(line);
+ g_strfreev(tokens);
+ continue;
+ }
+
+ rec->ts = time_val.tv_sec;
+
+ if (parse_value(tokens[12], &rec->roaming) == FALSE ||
+ parse_value(tokens[13], &rec->data.rx_packets)
== FALSE ||
+ parse_value(tokens[14], &rec->data.tx_packets)
== FALSE ||
+ parse_value(tokens[15], &rec->data.rx_bytes) ==
FALSE ||
+ parse_value(tokens[16], &rec->data.tx_bytes) ==
FALSE ||
+ parse_value(tokens[17], &rec->data.rx_errors)
== FALSE ||
+ parse_value(tokens[18], &rec->data.tx_errors)
== FALSE ||
+ parse_value(tokens[19], &rec->data.rx_dropped)
== FALSE ||
+ parse_value(tokens[20], &rec->data.tx_dropped)
== FALSE ||
+ parse_value(tokens[21], &rec->data.time) ==
FALSE) {
+ fprintf(stderr, "invalid line found '%s'\n", line);
+
+ g_free(line);
+ g_strfreev(tokens);
+ continue;
+ }
+
+ if (rec->roaming != TRUE)
+ set_home(file, rec);
+ else
+ set_roaming(file, rec);
+
+ set_end(file, rec);
+ }
+
+ g_io_channel_unref(channel);
+
+ if (error != NULL) {
+ fprintf(stderr, "error reading info_file: %s\n",
+ error->message);
+ g_error_free(error);
+
+ goto err;
+ }
+
+ if (status != G_IO_STATUS_EOF)
+ goto err;
+
+ stats_file_update_cache(file);
+
+ return file;
+
+err:
+ g_io_channel_unref(channel);
+ close_temp_stats_file(file);
+
+ return NULL;
+}
+
+static void info_file_update(struct stats_file *data_file,
+ const char *info_file_name)
+{
+ struct stats_file *temp_file;
+
+ temp_file = parse_info_file(info_file_name);
+ if (create_info_file(data_file, temp_file, info_file_name) < 0) {
+ fprintf(stderr, "couldn't write info file %s\n",
+ info_file_name);
+ }
+
+ close_temp_stats_file(temp_file);
+}
+
+int main(int argc, char *argv[])
+{
+ GOptionContext *context;
+ GError *error = NULL;
+
+ struct stats_file_header *hdr;
+ struct stats_file data, *data_file;
+ struct info_file info, *info_file;
+ struct stats_record *rec;
+ time_t start_ts;
+ int err;
+
+ rec = NULL;
+
+ data_file = &data;
+ info_file = &info;
+
+ putenv("TZ=GMT0");
+
+ context = g_option_context_new(NULL);
+ g_option_context_add_main_entries(context, options, NULL);
+
+ if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+ if (error != NULL) {
+ g_printerr("%s\n", error->message);
+ g_error_free(error);
+ } else
+ g_printerr("An unknown error occurred\n");
+ exit(1);
+ }
+
+ g_option_context_free(context);
+
+ if (argc < 2) {
+ printf("Usage: %s [FILENAME]\n", argv[0]);
+ exit(0);
+ }
+
+ err = stats_open(data_file, argv[1]);
+ if (err < 0) {
+ fprintf(stderr, "failed open file %s\n", argv[1]);
+ exit(1);
+ }
+
+ if (option_last_file_name != NULL) {
+ struct stats_file last;
+ if (stats_open(&last, option_last_file_name) < 0) {
+ fprintf(stderr, "failed open file %s\n",
+ option_last_file_name);
+ exit(1);
+ }
+
+ rec = get_end(&last);
+ }
+
+ if (option_start_ts == -1)
+ start_ts = time(NULL);
+ else
+ start_ts = option_start_ts;
+
+ if (option_create > 0)
+ stats_create(data_file, option_create, option_interval,
start_ts, rec);
+
+ hdr = get_hdr(data_file);
+ if (hdr->magic != MAGIC) {
+ fprintf(stderr, "header file magic test failed\n");
+ goto err;
+ }
+
+ stats_file_update_cache(data_file);
+
+ stats_hdr_info(data_file);
+
+ if (option_dump == TRUE)
+ stats_print_entries(data_file);
+
+ if (option_summary == TRUE)
+ stats_print_summary(data_file);
+
+ if (option_info_file_name != NULL)
+ info_file_update(data_file, option_info_file_name);
+
+err:
+ stats_close(data_file);
+
+ return 0;
+}
--
1.7.3.2
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman