1/* 2 * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (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 19static int ctr = 0; 20static ASYNC_JOB *currjob = NULL; 21 22static int only_pause(void *args) 23{ 24 ASYNC_pause_job(); 25 26 return 1; 27} 28 29static int add_two(void *args) 30{ 31 ctr++; 32 ASYNC_pause_job(); 33 ctr++; 34 35 return 2; 36} 37 38static int save_current(void *args) 39{ 40 currjob = ASYNC_get_current_job(); 41 ASYNC_pause_job(); 42 43 return 1; 44} 45 46#define MAGIC_WAIT_FD ((OSSL_ASYNC_FD)99) 47static int waitfd(void *args) 48{ 49 ASYNC_JOB *job; 50 ASYNC_WAIT_CTX *waitctx; 51 job = ASYNC_get_current_job(); 52 if (job == NULL) 53 return 0; 54 waitctx = ASYNC_get_wait_ctx(job); 55 if (waitctx == NULL) 56 return 0; 57 58 /* First case: no fd added or removed */ 59 ASYNC_pause_job(); 60 61 /* Second case: one fd added */ 62 if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL)) 63 return 0; 64 ASYNC_pause_job(); 65 66 /* Third case: all fd removed */ 67 if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx)) 68 return 0; 69 ASYNC_pause_job(); 70 71 /* Last case: fd added and immediately removed */ 72 if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL)) 73 return 0; 74 if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx)) 75 return 0; 76 77 return 1; 78} 79 80static int blockpause(void *args) 81{ 82 ASYNC_block_pause(); 83 ASYNC_pause_job(); 84 ASYNC_unblock_pause(); 85 ASYNC_pause_job(); 86 87 return 1; 88} 89 90static int test_ASYNC_init_thread(void) 91{ 92 ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL; 93 int funcret1, funcret2, funcret3; 94 ASYNC_WAIT_CTX *waitctx = NULL; 95 96 if ( !ASYNC_init_thread(2, 0) 97 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL 98 || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0) 99 != ASYNC_PAUSE 100 || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0) 101 != ASYNC_PAUSE 102 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0) 103 != ASYNC_NO_JOBS 104 || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0) 105 != ASYNC_FINISH 106 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0) 107 != ASYNC_PAUSE 108 || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0) 109 != ASYNC_FINISH 110 || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0) 111 != ASYNC_FINISH 112 || funcret1 != 1 113 || funcret2 != 1 114 || funcret3 != 1) { 115 fprintf(stderr, "test_ASYNC_init_thread() failed\n"); 116 ASYNC_WAIT_CTX_free(waitctx); 117 ASYNC_cleanup_thread(); 118 return 0; 119 } 120 121 ASYNC_WAIT_CTX_free(waitctx); 122 ASYNC_cleanup_thread(); 123 return 1; 124} 125 126static int test_ASYNC_start_job(void) 127{ 128 ASYNC_JOB *job = NULL; 129 int funcret; 130 ASYNC_WAIT_CTX *waitctx = NULL; 131 132 ctr = 0; 133 134 if ( !ASYNC_init_thread(1, 0) 135 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL 136 || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0) 137 != ASYNC_PAUSE 138 || ctr != 1 139 || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0) 140 != ASYNC_FINISH 141 || ctr != 2 142 || funcret != 2) { 143 fprintf(stderr, "test_ASYNC_start_job() failed\n"); 144 ASYNC_WAIT_CTX_free(waitctx); 145 ASYNC_cleanup_thread(); 146 return 0; 147 } 148 149 ASYNC_WAIT_CTX_free(waitctx); 150 ASYNC_cleanup_thread(); 151 return 1; 152} 153 154static int test_ASYNC_get_current_job(void) 155{ 156 ASYNC_JOB *job = NULL; 157 int funcret; 158 ASYNC_WAIT_CTX *waitctx = NULL; 159 160 currjob = NULL; 161 162 if ( !ASYNC_init_thread(1, 0) 163 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL 164 || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0) 165 != ASYNC_PAUSE 166 || currjob != job 167 || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0) 168 != ASYNC_FINISH 169 || funcret != 1) { 170 fprintf(stderr, "test_ASYNC_get_current_job() failed\n"); 171 ASYNC_WAIT_CTX_free(waitctx); 172 ASYNC_cleanup_thread(); 173 return 0; 174 } 175 176 ASYNC_WAIT_CTX_free(waitctx); 177 ASYNC_cleanup_thread(); 178 return 1; 179} 180 181static int test_ASYNC_WAIT_CTX_get_all_fds(void) 182{ 183 ASYNC_JOB *job = NULL; 184 int funcret; 185 ASYNC_WAIT_CTX *waitctx = NULL; 186 OSSL_ASYNC_FD fd = OSSL_BAD_ASYNC_FD, delfd = OSSL_BAD_ASYNC_FD; 187 size_t numfds, numdelfds; 188 189 if ( !ASYNC_init_thread(1, 0) 190 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL 191 /* On first run we're not expecting any wait fds */ 192 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0) 193 != ASYNC_PAUSE 194 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds) 195 || numfds != 0 196 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL, 197 &numdelfds) 198 || numfds != 0 199 || numdelfds != 0 200 /* On second run we're expecting one added fd */ 201 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0) 202 != ASYNC_PAUSE 203 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds) 204 || numfds != 1 205 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, &fd, &numfds) 206 || fd != MAGIC_WAIT_FD 207 || (fd = OSSL_BAD_ASYNC_FD, 0) /* Assign to something else */ 208 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL, 209 &numdelfds) 210 || numfds != 1 211 || numdelfds != 0 212 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, &fd, &numfds, NULL, 213 &numdelfds) 214 || fd != MAGIC_WAIT_FD 215 /* On third run we expect one deleted fd */ 216 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0) 217 != ASYNC_PAUSE 218 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds) 219 || numfds != 0 220 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL, 221 &numdelfds) 222 || numfds != 0 223 || numdelfds != 1 224 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, &delfd, 225 &numdelfds) 226 || delfd != MAGIC_WAIT_FD 227 /* On last run we are not expecting any wait fd */ 228 || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0) 229 != ASYNC_FINISH 230 || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds) 231 || numfds != 0 232 || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL, 233 &numdelfds) 234 || numfds != 0 235 || numdelfds != 0 236 || funcret != 1) { 237 fprintf(stderr, "test_ASYNC_get_wait_fd() failed\n"); 238 ASYNC_WAIT_CTX_free(waitctx); 239 ASYNC_cleanup_thread(); 240 return 0; 241 } 242 243 ASYNC_WAIT_CTX_free(waitctx); 244 ASYNC_cleanup_thread(); 245 return 1; 246} 247 248static int test_ASYNC_block_pause(void) 249{ 250 ASYNC_JOB *job = NULL; 251 int funcret; 252 ASYNC_WAIT_CTX *waitctx = NULL; 253 254 if ( !ASYNC_init_thread(1, 0) 255 || (waitctx = ASYNC_WAIT_CTX_new()) == NULL 256 || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0) 257 != ASYNC_PAUSE 258 || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0) 259 != ASYNC_FINISH 260 || funcret != 1) { 261 fprintf(stderr, "test_ASYNC_block_pause() failed\n"); 262 ASYNC_WAIT_CTX_free(waitctx); 263 ASYNC_cleanup_thread(); 264 return 0; 265 } 266 267 ASYNC_WAIT_CTX_free(waitctx); 268 ASYNC_cleanup_thread(); 269 return 1; 270} 271 272int main(int argc, char **argv) 273{ 274 if (!ASYNC_is_capable()) { 275 fprintf(stderr, 276 "OpenSSL build is not ASYNC capable - skipping async tests\n"); 277 } else { 278 CRYPTO_set_mem_debug(1); 279 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); 280 281 if ( !test_ASYNC_init_thread() 282 || !test_ASYNC_start_job() 283 || !test_ASYNC_get_current_job() 284 || !test_ASYNC_WAIT_CTX_get_all_fds() 285 || !test_ASYNC_block_pause()) { 286 return 1; 287 } 288 } 289 printf("PASS\n"); 290 return 0; 291} 292