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