OpenVPN 3 Core Library
Loading...
Searching...
No Matches
time.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#pragma once
13
14#include <chrono>
15#include <cstdint> // for std::uint32_t, uint64_t
16#include <limits>
17
23
24
25#ifdef OPENVPN_PLATFORM_WIN
26#include <time.h> // for ::time() on Windows
27#include <windows.h> // for GetTickCount64
28#else
29#include <sys/time.h> // for ::time() and ::gettimeofday()
30#endif
31
32namespace openvpn {
34
56template <typename T>
58{
59 public:
60 enum
61 {
62 prec = 1024
63 };
64 using base_type = ::time_t;
65 using type = T;
66
68 {
69 friend class TimeType;
70
71 public:
72 static Duration seconds(const T v)
73 {
74 return Duration(v * prec);
75 }
76 static Duration binary_ms(const T v)
77 {
78 return Duration(v);
79 }
81 {
82 return Duration(std::numeric_limits<T>::max());
83 }
84
85 static Duration milliseconds(const T v)
86 {
87 // NOTE: assumes that prec == 1024
88 // Also note that this might wrap if v is larger than 1/3 of max size of T
89 return Duration(v + (v * T(3) / T(128)));
90 }
91
92 static Duration milliseconds(std::chrono::milliseconds ms)
93 {
94 /* Windows on 32 bit platforms warns about loss of precision otherwise */
95 return milliseconds(openvpn::numeric_util::numeric_cast<T>(ms.count()));
96 }
97
98 Duration() noexcept
99 : duration_(T(0))
100 {
101 }
102
103 bool defined() const
104 {
105 return duration_ != T(0);
106 }
107 bool operator!() const
108 {
109 return duration_ == T(0);
110 }
111 bool is_infinite() const
112 {
113 return duration_ == std::numeric_limits<T>::max();
114 }
115 bool enabled() const
116 {
117 return defined() && !is_infinite();
118 }
120 {
121 duration_ = std::numeric_limits<T>::max();
122 }
123 void set_zero()
124 {
125 duration_ = T(0);
126 }
127
129 {
130 if (is_infinite() || d.is_infinite())
131 return infinite();
132 return Duration(duration_ + d.duration_);
133 }
134
135 Duration operator+(const int delta) const
136 {
137 if (is_infinite())
138 return infinite();
139 T duration = duration_;
140 if (delta >= 0)
141 duration += delta;
142 else
143 {
144 const unsigned int ndelta = -delta;
145 if (duration_ >= ndelta)
146 duration -= ndelta;
147 else
148 duration = 0;
149 }
150 return Duration(duration);
151 }
152
153 Duration operator*(const unsigned int mult) const
154 {
155 return Duration(duration_ * mult);
156 }
157
159 {
160 if (is_infinite() || d.is_infinite())
161 set_infinite();
162 else
163 duration_ += d.duration_;
164 return *this;
165 }
166
167 void min(const Duration &d)
168 {
169 if (d.duration_ < duration_)
171 }
172
173 void max(const Duration &d)
174 {
175 if (d.duration_ > duration_)
177 }
178
180 {
181 if (d.duration_ >= duration_)
182 return Duration(0);
183 if (is_infinite())
184 return Duration::infinite();
185 return Duration(duration_ - d.duration_);
186 }
187
189 {
190 if (d.duration_ >= duration_)
191 set_zero();
192 else if (!is_infinite())
193 duration_ -= d.duration_;
194 return *this;
195 }
196
197 T to_seconds() const
198 {
199 return duration_ / prec;
200 }
201 T to_binary_ms() const
202 {
203 return duration_;
204 }
205
207 {
208 // NOTE: assumes that prec == 1024
209 // Also note that this might wrap if duration_ is larger than 1/3 of max size of T
210 return duration_ - (duration_ * T(3) / T(128));
211 }
212
213 double to_double() const
214 {
215 return double(duration_) / double(prec);
216 }
217
218 T raw() const
219 {
220 return duration_;
221 }
222
223#define OPENVPN_DURATION_REL(OP) \
224 bool operator OP(const Duration &d) const \
225 { \
226 return duration_ OP d.duration_; \
227 }
234#undef OPENVPN_DURATION_REL
235
236 private:
237 explicit Duration(const T duration)
238 : duration_(duration)
239 {
240 }
241
243 };
244
245 TimeType() noexcept
246 : time_(T(0))
247 {
248 }
249
250 static TimeType zero()
251 {
252 return TimeType(T(0));
253 }
255 {
256 return TimeType(std::numeric_limits<T>::max());
257 }
258
259 static TimeType from_seconds_since_epoch(const time_t t)
260 {
261 if (t <= base_)
262 return TimeType(T(1));
263 return TimeType(T((t - base_) * prec));
264 }
265
266 bool is_infinite() const
267 {
268 return time_ == std::numeric_limits<T>::max();
269 }
270
271 void reset()
272 {
273 time_ = 0;
274 }
276 {
277 time_ = std::numeric_limits<T>::max();
278 }
279
280 bool defined() const
281 {
282 return time_ != 0;
283 }
284 bool operator!() const
285 {
286 return time_ == 0;
287 }
288
290 {
291 return base_ + time_ / prec;
292 }
293 std::uint64_t nanoseconds_since_epoch() const
294 {
295 return base_ * 1000000000ULL + time_ * (1000000000ULL / prec);
296 }
298 {
299 return time_ % prec;
300 }
301
302 static TimeType now()
303 {
304 return TimeType(now_());
305 }
306
307 void update()
308 {
309 time_ = now_();
310 }
311
313 {
314 if (is_infinite() || d.is_infinite())
315 return infinite();
316 return TimeType(time_ + d.duration_);
317 }
318
320 {
321 if (is_infinite() || d.is_infinite())
322 set_infinite();
323 else
324 time_ += d.duration_;
325 return *this;
326 }
327
329 {
330 if (t.time_ >= time_)
331 return Duration(0);
332 if (is_infinite())
333 return Duration::infinite();
334 return Duration(time_ - t.time_);
335 }
336
337 void min(const TimeType &t)
338 {
339 if (t.time_ < time_)
340 time_ = t.time_;
341 }
342
343 void max(const TimeType &t)
344 {
345 if (t.time_ > time_)
346 time_ = t.time_;
347 }
348
349 long delta_prec(const TimeType &t) const
350 {
351 return long(time_) - long(t.time_);
352 }
353
354 long delta(const TimeType &t) const
355 {
356 return delta_prec(t) / long(prec);
357 }
358
359 double delta_float(const TimeType &t) const
360 {
361 return (double(time_) - double(t.time_)) / double(prec);
362 }
363
367 std::string delta_str(const TimeType &t) const
368 {
369 if (!defined())
370 return "UNDEF-TIME";
371 if (is_infinite())
372 return "+INF";
373 const double df = delta_float(t);
374 std::string ret;
375 if (df >= 0.0)
376 ret += '+';
377 const int idf = int(df);
378 if (df == static_cast<double>(idf))
379 ret += openvpn::to_string(idf);
380 else
381 ret += openvpn::to_string(df);
382 return ret;
383 }
384
385#define OPENVPN_TIME_REL(OP) \
386 bool operator OP(const TimeType &t) const \
387 { \
388 return time_ OP t.time_; \
389 }
396#undef OPENVPN_TIME_REL
397
398 template <typename HASH>
399 void hash(HASH &h) const
400 {
401 h(time_);
402 }
403
404 T raw() const
405 {
406 return time_;
407 }
408
410 {
411 // on 32-bit systems, reset time base after 30 days
412 if (sizeof(T) == 4)
413 {
414 const base_type newbase = ::time(NULL);
415 if (newbase - base_ >= (60 * 60 * 24 * 30))
416 reset_base();
417 }
418 }
419
420 static void reset_base()
421 {
422#ifdef OPENVPN_TIME_NO_BASE
423 static_assert(sizeof(base_type) >= 8, "OPENVPN_TIME_NO_BASE requires time_t to be 64 bits");
424#else
425 base_ = ::time(NULL);
426#ifdef OPENVPN_PLATFORM_WIN
427 win_recalibrate(::GetTickCount64());
428#endif
429#endif
430 }
431
433 static uint64_t win_time()
434 {
435 // NOTE: assumes that prec == 1024
436 return ((11644473600ULL * uint64_t(prec)) + (uint64_t(base_) * uint64_t(prec)) + uint64_t(now_())) * 78125ULL / 8ULL;
437 }
438
439 private:
440 explicit TimeType(const T time)
441 : time_(time)
442 {
443 }
444
445#ifdef OPENVPN_PLATFORM_WIN
446
447 static void win_recalibrate(const ULONGLONG gtc)
448 {
449 gtc_last = gtc;
450 gtc_base = ::time(NULL) - gtc_last / 1000;
451 }
452
453 static T now_()
454 {
455 const ULONGLONG gtc = ::GetTickCount64();
456 if (gtc < gtc_last)
457 win_recalibrate(gtc);
458 const time_t sec = gtc_base + gtc / 1000;
459 const unsigned int msec = gtc % 1000;
460 return T((sec - base_) * prec + msec * prec / 1000);
461 }
462
463 static inline ULONGLONG gtc_last = 0;
464 static inline time_t gtc_base = 0;
465
466#else
467
468 static T now_()
469 {
470 ::timeval tv;
471 if (::gettimeofday(&tv, nullptr) != 0)
472 throw get_time_error();
473 return T((tv.tv_sec - base_) * prec + tv.tv_usec * prec / 1000000);
474 }
475
476#endif
477
478#ifdef OPENVPN_TIME_NO_BASE
479 static constexpr base_type base_ = 0;
480#else
481 static inline base_type base_ = 0;
482#endif
483
485};
486
488
489using TimePtr = Time *;
490
491} // namespace openvpn
static Duration binary_ms(const T v)
Definition time.hpp:76
static Duration infinite()
Definition time.hpp:80
void min(const Duration &d)
Definition time.hpp:167
Duration(const T duration)
Definition time.hpp:237
void max(const Duration &d)
Definition time.hpp:173
Duration operator+(const Duration &d) const
Definition time.hpp:128
Duration & operator+=(const Duration &d)
Definition time.hpp:158
double to_double() const
Definition time.hpp:213
Duration operator-(const Duration &d) const
Definition time.hpp:179
Duration operator+(const int delta) const
Definition time.hpp:135
static Duration milliseconds(std::chrono::milliseconds ms)
Definition time.hpp:92
Duration & operator-=(const Duration &d)
Definition time.hpp:188
static Duration milliseconds(const T v)
Definition time.hpp:85
static Duration seconds(const T v)
Definition time.hpp:72
bool is_infinite() const
Definition time.hpp:111
Duration operator*(const unsigned int mult) const
Definition time.hpp:153
static TimeType from_seconds_since_epoch(const time_t t)
Definition time.hpp:259
std::string delta_str(const TimeType &t) const
Definition time.hpp:367
static T now_()
Definition time.hpp:468
TimeType & operator+=(const Duration &d)
Definition time.hpp:319
bool operator!() const
Definition time.hpp:284
T raw() const
Definition time.hpp:404
static TimeType infinite()
Definition time.hpp:254
static void reset_base()
Definition time.hpp:420
static TimeType zero()
Definition time.hpp:250
void max(const TimeType &t)
Definition time.hpp:343
static base_type base_
Definition time.hpp:481
TimeType(const T time)
Definition time.hpp:440
void min(const TimeType &t)
Definition time.hpp:337
std::uint64_t nanoseconds_since_epoch() const
Definition time.hpp:293
static TimeType now()
Definition time.hpp:302
static uint64_t win_time()
Definition time.hpp:433
base_type seconds_since_epoch() const
Definition time.hpp:289
::time_t base_type
Definition time.hpp:64
static void reset_base_conditional()
Definition time.hpp:409
long delta_prec(const TimeType &t) const
Definition time.hpp:349
Duration operator-(const TimeType &t) const
Definition time.hpp:328
long delta(const TimeType &t) const
Definition time.hpp:354
void hash(HASH &h) const
Definition time.hpp:399
TimeType() noexcept
Definition time.hpp:245
TimeType operator+(const Duration &d) const
Definition time.hpp:312
double delta_float(const TimeType &t) const
Definition time.hpp:359
T fractional_binary_ms() const
Definition time.hpp:297
void set_infinite()
Definition time.hpp:275
bool defined() const
Definition time.hpp:280
bool is_infinite() const
Definition time.hpp:266
#define OPENVPN_SIMPLE_EXCEPTION(C)
Definition exception.hpp:74
std::string to_string(const T &t)
Convert a value to a string.
Definition to_string.hpp:45
std::string ret
#define OPENVPN_TIME_REL(OP)
Definition time.hpp:385
#define OPENVPN_DURATION_REL(OP)
Definition time.hpp:223