session: Use parent_handle instead of transport_opts
[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_t * quic_session, u32 opaque)
1338 {
1339   uint64_t quic_session_handle;
1340   session_t *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 = session_handle (quic_session);
1351   QUIC_DBG (2, "Opening new stream (qsession %u)", quic_session_handle);
1352
1353   if (session_type_transport_proto (quic_session->session_type) !=
1354       TRANSPORT_PROTO_QUIC)
1355     {
1356       QUIC_DBG (1, "received incompatible session");
1357       return -1;
1358     }
1359
1360   app_wrk = app_worker_get_if_valid (quic_session->app_wrk_index);
1361   if (!app_wrk)
1362     {
1363       QUIC_DBG (1, "Invalid app worker :(");
1364       return -1;
1365     }
1366
1367   sctx_index = quic_ctx_alloc (quic_session->thread_index);     /*  Allocate before we get pointers */
1368   sctx = quic_ctx_get (sctx_index, quic_session->thread_index);
1369   qctx =
1370     quic_ctx_get (quic_session->connection_index, quic_session->thread_index);
1371   if (quic_ctx_is_stream (qctx))
1372     {
1373       QUIC_DBG (1, "session is a stream");
1374       quic_ctx_free (sctx);
1375       return -1;
1376     }
1377
1378   sctx->parent_app_wrk_id = qctx->parent_app_wrk_id;
1379   sctx->parent_app_id = qctx->parent_app_id;
1380   sctx->c_quic_ctx_id.quic_connection_ctx_id = qctx->c_c_index;
1381   sctx->c_c_index = sctx_index;
1382   sctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1383   sctx->flags |= QUIC_F_IS_STREAM;
1384
1385   conn = qctx->c_quic_ctx_id.conn;
1386
1387   if (!conn || !quicly_connection_is_ready (conn))
1388     return -1;
1389
1390   if ((rv = quicly_open_stream (conn, &stream, 0 /* uni */ )))
1391     {
1392       QUIC_DBG (2, "Stream open failed with %d", rv);
1393       return -1;
1394     }
1395   sctx->c_quic_ctx_id.stream = stream;
1396
1397   QUIC_DBG (2, "Opened stream %d, creating session", stream->stream_id);
1398
1399   stream_session = session_alloc (qctx->c_thread_index);
1400   QUIC_DBG (2, "Allocated stream_session 0x%lx ctx %u",
1401             session_handle (stream_session), sctx_index);
1402   stream_session->app_wrk_index = app_wrk->wrk_index;
1403   stream_session->connection_index = sctx_index;
1404   stream_session->listener_handle = quic_session_handle;
1405   stream_session->session_type =
1406     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
1407                                     qctx->c_quic_ctx_id.udp_is_ip4);
1408
1409   sctx->c_s_index = stream_session->session_index;
1410
1411   if (app_worker_init_connected (app_wrk, stream_session))
1412     {
1413       QUIC_DBG (1, "failed to app_worker_init_connected");
1414       quicly_reset_stream (stream, QUIC_APP_ALLOCATION_ERROR);
1415       session_free_w_fifos (stream_session);
1416       quic_ctx_free (sctx);
1417       return app_worker_connect_notify (app_wrk, NULL, opaque);
1418     }
1419
1420   svm_fifo_add_want_deq_ntf (stream_session->rx_fifo,
1421                              SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL |
1422                              SVM_FIFO_WANT_DEQ_NOTIF_IF_EMPTY);
1423
1424   stream_session->session_state = SESSION_STATE_READY;
1425   if (app_worker_connect_notify (app_wrk, stream_session, opaque))
1426     {
1427       QUIC_DBG (1, "failed to notify app");
1428       quicly_reset_stream (stream, QUIC_APP_CONNECT_NOTIFY_ERROR);
1429       session_free_w_fifos (stream_session);
1430       quic_ctx_free (sctx);
1431       return -1;
1432     }
1433   stream_data = (quic_stream_data_t *) stream->data;
1434   stream_data->ctx_id = sctx->c_c_index;
1435   stream_data->thread_index = sctx->c_thread_index;
1436   stream_data->app_rx_data_len = 0;
1437   return 0;
1438 }
1439
1440 static int
1441 quic_connect_new_connection (session_endpoint_cfg_t * sep)
1442 {
1443   vnet_connect_args_t _cargs = { {}, }, *cargs = &_cargs;
1444   quic_main_t *qm = &quic_main;
1445   quic_ctx_t *ctx;
1446   app_worker_t *app_wrk;
1447   application_t *app;
1448   u32 ctx_index;
1449   int error;
1450
1451   ctx_index = quic_ctx_alloc (vlib_get_thread_index ());
1452   ctx = quic_ctx_get (ctx_index, vlib_get_thread_index ());
1453   ctx->parent_app_wrk_id = sep->app_wrk_index;
1454   ctx->c_s_index = QUIC_SESSION_INVALID;
1455   ctx->c_c_index = ctx_index;
1456   ctx->c_quic_ctx_id.udp_is_ip4 = sep->is_ip4;
1457   ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1458   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_HANDSHAKE;
1459   ctx->c_quic_ctx_id.client_opaque = sep->opaque;
1460   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1461   if (sep->hostname)
1462     {
1463       ctx->c_quic_ctx_id.srv_hostname = format (0, "%v", sep->hostname);
1464       vec_terminate_c_string (ctx->c_quic_ctx_id.srv_hostname);
1465     }
1466   else
1467     {
1468       /*  needed by quic for crypto + determining client / server */
1469       ctx->c_quic_ctx_id.srv_hostname =
1470         format (0, "%U", format_ip46_address, &sep->ip, sep->is_ip4);
1471     }
1472
1473   clib_memcpy (&cargs->sep, sep, sizeof (session_endpoint_cfg_t));
1474   cargs->sep.transport_proto = TRANSPORT_PROTO_UDPC;
1475   cargs->app_index = qm->app_index;
1476   cargs->api_context = ctx_index;
1477
1478   app_wrk = app_worker_get (sep->app_wrk_index);
1479   app = application_get (app_wrk->app_index);
1480   ctx->parent_app_id = app_wrk->app_index;
1481   cargs->sep_ext.ns_index = app->ns_index;
1482
1483   allocate_quicly_ctx (app, 1 /* is client */ );
1484
1485   if ((error = vnet_connect (cargs)))
1486     return error;
1487
1488   return 0;
1489 }
1490
1491 static int
1492 quic_connect (transport_endpoint_cfg_t * tep)
1493 {
1494   QUIC_DBG (2, "Called quic_connect");
1495   session_endpoint_cfg_t *sep = (session_endpoint_cfg_t *) tep;
1496   session_t *quic_session;
1497   sep = (session_endpoint_cfg_t *) tep;
1498
1499   quic_session = session_get_from_handle_if_valid (sep->parent_handle);
1500   if (quic_session)
1501     return quic_connect_new_stream (quic_session, sep->opaque);
1502   else
1503     return quic_connect_new_connection (sep);
1504 }
1505
1506 static void
1507 quic_proto_on_close (u32 ctx_index, u32 thread_index)
1508 {
1509   quic_ctx_t *ctx = quic_ctx_get_if_valid (ctx_index, thread_index);
1510   if (!ctx)
1511     return;
1512 #if QUIC_DEBUG >= 2
1513   session_t *stream_session =
1514     session_get (ctx->c_s_index, ctx->c_thread_index);
1515   clib_warning ("Closing session 0x%lx", session_handle (stream_session));
1516 #endif
1517   if (quic_ctx_is_stream (ctx))
1518     {
1519       quicly_stream_t *stream = ctx->c_quic_ctx_id.stream;
1520       quicly_reset_stream (stream, QUIC_APP_ERROR_CLOSE_NOTIFY);
1521       quic_send_packets (ctx);
1522     }
1523   else if (ctx->c_quic_ctx_id.conn_state == QUIC_CONN_STATE_PASSIVE_CLOSING)
1524     quic_connection_closed (ctx->c_c_index, ctx->c_thread_index,
1525                             0 /* notify_transport */ );
1526   else
1527     {
1528       quicly_conn_t *conn = ctx->c_quic_ctx_id.conn;
1529       /* Start connection closing. Keep sending packets until quicly_send
1530          returns QUICLY_ERROR_FREE_CONNECTION */
1531       quicly_close (conn, QUIC_APP_ERROR_CLOSE_NOTIFY, "Closed by peer");
1532       /* This also causes all streams to be closed (and the cb called) */
1533       quic_send_packets (ctx);
1534     }
1535 }
1536
1537 static u32
1538 quic_start_listen (u32 quic_listen_session_index, transport_endpoint_t * tep)
1539 {
1540   vnet_listen_args_t _bargs, *args = &_bargs;
1541   quic_main_t *qm = &quic_main;
1542   session_handle_t udp_handle;
1543   session_endpoint_cfg_t *sep;
1544   session_t *udp_listen_session;
1545   app_worker_t *app_wrk;
1546   application_t *app;
1547   quic_ctx_t *lctx;
1548   u32 lctx_index;
1549   app_listener_t *app_listener;
1550
1551   sep = (session_endpoint_cfg_t *) tep;
1552   app_wrk = app_worker_get (sep->app_wrk_index);
1553   /* We need to call this because we call app_worker_init_connected in
1554    * quic_accept_stream, which assumes the connect segment manager exists */
1555   app_worker_alloc_connects_segment_manager (app_wrk);
1556   app = application_get (app_wrk->app_index);
1557   QUIC_DBG (2, "Called quic_start_listen for app %d", app_wrk->app_index);
1558
1559   allocate_quicly_ctx (app, 0 /* is_client */ );
1560
1561   sep->transport_proto = TRANSPORT_PROTO_UDPC;
1562   memset (args, 0, sizeof (*args));
1563   args->app_index = qm->app_index;
1564   args->sep_ext = *sep;
1565   args->sep_ext.ns_index = app->ns_index;
1566   if (vnet_listen (args))
1567     return -1;
1568
1569   lctx_index = quic_ctx_alloc (0);
1570   udp_handle = args->handle;
1571   app_listener = app_listener_get_w_handle (udp_handle);
1572   udp_listen_session = app_listener_get_session (app_listener);
1573   udp_listen_session->opaque = lctx_index;
1574
1575   lctx = quic_ctx_get (lctx_index, 0);
1576   lctx->flags |= QUIC_F_IS_LISTENER;
1577
1578   clib_memcpy (&lctx->c_rmt_ip, &args->sep.peer.ip, sizeof (ip46_address_t));
1579   clib_memcpy (&lctx->c_lcl_ip, &args->sep.ip, sizeof (ip46_address_t));
1580   lctx->c_rmt_port = args->sep.peer.port;
1581   lctx->c_lcl_port = args->sep.port;
1582   lctx->c_is_ip4 = args->sep.is_ip4;
1583   lctx->c_fib_index = args->sep.fib_index;
1584   lctx->c_proto = TRANSPORT_PROTO_QUIC;
1585   lctx->parent_app_wrk_id = sep->app_wrk_index;
1586   lctx->parent_app_id = app_wrk->app_index;
1587   lctx->udp_session_handle = udp_handle;
1588   lctx->c_s_index = quic_listen_session_index;
1589
1590   QUIC_DBG (2, "Listening UDP session 0x%lx",
1591             session_handle (udp_listen_session));
1592   QUIC_DBG (2, "Listening QUIC session 0x%lx", quic_listen_session_index);
1593   return lctx_index;
1594 }
1595
1596 static u32
1597 quic_stop_listen (u32 lctx_index)
1598 {
1599   QUIC_DBG (2, "Called quic_stop_listen");
1600   quic_ctx_t *lctx;
1601   lctx = quic_ctx_get (lctx_index, 0);
1602   ASSERT (quic_ctx_is_listener (lctx));
1603   vnet_unlisten_args_t a = {
1604     .handle = lctx->udp_session_handle,
1605     .app_index = quic_main.app_index,
1606     .wrk_map_index = 0          /* default wrk */
1607   };
1608   if (vnet_unlisten (&a))
1609     clib_warning ("unlisten errored");
1610
1611   /*  TODO: crypto state cleanup */
1612
1613   quic_ctx_free (lctx);
1614   return 0;
1615 }
1616
1617 static transport_connection_t *
1618 quic_connection_get (u32 ctx_index, u32 thread_index)
1619 {
1620   quic_ctx_t *ctx;
1621   ctx = quic_ctx_get (ctx_index, thread_index);
1622   return &ctx->connection;
1623 }
1624
1625 static transport_connection_t *
1626 quic_listener_get (u32 listener_index)
1627 {
1628   QUIC_DBG (2, "Called quic_listener_get");
1629   quic_ctx_t *ctx;
1630   ctx = quic_ctx_get (listener_index, 0);
1631   return &ctx->connection;
1632 }
1633
1634 static u8 *
1635 format_quic_ctx (u8 * s, va_list * args)
1636 {
1637   quic_ctx_t *ctx = va_arg (*args, quic_ctx_t *);
1638   u32 verbose = va_arg (*args, u32);
1639   u8 *str = 0;
1640
1641   if (!ctx)
1642     return s;
1643   str = format (str, "[#%d][Q] ", ctx->c_thread_index);
1644
1645   if (quic_ctx_is_listener (ctx))
1646     str = format (str, "Listener, UDP %ld", ctx->udp_session_handle);
1647   else if (quic_ctx_is_stream (ctx))
1648     str = format (str, "Stream %ld conn %d",
1649                   ctx->c_quic_ctx_id.stream->stream_id,
1650                   ctx->c_quic_ctx_id.quic_connection_ctx_id);
1651   else                          /* connection */
1652     str = format (str, "Conn %d UDP %d", ctx->c_c_index,
1653                   ctx->udp_session_handle);
1654
1655   str = format (str, " app %d wrk %d", ctx->parent_app_id,
1656                 ctx->parent_app_wrk_id);
1657
1658   if (verbose == 1)
1659     s = format (s, "%-50s%-15d", str, ctx->c_quic_ctx_id.conn_state);
1660   else
1661     s = format (s, "%s\n", str);
1662   vec_free (str);
1663   return s;
1664 }
1665
1666 static u8 *
1667 format_quic_connection (u8 * s, va_list * args)
1668 {
1669   u32 qc_index = va_arg (*args, u32);
1670   u32 thread_index = va_arg (*args, u32);
1671   u32 verbose = va_arg (*args, u32);
1672   quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index);
1673   s = format (s, "%U", format_quic_ctx, ctx, verbose);
1674   return s;
1675 }
1676
1677 static u8 *
1678 format_quic_half_open (u8 * s, va_list * args)
1679 {
1680   u32 qc_index = va_arg (*args, u32);
1681   u32 thread_index = va_arg (*args, u32);
1682   quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index);
1683   s =
1684     format (s, "[#%d][Q] half-open app %u", thread_index, ctx->parent_app_id);
1685   return s;
1686 }
1687
1688 /*  TODO improve */
1689 static u8 *
1690 format_quic_listener (u8 * s, va_list * args)
1691 {
1692   u32 tci = va_arg (*args, u32);
1693   u32 thread_index = va_arg (*args, u32);
1694   u32 verbose = va_arg (*args, u32);
1695   quic_ctx_t *ctx = quic_ctx_get (tci, thread_index);
1696   s = format (s, "%U", format_quic_ctx, ctx, verbose);
1697   return s;
1698 }
1699
1700 /*****************************************************************************
1701  * END TRANSPORT PROTO FUNCTIONS
1702  *
1703  * START SESSION CALLBACKS
1704  * Called from UDP layer
1705  *****************************************************************************/
1706
1707 static inline void
1708 quic_build_sockaddr (struct sockaddr *sa, socklen_t * salen,
1709                      ip46_address_t * addr, u16 port, u8 is_ip4)
1710 {
1711   if (is_ip4)
1712     {
1713       struct sockaddr_in *sa4 = (struct sockaddr_in *) sa;
1714       sa4->sin_family = AF_INET;
1715       sa4->sin_port = port;
1716       sa4->sin_addr.s_addr = addr->ip4.as_u32;
1717       *salen = sizeof (struct sockaddr_in);
1718     }
1719   else
1720     {
1721       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
1722       sa6->sin6_family = AF_INET6;
1723       sa6->sin6_port = port;
1724       clib_memcpy (&sa6->sin6_addr, &addr->ip6, 16);
1725       *salen = sizeof (struct sockaddr_in6);
1726     }
1727 }
1728
1729 static int
1730 quic_on_client_connected (quic_ctx_t * ctx)
1731 {
1732   session_t *quic_session;
1733   app_worker_t *app_wrk;
1734   u32 ctx_id = ctx->c_c_index;
1735   u32 thread_index = ctx->c_thread_index;
1736
1737   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1738   if (!app_wrk)
1739     {
1740       quic_disconnect_transport (ctx);
1741       return -1;
1742     }
1743
1744   quic_session = session_alloc (thread_index);
1745
1746   QUIC_DBG (2, "Allocated quic session 0x%lx", session_handle (quic_session));
1747   ctx->c_s_index = quic_session->session_index;
1748   quic_session->app_wrk_index = ctx->parent_app_wrk_id;
1749   quic_session->connection_index = ctx->c_c_index;
1750   quic_session->listener_handle = SESSION_INVALID_HANDLE;
1751   quic_session->session_type =
1752     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
1753                                     ctx->c_quic_ctx_id.udp_is_ip4);
1754
1755   if (app_worker_init_connected (app_wrk, quic_session))
1756     {
1757       QUIC_DBG (1, "failed to app_worker_init_connected");
1758       quic_proto_on_close (ctx_id, thread_index);
1759       return app_worker_connect_notify (app_wrk, NULL,
1760                                         ctx->c_quic_ctx_id.client_opaque);
1761     }
1762
1763   quic_session->session_state = SESSION_STATE_CONNECTING;
1764   if (app_worker_connect_notify
1765       (app_wrk, quic_session, ctx->c_quic_ctx_id.client_opaque))
1766     {
1767       QUIC_DBG (1, "failed to notify app");
1768       quic_proto_on_close (ctx_id, thread_index);
1769       return -1;
1770     }
1771
1772   /*  If the app opens a stream in its callback it may invalidate ctx */
1773   ctx = quic_ctx_get (ctx_id, thread_index);
1774   quic_session->session_state = SESSION_STATE_LISTENING;
1775
1776   return 0;
1777 }
1778
1779 static void
1780 quic_receive_connection (void *arg)
1781 {
1782   u32 new_ctx_id, thread_index = vlib_get_thread_index ();
1783   quic_ctx_t *temp_ctx, *new_ctx;
1784   clib_bihash_kv_16_8_t kv;
1785   quicly_conn_t *conn;
1786
1787   temp_ctx = arg;
1788   new_ctx_id = quic_ctx_alloc (thread_index);
1789   new_ctx = quic_ctx_get (new_ctx_id, thread_index);
1790
1791   QUIC_DBG (2, "Received conn %u (now %u)", temp_ctx->c_thread_index,
1792             new_ctx_id);
1793
1794
1795   memcpy (new_ctx, temp_ctx, sizeof (quic_ctx_t));
1796   free (temp_ctx);
1797
1798   new_ctx->c_thread_index = thread_index;
1799   new_ctx->c_c_index = new_ctx_id;
1800
1801   conn = new_ctx->c_quic_ctx_id.conn;
1802   quic_store_conn_ctx (conn, new_ctx);
1803   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1804   kv.value = ((u64) thread_index) << 32 | (u64) new_ctx_id;
1805   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
1806   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
1807   new_ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1808   quic_update_timer (new_ctx);
1809
1810   /*  Trigger read on this connection ? */
1811 }
1812
1813 static void
1814 quic_transfer_connection (u32 ctx_index, u32 dest_thread)
1815 {
1816   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
1817   quic_ctx_t *ctx, *temp_ctx;
1818   clib_bihash_kv_16_8_t kv;
1819   quicly_conn_t *conn;
1820   u32 thread_index = vlib_get_thread_index ();
1821
1822   QUIC_DBG (2, "Transferring conn %u to thread %u", ctx_index, dest_thread);
1823
1824   temp_ctx = malloc (sizeof (quic_ctx_t));
1825   ASSERT (temp_ctx);
1826   ctx = quic_ctx_get (ctx_index, thread_index);
1827
1828   memcpy (temp_ctx, ctx, sizeof (quic_ctx_t));
1829
1830   /*  Remove from lookup hash, timer wheel and thread-local pool */
1831   conn = ctx->c_quic_ctx_id.conn;
1832   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1833   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 0 /* is_add */ );
1834   if (ctx->timer_handle != QUIC_TIMER_HANDLE_INVALID)
1835     {
1836       tw = &quic_main.wrk_ctx[thread_index].timer_wheel;
1837       tw_timer_stop_1t_3w_1024sl_ov (tw, ctx->timer_handle);
1838     }
1839   quic_ctx_free (ctx);
1840
1841   /*  Send connection to destination thread */
1842   session_send_rpc_evt_to_thread (dest_thread, quic_receive_connection,
1843                                   (void *) temp_ctx);
1844 }
1845
1846 static void
1847 quic_transfer_connection_rpc (void *arg)
1848 {
1849   u64 arg_int = (u64) arg;
1850   u32 ctx_index, dest_thread;
1851
1852   ctx_index = (u32) (arg_int >> 32);
1853   dest_thread = (u32) (arg_int & UINT32_MAX);
1854   quic_transfer_connection (ctx_index, dest_thread);
1855 }
1856
1857 /*
1858  * This assumes that the connection is not yet associated to a session
1859  * So currently it only works on the client side when receiving the first packet
1860  * from the server
1861  */
1862 static void
1863 quic_move_connection_to_thread (u32 ctx_index, u32 owner_thread,
1864                                 u32 to_thread)
1865 {
1866   QUIC_DBG (2, "Requesting transfer of conn %u from thread %u", ctx_index,
1867             owner_thread);
1868   u64 arg = ((u64) ctx_index) << 32 | to_thread;
1869   session_send_rpc_evt_to_thread (owner_thread, quic_transfer_connection_rpc,
1870                                   (void *) arg);
1871 }
1872
1873 static int
1874 quic_session_connected_callback (u32 quic_app_index, u32 ctx_index,
1875                                  session_t * udp_session, u8 is_fail)
1876 {
1877   QUIC_DBG (2, "QSession is now connected (id %u)",
1878             udp_session->session_index);
1879   /* This should always be called before quic_connect returns since UDP always
1880    * connects instantly. */
1881   clib_bihash_kv_16_8_t kv;
1882   struct sockaddr_in6 sa6;
1883   struct sockaddr *sa = (struct sockaddr *) &sa6;
1884   socklen_t salen;
1885   transport_connection_t *tc;
1886   app_worker_t *app_wrk;
1887   quicly_conn_t *conn;
1888   application_t *app;
1889   quic_ctx_t *ctx;
1890   u32 thread_index = vlib_get_thread_index ();
1891   int ret;
1892
1893   ctx = quic_ctx_get (ctx_index, thread_index);
1894   if (is_fail)
1895     {
1896       u32 api_context;
1897       int rv = 0;
1898
1899       app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1900       if (app_wrk)
1901         {
1902           api_context = ctx->c_s_index;
1903           app_worker_connect_notify (app_wrk, 0, api_context);
1904         }
1905       return rv;
1906     }
1907
1908   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1909   if (!app_wrk)
1910     {
1911       QUIC_DBG (1, "Appwrk not found");
1912       return -1;
1913     }
1914   app = application_get (app_wrk->app_index);
1915
1916   ctx->c_thread_index = thread_index;
1917   ctx->c_c_index = ctx_index;
1918
1919   QUIC_DBG (2, "Quic connect returned %u. New ctx [%u]%x",
1920             is_fail, thread_index, (ctx) ? ctx_index : ~0);
1921
1922   ctx->udp_session_handle = session_handle (udp_session);
1923   udp_session->opaque = ctx->parent_app_id;
1924   udp_session->session_state = SESSION_STATE_READY;
1925
1926   /* Init QUIC lib connection
1927    * Generate required sockaddr & salen */
1928   tc = session_get_transport (udp_session);
1929   quic_build_sockaddr (sa, &salen, &tc->rmt_ip, tc->rmt_port, tc->is_ip4);
1930
1931   ret =
1932     quicly_connect (&ctx->c_quic_ctx_id.conn,
1933                     (quicly_context_t *) app->quicly_ctx,
1934                     (char *) ctx->c_quic_ctx_id.srv_hostname, sa, salen,
1935                     &quic_main.next_cid, &quic_main.hs_properties, NULL);
1936   ++quic_main.next_cid.master_id;
1937   /*  Save context handle in quicly connection */
1938   quic_store_conn_ctx (ctx->c_quic_ctx_id.conn, ctx);
1939   assert (ret == 0);
1940
1941   /*  Register connection in connections map */
1942   conn = ctx->c_quic_ctx_id.conn;
1943   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1944   kv.value = ((u64) thread_index) << 32 | (u64) ctx_index;
1945   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
1946   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
1947
1948   quic_send_packets (ctx);
1949
1950   /*  UDP stack quirk? preemptively transfer connection if that happens */
1951   if (udp_session->thread_index != thread_index)
1952     quic_transfer_connection (ctx_index, udp_session->thread_index);
1953
1954   return ret;
1955 }
1956
1957 static void
1958 quic_session_disconnect_callback (session_t * s)
1959 {
1960   clib_warning ("UDP session disconnected???");
1961 }
1962
1963 static void
1964 quic_session_reset_callback (session_t * s)
1965 {
1966   clib_warning ("UDP session reset???");
1967 }
1968
1969 int
1970 quic_session_accepted_callback (session_t * udp_session)
1971 {
1972   /* New UDP connection, try to accept it */
1973   u32 ctx_index;
1974   u32 *pool_index;
1975   quic_ctx_t *ctx, *lctx;
1976   session_t *udp_listen_session;
1977   u32 thread_index = vlib_get_thread_index ();
1978
1979   udp_listen_session =
1980     listen_session_get_from_handle (udp_session->listener_handle);
1981
1982   ctx_index = quic_ctx_alloc (thread_index);
1983   ctx = quic_ctx_get (ctx_index, thread_index);
1984   ctx->c_thread_index = udp_session->thread_index;
1985   ctx->c_c_index = ctx_index;
1986   ctx->c_s_index = QUIC_SESSION_INVALID;
1987   ctx->udp_session_handle = session_handle (udp_session);
1988   QUIC_DBG (2, "ACCEPTED UDP 0x%lx", ctx->udp_session_handle);
1989   ctx->c_quic_ctx_id.listener_ctx_id = udp_listen_session->opaque;
1990   lctx = quic_ctx_get (udp_listen_session->opaque,
1991                        udp_listen_session->thread_index);
1992   ctx->c_quic_ctx_id.udp_is_ip4 = lctx->c_is_ip4;
1993   ctx->parent_app_id = lctx->parent_app_id;
1994   ctx->parent_app_wrk_id = lctx->parent_app_wrk_id;
1995   ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1996   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_OPENED;
1997   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1998
1999   udp_session->opaque = ctx->parent_app_id;
2000
2001   /* Put this ctx in the "opening" pool */
2002   pool_get (quic_main.wrk_ctx[ctx->c_thread_index].opening_ctx_pool,
2003             pool_index);
2004   *pool_index = ctx_index;
2005
2006   /* TODO timeout to delete these if they never connect */
2007   return 0;
2008 }
2009
2010 static int
2011 quic_add_segment_callback (u32 client_index, u64 seg_handle)
2012 {
2013   QUIC_DBG (2, "Called quic_add_segment_callback");
2014   QUIC_DBG (2, "NOT IMPLEMENTED");
2015   /* No-op for builtin */
2016   return 0;
2017 }
2018
2019 static int
2020 quic_del_segment_callback (u32 client_index, u64 seg_handle)
2021 {
2022   QUIC_DBG (2, "Called quic_del_segment_callback");
2023   QUIC_DBG (2, "NOT IMPLEMENTED");
2024   /* No-op for builtin */
2025   return 0;
2026 }
2027
2028
2029 static int
2030 quic_custom_app_rx_callback (transport_connection_t * tc)
2031 {
2032   quic_ctx_t *ctx;
2033   session_t *stream_session = session_get (tc->s_index, tc->thread_index);
2034   QUIC_DBG (3, "Received app READ notification");
2035   quic_ack_rx_data (stream_session);
2036   svm_fifo_reset_has_deq_ntf (stream_session->rx_fifo);
2037
2038   /* Need to send packets (acks may never be sent otherwise) */
2039   ctx = quic_ctx_get (stream_session->connection_index,
2040                       stream_session->thread_index);
2041   quic_send_packets (ctx);
2042   return 0;
2043 }
2044
2045 static int
2046 quic_custom_tx_callback (void *s)
2047 {
2048   session_t *stream_session = (session_t *) s;
2049   quicly_stream_t *stream;
2050   quic_ctx_t *ctx;
2051   int rv;
2052
2053   if (PREDICT_FALSE
2054       (stream_session->session_state >= SESSION_STATE_TRANSPORT_CLOSING))
2055     return 0;
2056   ctx =
2057     quic_ctx_get (stream_session->connection_index,
2058                   stream_session->thread_index);
2059   if (PREDICT_FALSE (!quic_ctx_is_stream (ctx)))
2060     {
2061       goto tx_end;              /* Most probably a reschedule */
2062     }
2063
2064   QUIC_DBG (3, "Stream TX event");
2065   quic_ack_rx_data (stream_session);
2066   if (!svm_fifo_max_dequeue (stream_session->tx_fifo))
2067     return 0;
2068
2069   stream = ctx->c_quic_ctx_id.stream;
2070   if (!quicly_sendstate_is_open (&stream->sendstate))
2071     {
2072       QUIC_DBG (1, "Warning: tried to send on closed stream");
2073       return -1;
2074     }
2075
2076   if ((rv = quicly_stream_sync_sendbuf (stream, 1)) != 0)
2077     return rv;
2078
2079 tx_end:
2080   quic_send_packets (ctx);
2081   return 0;
2082 }
2083
2084
2085 /*
2086  * Returns 0 if a matching connection is found and is on the right thread.
2087  * If a connection is found, even on the wrong thread, ctx_thread and ctx_index
2088  * will be set.
2089  */
2090 static inline int
2091 quic_find_packet_ctx (u32 * ctx_thread, u32 * ctx_index,
2092                       struct sockaddr *sa, socklen_t salen,
2093                       quicly_decoded_packet_t * packet,
2094                       u32 caller_thread_index)
2095 {
2096   quic_ctx_t *ctx_;
2097   quicly_conn_t *conn_;
2098   clib_bihash_kv_16_8_t kv;
2099   clib_bihash_16_8_t *h;
2100
2101   h = &quic_main.connection_hash;
2102   quic_make_connection_key (&kv, &packet->cid.dest.plaintext);
2103   QUIC_DBG (3, "Searching conn with id %lu %lu", kv.key[0], kv.key[1]);
2104
2105   if (clib_bihash_search_16_8 (h, &kv, &kv) == 0)
2106     {
2107       u32 index = kv.value & UINT32_MAX;
2108       u8 thread_id = kv.value >> 32;
2109       /* Check if this connection belongs to this thread, otherwise
2110        * ask for it to be moved */
2111       if (thread_id != caller_thread_index)
2112         {
2113           QUIC_DBG (2, "Connection is on wrong thread");
2114           /* Cannot make full check with quicly_is_destination... */
2115           *ctx_index = index;
2116           *ctx_thread = thread_id;
2117           return -1;
2118         }
2119       ctx_ = quic_ctx_get (index, vlib_get_thread_index ());
2120       conn_ = ctx_->c_quic_ctx_id.conn;
2121       if (conn_ && quicly_is_destination (conn_, sa, salen, packet))
2122         {
2123           QUIC_DBG (3, "Connection found");
2124           *ctx_index = index;
2125           *ctx_thread = thread_id;
2126           return 0;
2127         }
2128     }
2129   QUIC_DBG (3, "connection not found");
2130   return -1;
2131 }
2132
2133 static int
2134 quic_receive (quic_ctx_t * ctx, quicly_conn_t * conn,
2135               quicly_decoded_packet_t packet)
2136 {
2137   int rv;
2138   u32 ctx_id = ctx->c_c_index;
2139   u32 thread_index = ctx->c_thread_index;
2140   /* TODO : QUICLY_ERROR_PACKET_IGNORED sould be handled */
2141   rv = quicly_receive (conn, &packet);
2142   if (rv)
2143     {
2144       QUIC_DBG (2, "quicly_receive errored %U", quic_format_err, rv);
2145       return 0;
2146     }
2147   /* ctx pointer may change if a new stream is opened */
2148   ctx = quic_ctx_get (ctx_id, thread_index);
2149   /* Conn may be set to null if the connection is terminated */
2150   if (ctx->c_quic_ctx_id.conn
2151       && ctx->c_quic_ctx_id.conn_state == QUIC_CONN_STATE_HANDSHAKE)
2152     {
2153       if (quicly_connection_is_ready (conn))
2154         {
2155           ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_READY;
2156           if (quicly_is_client (conn))
2157             {
2158               quic_on_client_connected (ctx);
2159               ctx = quic_ctx_get (ctx_id, thread_index);
2160             }
2161         }
2162     }
2163   return quic_send_packets (ctx);
2164 }
2165
2166 static int
2167 quic_create_quic_session (quic_ctx_t * ctx)
2168 {
2169   session_t *quic_session;
2170   app_worker_t *app_wrk;
2171   quic_ctx_t *lctx;
2172   int rv;
2173
2174   quic_session = session_alloc (ctx->c_thread_index);
2175   QUIC_DBG (2, "Allocated quic_session, 0x%lx ctx %u",
2176             session_handle (quic_session), ctx->c_c_index);
2177   quic_session->session_state = SESSION_STATE_LISTENING;
2178   ctx->c_s_index = quic_session->session_index;
2179
2180   lctx = quic_ctx_get (ctx->c_quic_ctx_id.listener_ctx_id, 0);
2181
2182   quic_session->app_wrk_index = lctx->parent_app_wrk_id;
2183   quic_session->connection_index = ctx->c_c_index;
2184   quic_session->session_type =
2185     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
2186                                     ctx->c_quic_ctx_id.udp_is_ip4);
2187   quic_session->listener_handle = lctx->c_s_index;
2188
2189   /* TODO: don't alloc fifos when we don't transfer data on this session
2190    * but we still need fifos for the events? */
2191   if ((rv = app_worker_init_accepted (quic_session)))
2192     {
2193       QUIC_DBG (1, "failed to allocate fifos");
2194       session_free (quic_session);
2195       return rv;
2196     }
2197   app_wrk = app_worker_get (quic_session->app_wrk_index);
2198   rv = app_worker_accept_notify (app_wrk, quic_session);
2199   if (rv)
2200     {
2201       QUIC_DBG (1, "failed to notify accept worker app");
2202       return rv;
2203     }
2204   return 0;
2205 }
2206
2207 static int
2208 quic_create_connection (quicly_context_t * quicly_ctx,
2209                         u32 ctx_index, struct sockaddr *sa,
2210                         socklen_t salen, quicly_decoded_packet_t packet)
2211 {
2212   clib_bihash_kv_16_8_t kv;
2213   quic_ctx_t *ctx;
2214   quicly_conn_t *conn;
2215   u32 thread_index = vlib_get_thread_index ();
2216   int rv;
2217
2218   /* new connection, accept and create context if packet is valid
2219    * TODO: check if socket is actually listening? */
2220   if ((rv = quicly_accept (&conn, quicly_ctx, sa, salen,
2221                            &packet, ptls_iovec_init (NULL, 0),
2222                            &quic_main.next_cid, NULL)))
2223     {
2224       /* Invalid packet, pass */
2225       assert (conn == NULL);
2226       QUIC_DBG (1, "Accept failed with %d", rv);
2227       /* TODO: cleanup created quic ctx and UDP session */
2228       return 0;
2229     }
2230   assert (conn != NULL);
2231
2232   ++quic_main.next_cid.master_id;
2233   ctx = quic_ctx_get (ctx_index, thread_index);
2234   /* Save ctx handle in quicly connection */
2235   quic_store_conn_ctx (conn, ctx);
2236   ctx->c_quic_ctx_id.conn = conn;
2237   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_HANDSHAKE;
2238
2239   quic_create_quic_session (ctx);
2240
2241   /* Register connection in connections map */
2242   quic_make_connection_key (&kv, quicly_get_master_id (conn));
2243   kv.value = ((u64) thread_index) << 32 | (u64) ctx_index;
2244   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
2245   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
2246
2247   return quic_send_packets (ctx);
2248 }
2249
2250 static int
2251 quic_reset_connection (quicly_context_t * quicly_ctx, u64 udp_session_handle,
2252                        struct sockaddr *sa, socklen_t salen,
2253                        quicly_decoded_packet_t packet)
2254 {
2255   /* short header packet; potentially a dead connection. No need to check the
2256    * length of the incoming packet, because loop is prevented by authenticating
2257    * the CID (by checking node_id and thread_id). If the peer is also sending a
2258    * reset, then the next CID is highly likely to contain a non-authenticating
2259    * CID, ... */
2260   QUIC_DBG (2, "Sending stateless reset");
2261   int rv;
2262   quicly_datagram_t *dgram;
2263   session_t *udp_session;
2264   if (packet.cid.dest.plaintext.node_id == 0
2265       && packet.cid.dest.plaintext.thread_id == 0)
2266     {
2267       dgram = quicly_send_stateless_reset (quicly_ctx, sa, salen,
2268                                            &packet.cid.dest.plaintext);
2269       if (dgram == NULL)
2270         return 1;
2271       udp_session = session_get_from_handle (udp_session_handle);
2272       rv = quic_send_datagram (udp_session, dgram);
2273       if (svm_fifo_set_event (udp_session->tx_fifo))
2274         session_send_io_evt_to_thread (udp_session->tx_fifo,
2275                                        SESSION_IO_EVT_TX);
2276       return rv;
2277     }
2278   return 0;
2279 }
2280
2281 static int
2282 quic_app_rx_callback (session_t * udp_session)
2283 {
2284   /*  Read data from UDP rx_fifo and pass it to the quicly conn. */
2285   quicly_decoded_packet_t packet;
2286   session_dgram_hdr_t ph;
2287   application_t *app;
2288   quic_ctx_t *ctx = NULL;
2289   svm_fifo_t *f;
2290   size_t plen;
2291   struct sockaddr_in6 sa6;
2292   struct sockaddr *sa = (struct sockaddr *) &sa6;
2293   socklen_t salen;
2294   u32 max_deq, full_len, ctx_index = UINT32_MAX, ctx_thread = UINT32_MAX, ret;
2295   u8 *data;
2296   int err;
2297   u32 *opening_ctx_pool, *ctx_index_ptr;
2298   u32 app_index = udp_session->opaque;
2299   u64 udp_session_handle = session_handle (udp_session);
2300   int rv = 0;
2301   u32 thread_index = vlib_get_thread_index ();
2302   app = application_get_if_valid (app_index);
2303   if (!app)
2304     {
2305       QUIC_DBG (1, "Got RX on detached app");
2306       /*  TODO: close this session, cleanup state? */
2307       return 1;
2308     }
2309
2310   do
2311     {
2312       udp_session = session_get_from_handle (udp_session_handle);       /*  session alloc might have happened */
2313       f = udp_session->rx_fifo;
2314       max_deq = svm_fifo_max_dequeue (f);
2315       if (max_deq == 0)
2316         return 0;
2317
2318       if (max_deq < SESSION_CONN_HDR_LEN)
2319         {
2320           QUIC_DBG (1, "Not enough data for even a header in RX");
2321           return 1;
2322         }
2323       ret = svm_fifo_peek (f, 0, SESSION_CONN_HDR_LEN, (u8 *) & ph);
2324       if (ret != SESSION_CONN_HDR_LEN)
2325         {
2326           QUIC_DBG (1, "Not enough data for header in RX");
2327           return 1;
2328         }
2329       ASSERT (ph.data_offset == 0);
2330       full_len = ph.data_length + SESSION_CONN_HDR_LEN;
2331       if (full_len > max_deq)
2332         {
2333           QUIC_DBG (1, "Not enough data in fifo RX");
2334           return 1;
2335         }
2336
2337       /* Quicly can read len bytes from the fifo at offset:
2338        * ph.data_offset + SESSION_CONN_HDR_LEN */
2339       data = malloc (ph.data_length);
2340       ret = svm_fifo_peek (f, SESSION_CONN_HDR_LEN, ph.data_length, data);
2341       if (ret != ph.data_length)
2342         {
2343           QUIC_DBG (1, "Not enough data peeked in RX");
2344           free (data);
2345           return 1;
2346         }
2347
2348       rv = 0;
2349       quic_build_sockaddr (sa, &salen, &ph.rmt_ip, ph.rmt_port, ph.is_ip4);
2350       plen = quicly_decode_packet ((quicly_context_t *) app->quicly_ctx,
2351                                    &packet, data, ph.data_length);
2352
2353       if (plen != SIZE_MAX)
2354         {
2355
2356           err = quic_find_packet_ctx (&ctx_thread, &ctx_index, sa, salen,
2357                                       &packet, thread_index);
2358           if (err == 0)
2359             {
2360               ctx = quic_ctx_get (ctx_index, thread_index);
2361               quic_receive (ctx, ctx->c_quic_ctx_id.conn, packet);
2362             }
2363           else if (ctx_thread != UINT32_MAX)
2364             {
2365               /*  Connection found but on wrong thread, ask move */
2366               quic_move_connection_to_thread (ctx_index, ctx_thread,
2367                                               thread_index);
2368             }
2369           else if ((packet.octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) ==
2370                    QUICLY_PACKET_TYPE_INITIAL)
2371             {
2372               /*  Try to find matching "opening" ctx */
2373               opening_ctx_pool =
2374                 quic_main.wrk_ctx[thread_index].opening_ctx_pool;
2375
2376               /* *INDENT-OFF* */
2377               pool_foreach (ctx_index_ptr, opening_ctx_pool,
2378               ({
2379                 ctx = quic_ctx_get (*ctx_index_ptr, thread_index);
2380                 if (ctx->udp_session_handle == udp_session_handle)
2381                   {
2382                     /*  Right ctx found, create conn & remove from pool */
2383                     quic_create_connection ((quicly_context_t *) app->quicly_ctx,
2384                                             *ctx_index_ptr, sa, salen, packet);
2385                     pool_put (opening_ctx_pool, ctx_index_ptr);
2386                     goto ctx_search_done;
2387                   }
2388               }));
2389               /* *INDENT-ON* */
2390
2391             }
2392           else
2393             {
2394               quic_reset_connection ((quicly_context_t *) app->quicly_ctx,
2395                                      udp_session_handle, sa, salen, packet);
2396             }
2397         }
2398     ctx_search_done:
2399       svm_fifo_dequeue_drop (f, full_len);
2400       free (data);
2401     }
2402   while (1);
2403   return rv;
2404 }
2405
2406 always_inline void
2407 quic_common_get_transport_endpoint (quic_ctx_t * ctx,
2408                                     transport_endpoint_t * tep, u8 is_lcl)
2409 {
2410   session_t *udp_session;
2411   if (!quic_ctx_is_stream (ctx))
2412     {
2413       udp_session = session_get_from_handle (ctx->udp_session_handle);
2414       session_get_endpoint (udp_session, tep, is_lcl);
2415     }
2416 }
2417
2418 static void
2419 quic_get_transport_listener_endpoint (u32 listener_index,
2420                                       transport_endpoint_t * tep, u8 is_lcl)
2421 {
2422   quic_ctx_t *ctx;
2423   app_listener_t *app_listener;
2424   session_t *udp_listen_session;
2425   ctx = quic_ctx_get (listener_index, vlib_get_thread_index ());
2426   if (quic_ctx_is_listener (ctx))
2427     {
2428       app_listener = app_listener_get_w_handle (ctx->udp_session_handle);
2429       udp_listen_session = app_listener_get_session (app_listener);
2430       return session_get_endpoint (udp_listen_session, tep, is_lcl);
2431     }
2432   quic_common_get_transport_endpoint (ctx, tep, is_lcl);
2433 }
2434
2435 static void
2436 quic_get_transport_endpoint (u32 ctx_index, u32 thread_index,
2437                              transport_endpoint_t * tep, u8 is_lcl)
2438 {
2439   quic_ctx_t *ctx;
2440   ctx = quic_ctx_get (ctx_index, thread_index);
2441   quic_common_get_transport_endpoint (ctx, tep, is_lcl);
2442 }
2443
2444 /*****************************************************************************
2445  * END TRANSPORT PROTO FUNCTIONS
2446 *****************************************************************************/
2447
2448 /* *INDENT-OFF* */
2449 static session_cb_vft_t quic_app_cb_vft = {
2450   .session_accept_callback = quic_session_accepted_callback,
2451   .session_disconnect_callback = quic_session_disconnect_callback,
2452   .session_connected_callback = quic_session_connected_callback,
2453   .session_reset_callback = quic_session_reset_callback,
2454   .add_segment_callback = quic_add_segment_callback,
2455   .del_segment_callback = quic_del_segment_callback,
2456   .builtin_app_rx_callback = quic_app_rx_callback,
2457 };
2458
2459 static const transport_proto_vft_t quic_proto = {
2460   .connect = quic_connect,
2461   .close = quic_proto_on_close,
2462   .start_listen = quic_start_listen,
2463   .stop_listen = quic_stop_listen,
2464   .get_connection = quic_connection_get,
2465   .get_listener = quic_listener_get,
2466   .update_time = quic_update_time,
2467   .app_rx_evt = quic_custom_app_rx_callback,
2468   .custom_tx = quic_custom_tx_callback,
2469   .format_connection = format_quic_connection,
2470   .format_half_open = format_quic_half_open,
2471   .format_listener = format_quic_listener,
2472   .get_transport_endpoint = quic_get_transport_endpoint,
2473   .get_transport_listener_endpoint = quic_get_transport_listener_endpoint,
2474   .transport_options = {
2475     .tx_type = TRANSPORT_TX_INTERNAL,
2476     .service_type = TRANSPORT_SERVICE_APP,
2477   },
2478 };
2479 /* *INDENT-ON* */
2480
2481 static clib_error_t *
2482 quic_init (vlib_main_t * vm)
2483 {
2484   u32 segment_size = 256 << 20;
2485   vlib_thread_main_t *vtm = vlib_get_thread_main ();
2486   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
2487   vnet_app_attach_args_t _a, *a = &_a;
2488   u64 options[APP_OPTIONS_N_OPTIONS];
2489   quic_main_t *qm = &quic_main;
2490   u32 fifo_size = QUIC_FIFO_SIZE;
2491   u32 num_threads, i;
2492
2493   num_threads = 1 /* main thread */  + vtm->n_threads;
2494
2495   memset (a, 0, sizeof (*a));
2496   memset (options, 0, sizeof (options));
2497
2498   a->session_cb_vft = &quic_app_cb_vft;
2499   a->api_client_index = APP_INVALID_INDEX;
2500   a->options = options;
2501   a->name = format (0, "quic");
2502   a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
2503   a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
2504   a->options[APP_OPTIONS_RX_FIFO_SIZE] = fifo_size;
2505   a->options[APP_OPTIONS_TX_FIFO_SIZE] = fifo_size;
2506   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
2507   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
2508   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_TRANSPORT_APP;
2509
2510   if (vnet_application_attach (a))
2511     {
2512       clib_warning ("failed to attach quic app");
2513       return clib_error_return (0, "failed to attach quic app");
2514     }
2515
2516   vec_validate (qm->ctx_pool, num_threads - 1);
2517   vec_validate (qm->wrk_ctx, num_threads - 1);
2518   /*  Timer wheels, one per thread. */
2519   for (i = 0; i < num_threads; i++)
2520     {
2521       tw = &qm->wrk_ctx[i].timer_wheel;
2522       tw_timer_wheel_init_1t_3w_1024sl_ov (tw, quic_expired_timers_dispatch,
2523                                            1e-3 /* timer period 1ms */ , ~0);
2524       tw->last_run_time = vlib_time_now (vlib_get_main ());
2525     }
2526
2527   clib_bihash_init_16_8 (&qm->connection_hash, "quic connections", 1024,
2528                          4 << 20);
2529
2530
2531   qm->app_index = a->app_index;
2532   qm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
2533     / QUIC_TSTAMP_RESOLUTION;
2534
2535   transport_register_protocol (TRANSPORT_PROTO_QUIC, &quic_proto,
2536                                FIB_PROTOCOL_IP4, ~0);
2537   transport_register_protocol (TRANSPORT_PROTO_QUIC, &quic_proto,
2538                                FIB_PROTOCOL_IP6, ~0);
2539
2540   vec_free (a->name);
2541   return 0;
2542 }
2543
2544 VLIB_INIT_FUNCTION (quic_init);
2545
2546 static clib_error_t *
2547 quic_plugin_crypto_command_fn (vlib_main_t * vm,
2548                                unformat_input_t * input,
2549                                vlib_cli_command_t * cmd)
2550 {
2551   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2552     {
2553       if (unformat (input, "vpp"))
2554         {
2555           quic_tlsctx.cipher_suites = vpp_crypto_cipher_suites;
2556           return 0;
2557         }
2558       else if (unformat (input, "picotls"))
2559         {
2560           quic_tlsctx.cipher_suites = ptls_openssl_cipher_suites;
2561           return 0;
2562         }
2563       else
2564         return clib_error_return (0, "unknown input '%U'",
2565                                   format_unformat_error, input);
2566     }
2567
2568   return clib_error_return (0, "unknown input '%U'",
2569                             format_unformat_error, input);
2570 }
2571
2572 /* *INDENT-OFF* */
2573 VLIB_CLI_COMMAND(quic_plugin_crypto_command, static)=
2574 {
2575         .path = "quic set crypto api",
2576         .short_help = "quic set crypto api [picotls, vpp]",
2577         .function = quic_plugin_crypto_command_fn,
2578 };
2579
2580 VLIB_PLUGIN_REGISTER () =
2581 {
2582   .version = VPP_BUILD_VER,
2583   .description = "Quic transport protocol",
2584 };
2585 /* *INDENT-ON* */
2586
2587 /*
2588  * fd.io coding-style-patch-verification: ON
2589  *
2590  * Local Variables:
2591  * eval: (c-set-style "gnu")
2592  * End:
2593  */