quic: integrate vpp crypto api for quic packets encryption
[vpp.git] / src / plugins / quic / quic.c
1 /*
2  * Copyright (c) 2019 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 <sys/socket.h>
17
18 #include <vnet/session/application.h>
19 #include <vnet/session/transport.h>
20 #include <vnet/session/session.h>
21 #include <vlib/unix/plugin.h>
22 #include <vpp/app/version.h>
23 #include <openssl/pem.h>
24
25 #include <vppinfra/lock.h>
26
27 #include <quic/quic.h>
28
29 #include <quicly/defaults.h>
30 #include <picotls/openssl.h>
31 #include <picotls/pembase64.h>
32
33 #include <quic/quic_crypto.h>
34
35 static quic_main_t quic_main;
36 static void quic_update_timer (quic_ctx_t * ctx);
37
38 static u8 *
39 quic_format_err (u8 * s, va_list * args)
40 {
41   u64 code = va_arg (*args, u64);
42   switch (code)
43     {
44     case 0:
45       s = format (s, "no error");
46       break;
47       /* app errors */
48     case QUIC_ERROR_FULL_FIFO:
49       s = format (s, "full fifo");
50       break;
51     case QUIC_APP_ERROR_CLOSE_NOTIFY:
52       s = format (s, "QUIC_APP_ERROR_CLOSE_NOTIFY");
53       break;
54     case QUIC_APP_ALLOCATION_ERROR:
55       s = format (s, "QUIC_APP_ALLOCATION_ERROR");
56       break;
57     case QUIC_APP_ACCEPT_NOTIFY_ERROR:
58       s = format (s, "QUIC_APP_ACCEPT_NOTIFY_ERROR");
59       break;
60     case QUIC_APP_CONNECT_NOTIFY_ERROR:
61       s = format (s, "QUIC_APP_CONNECT_NOTIFY_ERROR");
62       break;
63       /* quicly errors */
64     case QUICLY_ERROR_PACKET_IGNORED:
65       s = format (s, "QUICLY_ERROR_PACKET_IGNORED");
66       break;
67     case QUICLY_ERROR_SENDBUF_FULL:
68       s = format (s, "QUICLY_ERROR_SENDBUF_FULL");
69       break;
70     case QUICLY_ERROR_FREE_CONNECTION:
71       s = format (s, "QUICLY_ERROR_FREE_CONNECTION");
72       break;
73     case QUICLY_ERROR_RECEIVED_STATELESS_RESET:
74       s = format (s, "QUICLY_ERROR_RECEIVED_STATELESS_RESET");
75       break;
76     case QUICLY_TRANSPORT_ERROR_NONE:
77       s = format (s, "QUICLY_TRANSPORT_ERROR_NONE");
78       break;
79     case QUICLY_TRANSPORT_ERROR_INTERNAL:
80       s = format (s, "QUICLY_TRANSPORT_ERROR_INTERNAL");
81       break;
82     case QUICLY_TRANSPORT_ERROR_SERVER_BUSY:
83       s = format (s, "QUICLY_TRANSPORT_ERROR_SERVER_BUSY");
84       break;
85     case QUICLY_TRANSPORT_ERROR_FLOW_CONTROL:
86       s = format (s, "QUICLY_TRANSPORT_ERROR_FLOW_CONTROL");
87       break;
88     case QUICLY_TRANSPORT_ERROR_STREAM_ID:
89       s = format (s, "QUICLY_TRANSPORT_ERROR_STREAM_ID");
90       break;
91     case QUICLY_TRANSPORT_ERROR_STREAM_STATE:
92       s = format (s, "QUICLY_TRANSPORT_ERROR_STREAM_STATE");
93       break;
94     case QUICLY_TRANSPORT_ERROR_FINAL_OFFSET:
95       s = format (s, "QUICLY_TRANSPORT_ERROR_FINAL_OFFSET");
96       break;
97     case QUICLY_TRANSPORT_ERROR_FRAME_ENCODING:
98       s = format (s, "QUICLY_TRANSPORT_ERROR_FRAME_ENCODING");
99       break;
100     case QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER:
101       s = format (s, "QUICLY_TRANSPORT_ERROR_TRANSPORT_PARAMETER");
102       break;
103     case QUICLY_TRANSPORT_ERROR_VERSION_NEGOTIATION:
104       s = format (s, "QUICLY_TRANSPORT_ERROR_VERSION_NEGOTIATION");
105       break;
106     case QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION:
107       s = format (s, "QUICLY_TRANSPORT_ERROR_PROTOCOL_VIOLATION");
108       break;
109     case QUICLY_TRANSPORT_ERROR_INVALID_MIGRATION:
110       s = format (s, "QUICLY_TRANSPORT_ERROR_INVALID_MIGRATION");
111       break;
112       /* picotls errors */
113     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_CLOSE_NOTIFY):
114       s =
115         format (s, "PTLS_ALERT_CLOSE_NOTIFY");
116       break;
117     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_UNEXPECTED_MESSAGE):
118       s =
119         format (s, "PTLS_ALERT_UNEXPECTED_MESSAGE");
120       break;
121     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_BAD_RECORD_MAC):
122       s =
123         format (s, "PTLS_ALERT_BAD_RECORD_MAC");
124       break;
125     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_HANDSHAKE_FAILURE):
126       s =
127         format (s, "PTLS_ALERT_HANDSHAKE_FAILURE");
128       break;
129     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_BAD_CERTIFICATE):
130       s =
131         format (s, "PTLS_ALERT_BAD_CERTIFICATE");
132       break;
133     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_CERTIFICATE_REVOKED):
134       s =
135         format (s, "PTLS_ALERT_CERTIFICATE_REVOKED");
136       break;
137     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_CERTIFICATE_EXPIRED):
138       s =
139         format (s, "PTLS_ALERT_CERTIFICATE_EXPIRED");
140       break;
141     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_CERTIFICATE_UNKNOWN):
142       s =
143         format (s, "PTLS_ALERT_CERTIFICATE_UNKNOWN");
144       break;
145     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_ILLEGAL_PARAMETER):
146       s =
147         format (s, "PTLS_ALERT_ILLEGAL_PARAMETER");
148       break;
149     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_UNKNOWN_CA):
150       s =
151         format (s, "PTLS_ALERT_UNKNOWN_CA");
152       break;
153     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_DECODE_ERROR):
154       s =
155         format (s, "PTLS_ALERT_DECODE_ERROR");
156       break;
157     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_DECRYPT_ERROR):
158       s =
159         format (s, "PTLS_ALERT_DECRYPT_ERROR");
160       break;
161     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_PROTOCOL_VERSION):
162       s =
163         format (s, "PTLS_ALERT_PROTOCOL_VERSION");
164       break;
165     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_INTERNAL_ERROR):
166       s =
167         format (s, "PTLS_ALERT_INTERNAL_ERROR");
168       break;
169     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_USER_CANCELED):
170       s =
171         format (s, "PTLS_ALERT_USER_CANCELED");
172       break;
173     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_MISSING_EXTENSION):
174       s =
175         format (s, "PTLS_ALERT_MISSING_EXTENSION");
176       break;
177     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_UNRECOGNIZED_NAME):
178       s =
179         format (s, "PTLS_ALERT_UNRECOGNIZED_NAME");
180       break;
181     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_CERTIFICATE_REQUIRED):
182       s =
183         format (s, "PTLS_ALERT_CERTIFICATE_REQUIRED");
184       break;
185     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ALERT_NO_APPLICATION_PROTOCOL):
186       s =
187         format (s, "PTLS_ALERT_NO_APPLICATION_PROTOCOL");
188       break;
189     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_NO_MEMORY):
190       s =
191         format (s, "PTLS_ERROR_NO_MEMORY");
192       break;
193     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_IN_PROGRESS):
194       s =
195         format (s, "PTLS_ERROR_IN_PROGRESS");
196       break;
197     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_LIBRARY):
198       s =
199         format (s, "PTLS_ERROR_LIBRARY");
200       break;
201     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_INCOMPATIBLE_KEY):
202       s =
203         format (s, "PTLS_ERROR_INCOMPATIBLE_KEY");
204       break;
205     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_SESSION_NOT_FOUND):
206       s =
207         format (s, "PTLS_ERROR_SESSION_NOT_FOUND");
208       break;
209     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_STATELESS_RETRY):
210       s =
211         format (s, "PTLS_ERROR_STATELESS_RETRY");
212       break;
213     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_NOT_AVAILABLE):
214       s =
215         format (s, "PTLS_ERROR_NOT_AVAILABLE");
216       break;
217     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_COMPRESSION_FAILURE):
218       s =
219         format (s, "PTLS_ERROR_COMPRESSION_FAILURE");
220       break;
221     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_BER_INCORRECT_ENCODING):
222       s =
223         format (s, "PTLS_ERROR_BER_INCORRECT_ENCODING");
224       break;
225     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_BER_MALFORMED_TYPE):
226       s =
227         format (s, "PTLS_ERROR_BER_MALFORMED_TYPE");
228       break;
229     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_BER_MALFORMED_LENGTH):
230       s =
231         format (s, "PTLS_ERROR_BER_MALFORMED_LENGTH");
232       break;
233     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_BER_EXCESSIVE_LENGTH):
234       s =
235         format (s, "PTLS_ERROR_BER_EXCESSIVE_LENGTH");
236       break;
237     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_BER_ELEMENT_TOO_SHORT):
238       s =
239         format (s, "PTLS_ERROR_BER_ELEMENT_TOO_SHORT");
240       break;
241     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_BER_UNEXPECTED_EOC):
242       s =
243         format (s, "PTLS_ERROR_BER_UNEXPECTED_EOC");
244       break;
245     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_DER_INDEFINITE_LENGTH):
246       s =
247         format (s, "PTLS_ERROR_DER_INDEFINITE_LENGTH");
248       break;
249     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_INCORRECT_ASN1_SYNTAX):
250       s =
251         format (s, "PTLS_ERROR_INCORRECT_ASN1_SYNTAX");
252       break;
253     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_INCORRECT_PEM_KEY_VERSION):
254       s =
255         format (s, "PTLS_ERROR_INCORRECT_PEM_KEY_VERSION");
256       break;
257     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_INCORRECT_PEM_ECDSA_KEY_VERSION):
258       s =
259         format (s, "PTLS_ERROR_INCORRECT_PEM_ECDSA_KEY_VERSION");
260       break;
261     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_INCORRECT_PEM_ECDSA_CURVE):
262       s =
263         format (s, "PTLS_ERROR_INCORRECT_PEM_ECDSA_CURVE");
264       break;
265     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_INCORRECT_PEM_ECDSA_KEYSIZE):
266       s =
267         format (s, "PTLS_ERROR_INCORRECT_PEM_ECDSA_KEYSIZE");
268       break;
269     case QUICLY_TRANSPORT_ERROR_TLS_ALERT_BASE + PTLS_ERROR_TO_ALERT (PTLS_ERROR_INCORRECT_ASN1_ECDSA_KEY_SYNTAX):
270       s =
271         format (s, "PTLS_ERROR_INCORRECT_ASN1_ECDSA_KEY_SYNTAX");
272       break;
273     default:
274       s = format (s, "unknown error 0x%lx", code);
275       break;
276     }
277   return s;
278 }
279
280 static u32
281 quic_ctx_alloc (u32 thread_index)
282 {
283   quic_main_t *qm = &quic_main;
284   quic_ctx_t *ctx;
285
286   pool_get (qm->ctx_pool[thread_index], ctx);
287
288   memset (ctx, 0, sizeof (quic_ctx_t));
289   ctx->c_thread_index = thread_index;
290   QUIC_DBG (1, "Allocated quic_ctx %u on thread %u",
291             ctx - qm->ctx_pool[thread_index], thread_index);
292   return ctx - qm->ctx_pool[thread_index];
293 }
294
295 static void
296 quic_ctx_free (quic_ctx_t * ctx)
297 {
298   QUIC_DBG (2, "Free ctx %u", ctx->c_c_index);
299   u32 thread_index = ctx->c_thread_index;
300   if (CLIB_DEBUG)
301     memset (ctx, 0xfb, sizeof (*ctx));
302   pool_put (quic_main.ctx_pool[thread_index], ctx);
303 }
304
305 static quic_ctx_t *
306 quic_ctx_get (u32 ctx_index, u32 thread_index)
307 {
308   return pool_elt_at_index (quic_main.ctx_pool[thread_index], ctx_index);
309 }
310
311 static quic_ctx_t *
312 quic_ctx_get_if_valid (u32 ctx_index, u32 thread_index)
313 {
314   if (pool_is_free_index (quic_main.ctx_pool[thread_index], ctx_index))
315     return 0;
316   return pool_elt_at_index (quic_main.ctx_pool[thread_index], ctx_index);
317 }
318
319 static quic_ctx_t *
320 quic_get_conn_ctx (quicly_conn_t * conn)
321 {
322   u64 conn_data;
323   conn_data = (u64) * quicly_get_data (conn);
324   return quic_ctx_get (conn_data & UINT32_MAX, conn_data >> 32);
325 }
326
327 static void
328 quic_store_conn_ctx (quicly_conn_t * conn, quic_ctx_t * ctx)
329 {
330   *quicly_get_data (conn) =
331     (void *) (((u64) ctx->c_thread_index) << 32 | (u64) ctx->c_c_index);
332 }
333
334 static inline int
335 quic_ctx_is_stream (quic_ctx_t * ctx)
336 {
337   return (ctx->flags & QUIC_F_IS_STREAM);
338 }
339
340 static inline int
341 quic_ctx_is_listener (quic_ctx_t * ctx)
342 {
343   return (ctx->flags & QUIC_F_IS_LISTENER);
344 }
345
346 static session_t *
347 get_stream_session_from_stream (quicly_stream_t * stream)
348 {
349   quic_ctx_t *ctx;
350   quic_stream_data_t *stream_data;
351
352   stream_data = (quic_stream_data_t *) stream->data;
353   ctx = quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
354   return session_get (ctx->c_s_index, stream_data->thread_index);
355 }
356
357 static inline void
358 quic_make_connection_key (clib_bihash_kv_16_8_t * kv,
359                           const quicly_cid_plaintext_t * id)
360 {
361   kv->key[0] = ((u64) id->master_id) << 32 | (u64) id->thread_id;
362   kv->key[1] = id->node_id;
363 }
364
365 static int
366 quic_sendable_packet_count (session_t * udp_session)
367 {
368   u32 max_enqueue;
369   u32 packet_size = QUIC_MAX_PACKET_SIZE + SESSION_CONN_HDR_LEN;
370   max_enqueue = svm_fifo_max_enqueue (udp_session->tx_fifo);
371   return clib_min (max_enqueue / packet_size, QUIC_SEND_PACKET_VEC_SIZE);
372 }
373
374
375 static void
376 quic_ack_rx_data (session_t * stream_session)
377 {
378   u32 max_deq;
379   quic_ctx_t *sctx;
380   svm_fifo_t *f;
381   quicly_stream_t *stream;
382   quic_stream_data_t *stream_data;
383
384   sctx =
385     quic_ctx_get (stream_session->connection_index,
386                   stream_session->thread_index);
387   ASSERT (quic_ctx_is_stream (sctx));
388   stream = sctx->c_quic_ctx_id.stream;
389   stream_data = (quic_stream_data_t *) stream->data;
390
391   f = stream_session->rx_fifo;
392   max_deq = svm_fifo_max_dequeue (f);
393
394   ASSERT (stream_data->app_rx_data_len >= max_deq);
395   quicly_stream_sync_recvbuf (stream, stream_data->app_rx_data_len - max_deq);
396   QUIC_DBG (3, "Acking %u bytes", stream_data->app_rx_data_len - max_deq);
397   stream_data->app_rx_data_len = max_deq;
398 }
399
400 static void
401 quic_disconnect_transport (quic_ctx_t * ctx)
402 {
403   QUIC_DBG (2, "Disconnecting transport 0x%lx", ctx->udp_session_handle);
404   vnet_disconnect_args_t a = {
405     .handle = ctx->udp_session_handle,
406     .app_index = quic_main.app_index,
407   };
408
409   if (vnet_disconnect_session (&a))
410     clib_warning ("UDP session 0x%lx disconnect errored",
411                   ctx->udp_session_handle);
412 }
413
414 static void
415 quic_connection_closed (u32 ctx_index, u32 thread_index, u8 notify_transport)
416 {
417   QUIC_DBG (2, "QUIC connection closed");
418   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
419   clib_bihash_kv_16_8_t kv;
420   quicly_conn_t *conn;
421   quic_ctx_t *ctx;
422
423   ctx = quic_ctx_get (ctx_index, thread_index);
424   ASSERT (!quic_ctx_is_stream (ctx));
425   /*  TODO if connection is not established, just delete the session? */
426
427   /*  Stop the timer */
428   if (ctx->timer_handle != QUIC_TIMER_HANDLE_INVALID)
429     {
430       tw = &quic_main.wrk_ctx[thread_index].timer_wheel;
431       tw_timer_stop_1t_3w_1024sl_ov (tw, ctx->timer_handle);
432     }
433
434   /*  Delete the connection from the connection map */
435   conn = ctx->c_quic_ctx_id.conn;
436   quic_make_connection_key (&kv, quicly_get_master_id (conn));
437   QUIC_DBG (2, "Deleting conn with id %lu %lu", kv.key[0], kv.key[1]);
438   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 0 /* is_add */ );
439
440   quic_disconnect_transport (ctx);
441   if (notify_transport)
442     session_transport_closing_notify (&ctx->connection);
443   else
444     session_transport_delete_notify (&ctx->connection);
445   /*  Do not try to send anything anymore */
446   quicly_free (ctx->c_quic_ctx_id.conn);
447   ctx->c_quic_ctx_id.conn = NULL;
448   quic_ctx_free (ctx);
449 }
450
451 static int
452 quic_send_datagram (session_t * udp_session, quicly_datagram_t * packet)
453 {
454   u32 max_enqueue;
455   session_dgram_hdr_t hdr;
456   u32 len, ret;
457   svm_fifo_t *f;
458   transport_connection_t *tc;
459
460   len = packet->data.len;
461   f = udp_session->tx_fifo;
462   tc = session_get_transport (udp_session);
463   max_enqueue = svm_fifo_max_enqueue (f);
464   if (max_enqueue < SESSION_CONN_HDR_LEN + len)
465     {
466       QUIC_DBG (1, "Too much data to send, max_enqueue %u, len %u",
467                 max_enqueue, len + SESSION_CONN_HDR_LEN);
468       return QUIC_ERROR_FULL_FIFO;
469     }
470
471   /*  Build packet header for fifo */
472   hdr.data_length = len;
473   hdr.data_offset = 0;
474   hdr.is_ip4 = tc->is_ip4;
475   clib_memcpy (&hdr.lcl_ip, &tc->lcl_ip, sizeof (ip46_address_t));
476   hdr.lcl_port = tc->lcl_port;
477
478   /*  Read dest address from quicly-provided sockaddr */
479   if (hdr.is_ip4)
480     {
481       ASSERT (packet->sa.sa_family == AF_INET);
482       struct sockaddr_in *sa4 = (struct sockaddr_in *) &packet->sa;
483       hdr.rmt_port = sa4->sin_port;
484       hdr.rmt_ip.ip4.as_u32 = sa4->sin_addr.s_addr;
485     }
486   else
487     {
488       ASSERT (packet->sa.sa_family == AF_INET6);
489       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &packet->sa;
490       hdr.rmt_port = sa6->sin6_port;
491       clib_memcpy (&hdr.rmt_ip.ip6, &sa6->sin6_addr, 16);
492     }
493
494   ret = svm_fifo_enqueue (f, sizeof (hdr), (u8 *) & hdr);
495   if (ret != sizeof (hdr))
496     {
497       QUIC_DBG (1, "Not enough space to enqueue header");
498       return QUIC_ERROR_FULL_FIFO;
499     }
500   ret = svm_fifo_enqueue (f, len, packet->data.base);
501   if (ret != len)
502     {
503       QUIC_DBG (1, "Not enough space to enqueue payload");
504       return QUIC_ERROR_FULL_FIFO;
505     }
506   return 0;
507 }
508
509 static int
510 quic_send_packets (quic_ctx_t * ctx)
511 {
512   quicly_datagram_t *packets[QUIC_SEND_PACKET_VEC_SIZE];
513   session_t *udp_session;
514   quicly_conn_t *conn;
515   size_t num_packets, i, max_packets;
516   quicly_context_t *quicly_context;
517   app_worker_t *app_wrk;
518   application_t *app;
519   int err = 0;
520
521   /* We have sctx, get qctx */
522   if (quic_ctx_is_stream (ctx))
523     ctx =
524       quic_ctx_get (ctx->c_quic_ctx_id.quic_connection_ctx_id,
525                     ctx->c_thread_index);
526
527   ASSERT (!quic_ctx_is_stream (ctx));
528
529   udp_session = session_get_from_handle_if_valid (ctx->udp_session_handle);
530   if (!udp_session)
531     goto quicly_error;
532
533   conn = ctx->c_quic_ctx_id.conn;
534
535   if (!conn)
536     return 0;
537
538   /* TODO : quicly can assert it can send min_packets up to 2 */
539   if (quic_sendable_packet_count (udp_session) < 2)
540     goto stop_sending;
541
542   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
543   if (!app_wrk)
544     {
545       clib_warning ("Tried to send packets on non existing app worker %u",
546                     ctx->parent_app_wrk_id);
547       quic_connection_closed (ctx->c_c_index, ctx->c_thread_index,
548                               1 /* notify_transport */ );
549       return 1;
550     }
551   app = application_get (app_wrk->app_index);
552
553   quicly_context = (quicly_context_t *) app->quicly_ctx;
554   do
555     {
556       max_packets = quic_sendable_packet_count (udp_session);
557       if (max_packets < 2)
558         break;
559       num_packets = max_packets;
560       if ((err = quicly_send (conn, packets, &num_packets)))
561         goto quicly_error;
562
563       for (i = 0; i != num_packets; ++i)
564         {
565           if ((err = quic_send_datagram (udp_session, packets[i])))
566             goto quicly_error;
567
568           quicly_context->packet_allocator->
569             free_packet (quicly_context->packet_allocator, packets[i]);
570         }
571     }
572   while (num_packets > 0 && num_packets == max_packets);
573
574 stop_sending:
575   if (svm_fifo_set_event (udp_session->tx_fifo))
576     if ((err =
577          session_send_io_evt_to_thread (udp_session->tx_fifo,
578                                         SESSION_IO_EVT_TX)))
579       clib_warning ("Event enqueue errored %d", err);
580
581   QUIC_DBG (3, "%u[TX] %u[RX]", svm_fifo_max_dequeue (udp_session->tx_fifo),
582             svm_fifo_max_dequeue (udp_session->rx_fifo));
583   quic_update_timer (ctx);
584   return 0;
585
586 quicly_error:
587   if (err && err != QUICLY_ERROR_PACKET_IGNORED
588       && err != QUICLY_ERROR_FREE_CONNECTION)
589     clib_warning ("Quic error '%U'.", quic_format_err, err);
590   quic_connection_closed (ctx->c_c_index, ctx->c_thread_index,
591                           1 /* notify_transport */ );
592   return 1;
593 }
594
595 /*****************************************************************************
596  *
597  * START QUICLY CALLBACKS
598  * Called from QUIC lib
599  *
600  *****************************************************************************/
601
602 static void
603 quic_on_stream_destroy (quicly_stream_t * stream, int err)
604 {
605   quic_stream_data_t *stream_data = (quic_stream_data_t *) stream->data;
606   quic_ctx_t *sctx =
607     quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
608   session_t *stream_session =
609     session_get (sctx->c_s_index, sctx->c_thread_index);
610   QUIC_DBG (2, "DESTROYED_STREAM: session 0x%lx (%U)",
611             session_handle (stream_session), quic_format_err, err);
612
613   stream_session->session_state = SESSION_STATE_CLOSED;
614   session_transport_delete_notify (&sctx->connection);
615
616   quic_ctx_free (sctx);
617   free (stream->data);
618 }
619
620 static int
621 quic_on_stop_sending (quicly_stream_t * stream, int err)
622 {
623 #if QUIC_DEBUG >= 2
624   quic_stream_data_t *stream_data = (quic_stream_data_t *) stream->data;
625   quic_ctx_t *sctx =
626     quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
627   session_t *stream_session =
628     session_get (sctx->c_s_index, sctx->c_thread_index);
629   clib_warning ("(NOT IMPLEMENTD) STOP_SENDING: session 0x%lx (%U)",
630                 session_handle (stream_session), quic_format_err, err);
631 #endif
632   /* TODO : handle STOP_SENDING */
633   return 0;
634 }
635
636 static int
637 quic_on_receive_reset (quicly_stream_t * stream, int err)
638 {
639   quic_stream_data_t *stream_data = (quic_stream_data_t *) stream->data;
640   quic_ctx_t *sctx =
641     quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
642 #if QUIC_DEBUG >= 2
643   session_t *stream_session =
644     session_get (sctx->c_s_index, sctx->c_thread_index);
645   clib_warning ("RESET_STREAM: session 0x%lx (%U)",
646                 session_handle (stream_session), quic_format_err, err);
647 #endif
648   session_transport_closing_notify (&sctx->connection);
649   return 0;
650 }
651
652 static int
653 quic_on_receive (quicly_stream_t * stream, size_t off, const void *src,
654                  size_t len)
655 {
656   QUIC_DBG (3, "received data: %lu bytes, offset %lu", len, off);
657   u32 max_enq;
658   quic_ctx_t *sctx;
659   session_t *stream_session;
660   app_worker_t *app_wrk;
661   svm_fifo_t *f;
662   quic_stream_data_t *stream_data;
663   int rlen;
664
665   stream_data = (quic_stream_data_t *) stream->data;
666   sctx = quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
667   stream_session = session_get (sctx->c_s_index, stream_data->thread_index);
668   f = stream_session->rx_fifo;
669
670   max_enq = svm_fifo_max_enqueue_prod (f);
671   QUIC_DBG (3, "Enqueuing %u at off %u in %u space", len, off, max_enq);
672   if (off - stream_data->app_rx_data_len + len > max_enq)
673     {
674       QUIC_DBG (1, "Error RX fifo is full");
675       return 1;
676     }
677   if (off == stream_data->app_rx_data_len)
678     {
679       /* Streams live on the same thread so (f, stream_data) should stay consistent */
680       rlen = svm_fifo_enqueue (f, len, (u8 *) src);
681       stream_data->app_rx_data_len += rlen;
682       ASSERT (rlen >= len);
683       app_wrk = app_worker_get_if_valid (stream_session->app_wrk_index);
684       if (PREDICT_TRUE (app_wrk != 0))
685         app_worker_lock_and_send_event (app_wrk, stream_session,
686                                         SESSION_IO_EVT_RX);
687       quic_ack_rx_data (stream_session);
688     }
689   else
690     {
691       rlen =
692         svm_fifo_enqueue_with_offset (f, off - stream_data->app_rx_data_len,
693                                       len, (u8 *) src);
694       ASSERT (rlen == 0);
695     }
696   return 0;
697 }
698
699 void
700 quic_fifo_egress_shift (quicly_stream_t * stream, size_t delta)
701 {
702   session_t *stream_session;
703   svm_fifo_t *f;
704   int rv;
705
706   stream_session = get_stream_session_from_stream (stream);
707   f = stream_session->tx_fifo;
708
709   rv = svm_fifo_dequeue_drop (f, delta);
710   ASSERT (rv == delta);
711   quicly_stream_sync_sendbuf (stream, 0);
712 }
713
714 int
715 quic_fifo_egress_emit (quicly_stream_t * stream, size_t off, void *dst,
716                        size_t * len, int *wrote_all)
717 {
718   session_t *stream_session;
719   svm_fifo_t *f;
720   u32 deq_max, first_deq, max_rd_chunk, rem_offset;
721
722   stream_session = get_stream_session_from_stream (stream);
723   f = stream_session->tx_fifo;
724
725   QUIC_DBG (3, "Emitting %u, offset %u", *len, off);
726
727   deq_max = svm_fifo_max_dequeue_cons (f);
728   ASSERT (off <= deq_max);
729   if (off + *len < deq_max)
730     {
731       *wrote_all = 0;
732     }
733   else
734     {
735       *wrote_all = 1;
736       *len = deq_max - off;
737       QUIC_DBG (3, "Wrote ALL, %u", *len);
738     }
739
740   /* TODO, use something like : return svm_fifo_peek (f, off, *len, dst); */
741   max_rd_chunk = svm_fifo_max_read_chunk (f);
742
743   first_deq = 0;
744   if (off < max_rd_chunk)
745     {
746       first_deq = clib_min (*len, max_rd_chunk - off);
747       clib_memcpy_fast (dst, svm_fifo_head (f) + off, first_deq);
748     }
749
750   if (max_rd_chunk < off + *len)
751     {
752       rem_offset = max_rd_chunk < off ? off - max_rd_chunk : 0;
753       clib_memcpy_fast (dst + first_deq, f->head_chunk->data + rem_offset,
754                         *len - first_deq);
755     }
756
757   return 0;
758 }
759
760 static const quicly_stream_callbacks_t quic_stream_callbacks = {
761   .on_destroy = quic_on_stream_destroy,
762   .on_send_shift = quic_fifo_egress_shift,
763   .on_send_emit = quic_fifo_egress_emit,
764   .on_send_stop = quic_on_stop_sending,
765   .on_receive = quic_on_receive,
766   .on_receive_reset = quic_on_receive_reset
767 };
768
769 static void
770 quic_accept_stream (void *s)
771 {
772   quicly_stream_t *stream = (quicly_stream_t *) s;
773   session_t *stream_session, *quic_session;
774   quic_stream_data_t *stream_data;
775   app_worker_t *app_wrk;
776   quic_ctx_t *qctx, *sctx;
777   u32 sctx_id;
778   int rv;
779
780   sctx_id = quic_ctx_alloc (vlib_get_thread_index ());
781
782   qctx = quic_get_conn_ctx (stream->conn);
783
784   stream_session = session_alloc (qctx->c_thread_index);
785   QUIC_DBG (2, "ACCEPTED stream_session 0x%lx ctx %u",
786             session_handle (stream_session), sctx_id);
787   sctx = quic_ctx_get (sctx_id, qctx->c_thread_index);
788   sctx->parent_app_wrk_id = qctx->parent_app_wrk_id;
789   sctx->parent_app_id = qctx->parent_app_id;
790   sctx->c_quic_ctx_id.quic_connection_ctx_id = qctx->c_c_index;
791   sctx->c_c_index = sctx_id;
792   sctx->c_s_index = stream_session->session_index;
793   sctx->c_quic_ctx_id.stream = stream;
794   sctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
795   sctx->flags |= QUIC_F_IS_STREAM;
796
797   stream_data = (quic_stream_data_t *) stream->data;
798   stream_data->ctx_id = sctx_id;
799   stream_data->thread_index = sctx->c_thread_index;
800   stream_data->app_rx_data_len = 0;
801
802   sctx->c_s_index = stream_session->session_index;
803   stream_session->session_state = SESSION_STATE_CREATED;
804   stream_session->app_wrk_index = sctx->parent_app_wrk_id;
805   stream_session->connection_index = sctx->c_c_index;
806   stream_session->session_type =
807     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
808                                     qctx->c_quic_ctx_id.udp_is_ip4);
809   quic_session = session_get (qctx->c_s_index, qctx->c_thread_index);
810   stream_session->listener_handle = listen_session_get_handle (quic_session);
811
812   app_wrk = app_worker_get (stream_session->app_wrk_index);
813   if ((rv = app_worker_init_connected (app_wrk, stream_session)))
814     {
815       QUIC_DBG (1, "failed to allocate fifos");
816       session_free (stream_session);
817       quicly_reset_stream (stream, QUIC_APP_ALLOCATION_ERROR);
818       return;
819     }
820   svm_fifo_add_want_deq_ntf (stream_session->rx_fifo,
821                              SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL |
822                              SVM_FIFO_WANT_DEQ_NOTIF_IF_EMPTY);
823
824   rv = app_worker_accept_notify (app_wrk, stream_session);
825   if (rv)
826     {
827       QUIC_DBG (1, "failed to notify accept worker app");
828       session_free_w_fifos (stream_session);
829       quicly_reset_stream (stream, QUIC_APP_ACCEPT_NOTIFY_ERROR);
830       return;
831     }
832 }
833
834 static int
835 quic_on_stream_open (quicly_stream_open_t * self, quicly_stream_t * stream)
836 {
837   QUIC_DBG (2, "on_stream_open called");
838   stream->data = malloc (sizeof (quic_stream_data_t));
839   stream->callbacks = &quic_stream_callbacks;
840   /* Notify accept on parent qsession, but only if this is not a locally
841    * initiated stream */
842   if (!quicly_stream_is_self_initiated (stream))
843     {
844       quic_accept_stream (stream);
845     }
846   return 0;
847 }
848
849 static void
850 quic_on_closed_by_peer (quicly_closed_by_peer_t * self, quicly_conn_t * conn,
851                         int code, uint64_t frame_type,
852                         const char *reason, size_t reason_len)
853 {
854   quic_ctx_t *ctx = quic_get_conn_ctx (conn);
855 #if QUIC_DEBUG >= 2
856   session_t *quic_session = session_get (ctx->c_s_index, ctx->c_thread_index);
857   clib_warning ("Session 0x%lx closed by peer (%U) %.*s ",
858                 session_handle (quic_session), quic_format_err, code,
859                 reason_len, reason);
860 #endif
861   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_PASSIVE_CLOSING;
862   session_transport_closing_notify (&ctx->connection);
863 }
864
865 static quicly_stream_open_t on_stream_open = { &quic_on_stream_open };
866 static quicly_closed_by_peer_t on_closed_by_peer =
867   { &quic_on_closed_by_peer };
868
869
870 /*****************************************************************************
871  *
872  * END QUICLY CALLBACKS
873  *
874  *****************************************************************************/
875
876 /*****************************************************************************
877  *
878  * BEGIN TIMERS HANDLING
879  *
880  *****************************************************************************/
881
882 static int64_t
883 quic_get_thread_time (u8 thread_index)
884 {
885   return quic_main.wrk_ctx[thread_index].time_now;
886 }
887
888 static int64_t
889 quic_get_time (quicly_now_t * self)
890 {
891   u8 thread_index = vlib_get_thread_index ();
892   return quic_get_thread_time (thread_index);
893 }
894
895 static quicly_now_t quicly_vpp_now_cb = { quic_get_time };
896
897 static u32
898 quic_set_time_now (u32 thread_index)
899 {
900   vlib_main_t *vlib_main = vlib_get_main ();
901   f64 time = vlib_time_now (vlib_main);
902   quic_main.wrk_ctx[thread_index].time_now = (int64_t) (time * 1000.f);
903   return quic_main.wrk_ctx[thread_index].time_now;
904 }
905
906 /* Transport proto callback */
907 static void
908 quic_update_time (f64 now, u8 thread_index)
909 {
910   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
911
912   tw = &quic_main.wrk_ctx[thread_index].timer_wheel;
913   quic_set_time_now (thread_index);
914   tw_timer_expire_timers_1t_3w_1024sl_ov (tw, now);
915 }
916
917 static void
918 quic_timer_expired (u32 conn_index)
919 {
920   quic_ctx_t *ctx;
921   QUIC_DBG (4, "Timer expired for conn %u at %ld", conn_index,
922             quic_get_time (NULL));
923   ctx = quic_ctx_get (conn_index, vlib_get_thread_index ());
924   ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
925   quic_send_packets (ctx);
926 }
927
928 static void
929 quic_update_timer (quic_ctx_t * ctx)
930 {
931   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
932   int64_t next_timeout, next_interval;
933   session_t *quic_session;
934
935   /*  This timeout is in ms which is the unit of our timer */
936   next_timeout = quicly_get_first_timeout (ctx->c_quic_ctx_id.conn);
937   next_interval = next_timeout - quic_get_time (NULL);
938
939   if (next_timeout == 0 || next_interval <= 0)
940     {
941       if (ctx->c_s_index == QUIC_SESSION_INVALID)
942         {
943           next_interval = 1;
944         }
945       else
946         {
947           quic_session = session_get (ctx->c_s_index, ctx->c_thread_index);
948           if (svm_fifo_set_event (quic_session->tx_fifo))
949             session_send_io_evt_to_thread_custom (quic_session,
950                                                   quic_session->thread_index,
951                                                   SESSION_IO_EVT_BUILTIN_TX);
952           return;
953         }
954     }
955
956   tw = &quic_main.wrk_ctx[vlib_get_thread_index ()].timer_wheel;
957
958   QUIC_DBG (4, "Timer set to %ld (int %ld) for ctx %u", next_timeout,
959             next_interval, ctx->c_c_index);
960
961   if (ctx->timer_handle == QUIC_TIMER_HANDLE_INVALID)
962     {
963       if (next_timeout == INT64_MAX)
964         {
965           QUIC_DBG (4, "timer for ctx %u already stopped", ctx->c_c_index);
966           return;
967         }
968       ctx->timer_handle =
969         tw_timer_start_1t_3w_1024sl_ov (tw, ctx->c_c_index, 0, next_interval);
970     }
971   else
972     {
973       if (next_timeout == INT64_MAX)
974         {
975           tw_timer_stop_1t_3w_1024sl_ov (tw, ctx->timer_handle);
976           ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
977           QUIC_DBG (4, "Stopping timer for ctx %u", ctx->c_c_index);
978         }
979       else
980         tw_timer_update_1t_3w_1024sl_ov (tw, ctx->timer_handle,
981                                          next_interval);
982     }
983   return;
984 }
985
986 static void
987 quic_expired_timers_dispatch (u32 * expired_timers)
988 {
989   int i;
990
991   for (i = 0; i < vec_len (expired_timers); i++)
992     {
993       quic_timer_expired (expired_timers[i]);
994     }
995 }
996
997 /*****************************************************************************
998  *
999  * END TIMERS HANDLING
1000  *
1001  *****************************************************************************/
1002
1003 /* single-entry session cache */
1004 struct st_util_session_cache_t
1005 {
1006   ptls_encrypt_ticket_t super;
1007   uint8_t id[32];
1008   ptls_iovec_t data;
1009 };
1010
1011 static int
1012 encrypt_ticket_cb (ptls_encrypt_ticket_t * _self, ptls_t * tls,
1013                    int is_encrypt, ptls_buffer_t * dst, ptls_iovec_t src)
1014 {
1015   struct st_util_session_cache_t *self = (void *) _self;
1016   int ret;
1017
1018   if (is_encrypt)
1019     {
1020
1021       /* replace the cached entry along with a newly generated session id */
1022       free (self->data.base);
1023       if ((self->data.base = malloc (src.len)) == NULL)
1024         return PTLS_ERROR_NO_MEMORY;
1025
1026       ptls_get_context (tls)->random_bytes (self->id, sizeof (self->id));
1027       memcpy (self->data.base, src.base, src.len);
1028       self->data.len = src.len;
1029
1030       /* store the session id in buffer */
1031       if ((ret = ptls_buffer_reserve (dst, sizeof (self->id))) != 0)
1032         return ret;
1033       memcpy (dst->base + dst->off, self->id, sizeof (self->id));
1034       dst->off += sizeof (self->id);
1035
1036     }
1037   else
1038     {
1039
1040       /* check if session id is the one stored in cache */
1041       if (src.len != sizeof (self->id))
1042         return PTLS_ERROR_SESSION_NOT_FOUND;
1043       if (memcmp (self->id, src.base, sizeof (self->id)) != 0)
1044         return PTLS_ERROR_SESSION_NOT_FOUND;
1045
1046       /* return the cached value */
1047       if ((ret = ptls_buffer_reserve (dst, self->data.len)) != 0)
1048         return ret;
1049       memcpy (dst->base + dst->off, self->data.base, self->data.len);
1050       dst->off += self->data.len;
1051     }
1052
1053   return 0;
1054 }
1055
1056 /* *INDENT-OFF* */
1057 static struct st_util_session_cache_t sc = {
1058   .super = {
1059     .cb = encrypt_ticket_cb,
1060   },
1061 };
1062
1063 static ptls_context_t quic_tlsctx = {
1064   .random_bytes = ptls_openssl_random_bytes,
1065   .get_time = &ptls_get_time,
1066   .key_exchanges = ptls_openssl_key_exchanges,
1067   .cipher_suites = ptls_openssl_cipher_suites,
1068   .certificates = {
1069     .list = NULL,
1070     .count = 0
1071   },
1072   .esni = NULL,
1073   .on_client_hello = NULL,
1074   .emit_certificate = NULL,
1075   .sign_certificate = NULL,
1076   .verify_certificate = NULL,
1077   .ticket_lifetime = 86400,
1078   .max_early_data_size = 8192,
1079   .hkdf_label_prefix__obsolete = NULL,
1080   .require_dhe_on_psk = 1,
1081   .encrypt_ticket = &sc.super,
1082 };
1083 /* *INDENT-ON* */
1084
1085 static int
1086 ptls_compare_separator_line (const char *line, const char *begin_or_end,
1087                              const char *label)
1088 {
1089   int ret = strncmp (line, "-----", 5);
1090   size_t text_index = 5;
1091
1092   if (ret == 0)
1093     {
1094       size_t begin_or_end_length = strlen (begin_or_end);
1095       ret = strncmp (line + text_index, begin_or_end, begin_or_end_length);
1096       text_index += begin_or_end_length;
1097     }
1098
1099   if (ret == 0)
1100     {
1101       ret = line[text_index] - ' ';
1102       text_index++;
1103     }
1104
1105   if (ret == 0)
1106     {
1107       size_t label_length = strlen (label);
1108       ret = strncmp (line + text_index, label, label_length);
1109       text_index += label_length;
1110     }
1111
1112   if (ret == 0)
1113     {
1114       ret = strncmp (line + text_index, "-----", 5);
1115     }
1116
1117   return ret;
1118 }
1119
1120 static int
1121 ptls_get_bio_pem_object (BIO * bio, const char *label, ptls_buffer_t * buf)
1122 {
1123   int ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
1124   char line[256];
1125   ptls_base64_decode_state_t state;
1126
1127   /* Get the label on a line by itself */
1128   while (BIO_gets (bio, line, 256))
1129     {
1130       if (ptls_compare_separator_line (line, "BEGIN", label) == 0)
1131         {
1132           ret = 0;
1133           ptls_base64_decode_init (&state);
1134           break;
1135         }
1136     }
1137   /* Get the data in the buffer */
1138   while (ret == 0 && BIO_gets (bio, line, 256))
1139     {
1140       if (ptls_compare_separator_line (line, "END", label) == 0)
1141         {
1142           if (state.status == PTLS_BASE64_DECODE_DONE
1143               || (state.status == PTLS_BASE64_DECODE_IN_PROGRESS
1144                   && state.nbc == 0))
1145             {
1146               ret = 0;
1147             }
1148           else
1149             {
1150               ret = PTLS_ERROR_INCORRECT_BASE64;
1151             }
1152           break;
1153         }
1154       else
1155         {
1156           ret = ptls_base64_decode (line, &state, buf);
1157         }
1158     }
1159
1160   return ret;
1161 }
1162
1163 static int
1164 ptls_load_bio_pem_objects (BIO * bio, const char *label, ptls_iovec_t * list,
1165                            size_t list_max, size_t * nb_objects)
1166 {
1167   int ret = 0;
1168   size_t count = 0;
1169
1170   *nb_objects = 0;
1171
1172   if (ret == 0)
1173     {
1174       while (count < list_max)
1175         {
1176           ptls_buffer_t buf;
1177
1178           ptls_buffer_init (&buf, "", 0);
1179
1180           ret = ptls_get_bio_pem_object (bio, label, &buf);
1181
1182           if (ret == 0)
1183             {
1184               if (buf.off > 0 && buf.is_allocated)
1185                 {
1186                   list[count].base = buf.base;
1187                   list[count].len = buf.off;
1188                   count++;
1189                 }
1190               else
1191                 {
1192                   ptls_buffer_dispose (&buf);
1193                 }
1194             }
1195           else
1196             {
1197               ptls_buffer_dispose (&buf);
1198               break;
1199             }
1200         }
1201     }
1202
1203   if (ret == PTLS_ERROR_PEM_LABEL_NOT_FOUND && count > 0)
1204     {
1205       ret = 0;
1206     }
1207
1208   *nb_objects = count;
1209
1210   return ret;
1211 }
1212
1213 #define PTLS_MAX_CERTS_IN_CONTEXT 16
1214
1215 static int
1216 ptls_load_bio_certificates (ptls_context_t * ctx, BIO * bio)
1217 {
1218   int ret = 0;
1219
1220   ctx->certificates.list =
1221     (ptls_iovec_t *) malloc (PTLS_MAX_CERTS_IN_CONTEXT *
1222                              sizeof (ptls_iovec_t));
1223
1224   if (ctx->certificates.list == NULL)
1225     {
1226       ret = PTLS_ERROR_NO_MEMORY;
1227     }
1228   else
1229     {
1230       ret =
1231         ptls_load_bio_pem_objects (bio, "CERTIFICATE", ctx->certificates.list,
1232                                    PTLS_MAX_CERTS_IN_CONTEXT,
1233                                    &ctx->certificates.count);
1234     }
1235
1236   return ret;
1237 }
1238
1239 static inline void
1240 load_bio_certificate_chain (ptls_context_t * ctx, const char *cert_data)
1241 {
1242   BIO *cert_bio;
1243   cert_bio = BIO_new_mem_buf (cert_data, -1);
1244   if (ptls_load_bio_certificates (ctx, cert_bio) != 0)
1245     {
1246       BIO_free (cert_bio);
1247       fprintf (stderr, "failed to load certificate:%s\n", strerror (errno));
1248       exit (1);
1249     }
1250   BIO_free (cert_bio);
1251 }
1252
1253 static inline void
1254 load_bio_private_key (ptls_context_t * ctx, const char *pk_data)
1255 {
1256   static ptls_openssl_sign_certificate_t sc;
1257   EVP_PKEY *pkey;
1258   BIO *key_bio;
1259
1260   key_bio = BIO_new_mem_buf (pk_data, -1);
1261   pkey = PEM_read_bio_PrivateKey (key_bio, NULL, NULL, NULL);
1262   BIO_free (key_bio);
1263
1264   if (pkey == NULL)
1265     {
1266       fprintf (stderr, "failed to read private key from app configuration\n");
1267       exit (1);
1268     }
1269
1270   ptls_openssl_init_sign_certificate (&sc, pkey);
1271   EVP_PKEY_free (pkey);
1272
1273   ctx->sign_certificate = &sc.super;
1274 }
1275
1276 static void
1277 allocate_quicly_ctx (application_t * app, u8 is_client)
1278 {
1279   struct
1280   {
1281     quicly_context_t _;
1282     char cid_key[17];
1283   } *ctx_data;
1284   quicly_context_t *quicly_ctx;
1285   ptls_iovec_t key_vec;
1286   QUIC_DBG (2, "Called allocate_quicly_ctx");
1287
1288   if (app->quicly_ctx)
1289     {
1290       QUIC_DBG (1, "Trying to reallocate quicly_ctx");
1291       return;
1292     }
1293
1294   ctx_data = malloc (sizeof (*ctx_data));
1295   quicly_ctx = &ctx_data->_;
1296   app->quicly_ctx = (u64 *) quicly_ctx;
1297   memcpy (quicly_ctx, &quicly_spec_context, sizeof (quicly_context_t));
1298
1299   quicly_ctx->max_packet_size = QUIC_MAX_PACKET_SIZE;
1300   quicly_ctx->tls = &quic_tlsctx;
1301   quicly_ctx->stream_open = &on_stream_open;
1302   quicly_ctx->closed_by_peer = &on_closed_by_peer;
1303   quicly_ctx->now = &quicly_vpp_now_cb;
1304
1305   quicly_amend_ptls_context (quicly_ctx->tls);
1306
1307   quicly_ctx->event_log.mask = 0;       /* logs */
1308   quicly_ctx->event_log.cb = quicly_new_default_event_logger (stderr);
1309
1310   quicly_ctx->transport_params.max_data = QUIC_INT_MAX;
1311   quicly_ctx->transport_params.max_streams_uni = QUIC_INT_MAX;
1312   quicly_ctx->transport_params.max_streams_bidi = QUIC_INT_MAX;
1313   quicly_ctx->transport_params.max_stream_data.bidi_local = (QUIC_FIFO_SIZE - 1);       /* max_enq is SIZE - 1 */
1314   quicly_ctx->transport_params.max_stream_data.bidi_remote = (QUIC_FIFO_SIZE - 1);      /* max_enq is SIZE - 1 */
1315   quicly_ctx->transport_params.max_stream_data.uni = QUIC_INT_MAX;
1316
1317   quicly_ctx->tls->random_bytes (ctx_data->cid_key, 16);
1318   ctx_data->cid_key[16] = 0;
1319   key_vec = ptls_iovec_init (ctx_data->cid_key, strlen (ctx_data->cid_key));
1320   quicly_ctx->cid_encryptor =
1321     quicly_new_default_cid_encryptor (&ptls_openssl_bfecb,
1322                                       &ptls_openssl_sha256, key_vec);
1323   if (!is_client && app->tls_key != NULL && app->tls_cert != NULL)
1324     {
1325       load_bio_private_key (quicly_ctx->tls, (char *) app->tls_key);
1326       load_bio_certificate_chain (quicly_ctx->tls, (char *) app->tls_cert);
1327     }
1328 }
1329
1330 /*****************************************************************************
1331  *
1332  * BEGIN TRANSPORT PROTO FUNCTIONS
1333  *
1334  *****************************************************************************/
1335
1336 static int
1337 quic_connect_new_stream (session_endpoint_cfg_t * sep)
1338 {
1339   uint64_t quic_session_handle;
1340   session_t *quic_session, *stream_session;
1341   quic_stream_data_t *stream_data;
1342   quicly_stream_t *stream;
1343   quicly_conn_t *conn;
1344   app_worker_t *app_wrk;
1345   quic_ctx_t *qctx, *sctx;
1346   u32 sctx_index;
1347   int rv;
1348
1349   /*  Find base session to which the user want to attach a stream */
1350   quic_session_handle = sep->transport_opts;
1351   QUIC_DBG (2, "Opening new stream (qsession %u)", sep->transport_opts);
1352   quic_session = session_get_from_handle (quic_session_handle);
1353
1354   if (quic_session->session_type !=
1355       session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC, sep->is_ip4))
1356     {
1357       QUIC_DBG (1, "received incompatible session");
1358       return -1;
1359     }
1360
1361   app_wrk = app_worker_get_if_valid (quic_session->app_wrk_index);
1362   if (!app_wrk)
1363     {
1364       QUIC_DBG (1, "Invalid app worker :(");
1365       return -1;
1366     }
1367
1368   sctx_index = quic_ctx_alloc (quic_session->thread_index);     /*  Allocate before we get pointers */
1369   sctx = quic_ctx_get (sctx_index, quic_session->thread_index);
1370   qctx =
1371     quic_ctx_get (quic_session->connection_index, quic_session->thread_index);
1372   if (quic_ctx_is_stream (qctx))
1373     {
1374       QUIC_DBG (1, "session is a stream");
1375       quic_ctx_free (sctx);
1376       return -1;
1377     }
1378
1379   sctx->parent_app_wrk_id = qctx->parent_app_wrk_id;
1380   sctx->parent_app_id = qctx->parent_app_id;
1381   sctx->c_quic_ctx_id.quic_connection_ctx_id = qctx->c_c_index;
1382   sctx->c_c_index = sctx_index;
1383   sctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1384   sctx->flags |= QUIC_F_IS_STREAM;
1385
1386   conn = qctx->c_quic_ctx_id.conn;
1387
1388   if (!conn || !quicly_connection_is_ready (conn))
1389     return -1;
1390
1391   if ((rv = quicly_open_stream (conn, &stream, 0 /* uni */ )))
1392     {
1393       QUIC_DBG (2, "Stream open failed with %d", rv);
1394       return -1;
1395     }
1396   sctx->c_quic_ctx_id.stream = stream;
1397
1398   QUIC_DBG (2, "Opened stream %d, creating session", stream->stream_id);
1399
1400   stream_session = session_alloc (qctx->c_thread_index);
1401   QUIC_DBG (2, "Allocated stream_session 0x%lx ctx %u",
1402             session_handle (stream_session), sctx_index);
1403   stream_session->app_wrk_index = app_wrk->wrk_index;
1404   stream_session->connection_index = sctx_index;
1405   stream_session->listener_handle = quic_session_handle;
1406   stream_session->session_type =
1407     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
1408                                     qctx->c_quic_ctx_id.udp_is_ip4);
1409
1410   sctx->c_s_index = stream_session->session_index;
1411
1412   if (app_worker_init_connected (app_wrk, stream_session))
1413     {
1414       QUIC_DBG (1, "failed to app_worker_init_connected");
1415       quicly_reset_stream (stream, QUIC_APP_ALLOCATION_ERROR);
1416       session_free_w_fifos (stream_session);
1417       quic_ctx_free (sctx);
1418       return app_worker_connect_notify (app_wrk, NULL, sep->opaque);
1419     }
1420
1421   svm_fifo_add_want_deq_ntf (stream_session->rx_fifo,
1422                              SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL |
1423                              SVM_FIFO_WANT_DEQ_NOTIF_IF_EMPTY);
1424
1425   stream_session->session_state = SESSION_STATE_READY;
1426   if (app_worker_connect_notify (app_wrk, stream_session, sep->opaque))
1427     {
1428       QUIC_DBG (1, "failed to notify app");
1429       quicly_reset_stream (stream, QUIC_APP_CONNECT_NOTIFY_ERROR);
1430       session_free_w_fifos (stream_session);
1431       quic_ctx_free (sctx);
1432       return -1;
1433     }
1434   stream_data = (quic_stream_data_t *) stream->data;
1435   stream_data->ctx_id = sctx->c_c_index;
1436   stream_data->thread_index = sctx->c_thread_index;
1437   stream_data->app_rx_data_len = 0;
1438   return 0;
1439 }
1440
1441 static int
1442 quic_connect_new_connection (session_endpoint_cfg_t * sep)
1443 {
1444   vnet_connect_args_t _cargs = { {}, }, *cargs = &_cargs;
1445   quic_main_t *qm = &quic_main;
1446   quic_ctx_t *ctx;
1447   app_worker_t *app_wrk;
1448   application_t *app;
1449   u32 ctx_index;
1450   int error;
1451
1452   ctx_index = quic_ctx_alloc (vlib_get_thread_index ());
1453   ctx = quic_ctx_get (ctx_index, vlib_get_thread_index ());
1454   ctx->parent_app_wrk_id = sep->app_wrk_index;
1455   ctx->c_s_index = QUIC_SESSION_INVALID;
1456   ctx->c_c_index = ctx_index;
1457   ctx->c_quic_ctx_id.udp_is_ip4 = sep->is_ip4;
1458   ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1459   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_HANDSHAKE;
1460   ctx->c_quic_ctx_id.client_opaque = sep->opaque;
1461   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1462   if (sep->hostname)
1463     {
1464       ctx->c_quic_ctx_id.srv_hostname = format (0, "%v", sep->hostname);
1465       vec_terminate_c_string (ctx->c_quic_ctx_id.srv_hostname);
1466     }
1467   else
1468     {
1469       /*  needed by quic for crypto + determining client / server */
1470       ctx->c_quic_ctx_id.srv_hostname =
1471         format (0, "%U", format_ip46_address, &sep->ip, sep->is_ip4);
1472     }
1473
1474   clib_memcpy (&cargs->sep, sep, sizeof (session_endpoint_cfg_t));
1475   cargs->sep.transport_proto = TRANSPORT_PROTO_UDPC;
1476   cargs->app_index = qm->app_index;
1477   cargs->api_context = ctx_index;
1478
1479   app_wrk = app_worker_get (sep->app_wrk_index);
1480   app = application_get (app_wrk->app_index);
1481   ctx->parent_app_id = app_wrk->app_index;
1482   cargs->sep_ext.ns_index = app->ns_index;
1483
1484   allocate_quicly_ctx (app, 1 /* is client */ );
1485
1486   if ((error = vnet_connect (cargs)))
1487     return error;
1488
1489   return 0;
1490 }
1491
1492 static int
1493 quic_connect (transport_endpoint_cfg_t * tep)
1494 {
1495   QUIC_DBG (2, "Called quic_connect");
1496   session_endpoint_cfg_t *sep = (session_endpoint_cfg_t *) tep;
1497   sep = (session_endpoint_cfg_t *) tep;
1498   if (sep->transport_opts)
1499     return quic_connect_new_stream (sep);
1500   else
1501     return quic_connect_new_connection (sep);
1502 }
1503
1504 static void
1505 quic_proto_on_close (u32 ctx_index, u32 thread_index)
1506 {
1507   quic_ctx_t *ctx = quic_ctx_get_if_valid (ctx_index, thread_index);
1508   if (!ctx)
1509     return;
1510 #if QUIC_DEBUG >= 2
1511   session_t *stream_session =
1512     session_get (ctx->c_s_index, ctx->c_thread_index);
1513   clib_warning ("Closing session 0x%lx", session_handle (stream_session));
1514 #endif
1515   if (quic_ctx_is_stream (ctx))
1516     {
1517       quicly_stream_t *stream = ctx->c_quic_ctx_id.stream;
1518       quicly_reset_stream (stream, QUIC_APP_ERROR_CLOSE_NOTIFY);
1519       quic_send_packets (ctx);
1520     }
1521   else if (ctx->c_quic_ctx_id.conn_state == QUIC_CONN_STATE_PASSIVE_CLOSING)
1522     quic_connection_closed (ctx->c_c_index, ctx->c_thread_index,
1523                             0 /* notify_transport */ );
1524   else
1525     {
1526       quicly_conn_t *conn = ctx->c_quic_ctx_id.conn;
1527       /* Start connection closing. Keep sending packets until quicly_send
1528          returns QUICLY_ERROR_FREE_CONNECTION */
1529       quicly_close (conn, QUIC_APP_ERROR_CLOSE_NOTIFY, "Closed by peer");
1530       /* This also causes all streams to be closed (and the cb called) */
1531       quic_send_packets (ctx);
1532     }
1533 }
1534
1535 static u32
1536 quic_start_listen (u32 quic_listen_session_index, transport_endpoint_t * tep)
1537 {
1538   vnet_listen_args_t _bargs, *args = &_bargs;
1539   quic_main_t *qm = &quic_main;
1540   session_handle_t udp_handle;
1541   session_endpoint_cfg_t *sep;
1542   session_t *udp_listen_session;
1543   app_worker_t *app_wrk;
1544   application_t *app;
1545   quic_ctx_t *lctx;
1546   u32 lctx_index;
1547   app_listener_t *app_listener;
1548
1549   sep = (session_endpoint_cfg_t *) tep;
1550   app_wrk = app_worker_get (sep->app_wrk_index);
1551   /* We need to call this because we call app_worker_init_connected in
1552    * quic_accept_stream, which assumes the connect segment manager exists */
1553   app_worker_alloc_connects_segment_manager (app_wrk);
1554   app = application_get (app_wrk->app_index);
1555   QUIC_DBG (2, "Called quic_start_listen for app %d", app_wrk->app_index);
1556
1557   allocate_quicly_ctx (app, 0 /* is_client */ );
1558
1559   sep->transport_proto = TRANSPORT_PROTO_UDPC;
1560   memset (args, 0, sizeof (*args));
1561   args->app_index = qm->app_index;
1562   args->sep_ext = *sep;
1563   args->sep_ext.ns_index = app->ns_index;
1564   if (vnet_listen (args))
1565     return -1;
1566
1567   lctx_index = quic_ctx_alloc (0);
1568   udp_handle = args->handle;
1569   app_listener = app_listener_get_w_handle (udp_handle);
1570   udp_listen_session = app_listener_get_session (app_listener);
1571   udp_listen_session->opaque = lctx_index;
1572
1573   lctx = quic_ctx_get (lctx_index, 0);
1574   lctx->flags |= QUIC_F_IS_LISTENER;
1575
1576   clib_memcpy (&lctx->c_rmt_ip, &args->sep.peer.ip, sizeof (ip46_address_t));
1577   clib_memcpy (&lctx->c_lcl_ip, &args->sep.ip, sizeof (ip46_address_t));
1578   lctx->c_rmt_port = args->sep.peer.port;
1579   lctx->c_lcl_port = args->sep.port;
1580   lctx->c_is_ip4 = args->sep.is_ip4;
1581   lctx->c_fib_index = args->sep.fib_index;
1582   lctx->c_proto = TRANSPORT_PROTO_QUIC;
1583   lctx->parent_app_wrk_id = sep->app_wrk_index;
1584   lctx->parent_app_id = app_wrk->app_index;
1585   lctx->udp_session_handle = udp_handle;
1586   lctx->c_s_index = quic_listen_session_index;
1587
1588   QUIC_DBG (2, "Listening UDP session 0x%lx",
1589             session_handle (udp_listen_session));
1590   QUIC_DBG (2, "Listening QUIC session 0x%lx", quic_listen_session_index);
1591   return lctx_index;
1592 }
1593
1594 static u32
1595 quic_stop_listen (u32 lctx_index)
1596 {
1597   QUIC_DBG (2, "Called quic_stop_listen");
1598   quic_ctx_t *lctx;
1599   lctx = quic_ctx_get (lctx_index, 0);
1600   ASSERT (quic_ctx_is_listener (lctx));
1601   vnet_unlisten_args_t a = {
1602     .handle = lctx->udp_session_handle,
1603     .app_index = quic_main.app_index,
1604     .wrk_map_index = 0          /* default wrk */
1605   };
1606   if (vnet_unlisten (&a))
1607     clib_warning ("unlisten errored");
1608
1609   /*  TODO: crypto state cleanup */
1610
1611   quic_ctx_free (lctx);
1612   return 0;
1613 }
1614
1615 static transport_connection_t *
1616 quic_connection_get (u32 ctx_index, u32 thread_index)
1617 {
1618   quic_ctx_t *ctx;
1619   ctx = quic_ctx_get (ctx_index, thread_index);
1620   return &ctx->connection;
1621 }
1622
1623 static transport_connection_t *
1624 quic_listener_get (u32 listener_index)
1625 {
1626   QUIC_DBG (2, "Called quic_listener_get");
1627   quic_ctx_t *ctx;
1628   ctx = quic_ctx_get (listener_index, 0);
1629   return &ctx->connection;
1630 }
1631
1632 static u8 *
1633 format_quic_ctx (u8 * s, va_list * args)
1634 {
1635   quic_ctx_t *ctx = va_arg (*args, quic_ctx_t *);
1636   u32 verbose = va_arg (*args, u32);
1637   u8 *str = 0;
1638
1639   if (!ctx)
1640     return s;
1641   str = format (str, "[#%d][Q] ", ctx->c_thread_index);
1642
1643   if (quic_ctx_is_listener (ctx))
1644     str = format (str, "Listener, UDP %ld", ctx->udp_session_handle);
1645   else if (quic_ctx_is_stream (ctx))
1646     str = format (str, "Stream %ld conn %d",
1647                   ctx->c_quic_ctx_id.stream->stream_id,
1648                   ctx->c_quic_ctx_id.quic_connection_ctx_id);
1649   else                          /* connection */
1650     str = format (str, "Conn %d UDP %d", ctx->c_c_index,
1651                   ctx->udp_session_handle);
1652
1653   str = format (str, " app %d wrk %d", ctx->parent_app_id,
1654                 ctx->parent_app_wrk_id);
1655
1656   if (verbose == 1)
1657     s = format (s, "%-50s%-15d", str, ctx->c_quic_ctx_id.conn_state);
1658   else
1659     s = format (s, "%s\n", str);
1660   vec_free (str);
1661   return s;
1662 }
1663
1664 static u8 *
1665 format_quic_connection (u8 * s, va_list * args)
1666 {
1667   u32 qc_index = va_arg (*args, u32);
1668   u32 thread_index = va_arg (*args, u32);
1669   u32 verbose = va_arg (*args, u32);
1670   quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index);
1671   s = format (s, "%U", format_quic_ctx, ctx, verbose);
1672   return s;
1673 }
1674
1675 static u8 *
1676 format_quic_half_open (u8 * s, va_list * args)
1677 {
1678   u32 qc_index = va_arg (*args, u32);
1679   u32 thread_index = va_arg (*args, u32);
1680   quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index);
1681   s =
1682     format (s, "[#%d][Q] half-open app %u", thread_index, ctx->parent_app_id);
1683   return s;
1684 }
1685
1686 /*  TODO improve */
1687 static u8 *
1688 format_quic_listener (u8 * s, va_list * args)
1689 {
1690   u32 tci = va_arg (*args, u32);
1691   u32 thread_index = va_arg (*args, u32);
1692   u32 verbose = va_arg (*args, u32);
1693   quic_ctx_t *ctx = quic_ctx_get (tci, thread_index);
1694   s = format (s, "%U", format_quic_ctx, ctx, verbose);
1695   return s;
1696 }
1697
1698 /*****************************************************************************
1699  * END TRANSPORT PROTO FUNCTIONS
1700  *
1701  * START SESSION CALLBACKS
1702  * Called from UDP layer
1703  *****************************************************************************/
1704
1705 static inline void
1706 quic_build_sockaddr (struct sockaddr *sa, socklen_t * salen,
1707                      ip46_address_t * addr, u16 port, u8 is_ip4)
1708 {
1709   if (is_ip4)
1710     {
1711       struct sockaddr_in *sa4 = (struct sockaddr_in *) sa;
1712       sa4->sin_family = AF_INET;
1713       sa4->sin_port = port;
1714       sa4->sin_addr.s_addr = addr->ip4.as_u32;
1715       *salen = sizeof (struct sockaddr_in);
1716     }
1717   else
1718     {
1719       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
1720       sa6->sin6_family = AF_INET6;
1721       sa6->sin6_port = port;
1722       clib_memcpy (&sa6->sin6_addr, &addr->ip6, 16);
1723       *salen = sizeof (struct sockaddr_in6);
1724     }
1725 }
1726
1727 static int
1728 quic_on_client_connected (quic_ctx_t * ctx)
1729 {
1730   session_t *quic_session;
1731   app_worker_t *app_wrk;
1732   u32 ctx_id = ctx->c_c_index;
1733   u32 thread_index = ctx->c_thread_index;
1734
1735   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1736   if (!app_wrk)
1737     {
1738       quic_disconnect_transport (ctx);
1739       return -1;
1740     }
1741
1742   quic_session = session_alloc (thread_index);
1743
1744   QUIC_DBG (2, "Allocated quic session 0x%lx", session_handle (quic_session));
1745   ctx->c_s_index = quic_session->session_index;
1746   quic_session->app_wrk_index = ctx->parent_app_wrk_id;
1747   quic_session->connection_index = ctx->c_c_index;
1748   quic_session->listener_handle = SESSION_INVALID_HANDLE;
1749   quic_session->session_type =
1750     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
1751                                     ctx->c_quic_ctx_id.udp_is_ip4);
1752
1753   if (app_worker_init_connected (app_wrk, quic_session))
1754     {
1755       QUIC_DBG (1, "failed to app_worker_init_connected");
1756       quic_proto_on_close (ctx_id, thread_index);
1757       return app_worker_connect_notify (app_wrk, NULL,
1758                                         ctx->c_quic_ctx_id.client_opaque);
1759     }
1760
1761   quic_session->session_state = SESSION_STATE_CONNECTING;
1762   if (app_worker_connect_notify
1763       (app_wrk, quic_session, ctx->c_quic_ctx_id.client_opaque))
1764     {
1765       QUIC_DBG (1, "failed to notify app");
1766       quic_proto_on_close (ctx_id, thread_index);
1767       return -1;
1768     }
1769
1770   /*  If the app opens a stream in its callback it may invalidate ctx */
1771   ctx = quic_ctx_get (ctx_id, thread_index);
1772   quic_session->session_state = SESSION_STATE_LISTENING;
1773
1774   return 0;
1775 }
1776
1777 static void
1778 quic_receive_connection (void *arg)
1779 {
1780   u32 new_ctx_id, thread_index = vlib_get_thread_index ();
1781   quic_ctx_t *temp_ctx, *new_ctx;
1782   clib_bihash_kv_16_8_t kv;
1783   quicly_conn_t *conn;
1784
1785   temp_ctx = arg;
1786   new_ctx_id = quic_ctx_alloc (thread_index);
1787   new_ctx = quic_ctx_get (new_ctx_id, thread_index);
1788
1789   QUIC_DBG (2, "Received conn %u (now %u)", temp_ctx->c_thread_index,
1790             new_ctx_id);
1791
1792
1793   memcpy (new_ctx, temp_ctx, sizeof (quic_ctx_t));
1794   free (temp_ctx);
1795
1796   new_ctx->c_thread_index = thread_index;
1797   new_ctx->c_c_index = new_ctx_id;
1798
1799   conn = new_ctx->c_quic_ctx_id.conn;
1800   quic_store_conn_ctx (conn, new_ctx);
1801   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1802   kv.value = ((u64) thread_index) << 32 | (u64) new_ctx_id;
1803   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
1804   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
1805   new_ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1806   quic_update_timer (new_ctx);
1807
1808   /*  Trigger read on this connection ? */
1809 }
1810
1811 static void
1812 quic_transfer_connection (u32 ctx_index, u32 dest_thread)
1813 {
1814   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
1815   quic_ctx_t *ctx, *temp_ctx;
1816   clib_bihash_kv_16_8_t kv;
1817   quicly_conn_t *conn;
1818   u32 thread_index = vlib_get_thread_index ();
1819
1820   QUIC_DBG (2, "Transferring conn %u to thread %u", ctx_index, dest_thread);
1821
1822   temp_ctx = malloc (sizeof (quic_ctx_t));
1823   ASSERT (temp_ctx);
1824   ctx = quic_ctx_get (ctx_index, thread_index);
1825
1826   memcpy (temp_ctx, ctx, sizeof (quic_ctx_t));
1827
1828   /*  Remove from lookup hash, timer wheel and thread-local pool */
1829   conn = ctx->c_quic_ctx_id.conn;
1830   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1831   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 0 /* is_add */ );
1832   if (ctx->timer_handle != QUIC_TIMER_HANDLE_INVALID)
1833     {
1834       tw = &quic_main.wrk_ctx[thread_index].timer_wheel;
1835       tw_timer_stop_1t_3w_1024sl_ov (tw, ctx->timer_handle);
1836     }
1837   quic_ctx_free (ctx);
1838
1839   /*  Send connection to destination thread */
1840   session_send_rpc_evt_to_thread (dest_thread, quic_receive_connection,
1841                                   (void *) temp_ctx);
1842 }
1843
1844 static void
1845 quic_transfer_connection_rpc (void *arg)
1846 {
1847   u64 arg_int = (u64) arg;
1848   u32 ctx_index, dest_thread;
1849
1850   ctx_index = (u32) (arg_int >> 32);
1851   dest_thread = (u32) (arg_int & UINT32_MAX);
1852   quic_transfer_connection (ctx_index, dest_thread);
1853 }
1854
1855 /*
1856  * This assumes that the connection is not yet associated to a session
1857  * So currently it only works on the client side when receiving the first packet
1858  * from the server
1859  */
1860 static void
1861 quic_move_connection_to_thread (u32 ctx_index, u32 owner_thread,
1862                                 u32 to_thread)
1863 {
1864   QUIC_DBG (2, "Requesting transfer of conn %u from thread %u", ctx_index,
1865             owner_thread);
1866   u64 arg = ((u64) ctx_index) << 32 | to_thread;
1867   session_send_rpc_evt_to_thread (owner_thread, quic_transfer_connection_rpc,
1868                                   (void *) arg);
1869 }
1870
1871 static int
1872 quic_session_connected_callback (u32 quic_app_index, u32 ctx_index,
1873                                  session_t * udp_session, u8 is_fail)
1874 {
1875   QUIC_DBG (2, "QSession is now connected (id %u)",
1876             udp_session->session_index);
1877   /* This should always be called before quic_connect returns since UDP always
1878    * connects instantly. */
1879   clib_bihash_kv_16_8_t kv;
1880   struct sockaddr_in6 sa6;
1881   struct sockaddr *sa = (struct sockaddr *) &sa6;
1882   socklen_t salen;
1883   transport_connection_t *tc;
1884   app_worker_t *app_wrk;
1885   quicly_conn_t *conn;
1886   application_t *app;
1887   quic_ctx_t *ctx;
1888   u32 thread_index = vlib_get_thread_index ();
1889   int ret;
1890
1891   ctx = quic_ctx_get (ctx_index, thread_index);
1892   if (is_fail)
1893     {
1894       u32 api_context;
1895       int rv = 0;
1896
1897       app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1898       if (app_wrk)
1899         {
1900           api_context = ctx->c_s_index;
1901           app_worker_connect_notify (app_wrk, 0, api_context);
1902         }
1903       return rv;
1904     }
1905
1906   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1907   if (!app_wrk)
1908     {
1909       QUIC_DBG (1, "Appwrk not found");
1910       return -1;
1911     }
1912   app = application_get (app_wrk->app_index);
1913
1914   ctx->c_thread_index = thread_index;
1915   ctx->c_c_index = ctx_index;
1916
1917   QUIC_DBG (2, "Quic connect returned %u. New ctx [%u]%x",
1918             is_fail, thread_index, (ctx) ? ctx_index : ~0);
1919
1920   ctx->udp_session_handle = session_handle (udp_session);
1921   udp_session->opaque = ctx->parent_app_id;
1922   udp_session->session_state = SESSION_STATE_READY;
1923
1924   /* Init QUIC lib connection
1925    * Generate required sockaddr & salen */
1926   tc = session_get_transport (udp_session);
1927   quic_build_sockaddr (sa, &salen, &tc->rmt_ip, tc->rmt_port, tc->is_ip4);
1928
1929   ret =
1930     quicly_connect (&ctx->c_quic_ctx_id.conn,
1931                     (quicly_context_t *) app->quicly_ctx,
1932                     (char *) ctx->c_quic_ctx_id.srv_hostname, sa, salen,
1933                     &quic_main.next_cid, &quic_main.hs_properties, NULL);
1934   ++quic_main.next_cid.master_id;
1935   /*  Save context handle in quicly connection */
1936   quic_store_conn_ctx (ctx->c_quic_ctx_id.conn, ctx);
1937   assert (ret == 0);
1938
1939   /*  Register connection in connections map */
1940   conn = ctx->c_quic_ctx_id.conn;
1941   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1942   kv.value = ((u64) thread_index) << 32 | (u64) ctx_index;
1943   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
1944   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
1945
1946   quic_send_packets (ctx);
1947
1948   /*  UDP stack quirk? preemptively transfer connection if that happens */
1949   if (udp_session->thread_index != thread_index)
1950     quic_transfer_connection (ctx_index, udp_session->thread_index);
1951
1952   return ret;
1953 }
1954
1955 static void
1956 quic_session_disconnect_callback (session_t * s)
1957 {
1958   clib_warning ("UDP session disconnected???");
1959 }
1960
1961 static void
1962 quic_session_reset_callback (session_t * s)
1963 {
1964   clib_warning ("UDP session reset???");
1965 }
1966
1967 int
1968 quic_session_accepted_callback (session_t * udp_session)
1969 {
1970   /* New UDP connection, try to accept it */
1971   u32 ctx_index;
1972   u32 *pool_index;
1973   quic_ctx_t *ctx, *lctx;
1974   session_t *udp_listen_session;
1975   u32 thread_index = vlib_get_thread_index ();
1976
1977   udp_listen_session =
1978     listen_session_get_from_handle (udp_session->listener_handle);
1979
1980   ctx_index = quic_ctx_alloc (thread_index);
1981   ctx = quic_ctx_get (ctx_index, thread_index);
1982   ctx->c_thread_index = udp_session->thread_index;
1983   ctx->c_c_index = ctx_index;
1984   ctx->c_s_index = QUIC_SESSION_INVALID;
1985   ctx->udp_session_handle = session_handle (udp_session);
1986   QUIC_DBG (2, "ACCEPTED UDP 0x%lx", ctx->udp_session_handle);
1987   ctx->c_quic_ctx_id.listener_ctx_id = udp_listen_session->opaque;
1988   lctx = quic_ctx_get (udp_listen_session->opaque,
1989                        udp_listen_session->thread_index);
1990   ctx->c_quic_ctx_id.udp_is_ip4 = lctx->c_is_ip4;
1991   ctx->parent_app_id = lctx->parent_app_id;
1992   ctx->parent_app_wrk_id = lctx->parent_app_wrk_id;
1993   ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1994   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_OPENED;
1995   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1996
1997   udp_session->opaque = ctx->parent_app_id;
1998
1999   /* Put this ctx in the "opening" pool */
2000   pool_get (quic_main.wrk_ctx[ctx->c_thread_index].opening_ctx_pool,
2001             pool_index);
2002   *pool_index = ctx_index;
2003
2004   /* TODO timeout to delete these if they never connect */
2005   return 0;
2006 }
2007
2008 static int
2009 quic_add_segment_callback (u32 client_index, u64 seg_handle)
2010 {
2011   QUIC_DBG (2, "Called quic_add_segment_callback");
2012   QUIC_DBG (2, "NOT IMPLEMENTED");
2013   /* No-op for builtin */
2014   return 0;
2015 }
2016
2017 static int
2018 quic_del_segment_callback (u32 client_index, u64 seg_handle)
2019 {
2020   QUIC_DBG (2, "Called quic_del_segment_callback");
2021   QUIC_DBG (2, "NOT IMPLEMENTED");
2022   /* No-op for builtin */
2023   return 0;
2024 }
2025
2026
2027 static int
2028 quic_custom_app_rx_callback (transport_connection_t * tc)
2029 {
2030   quic_ctx_t *ctx;
2031   session_t *stream_session = session_get (tc->s_index, tc->thread_index);
2032   QUIC_DBG (3, "Received app READ notification");
2033   quic_ack_rx_data (stream_session);
2034   svm_fifo_reset_has_deq_ntf (stream_session->rx_fifo);
2035
2036   /* Need to send packets (acks may never be sent otherwise) */
2037   ctx = quic_ctx_get (stream_session->connection_index,
2038                       stream_session->thread_index);
2039   quic_send_packets (ctx);
2040   return 0;
2041 }
2042
2043 static int
2044 quic_custom_tx_callback (void *s)
2045 {
2046   session_t *stream_session = (session_t *) s;
2047   quicly_stream_t *stream;
2048   quic_ctx_t *ctx;
2049   int rv;
2050
2051   if (PREDICT_FALSE
2052       (stream_session->session_state >= SESSION_STATE_TRANSPORT_CLOSING))
2053     return 0;
2054   ctx =
2055     quic_ctx_get (stream_session->connection_index,
2056                   stream_session->thread_index);
2057   if (PREDICT_FALSE (!quic_ctx_is_stream (ctx)))
2058     {
2059       goto tx_end;              /* Most probably a reschedule */
2060     }
2061
2062   QUIC_DBG (3, "Stream TX event");
2063   quic_ack_rx_data (stream_session);
2064   if (!svm_fifo_max_dequeue (stream_session->tx_fifo))
2065     return 0;
2066
2067   stream = ctx->c_quic_ctx_id.stream;
2068   if (!quicly_sendstate_is_open (&stream->sendstate))
2069     {
2070       QUIC_DBG (1, "Warning: tried to send on closed stream");
2071       return -1;
2072     }
2073
2074   if ((rv = quicly_stream_sync_sendbuf (stream, 1)) != 0)
2075     return rv;
2076
2077 tx_end:
2078   quic_send_packets (ctx);
2079   return 0;
2080 }
2081
2082
2083 /*
2084  * Returns 0 if a matching connection is found and is on the right thread.
2085  * If a connection is found, even on the wrong thread, ctx_thread and ctx_index
2086  * will be set.
2087  */
2088 static inline int
2089 quic_find_packet_ctx (u32 * ctx_thread, u32 * ctx_index,
2090                       struct sockaddr *sa, socklen_t salen,
2091                       quicly_decoded_packet_t * packet,
2092                       u32 caller_thread_index)
2093 {
2094   quic_ctx_t *ctx_;
2095   quicly_conn_t *conn_;
2096   clib_bihash_kv_16_8_t kv;
2097   clib_bihash_16_8_t *h;
2098
2099   h = &quic_main.connection_hash;
2100   quic_make_connection_key (&kv, &packet->cid.dest.plaintext);
2101   QUIC_DBG (3, "Searching conn with id %lu %lu", kv.key[0], kv.key[1]);
2102
2103   if (clib_bihash_search_16_8 (h, &kv, &kv) == 0)
2104     {
2105       u32 index = kv.value & UINT32_MAX;
2106       u8 thread_id = kv.value >> 32;
2107       /* Check if this connection belongs to this thread, otherwise
2108        * ask for it to be moved */
2109       if (thread_id != caller_thread_index)
2110         {
2111           QUIC_DBG (2, "Connection is on wrong thread");
2112           /* Cannot make full check with quicly_is_destination... */
2113           *ctx_index = index;
2114           *ctx_thread = thread_id;
2115           return -1;
2116         }
2117       ctx_ = quic_ctx_get (index, vlib_get_thread_index ());
2118       conn_ = ctx_->c_quic_ctx_id.conn;
2119       if (conn_ && quicly_is_destination (conn_, sa, salen, packet))
2120         {
2121           QUIC_DBG (3, "Connection found");
2122           *ctx_index = index;
2123           *ctx_thread = thread_id;
2124           return 0;
2125         }
2126     }
2127   QUIC_DBG (3, "connection not found");
2128   return -1;
2129 }
2130
2131 static int
2132 quic_receive (quic_ctx_t * ctx, quicly_conn_t * conn,
2133               quicly_decoded_packet_t packet)
2134 {
2135   int rv;
2136   u32 ctx_id = ctx->c_c_index;
2137   u32 thread_index = ctx->c_thread_index;
2138   /* TODO : QUICLY_ERROR_PACKET_IGNORED sould be handled */
2139   rv = quicly_receive (conn, &packet);
2140   if (rv)
2141     {
2142       QUIC_DBG (2, "quicly_receive errored %U", quic_format_err, rv);
2143       return 0;
2144     }
2145   /* ctx pointer may change if a new stream is opened */
2146   ctx = quic_ctx_get (ctx_id, thread_index);
2147   /* Conn may be set to null if the connection is terminated */
2148   if (ctx->c_quic_ctx_id.conn
2149       && ctx->c_quic_ctx_id.conn_state == QUIC_CONN_STATE_HANDSHAKE)
2150     {
2151       if (quicly_connection_is_ready (conn))
2152         {
2153           ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_READY;
2154           if (quicly_is_client (conn))
2155             {
2156               quic_on_client_connected (ctx);
2157               ctx = quic_ctx_get (ctx_id, thread_index);
2158             }
2159         }
2160     }
2161   return quic_send_packets (ctx);
2162 }
2163
2164 static int
2165 quic_create_quic_session (quic_ctx_t * ctx)
2166 {
2167   session_t *quic_session;
2168   app_worker_t *app_wrk;
2169   quic_ctx_t *lctx;
2170   int rv;
2171
2172   quic_session = session_alloc (ctx->c_thread_index);
2173   QUIC_DBG (2, "Allocated quic_session, 0x%lx ctx %u",
2174             session_handle (quic_session), ctx->c_c_index);
2175   quic_session->session_state = SESSION_STATE_LISTENING;
2176   ctx->c_s_index = quic_session->session_index;
2177
2178   lctx = quic_ctx_get (ctx->c_quic_ctx_id.listener_ctx_id, 0);
2179
2180   quic_session->app_wrk_index = lctx->parent_app_wrk_id;
2181   quic_session->connection_index = ctx->c_c_index;
2182   quic_session->session_type =
2183     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
2184                                     ctx->c_quic_ctx_id.udp_is_ip4);
2185   quic_session->listener_handle = lctx->c_s_index;
2186
2187   /* TODO: don't alloc fifos when we don't transfer data on this session
2188    * but we still need fifos for the events? */
2189   if ((rv = app_worker_init_accepted (quic_session)))
2190     {
2191       QUIC_DBG (1, "failed to allocate fifos");
2192       session_free (quic_session);
2193       return rv;
2194     }
2195   app_wrk = app_worker_get (quic_session->app_wrk_index);
2196   rv = app_worker_accept_notify (app_wrk, quic_session);
2197   if (rv)
2198     {
2199       QUIC_DBG (1, "failed to notify accept worker app");
2200       return rv;
2201     }
2202   return 0;
2203 }
2204
2205 static int
2206 quic_create_connection (quicly_context_t * quicly_ctx,
2207                         u32 ctx_index, struct sockaddr *sa,
2208                         socklen_t salen, quicly_decoded_packet_t packet)
2209 {
2210   clib_bihash_kv_16_8_t kv;
2211   quic_ctx_t *ctx;
2212   quicly_conn_t *conn;
2213   u32 thread_index = vlib_get_thread_index ();
2214   int rv;
2215
2216   /* new connection, accept and create context if packet is valid
2217    * TODO: check if socket is actually listening? */
2218   if ((rv = quicly_accept (&conn, quicly_ctx, sa, salen,
2219                            &packet, ptls_iovec_init (NULL, 0),
2220                            &quic_main.next_cid, NULL)))
2221     {
2222       /* Invalid packet, pass */
2223       assert (conn == NULL);
2224       QUIC_DBG (1, "Accept failed with %d", rv);
2225       /* TODO: cleanup created quic ctx and UDP session */
2226       return 0;
2227     }
2228   assert (conn != NULL);
2229
2230   ++quic_main.next_cid.master_id;
2231   ctx = quic_ctx_get (ctx_index, thread_index);
2232   /* Save ctx handle in quicly connection */
2233   quic_store_conn_ctx (conn, ctx);
2234   ctx->c_quic_ctx_id.conn = conn;
2235   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_HANDSHAKE;
2236
2237   quic_create_quic_session (ctx);
2238
2239   /* Register connection in connections map */
2240   quic_make_connection_key (&kv, quicly_get_master_id (conn));
2241   kv.value = ((u64) thread_index) << 32 | (u64) ctx_index;
2242   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
2243   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
2244
2245   return quic_send_packets (ctx);
2246 }
2247
2248 static int
2249 quic_reset_connection (quicly_context_t * quicly_ctx, u64 udp_session_handle,
2250                        struct sockaddr *sa, socklen_t salen,
2251                        quicly_decoded_packet_t packet)
2252 {
2253   /* short header packet; potentially a dead connection. No need to check the
2254    * length of the incoming packet, because loop is prevented by authenticating
2255    * the CID (by checking node_id and thread_id). If the peer is also sending a
2256    * reset, then the next CID is highly likely to contain a non-authenticating
2257    * CID, ... */
2258   QUIC_DBG (2, "Sending stateless reset");
2259   int rv;
2260   quicly_datagram_t *dgram;
2261   session_t *udp_session;
2262   if (packet.cid.dest.plaintext.node_id == 0
2263       && packet.cid.dest.plaintext.thread_id == 0)
2264     {
2265       dgram = quicly_send_stateless_reset (quicly_ctx, sa, salen,
2266                                            &packet.cid.dest.plaintext);
2267       if (dgram == NULL)
2268         return 1;
2269       udp_session = session_get_from_handle (udp_session_handle);
2270       rv = quic_send_datagram (udp_session, dgram);
2271       if (svm_fifo_set_event (udp_session->tx_fifo))
2272         session_send_io_evt_to_thread (udp_session->tx_fifo,
2273                                        SESSION_IO_EVT_TX);
2274       return rv;
2275     }
2276   return 0;
2277 }
2278
2279 static int
2280 quic_app_rx_callback (session_t * udp_session)
2281 {
2282   /*  Read data from UDP rx_fifo and pass it to the quicly conn. */
2283   quicly_decoded_packet_t packet;
2284   session_dgram_hdr_t ph;
2285   application_t *app;
2286   quic_ctx_t *ctx = NULL;
2287   svm_fifo_t *f;
2288   size_t plen;
2289   struct sockaddr_in6 sa6;
2290   struct sockaddr *sa = (struct sockaddr *) &sa6;
2291   socklen_t salen;
2292   u32 max_deq, full_len, ctx_index = UINT32_MAX, ctx_thread = UINT32_MAX, ret;
2293   u8 *data;
2294   int err;
2295   u32 *opening_ctx_pool, *ctx_index_ptr;
2296   u32 app_index = udp_session->opaque;
2297   u64 udp_session_handle = session_handle (udp_session);
2298   int rv = 0;
2299   u32 thread_index = vlib_get_thread_index ();
2300   app = application_get_if_valid (app_index);
2301   if (!app)
2302     {
2303       QUIC_DBG (1, "Got RX on detached app");
2304       /*  TODO: close this session, cleanup state? */
2305       return 1;
2306     }
2307
2308   do
2309     {
2310       udp_session = session_get_from_handle (udp_session_handle);       /*  session alloc might have happened */
2311       f = udp_session->rx_fifo;
2312       max_deq = svm_fifo_max_dequeue (f);
2313       if (max_deq == 0)
2314         return 0;
2315
2316       if (max_deq < SESSION_CONN_HDR_LEN)
2317         {
2318           QUIC_DBG (1, "Not enough data for even a header in RX");
2319           return 1;
2320         }
2321       ret = svm_fifo_peek (f, 0, SESSION_CONN_HDR_LEN, (u8 *) & ph);
2322       if (ret != SESSION_CONN_HDR_LEN)
2323         {
2324           QUIC_DBG (1, "Not enough data for header in RX");
2325           return 1;
2326         }
2327       ASSERT (ph.data_offset == 0);
2328       full_len = ph.data_length + SESSION_CONN_HDR_LEN;
2329       if (full_len > max_deq)
2330         {
2331           QUIC_DBG (1, "Not enough data in fifo RX");
2332           return 1;
2333         }
2334
2335       /* Quicly can read len bytes from the fifo at offset:
2336        * ph.data_offset + SESSION_CONN_HDR_LEN */
2337       data = malloc (ph.data_length);
2338       ret = svm_fifo_peek (f, SESSION_CONN_HDR_LEN, ph.data_length, data);
2339       if (ret != ph.data_length)
2340         {
2341           QUIC_DBG (1, "Not enough data peeked in RX");
2342           free (data);
2343           return 1;
2344         }
2345
2346       rv = 0;
2347       quic_build_sockaddr (sa, &salen, &ph.rmt_ip, ph.rmt_port, ph.is_ip4);
2348       plen = quicly_decode_packet ((quicly_context_t *) app->quicly_ctx,
2349                                    &packet, data, ph.data_length);
2350
2351       if (plen != SIZE_MAX)
2352         {
2353
2354           err = quic_find_packet_ctx (&ctx_thread, &ctx_index, sa, salen,
2355                                       &packet, thread_index);
2356           if (err == 0)
2357             {
2358               ctx = quic_ctx_get (ctx_index, thread_index);
2359               quic_receive (ctx, ctx->c_quic_ctx_id.conn, packet);
2360             }
2361           else if (ctx_thread != UINT32_MAX)
2362             {
2363               /*  Connection found but on wrong thread, ask move */
2364               quic_move_connection_to_thread (ctx_index, ctx_thread,
2365                                               thread_index);
2366             }
2367           else if ((packet.octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) ==
2368                    QUICLY_PACKET_TYPE_INITIAL)
2369             {
2370               /*  Try to find matching "opening" ctx */
2371               opening_ctx_pool =
2372                 quic_main.wrk_ctx[thread_index].opening_ctx_pool;
2373
2374               /* *INDENT-OFF* */
2375               pool_foreach (ctx_index_ptr, opening_ctx_pool,
2376               ({
2377                 ctx = quic_ctx_get (*ctx_index_ptr, thread_index);
2378                 if (ctx->udp_session_handle == udp_session_handle)
2379                   {
2380                     /*  Right ctx found, create conn & remove from pool */
2381                     quic_create_connection ((quicly_context_t *) app->quicly_ctx,
2382                                             *ctx_index_ptr, sa, salen, packet);
2383                     pool_put (opening_ctx_pool, ctx_index_ptr);
2384                     goto ctx_search_done;
2385                   }
2386               }));
2387               /* *INDENT-ON* */
2388
2389             }
2390           else
2391             {
2392               quic_reset_connection ((quicly_context_t *) app->quicly_ctx,
2393                                      udp_session_handle, sa, salen, packet);
2394             }
2395         }
2396     ctx_search_done:
2397       svm_fifo_dequeue_drop (f, full_len);
2398       free (data);
2399     }
2400   while (1);
2401   return rv;
2402 }
2403
2404 always_inline void
2405 quic_common_get_transport_endpoint (quic_ctx_t * ctx,
2406                                     transport_endpoint_t * tep, u8 is_lcl)
2407 {
2408   session_t *udp_session;
2409   if (!quic_ctx_is_stream (ctx))
2410     {
2411       udp_session = session_get_from_handle (ctx->udp_session_handle);
2412       session_get_endpoint (udp_session, tep, is_lcl);
2413     }
2414 }
2415
2416 static void
2417 quic_get_transport_listener_endpoint (u32 listener_index,
2418                                       transport_endpoint_t * tep, u8 is_lcl)
2419 {
2420   quic_ctx_t *ctx;
2421   app_listener_t *app_listener;
2422   session_t *udp_listen_session;
2423   ctx = quic_ctx_get (listener_index, vlib_get_thread_index ());
2424   if (quic_ctx_is_listener (ctx))
2425     {
2426       app_listener = app_listener_get_w_handle (ctx->udp_session_handle);
2427       udp_listen_session = app_listener_get_session (app_listener);
2428       return session_get_endpoint (udp_listen_session, tep, is_lcl);
2429     }
2430   quic_common_get_transport_endpoint (ctx, tep, is_lcl);
2431 }
2432
2433 static void
2434 quic_get_transport_endpoint (u32 ctx_index, u32 thread_index,
2435                              transport_endpoint_t * tep, u8 is_lcl)
2436 {
2437   quic_ctx_t *ctx;
2438   ctx = quic_ctx_get (ctx_index, thread_index);
2439   quic_common_get_transport_endpoint (ctx, tep, is_lcl);
2440 }
2441
2442 /*****************************************************************************
2443  * END TRANSPORT PROTO FUNCTIONS
2444 *****************************************************************************/
2445
2446 /* *INDENT-OFF* */
2447 static session_cb_vft_t quic_app_cb_vft = {
2448   .session_accept_callback = quic_session_accepted_callback,
2449   .session_disconnect_callback = quic_session_disconnect_callback,
2450   .session_connected_callback = quic_session_connected_callback,
2451   .session_reset_callback = quic_session_reset_callback,
2452   .add_segment_callback = quic_add_segment_callback,
2453   .del_segment_callback = quic_del_segment_callback,
2454   .builtin_app_rx_callback = quic_app_rx_callback,
2455 };
2456
2457 static const transport_proto_vft_t quic_proto = {
2458   .connect = quic_connect,
2459   .close = quic_proto_on_close,
2460   .start_listen = quic_start_listen,
2461   .stop_listen = quic_stop_listen,
2462   .get_connection = quic_connection_get,
2463   .get_listener = quic_listener_get,
2464   .update_time = quic_update_time,
2465   .app_rx_evt = quic_custom_app_rx_callback,
2466   .custom_tx = quic_custom_tx_callback,
2467   .format_connection = format_quic_connection,
2468   .format_half_open = format_quic_half_open,
2469   .format_listener = format_quic_listener,
2470   .get_transport_endpoint = quic_get_transport_endpoint,
2471   .get_transport_listener_endpoint = quic_get_transport_listener_endpoint,
2472   .transport_options = {
2473     .tx_type = TRANSPORT_TX_INTERNAL,
2474     .service_type = TRANSPORT_SERVICE_APP,
2475   },
2476 };
2477 /* *INDENT-ON* */
2478
2479 static clib_error_t *
2480 quic_init (vlib_main_t * vm)
2481 {
2482   u32 segment_size = 256 << 20;
2483   vlib_thread_main_t *vtm = vlib_get_thread_main ();
2484   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
2485   vnet_app_attach_args_t _a, *a = &_a;
2486   u64 options[APP_OPTIONS_N_OPTIONS];
2487   quic_main_t *qm = &quic_main;
2488   u32 fifo_size = QUIC_FIFO_SIZE;
2489   u32 num_threads, i;
2490
2491   num_threads = 1 /* main thread */  + vtm->n_threads;
2492
2493   memset (a, 0, sizeof (*a));
2494   memset (options, 0, sizeof (options));
2495
2496   a->session_cb_vft = &quic_app_cb_vft;
2497   a->api_client_index = APP_INVALID_INDEX;
2498   a->options = options;
2499   a->name = format (0, "quic");
2500   a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
2501   a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
2502   a->options[APP_OPTIONS_RX_FIFO_SIZE] = fifo_size;
2503   a->options[APP_OPTIONS_TX_FIFO_SIZE] = fifo_size;
2504   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
2505   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
2506   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_TRANSPORT_APP;
2507
2508   if (vnet_application_attach (a))
2509     {
2510       clib_warning ("failed to attach quic app");
2511       return clib_error_return (0, "failed to attach quic app");
2512     }
2513
2514   vec_validate (qm->ctx_pool, num_threads - 1);
2515   vec_validate (qm->wrk_ctx, num_threads - 1);
2516   /*  Timer wheels, one per thread. */
2517   for (i = 0; i < num_threads; i++)
2518     {
2519       tw = &qm->wrk_ctx[i].timer_wheel;
2520       tw_timer_wheel_init_1t_3w_1024sl_ov (tw, quic_expired_timers_dispatch,
2521                                            1e-3 /* timer period 1ms */ , ~0);
2522       tw->last_run_time = vlib_time_now (vlib_get_main ());
2523     }
2524
2525   clib_bihash_init_16_8 (&qm->connection_hash, "quic connections", 1024,
2526                          4 << 20);
2527
2528
2529   qm->app_index = a->app_index;
2530   qm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
2531     / QUIC_TSTAMP_RESOLUTION;
2532
2533   transport_register_protocol (TRANSPORT_PROTO_QUIC, &quic_proto,
2534                                FIB_PROTOCOL_IP4, ~0);
2535   transport_register_protocol (TRANSPORT_PROTO_QUIC, &quic_proto,
2536                                FIB_PROTOCOL_IP6, ~0);
2537
2538   vec_free (a->name);
2539   return 0;
2540 }
2541
2542 VLIB_INIT_FUNCTION (quic_init);
2543
2544 static clib_error_t *
2545 quic_plugin_crypto_command_fn (vlib_main_t * vm,
2546                                unformat_input_t * input,
2547                                vlib_cli_command_t * cmd)
2548 {
2549   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2550     {
2551       if (unformat (input, "vpp"))
2552         {
2553           quic_tlsctx.cipher_suites = vpp_crypto_cipher_suites;
2554           return 0;
2555         }
2556       else if (unformat (input, "picotls"))
2557         {
2558           quic_tlsctx.cipher_suites = ptls_openssl_cipher_suites;
2559           return 0;
2560         }
2561       else
2562         return clib_error_return (0, "unknown input '%U'",
2563                                   format_unformat_error, input);
2564     }
2565
2566   return clib_error_return (0, "unknown input '%U'",
2567                             format_unformat_error, input);
2568 }
2569
2570 /* *INDENT-OFF* */
2571 VLIB_CLI_COMMAND(quic_plugin_crypto_command, static)=
2572 {
2573         .path = "quic set crypto api",
2574         .short_help = "quic set crypto api [picotls, vpp]",
2575         .function = quic_plugin_crypto_command_fn,
2576 };
2577
2578 VLIB_PLUGIN_REGISTER () =
2579 {
2580   .version = VPP_BUILD_VER,
2581   .description = "Quic transport protocol",
2582 };
2583 /* *INDENT-ON* */
2584
2585 /*
2586  * fd.io coding-style-patch-verification: ON
2587  *
2588  * Local Variables:
2589  * eval: (c-set-style "gnu")
2590  * End:
2591  */