OpenVPN
compat-gettimeofday.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single 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-2025 OpenVPN 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 along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#ifndef HAVE_GETTIMEOFDAY
28
29#include "compat.h"
30
31#ifdef _WIN32
32/*
33 * NOTICE: mingw has much faster gettimeofday!
34 * autoconf will set HAVE_GETTIMEOFDAY
35 */
36
37#include <windows.h>
38#include <time.h>
39
40static time_t gtc_base = 0;
41static DWORD gtc_last = 0;
42static time_t last_sec = 0;
43static unsigned int last_msec = 0;
44static int bt_last = 0;
45
46static void
47gettimeofday_calibrate(void)
48{
49 const time_t t = time(NULL);
50 const DWORD gtc = GetTickCount();
51 gtc_base = t - gtc / 1000;
52 gtc_last = gtc;
53}
54
55/*
56 * Rewritten by JY for OpenVPN 2.1, after I realized that
57 * QueryPerformanceCounter takes nearly 2 orders of magnitude
58 * more processor cycles than GetTickCount.
59 */
60int
61gettimeofday(struct timeval *tv, void *tz)
62{
63 const DWORD gtc = GetTickCount();
64 int bt = 0;
65 time_t sec;
66 unsigned int msec;
67 const int backtrack_hold_seconds = 10;
68
69 (void)tz;
70
71 /* recalibrate at the dreaded 49.7 day mark */
72 if (!gtc_base || gtc < gtc_last)
73 {
74 gettimeofday_calibrate();
75 }
76 gtc_last = gtc;
77
78 sec = gtc_base + gtc / 1000;
79 msec = gtc % 1000;
80
81 if (sec == last_sec)
82 {
83 if (msec < last_msec)
84 {
85 msec = last_msec;
86 bt = 1;
87 }
88 }
89 else if (sec < last_sec)
90 {
91 /* We try to dampen out backtracks of less than backtrack_hold_seconds.
92 * Larger backtracks will be passed through and dealt with by the
93 * TIME_BACKTRACK_PROTECTION code */
94 if (sec > last_sec - backtrack_hold_seconds)
95 {
96 sec = last_sec;
97 msec = last_msec;
98 }
99 bt = 1;
100 }
101
102 last_sec = sec;
103 tv->tv_sec = (long)sec;
104 tv->tv_usec = (last_msec = msec) * 1000;
105
106 if (bt && !bt_last)
107 {
108 gettimeofday_calibrate();
109 }
110 bt_last = bt;
111
112 return 0;
113}
114
115#else /* ifdef _WIN32 */
116
117#include <time.h>
118
119int
120gettimeofday(struct timeval *tv, void *tz)
121{
122 (void)tz;
123 tv->tv_sec = time(NULL);
124 tv->tv_usec = 0;
125 return 0;
126}
127
128#endif /* _WIN32 */
129
130#endif /* HAVE_GETTIMEOFDAY */