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