interval.h
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
1c0cc4ad
  *  Copyright (C) 2002-2008 Telethra, Inc. <sales@openvpn.net>
6fbf66fa
  *
  *  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 (see the file COPYING included with this
  *  distribution); if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /*
  * The interval_ routines are designed to optimize the calling of a routine
  * (normally tls_multi_process()) which can be called less frequently
  * between triggers.
  */
 
 #ifndef INTERVAL_H
 #define INTERVAL_H
 
 #include "otime.h"
 
 #define INTERVAL_DEBUG 0
 
 /*
  * Designed to limit calls to expensive functions that need to be called
  * regularly.
  */
 
 struct interval
 {
   interval_t refresh;
   interval_t horizon;
   time_t future_trigger;
   time_t last_action;
   time_t last_test_true;
 };
 
 void interval_init (struct interval *top, int horizon, int refresh);
 
 /*
  * IF
  *   last_action less than horizon seconds ago
  *   OR last_test_true more than refresh seconds ago
  *   OR hit future_trigger
  * THEN
  *   return true
  * ELSE
  *   set wakeup to the number of seconds until a true return
  *   return false
  */
 
 static inline bool
 interval_test (struct interval* top)
 {
   bool trigger = false;
   const time_t local_now = now;
 
   if (top->future_trigger && local_now >= top->future_trigger)
     {
       trigger = true;
       top->future_trigger = 0;
     }
 
   if (top->last_action + top->horizon > local_now ||
       top->last_test_true + top->refresh <= local_now ||
       trigger)
     {
       top->last_test_true = local_now;
 #if INTERVAL_DEBUG
       dmsg (D_INTERVAL, "INTERVAL interval_test true");
 #endif
       return true;
     }
   else
     {
       return false;
     }
 }
 
 static inline void
 interval_schedule_wakeup (struct interval* top, interval_t *wakeup)
 {
   const time_t local_now = now;
   interval_earliest_wakeup (wakeup, top->last_test_true + top->refresh, local_now);
   interval_earliest_wakeup (wakeup, top->future_trigger, local_now);
 #if INTERVAL_DEBUG
   dmsg (D_INTERVAL, "INTERVAL interval_schedule wakeup=%d", (int)*wakeup);
 #endif
 }
 
 /*
  * In wakeup seconds, interval_test will return true once.
  */
 static inline void
 interval_future_trigger (struct interval* top, interval_t wakeup) {
   if (wakeup)
     {
 #if INTERVAL_DEBUG
       dmsg (D_INTERVAL, "INTERVAL interval_future_trigger %d", (int)wakeup);
 #endif
       top->future_trigger = now + wakeup;
     }
 }
 
 /*
  * Once an action is triggered, interval_test will remain true for
  * horizon seconds.
  */
 static inline void
 interval_action (struct interval* top)
 {
 #if INTERVAL_DEBUG
   dmsg (D_INTERVAL, "INTERVAL action");
 #endif
   top->last_action = now;
 }
 
 /*
  * Measure when n seconds beyond an event have elapsed
  */
 
 struct event_timeout
 {
   bool defined;
   interval_t n;
   time_t last; /* time of last event */
 };
 
 static inline bool
 event_timeout_defined (const struct event_timeout* et)
 {
   return et->defined;
 }
 
 static inline void
 event_timeout_clear (struct event_timeout* et)
 {
   et->defined = false;
   et->n = 0;
   et->last = 0;
 }
 
 static inline struct event_timeout
 event_timeout_clear_ret ()
 {
   struct event_timeout ret;
   event_timeout_clear (&ret);
   return ret;
 }
 
 static inline void
 event_timeout_init (struct event_timeout* et, interval_t n, const time_t local_now)
 {
   et->defined = true;
   et->n = (n >= 0) ? n : 0;
   et->last = local_now;
 }
 
 static inline void
 event_timeout_reset (struct event_timeout* et)
 {
   if (et->defined)
     et->last = now;
 }
 
 /*
  * This is the principal function for testing and triggering recurring
  * timers and will return true on a timer signal event.
  * If et_const_retry == ETT_DEFAULT and a signal occurs,
  * the function will return true and *et will be armed for the
  * next event.  If et_const_retry >= 0 and a signal occurs,
  * *et will not be touched, but *tv will be set to
  * minimum (*tv, et_const_retry) for a future re-test,
  * and the function will return true.
  */
 
 #define ETT_DEFAULT (-1)
 
 bool event_timeout_trigger (struct event_timeout *et,
 			    struct timeval *tv,
 			    const int et_const_retry);
 
 /*
  * Measure time intervals in microseconds
  */
 
 #define USEC_TIMER_MAX      60 /* maximum interval size in seconds */
 
 #define USEC_TIMER_MAX_USEC (USEC_TIMER_MAX * 1000000)
 
 struct usec_timer {
   struct timeval start;
   struct timeval end;
 };
 
 #ifdef HAVE_GETTIMEOFDAY
 
 static inline void
 usec_timer_start (struct usec_timer *obj)
 {
   CLEAR (*obj);
0475d17e
   openvpn_gettimeofday (&obj->start, NULL);
6fbf66fa
 }
 
 static inline void
 usec_timer_end (struct usec_timer *obj)
 {
0475d17e
   openvpn_gettimeofday (&obj->end, NULL);
6fbf66fa
 }
 
 #endif /* HAVE_GETTIMEOFDAY */
 
 static inline bool
 usec_timer_interval_defined (struct usec_timer *obj)
 {
   return obj->start.tv_sec && obj->end.tv_sec;
 }
 
 static inline int
 usec_timer_interval (struct usec_timer *obj)
 {
   return tv_subtract (&obj->end, &obj->start, USEC_TIMER_MAX);
 }
 
 #endif /* INTERVAL_H */