New SSL test framework
[openssl.git] / test / asynctest.c
1 /*
2  * Written by Matt Caswell for the OpenSSL project.
3  */
4 /* ====================================================================
5  * Copyright (c) 2015 The OpenSSL Project.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. All advertising materials mentioning features or use of this
20  *    software must display the following acknowledgment:
21  *    "This product includes software developed by the OpenSSL Project
22  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
23  *
24  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25  *    endorse or promote products derived from this software without
26  *    prior written permission. For written permission, please contact
27  *    openssl-core@openssl.org.
28  *
29  * 5. Products derived from this software may not be called "OpenSSL"
30  *    nor may "OpenSSL" appear in their names without prior written
31  *    permission of the OpenSSL Project.
32  *
33  * 6. Redistributions of any form whatsoever must retain the following
34  *    acknowledgment:
35  *    "This product includes software developed by the OpenSSL Project
36  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
37  *
38  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49  * OF THE POSSIBILITY OF SUCH DAMAGE.
50  * ====================================================================
51  *
52  * This product includes cryptographic software written by Eric Young
53  * (eay@cryptsoft.com).  This product includes software written by Tim
54  * Hudson (tjh@cryptsoft.com).
55  *
56  */
57
58 #include <stdio.h>
59 #include <string.h>
60 #include <openssl/async.h>
61 #include <openssl/crypto.h>
62 #include <../apps/apps.h>
63
64 static int ctr = 0;
65 static ASYNC_JOB *currjob = NULL;
66
67 static int only_pause(void *args)
68 {
69     ASYNC_pause_job();
70
71     return 1;
72 }
73
74 static int add_two(void *args)
75 {
76     ctr++;
77     ASYNC_pause_job();
78     ctr++;
79
80     return 2;
81 }
82
83 static int save_current(void *args)
84 {
85     currjob = ASYNC_get_current_job();
86     ASYNC_pause_job();
87
88     return 1;
89 }
90
91 #define MAGIC_WAIT_FD   ((OSSL_ASYNC_FD)99)
92 static int waitfd(void *args)
93 {
94     ASYNC_JOB *job;
95     ASYNC_WAIT_CTX *waitctx;
96     ASYNC_pause_job();
97     job = ASYNC_get_current_job();
98     if (job == NULL)
99         return 0;
100     waitctx = ASYNC_get_wait_ctx(job);
101     if (waitctx == NULL)
102         return 0;
103     if(!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
104         return 0;
105     ASYNC_pause_job();
106
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()
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_ASYNC_start_job()
160 {
161     ASYNC_JOB *job = NULL;
162     int funcret;
163     ASYNC_WAIT_CTX *waitctx = NULL;
164
165     ctr = 0;
166
167     if (       !ASYNC_init_thread(1, 0)
168             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
169             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
170                != ASYNC_PAUSE
171             || ctr != 1
172             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
173                != ASYNC_FINISH
174             || ctr != 2
175             || funcret != 2) {
176         fprintf(stderr, "test_ASYNC_start_job() failed\n");
177         ASYNC_WAIT_CTX_free(waitctx);
178         ASYNC_cleanup_thread();
179         return 0;
180     }
181
182     ASYNC_WAIT_CTX_free(waitctx);
183     ASYNC_cleanup_thread();
184     return 1;
185 }
186
187 static int test_ASYNC_get_current_job()
188 {
189     ASYNC_JOB *job = NULL;
190     int funcret;
191     ASYNC_WAIT_CTX *waitctx = NULL;
192
193     currjob = NULL;
194
195     if (       !ASYNC_init_thread(1, 0)
196             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
197             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
198                 != ASYNC_PAUSE
199             || currjob != job
200             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
201                 != ASYNC_FINISH
202             || funcret != 1) {
203         fprintf(stderr, "test_ASYNC_get_current_job() failed\n");
204         ASYNC_WAIT_CTX_free(waitctx);
205         ASYNC_cleanup_thread();
206         return 0;
207     }
208
209     ASYNC_WAIT_CTX_free(waitctx);
210     ASYNC_cleanup_thread();
211     return 1;
212 }
213
214 static int test_ASYNC_WAIT_CTX_get_all_fds()
215 {
216     ASYNC_JOB *job = NULL;
217     int funcret;
218     ASYNC_WAIT_CTX *waitctx = NULL;
219     OSSL_ASYNC_FD fd = OSSL_BAD_ASYNC_FD, delfd = OSSL_BAD_ASYNC_FD;
220     size_t numfds, numdelfds;
221
222     if (       !ASYNC_init_thread(1, 0)
223             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
224                /* On first run we're not expecting any wait fds */
225             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
226                 != ASYNC_PAUSE
227             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
228             || numfds != 0
229             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
230                                                &numdelfds)
231             || numfds != 0
232             || numdelfds != 0
233                /* On second run we're expecting one added fd */
234             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
235                 != ASYNC_PAUSE
236             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
237             || numfds != 1
238             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, &fd, &numfds)
239             || fd != MAGIC_WAIT_FD
240             || (fd = OSSL_BAD_ASYNC_FD, 0) /* Assign to something else */
241             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
242                                               &numdelfds)
243             || numfds != 1
244             || numdelfds != 0
245             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, &fd, &numfds, NULL,
246                                                &numdelfds)
247             || fd != MAGIC_WAIT_FD
248                /* On final run we expect one deleted fd */
249             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
250                 != ASYNC_FINISH
251             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
252             || numfds != 0
253             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
254                                                &numdelfds)
255             || numfds != 0
256             || numdelfds != 1
257             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, &delfd,
258                                                &numdelfds)
259             || delfd != MAGIC_WAIT_FD
260             || funcret != 1) {
261         fprintf(stderr, "test_ASYNC_get_wait_fd() 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
272 static int test_ASYNC_block_pause()
273 {
274     ASYNC_JOB *job = NULL;
275     int funcret;
276     ASYNC_WAIT_CTX *waitctx = NULL;
277
278     if (       !ASYNC_init_thread(1, 0)
279             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
280             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
281                 != ASYNC_PAUSE
282             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
283                 != ASYNC_FINISH
284             || funcret != 1) {
285         fprintf(stderr, "test_ASYNC_block_pause() failed\n");
286         ASYNC_WAIT_CTX_free(waitctx);
287         ASYNC_cleanup_thread();
288         return 0;
289     }
290
291     ASYNC_WAIT_CTX_free(waitctx);
292     ASYNC_cleanup_thread();
293     return 1;
294 }
295
296 int main(int argc, char **argv)
297 {
298     if (!ASYNC_is_capable()) {
299         fprintf(stderr,
300                 "OpenSSL build is not ASYNC capable - skipping async tests\n");
301     } else {
302         CRYPTO_set_mem_debug(1);
303         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
304
305         if (       !test_ASYNC_init_thread()
306                 || !test_ASYNC_start_job()
307                 || !test_ASYNC_get_current_job()
308                 || !test_ASYNC_WAIT_CTX_get_all_fds()
309                 || !test_ASYNC_block_pause()) {
310             return 1;
311         }
312     }
313     printf("PASS\n");
314     return 0;
315 }