hsa: unify echo test setup
[vpp.git] / src / plugins / hs_apps / vcl / vcl_test_protos.c
1 /*
2  * Copyright (c) 2021 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <hs_apps/vcl/vcl_test.h>
17
18 static int
19 vt_tcp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
20 {
21   uint32_t flags, flen;
22   int rv;
23
24   ts->fd = vppcom_session_create (VPPCOM_PROTO_TCP, ts->noblk_connect);
25   if (ts->fd < 0)
26     {
27       vterr ("vppcom_session_create()", ts->fd);
28       return ts->fd;
29     }
30
31   rv = vppcom_session_connect (ts->fd, endpt);
32   if (rv < 0 && rv != VPPCOM_EINPROGRESS)
33     {
34       vterr ("vppcom_session_connect()", rv);
35       return rv;
36     }
37
38   ts->read = vcl_test_read;
39   ts->write = vcl_test_write;
40
41   if (!ts->noblk_connect)
42     {
43       flags = O_NONBLOCK;
44       flen = sizeof (flags);
45       vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
46       vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
47     }
48
49   return 0;
50 }
51
52 static int
53 vt_tcp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
54 {
55   int rv;
56
57   ts->fd = vppcom_session_create (VPPCOM_PROTO_TCP, 1 /* is_nonblocking */);
58   if (ts->fd < 0)
59     {
60       vterr ("vppcom_session_create()", ts->fd);
61       return ts->fd;
62     }
63
64   rv = vppcom_session_bind (ts->fd, endpt);
65   if (rv < 0)
66     {
67       vterr ("vppcom_session_bind()", rv);
68       return rv;
69     }
70
71   rv = vppcom_session_listen (ts->fd, 10);
72   if (rv < 0)
73     {
74       vterr ("vppcom_session_listen()", rv);
75       return rv;
76     }
77
78   return 0;
79 }
80
81 static int
82 vt_tcp_accept (int listen_fd, vcl_test_session_t *ts)
83 {
84   int client_fd;
85
86   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
87   if (client_fd < 0)
88     {
89       vterr ("vppcom_session_accept()", client_fd);
90       return client_fd;
91     }
92   ts->fd = client_fd;
93   ts->is_open = 1;
94   ts->read = vcl_test_read;
95   ts->write = vcl_test_write;
96
97   return 0;
98 }
99
100 static const vcl_test_proto_vft_t vcl_test_tcp = {
101   .open = vt_tcp_connect,
102   .listen = vt_tcp_listen,
103   .accept = vt_tcp_accept,
104 };
105
106 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_TCP, vcl_test_tcp);
107
108 static int
109 vt_udp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
110 {
111   uint32_t flags, flen;
112   int rv;
113
114   ts->fd = vppcom_session_create (VPPCOM_PROTO_UDP, ts->noblk_connect);
115   if (ts->fd < 0)
116     {
117       vterr ("vppcom_session_create()", ts->fd);
118       return ts->fd;
119     }
120
121   rv = vppcom_session_connect (ts->fd, endpt);
122   if (rv < 0 && rv != VPPCOM_EINPROGRESS)
123     {
124       vterr ("vppcom_session_connect()", rv);
125       return rv;
126     }
127
128   ts->read = vcl_test_read;
129   ts->write = vcl_test_write;
130
131   if (!ts->noblk_connect)
132     {
133       flags = O_NONBLOCK;
134       flen = sizeof (flags);
135       vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
136       vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
137     }
138
139   return 0;
140 }
141
142 static int
143 vt_udp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
144 {
145   int rv;
146
147   ts->fd = vppcom_session_create (VPPCOM_PROTO_UDP, 1 /* is_nonblocking */);
148   if (ts->fd < 0)
149     {
150       vterr ("vppcom_session_create()", ts->fd);
151       return ts->fd;
152     }
153
154   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CONNECTED, 0, 0);
155
156   /* Listen is implicit */
157   rv = vppcom_session_bind (ts->fd, endpt);
158   if (rv < 0)
159     {
160       vterr ("vppcom_session_bind()", rv);
161       return rv;
162     }
163
164   return 0;
165 }
166
167 static int
168 vt_udp_accept (int listen_fd, vcl_test_session_t *ts)
169 {
170   int client_fd;
171
172   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
173   if (client_fd < 0)
174     {
175       vterr ("vppcom_session_accept()", client_fd);
176       return client_fd;
177     }
178   ts->fd = client_fd;
179   ts->is_open = 1;
180   ts->read = vcl_test_read;
181   ts->write = vcl_test_write;
182
183   return 0;
184 }
185
186 static const vcl_test_proto_vft_t vcl_test_udp = {
187   .open = vt_udp_connect,
188   .listen = vt_udp_listen,
189   .accept = vt_udp_accept,
190 };
191
192 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_UDP, vcl_test_udp);
193
194 /*
195  * TLS server cert and keys to be used for testing only
196  */
197 static char vcl_test_crt_rsa[] =
198   "-----BEGIN CERTIFICATE-----\r\n"
199   "MIID5zCCAs+gAwIBAgIJALeMYCEHrTtJMA0GCSqGSIb3DQEBCwUAMIGJMQswCQYD\r\n"
200   "VQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMQ4wDAYDVQQK\r\n"
201   "DAVDaXNjbzEOMAwGA1UECwwFZmQuaW8xFjAUBgNVBAMMDXRlc3R0bHMuZmQuaW8x\r\n"
202   "IjAgBgkqhkiG9w0BCQEWE3ZwcC1kZXZAbGlzdHMuZmQuaW8wHhcNMTgwMzA1MjEx\r\n"
203   "NTEyWhcNMjgwMzAyMjExNTEyWjCBiTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNB\r\n"
204   "MREwDwYDVQQHDAhTYW4gSm9zZTEOMAwGA1UECgwFQ2lzY28xDjAMBgNVBAsMBWZk\r\n"
205   "LmlvMRYwFAYDVQQDDA10ZXN0dGxzLmZkLmlvMSIwIAYJKoZIhvcNAQkBFhN2cHAt\r\n"
206   "ZGV2QGxpc3RzLmZkLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\r\n"
207   "4C1k8a1DuStgggqT4o09fP9sJ2dC54bxhS/Xk2VEfaIZ222WSo4X/syRVfVy9Yah\r\n"
208   "cpI1zJ/RDxaZSFhgA+nPZBrFMsrULkrdAOpOVj8eDEp9JuWdO2ODSoFnCvLxcYWB\r\n"
209   "Yc5kHryJpEaGJl1sFQSesnzMFty/59ta0stk0Fp8r5NhIjWvSovGzPo6Bhz+VS2c\r\n"
210   "ebIZh4x1t2hHaFcgm0qJoJ6DceReWCW8w+yOVovTolGGq+bpb2Hn7MnRSZ2K2NdL\r\n"
211   "+aLXpkZbS/AODP1FF2vTO1mYL290LO7/51vJmPXNKSDYMy5EvILr5/VqtjsFCwRL\r\n"
212   "Q4jcM/+GeHSAFWx4qIv0BwIDAQABo1AwTjAdBgNVHQ4EFgQUWa1SOB37xmT53tZQ\r\n"
213   "aXuLLhRI7U8wHwYDVR0jBBgwFoAUWa1SOB37xmT53tZQaXuLLhRI7U8wDAYDVR0T\r\n"
214   "BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAoUht13W4ya27NVzQuCMvqPWL3VM4\r\n"
215   "3xbPFk02FaGz/WupPu276zGlzJAZrbuDcQowwwU1Ni1Yygxl96s1c2M5rHDTrOKG\r\n"
216   "rK0hbkSFBo+i6I8u4HiiQ4rYmG0Hv6+sXn3of0HsbtDPGgWZoipPWDljPYEURu3e\r\n"
217   "3HRe/Dtsj9CakBoSDzs8ndWaBR+f4sM9Tk1cjD46Gq2T/qpSPXqKxEUXlzhdCAn4\r\n"
218   "twub17Bq2kykHpppCwPg5M+v30tHG/R2Go15MeFWbEJthFk3TZMjKL7UFs7fH+x2\r\n"
219   "wSonXb++jY+KmCb93C+soABBizE57g/KmiR2IxQ/LMjDik01RSUIaM0lLA==\r\n"
220   "-----END CERTIFICATE-----\r\n";
221 static uint32_t vcl_test_crt_rsa_len = sizeof (vcl_test_crt_rsa);
222
223 static char vcl_test_key_rsa[] =
224   "-----BEGIN PRIVATE KEY-----\r\n"
225   "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgLWTxrUO5K2CC\r\n"
226   "CpPijT18/2wnZ0LnhvGFL9eTZUR9ohnbbZZKjhf+zJFV9XL1hqFykjXMn9EPFplI\r\n"
227   "WGAD6c9kGsUyytQuSt0A6k5WPx4MSn0m5Z07Y4NKgWcK8vFxhYFhzmQevImkRoYm\r\n"
228   "XWwVBJ6yfMwW3L/n21rSy2TQWnyvk2EiNa9Ki8bM+joGHP5VLZx5shmHjHW3aEdo\r\n"
229   "VyCbSomgnoNx5F5YJbzD7I5Wi9OiUYar5ulvYefsydFJnYrY10v5otemRltL8A4M\r\n"
230   "/UUXa9M7WZgvb3Qs7v/nW8mY9c0pINgzLkS8guvn9Wq2OwULBEtDiNwz/4Z4dIAV\r\n"
231   "bHioi/QHAgMBAAECggEBAMzGipP8+oT166U+NlJXRFifFVN1DvdhG9PWnOxGL+c3\r\n"
232   "ILmBBC08WQzmHshPemBvR6DZkA1H23cV5JTiLWrFtC00CvhXsLRMrE5+uWotI6yE\r\n"
233   "iofybMroHvD6/X5R510UX9hQ6MHu5ShLR5VZ9zXHz5MpTmB/60jG5dLx+jgcwBK8\r\n"
234   "LuGv2YB/WCUwT9QJ3YU2eaingnXtz/MrFbkbltrqlnBdlD+kTtw6Yac9y1XuuQXc\r\n"
235   "BPeulLNDuPolJVWbUvDBZrpt2dXTgz8ws1sv+wCNE0xwQJsqW4Nx3QkpibUL9RUr\r\n"
236   "CVbKlNfa9lopT6nGKlgX69R/uH35yh9AOsfasro6w0ECgYEA82UJ8u/+ORah+0sF\r\n"
237   "Q0FfW5MTdi7OAUHOz16pUsGlaEv0ERrjZxmAkHA/VRwpvDBpx4alCv0Hc39PFLIk\r\n"
238   "nhSsM2BEuBkTAs6/GaoNAiBtQVE/hN7awNRWVmlieS0go3Y3dzaE9IUMyj8sPOFT\r\n"
239   "5JdJ6BM69PHKCkY3dKdnnfpFEuECgYEA68mRpteunF1mdZgXs+WrN+uLlRrQR20F\r\n"
240   "ZyMYiUCH2Dtn26EzA2moy7FipIIrQcX/j+KhYNGM3e7MU4LymIO29E18mn8JODnH\r\n"
241   "sQOXzBTsf8A4yIVMkcuQD3bfb0JiUGYUPOidTp2N7IJA7+6Yc3vQOyb74lnKnJoO\r\n"
242   "gougPT2wS+cCgYAn7muzb6xFsXDhyW0Tm6YJYBfRS9yAWEuVufINobeBZPSl2cN1\r\n"
243   "Jrnw+HlrfTNbrJWuJmjtZJXUXQ6cVp2rUbjutNyRV4vG6iRwEXYQ40EJdkr1gZpi\r\n"
244   "CHQhuShuuPih2MNAy7EEbM+sXrDjTBR3bFqzuHPzu7dp+BshCFX3lRfAAQKBgGQt\r\n"
245   "K5i7IhCFDjb/+3IPLgOAK7mZvsvZ4eXD33TQ2eZgtut1PXtBtNl17/b85uv293Fm\r\n"
246   "VDISVcsk3eLNS8zIiT6afUoWlxAwXEs0v5WRfjl4radkGvgGiJpJYvyeM67877RB\r\n"
247   "EDSKc/X8ESLfOB44iGvZUEMG6zJFscx9DgN25iQZAoGAbyd+JEWwdVH9/K3IH1t2\r\n"
248   "PBkZX17kNWv+iVM1WyFjbe++vfKZCrOJiyiqhDeEqgrP3AuNMlaaduC3VRC3G5oV\r\n"
249   "Mj1tlhDWQ/qhvKdCKNdIVQYDE75nw+FRWV8yYkHAnXYW3tNoweDIwixE0hkPR1bc\r\n"
250   "oEjPLVNtx8SOj/M4rhaPT3I=\r\n"
251   "-----END PRIVATE KEY-----\r\n";
252 static uint32_t vcl_test_key_rsa_len = sizeof (vcl_test_key_rsa);
253
254 static int
255 vt_add_cert_key_pair ()
256 {
257   vcl_test_main_t *vt = &vcl_test_main;
258   vppcom_cert_key_pair_t ckpair;
259   int ckp_index;
260
261   vtinf ("Adding tls certs ...");
262
263   ckpair.cert = vcl_test_crt_rsa;
264   ckpair.key = vcl_test_key_rsa;
265   ckpair.cert_len = vcl_test_crt_rsa_len;
266   ckpair.key_len = vcl_test_key_rsa_len;
267   ckp_index = vppcom_add_cert_key_pair (&ckpair);
268   if (ckp_index < 0)
269     {
270       vterr ("vppcom_add_cert_key_pair()", ckp_index);
271       return ckp_index;
272     }
273
274   vt->ckpair_index = ckp_index;
275   return 0;
276 }
277
278 static int
279 vt_tls_init (hs_test_cfg_t *cfg)
280 {
281   return vt_add_cert_key_pair ();
282 }
283
284 static int
285 vt_tls_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
286 {
287   vcl_test_main_t *vt = &vcl_test_main;
288   uint32_t flags, flen, ckp_len;
289   int rv;
290
291   ts->fd = vppcom_session_create (VPPCOM_PROTO_TLS, ts->noblk_connect);
292   if (ts->fd < 0)
293     {
294       vterr ("vppcom_session_create()", ts->fd);
295       return ts->fd;
296     }
297
298   ckp_len = sizeof (vt->ckpair_index);
299   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
300                        &ckp_len);
301
302   rv = vppcom_session_connect (ts->fd, endpt);
303   if (rv < 0 && rv != VPPCOM_EINPROGRESS)
304     {
305       vterr ("vppcom_session_connect()", rv);
306       return rv;
307     }
308
309   ts->read = vcl_test_read;
310   ts->write = vcl_test_write;
311
312   if (!ts->noblk_connect)
313     {
314       flags = O_NONBLOCK;
315       flen = sizeof (flags);
316       vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
317       vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
318     }
319
320   return 0;
321 }
322
323 static int
324 vt_tls_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
325 {
326   vcl_test_main_t *vt = &vcl_test_main;
327   uint32_t ckp_len;
328   int rv;
329
330   ts->fd = vppcom_session_create (VPPCOM_PROTO_TLS, 1 /* is_nonblocking */);
331   if (ts->fd < 0)
332     {
333       vterr ("vppcom_session_create()", ts->fd);
334       return ts->fd;
335     }
336
337   ckp_len = sizeof (vt->ckpair_index);
338   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
339                        &ckp_len);
340
341   rv = vppcom_session_bind (ts->fd, endpt);
342   if (rv < 0)
343     {
344       vterr ("vppcom_session_bind()", rv);
345       return rv;
346     }
347
348   rv = vppcom_session_listen (ts->fd, 10);
349   if (rv < 0)
350     {
351       vterr ("vppcom_session_listen()", rv);
352       return rv;
353     }
354
355   return 0;
356 }
357
358 static int
359 vt_tls_accept (int listen_fd, vcl_test_session_t *ts)
360 {
361   int client_fd;
362
363   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
364   if (client_fd < 0)
365     {
366       vterr ("vppcom_session_accept()", client_fd);
367       return client_fd;
368     }
369   ts->fd = client_fd;
370   ts->is_open = 1;
371   ts->read = vcl_test_read;
372   ts->write = vcl_test_write;
373
374   return 0;
375 }
376
377 static const vcl_test_proto_vft_t vcl_test_tls = {
378   .init = vt_tls_init,
379   .open = vt_tls_connect,
380   .listen = vt_tls_listen,
381   .accept = vt_tls_accept,
382 };
383
384 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_TLS, vcl_test_tls);
385
386 static int
387 vt_dtls_init (hs_test_cfg_t *cfg)
388 {
389   return vt_add_cert_key_pair ();
390 }
391
392 static int
393 vt_dtls_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
394 {
395   vcl_test_main_t *vt = &vcl_test_main;
396   uint32_t flags, flen, ckp_len;
397   int rv;
398
399   ts->fd = vppcom_session_create (VPPCOM_PROTO_DTLS, ts->noblk_connect);
400   if (ts->fd < 0)
401     {
402       vterr ("vppcom_session_create()", ts->fd);
403       return ts->fd;
404     }
405
406   ckp_len = sizeof (vt->ckpair_index);
407   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
408                        &ckp_len);
409
410   rv = vppcom_session_connect (ts->fd, endpt);
411   if (rv < 0 && rv != VPPCOM_EINPROGRESS)
412     {
413       vterr ("vppcom_session_connect()", rv);
414       return rv;
415     }
416
417   ts->read = vcl_test_read;
418   ts->write = vcl_test_write;
419
420   if (!ts->noblk_connect)
421     {
422       flags = O_NONBLOCK;
423       flen = sizeof (flags);
424       vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
425       vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
426     }
427
428   return 0;
429 }
430
431 static int
432 vt_dtls_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
433 {
434   vcl_test_main_t *vt = &vcl_test_main;
435   uint32_t ckp_len;
436   int rv;
437
438   ts->fd = vppcom_session_create (VPPCOM_PROTO_DTLS, 1 /* is_nonblocking */);
439   if (ts->fd < 0)
440     {
441       vterr ("vppcom_session_create()", ts->fd);
442       return ts->fd;
443     }
444
445   ckp_len = sizeof (vt->ckpair_index);
446   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
447                        &ckp_len);
448
449   rv = vppcom_session_bind (ts->fd, endpt);
450   if (rv < 0)
451     {
452       vterr ("vppcom_session_bind()", rv);
453       return rv;
454     }
455
456   rv = vppcom_session_listen (ts->fd, 10);
457   if (rv < 0)
458     {
459       vterr ("vppcom_session_listen()", rv);
460       return rv;
461     }
462
463   return 0;
464 }
465
466 static int
467 vt_dtls_accept (int listen_fd, vcl_test_session_t *ts)
468 {
469   int client_fd;
470
471   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
472   if (client_fd < 0)
473     {
474       vterr ("vppcom_session_accept()", client_fd);
475       return client_fd;
476     }
477   ts->fd = client_fd;
478   ts->is_open = 1;
479   ts->read = vcl_test_read;
480   ts->write = vcl_test_write;
481
482   return 0;
483 }
484
485 static const vcl_test_proto_vft_t vcl_test_dtls = {
486   .init = vt_dtls_init,
487   .open = vt_dtls_connect,
488   .listen = vt_dtls_listen,
489   .accept = vt_dtls_accept,
490 };
491
492 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_DTLS, vcl_test_dtls);
493
494 static int
495 vt_quic_init (hs_test_cfg_t *cfg)
496 {
497   vcl_test_main_t *vt = &vcl_test_main;
498
499   if (cfg)
500     vt->cfg = *cfg;
501
502   return vt_add_cert_key_pair ();
503 }
504
505 static int
506 vt_quic_maybe_init_wrk (vcl_test_main_t *vt, vcl_test_wrk_t *wrk,
507                         vppcom_endpt_t *endpt)
508 {
509   uint32_t size, i, flags, flen, ckp_len;
510   vcl_test_session_t *tq;
511   int rv;
512
513   /* Test already initialized */
514   if (wrk->n_qsessions == vt->cfg.num_test_qsessions)
515     return 0;
516
517   /* Make sure pool is large enough */
518   if (!wrk->qsessions)
519     {
520       wrk->qsessions =
521         calloc (vt->cfg.num_test_qsessions, sizeof (vcl_test_session_t));
522     }
523   else
524     {
525       size = vt->cfg.num_test_qsessions * sizeof (vcl_test_session_t);
526       wrk->qsessions = realloc (wrk->qsessions, size);
527     }
528
529   if (!wrk->qsessions)
530     {
531       vterr ("failed to alloc Qsessions", -errno);
532       return errno;
533     }
534
535   for (i = 0; i < vt->cfg.num_test_qsessions; i++)
536     {
537       tq = &wrk->qsessions[i];
538       tq->fd =
539         vppcom_session_create (VPPCOM_PROTO_QUIC, 0 /* is_nonblocking */);
540       tq->session_index = i;
541       if (tq->fd < 0)
542         {
543           vterr ("vppcom_session_create()", tq->fd);
544           return tq->fd;
545         }
546
547       ckp_len = sizeof (vt->ckpair_index);
548       vppcom_session_attr (tq->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
549                            &ckp_len);
550
551       /* Connect is blocking */
552       rv = vppcom_session_connect (tq->fd, endpt);
553       if (rv < 0)
554         {
555           vterr ("vppcom_session_connect()", rv);
556           return rv;
557         }
558       flags = O_NONBLOCK;
559       flen = sizeof (flags);
560       vppcom_session_attr (tq->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
561       vtinf ("Test Qsession %d (fd %d) connected.", i, tq->fd);
562     }
563   wrk->n_qsessions = vt->cfg.num_test_qsessions;
564
565   return 0;
566 }
567
568 static int
569 vt_quic_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
570 {
571   vcl_test_main_t *vt = &vcl_test_main;
572   uint32_t wrk_index, flags, flen;
573   vcl_test_session_t *tq;
574   vcl_test_wrk_t *wrk;
575   int rv;
576
577   wrk_index = vcl_test_worker_index ();
578   wrk = &vt->wrk[wrk_index];
579
580   /* Make sure qsessions are initialized */
581   vt_quic_maybe_init_wrk (vt, wrk, endpt);
582
583   ts->fd = vppcom_session_create (VPPCOM_PROTO_QUIC, ts->noblk_connect);
584   if (ts->fd < 0)
585     {
586       vterr ("vppcom_session_create()", ts->fd);
587       return ts->fd;
588     }
589
590   /* Choose qession to use for stream */
591   tq = &wrk->qsessions[ts->session_index / vt->cfg.num_test_sessions_perq];
592
593   rv = vppcom_session_stream_connect (ts->fd, tq->fd);
594   if (rv < 0 && rv != VPPCOM_EINPROGRESS)
595     {
596       vterr ("vppcom_session_stream_connect()", rv);
597       return rv;
598     }
599
600   ts->read = vcl_test_read;
601   ts->write = vcl_test_write;
602
603   if (!ts->noblk_connect)
604     {
605       flags = O_NONBLOCK;
606       flen = sizeof (flags);
607       vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
608       vtinf ("Test (quic stream) session %d (fd %d) connected.",
609              ts->session_index, ts->fd);
610     }
611
612   return 0;
613 }
614
615 static int
616 vt_quic_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
617 {
618   vcl_test_main_t *vt = &vcl_test_main;
619   uint32_t ckp_len;
620   int rv;
621
622   ts->fd = vppcom_session_create (VPPCOM_PROTO_QUIC, 1 /* is_nonblocking */);
623   if (ts->fd < 0)
624     {
625       vterr ("vppcom_session_create()", ts->fd);
626       return ts->fd;
627     }
628
629   ckp_len = sizeof (vt->ckpair_index);
630   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_CKPAIR, &vt->ckpair_index,
631                        &ckp_len);
632
633   rv = vppcom_session_bind (ts->fd, endpt);
634   if (rv < 0)
635     {
636       vterr ("vppcom_session_bind()", rv);
637       return rv;
638     }
639
640   rv = vppcom_session_listen (ts->fd, 10);
641   if (rv < 0)
642     {
643       vterr ("vppcom_session_listen()", rv);
644       return rv;
645     }
646
647   return 0;
648 }
649
650 static int
651 vt_quic_accept (int listen_fd, vcl_test_session_t *ts)
652 {
653   int client_fd;
654
655   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
656   if (client_fd < 0)
657     {
658       vterr ("vppcom_session_accept()", client_fd);
659       return client_fd;
660     }
661   ts->fd = client_fd;
662   ts->is_open = 1;
663   ts->read = vcl_test_read;
664   ts->write = vcl_test_write;
665
666   return 0;
667 }
668
669 static int
670 vt_quic_close (vcl_test_session_t *ts)
671 {
672   int listener_fd = vppcom_session_listener (ts->fd);
673
674   if ((vppcom_session_n_accepted (listener_fd) == 0) &
675       vppcom_session_is_connectable_listener (listener_fd))
676     {
677       vtinf ("Connected Listener fd %x has no more sessions", listener_fd);
678       vppcom_session_close (listener_fd);
679     }
680
681   return 0;
682 }
683
684 static const vcl_test_proto_vft_t vcl_test_quic = {
685   .init = vt_quic_init,
686   .open = vt_quic_connect,
687   .listen = vt_quic_listen,
688   .accept = vt_quic_accept,
689   .close = vt_quic_close,
690 };
691
692 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_QUIC, vcl_test_quic);
693
694 static unsigned char test_key[46] = {
695   0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0, 0xd6, 0x4f, 0xa3, 0x2c,
696   0x06, 0xde, 0x41, 0x39, 0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
697   0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6, 0xc1, 0x73, 0xc3, 0x17, 0xf2, 0xda,
698   0xbe, 0x35, 0x77, 0x93, 0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
699 };
700
701 typedef struct
702 {
703   unsigned char cc : 4;
704   unsigned char x : 1;
705   unsigned char p : 1;
706   unsigned char version : 2;
707   unsigned char pt : 7;
708   unsigned char m : 1;
709   uint16_t seq;
710   uint32_t ts;
711   uint32_t ssrc;
712 } rtp_hdr_t;
713
714 typedef struct
715 {
716   rtp_hdr_t tx_hdr;
717   rtp_hdr_t rx_hdr;
718 } rtp_headers_t;
719
720 typedef struct transport_endpt_cfg_srtp_policy
721 {
722   uint32_t ssrc_type;
723   uint32_t ssrc_value;
724   uint32_t window_size;
725   uint8_t allow_repeat_tx;
726   uint8_t key_len;
727   uint8_t key[46];
728 } transport_endpt_cfg_srtp_policy_t;
729
730 typedef struct transport_endpt_cfg_srtp
731 {
732   transport_endpt_cfg_srtp_policy_t policy[2];
733 } transport_endpt_cfg_srtp_t;
734
735 static void
736 vt_session_add_srtp_policy (vcl_test_session_t *ts, int is_connect)
737 {
738   transport_endpt_cfg_srtp_t *srtp_cfg;
739   transport_endpt_cfg_srtp_policy_t *test_policy;
740   uint32_t rx_ssrc, tx_ssrc;
741   uint32_t cfg_size;
742
743   rx_ssrc = is_connect ? 0xcafebeef : 0xbeefcafe;
744   tx_ssrc = is_connect ? 0xbeefcafe : 0xcafebeef;
745
746   cfg_size = sizeof (transport_endpt_cfg_srtp_t);
747   srtp_cfg = malloc (cfg_size);
748   memset (srtp_cfg, 0, cfg_size);
749
750   test_policy = &srtp_cfg->policy[0];
751   test_policy->ssrc_type = 1 /* ssrc_specific */;
752   test_policy->ssrc_value = rx_ssrc;
753   memcpy (test_policy->key, test_key, sizeof (test_key));
754   test_policy->key_len = sizeof (test_key);
755   test_policy->window_size = 128;
756   test_policy->allow_repeat_tx = 1;
757
758   test_policy = &srtp_cfg->policy[1];
759   test_policy->ssrc_type = 1 /* ssrc_specific */;
760   test_policy->ssrc_value = tx_ssrc;
761   memcpy (test_policy->key, test_key, sizeof (test_key));
762   test_policy->key_len = sizeof (test_key);
763   test_policy->window_size = 128;
764   test_policy->allow_repeat_tx = 1;
765
766   vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_ENDPT_EXT_CFG, srtp_cfg,
767                        &cfg_size);
768   free (srtp_cfg);
769 }
770
771 static void
772 vt_srtp_session_init (vcl_test_session_t *ts, int is_connect)
773 {
774   uint32_t rx_ssrc, tx_ssrc;
775   rtp_headers_t *rtp_hdrs;
776   rtp_hdr_t *hdr;
777
778   rx_ssrc = is_connect ? 0xcafebeef : 0xbeefcafe;
779   tx_ssrc = is_connect ? 0xbeefcafe : 0xcafebeef;
780
781   rtp_hdrs = malloc (sizeof (rtp_headers_t));
782   memset (rtp_hdrs, 0, sizeof (*rtp_hdrs));
783   ts->opaque = rtp_hdrs;
784
785   hdr = &rtp_hdrs->rx_hdr;
786   hdr->version = 2;
787   hdr->p = 0;
788   hdr->x = 0;
789   hdr->cc = 0;
790   hdr->m = 0;
791   hdr->pt = 0x1;
792   hdr->seq = 0;
793   hdr->ts = 0;
794   hdr->ssrc = htonl (rx_ssrc);
795
796   hdr = &rtp_hdrs->tx_hdr;
797   hdr->version = 2;
798   hdr->p = 0;
799   hdr->x = 0;
800   hdr->cc = 0;
801   hdr->m = 0;
802   hdr->pt = 0x1;
803   hdr->seq = 0;
804   hdr->ts = 0;
805   hdr->ssrc = htonl (tx_ssrc);
806 }
807
808 static int
809 vt_srtp_write (vcl_test_session_t *ts, void *buf, uint32_t nbytes)
810 {
811   int tx_bytes = 0, nbytes_left = nbytes, rv;
812   vcl_test_stats_t *stats = &ts->stats;
813   rtp_hdr_t *hdr;
814
815   hdr = &((rtp_headers_t *) ts->opaque)->tx_hdr;
816   hdr->seq = htons (ntohs (hdr->seq) + 1);
817   hdr->ts = htonl (ntohl (hdr->ts) + 1);
818
819   memcpy (buf, hdr, sizeof (*hdr));
820
821   do
822     {
823       stats->tx_xacts++;
824       rv = vppcom_session_write (ts->fd, buf, nbytes_left);
825       if (rv < 0)
826         {
827           if ((rv == VPPCOM_EAGAIN || rv == VPPCOM_EWOULDBLOCK))
828             stats->tx_eagain++;
829           break;
830         }
831       tx_bytes += rv;
832       nbytes_left = nbytes_left - rv;
833       buf += rv;
834       stats->tx_incomp++;
835     }
836   while (tx_bytes != nbytes);
837
838   if (tx_bytes < 0)
839     return 0;
840
841   stats->tx_bytes += tx_bytes;
842
843   return (tx_bytes);
844 }
845
846 static inline int
847 vt_srtp_read (vcl_test_session_t *ts, void *buf, uint32_t nbytes)
848 {
849   vcl_test_stats_t *stats = &ts->stats;
850   rtp_hdr_t *hdr;
851   int rx_bytes;
852
853   stats->rx_xacts++;
854   rx_bytes = vppcom_session_read (ts->fd, buf, nbytes);
855
856   if (rx_bytes <= 0)
857     {
858       if (rx_bytes == VPPCOM_EAGAIN || rx_bytes == VPPCOM_EWOULDBLOCK)
859         stats->rx_eagain++;
860       else
861         return -1;
862     }
863
864   if (rx_bytes < nbytes)
865     stats->rx_incomp++;
866
867   stats->rx_bytes += rx_bytes;
868
869   hdr = &((rtp_headers_t *) ts->opaque)->rx_hdr;
870   if (((rtp_hdr_t *) buf)->ssrc != hdr->ssrc)
871     hdr->ssrc = ((rtp_hdr_t *) buf)->ssrc;
872   return (rx_bytes);
873 }
874
875 static int
876 vt_srtp_connect (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
877 {
878   uint32_t flags, flen;
879   int rv;
880
881   ts->fd = vppcom_session_create (VPPCOM_PROTO_SRTP, ts->noblk_connect);
882   if (ts->fd < 0)
883     {
884       vterr ("vppcom_session_create()", ts->fd);
885       return ts->fd;
886     }
887
888   vt_session_add_srtp_policy (ts, 1 /* is connect */);
889
890   rv = vppcom_session_connect (ts->fd, endpt);
891   if (rv < 0 && rv != VPPCOM_EINPROGRESS)
892     {
893       vterr ("vppcom_session_connect()", rv);
894       return rv;
895     }
896
897   ts->read = vt_srtp_read;
898   ts->write = vt_srtp_write;
899
900   if (!ts->noblk_connect)
901     {
902       flags = O_NONBLOCK;
903       flen = sizeof (flags);
904       vppcom_session_attr (ts->fd, VPPCOM_ATTR_SET_FLAGS, &flags, &flen);
905       vtinf ("Test session %d (fd %d) connected.", ts->session_index, ts->fd);
906     }
907
908   vt_srtp_session_init (ts, 1 /* is connect */);
909
910   return 0;
911 }
912
913 static int
914 vt_srtp_listen (vcl_test_session_t *ts, vppcom_endpt_t *endpt)
915 {
916   int rv;
917
918   ts->fd = vppcom_session_create (VPPCOM_PROTO_SRTP, 1 /* is_nonblocking */);
919   if (ts->fd < 0)
920     {
921       vterr ("vppcom_session_create()", ts->fd);
922       return ts->fd;
923     }
924
925   vt_session_add_srtp_policy (ts, 0 /* is connect */);
926
927   rv = vppcom_session_bind (ts->fd, endpt);
928   if (rv < 0)
929     {
930       vterr ("vppcom_session_bind()", rv);
931       return rv;
932     }
933
934   rv = vppcom_session_listen (ts->fd, 10);
935   if (rv < 0)
936     {
937       vterr ("vppcom_session_listen()", rv);
938       return rv;
939     }
940
941   return 0;
942 }
943
944 static int
945 vt_srtp_accept (int listen_fd, vcl_test_session_t *ts)
946 {
947   int client_fd;
948
949   client_fd = vppcom_session_accept (listen_fd, &ts->endpt, 0);
950   if (client_fd < 0)
951     {
952       vterr ("vppcom_session_accept()", client_fd);
953       return client_fd;
954     }
955   ts->fd = client_fd;
956   ts->is_open = 1;
957   ts->read = vt_srtp_read;
958   ts->write = vt_srtp_write;
959
960   vt_srtp_session_init (ts, 0 /* is connect */);
961
962   return 0;
963 }
964
965 static int
966 vt_srtp_close (vcl_test_session_t *ts)
967 {
968   free (ts->opaque);
969   return 0;
970 }
971
972 static const vcl_test_proto_vft_t vcl_test_srtp = {
973   .open = vt_srtp_connect,
974   .listen = vt_srtp_listen,
975   .accept = vt_srtp_accept,
976   .close = vt_srtp_close,
977 };
978
979 VCL_TEST_REGISTER_PROTO (VPPCOM_PROTO_SRTP, vcl_test_srtp);
980
981 /*
982  * fd.io coding-style-patch-verification: ON
983  *
984  * Local Variables:
985  * eval: (c-set-style "gnu")
986  * End:
987  */