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 22 static int only_pause(void *args) 23 { 24 ASYNC_pause_job(); 25 26 return 1; 27 } 28 29 static int add_two(void *args) 30 { 31 ctr++; 32 ASYNC_pause_job(); 33 ctr++; 34 35 return 2; 36 } 37 38 static int save_current(void *args) 39 { 40 currjob = ASYNC_get_current_job(); 41 ASYNC_pause_job(); 42 43 return 1; 44 } 45 46 static int change_deflt_libctx(void *args) 47 { 48 OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new(); 49 OSSL_LIB_CTX *oldctx, *tmpctx; 50 int ret = 0; 51 52 if (libctx == NULL) 53 return 0; 54 55 oldctx = OSSL_LIB_CTX_set0_default(libctx); 56 ASYNC_pause_job(); 57 58 /* Check the libctx is set up as we expect */ 59 tmpctx = OSSL_LIB_CTX_set0_default(oldctx); 60 if (tmpctx != libctx) 61 goto err; 62 63 /* Set it back again to continue to use our own libctx */ 64 oldctx = OSSL_LIB_CTX_set0_default(libctx); 65 ASYNC_pause_job(); 66 67 /* Check the libctx is set up as we expect */ 68 tmpctx = OSSL_LIB_CTX_set0_default(oldctx); 69 if (tmpctx != libctx) 70 goto err; 71 72 ret = 1; 73 err: 74 OSSL_LIB_CTX_free(libctx); 75 return ret; 76 } 77 78 79 #define MAGIC_WAIT_FD ((OSSL_ASYNC_FD)99) 80 static int waitfd(void *args) 81 { 82 ASYNC_JOB *job; 83 ASYNC_WAIT_CTX *waitctx; 84 job = ASYNC_get_current_job(); 85 if (job == NULL) 86 return 0; 87 waitctx = ASYNC_get_wait_ctx(job); 88 if (waitctx == NULL) 89 return 0; 90 91 /* First case: no fd added or removed */ 92 ASYNC_pause_job(); 93 94 /* Second case: one fd added */ 95 if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL)) 96 return 0; 97 ASYNC_pause_job(); 98 99 /* Third case: all fd removed */ 100 if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx)) 101 return 0; 102 ASYNC_pause_job(); 103 104 /* Last case: fd added and immediately removed */ 105 if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL)) 106 return 0; 107 if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx)) 108 return 0; 109 110 return 1; 111 } 112 113 static int blockpause(void *args) 114 { 115 ASYNC_block_pause(); 116 ASYNC_pause_job(); 117 ASYNC_unblock_pause(); 118 ASYNC_pause_job(); 119 120 return 1; 121 } 122 123 static int test_ASYNC_init_thread(void) 124 { 125 ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL; 126 int funcret1, funcret2, funcret3; 127 ASYNC_WAIT_CTX *waitctx = NULL; 128 129 if ( !ASYNC_init_thread(2, 0) 130 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL 131 || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0) 132 != ASYNC_PAUSE 133 || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0) 134 != ASYNC_PAUSE 135 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0) 136 != ASYNC_NO_JOBS 137 || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0) 138 != ASYNC_FINISH 139 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0) 140 != ASYNC_PAUSE 141 || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0) 142 != ASYNC_FINISH 143 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0) 144 != ASYNC_FINISH 145 || funcret1 != 1 146 || funcret2 != 1 147 || funcret3 != 1) { 148 fprintf(stderr, "test_ASYNC_init_thread() failed\n"); 149 ASYNC_WAIT_CTX_free(waitctx); 150 ASYNC_cleanup_thread(); 151 return 0; 152 } 153 154 ASYNC_WAIT_CTX_free(waitctx); 155 ASYNC_cleanup_thread(); 156 return 1; 157 } 158 159 static int test_callback(void *arg) 160 { 161 printf("callback test pass\n"); 162 return 1; 163 } 164 165 static int test_ASYNC_callback_status(void) 166 { 167 ASYNC_WAIT_CTX *waitctx = NULL; 168 int set_arg = 100; 169 ASYNC_callback_fn get_callback; 170 void *get_arg; 171 int set_status = 1; 172 173 if ( !ASYNC_init_thread(1, 0) 174 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL 175 || ASYNC_WAIT_CTX_set_callback(waitctx, test_callback, (void*)&set_arg) 176 != 1 177 || ASYNC_WAIT_CTX_get_callback(waitctx, &get_callback, &get_arg) 178 != 1 179 || test_callback != get_callback 180 || get_arg != (void*)&set_arg 181 || (*get_callback)(get_arg) != 1 182 || ASYNC_WAIT_CTX_set_status(waitctx, set_status) != 1 183 || set_status != ASYNC_WAIT_CTX_get_status(waitctx)) { 184 fprintf(stderr, "test_ASYNC_callback_status() failed\n"); 185 ASYNC_WAIT_CTX_free(waitctx); 186 ASYNC_cleanup_thread(); 187 return 0; 188 } 189 190 ASYNC_WAIT_CTX_free(waitctx); 191 ASYNC_cleanup_thread(); 192 return 1; 193 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 int main(int argc, char **argv) 418 { 419 if (!ASYNC_is_capable()) { 420 fprintf(stderr, 421 "OpenSSL build is not ASYNC capable - skipping async tests\n"); 422 } else { 423 if (!test_ASYNC_init_thread() 424 || !test_ASYNC_callback_status() 425 || !test_ASYNC_start_job() 426 || !test_ASYNC_get_current_job() 427 || !test_ASYNC_WAIT_CTX_get_all_fds() 428 || !test_ASYNC_block_pause() 429 || !test_ASYNC_start_job_ex()) { 430 return 1; 431 } 432 } 433 printf("PASS\n"); 434 return 0; 435 } 436