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