Auto init/deinit libcrypto
[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 #if (defined(OPENSSL_SYS_UNIX) || defined(OPENSSL_SYS_CYGWIN)) && defined(OPENSSL_THREADS)
65 # include <unistd.h>
66 # if _POSIX_VERSION >= 200112L
67 #  define ASYNC_POSIX
68 # endif
69 #elif defined(_WIN32)
70 # define ASYNC_WIN
71 #endif
72
73 #if !defined(ASYNC_POSIX) && !defined(ASYNC_WIN)
74 # define ASYNC_NULL
75 #endif
76
77 #ifndef ASYNC_NULL
78
79 static int ctr = 0;
80 static ASYNC_JOB *currjob = NULL;
81
82 static int only_pause(void *args)
83 {
84     ASYNC_pause_job();
85
86     return 1;
87 }
88
89 static int add_two(void *args)
90 {
91     ctr++;
92     ASYNC_pause_job();
93     ctr++;
94
95     return 2;
96 }
97
98 static int save_current(void *args)
99 {
100     currjob = ASYNC_get_current_job();
101     ASYNC_pause_job();
102
103     return 1;
104 }
105
106 static int wake(void *args)
107 {
108     ASYNC_pause_job();
109     ASYNC_wake(ASYNC_get_current_job());
110     ASYNC_pause_job();
111     ASYNC_clear_wake(ASYNC_get_current_job());
112
113     return 1;
114 }
115
116 static int blockpause(void *args)
117 {
118     ASYNC_block_pause();
119     ASYNC_pause_job();
120     ASYNC_unblock_pause();
121     ASYNC_pause_job();
122
123     return 1;
124 }
125
126 static int test_ASYNC_init_thread()
127 {
128     ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL;
129     int funcret1, funcret2, funcret3;
130
131     if (       !ASYNC_init_thread(2, 0)
132             || ASYNC_start_job(&job1, &funcret1, only_pause, NULL, 0)
133                 != ASYNC_PAUSE
134             || ASYNC_start_job(&job2, &funcret2, only_pause, NULL, 0)
135                 != ASYNC_PAUSE
136             || ASYNC_start_job(&job3, &funcret3, only_pause, NULL, 0)
137                 != ASYNC_NO_JOBS
138             || ASYNC_start_job(&job1, &funcret1, only_pause, NULL, 0)
139                 != ASYNC_FINISH
140             || ASYNC_start_job(&job3, &funcret3, only_pause, NULL, 0)
141                 != ASYNC_PAUSE
142             || ASYNC_start_job(&job2, &funcret2, only_pause, NULL, 0)
143                 != ASYNC_FINISH
144             || ASYNC_start_job(&job3, &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_cleanup_thread();
151         return 0;
152     }
153
154     ASYNC_cleanup_thread();
155     return 1;
156 }
157
158 static int test_ASYNC_start_job()
159 {
160     ASYNC_JOB *job = NULL;
161     int funcret;
162
163     ctr = 0;
164
165     if (       !ASYNC_init_thread(1, 0)
166             || ASYNC_start_job(&job, &funcret, add_two, NULL, 0) != ASYNC_PAUSE
167             || ctr != 1
168             || ASYNC_start_job(&job, &funcret, add_two, NULL, 0) != ASYNC_FINISH
169             || ctr != 2
170             || funcret != 2) {
171         fprintf(stderr, "test_ASYNC_start_job() failed\n");
172         ASYNC_cleanup_thread();
173         return 0;
174     }
175
176     ASYNC_cleanup_thread();
177     return 1;
178 }
179
180 static int test_ASYNC_get_current_job()
181 {
182     ASYNC_JOB *job = NULL;
183     int funcret;
184
185     currjob = NULL;
186
187     if (       !ASYNC_init_thread(1, 0)
188             || ASYNC_start_job(&job, &funcret, save_current, NULL, 0)
189                 != ASYNC_PAUSE
190             || currjob != job
191             || ASYNC_start_job(&job, &funcret, save_current, NULL, 0)
192                 != ASYNC_FINISH
193             || funcret != 1) {
194         fprintf(stderr, "test_ASYNC_get_current_job() failed\n");
195         ASYNC_cleanup_thread();
196         return 0;
197     }
198
199     ASYNC_cleanup_thread();
200     return 1;
201 }
202
203 static int hasdata(OSSL_ASYNC_FD fd)
204 {
205 #ifdef ASYNC_POSIX
206     fd_set checkfds;
207     struct timeval tv;
208     FD_ZERO(&checkfds);
209     openssl_fdset(fd, &checkfds);
210     memset(&tv, 0, sizeof tv);
211     if (select(fd + 1, (void *)&checkfds, NULL, NULL, &tv) < 0)
212         return -1;
213     if (FD_ISSET(fd, &checkfds))
214         return 1;
215     return 0;
216 #else
217     DWORD avail = 0;
218
219     if (PeekNamedPipe(fd, NULL, 0, NULL, &avail, NULL) && avail > 0)
220         return 1;
221
222     return 0;
223 #endif
224 }
225
226 static int test_ASYNC_get_wait_fd()
227 {
228     ASYNC_JOB *job = NULL;
229     int funcret;
230     OSSL_ASYNC_FD fd;
231
232     if (       !ASYNC_init_thread(1, 0)
233             || ASYNC_start_job(&job, &funcret, wake, NULL, 0)
234                 != ASYNC_PAUSE
235             || (fd = ASYNC_get_wait_fd(job)) < 0
236             || hasdata(fd) != 0
237             || ASYNC_start_job(&job, &funcret, save_current, NULL, 0)
238                 != ASYNC_PAUSE
239             || hasdata(fd) != 1
240             || (ASYNC_clear_wake(job), 0)
241             || hasdata(fd) != 0
242             || (ASYNC_wake(job), 0)
243             || hasdata(fd) != 1
244             || ASYNC_start_job(&job, &funcret, save_current, NULL, 0)
245                 != ASYNC_FINISH
246             || funcret != 1) {
247         fprintf(stderr, "test_ASYNC_get_wait_fd() failed\n");
248         ASYNC_cleanup_thread();
249         return 0;
250     }
251
252     ASYNC_cleanup_thread();
253     return 1;
254 }
255
256 static int test_ASYNC_block_pause()
257 {
258     ASYNC_JOB *job = NULL;
259     int funcret;
260
261     if (       !ASYNC_init_thread(1, 0)
262             || ASYNC_start_job(&job, &funcret, blockpause, NULL, 0)
263                 != ASYNC_PAUSE
264             || ASYNC_start_job(&job, &funcret, blockpause, NULL, 0)
265                 != ASYNC_FINISH
266             || funcret != 1) {
267         fprintf(stderr, "test_ASYNC_block_pause() failed\n");
268         ASYNC_cleanup_thread();
269         return 0;
270     }
271
272     ASYNC_cleanup_thread();
273     return 1;
274 }
275
276 #endif
277
278 int main(int argc, char **argv)
279 {
280
281 #ifdef ASYNC_NULL
282     fprintf(stderr, "NULL implementation - skipping async tests\n");
283 #else
284     CRYPTO_set_mem_debug(1);
285     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
286
287     if (       !test_ASYNC_init_thread()
288             || !test_ASYNC_start_job()
289             || !test_ASYNC_get_current_job()
290             || !test_ASYNC_get_wait_fd()
291             || !test_ASYNC_block_pause()) {
292         return 1;
293     }
294 #endif
295     printf("PASS\n");
296     return 0;
297 }