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