xref: /openssl/test/asynctest.c (revision fecb3aae)
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 
81 #define MAGIC_WAIT_FD   ((OSSL_ASYNC_FD)99)
waitfd(void * args)82 static int waitfd(void *args)
83 {
84     ASYNC_JOB *job;
85     ASYNC_WAIT_CTX *waitctx;
86     job = ASYNC_get_current_job();
87     if (job == NULL)
88         return 0;
89     waitctx = ASYNC_get_wait_ctx(job);
90     if (waitctx == NULL)
91         return 0;
92 
93     /* First case: no fd added or removed */
94     ASYNC_pause_job();
95 
96     /* Second case: one fd added */
97     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
98         return 0;
99     ASYNC_pause_job();
100 
101     /* Third case: all fd removed */
102     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
103         return 0;
104     ASYNC_pause_job();
105 
106     /* Last case: fd added and immediately removed */
107     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
108         return 0;
109     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
110         return 0;
111 
112     return 1;
113 }
114 
blockpause(void * args)115 static int blockpause(void *args)
116 {
117     ASYNC_block_pause();
118     ASYNC_pause_job();
119     ASYNC_unblock_pause();
120     ASYNC_pause_job();
121 
122     return 1;
123 }
124 
test_ASYNC_init_thread(void)125 static int test_ASYNC_init_thread(void)
126 {
127     ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL;
128     int funcret1, funcret2, funcret3;
129     ASYNC_WAIT_CTX *waitctx = NULL;
130 
131     if (       !ASYNC_init_thread(2, 0)
132             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
133             || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
134                 != ASYNC_PAUSE
135             || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
136                 != ASYNC_PAUSE
137             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
138                 != ASYNC_NO_JOBS
139             || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
140                 != ASYNC_FINISH
141             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
142                 != ASYNC_PAUSE
143             || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
144                 != ASYNC_FINISH
145             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
146                 != ASYNC_FINISH
147             || funcret1 != 1
148             || funcret2 != 1
149             || funcret3 != 1) {
150         fprintf(stderr, "test_ASYNC_init_thread() failed\n");
151         ASYNC_WAIT_CTX_free(waitctx);
152         ASYNC_cleanup_thread();
153         return 0;
154     }
155 
156     ASYNC_WAIT_CTX_free(waitctx);
157     ASYNC_cleanup_thread();
158     return 1;
159 }
160 
test_callback(void * arg)161 static int test_callback(void *arg)
162 {
163     printf("callback test pass\n");
164     return 1;
165 }
166 
test_ASYNC_callback_status(void)167 static int test_ASYNC_callback_status(void)
168 {
169     ASYNC_WAIT_CTX *waitctx = NULL;
170     int set_arg = 100;
171     ASYNC_callback_fn get_callback;
172     void *get_arg;
173     int set_status = 1;
174 
175     if (       !ASYNC_init_thread(1, 0)
176             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
177             || ASYNC_WAIT_CTX_set_callback(waitctx, test_callback, (void*)&set_arg)
178                != 1
179             || ASYNC_WAIT_CTX_get_callback(waitctx, &get_callback, &get_arg)
180                != 1
181             || test_callback != get_callback
182             || get_arg != (void*)&set_arg
183             || (*get_callback)(get_arg) != 1
184             || ASYNC_WAIT_CTX_set_status(waitctx, set_status) != 1
185             || set_status != ASYNC_WAIT_CTX_get_status(waitctx)) {
186         fprintf(stderr, "test_ASYNC_callback_status() failed\n");
187         ASYNC_WAIT_CTX_free(waitctx);
188         ASYNC_cleanup_thread();
189         return 0;
190     }
191 
192     ASYNC_WAIT_CTX_free(waitctx);
193     ASYNC_cleanup_thread();
194     return 1;
195 
196 }
197 
test_ASYNC_start_job(void)198 static int test_ASYNC_start_job(void)
199 {
200     ASYNC_JOB *job = NULL;
201     int funcret;
202     ASYNC_WAIT_CTX *waitctx = NULL;
203 
204     ctr = 0;
205 
206     if (       !ASYNC_init_thread(1, 0)
207             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
208             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
209                != ASYNC_PAUSE
210             || ctr != 1
211             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
212                != ASYNC_FINISH
213             || ctr != 2
214             || funcret != 2) {
215         fprintf(stderr, "test_ASYNC_start_job() failed\n");
216         ASYNC_WAIT_CTX_free(waitctx);
217         ASYNC_cleanup_thread();
218         return 0;
219     }
220 
221     ASYNC_WAIT_CTX_free(waitctx);
222     ASYNC_cleanup_thread();
223     return 1;
224 }
225 
test_ASYNC_get_current_job(void)226 static int test_ASYNC_get_current_job(void)
227 {
228     ASYNC_JOB *job = NULL;
229     int funcret;
230     ASYNC_WAIT_CTX *waitctx = NULL;
231 
232     currjob = NULL;
233 
234     if (       !ASYNC_init_thread(1, 0)
235             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
236             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
237                 != ASYNC_PAUSE
238             || currjob != job
239             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
240                 != ASYNC_FINISH
241             || funcret != 1) {
242         fprintf(stderr, "test_ASYNC_get_current_job() failed\n");
243         ASYNC_WAIT_CTX_free(waitctx);
244         ASYNC_cleanup_thread();
245         return 0;
246     }
247 
248     ASYNC_WAIT_CTX_free(waitctx);
249     ASYNC_cleanup_thread();
250     return 1;
251 }
252 
test_ASYNC_WAIT_CTX_get_all_fds(void)253 static int test_ASYNC_WAIT_CTX_get_all_fds(void)
254 {
255     ASYNC_JOB *job = NULL;
256     int funcret;
257     ASYNC_WAIT_CTX *waitctx = NULL;
258     OSSL_ASYNC_FD fd = OSSL_BAD_ASYNC_FD, delfd = OSSL_BAD_ASYNC_FD;
259     size_t numfds, numdelfds;
260 
261     if (       !ASYNC_init_thread(1, 0)
262             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
263                /* On first run we're not expecting any wait fds */
264             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
265                 != ASYNC_PAUSE
266             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
267             || numfds != 0
268             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
269                                                &numdelfds)
270             || numfds != 0
271             || numdelfds != 0
272                /* On second run we're expecting one added fd */
273             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
274                 != ASYNC_PAUSE
275             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
276             || numfds != 1
277             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, &fd, &numfds)
278             || fd != MAGIC_WAIT_FD
279             || (fd = OSSL_BAD_ASYNC_FD, 0) /* Assign to something else */
280             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
281                                                &numdelfds)
282             || numfds != 1
283             || numdelfds != 0
284             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, &fd, &numfds, NULL,
285                                                &numdelfds)
286             || fd != MAGIC_WAIT_FD
287                /* On third run we expect one deleted fd */
288             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
289                 != ASYNC_PAUSE
290             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
291             || numfds != 0
292             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
293                                                &numdelfds)
294             || numfds != 0
295             || numdelfds != 1
296             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, &delfd,
297                                                &numdelfds)
298             || delfd != MAGIC_WAIT_FD
299             /* On last run we are not expecting any wait fd */
300             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
301                 != ASYNC_FINISH
302             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
303             || numfds != 0
304             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
305                                                &numdelfds)
306             || numfds != 0
307             || numdelfds != 0
308             || funcret != 1) {
309         fprintf(stderr, "test_ASYNC_get_wait_fd() failed\n");
310         ASYNC_WAIT_CTX_free(waitctx);
311         ASYNC_cleanup_thread();
312         return 0;
313     }
314 
315     ASYNC_WAIT_CTX_free(waitctx);
316     ASYNC_cleanup_thread();
317     return 1;
318 }
319 
test_ASYNC_block_pause(void)320 static int test_ASYNC_block_pause(void)
321 {
322     ASYNC_JOB *job = NULL;
323     int funcret;
324     ASYNC_WAIT_CTX *waitctx = NULL;
325 
326     if (       !ASYNC_init_thread(1, 0)
327             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
328             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
329                 != ASYNC_PAUSE
330             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
331                 != ASYNC_FINISH
332             || funcret != 1) {
333         fprintf(stderr, "test_ASYNC_block_pause() failed\n");
334         ASYNC_WAIT_CTX_free(waitctx);
335         ASYNC_cleanup_thread();
336         return 0;
337     }
338 
339     ASYNC_WAIT_CTX_free(waitctx);
340     ASYNC_cleanup_thread();
341     return 1;
342 }
343 
test_ASYNC_start_job_ex(void)344 static int test_ASYNC_start_job_ex(void)
345 {
346     ASYNC_JOB *job = NULL;
347     int funcret;
348     ASYNC_WAIT_CTX *waitctx = NULL;
349     OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
350     OSSL_LIB_CTX *oldctx, *tmpctx, *globalctx;
351     int ret = 0;
352 
353     if (libctx == NULL) {
354         fprintf(stderr,
355                 "test_ASYNC_start_job_ex() failed to create libctx\n");
356         goto err;
357     }
358 
359     globalctx = oldctx = OSSL_LIB_CTX_set0_default(libctx);
360 
361     if ((waitctx = ASYNC_WAIT_CTX_new()) == NULL
362             || ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx,
363                                NULL, 0)
364                != ASYNC_PAUSE) {
365         fprintf(stderr,
366                 "test_ASYNC_start_job_ex() failed to start job\n");
367         goto err;
368     }
369 
370     /* Reset the libctx temporarily to find out what it is*/
371     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
372     oldctx = OSSL_LIB_CTX_set0_default(tmpctx);
373     if (tmpctx != libctx) {
374         fprintf(stderr,
375                 "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
376         goto err;
377     }
378 
379     if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
380                != ASYNC_PAUSE) {
381         fprintf(stderr,
382                 "test_ASYNC_start_job_ex() - restarting job failed\n");
383         goto err;
384     }
385 
386     /* Reset the libctx and continue with the global default libctx */
387     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
388     if (tmpctx != libctx) {
389         fprintf(stderr,
390                 "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
391         goto err;
392     }
393 
394     if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
395                != ASYNC_FINISH
396                 || funcret != 1) {
397         fprintf(stderr,
398                 "test_ASYNC_start_job_ex() - finishing job failed\n");
399         goto err;
400     }
401 
402     /* Reset the libctx temporarily to find out what it is*/
403     tmpctx = OSSL_LIB_CTX_set0_default(libctx);
404     OSSL_LIB_CTX_set0_default(tmpctx);
405     if (tmpctx != globalctx) {
406         fprintf(stderr,
407                 "test_ASYNC_start_job_ex() failed - global libctx check failed\n");
408         goto err;
409     }
410 
411     ret = 1;
412  err:
413     ASYNC_WAIT_CTX_free(waitctx);
414     OSSL_LIB_CTX_free(libctx);
415     return ret;
416 }
417 
test_alloc_stack(size_t * num)418 static void *test_alloc_stack(size_t *num)
419 {
420     custom_alloc_used = 1;
421     return OPENSSL_malloc(*num);
422 }
423 
test_free_stack(void * addr)424 static void test_free_stack(void *addr)
425 {
426     custom_free_used = 1;
427     OPENSSL_free(addr);
428 }
429 
test_ASYNC_set_mem_functions(void)430 static int test_ASYNC_set_mem_functions(void)
431 {
432     ASYNC_stack_alloc_fn alloc_fn;
433     ASYNC_stack_free_fn free_fn;
434 
435     /* Not all platforms support this */
436     if (ASYNC_set_mem_functions(test_alloc_stack, test_free_stack) == 0) 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