QUIC Thread Assisted Mode: Support Windows XP
[openssl.git] / test / quic_tserver_test.c
1 /*
2  * Copyright 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 #include <openssl/ssl.h>
10 #include <openssl/quic.h>
11 #include <openssl/bio.h>
12 #include "internal/common.h"
13 #include "internal/sockets.h"
14 #include "internal/quic_tserver.h"
15 #include "internal/quic_ssl.h"
16 #include "internal/time.h"
17 #include "testutil.h"
18
19 static const char msg1[] = "The quick brown fox jumped over the lazy dogs.";
20 static char msg2[1024], msg3[1024];
21 static OSSL_TIME fake_time;
22 static CRYPTO_RWLOCK *fake_time_lock;
23
24 static const char *certfile, *keyfile;
25
26 static int is_want(SSL *s, int ret)
27 {
28     int ec = SSL_get_error(s, ret);
29
30     return ec == SSL_ERROR_WANT_READ || ec == SSL_ERROR_WANT_WRITE;
31 }
32
33 static unsigned char scratch_buf[2048];
34
35 static OSSL_TIME fake_now(void *arg)
36 {
37     OSSL_TIME t;
38
39     if (!CRYPTO_THREAD_read_lock(fake_time_lock))
40         return ossl_time_zero();
41
42     t = fake_time;
43
44     CRYPTO_THREAD_unlock(fake_time_lock);
45     return t;
46 }
47
48 static OSSL_TIME real_now(void *arg)
49 {
50     return ossl_time_now();
51 }
52
53 static int do_test(int use_thread_assist, int use_fake_time, int use_inject)
54 {
55     int testresult = 0, ret;
56     int s_fd = -1, c_fd = -1;
57     BIO *s_net_bio = NULL, *s_net_bio_own = NULL;
58     BIO *c_net_bio = NULL, *c_net_bio_own = NULL;
59     BIO *c_pair_own = NULL, *s_pair_own = NULL;
60     QUIC_TSERVER_ARGS tserver_args = {0};
61     QUIC_TSERVER *tserver = NULL;
62     BIO_ADDR *s_addr_ = NULL;
63     struct in_addr ina = {0};
64     union BIO_sock_info_u s_info = {0};
65     SSL_CTX *c_ctx = NULL;
66     SSL *c_ssl = NULL;
67     short port = 8186;
68     int c_connected = 0, c_write_done = 0, c_begin_read = 0, s_read_done = 0;
69     int c_wait_eos = 0, c_done_eos = 0;
70     int c_start_idle_test = 0, c_done_idle_test = 0;
71     size_t l = 0, s_total_read = 0, s_total_written = 0, c_total_read = 0;
72     size_t idle_units_done = 0;
73     int s_begin_write = 0;
74     OSSL_TIME start_time;
75     unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' };
76     OSSL_TIME (*now_cb)(void *arg) = use_fake_time ? fake_now : real_now;
77     size_t limit_ms = 1000;
78
79     ina.s_addr = htonl(0x7f000001UL);
80
81     /* Setup test server. */
82     s_fd = BIO_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0);
83     if (!TEST_int_ge(s_fd, 0))
84         goto err;
85
86     if (!TEST_true(BIO_socket_nbio(s_fd, 1)))
87         goto err;
88
89     if (!TEST_ptr(s_addr_ = BIO_ADDR_new()))
90         goto err;
91
92     if (!TEST_true(BIO_ADDR_rawmake(s_addr_, AF_INET, &ina, sizeof(ina),
93                                     htons(port))))
94         goto err;
95
96     if (!TEST_true(BIO_bind(s_fd, s_addr_, 0)))
97         goto err;
98
99     s_info.addr = s_addr_;
100     if (!TEST_true(BIO_sock_info(s_fd, BIO_SOCK_INFO_ADDRESS, &s_info)))
101         goto err;
102
103     if (!TEST_int_gt(BIO_ADDR_rawport(s_addr_), 0))
104         goto err;
105
106     if (!TEST_ptr(s_net_bio = s_net_bio_own = BIO_new_dgram(s_fd, 0)))
107         goto err;
108
109     if (!BIO_up_ref(s_net_bio))
110         goto err;
111
112     fake_time = ossl_ms2time(1000);
113
114     tserver_args.net_rbio = s_net_bio;
115     tserver_args.net_wbio = s_net_bio;
116     if (use_fake_time)
117         tserver_args.now_cb = fake_now;
118
119     if (!TEST_ptr(tserver = ossl_quic_tserver_new(&tserver_args, certfile,
120                                                   keyfile))) {
121         BIO_free(s_net_bio);
122         goto err;
123     }
124
125     s_net_bio_own = NULL;
126
127     if (use_inject) {
128         /*
129          * In inject mode we create a dgram pair to feed to the QUIC client on
130          * the read side. We don't feed anything to this, it is just a
131          * placeholder to give the client something which never returns any
132          * datagrams.
133          */
134         if (!TEST_true(BIO_new_bio_dgram_pair(&c_pair_own, 5000,
135                                               &s_pair_own, 5000)))
136             goto err;
137     }
138
139     /* Setup test client. */
140     c_fd = BIO_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0);
141     if (!TEST_int_ge(c_fd, 0))
142         goto err;
143
144     if (!TEST_true(BIO_socket_nbio(c_fd, 1)))
145         goto err;
146
147     if (!TEST_ptr(c_net_bio = c_net_bio_own = BIO_new_dgram(c_fd, 0)))
148         goto err;
149
150     if (!BIO_dgram_set_peer(c_net_bio, s_addr_))
151         goto err;
152
153     if (!TEST_ptr(c_ctx = SSL_CTX_new(use_thread_assist
154                                       ? OSSL_QUIC_client_thread_method()
155                                       : OSSL_QUIC_client_method())))
156         goto err;
157
158     if (!TEST_ptr(c_ssl = SSL_new(c_ctx)))
159         goto err;
160
161     if (use_fake_time)
162         ossl_quic_conn_set_override_now_cb(c_ssl, fake_now, NULL);
163
164     /* 0 is a success for SSL_set_alpn_protos() */
165     if (!TEST_false(SSL_set_alpn_protos(c_ssl, alpn, sizeof(alpn))))
166         goto err;
167
168     /* Takes ownership of our reference to the BIO. */
169     if (use_inject) {
170         SSL_set0_rbio(c_ssl, c_pair_own);
171         c_pair_own = NULL;
172     } else {
173         SSL_set0_rbio(c_ssl, c_net_bio);
174
175         /* Get another reference to be transferred in the SSL_set0_wbio call. */
176         if (!TEST_true(BIO_up_ref(c_net_bio))) {
177             c_net_bio_own = NULL; /* SSL_free will free the first reference. */
178             goto err;
179         }
180     }
181
182     SSL_set0_wbio(c_ssl, c_net_bio);
183     c_net_bio_own = NULL;
184
185     if (!TEST_true(SSL_set_blocking_mode(c_ssl, 0)))
186         goto err;
187
188     start_time = now_cb(NULL);
189
190     for (;;) {
191         if (ossl_time_compare(ossl_time_subtract(now_cb(NULL), start_time),
192                               ossl_ms2time(limit_ms)) >= 0) {
193             TEST_error("timeout while attempting QUIC server test");
194             goto err;
195         }
196
197         if (!c_start_idle_test) {
198             ret = SSL_connect(c_ssl);
199             if (!TEST_true(ret == 1 || is_want(c_ssl, ret)))
200                 goto err;
201
202             if (ret == 1)
203                 c_connected = 1;
204         }
205
206         if (c_connected && !c_write_done) {
207             if (!TEST_int_eq(SSL_write(c_ssl, msg1, sizeof(msg1) - 1),
208                              (int)sizeof(msg1) - 1))
209                 goto err;
210
211             if (!TEST_true(SSL_stream_conclude(c_ssl, 0)))
212                 goto err;
213
214             c_write_done = 1;
215         }
216
217         if (c_connected && c_write_done && !s_read_done) {
218             if (!ossl_quic_tserver_read(tserver,
219                                         (unsigned char *)msg2 + s_total_read,
220                                         sizeof(msg2) - s_total_read, &l)) {
221                 if (!TEST_true(ossl_quic_tserver_has_read_ended(tserver)))
222                     goto err;
223
224                 if (!TEST_mem_eq(msg1, sizeof(msg1) - 1, msg2, s_total_read))
225                     goto err;
226
227                 s_begin_write = 1;
228             } else {
229                 s_total_read += l;
230                 if (!TEST_size_t_le(s_total_read, sizeof(msg1) - 1))
231                     goto err;
232             }
233         }
234
235         if (s_begin_write && s_total_written < sizeof(msg1) - 1) {
236             if (!TEST_true(ossl_quic_tserver_write(tserver,
237                                                    (unsigned char *)msg2 + s_total_written,
238                                                    sizeof(msg1) - 1 - s_total_written, &l)))
239                 goto err;
240
241             s_total_written += l;
242
243             if (s_total_written == sizeof(msg1) - 1) {
244                 ossl_quic_tserver_conclude(tserver);
245                 c_begin_read = 1;
246             }
247         }
248
249         if (c_begin_read && c_total_read < sizeof(msg1) - 1) {
250             ret = SSL_read_ex(c_ssl, msg3 + c_total_read,
251                               sizeof(msg1) - 1 - c_total_read, &l);
252             if (!TEST_true(ret == 1 || is_want(c_ssl, ret)))
253                 goto err;
254
255             c_total_read += l;
256
257             if (c_total_read == sizeof(msg1) - 1) {
258                 if (!TEST_mem_eq(msg1, sizeof(msg1) - 1,
259                                  msg3, c_total_read))
260                     goto err;
261
262                 c_wait_eos = 1;
263             }
264         }
265
266         if (c_wait_eos && !c_done_eos) {
267             unsigned char c;
268
269             ret = SSL_read_ex(c_ssl, &c, sizeof(c), &l);
270             if (!TEST_false(ret))
271                 goto err;
272
273             /*
274              * Allow the implementation to take as long as it wants to finally
275              * notice EOS. Account for varied timings in OS networking stacks.
276              */
277             if (SSL_get_error(c_ssl, ret) != SSL_ERROR_WANT_READ) {
278                 if (!TEST_int_eq(SSL_get_error(c_ssl, ret),
279                                  SSL_ERROR_ZERO_RETURN))
280                     goto err;
281
282                 c_done_eos = 1;
283                 if (use_thread_assist && use_fake_time) {
284                     if (!TEST_true(ossl_quic_tserver_is_connected(tserver)))
285                         goto err;
286                     c_start_idle_test = 1;
287                     limit_ms = 120000; /* extend time limit */
288                 } else {
289                     /* DONE */
290                     break;
291                 }
292             }
293         }
294
295         if (c_start_idle_test && !c_done_idle_test) {
296             /* This is more than our default idle timeout of 30s. */
297             if (idle_units_done < 600) {
298                 if (!TEST_true(CRYPTO_THREAD_write_lock(fake_time_lock)))
299                     goto err;
300                 fake_time = ossl_time_add(fake_time, ossl_ms2time(100));
301                 CRYPTO_THREAD_unlock(fake_time_lock);
302
303                 ++idle_units_done;
304                 ossl_quic_conn_force_assist_thread_wake(c_ssl);
305                 OSSL_sleep(1); /* Ensure CPU scheduling for test purposes */
306             } else {
307                 c_done_idle_test = 1;
308             }
309         }
310
311         if (c_done_idle_test) {
312             /*
313              * If we have finished the fake idling duration, the connection
314              * should still be healthy in TA mode.
315              */
316             if (!TEST_true(ossl_quic_tserver_is_connected(tserver)))
317                 goto err;
318
319             /* DONE */
320             break;
321         }
322
323         /*
324          * This is inefficient because we spin until things work without
325          * blocking but this is just a test.
326          */
327         if (!c_start_idle_test || c_done_idle_test) {
328             /* Inhibit manual ticking during idle test to test TA mode. */
329             SSL_tick(c_ssl);
330         }
331
332         ossl_quic_tserver_tick(tserver);
333
334         if (use_inject) {
335             BIO_MSG rmsg = {0};
336             size_t msgs_processed = 0;
337
338             for (;;) {
339                 /*
340                  * Manually spoonfeed received datagrams from the real BIO_dgram
341                  * into QUIC via the injection interface, thereby testing the
342                  * injection interface.
343                  */
344                 rmsg.data       = scratch_buf;
345                 rmsg.data_len   = sizeof(scratch_buf);
346
347                 if (!BIO_recvmmsg(c_net_bio, &rmsg, sizeof(rmsg), 1, 0, &msgs_processed)
348                     || msgs_processed == 0 || rmsg.data_len == 0)
349                     break;
350
351                 if (!TEST_true(SSL_inject_net_dgram(c_ssl, rmsg.data, rmsg.data_len,
352                                                     NULL, NULL)))
353                     goto err;
354             }
355         }
356     }
357
358     testresult = 1;
359 err:
360     SSL_free(c_ssl);
361     SSL_CTX_free(c_ctx);
362     ossl_quic_tserver_free(tserver);
363     BIO_ADDR_free(s_addr_);
364     BIO_free(s_net_bio_own);
365     BIO_free(c_net_bio_own);
366     BIO_free(c_pair_own);
367     BIO_free(s_pair_own);
368     if (s_fd >= 0)
369         BIO_closesocket(s_fd);
370     if (c_fd >= 0)
371         BIO_closesocket(c_fd);
372     return testresult;
373 }
374
375 static int test_tserver(int idx)
376 {
377     int use_thread_assist, use_inject;
378
379     use_thread_assist = idx % 2;
380     idx /= 2;
381
382     use_inject = idx % 2;
383
384     return test_tserver_actual(use_thread_assist, use_inject);
385 }
386
387 static int test_tserver_simple(void)
388 {
389     return do_test(/*thread_assisted=*/0, /*fake_time=*/0, /*use_inject=*/0);
390 }
391
392 static int test_tserver_thread(void)
393 {
394     return do_test(/*thread_assisted=*/1, /*fake_time=*/0, /*use_inject=*/0);
395 }
396
397 static int test_tserver_thread_fake_time(void)
398 {
399     return do_test(/*thread_assisted=*/1, /*fake_time=*/1, /*use_inject=*/0);
400 }
401
402 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
403
404 int setup_tests(void)
405 {
406     if (!test_skip_common_options()) {
407         TEST_error("Error parsing test options\n");
408         return 0;
409     }
410
411     if (!TEST_ptr(certfile = test_get_argument(0))
412             || !TEST_ptr(keyfile = test_get_argument(1)))
413         return 0;
414
415     if ((fake_time_lock = CRYPTO_THREAD_lock_new()) == NULL)
416         return 0;
417
418     ADD_TEST(test_tserver_simple);
419     ADD_TEST(test_tserver_thread);
420     ADD_TEST(test_tserver_thread_fake_time);
421     return 1;
422 }