Protect OLSR against jumping timestamps of system.
authorHenning Rogge <hrogge@googlemail.com>
Thu, 19 Mar 2009 19:12:30 +0000 (20:12 +0100)
committerHenning Rogge <hrogge@googlemail.com>
Thu, 19 Mar 2009 19:12:30 +0000 (20:12 +0100)
replace internal clock_t with uint32 (and always ms resolution).

12 files changed:
lib/bmf/src/PacketHistory.h
lib/secure/src/olsrd_secure.c
lib/txtinfo/src/olsrd_txtinfo.c
src/build_msg.h
src/duplicate_set.c
src/duplicate_set.h
src/link_set.h
src/main.c
src/olsr_cfg.c
src/olsr_cfg.h
src/scheduler.c
src/scheduler.h

index 431b8f3..d334698 100644 (file)
@@ -43,7 +43,6 @@
 
 /* System includes */
 #include <sys/types.h> /* ssize_t */
-#include <sys/times.h> /* clock_t */
 
 #define N_HASH_BITS 12
 #define HISTORY_HASH_SIZE (1 << N_HASH_BITS)
@@ -54,7 +53,7 @@
 struct TDupEntry
 {
   u_int32_t crc32;
-  clock_t timeOut;
+  u_int32_t timeOut;
   struct TDupEntry* next;
 };
 
index 4e1159c..300491c 100644 (file)
@@ -120,8 +120,8 @@ struct stamp
   int diff;
   uint32_t challenge;
   uint8_t validated;
-  clock_t valtime; /* Validity time */
-  clock_t conftime; /* Reconfiguration time */
+  uint32_t valtime; /* Validity time */
+  uint32_t conftime; /* Reconfiguration time */
   struct stamp *prev;
   struct stamp *next;
 };
index 40e8eec..7bc820d 100644 (file)
@@ -118,9 +118,10 @@ static int ipc_print_mid(struct ipc_conn *);
 
 static int ipc_print_stat(struct ipc_conn *);
 
-static void update_statistics_ptr(void);
+static void update_statistics_ptr(void *);
 static bool olsr_msg_statistics(union olsr_message *msg, struct interface *input_if, union olsr_ip_addr *from_addr);
 static char *olsr_packet_statistics(char *packet, struct interface *interface, union olsr_ip_addr *, int *length);
+static void update_statistics_ptr(void *data __attribute__ ((unused)));
 
 #define isprefix(str, pre) (strncmp((str), (pre), strlen(pre)) == 0)
 
@@ -137,8 +138,8 @@ static char *olsr_packet_statistics(char *packet, struct interface *interface, u
 
 /* variables for statistics */
 static uint32_t recv_packets[60], recv_messages[60][6];
-static clock_t recv_last_now;
 static uint32_t recv_last_relevantTCs;
+struct olsr_cookie_info *statistics_timer = NULL;
 
 /**
  * destructor - called at unload
@@ -164,6 +165,9 @@ olsrd_plugin_init(void)
   uint32_t yes = 1;
   socklen_t addrlen;
 
+  statistics_timer = olsr_alloc_cookie("Txtinfo statistics timer", OLSR_COOKIE_TYPE_TIMER);
+  olsr_start_timer(1000, 0, true, &update_statistics_ptr, NULL, statistics_timer->ci_id);
+
   /* Init ipc socket */
   listen_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0);
   if (listen_socket == -1) {
@@ -238,7 +242,6 @@ olsrd_plugin_init(void)
   memset(recv_packets, 0, sizeof(recv_packets));
   memset(recv_messages, 0, sizeof(recv_messages));
 
-  recv_last_now = now_times / 100;
   recv_last_relevantTCs = 0;
   olsr_parser_add_function(&olsr_msg_statistics, PROMISCUOUS);
   olsr_preprocessor_add_function(&olsr_packet_statistics);
@@ -247,29 +250,14 @@ olsrd_plugin_init(void)
 
 
 static void
-update_statistics_ptr(void)
+update_statistics_ptr(void *data __attribute__ ((unused)))
 {
-  clock_t now = now_times / (1000 / olsr_cnf->system_tick_divider);
-  if (recv_last_now < now) {
-    if (recv_last_now + 60 <= now) {
-      memset(recv_packets, 0, sizeof(recv_packets));
-      memset(recv_messages, 0, sizeof(recv_messages));
-      recv_last_now = now % 60;
-    } else {
-      do {
-        int i;
-        recv_last_now++;
-        recv_packets[recv_last_now % 60] = 0;
+  uint32_t now = now_times / 1000;
+  int i;
 
-        for (i = 0; i < 6; i++) {
-          recv_messages[recv_last_now % 60][i] = 0;
-        }
-      } while (recv_last_now < now);
-    }
-    while (recv_last_relevantTCs != getRelevantTcCount()) {
-      recv_messages[recv_last_now % 60][5]++;
-      recv_last_relevantTCs++;
-    }
+  recv_packets[now % 60] = 0;
+  for (i = 0; i < 6; i++) {
+    recv_messages[now % 60][i] = 0;
   }
 }
 
@@ -278,9 +266,9 @@ static bool
 olsr_msg_statistics(union olsr_message *msg,
                     struct interface *input_if __attribute__ ((unused)), union olsr_ip_addr *from_addr __attribute__ ((unused)))
 {
+  uint32_t now = now_times / 1000;
   int idx, msgtype;
 
-  update_statistics_ptr();
   if (olsr_cnf->ip_version == AF_INET) {
     msgtype = msg->v4.olsr_msgtype;
   } else {
@@ -306,7 +294,11 @@ olsr_msg_statistics(union olsr_message *msg,
     break;
   }
 
-  recv_messages[recv_last_now % 60][idx]++;
+  recv_messages[now % 60][idx]++;
+  if (recv_last_relevantTCs != getRelevantTcCount()) {
+    recv_messages[now % 60][5]++;
+    recv_last_relevantTCs ++;
+  }
   return true;
 }
 
@@ -316,9 +308,8 @@ olsr_packet_statistics(char *packet __attribute__ ((unused)),
                        struct interface *interface __attribute__ ((unused)),
                        union olsr_ip_addr *ip __attribute__ ((unused)), int *length __attribute__ ((unused)))
 {
-
-  update_statistics_ptr();
-  recv_packets[recv_last_now % 60] += *length;
+  uint32_t now = now_times / 1000;
+  recv_packets[now % 60] += *length;
 
   return packet;
 }
@@ -835,7 +826,7 @@ ipc_print_stat(struct ipc_conn *conn)
   static const char *names[] = { "HELLO", "TC", "MID", "HNA", "Other", "Rel.TCs" };
 
   uint32_t msgs[6], traffic, i, j;
-  clock_t slot = (now_times / 100 + 59) % 60;
+  uint32_t slot = (now_times / 1000 + 59) % 60;
 
   if (!conn->csv) {
     if (abuf_appendf(&conn->resp, "Table: Statistics (without duplicates)\nType\tlast seconds\t\t\t\tlast min.\taverage\n") < 0) {
index 3804907..7732a74 100644 (file)
 #define _BUILD_MSG_H
 
 #include "olsr_protocol.h"
-#include <time.h> /* For clock_t */
-
-void
-set_empty_tc_timer(clock_t);
-
-clock_t
-get_empty_tc_timer(void);
 
 bool
 queue_mid(struct interface *);
index 67dfaeb..08cff0e 100644 (file)
@@ -140,7 +140,7 @@ olsr_message_is_duplicate(union olsr_message *m)
   struct dup_entry *entry;
   int diff;
   union olsr_ip_addr *mainIp;
-  clock_t valid_until;
+  uint32_t valid_until;
   uint16_t seqnr;
   union olsr_ip_addr *ip;
 #if !defined(REMOVE_LOG_DEBUG)
index cfbe54e..d20b4fe 100644 (file)
@@ -57,7 +57,7 @@ struct dup_entry {
   uint16_t seqnr;
   uint16_t too_low_counter;
   uint32_t array;
-  clock_t valid_until;
+  uint32_t valid_until;
 };
 
 AVLNODE2STRUCT(duptree2dupentry, struct dup_entry, avl);
index 7d39798..757b2dc 100644 (file)
@@ -62,7 +62,7 @@ struct link_entry {
   char *if_name;
   struct timer_entry *link_timer;
   struct timer_entry *link_sym_timer;
-  clock_t ASYM_time;
+  uint32_t ASYM_time;
   olsr_reltime vtime;
   struct neighbor_entry *neighbor;
   uint8_t prev_status;
index bad22c4..bceda91 100644 (file)
@@ -214,13 +214,6 @@ main(int argc, char *argv[])
     avl_comp_prefix_origin_default = avl_comp_ipv6_prefix_origin;
   }
 
-  /* Initialize tick resolution */
-#ifndef WIN32
-  olsr_cnf->system_tick_divider = 1000 / sysconf(_SC_CLK_TCK);
-#else
-  olsr_cnf->system_tick_divider = 1;
-#endif
-
   /* Initialize net */
   init_net();
 
index 23c2b50..ae00fdf 100644 (file)
@@ -1554,7 +1554,6 @@ olsr_get_default_cfg(void)
   cfg->olsr_port = OLSRPORT;
   assert(cfg->dlPath == NULL);
 
-  assert(cfg->system_tick_divider == 0);
   assert(0 == memcmp(&all_zero, &cfg->router_id, sizeof(cfg->router_id)));
   assert(0 == cfg->source_ip_mode);
   cfg->will_int = 10 * HELLO_INTERVAL;
index 2a459e5..7526501 100644 (file)
@@ -222,7 +222,6 @@ struct olsr_config {
    * ========= Please add globals below this line. =========
    */
 
-  uint16_t system_tick_divider;        /* Tick resolution */
   union olsr_ip_addr router_id;        /* Main address of this node */
   float will_int;                      /* Willingness update interval if willingness_auto */
   int exit_value;                      /* Global return value for process termination */
index c476889..50bc728 100644 (file)
 #include <assert.h>
 
 /* Timer data, global. Externed in scheduler.h */
-clock_t now_times;                     /* current idea of times(2) reported uptime */
+uint32_t now_times;                    /* relative time compared to startup (in milliseconds */
+struct timeval first_tv;      /* timevalue during startup */
+struct timeval last_tv;     /* timevalue used for last olsr_times() calculation */
 
 /* Hashed root of all timers */
 static struct list_node timer_wheel[TIMER_WHEEL_SLOTS];
-static clock_t timer_last_run;         /* remember the last timeslot walk */
+static uint32_t timer_last_run;                /* remember the last timeslot walk */
 
 /* Memory cookie for the block based memory manager */
 static struct olsr_cookie_info *timer_mem_cookie = NULL;
@@ -67,9 +69,9 @@ static struct olsr_cookie_info *timer_mem_cookie = NULL;
 static struct list_node socket_head = {&socket_head, &socket_head};
 
 /* Prototypes */
-static void walk_timers(clock_t *);
+static void walk_timers(uint32_t *);
 static void poll_sockets(void);
-static clock_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct,
+static uint32_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct,
                            unsigned int random_val);
 
 /*
@@ -79,14 +81,78 @@ static clock_t calc_jitter(unsigned int rel_time, uint8_t jitter_pct,
  * in kernel/sys.c and will only return an error if the tms_buf is
  * not writeable.
  */
-static INLINE clock_t olsr_times(void)
+static uint32_t olsr_times(void)
 {
-#ifndef linux
-  struct tms tms_buf;
-  return times(&tms_buf);
-#else
-  return times(NULL);
-#endif
+  struct timeval tv;
+  uint32_t t;
+
+  if (gettimeofday(&tv, NULL) != 0) {
+    OLSR_ERROR(LOG_SCHEDULER, "OS clock is not working, have to shut down OLSR (%d)\n", errno);
+    olsr_exit(1);
+  }
+
+  /* test if time jumped backward or more than 60 seconds forward */
+  if (tv.tv_sec < last_tv.tv_sec
+      || (tv.tv_sec == last_tv.tv_sec && tv.tv_usec < last_tv.tv_usec)
+      || tv.tv_sec - last_tv.tv_sec > 60) {
+    OLSR_WARN(LOG_SCHEDULER, "Time jump (%d.%06d to %d.%06d)\n",
+        (int32_t)(last_tv.tv_sec), (int32_t)(last_tv.tv_usec), (int32_t)(tv.tv_sec), (int32_t)(tv.tv_usec));
+
+    t = (last_tv.tv_sec - first_tv.tv_sec) * 1000 + (last_tv.tv_usec - first_tv.tv_usec) / 1000;
+    t++; /* advance time by one millisecond */
+
+    first_tv = tv;
+    first_tv.tv_sec -= (t / 1000);
+    first_tv.tv_usec -= ((t % 1000) * 1000);
+
+    if (first_tv.tv_usec < 0) {
+      first_tv.tv_sec--;
+      first_tv.tv_usec += 1000000;
+    }
+    last_tv = tv;
+    return t;
+  }
+  last_tv = tv;
+  return (tv.tv_sec - first_tv.tv_sec) * 1000 + (tv.tv_usec - first_tv.tv_usec) / 1000;
+}
+
+/**
+ * Returns a timestamp s seconds in the future
+ */
+uint32_t olsr_getTimestamp(uint32_t s) {
+  return now_times + s;
+}
+
+/**
+ * Returns the number of milliseconds until the timestamp will happen
+ */
+
+int32_t olsr_getTimeDue(uint32_t s) {
+  uint32_t diff;
+  if (s > now_times) {
+    diff = s - now_times;
+
+    /* overflow ? */
+    if (diff > (1u<<31)) {
+      return -(int32_t)(0xffffffff - diff);
+    }
+    return (int32_t)(diff);
+  }
+
+  diff = now_times - s;
+  /* overflow ? */
+  if (diff > (1u<<31)) {
+    return (int32_t)(0xffffffff - diff);
+  }
+  return -(int32_t)(diff);
+}
+
+bool olsr_isTimedOut(uint32_t s) {
+  if (s > now_times) {
+    return s - now_times > (1u<<31);
+  }
+
+  return now_times - s <= (1u<<31);
 }
 
 /**
@@ -138,7 +204,7 @@ remove_olsr_socket(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm
     OLSR_WARN(LOG_SCHEDULER, "Bogus socket entry - not processing...");
     return 0;
   }
-  OLSR_PRINTF(1, "Removing OLSR socket entry %d\n", fd);
+  OLSR_PRINTF(2, "Removing OLSR socket entry %d\n", fd);
 
   OLSR_FOR_ALL_SOCKETS(entry) {
     if (entry->fd == fd && entry->process_immediate == pf_imm &&
@@ -264,16 +330,16 @@ poll_sockets(void)
   } OLSR_FOR_ALL_SOCKETS_END(entry);
 }
 
-static void handle_fds(const unsigned long next_interval)
+static void handle_fds(uint32_t next_interval)
 {
   struct timeval tvp;
-  unsigned long remaining;
+  int32_t remaining;
 
   /* calculate the first timeout */
   now_times = olsr_times();
 
-  remaining = next_interval - (unsigned long)now_times;
-  if ((long)remaining <= 0) {
+  remaining = TIME_DUE(next_interval);
+  if (remaining <= 0) {
     /* we are already over the interval */
     if (list_is_empty(&socket_head)) {
       /* If there are no registered sockets we do not call select(2) */
@@ -283,7 +349,6 @@ static void handle_fds(const unsigned long next_interval)
     tvp.tv_usec = 0;
   } else {
     /* we need an absolute time - milliseconds */
-    remaining *= olsr_cnf->system_tick_divider;
     tvp.tv_sec = remaining / MSEC_PER_SEC;
     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
   }
@@ -355,13 +420,12 @@ static void handle_fds(const unsigned long next_interval)
     } OLSR_FOR_ALL_SOCKETS_END(entry);
 
     /* calculate the next timeout */
-    remaining = next_interval - (unsigned long)now_times;
-    if ((long)remaining <= 0) {
+    remaining = TIME_DUE(next_interval);
+    if (remaining <= 0) {
       /* we are already over the interval */
       break;
     }
     /* we need an absolute time - milliseconds */
-    remaining *= olsr_cnf->system_tick_divider;
     tvp.tv_sec = remaining / MSEC_PER_SEC;
     tvp.tv_usec = (remaining % MSEC_PER_SEC) * USEC_PER_MSEC;
   }
@@ -383,7 +447,7 @@ olsr_scheduler(void)
 
   /* Main scheduler loop */
   while (app_state == STATE_RUNNING) {
-    clock_t next_interval;
+    uint32_t next_interval;
 
     /*
      * Update the global timestamp. We are using a non-wallclock timer here
@@ -421,7 +485,7 @@ olsr_scheduler(void)
  * @param cached result of random() at system init.
  * @return the absolute timer in system clock tick units
  */
-static clock_t
+static uint32_t
 calc_jitter(unsigned int rel_time, uint8_t jitter_pct, unsigned int random_val)
 {
   unsigned int jitter_time;
@@ -457,27 +521,13 @@ olsr_init_timers(void)
   int idx;
 
   /* Grab initial timestamp */
+  if (gettimeofday(&first_tv, NULL)) {
+    OLSR_ERROR(LOG_SCHEDULER, "OS clock is not working, have to shut down OLSR (%d)\n", errno);
+    olsr_exit(1);
+  }
+  last_tv = first_tv;
   now_times = olsr_times();
 
-#ifndef linux
-  /*
-   * Note: if using linux, olsr_times does not return any
-   * error, because it calls the kernel sys_times(NULL)
-   * If not using linux, errors may be returned, e.g.
-   * the mandatory output buffer is not kernel-writeable
-   */
-       if ((clock_t)-1 == now_times) {
-               const char * const err_msg = strerror(errno);
-               OLSR_WARN(LOG_SCHEDULER, "Error in times(): %s, sleeping for a second", err_msg);
-               sleep(1);
-               now_times = olsr_times();
-               if ((clock_t)-1 == now_times) {
-                               OLSR_ERROR(LOG_SCHEDULER, "Shutting down because times() does not work");
-                       exit(EXIT_FAILURE);
-               }
-       }
-#endif
-
   for (idx = 0; idx < TIMER_WHEEL_SLOTS; idx++) {
     list_head_init(&timer_wheel[idx]);
   }
@@ -499,7 +549,7 @@ olsr_init_timers(void)
  * Callback the provided function with the context pointer.
  */
 static void
-walk_timers(clock_t * last_run)
+walk_timers(uint32_t * last_run)
 {
   unsigned int total_timers_walked = 0, total_timers_fired = 0;
   unsigned int wheel_slot_walks = 0;
@@ -584,7 +634,7 @@ walk_timers(clock_t * last_run)
   }
 
 #ifdef DEBUG
-  OLSR_PRINTF(3, "TIMER: processed %4u/%d clockwheel slots, "
+  OLSR_PRINTF(4, "TIMER: processed %4u/%d clockwheel slots, "
              "timers walked %4u/%u, timers fired %u\n",
              wheel_slot_walks, TIMER_WHEEL_SLOTS,
              total_timers_walked, timer_mem_cookie->ci_usage,
@@ -687,13 +737,13 @@ olsr_wallclock_string(void)
  * @return buffer to a formatted system time string.
  */
 const char *
-olsr_clock_string(clock_t clk)
+olsr_clock_string(uint32_t clk)
 {
   static char buf[sizeof("00:00:00.000")];
 
   /* On most systems a clocktick is a 10ms quantity. */
-  unsigned int msec = olsr_cnf->system_tick_divider * (unsigned int)(clk - now_times);
-  unsigned int sec = msec / MSEC_PER_SEC;
+  unsigned int msec = clk % 1000;
+  unsigned int sec = clk / 1000;
 
   snprintf(buf, sizeof(buf), "%02u:%02u:%02u.%03u",
           sec / 3600, (sec % 3600) / 60, (sec % 60), (msec % MSEC_PER_SEC));
index 6df1445..9c2a243 100644 (file)
@@ -49,7 +49,7 @@
 
 #include <time.h>
 
-#define TIMER_WHEEL_SLOTS 256
+#define TIMER_WHEEL_SLOTS 1024
 #define TIMER_WHEEL_MASK (TIMER_WHEEL_SLOTS - 1)
 
 /* Some defs for juggling with timers */
@@ -72,7 +72,7 @@ typedef void (*timer_cb_func)(void *);               /* callback function */
  */
 struct timer_entry {
   struct list_node timer_list;        /* Wheel membership */
-  clock_t timer_clock;                /* when timer shall fire (absolute time) */
+  uint32_t timer_clock;                       /* when timer shall fire (absolute time) */
   unsigned int timer_period;          /* set for periodical timers (relative time) */
   olsr_cookie_t timer_cookie;         /* used for diag stuff */
   uint8_t timer_jitter_pct;           /* the jitter expressed in percent */
@@ -103,7 +103,7 @@ void EXPORT(olsr_stop_timer)(struct timer_entry *);
 
 /* Printing timestamps */
 #ifndef NODEBUG
-const char *olsr_clock_string(clock_t);
+const char *olsr_clock_string(uint32_t);
 const char *olsr_wallclock_string(void);
 #endif /* !NODEBUG */
 
@@ -111,23 +111,18 @@ const char *olsr_wallclock_string(void);
 void olsr_scheduler(void);
 
 /*
- * Provides a timestamp s1 milliseconds in the future according
- * to system ticks returned by times(2)
- * We cast the result of the division to clock_t. That serves two purposes:
- * - it workarounds numeric underflows if the pollrate is <= 0.5
- * - since we add "now_times" which is an integer, users (hopefully) expect
- *   to get integeres as result (which is without the cast not guaranteed)
+ * Provides a timestamp s1 milliseconds in the future
  */
-#define GET_TIMESTAMP(s1)      (now_times + (clock_t)((s1) / olsr_cnf->system_tick_divider))
+#define GET_TIMESTAMP(s1)      olsr_getTimestamp(s1)
 
 /* Compute the time in milliseconds when a timestamp will expire. */
-#define TIME_DUE(s1)    ((long)((s1) * olsr_cnf->system_tick_divider) - now_times)
+#define TIME_DUE(s1)    olsr_getTimeDue(s1)
 
 /* Returns TRUE if a timestamp is expired */
-#define TIMED_OUT(s1)  ((long)((s1) - now_times) < 0)
+#define TIMED_OUT(s1)    olsr_isTimedOut(s1)
 
 /* Timer data */
-extern clock_t EXPORT(now_times); /* current idea of times(2) reported uptime */
+extern uint32_t EXPORT(now_times); /* current idea of times(2) reported uptime */
 
 
 #define SP_PR_READ             0x01
@@ -162,6 +157,9 @@ LISTNODE2STRUCT(list2socket, struct olsr_socket_entry, socket_node);
     socket = list2socket(_socket_node);
 #define OLSR_FOR_ALL_SOCKETS_END(socket) }}
 
+uint32_t EXPORT(olsr_getTimestamp)(uint32_t s);
+int32_t EXPORT(olsr_getTimeDue)(uint32_t s);
+bool EXPORT(olsr_isTimedOut)(uint32_t s);
 
 void EXPORT(add_olsr_socket)(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm, void *data, unsigned int flags);
 int EXPORT(remove_olsr_socket)(int fd, socket_handler_func pf_pr, socket_handler_func pf_imm);