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 81 #define MAGIC_WAIT_FD ((OSSL_ASYNC_FD)99) 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 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 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 161 static int test_callback(void *arg) 162 { 163 printf("callback test pass\n"); 164 return 1; 165 } 166 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 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 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 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 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 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 ASYNC_cleanup_thread(); 415 OSSL_LIB_CTX_free(libctx); 416 return ret; 417 } 418 419 static void *test_alloc_stack(size_t *num) 420 { 421 custom_alloc_used = 1; 422 return OPENSSL_malloc(*num); 423 } 424 425 static void test_free_stack(void *addr) 426 { 427 custom_free_used = 1; 428 OPENSSL_free(addr); 429 } 430 431 static int test_ASYNC_set_mem_functions(void) 432 { 433 ASYNC_stack_alloc_fn alloc_fn; 434 ASYNC_stack_free_fn free_fn; 435 436 /* Not all platforms support this */ 437 if (ASYNC_set_mem_functions(test_alloc_stack, test_free_stack) == 0) return 1; 438 439 ASYNC_get_mem_functions(&alloc_fn, &free_fn); 440 441 if ((alloc_fn != test_alloc_stack) || (free_fn != test_free_stack)) { 442 fprintf(stderr, 443 "test_ASYNC_set_mem_functions() - setting and retrieving custom allocators failed\n"); 444 return 0; 445 } 446 447 if (!ASYNC_init_thread(1, 1)) { 448 fprintf(stderr, 449 "test_ASYNC_set_mem_functions() - failed initialising ctx pool\n"); 450 return 0; 451 } 452 ASYNC_cleanup_thread(); 453 454 if (!custom_alloc_used || !custom_free_used) { 455 fprintf(stderr, 456 "test_ASYNC_set_mem_functions() - custom allocation functions not used\n"); 457 458 return 0; 459 } 460 461 return 1; 462 } 463 464 int main(int argc, char **argv) 465 { 466 if (!ASYNC_is_capable()) { 467 fprintf(stderr, 468 "OpenSSL build is not ASYNC capable - skipping async tests\n"); 469 } else { 470 if (!test_ASYNC_init_thread() 471 || !test_ASYNC_callback_status() 472 || !test_ASYNC_start_job() 473 || !test_ASYNC_get_current_job() 474 || !test_ASYNC_WAIT_CTX_get_all_fds() 475 || !test_ASYNC_block_pause() 476 || !test_ASYNC_start_job_ex() 477 || !test_ASYNC_set_mem_functions()) { 478 return 1; 479 } 480 } 481 printf("PASS\n"); 482 return 0; 483 } 484