1 /*
2 * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #ifdef _WIN32
11 # include <windows.h>
12 #endif
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <openssl/async.h>
17 #include <openssl/crypto.h>
18
19 static int ctr = 0;
20 static ASYNC_JOB *currjob = NULL;
21
only_pause(void * args)22 static int only_pause(void *args)
23 {
24 ASYNC_pause_job();
25
26 return 1;
27 }
28
add_two(void * args)29 static int add_two(void *args)
30 {
31 ctr++;
32 ASYNC_pause_job();
33 ctr++;
34
35 return 2;
36 }
37
save_current(void * args)38 static int save_current(void *args)
39 {
40 currjob = ASYNC_get_current_job();
41 ASYNC_pause_job();
42
43 return 1;
44 }
45
change_deflt_libctx(void * args)46 static int change_deflt_libctx(void *args)
47 {
48 OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
49 OSSL_LIB_CTX *oldctx, *tmpctx;
50 int ret = 0;
51
52 if (libctx == NULL)
53 return 0;
54
55 oldctx = OSSL_LIB_CTX_set0_default(libctx);
56 ASYNC_pause_job();
57
58 /* Check the libctx is set up as we expect */
59 tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
60 if (tmpctx != libctx)
61 goto err;
62
63 /* Set it back again to continue to use our own libctx */
64 oldctx = OSSL_LIB_CTX_set0_default(libctx);
65 ASYNC_pause_job();
66
67 /* Check the libctx is set up as we expect */
68 tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
69 if (tmpctx != libctx)
70 goto err;
71
72 ret = 1;
73 err:
74 OSSL_LIB_CTX_free(libctx);
75 return ret;
76 }
77
78
79 #define MAGIC_WAIT_FD ((OSSL_ASYNC_FD)99)
waitfd(void * args)80 static int waitfd(void *args)
81 {
82 ASYNC_JOB *job;
83 ASYNC_WAIT_CTX *waitctx;
84 job = ASYNC_get_current_job();
85 if (job == NULL)
86 return 0;
87 waitctx = ASYNC_get_wait_ctx(job);
88 if (waitctx == NULL)
89 return 0;
90
91 /* First case: no fd added or removed */
92 ASYNC_pause_job();
93
94 /* Second case: one fd added */
95 if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
96 return 0;
97 ASYNC_pause_job();
98
99 /* Third case: all fd removed */
100 if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
101 return 0;
102 ASYNC_pause_job();
103
104 /* Last case: fd added and immediately removed */
105 if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
106 return 0;
107 if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
108 return 0;
109
110 return 1;
111 }
112
blockpause(void * args)113 static int blockpause(void *args)
114 {
115 ASYNC_block_pause();
116 ASYNC_pause_job();
117 ASYNC_unblock_pause();
118 ASYNC_pause_job();
119
120 return 1;
121 }
122
test_ASYNC_init_thread(void)123 static int test_ASYNC_init_thread(void)
124 {
125 ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL;
126 int funcret1, funcret2, funcret3;
127 ASYNC_WAIT_CTX *waitctx = NULL;
128
129 if ( !ASYNC_init_thread(2, 0)
130 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
131 || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
132 != ASYNC_PAUSE
133 || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
134 != ASYNC_PAUSE
135 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
136 != ASYNC_NO_JOBS
137 || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
138 != ASYNC_FINISH
139 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
140 != ASYNC_PAUSE
141 || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
142 != ASYNC_FINISH
143 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
144 != ASYNC_FINISH
145 || funcret1 != 1
146 || funcret2 != 1
147 || funcret3 != 1) {
148 fprintf(stderr, "test_ASYNC_init_thread() failed\n");
149 ASYNC_WAIT_CTX_free(waitctx);
150 ASYNC_cleanup_thread();
151 return 0;
152 }
153
154 ASYNC_WAIT_CTX_free(waitctx);
155 ASYNC_cleanup_thread();
156 return 1;
157 }
158
test_callback(void * arg)159 static int test_callback(void *arg)
160 {
161 printf("callback test pass\n");
162 return 1;
163 }
164
test_ASYNC_callback_status(void)165 static int test_ASYNC_callback_status(void)
166 {
167 ASYNC_WAIT_CTX *waitctx = NULL;
168 int set_arg = 100;
169 ASYNC_callback_fn get_callback;
170 void *get_arg;
171 int set_status = 1;
172
173 if ( !ASYNC_init_thread(1, 0)
174 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
175 || ASYNC_WAIT_CTX_set_callback(waitctx, test_callback, (void*)&set_arg)
176 != 1
177 || ASYNC_WAIT_CTX_get_callback(waitctx, &get_callback, &get_arg)
178 != 1
179 || test_callback != get_callback
180 || get_arg != (void*)&set_arg
181 || (*get_callback)(get_arg) != 1
182 || ASYNC_WAIT_CTX_set_status(waitctx, set_status) != 1
183 || set_status != ASYNC_WAIT_CTX_get_status(waitctx)) {
184 fprintf(stderr, "test_ASYNC_callback_status() failed\n");
185 ASYNC_WAIT_CTX_free(waitctx);
186 ASYNC_cleanup_thread();
187 return 0;
188 }
189
190 ASYNC_WAIT_CTX_free(waitctx);
191 ASYNC_cleanup_thread();
192 return 1;
193
194 }
195
test_ASYNC_start_job(void)196 static int test_ASYNC_start_job(void)
197 {
198 ASYNC_JOB *job = NULL;
199 int funcret;
200 ASYNC_WAIT_CTX *waitctx = NULL;
201
202 ctr = 0;
203
204 if ( !ASYNC_init_thread(1, 0)
205 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
206 || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
207 != ASYNC_PAUSE
208 || ctr != 1
209 || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
210 != ASYNC_FINISH
211 || ctr != 2
212 || funcret != 2) {
213 fprintf(stderr, "test_ASYNC_start_job() failed\n");
214 ASYNC_WAIT_CTX_free(waitctx);
215 ASYNC_cleanup_thread();
216 return 0;
217 }
218
219 ASYNC_WAIT_CTX_free(waitctx);
220 ASYNC_cleanup_thread();
221 return 1;
222 }
223
test_ASYNC_get_current_job(void)224 static int test_ASYNC_get_current_job(void)
225 {
226 ASYNC_JOB *job = NULL;
227 int funcret;
228 ASYNC_WAIT_CTX *waitctx = NULL;
229
230 currjob = NULL;
231
232 if ( !ASYNC_init_thread(1, 0)
233 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
234 || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
235 != ASYNC_PAUSE
236 || currjob != job
237 || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
238 != ASYNC_FINISH
239 || funcret != 1) {
240 fprintf(stderr, "test_ASYNC_get_current_job() failed\n");
241 ASYNC_WAIT_CTX_free(waitctx);
242 ASYNC_cleanup_thread();
243 return 0;
244 }
245
246 ASYNC_WAIT_CTX_free(waitctx);
247 ASYNC_cleanup_thread();
248 return 1;
249 }
250
test_ASYNC_WAIT_CTX_get_all_fds(void)251 static int test_ASYNC_WAIT_CTX_get_all_fds(void)
252 {
253 ASYNC_JOB *job = NULL;
254 int funcret;
255 ASYNC_WAIT_CTX *waitctx = NULL;
256 OSSL_ASYNC_FD fd = OSSL_BAD_ASYNC_FD, delfd = OSSL_BAD_ASYNC_FD;
257 size_t numfds, numdelfds;
258
259 if ( !ASYNC_init_thread(1, 0)
260 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
261 /* On first run we're not expecting any wait fds */
262 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
263 != ASYNC_PAUSE
264 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
265 || numfds != 0
266 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
267 &numdelfds)
268 || numfds != 0
269 || numdelfds != 0
270 /* On second run we're expecting one added fd */
271 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
272 != ASYNC_PAUSE
273 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
274 || numfds != 1
275 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, &fd, &numfds)
276 || fd != MAGIC_WAIT_FD
277 || (fd = OSSL_BAD_ASYNC_FD, 0) /* Assign to something else */
278 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
279 &numdelfds)
280 || numfds != 1
281 || numdelfds != 0
282 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, &fd, &numfds, NULL,
283 &numdelfds)
284 || fd != MAGIC_WAIT_FD
285 /* On third run we expect one deleted fd */
286 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
287 != ASYNC_PAUSE
288 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
289 || numfds != 0
290 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
291 &numdelfds)
292 || numfds != 0
293 || numdelfds != 1
294 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, &delfd,
295 &numdelfds)
296 || delfd != MAGIC_WAIT_FD
297 /* On last run we are not expecting any wait fd */
298 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
299 != ASYNC_FINISH
300 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
301 || numfds != 0
302 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
303 &numdelfds)
304 || numfds != 0
305 || numdelfds != 0
306 || funcret != 1) {
307 fprintf(stderr, "test_ASYNC_get_wait_fd() failed\n");
308 ASYNC_WAIT_CTX_free(waitctx);
309 ASYNC_cleanup_thread();
310 return 0;
311 }
312
313 ASYNC_WAIT_CTX_free(waitctx);
314 ASYNC_cleanup_thread();
315 return 1;
316 }
317
test_ASYNC_block_pause(void)318 static int test_ASYNC_block_pause(void)
319 {
320 ASYNC_JOB *job = NULL;
321 int funcret;
322 ASYNC_WAIT_CTX *waitctx = NULL;
323
324 if ( !ASYNC_init_thread(1, 0)
325 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
326 || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
327 != ASYNC_PAUSE
328 || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
329 != ASYNC_FINISH
330 || funcret != 1) {
331 fprintf(stderr, "test_ASYNC_block_pause() failed\n");
332 ASYNC_WAIT_CTX_free(waitctx);
333 ASYNC_cleanup_thread();
334 return 0;
335 }
336
337 ASYNC_WAIT_CTX_free(waitctx);
338 ASYNC_cleanup_thread();
339 return 1;
340 }
341
test_ASYNC_start_job_ex(void)342 static int test_ASYNC_start_job_ex(void)
343 {
344 ASYNC_JOB *job = NULL;
345 int funcret;
346 ASYNC_WAIT_CTX *waitctx = NULL;
347 OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
348 OSSL_LIB_CTX *oldctx, *tmpctx, *globalctx;
349 int ret = 0;
350
351 if (libctx == NULL) {
352 fprintf(stderr,
353 "test_ASYNC_start_job_ex() failed to create libctx\n");
354 goto err;
355 }
356
357 globalctx = oldctx = OSSL_LIB_CTX_set0_default(libctx);
358
359 if ((waitctx = ASYNC_WAIT_CTX_new()) == NULL
360 || ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx,
361 NULL, 0)
362 != ASYNC_PAUSE) {
363 fprintf(stderr,
364 "test_ASYNC_start_job_ex() failed to start job\n");
365 goto err;
366 }
367
368 /* Reset the libctx temporarily to find out what it is*/
369 tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
370 oldctx = OSSL_LIB_CTX_set0_default(tmpctx);
371 if (tmpctx != libctx) {
372 fprintf(stderr,
373 "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
374 goto err;
375 }
376
377 if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
378 != ASYNC_PAUSE) {
379 fprintf(stderr,
380 "test_ASYNC_start_job_ex() - restarting job failed\n");
381 goto err;
382 }
383
384 /* Reset the libctx and continue with the global default libctx */
385 tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
386 if (tmpctx != libctx) {
387 fprintf(stderr,
388 "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
389 goto err;
390 }
391
392 if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
393 != ASYNC_FINISH
394 || funcret != 1) {
395 fprintf(stderr,
396 "test_ASYNC_start_job_ex() - finishing job failed\n");
397 goto err;
398 }
399
400 /* Reset the libctx temporarily to find out what it is*/
401 tmpctx = OSSL_LIB_CTX_set0_default(libctx);
402 OSSL_LIB_CTX_set0_default(tmpctx);
403 if (tmpctx != globalctx) {
404 fprintf(stderr,
405 "test_ASYNC_start_job_ex() failed - global libctx check failed\n");
406 goto err;
407 }
408
409 ret = 1;
410 err:
411 ASYNC_WAIT_CTX_free(waitctx);
412 ASYNC_cleanup_thread();
413 OSSL_LIB_CTX_free(libctx);
414 return ret;
415 }
416
main(int argc,char ** argv)417 int main(int argc, char **argv)
418 {
419 if (!ASYNC_is_capable()) {
420 fprintf(stderr,
421 "OpenSSL build is not ASYNC capable - skipping async tests\n");
422 } else {
423 if (!test_ASYNC_init_thread()
424 || !test_ASYNC_callback_status()
425 || !test_ASYNC_start_job()
426 || !test_ASYNC_get_current_job()
427 || !test_ASYNC_WAIT_CTX_get_all_fds()
428 || !test_ASYNC_block_pause()
429 || !test_ASYNC_start_job_ex()) {
430 return 1;
431 }
432 }
433 printf("PASS\n");
434 return 0;
435 }
436