src/openvpn/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.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN 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.
  *
caa54ac3
  *  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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
 /*
  * 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
 {
81d882d5
     interval_t refresh;
     interval_t horizon;
     time_t future_trigger;
     time_t last_action;
     time_t last_test_true;
6fbf66fa
 };
 
81d882d5
 void interval_init(struct interval *top, int horizon, int refresh);
6fbf66fa
 
 /*
  * 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
81d882d5
 interval_test(struct interval *top)
6fbf66fa
 {
81d882d5
     bool trigger = false;
     const time_t local_now = now;
6fbf66fa
 
81d882d5
     if (top->future_trigger && local_now >= top->future_trigger)
6fbf66fa
     {
81d882d5
         trigger = true;
         top->future_trigger = 0;
6fbf66fa
     }
 
81d882d5
     if (top->last_action + top->horizon > local_now
         || top->last_test_true + top->refresh <= local_now
         || trigger)
6fbf66fa
     {
81d882d5
         top->last_test_true = local_now;
6fbf66fa
 #if INTERVAL_DEBUG
81d882d5
         dmsg(D_INTERVAL, "INTERVAL interval_test true");
6fbf66fa
 #endif
81d882d5
         return true;
6fbf66fa
     }
81d882d5
     else
6fbf66fa
     {
81d882d5
         return false;
6fbf66fa
     }
 }
 
 static inline void
81d882d5
 interval_schedule_wakeup(struct interval *top, interval_t *wakeup)
6fbf66fa
 {
81d882d5
     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);
6fbf66fa
 #if INTERVAL_DEBUG
81d882d5
     dmsg(D_INTERVAL, "INTERVAL interval_schedule wakeup=%d", (int)*wakeup);
6fbf66fa
 #endif
 }
 
 /*
  * In wakeup seconds, interval_test will return true once.
  */
 static inline void
4cd4899e
 interval_future_trigger(struct interval *top, interval_t wakeup)
 {
81d882d5
     if (wakeup)
6fbf66fa
     {
 #if INTERVAL_DEBUG
81d882d5
         dmsg(D_INTERVAL, "INTERVAL interval_future_trigger %d", (int)wakeup);
6fbf66fa
 #endif
81d882d5
         top->future_trigger = now + wakeup;
6fbf66fa
     }
 }
 
 /*
  * Once an action is triggered, interval_test will remain true for
  * horizon seconds.
  */
 static inline void
81d882d5
 interval_action(struct interval *top)
6fbf66fa
 {
 #if INTERVAL_DEBUG
81d882d5
     dmsg(D_INTERVAL, "INTERVAL action");
6fbf66fa
 #endif
81d882d5
     top->last_action = now;
6fbf66fa
 }
 
 /*
  * Measure when n seconds beyond an event have elapsed
  */
 
 struct event_timeout
 {
81d882d5
     bool defined;
     interval_t n;
     time_t last; /* time of last event */
6fbf66fa
 };
 
 static inline bool
81d882d5
 event_timeout_defined(const struct event_timeout *et)
6fbf66fa
 {
81d882d5
     return et->defined;
6fbf66fa
 }
 
 static inline void
81d882d5
 event_timeout_clear(struct event_timeout *et)
6fbf66fa
 {
81d882d5
     et->defined = false;
     et->n = 0;
     et->last = 0;
6fbf66fa
 }
 
 static inline struct event_timeout
e2a0cad4
 event_timeout_clear_ret(void)
6fbf66fa
 {
81d882d5
     struct event_timeout ret;
     event_timeout_clear(&ret);
     return ret;
6fbf66fa
 }
 
 static inline void
81d882d5
 event_timeout_init(struct event_timeout *et, interval_t n, const time_t local_now)
6fbf66fa
 {
81d882d5
     et->defined = true;
     et->n = (n >= 0) ? n : 0;
     et->last = local_now;
6fbf66fa
 }
 
 static inline void
81d882d5
 event_timeout_reset(struct event_timeout *et)
6fbf66fa
 {
81d882d5
     if (et->defined)
     {
         et->last = now;
     }
6fbf66fa
 }
 
72bf37c7
 static inline void
81d882d5
 event_timeout_modify_wakeup(struct event_timeout *et, interval_t n)
72bf37c7
 {
81d882d5
     /* note that you might need to call reset_coarse_timers after this */
     if (et->defined)
     {
         et->n = (n >= 0) ? n : 0;
     }
72bf37c7
 }
 
6fbf66fa
 /*
f2134b7b
  * Will return the time left for a timeout, this function does not check
  * if the timeout is actually valid
  */
81d882d5
 static inline interval_t
 event_timeout_remaining(struct event_timeout *et)
f2134b7b
 {
81d882d5
     return (int) et->last + et->n - now;
f2134b7b
 }
 
 /*
6fbf66fa
  * 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)
 
81d882d5
 bool event_timeout_trigger(struct event_timeout *et,
                            struct timeval *tv,
                            const int et_const_retry);
6fbf66fa
 
 /*
  * 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 {
81d882d5
     struct timeval start;
     struct timeval end;
6fbf66fa
 };
 
 #ifdef HAVE_GETTIMEOFDAY
 
 static inline void
81d882d5
 usec_timer_start(struct usec_timer *obj)
6fbf66fa
 {
81d882d5
     CLEAR(*obj);
     openvpn_gettimeofday(&obj->start, NULL);
6fbf66fa
 }
 
 static inline void
81d882d5
 usec_timer_end(struct usec_timer *obj)
6fbf66fa
 {
81d882d5
     openvpn_gettimeofday(&obj->end, NULL);
6fbf66fa
 }
 
 #endif /* HAVE_GETTIMEOFDAY */
 
 static inline bool
81d882d5
 usec_timer_interval_defined(struct usec_timer *obj)
6fbf66fa
 {
81d882d5
     return obj->start.tv_sec && obj->end.tv_sec;
6fbf66fa
 }
 
 static inline int
81d882d5
 usec_timer_interval(struct usec_timer *obj)
6fbf66fa
 {
81d882d5
     return tv_subtract(&obj->end, &obj->start, USEC_TIMER_MAX);
6fbf66fa
 }
 
 #endif /* INTERVAL_H */