xref: /src/crypto/openssl/test/asynctest.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
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 static int custom_alloc_used = 0;
22 static int custom_free_used = 0;
23 
only_pause(void * args)24 static int only_pause(void *args)
25 {
26     ASYNC_pause_job();
27 
28     return 1;
29 }
30 
add_two(void * args)31 static int add_two(void *args)
32 {
33     ctr++;
34     ASYNC_pause_job();
35     ctr++;
36 
37     return 2;
38 }
39 
save_current(void * args)40 static int save_current(void *args)
41 {
42     currjob = ASYNC_get_current_job();
43     ASYNC_pause_job();
44 
45     return 1;
46 }
47 
change_deflt_libctx(void * args)48 static int change_deflt_libctx(void *args)
49 {
50     OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
51     OSSL_LIB_CTX *oldctx, *tmpctx;
52     int ret = 0;
53 
54     if (libctx == NULL)
55         return 0;
56 
57     oldctx = OSSL_LIB_CTX_set0_default(libctx);
58     ASYNC_pause_job();
59 
60     /* Check the libctx is set up as we expect */
61     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
62     if (tmpctx != libctx)
63         goto err;
64 
65     /* Set it back again to continue to use our own libctx */
66     oldctx = OSSL_LIB_CTX_set0_default(libctx);
67     ASYNC_pause_job();
68 
69     /* Check the libctx is set up as we expect */
70     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
71     if (tmpctx != libctx)
72         goto err;
73 
74     ret = 1;
75 err:
76     OSSL_LIB_CTX_free(libctx);
77     return ret;
78 }
79 
80 #define MAGIC_WAIT_FD ((OSSL_ASYNC_FD)99)
waitfd(void * args)81 static int waitfd(void *args)
82 {
83     ASYNC_JOB *job;
84     ASYNC_WAIT_CTX *waitctx;
85     job = ASYNC_get_current_job();
86     if (job == NULL)
87         return 0;
88     waitctx = ASYNC_get_wait_ctx(job);
89     if (waitctx == NULL)
90         return 0;
91 
92     /* First case: no fd added or removed */
93     ASYNC_pause_job();
94 
95     /* Second case: one fd added */
96     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
97         return 0;
98     ASYNC_pause_job();
99 
100     /* Third case: all fd removed */
101     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
102         return 0;
103     ASYNC_pause_job();
104 
105     /* Last case: fd added and immediately removed */
106     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
107         return 0;
108     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
109         return 0;
110 
111     return 1;
112 }
113 
blockpause(void * args)114 static int blockpause(void *args)
115 {
116     ASYNC_block_pause();
117     ASYNC_pause_job();
118     ASYNC_unblock_pause();
119     ASYNC_pause_job();
120 
121     return 1;
122 }
123 
test_ASYNC_init_thread(void)124 static int test_ASYNC_init_thread(void)
125 {
126     ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL;
127     int funcret1, funcret2, funcret3;
128     ASYNC_WAIT_CTX *waitctx = NULL;
129 
130     if (!ASYNC_init_thread(2, 0)
131         || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
132         || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
133             != ASYNC_PAUSE
134         || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
135             != ASYNC_PAUSE
136         || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
137             != ASYNC_NO_JOBS
138         || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
139             != ASYNC_FINISH
140         || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
141             != ASYNC_PAUSE
142         || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
143             != ASYNC_FINISH
144         || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
145             != ASYNC_FINISH
146         || funcret1 != 1
147         || funcret2 != 1
148         || funcret3 != 1) {
149         fprintf(stderr, "test_ASYNC_init_thread() failed\n");
150         ASYNC_WAIT_CTX_free(waitctx);
151         ASYNC_cleanup_thread();
152         return 0;
153     }
154 
155     ASYNC_WAIT_CTX_free(waitctx);
156     ASYNC_cleanup_thread();
157     return 1;
158 }
159 
test_callback(void * arg)160 static int test_callback(void *arg)
161 {
162     printf("callback test pass\n");
163     return 1;
164 }
165 
test_ASYNC_callback_status(void)166 static int test_ASYNC_callback_status(void)
167 {
168     ASYNC_WAIT_CTX *waitctx = NULL;
169     int set_arg = 100;
170     ASYNC_callback_fn get_callback;
171     void *get_arg;
172     int set_status = 1;
173 
174     if (!ASYNC_init_thread(1, 0)
175         || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
176         || ASYNC_WAIT_CTX_set_callback(waitctx, test_callback, (void *)&set_arg)
177             != 1
178         || ASYNC_WAIT_CTX_get_callback(waitctx, &get_callback, &get_arg)
179             != 1
180         || test_callback != get_callback
181         || get_arg != (void *)&set_arg
182         || (*get_callback)(get_arg) != 1
183         || ASYNC_WAIT_CTX_set_status(waitctx, set_status) != 1
184         || set_status != ASYNC_WAIT_CTX_get_status(waitctx)) {
185         fprintf(stderr, "test_ASYNC_callback_status() failed\n");
186         ASYNC_WAIT_CTX_free(waitctx);
187         ASYNC_cleanup_thread();
188         return 0;
189     }
190 
191     ASYNC_WAIT_CTX_free(waitctx);
192     ASYNC_cleanup_thread();
193     return 1;
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 
test_alloc_stack(size_t * num)417 static void *test_alloc_stack(size_t *num)
418 {
419     custom_alloc_used = 1;
420     return OPENSSL_malloc(*num);
421 }
422 
test_free_stack(void * addr)423 static void test_free_stack(void *addr)
424 {
425     custom_free_used = 1;
426     OPENSSL_free(addr);
427 }
428 
test_ASYNC_set_mem_functions(void)429 static int test_ASYNC_set_mem_functions(void)
430 {
431     ASYNC_stack_alloc_fn alloc_fn;
432     ASYNC_stack_free_fn free_fn;
433 
434     /* Not all platforms support this */
435     if (ASYNC_set_mem_functions(test_alloc_stack, test_free_stack) == 0)
436         return 1;
437 
438     ASYNC_get_mem_functions(&alloc_fn, &free_fn);
439 
440     if ((alloc_fn != test_alloc_stack) || (free_fn != test_free_stack)) {
441         fprintf(stderr,
442             "test_ASYNC_set_mem_functions() - setting and retrieving custom allocators failed\n");
443         return 0;
444     }
445 
446     if (!ASYNC_init_thread(1, 1)) {
447         fprintf(stderr,
448             "test_ASYNC_set_mem_functions() - failed initialising ctx pool\n");
449         return 0;
450     }
451     ASYNC_cleanup_thread();
452 
453     if (!custom_alloc_used || !custom_free_used) {
454         fprintf(stderr,
455             "test_ASYNC_set_mem_functions() - custom allocation functions not used\n");
456 
457         return 0;
458     }
459 
460     return 1;
461 }
462 
main(int argc,char ** argv)463 int main(int argc, char **argv)
464 {
465     if (!ASYNC_is_capable()) {
466         fprintf(stderr,
467             "OpenSSL build is not ASYNC capable - skipping async tests\n");
468     } else {
469         if (!test_ASYNC_init_thread()
470             || !test_ASYNC_callback_status()
471             || !test_ASYNC_start_job()
472             || !test_ASYNC_get_current_job()
473             || !test_ASYNC_WAIT_CTX_get_all_fds()
474             || !test_ASYNC_block_pause()
475             || !test_ASYNC_start_job_ex()
476             || !test_ASYNC_set_mem_functions()) {
477             return 1;
478         }
479     }
480     printf("PASS\n");
481     return 0;
482 }
483