OpenVPN
test_schedule.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-2026 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#include "syshead.h"
28#include "schedule.h"
29#include "test_common.h"
30
31static inline bool
32tv_lt(const struct timeval *t1, const struct timeval *t2)
33{
34 if (t1->tv_sec < t2->tv_sec)
35 {
36 return true;
37 }
38 else if (t1->tv_sec > t2->tv_sec)
39 {
40 return false;
41 }
42 else
43 {
44 return t1->tv_usec < t2->tv_usec;
45 }
46}
47
48static inline bool
49tv_le(const struct timeval *t1, const struct timeval *t2)
50{
51 if (t1->tv_sec < t2->tv_sec)
52 {
53 return true;
54 }
55 else if (t1->tv_sec > t2->tv_sec)
56 {
57 return false;
58 }
59 else
60 {
61 return t1->tv_usec <= t2->tv_usec;
62 }
63}
64
65static inline bool
66tv_eq(const struct timeval *t1, const struct timeval *t2)
67{
68 return t1->tv_sec == t2->tv_sec && t1->tv_usec == t2->tv_usec;
69}
70
71static inline struct schedule_entry *
76
77/*
78 * Recursively check that the treap (btree) is
79 * internally consistent.
80 */
81int
82schedule_debug_entry(const struct schedule_entry *e, int depth, int *count, struct timeval *least,
83 const struct timeval *min, const struct timeval *max)
84{
85 struct gc_arena gc = gc_new();
86 int maxdepth = depth;
87 if (e)
88 {
89 int d;
90
91 assert_ptr_not_equal(e, e->lt);
92 assert_ptr_not_equal(e, e->gt);
93 assert_ptr_not_equal(e, e->parent);
94 assert_true(!e->parent || e->parent != e->lt);
95 assert_true(!e->parent || e->parent != e->gt);
96 assert_true(!e->lt || e->lt != e->gt);
97
98 if (e->lt)
99 {
100 assert_ptr_equal(e->lt->parent, e);
101 assert_int_equal(schedule_entry_compare(e->lt, e), -1);
102 assert_true(e->lt->pri >= e->pri);
103 }
104
105 if (e->gt)
106 {
107 assert_ptr_equal(e->gt->parent, e);
108 assert_int_equal(schedule_entry_compare(e->gt, e), 1);
109 assert_true(e->gt->pri >= e->pri);
110 }
111
112 assert_true(tv_le(min, &e->tv));
113 assert_true(tv_le(&e->tv, max));
114
115 if (count)
116 {
117 ++(*count);
118 }
119
120 if (least && tv_lt(&e->tv, least))
121 {
122 *least = e->tv;
123 }
124
125 d = schedule_debug_entry(e->lt, depth + 1, count, least, min, &e->tv);
126 if (d > maxdepth)
127 {
128 maxdepth = d;
129 }
130
131 d = schedule_debug_entry(e->gt, depth + 1, count, least, &e->tv, max);
132 if (d > maxdepth)
133 {
134 maxdepth = d;
135 }
136 }
137 gc_free(&gc);
138 return maxdepth;
139}
140
141int
142schedule_debug(struct schedule *s, int *count, struct timeval *least)
143{
144 struct timeval min;
145 struct timeval max;
146
147 min.tv_sec = 0;
148 min.tv_usec = 0;
149 max.tv_sec = 0x7FFFFFFF;
150 max.tv_usec = 0x7FFFFFFF;
151
152 if (s->root)
153 {
154 assert_null(s->root->parent);
155 }
156 return schedule_debug_entry(s->root, 0, count, least, &min, &max);
157}
158
159void
160tv_randomize(struct timeval *tv)
161{
162 tv->tv_sec += random() % 100;
163 tv->tv_usec = random() % 100;
164}
165
166void
167schedule_verify(struct schedule *s, int n)
168{
169 struct gc_arena gc = gc_new();
170 struct timeval least;
171
172 least.tv_sec = least.tv_usec = 0x7FFFFFFF;
173
174 int count = 0;
175 int maxlev = schedule_debug(s, &count, &least);
176
177 /* a stupid algorithm to do C23 stdc_bit_ceil_ui/stdc_bit_width
178 * calculate roundup(log2 n) */
179 int bit_ceil_n = 1;
180 int log2n = 0;
181 while (bit_ceil_n < n)
182 {
183 bit_ceil_n <<= 1;
184 log2n++;
185 }
186
187 /* Since this is a binary tree the maximum level needs to be at least
188 * log2(n) */
189 assert_true(maxlev >= log2n);
191
192 if (e)
193 {
194 assert_true(tv_eq(&least, &e->tv));
195 }
196
197 gc_free(&gc);
198}
199
200void
202{
203 int i;
204 for (i = 0; i < size; ++i)
205 {
206 const int src = rand() % size;
207 struct schedule_entry *tmp = array[i];
208 if (i != src)
209 {
210 array[i] = array[src];
211 array[src] = tmp;
212 }
213 }
214}
215
216void
218{
219 struct gc_arena gc = gc_new();
220 int i;
221 for (i = 0; i < indent; ++i)
222 {
223 printf(" ");
224 }
225 if (e)
226 {
227 printf("%s [%u] e=" ptr_format ", p=" ptr_format " lt=" ptr_format " gt=" ptr_format "\n",
228 tv_string(&e->tv, &gc), e->pri, (ptr_type)e, (ptr_type)e->parent, (ptr_type)e->lt,
229 (ptr_type)e->gt);
230 schedule_print_work(e->lt, indent + 1);
231 schedule_print_work(e->gt, indent + 1);
232 }
233 else
234 {
235 printf("NULL\n");
236 }
237 gc_free(&gc);
238}
239
240void
242{
243 printf("*************************\n");
245}
246
247void
248schedule_test(void **state)
249{
250 struct gc_arena gc = gc_new();
251 int n = 1000;
252 int n_mod = 25;
253
254 int i, j;
255 struct schedule_entry **array;
256 struct schedule *s = schedule_init();
257 struct schedule_entry *e;
258
259 ALLOC_ARRAY(array, struct schedule_entry *, n);
260
261 for (i = 0; i < n; ++i)
262 {
263 ALLOC_OBJ_CLEAR(array[i], struct schedule_entry);
264 tv_randomize(&array[i]->tv);
265 /*schedule_print (s);*/
266 /*schedule_verify (s, n);*/
267 schedule_add_modify(s, array[i]);
268 }
269
270 schedule_randomize_array(array, n);
271
272 /*schedule_print (s);*/
273 schedule_verify(s, n);
274
275 for (j = 1; j <= n_mod; ++j)
276 {
277 /*printf("Modification Phase Pass %d\n", j);*/
278
279 for (i = 0; i < n; ++i)
280 {
282 /*printf ("BEFORE %s\n", tv_string (&e->tv, &gc));*/
283 tv_randomize(&e->tv);
284 /*printf ("AFTER %s\n", tv_string (&e->tv, &gc));*/
286 /*schedule_verify (s, n);*/
287 /*schedule_print (s);*/
288 }
289 schedule_verify(s, n);
290 /*schedule_print (s);*/
291 }
292
293 /*printf ("INS=%d\n", z.ins);*/
294
295 while ((e = schedule_find_earliest_wakeup(s)))
296 {
298 /*schedule_verify (s, n);*/
299 }
300 schedule_verify(s, 0);
301 assert_null(s->root);
302
303 for (i = 0; i < n; ++i)
304 {
305 free(array[i]);
306 }
307 free(array);
308 schedule_free(s);
309 gc_free(&gc);
310}
static void gc_free(struct gc_arena *a)
Definition buffer.h:1081
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition buffer.h:1120
#define ALLOC_ARRAY(dptr, type, n)
Definition buffer.h:1126
static struct gc_arena gc_new(void)
Definition buffer.h:1073
unsigned long ptr_type
Definition common.h:59
#define ptr_format
Definition common.h:50
const char * tv_string(const struct timeval *tv, struct gc_arena *gc)
Definition otime.c:83
struct schedule * schedule_init(void)
Definition schedule.c:373
void schedule_remove_node(struct schedule *s, struct schedule_entry *e)
Definition schedule.c:220
struct schedule_entry * schedule_find_least(struct schedule_entry *e)
Definition schedule.c:348
int schedule_entry_compare(const struct schedule_entry *e1, const struct schedule_entry *e2)
This method compares two schedule entries and return which one is earlier,later or equal.
Definition schedule.c:65
void schedule_add_modify(struct schedule *s, struct schedule_entry *e)
Definition schedule.c:309
void schedule_free(struct schedule *s)
Definition schedule.c:382
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
Definition schedule.h:41
unsigned int pri
Definition schedule.h:43
struct timeval tv
Definition schedule.h:42
struct schedule_entry * lt
Definition schedule.h:45
struct schedule_entry * parent
Definition schedule.h:44
struct schedule_entry * gt
Definition schedule.h:46
struct schedule_entry * root
Definition schedule.h:52
#define random
Definition syshead.h:43
static bool tv_le(const struct timeval *t1, const struct timeval *t2)
static bool tv_eq(const struct timeval *t1, const struct timeval *t2)
void tv_randomize(struct timeval *tv)
static struct schedule_entry * schedule_find_earliest_wakeup(struct schedule *s)
int schedule_debug(struct schedule *s, int *count, struct timeval *least)
static bool tv_lt(const struct timeval *t1, const struct timeval *t2)
void schedule_verify(struct schedule *s, int n)
void schedule_print_work(struct schedule_entry *e, int indent)
void schedule_randomize_array(struct schedule_entry **array, int size)
void schedule_test(void **state)
Runs the schedule test.
int schedule_debug_entry(const struct schedule_entry *e, int depth, int *count, struct timeval *least, const struct timeval *min, const struct timeval *max)
void schedule_print(struct schedule *s)
struct gc_arena gc
Definition test_ssl.c:133