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
19 static int ctr = 0;
20 static ASYNC_JOB *currjob = NULL;
21
only_pause(void * args)22 static int only_pause(void *args)
23 {
24 ASYNC_pause_job();
25
26 return 1;
27 }
28
add_two(void * args)29 static int add_two(void *args)
30 {
31 ctr++;
32 ASYNC_pause_job();
33 ctr++;
34
35 return 2;
36 }
37
save_current(void * args)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 #define MAGIC_WAIT_FD ((OSSL_ASYNC_FD)99)
waitfd(void * args)47 static 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
blockpause(void * args)80 static 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
test_ASYNC_init_thread(void)90 static 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
test_ASYNC_start_job(void)126 static 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
test_ASYNC_get_current_job(void)154 static 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
test_ASYNC_WAIT_CTX_get_all_fds(void)181 static 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
test_ASYNC_block_pause(void)248 static 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
main(int argc,char ** argv)272 int 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