Fix "clock error" due to machine reboot.
authorEmil Mikulic <emikulic@gmail.com>
Sun, 7 Dec 2014 06:37:38 +0000 (17:37 +1100)
committerEmil Mikulic <emikulic@gmail.com>
Sun, 7 Dec 2014 09:47:25 +0000 (20:47 +1100)
Treat per-host last_seen_mono as a signed integer which can go negative
if the host was last seen before reboot (or whatever corresponds to t=0
on the monotonic clock)

hosts_db.c
hosts_db.h
hosts_sort.c
now.c
now.h

index 3058d65..722d79f 100644 (file)
@@ -347,20 +347,21 @@ format_row_host(struct str *buf, const struct bucket *b,
       (qu)b->total);
 
    if (opt_want_lastseen) {
-      time_t last = b->u.host.last_seen_mono;
+      int64_t last = b->u.host.last_seen_mono;
+      int64_t now = (int64_t)now_mono();
       struct str *last_str = NULL;
 
-      if ((now_mono() >= last) && (last > 0))
-         last_str = length_of_time(now_mono() - last);
+      if ((now >= last) && (last != 0))
+         last_str = length_of_time(now - last);
 
       str_append(buf, " <td class=\"num\">");
       if (last_str == NULL) {
          if (last == 0)
             str_append(buf, "(never)");
          else
-            str_appendf(buf, "(clock error: now = %qu, last = %qu)",
-                        (qu)now_mono(),
-                        (qu)last);
+            str_appendf(buf, "(clock error: last = %qd, now = %qu)",
+                        (qd)last,
+                        (qu)now);
       } else {
          str_appendstr(buf, last_str);
          str_free(last_str);
@@ -1087,13 +1088,16 @@ static struct str *html_hosts_detail(const char *ip) {
          str_append(buf, ls_when);
 
    if (h->u.host.last_seen_mono <= now_mono()) {
-      ls_len = length_of_time(now_mono() - h->u.host.last_seen_mono);
+      ls_len = length_of_time((int64_t)now_mono() - h->u.host.last_seen_mono);
       str_append(buf, " (");
       str_appendstr(buf, ls_len);
       str_free(ls_len);
       str_append(buf, " ago)");
    } else {
-      str_append(buf, " (in the future, possible clock problem)");
+      str_appendf(buf, " (in the future, possible clock problem, "
+                  "last = %qd, now = %qu)",
+                  (qd)h->u.host.last_seen_mono,
+                  (qu)now_mono());
    }
 
    str_appendf(buf,
index 109f373..5c153b4 100644 (file)
@@ -19,7 +19,10 @@ struct host {
    struct addr addr;
    char *dns;
    uint8_t mac_addr[6];
-   time_t last_seen_mono;
+   /* last_seen_mono is converted to/from time_t in export/import.
+    * It can be negative (due to machine reboots).
+    */
+   int64_t last_seen_mono;
    struct hashtable *ports_tcp, *ports_udp, *ip_protos;
 };
 
index bb88581..110fbfb 100644 (file)
 #include "err.h"
 #include "hosts_db.h"
 
-/* ---------------------------------------------------------------------------
- * comparator for sorting (biggest first)
- */
-static int
-cmp(const struct bucket * const *x, const struct bucket * const *y,
-    const enum sort_dir dir)
-{
-   uint64_t a, b;
+static int cmp_u64(const uint64_t a, const uint64_t b) {
+   if (a < b) return (1);
+   if (a > b) return (-1);
+   return (0);
+}
 
+static int cmp_i64(const int64_t a, const int64_t b) {
+   if (a < b) return (1);
+   if (a > b) return (-1);
+   return (0);
+}
+
+/* Comparator for sorting 'struct bucket' */
+static int cmp(const struct bucket * const *x, const struct bucket * const *y,
+    const enum sort_dir dir) {
    switch (dir) {
-   case IN:
-      a = (*x)->in;
-      b = (*y)->in;
-      break;
-   case OUT:
-      a = (*x)->out;
-      b = (*y)->out;
-      break;
-   case TOTAL:
-      a = (*x)->total;
-      b = (*y)->total;
-      break;
-   case LASTSEEN:
-      a = (*x)->u.host.last_seen_mono;
-      b = (*y)->u.host.last_seen_mono;
-      break;
-   default:
-      errx(1, "cmp: unknown direction: %d", dir);
+      case IN:
+         return cmp_u64((*x)->in, (*y)->in);
+      case OUT:
+         return cmp_u64((*x)->out, (*y)->out);
+      case TOTAL:
+         return cmp_u64((*x)->total, (*y)->total);
+      case LASTSEEN:
+         return cmp_i64((*x)->u.host.last_seen_mono,
+                        (*y)->u.host.last_seen_mono);
+      default:
+         errx(1, "cmp: unknown direction: %d", dir);
    }
-
-   if (a < b) return (1);
-   else if (a > b) return (-1);
-   else return (0);
 }
 
 /*
diff --git a/now.c b/now.c
index 0bc0061..abfc370 100644 (file)
--- a/now.c
+++ b/now.c
@@ -119,14 +119,14 @@ void now_update(void) {
    all_clocks_update();
 }
 
-time_t mono_to_real(const time_t t) {
+time_t mono_to_real(const int64_t t) {
    assert(now_initialized);
-   return t - clock_mono.tv_sec + clock_real.tv_sec;
+   return (time_t)(t - (int64_t)clock_mono.tv_sec + (int64_t)clock_real.tv_sec);
 }
 
-time_t real_to_mono(const time_t t) {
+int64_t real_to_mono(const time_t t) {
    assert(now_initialized);
-   return t - clock_real.tv_sec + clock_mono.tv_sec;
+   return (int64_t)(t - clock_real.tv_sec + clock_mono.tv_sec);
 }
 
 void timer_start(struct timespec *t) {
diff --git a/now.h b/now.h
index 03366e7..12231a4 100644 (file)
--- a/now.h
+++ b/now.h
@@ -23,8 +23,10 @@ void now_update(void); /* once per event loop (in darkstat.c) */
 time_t now_real(void);
 time_t now_mono(void);
 
-time_t mono_to_real(const time_t t);
-time_t real_to_mono(const time_t t);
+/* Monotonic times can be negative (a time from before the machine booted) so
+ * treat them as signed. */
+time_t mono_to_real(const int64_t t);
+int64_t real_to_mono(const time_t t);
 
 /* Emits warnings if a call is too slow. */
 struct timespec;