Home | History | Annotate | Line # | Download | only in test
      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 
     24 static int only_pause(void *args)
     25 {
     26     ASYNC_pause_job();
     27 
     28     return 1;
     29 }
     30 
     31 static int add_two(void *args)
     32 {
     33     ctr++;
     34     ASYNC_pause_job();
     35     ctr++;
     36 
     37     return 2;
     38 }
     39 
     40 static int save_current(void *args)
     41 {
     42     currjob = ASYNC_get_current_job();
     43     ASYNC_pause_job();
     44 
     45     return 1;
     46 }
     47 
     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)
     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 
    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 
    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 
    160 static int test_callback(void *arg)
    161 {
    162     printf("callback test pass\n");
    163     return 1;
    164 }
    165 
    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 
    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 
    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 
    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 
    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 
    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 
    417 static void *test_alloc_stack(size_t *num)
    418 {
    419     custom_alloc_used = 1;
    420     return OPENSSL_malloc(*num);
    421 }
    422 
    423 static void test_free_stack(void *addr)
    424 {
    425     custom_free_used = 1;
    426     OPENSSL_free(addr);
    427 }
    428 
    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 
    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