/* darkstat 3
- * copyright (c) 2006-2011 Emil Mikulic.
+ * copyright (c) 2006-2014 Emil Mikulic.
*
* graph_db.c: round robin database for graph data
*
#include <assert.h>
#include <stdlib.h>
#include <string.h> /* for memcpy() */
+#include <time.h>
#define GRAPH_WIDTH "320"
#define GRAPH_HEIGHT "200"
};
static unsigned int graph_db_size = sizeof(graph_db)/sizeof(*graph_db);
+static time_t start_mono, start_real, last_real;
-static time_t start_time, last_time;
-
-void
-graph_init(void)
-{
+void graph_init(void) {
unsigned int i;
for (i=0; i<graph_db_size; i++) {
graph_db[i]->in = xmalloc(sizeof(uint64_t) * graph_db[i]->num_bars);
graph_db[i]->out = xmalloc(sizeof(uint64_t) * graph_db[i]->num_bars);
}
- start_time = time(NULL);
graph_reset();
}
-static void
-zero_graph(struct graph *g)
-{
+static void zero_graph(struct graph *g) {
memset(g->in, 0, sizeof(uint64_t) * g->num_bars);
memset(g->out, 0, sizeof(uint64_t) * g->num_bars);
}
-void
-graph_reset(void)
-{
+void graph_reset(void) {
unsigned int i;
+
for (i=0; i<graph_db_size; i++)
zero_graph(graph_db[i]);
- last_time = 0;
+
+ /* Reset starting time. */
+ start_mono = now_mono();
+ start_real = now_real();
+ last_real = 0;
+
+ /* Clear counters. */
+ acct_total_bytes = 0;
+ acct_total_packets = 0;
}
-void
-graph_free(void)
-{
+void graph_free(void) {
unsigned int i;
+
for (i=0; i<graph_db_size; i++) {
free(graph_db[i]->in);
free(graph_db[i]->out);
}
}
-void
-graph_acct(uint64_t amount, enum graph_dir dir)
-{
+void graph_acct(uint64_t amount, enum graph_dir dir) {
unsigned int i;
for (i=0; i<graph_db_size; i++)
- switch (dir) {
- case GRAPH_IN: graph_db[i]->in[ graph_db[i]->pos ] += amount; break;
- case GRAPH_OUT: graph_db[i]->out[ graph_db[i]->pos ] += amount; break;
- default: errx(1, "unknown graph_dir in graph_acct: %d", dir);
- }
+ if (dir == GRAPH_IN) {
+ graph_db[i]->in[ graph_db[i]->pos ] += amount;
+ } else {
+ assert(dir == GRAPH_OUT);
+ graph_db[i]->out[ graph_db[i]->pos ] += amount;
+ }
}
/* Advance a graph: advance the pos, zeroing out bars as we move. */
-static void
-advance(struct graph *g, const unsigned int pos)
-{
+static void advance(struct graph *g, const unsigned int pos) {
if (g->pos == pos)
return; /* didn't need to advance */
do {
}
/* Rotate a graph: rotate all bars so that the bar at the current pos is moved
- * to the newly given pos. This is non-destructive. */
-static void
-rotate(struct graph *g, const unsigned int pos)
-{
+ * to the newly given pos.
+ */
+static void rotate(struct graph *g, const unsigned int pos) {
uint64_t *tmp;
unsigned int i, ofs;
size_t size;
memcpy(g->out, tmp, size);
free(tmp);
+ assert(g->num_bars > 0);
assert(pos == ( (g->pos + ofs) % g->num_bars ));
g->pos = pos;
}
-static void
-graph_resync(const time_t new_time)
-{
+static void graph_resync(const time_t new_real) {
struct tm *tm;
/*
- * If time went backwards, we assume that real time is continuous and that
- * the time adjustment should only affect display. i.e., if we have:
+ * If real time went backwards, we assume that the time adjustment should
+ * only affect display. i.e., if we have:
*
* second 15: 12 bytes
* second 16: 345 bytes
* second 7: 345 bytes
* second 8: <-- current pos
*
- * Note that we don't make any corrections for time being stepped forward.
+ * We don't make any corrections for time being stepped forward,
+ * it's treated as though there was no traffic during that time.
+ *
* We rely on graph advancement to happen at the correct real time to
* account for, for example, bandwidth used per day.
*/
- assert(new_time < last_time);
+ assert(new_real < last_real);
- tm = localtime(&new_time);
+ tm = localtime(&new_real);
if (tm->tm_sec == 60)
tm->tm_sec = 59; /* mis-handle leap seconds */
rotate(&graph_hrs, tm->tm_hour);
rotate(&graph_days, tm->tm_mday - 1);
- last_time = new_time;
+ last_real = new_real;
}
-void
-graph_rotate(void)
-{
+void graph_rotate(void) {
time_t t, td;
struct tm *tm;
unsigned int i;
- t = now;
+ t = now_real();
+ td = t - last_real;
- if (last_time == 0) {
+ if (last_real == 0) {
verbosef("first rotate");
- last_time = t;
+ last_real = t;
tm = localtime(&t);
- if (tm->tm_sec == 60)
- tm->tm_sec = 59; /* mis-handle leap seconds */
-
graph_secs.pos = tm->tm_sec;
graph_mins.pos = tm->tm_min;
graph_hrs.pos = tm->tm_hour;
return;
}
- if (t == last_time)
- return; /* superfluous rotate */
+ if (t == last_real)
+ return; /* time has not advanced a full second, don't rotate */
- if (t < last_time) {
- verbosef("time went backwards! (from %u to %u, offset is %d)",
- (unsigned int)last_time, (unsigned int)t, (int)(t - last_time));
+ if (t < last_real) {
+ verbosef("graph_db: realtime went backwards! "
+ "(from %ld to %ld, offset is %ld)",
+ last_real, t, td);
graph_resync(t);
return;
}
/* else, normal rotation */
- td = t - last_time;
- last_time = t;
+ last_real = t;
tm = localtime(&t);
- if (tm->tm_sec == 60)
- tm->tm_sec = 59; /* mis-handle leap seconds */
/* zero out graphs which have been completely rotated through */
for (i=0; i<graph_db_size; i++)
* to have validated the header of the segment, and left the file position at
* the start of the data.
*/
-int
-graph_import(const int fd)
-{
+int graph_import(const int fd) {
uint64_t last;
unsigned int i, j;
if (!read64(fd, &last)) return 0;
- last_time = (time_t)last;
+ last_real = last;
for (i=0; i<graph_db_size; i++) {
unsigned char num_bars, pos;
* Database Export: Dump hosts_db into a file provided by the caller.
* The caller is responsible for writing out the header first.
*/
-int
-graph_export(const int fd)
-{
+int graph_export(const int fd) {
unsigned int i, j;
- if (!write64(fd, (uint64_t)last_time)) return 0;
+ if (!write64(fd, (uint64_t)last_real)) return 0;
for (i=0; i<graph_db_size; i++) {
if (!write8(fd, graph_db[i]->num_bars)) return 0;
if (!write8(fd, graph_db[i]->pos)) return 0;
/* ---------------------------------------------------------------------------
* Web interface: front page!
*/
-struct str *
-html_front_page(void)
-{
+struct str *html_front_page(void) {
struct str *buf, *rf;
unsigned int i;
char start_when[100];
+ time_t d_real, d_mono;
buf = str_make();
html_open(buf, "Graphs", /*path_depth=*/0, /*want_graph_js=*/1);
+ d_mono = now_mono() - start_mono;
+ d_real = now_real() - start_real;
str_append(buf, "<p>\n");
- str_append(buf, "<b>Running for</b> <span id=\"rf\">");
- rf = length_of_time(now - start_time);
- /* FIXME: use a more monotonic clock perhaps? */
+ str_append(buf, "<b>Measuring for</b> <span id=\"rf\">");
+ rf = length_of_time(d_mono);
str_appendstr(buf, rf);
str_free(rf);
str_append(buf, "</span>");
+ if (labs((long)(d_real - d_mono)) > 1)
+ str_appendf(buf, " (real time is off by %qd sec)",
+ (qd)(d_real - d_mono));
if (strftime(start_when, sizeof(start_when),
- "%Y-%m-%d %H:%M:%S %Z%z", localtime(&start_time)) != 0)
+ "%Y-%m-%d %H:%M:%S %Z%z", localtime(&start_real)) != 0)
str_appendf(buf, "<b>, since</b> %s", start_when);
str_appendf(buf,"<b>.</b><br>\n"
- "<b>Total</b> <span id=\"tb\">%'qu</span> <b>bytes, "
+ "<b>Seen</b> <span id=\"tb\">%'qu</span> <b>bytes, "
"in</b> <span id=\"tp\">%'qu</span> <b>packets.</b> "
"(<span id=\"pc\">%'u</span> <b>captured,</b> "
"<span id=\"pd\">%'u</span> <b>dropped)</b><br>\n"
"</p>\n",
- acct_total_bytes,
- acct_total_packets,
- cap_pkts_recv, cap_pkts_drop);
+ (qu)acct_total_bytes,
+ (qu)acct_total_packets,
+ cap_pkts_recv,
+ cap_pkts_drop);
str_append(buf,
"<div id=\"graphs\">\n"
/* ---------------------------------------------------------------------------
* Web interface: graphs.xml
*/
-struct str *
-xml_graphs(void)
-{
+struct str *xml_graphs(void) {
unsigned int i, j;
struct str *buf = str_make(), *rf;
str_appendf(buf, "<graphs tp=\"%qu\" tb=\"%qu\" pc=\"%u\" pd=\"%u\" rf=\"",
- acct_total_packets, acct_total_bytes, cap_pkts_recv, cap_pkts_drop);
- rf = length_of_time(now - start_time);
+ (qu)acct_total_packets,
+ (qu)acct_total_bytes,
+ cap_pkts_recv,
+ cap_pkts_drop);
+ rf = length_of_time(now_real() - start_real);
str_appendstr(buf, rf);
str_free(rf);
str_append(buf, "\">\n");
j = (j + 1) % g->num_bars;
/* <element pos="" in="" out=""/> */
str_appendf(buf, "<e p=\"%u\" i=\"%qu\" o=\"%qu\"/>\n",
- g->offset + j, g->in[j], g->out[j]);
+ g->offset + j,
+ (qu)g->in[j],
+ (qu)g->out[j]);
} while (j != g->pos);
str_appendf(buf, "</%s>\n", g->unit);
}
return (buf);
}
-/* vim:set ts=3 sw=3 tw=78 expandtab: */
+/* vim:set ts=3 sw=3 tw=80 et: */