1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single TCP/UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25/*
26 * The interval_ routines are designed to optimize the calling of a routine
27 * (normally tls_multi_process()) which can be called less frequently
28 * between triggers.
29 */
30
31#ifndef INTERVAL_H
32#define INTERVAL_H
33
34#include "otime.h"
35
36#define INTERVAL_DEBUG 0
37
38/*
39 * Designed to limit calls to expensive functions that need to be called
40 * regularly.
41 */
42
43struct interval
44{
45  interval_t refresh;
46  interval_t horizon;
47  time_t future_trigger;
48  time_t last_action;
49  time_t last_test_true;
50};
51
52void interval_init (struct interval *top, int horizon, int refresh);
53
54/*
55 * IF
56 *   last_action less than horizon seconds ago
57 *   OR last_test_true more than refresh seconds ago
58 *   OR hit future_trigger
59 * THEN
60 *   return true
61 * ELSE
62 *   set wakeup to the number of seconds until a true return
63 *   return false
64 */
65
66static inline bool
67interval_test (struct interval* top)
68{
69  bool trigger = false;
70  const time_t local_now = now;
71
72  if (top->future_trigger && local_now >= top->future_trigger)
73    {
74      trigger = true;
75      top->future_trigger = 0;
76    }
77
78  if (top->last_action + top->horizon > local_now ||
79      top->last_test_true + top->refresh <= local_now ||
80      trigger)
81    {
82      top->last_test_true = local_now;
83#if INTERVAL_DEBUG
84      dmsg (D_INTERVAL, "INTERVAL interval_test true");
85#endif
86      return true;
87    }
88  else
89    {
90      return false;
91    }
92}
93
94static inline void
95interval_schedule_wakeup (struct interval* top, interval_t *wakeup)
96{
97  const time_t local_now = now;
98  interval_earliest_wakeup (wakeup, top->last_test_true + top->refresh, local_now);
99  interval_earliest_wakeup (wakeup, top->future_trigger, local_now);
100#if INTERVAL_DEBUG
101  dmsg (D_INTERVAL, "INTERVAL interval_schedule wakeup=%d", (int)*wakeup);
102#endif
103}
104
105/*
106 * In wakeup seconds, interval_test will return true once.
107 */
108static inline void
109interval_future_trigger (struct interval* top, interval_t wakeup) {
110  if (wakeup)
111    {
112#if INTERVAL_DEBUG
113      dmsg (D_INTERVAL, "INTERVAL interval_future_trigger %d", (int)wakeup);
114#endif
115      top->future_trigger = now + wakeup;
116    }
117}
118
119/*
120 * Once an action is triggered, interval_test will remain true for
121 * horizon seconds.
122 */
123static inline void
124interval_action (struct interval* top)
125{
126#if INTERVAL_DEBUG
127  dmsg (D_INTERVAL, "INTERVAL action");
128#endif
129  top->last_action = now;
130}
131
132/*
133 * Measure when n seconds beyond an event have elapsed
134 */
135
136struct event_timeout
137{
138  bool defined;
139  interval_t n;
140  time_t last; /* time of last event */
141};
142
143static inline bool
144event_timeout_defined (const struct event_timeout* et)
145{
146  return et->defined;
147}
148
149static inline void
150event_timeout_clear (struct event_timeout* et)
151{
152  et->defined = false;
153  et->n = 0;
154  et->last = 0;
155}
156
157static inline struct event_timeout
158event_timeout_clear_ret ()
159{
160  struct event_timeout ret;
161  event_timeout_clear (&ret);
162  return ret;
163}
164
165static inline void
166event_timeout_init (struct event_timeout* et, interval_t n, const time_t local_now)
167{
168  et->defined = true;
169  et->n = (n >= 0) ? n : 0;
170  et->last = local_now;
171}
172
173static inline void
174event_timeout_reset (struct event_timeout* et)
175{
176  if (et->defined)
177    et->last = now;
178}
179
180static inline void
181event_timeout_modify_wakeup (struct event_timeout* et, interval_t n)
182{
183  /* note that you might need to call reset_coarse_timers after this */
184  if (et->defined)
185    et->n = (n >= 0) ? n : 0;
186}
187
188/*
189 * This is the principal function for testing and triggering recurring
190 * timers and will return true on a timer signal event.
191 * If et_const_retry == ETT_DEFAULT and a signal occurs,
192 * the function will return true and *et will be armed for the
193 * next event.  If et_const_retry >= 0 and a signal occurs,
194 * *et will not be touched, but *tv will be set to
195 * minimum (*tv, et_const_retry) for a future re-test,
196 * and the function will return true.
197 */
198
199#define ETT_DEFAULT (-1)
200
201bool event_timeout_trigger (struct event_timeout *et,
202			    struct timeval *tv,
203			    const int et_const_retry);
204
205/*
206 * Measure time intervals in microseconds
207 */
208
209#define USEC_TIMER_MAX      60 /* maximum interval size in seconds */
210
211#define USEC_TIMER_MAX_USEC (USEC_TIMER_MAX * 1000000)
212
213struct usec_timer {
214  struct timeval start;
215  struct timeval end;
216};
217
218#ifdef HAVE_GETTIMEOFDAY
219
220static inline void
221usec_timer_start (struct usec_timer *obj)
222{
223  CLEAR (*obj);
224  openvpn_gettimeofday (&obj->start, NULL);
225}
226
227static inline void
228usec_timer_end (struct usec_timer *obj)
229{
230  openvpn_gettimeofday (&obj->end, NULL);
231}
232
233#endif /* HAVE_GETTIMEOFDAY */
234
235static inline bool
236usec_timer_interval_defined (struct usec_timer *obj)
237{
238  return obj->start.tv_sec && obj->end.tv_sec;
239}
240
241static inline int
242usec_timer_interval (struct usec_timer *obj)
243{
244  return tv_subtract (&obj->end, &obj->start, USEC_TIMER_MAX);
245}
246
247#endif /* INTERVAL_H */
248