OpenVPN
otime.c
Go to the documentation of this file.
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-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, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include "otime.h"
31
32#include "memdbg.h"
33
34time_t now = 0; /* GLOBAL */
35
36static time_t now_adj = 0; /* GLOBAL */
37time_t now_usec = 0; /* GLOBAL */
38
39/*
40 * Try to filter out time instability caused by the system
41 * clock backtracking or jumping forward.
42 */
43
44void
45update_now(const time_t system_time)
46{
47 /* threshold at which to dampen forward jumps */
48 const int forward_threshold = 86400;
49 /* backward jump must be >= this many seconds before we adjust */
50 const int backward_trigger = 10;
51 time_t real_time = system_time + now_adj;
52
53 if (real_time > now)
54 {
55 const time_t overshoot = real_time - now - 1;
56 if (overshoot > forward_threshold && now_adj >= overshoot)
57 {
58 now_adj -= overshoot;
59 real_time -= overshoot;
60 }
61 now = real_time;
62 }
63 else if (real_time < now - backward_trigger)
64 {
65 now_adj += (now - real_time);
66 }
67}
68
69void
70update_now_usec(struct timeval *tv)
71{
72 const time_t last = now;
73 update_now(tv->tv_sec);
74 if (now > last || (now == last && tv->tv_usec > now_usec))
75 {
76 now_usec = tv->tv_usec;
77 }
78}
79
80/*
81 * Return a numerical string describing a struct timeval.
82 */
83const char *
84tv_string(const struct timeval *tv, struct gc_arena *gc)
85{
86 struct buffer out = alloc_buf_gc(64, gc);
87 buf_printf(&out, "[%" PRIi64 "/%ld]",
88 (int64_t)tv->tv_sec,
89 (long)tv->tv_usec);
90 return BSTR(&out);
91}
92
93/*
94 * Return an ascii string describing an absolute
95 * date/time in a struct timeval.
96 *
97 */
98const char *
99tv_string_abs(const struct timeval *tv, struct gc_arena *gc)
100{
101 return time_string((time_t) tv->tv_sec,
102 (long) tv->tv_usec,
103 true,
104 gc);
105}
106
107/* format a time_t as ascii, or use current time if 0 */
108
109const char *
111{
112 struct buffer out = alloc_buf_gc(64, gc);
113 struct timeval tv;
114
115 if (t)
116 {
117 tv.tv_sec = t;
118 tv.tv_usec = usec;
119 }
120 else
121 {
122 gettimeofday(&tv, NULL);
123 }
124
125 t = tv.tv_sec;
126 struct tm *tm = localtime(&t);
127
128 buf_printf(&out, "%04d-%02d-%02d %02d:%02d:%02d",
129 tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
130 tm->tm_hour, tm->tm_min, tm->tm_sec);
131
132 if (show_usec && tv.tv_usec)
133 {
134 buf_printf(&out, " us=%ld", (long)tv.tv_usec);
135 }
136
137 return BSTR(&out);
138}
139
140/*
141 * Limit the frequency of an event stream.
142 *
143 * Used to control maximum rate of new
144 * incoming connections.
145 */
146
147struct frequency_limit *
149{
150 struct frequency_limit *f;
151
152 ASSERT(max >= 0 && per >= 0);
153
154 ALLOC_OBJ(f, struct frequency_limit);
155 f->max = max;
156 f->per = per;
157 f->n = 0;
158 f->reset = 0;
159 return f;
160}
161
162void
164{
165 free(f);
166}
167
168bool
170{
171 if (f->per)
172 {
173 bool ret;
174 if (now >= f->reset + f->per)
175 {
176 f->reset = now;
177 f->n = 0;
178 }
179 ret = (++f->n <= f->max);
180 return ret;
181 }
182 else
183 {
184 return true;
185 }
186}
187
188#ifdef TIME_TEST
189void
190time_test(void)
191{
192 struct timeval tv;
193 time_t t;
194 int i;
195 for (i = 0; i < 10000; ++i)
196 {
197 t = time(NULL);
198 gettimeofday(&tv, NULL);
199#if 1
200 msg(M_INFO, "t=%" PRIi64 " s=%" PRIi64 " us=%ld",
201 (int64_t)t,
202 (int64_t)tv.tv_sec,
203 (long)tv.tv_usec);
204#endif
205 }
206}
207#endif
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
#define ALLOC_OBJ(dptr, type)
Definition buffer.h:1055
#define BSTR(buf)
Definition buffer.h:129
#define M_INFO
Definition errlevel.h:55
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
const char * time_string(time_t t, long usec, bool show_usec, struct gc_arena *gc)
Definition otime.c:110
time_t now_usec
Definition otime.c:37
struct frequency_limit * frequency_limit_init(int max, int per)
Definition otime.c:148
void update_now(const time_t system_time)
Definition otime.c:45
void update_now_usec(struct timeval *tv)
Definition otime.c:70
time_t now
Definition otime.c:34
void frequency_limit_free(struct frequency_limit *f)
Definition otime.c:163
const char * tv_string(const struct timeval *tv, struct gc_arena *gc)
Definition otime.c:84
const char * tv_string_abs(const struct timeval *tv, struct gc_arena *gc)
Definition otime.c:99
bool frequency_limit_event_allowed(struct frequency_limit *f)
Definition otime.c:169
static time_t now_adj
Definition otime.c:36
void time_test(void)
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
time_t reset
Definition otime.h:36
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct gc_arena gc
Definition test_ssl.c:155