quic: fix show session verbose
[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   u8 *str = 0;
1636
1637   if (!ctx)
1638     return s;
1639   str = format (str, "[#%d][Q] ", ctx->c_thread_index);
1640
1641   if (quic_ctx_is_listener (ctx))
1642     str = format (str, "Listener, UDP %ld", ctx->udp_session_handle);
1643   else if (quic_ctx_is_stream (ctx))
1644     str = format (str, "Stream %ld conn %d",
1645                   ctx->c_quic_ctx_id.stream->stream_id,
1646                   ctx->c_quic_ctx_id.quic_connection_ctx_id);
1647   else                          /* connection */
1648     str = format (str, "Conn %d UDP %d", ctx->c_c_index,
1649                   ctx->udp_session_handle);
1650
1651   str = format (str, " app %d wrk %d", ctx->parent_app_id,
1652                 ctx->parent_app_wrk_id);
1653
1654   if (verbose == 1)
1655     s = format (s, "%-50s%-15d", str, ctx->c_quic_ctx_id.conn_state);
1656   else
1657     s = format (s, "%s\n", str);
1658   vec_free (str);
1659   return s;
1660 }
1661
1662 static u8 *
1663 format_quic_connection (u8 * s, va_list * args)
1664 {
1665   u32 qc_index = va_arg (*args, u32);
1666   u32 thread_index = va_arg (*args, u32);
1667   u32 verbose = va_arg (*args, u32);
1668   quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index);
1669   s = format (s, "%U", format_quic_ctx, ctx, verbose);
1670   return s;
1671 }
1672
1673 static u8 *
1674 format_quic_half_open (u8 * s, va_list * args)
1675 {
1676   u32 qc_index = va_arg (*args, u32);
1677   u32 thread_index = va_arg (*args, u32);
1678   quic_ctx_t *ctx = quic_ctx_get (qc_index, thread_index);
1679   s =
1680     format (s, "[#%d][Q] half-open app %u", thread_index, ctx->parent_app_id);
1681   return s;
1682 }
1683
1684 /*  TODO improve */
1685 static u8 *
1686 format_quic_listener (u8 * s, va_list * args)
1687 {
1688   u32 tci = va_arg (*args, u32);
1689   u32 thread_index = va_arg (*args, u32);
1690   u32 verbose = va_arg (*args, u32);
1691   quic_ctx_t *ctx = quic_ctx_get (tci, thread_index);
1692   s = format (s, "%U", format_quic_ctx, ctx, verbose);
1693   return s;
1694 }
1695
1696 /*****************************************************************************
1697  * END TRANSPORT PROTO FUNCTIONS
1698  *
1699  * START SESSION CALLBACKS
1700  * Called from UDP layer
1701  *****************************************************************************/
1702
1703 static inline void
1704 quic_build_sockaddr (struct sockaddr *sa, socklen_t * salen,
1705                      ip46_address_t * addr, u16 port, u8 is_ip4)
1706 {
1707   if (is_ip4)
1708     {
1709       struct sockaddr_in *sa4 = (struct sockaddr_in *) sa;
1710       sa4->sin_family = AF_INET;
1711       sa4->sin_port = port;
1712       sa4->sin_addr.s_addr = addr->ip4.as_u32;
1713       *salen = sizeof (struct sockaddr_in);
1714     }
1715   else
1716     {
1717       struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) sa;
1718       sa6->sin6_family = AF_INET6;
1719       sa6->sin6_port = port;
1720       clib_memcpy (&sa6->sin6_addr, &addr->ip6, 16);
1721       *salen = sizeof (struct sockaddr_in6);
1722     }
1723 }
1724
1725 static int
1726 quic_on_client_connected (quic_ctx_t * ctx)
1727 {
1728   session_t *quic_session;
1729   app_worker_t *app_wrk;
1730   u32 ctx_id = ctx->c_c_index;
1731   u32 thread_index = ctx->c_thread_index;
1732
1733   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1734   if (!app_wrk)
1735     {
1736       quic_disconnect_transport (ctx);
1737       return -1;
1738     }
1739
1740   quic_session = session_alloc (thread_index);
1741
1742   QUIC_DBG (2, "Allocated quic session 0x%lx", session_handle (quic_session));
1743   ctx->c_s_index = quic_session->session_index;
1744   quic_session->app_wrk_index = ctx->parent_app_wrk_id;
1745   quic_session->connection_index = ctx->c_c_index;
1746   quic_session->listener_handle = SESSION_INVALID_HANDLE;
1747   quic_session->session_type =
1748     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
1749                                     ctx->c_quic_ctx_id.udp_is_ip4);
1750
1751   if (app_worker_init_connected (app_wrk, quic_session))
1752     {
1753       QUIC_DBG (1, "failed to app_worker_init_connected");
1754       quic_proto_on_close (ctx_id, thread_index);
1755       return app_worker_connect_notify (app_wrk, NULL,
1756                                         ctx->c_quic_ctx_id.client_opaque);
1757     }
1758
1759   quic_session->session_state = SESSION_STATE_CONNECTING;
1760   if (app_worker_connect_notify
1761       (app_wrk, quic_session, ctx->c_quic_ctx_id.client_opaque))
1762     {
1763       QUIC_DBG (1, "failed to notify app");
1764       quic_proto_on_close (ctx_id, thread_index);
1765       return -1;
1766     }
1767
1768   /*  If the app opens a stream in its callback it may invalidate ctx */
1769   ctx = quic_ctx_get (ctx_id, thread_index);
1770   quic_session->session_state = SESSION_STATE_LISTENING;
1771
1772   return 0;
1773 }
1774
1775 static void
1776 quic_receive_connection (void *arg)
1777 {
1778   u32 new_ctx_id, thread_index = vlib_get_thread_index ();
1779   quic_ctx_t *temp_ctx, *new_ctx;
1780   clib_bihash_kv_16_8_t kv;
1781   quicly_conn_t *conn;
1782
1783   temp_ctx = arg;
1784   new_ctx_id = quic_ctx_alloc (thread_index);
1785   new_ctx = quic_ctx_get (new_ctx_id, thread_index);
1786
1787   QUIC_DBG (2, "Received conn %u (now %u)", temp_ctx->c_thread_index,
1788             new_ctx_id);
1789
1790
1791   memcpy (new_ctx, temp_ctx, sizeof (quic_ctx_t));
1792   free (temp_ctx);
1793
1794   new_ctx->c_thread_index = thread_index;
1795   new_ctx->c_c_index = new_ctx_id;
1796
1797   conn = new_ctx->c_quic_ctx_id.conn;
1798   quic_store_conn_ctx (conn, new_ctx);
1799   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1800   kv.value = ((u64) thread_index) << 32 | (u64) new_ctx_id;
1801   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
1802   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
1803   new_ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1804   quic_update_timer (new_ctx);
1805
1806   /*  Trigger read on this connection ? */
1807 }
1808
1809 static void
1810 quic_transfer_connection (u32 ctx_index, u32 dest_thread)
1811 {
1812   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
1813   quic_ctx_t *ctx, *temp_ctx;
1814   clib_bihash_kv_16_8_t kv;
1815   quicly_conn_t *conn;
1816   u32 thread_index = vlib_get_thread_index ();
1817
1818   QUIC_DBG (2, "Transferring conn %u to thread %u", ctx_index, dest_thread);
1819
1820   temp_ctx = malloc (sizeof (quic_ctx_t));
1821   ASSERT (temp_ctx);
1822   ctx = quic_ctx_get (ctx_index, thread_index);
1823
1824   memcpy (temp_ctx, ctx, sizeof (quic_ctx_t));
1825
1826   /*  Remove from lookup hash, timer wheel and thread-local pool */
1827   conn = ctx->c_quic_ctx_id.conn;
1828   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1829   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 0 /* is_add */ );
1830   if (ctx->timer_handle != QUIC_TIMER_HANDLE_INVALID)
1831     {
1832       tw = &quic_main.wrk_ctx[thread_index].timer_wheel;
1833       tw_timer_stop_1t_3w_1024sl_ov (tw, ctx->timer_handle);
1834     }
1835   quic_ctx_free (ctx);
1836
1837   /*  Send connection to destination thread */
1838   session_send_rpc_evt_to_thread (dest_thread, quic_receive_connection,
1839                                   (void *) temp_ctx);
1840 }
1841
1842 static void
1843 quic_transfer_connection_rpc (void *arg)
1844 {
1845   u64 arg_int = (u64) arg;
1846   u32 ctx_index, dest_thread;
1847
1848   ctx_index = (u32) (arg_int >> 32);
1849   dest_thread = (u32) (arg_int & UINT32_MAX);
1850   quic_transfer_connection (ctx_index, dest_thread);
1851 }
1852
1853 /*
1854  * This assumes that the connection is not yet associated to a session
1855  * So currently it only works on the client side when receiving the first packet
1856  * from the server
1857  */
1858 static void
1859 quic_move_connection_to_thread (u32 ctx_index, u32 owner_thread,
1860                                 u32 to_thread)
1861 {
1862   QUIC_DBG (2, "Requesting transfer of conn %u from thread %u", ctx_index,
1863             owner_thread);
1864   u64 arg = ((u64) ctx_index) << 32 | to_thread;
1865   session_send_rpc_evt_to_thread (owner_thread, quic_transfer_connection_rpc,
1866                                   (void *) arg);
1867 }
1868
1869 static int
1870 quic_session_connected_callback (u32 quic_app_index, u32 ctx_index,
1871                                  session_t * udp_session, u8 is_fail)
1872 {
1873   QUIC_DBG (2, "QSession is now connected (id %u)",
1874             udp_session->session_index);
1875   /* This should always be called before quic_connect returns since UDP always
1876    * connects instantly. */
1877   clib_bihash_kv_16_8_t kv;
1878   struct sockaddr_in6 sa6;
1879   struct sockaddr *sa = (struct sockaddr *) &sa6;
1880   socklen_t salen;
1881   transport_connection_t *tc;
1882   app_worker_t *app_wrk;
1883   quicly_conn_t *conn;
1884   application_t *app;
1885   quic_ctx_t *ctx;
1886   u32 thread_index = vlib_get_thread_index ();
1887   int ret;
1888
1889   ctx = quic_ctx_get (ctx_index, thread_index);
1890   if (is_fail)
1891     {
1892       u32 api_context;
1893       int rv = 0;
1894
1895       app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1896       if (app_wrk)
1897         {
1898           api_context = ctx->c_s_index;
1899           app_worker_connect_notify (app_wrk, 0, api_context);
1900         }
1901       return rv;
1902     }
1903
1904   app_wrk = app_worker_get_if_valid (ctx->parent_app_wrk_id);
1905   if (!app_wrk)
1906     {
1907       QUIC_DBG (1, "Appwrk not found");
1908       return -1;
1909     }
1910   app = application_get (app_wrk->app_index);
1911
1912   ctx->c_thread_index = thread_index;
1913   ctx->c_c_index = ctx_index;
1914
1915   QUIC_DBG (2, "Quic connect returned %u. New ctx [%u]%x",
1916             is_fail, thread_index, (ctx) ? ctx_index : ~0);
1917
1918   ctx->udp_session_handle = session_handle (udp_session);
1919   udp_session->opaque = ctx->parent_app_id;
1920   udp_session->session_state = SESSION_STATE_READY;
1921
1922   /* Init QUIC lib connection
1923    * Generate required sockaddr & salen */
1924   tc = session_get_transport (udp_session);
1925   quic_build_sockaddr (sa, &salen, &tc->rmt_ip, tc->rmt_port, tc->is_ip4);
1926
1927   ret =
1928     quicly_connect (&ctx->c_quic_ctx_id.conn,
1929                     (quicly_context_t *) app->quicly_ctx,
1930                     (char *) ctx->c_quic_ctx_id.srv_hostname, sa, salen,
1931                     &quic_main.next_cid, &quic_main.hs_properties, NULL);
1932   ++quic_main.next_cid.master_id;
1933   /*  Save context handle in quicly connection */
1934   quic_store_conn_ctx (ctx->c_quic_ctx_id.conn, ctx);
1935   assert (ret == 0);
1936
1937   /*  Register connection in connections map */
1938   conn = ctx->c_quic_ctx_id.conn;
1939   quic_make_connection_key (&kv, quicly_get_master_id (conn));
1940   kv.value = ((u64) thread_index) << 32 | (u64) ctx_index;
1941   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
1942   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
1943
1944   quic_send_packets (ctx);
1945
1946   /*  UDP stack quirk? preemptively transfer connection if that happens */
1947   if (udp_session->thread_index != thread_index)
1948     quic_transfer_connection (ctx_index, udp_session->thread_index);
1949
1950   return ret;
1951 }
1952
1953 static void
1954 quic_session_disconnect_callback (session_t * s)
1955 {
1956   clib_warning ("UDP session disconnected???");
1957 }
1958
1959 static void
1960 quic_session_reset_callback (session_t * s)
1961 {
1962   clib_warning ("UDP session reset???");
1963 }
1964
1965 int
1966 quic_session_accepted_callback (session_t * udp_session)
1967 {
1968   /* New UDP connection, try to accept it */
1969   u32 ctx_index;
1970   u32 *pool_index;
1971   quic_ctx_t *ctx, *lctx;
1972   session_t *udp_listen_session;
1973   u32 thread_index = vlib_get_thread_index ();
1974
1975   udp_listen_session =
1976     listen_session_get_from_handle (udp_session->listener_handle);
1977
1978   ctx_index = quic_ctx_alloc (thread_index);
1979   ctx = quic_ctx_get (ctx_index, thread_index);
1980   ctx->c_thread_index = udp_session->thread_index;
1981   ctx->c_c_index = ctx_index;
1982   ctx->c_s_index = QUIC_SESSION_INVALID;
1983   ctx->udp_session_handle = session_handle (udp_session);
1984   QUIC_DBG (2, "ACCEPTED UDP 0x%lx", ctx->udp_session_handle);
1985   ctx->c_quic_ctx_id.listener_ctx_id = udp_listen_session->opaque;
1986   lctx = quic_ctx_get (udp_listen_session->opaque,
1987                        udp_listen_session->thread_index);
1988   ctx->c_quic_ctx_id.udp_is_ip4 = lctx->c_is_ip4;
1989   ctx->parent_app_id = lctx->parent_app_id;
1990   ctx->parent_app_wrk_id = lctx->parent_app_wrk_id;
1991   ctx->timer_handle = QUIC_TIMER_HANDLE_INVALID;
1992   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_OPENED;
1993   ctx->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
1994
1995   udp_session->opaque = ctx->parent_app_id;
1996
1997   /* Put this ctx in the "opening" pool */
1998   pool_get (quic_main.wrk_ctx[ctx->c_thread_index].opening_ctx_pool,
1999             pool_index);
2000   *pool_index = ctx_index;
2001
2002   /* TODO timeout to delete these if they never connect */
2003   return 0;
2004 }
2005
2006 static int
2007 quic_add_segment_callback (u32 client_index, u64 seg_handle)
2008 {
2009   QUIC_DBG (2, "Called quic_add_segment_callback");
2010   QUIC_DBG (2, "NOT IMPLEMENTED");
2011   /* No-op for builtin */
2012   return 0;
2013 }
2014
2015 static int
2016 quic_del_segment_callback (u32 client_index, u64 seg_handle)
2017 {
2018   QUIC_DBG (2, "Called quic_del_segment_callback");
2019   QUIC_DBG (2, "NOT IMPLEMENTED");
2020   /* No-op for builtin */
2021   return 0;
2022 }
2023
2024
2025 static int
2026 quic_custom_app_rx_callback (transport_connection_t * tc)
2027 {
2028   quic_ctx_t *ctx;
2029   session_t *stream_session = session_get (tc->s_index, tc->thread_index);
2030   QUIC_DBG (3, "Received app READ notification");
2031   quic_ack_rx_data (stream_session);
2032   svm_fifo_reset_has_deq_ntf (stream_session->rx_fifo);
2033
2034   /* Need to send packets (acks may never be sent otherwise) */
2035   ctx = quic_ctx_get (stream_session->connection_index,
2036                       stream_session->thread_index);
2037   quic_send_packets (ctx);
2038   return 0;
2039 }
2040
2041 static int
2042 quic_custom_tx_callback (void *s)
2043 {
2044   session_t *stream_session = (session_t *) s;
2045   quicly_stream_t *stream;
2046   quic_ctx_t *ctx;
2047   int rv;
2048
2049   if (PREDICT_FALSE
2050       (stream_session->session_state >= SESSION_STATE_TRANSPORT_CLOSING))
2051     return 0;
2052   ctx =
2053     quic_ctx_get (stream_session->connection_index,
2054                   stream_session->thread_index);
2055   if (PREDICT_FALSE (!quic_ctx_is_stream (ctx)))
2056     {
2057       goto tx_end;              /* Most probably a reschedule */
2058     }
2059
2060   QUIC_DBG (3, "Stream TX event");
2061   quic_ack_rx_data (stream_session);
2062   if (!svm_fifo_max_dequeue (stream_session->tx_fifo))
2063     return 0;
2064
2065   stream = ctx->c_quic_ctx_id.stream;
2066   if (!quicly_sendstate_is_open (&stream->sendstate))
2067     {
2068       QUIC_DBG (1, "Warning: tried to send on closed stream");
2069       return -1;
2070     }
2071
2072   if ((rv = quicly_stream_sync_sendbuf (stream, 1)) != 0)
2073     return rv;
2074
2075 tx_end:
2076   quic_send_packets (ctx);
2077   return 0;
2078 }
2079
2080
2081 /*
2082  * Returns 0 if a matching connection is found and is on the right thread.
2083  * If a connection is found, even on the wrong thread, ctx_thread and ctx_index
2084  * will be set.
2085  */
2086 static inline int
2087 quic_find_packet_ctx (u32 * ctx_thread, u32 * ctx_index,
2088                       struct sockaddr *sa, socklen_t salen,
2089                       quicly_decoded_packet_t * packet,
2090                       u32 caller_thread_index)
2091 {
2092   quic_ctx_t *ctx_;
2093   quicly_conn_t *conn_;
2094   clib_bihash_kv_16_8_t kv;
2095   clib_bihash_16_8_t *h;
2096
2097   h = &quic_main.connection_hash;
2098   quic_make_connection_key (&kv, &packet->cid.dest.plaintext);
2099   QUIC_DBG (3, "Searching conn with id %lu %lu", kv.key[0], kv.key[1]);
2100
2101   if (clib_bihash_search_16_8 (h, &kv, &kv) == 0)
2102     {
2103       u32 index = kv.value & UINT32_MAX;
2104       u8 thread_id = kv.value >> 32;
2105       /* Check if this connection belongs to this thread, otherwise
2106        * ask for it to be moved */
2107       if (thread_id != caller_thread_index)
2108         {
2109           QUIC_DBG (2, "Connection is on wrong thread");
2110           /* Cannot make full check with quicly_is_destination... */
2111           *ctx_index = index;
2112           *ctx_thread = thread_id;
2113           return -1;
2114         }
2115       ctx_ = quic_ctx_get (index, vlib_get_thread_index ());
2116       conn_ = ctx_->c_quic_ctx_id.conn;
2117       if (conn_ && quicly_is_destination (conn_, sa, salen, packet))
2118         {
2119           QUIC_DBG (3, "Connection found");
2120           *ctx_index = index;
2121           *ctx_thread = thread_id;
2122           return 0;
2123         }
2124     }
2125   QUIC_DBG (3, "connection not found");
2126   return -1;
2127 }
2128
2129 static int
2130 quic_receive (quic_ctx_t * ctx, quicly_conn_t * conn,
2131               quicly_decoded_packet_t packet)
2132 {
2133   int rv;
2134   u32 ctx_id = ctx->c_c_index;
2135   u32 thread_index = ctx->c_thread_index;
2136   /* TODO : QUICLY_ERROR_PACKET_IGNORED sould be handled */
2137   rv = quicly_receive (conn, &packet);
2138   if (rv)
2139     {
2140       QUIC_DBG (2, "quicly_receive errored %U", quic_format_err, rv);
2141       return 0;
2142     }
2143   /* ctx pointer may change if a new stream is opened */
2144   ctx = quic_ctx_get (ctx_id, thread_index);
2145   /* Conn may be set to null if the connection is terminated */
2146   if (ctx->c_quic_ctx_id.conn
2147       && ctx->c_quic_ctx_id.conn_state == QUIC_CONN_STATE_HANDSHAKE)
2148     {
2149       if (quicly_connection_is_ready (conn))
2150         {
2151           ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_READY;
2152           if (quicly_is_client (conn))
2153             {
2154               quic_on_client_connected (ctx);
2155               ctx = quic_ctx_get (ctx_id, thread_index);
2156             }
2157         }
2158     }
2159   return quic_send_packets (ctx);
2160 }
2161
2162 static int
2163 quic_create_quic_session (quic_ctx_t * ctx)
2164 {
2165   session_t *quic_session;
2166   app_worker_t *app_wrk;
2167   quic_ctx_t *lctx;
2168   int rv;
2169
2170   quic_session = session_alloc (ctx->c_thread_index);
2171   QUIC_DBG (2, "Allocated quic_session, 0x%lx ctx %u",
2172             session_handle (quic_session), ctx->c_c_index);
2173   quic_session->session_state = SESSION_STATE_LISTENING;
2174   ctx->c_s_index = quic_session->session_index;
2175
2176   lctx = quic_ctx_get (ctx->c_quic_ctx_id.listener_ctx_id, 0);
2177
2178   quic_session->app_wrk_index = lctx->parent_app_wrk_id;
2179   quic_session->connection_index = ctx->c_c_index;
2180   quic_session->session_type =
2181     session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
2182                                     ctx->c_quic_ctx_id.udp_is_ip4);
2183   quic_session->listener_handle = lctx->c_s_index;
2184
2185   /* TODO: don't alloc fifos when we don't transfer data on this session
2186    * but we still need fifos for the events? */
2187   if ((rv = app_worker_init_accepted (quic_session)))
2188     {
2189       QUIC_DBG (1, "failed to allocate fifos");
2190       session_free (quic_session);
2191       return rv;
2192     }
2193   app_wrk = app_worker_get (quic_session->app_wrk_index);
2194   rv = app_worker_accept_notify (app_wrk, quic_session);
2195   if (rv)
2196     {
2197       QUIC_DBG (1, "failed to notify accept worker app");
2198       return rv;
2199     }
2200   return 0;
2201 }
2202
2203 static int
2204 quic_create_connection (quicly_context_t * quicly_ctx,
2205                         u32 ctx_index, struct sockaddr *sa,
2206                         socklen_t salen, quicly_decoded_packet_t packet)
2207 {
2208   clib_bihash_kv_16_8_t kv;
2209   quic_ctx_t *ctx;
2210   quicly_conn_t *conn;
2211   u32 thread_index = vlib_get_thread_index ();
2212   int rv;
2213
2214   /* new connection, accept and create context if packet is valid
2215    * TODO: check if socket is actually listening? */
2216   if ((rv = quicly_accept (&conn, quicly_ctx, sa, salen,
2217                            &packet, ptls_iovec_init (NULL, 0),
2218                            &quic_main.next_cid, NULL)))
2219     {
2220       /* Invalid packet, pass */
2221       assert (conn == NULL);
2222       QUIC_DBG (1, "Accept failed with %d", rv);
2223       /* TODO: cleanup created quic ctx and UDP session */
2224       return 0;
2225     }
2226   assert (conn != NULL);
2227
2228   ++quic_main.next_cid.master_id;
2229   ctx = quic_ctx_get (ctx_index, thread_index);
2230   /* Save ctx handle in quicly connection */
2231   quic_store_conn_ctx (conn, ctx);
2232   ctx->c_quic_ctx_id.conn = conn;
2233   ctx->c_quic_ctx_id.conn_state = QUIC_CONN_STATE_HANDSHAKE;
2234
2235   quic_create_quic_session (ctx);
2236
2237   /* Register connection in connections map */
2238   quic_make_connection_key (&kv, quicly_get_master_id (conn));
2239   kv.value = ((u64) thread_index) << 32 | (u64) ctx_index;
2240   clib_bihash_add_del_16_8 (&quic_main.connection_hash, &kv, 1 /* is_add */ );
2241   QUIC_DBG (2, "Registering conn with id %lu %lu", kv.key[0], kv.key[1]);
2242
2243   return quic_send_packets (ctx);
2244 }
2245
2246 static int
2247 quic_reset_connection (quicly_context_t * quicly_ctx, u64 udp_session_handle,
2248                        struct sockaddr *sa, socklen_t salen,
2249                        quicly_decoded_packet_t packet)
2250 {
2251   /* short header packet; potentially a dead connection. No need to check the
2252    * length of the incoming packet, because loop is prevented by authenticating
2253    * the CID (by checking node_id and thread_id). If the peer is also sending a
2254    * reset, then the next CID is highly likely to contain a non-authenticating
2255    * CID, ... */
2256   QUIC_DBG (2, "Sending stateless reset");
2257   int rv;
2258   quicly_datagram_t *dgram;
2259   session_t *udp_session;
2260   if (packet.cid.dest.plaintext.node_id == 0
2261       && packet.cid.dest.plaintext.thread_id == 0)
2262     {
2263       dgram = quicly_send_stateless_reset (quicly_ctx, sa, salen,
2264                                            &packet.cid.dest.plaintext);
2265       if (dgram == NULL)
2266         return 1;
2267       udp_session = session_get_from_handle (udp_session_handle);
2268       rv = quic_send_datagram (udp_session, dgram);
2269       if (svm_fifo_set_event (udp_session->tx_fifo))
2270         session_send_io_evt_to_thread (udp_session->tx_fifo,
2271                                        SESSION_IO_EVT_TX);
2272       return rv;
2273     }
2274   return 0;
2275 }
2276
2277 static int
2278 quic_app_rx_callback (session_t * udp_session)
2279 {
2280   /*  Read data from UDP rx_fifo and pass it to the quicly conn. */
2281   quicly_decoded_packet_t packet;
2282   session_dgram_hdr_t ph;
2283   application_t *app;
2284   quic_ctx_t *ctx = NULL;
2285   svm_fifo_t *f;
2286   size_t plen;
2287   struct sockaddr_in6 sa6;
2288   struct sockaddr *sa = (struct sockaddr *) &sa6;
2289   socklen_t salen;
2290   u32 max_deq, full_len, ctx_index = UINT32_MAX, ctx_thread = UINT32_MAX, ret;
2291   u8 *data;
2292   int err;
2293   u32 *opening_ctx_pool, *ctx_index_ptr;
2294   u32 app_index = udp_session->opaque;
2295   u64 udp_session_handle = session_handle (udp_session);
2296   int rv = 0;
2297   u32 thread_index = vlib_get_thread_index ();
2298   app = application_get_if_valid (app_index);
2299   if (!app)
2300     {
2301       QUIC_DBG (1, "Got RX on detached app");
2302       /*  TODO: close this session, cleanup state? */
2303       return 1;
2304     }
2305
2306   do
2307     {
2308       udp_session = session_get_from_handle (udp_session_handle);       /*  session alloc might have happened */
2309       f = udp_session->rx_fifo;
2310       max_deq = svm_fifo_max_dequeue (f);
2311       if (max_deq == 0)
2312         return 0;
2313
2314       if (max_deq < SESSION_CONN_HDR_LEN)
2315         {
2316           QUIC_DBG (1, "Not enough data for even a header in RX");
2317           return 1;
2318         }
2319       ret = svm_fifo_peek (f, 0, SESSION_CONN_HDR_LEN, (u8 *) & ph);
2320       if (ret != SESSION_CONN_HDR_LEN)
2321         {
2322           QUIC_DBG (1, "Not enough data for header in RX");
2323           return 1;
2324         }
2325       ASSERT (ph.data_offset == 0);
2326       full_len = ph.data_length + SESSION_CONN_HDR_LEN;
2327       if (full_len > max_deq)
2328         {
2329           QUIC_DBG (1, "Not enough data in fifo RX");
2330           return 1;
2331         }
2332
2333       /* Quicly can read len bytes from the fifo at offset:
2334        * ph.data_offset + SESSION_CONN_HDR_LEN */
2335       data = malloc (ph.data_length);
2336       ret = svm_fifo_peek (f, SESSION_CONN_HDR_LEN, ph.data_length, data);
2337       if (ret != ph.data_length)
2338         {
2339           QUIC_DBG (1, "Not enough data peeked in RX");
2340           free (data);
2341           return 1;
2342         }
2343
2344       rv = 0;
2345       quic_build_sockaddr (sa, &salen, &ph.rmt_ip, ph.rmt_port, ph.is_ip4);
2346       plen = quicly_decode_packet ((quicly_context_t *) app->quicly_ctx,
2347                                    &packet, data, ph.data_length);
2348
2349       if (plen != SIZE_MAX)
2350         {
2351
2352           err = quic_find_packet_ctx (&ctx_thread, &ctx_index, sa, salen,
2353                                       &packet, thread_index);
2354           if (err == 0)
2355             {
2356               ctx = quic_ctx_get (ctx_index, thread_index);
2357               quic_receive (ctx, ctx->c_quic_ctx_id.conn, packet);
2358             }
2359           else if (ctx_thread != UINT32_MAX)
2360             {
2361               /*  Connection found but on wrong thread, ask move */
2362               quic_move_connection_to_thread (ctx_index, ctx_thread,
2363                                               thread_index);
2364             }
2365           else if ((packet.octets.base[0] & QUICLY_PACKET_TYPE_BITMASK) ==
2366                    QUICLY_PACKET_TYPE_INITIAL)
2367             {
2368               /*  Try to find matching "opening" ctx */
2369               opening_ctx_pool =
2370                 quic_main.wrk_ctx[thread_index].opening_ctx_pool;
2371
2372               /* *INDENT-OFF* */
2373               pool_foreach (ctx_index_ptr, opening_ctx_pool,
2374               ({
2375                 ctx = quic_ctx_get (*ctx_index_ptr, thread_index);
2376                 if (ctx->udp_session_handle == udp_session_handle)
2377                   {
2378                     /*  Right ctx found, create conn & remove from pool */
2379                     quic_create_connection ((quicly_context_t *) app->quicly_ctx,
2380                                             *ctx_index_ptr, sa, salen, packet);
2381                     pool_put (opening_ctx_pool, ctx_index_ptr);
2382                     goto ctx_search_done;
2383                   }
2384               }));
2385               /* *INDENT-ON* */
2386
2387             }
2388           else
2389             {
2390               quic_reset_connection ((quicly_context_t *) app->quicly_ctx,
2391                                      udp_session_handle, sa, salen, packet);
2392             }
2393         }
2394     ctx_search_done:
2395       svm_fifo_dequeue_drop (f, full_len);
2396       free (data);
2397     }
2398   while (1);
2399   return rv;
2400 }
2401
2402 always_inline void
2403 quic_common_get_transport_endpoint (quic_ctx_t * ctx,
2404                                     transport_endpoint_t * tep, u8 is_lcl)
2405 {
2406   session_t *udp_session;
2407   if (!quic_ctx_is_stream (ctx))
2408     {
2409       udp_session = session_get_from_handle (ctx->udp_session_handle);
2410       session_get_endpoint (udp_session, tep, is_lcl);
2411     }
2412 }
2413
2414 static void
2415 quic_get_transport_listener_endpoint (u32 listener_index,
2416                                       transport_endpoint_t * tep, u8 is_lcl)
2417 {
2418   quic_ctx_t *ctx;
2419   app_listener_t *app_listener;
2420   session_t *udp_listen_session;
2421   ctx = quic_ctx_get (listener_index, vlib_get_thread_index ());
2422   if (quic_ctx_is_listener (ctx))
2423     {
2424       app_listener = app_listener_get_w_handle (ctx->udp_session_handle);
2425       udp_listen_session = app_listener_get_session (app_listener);
2426       return session_get_endpoint (udp_listen_session, tep, is_lcl);
2427     }
2428   quic_common_get_transport_endpoint (ctx, tep, is_lcl);
2429 }
2430
2431 static void
2432 quic_get_transport_endpoint (u32 ctx_index, u32 thread_index,
2433                              transport_endpoint_t * tep, u8 is_lcl)
2434 {
2435   quic_ctx_t *ctx;
2436   ctx = quic_ctx_get (ctx_index, thread_index);
2437   quic_common_get_transport_endpoint (ctx, tep, is_lcl);
2438 }
2439
2440 /*****************************************************************************
2441  * END TRANSPORT PROTO FUNCTIONS
2442 *****************************************************************************/
2443
2444 /* *INDENT-OFF* */
2445 static session_cb_vft_t quic_app_cb_vft = {
2446   .session_accept_callback = quic_session_accepted_callback,
2447   .session_disconnect_callback = quic_session_disconnect_callback,
2448   .session_connected_callback = quic_session_connected_callback,
2449   .session_reset_callback = quic_session_reset_callback,
2450   .add_segment_callback = quic_add_segment_callback,
2451   .del_segment_callback = quic_del_segment_callback,
2452   .builtin_app_rx_callback = quic_app_rx_callback,
2453 };
2454
2455 static const transport_proto_vft_t quic_proto = {
2456   .connect = quic_connect,
2457   .close = quic_proto_on_close,
2458   .start_listen = quic_start_listen,
2459   .stop_listen = quic_stop_listen,
2460   .get_connection = quic_connection_get,
2461   .get_listener = quic_listener_get,
2462   .update_time = quic_update_time,
2463   .app_rx_evt = quic_custom_app_rx_callback,
2464   .custom_tx = quic_custom_tx_callback,
2465   .format_connection = format_quic_connection,
2466   .format_half_open = format_quic_half_open,
2467   .format_listener = format_quic_listener,
2468   .get_transport_endpoint = quic_get_transport_endpoint,
2469   .get_transport_listener_endpoint = quic_get_transport_listener_endpoint,
2470   .transport_options = {
2471     .tx_type = TRANSPORT_TX_INTERNAL,
2472     .service_type = TRANSPORT_SERVICE_APP,
2473   },
2474 };
2475 /* *INDENT-ON* */
2476
2477 static clib_error_t *
2478 quic_init (vlib_main_t * vm)
2479 {
2480   u32 segment_size = 256 << 20;
2481   vlib_thread_main_t *vtm = vlib_get_thread_main ();
2482   tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
2483   vnet_app_attach_args_t _a, *a = &_a;
2484   u64 options[APP_OPTIONS_N_OPTIONS];
2485   quic_main_t *qm = &quic_main;
2486   u32 fifo_size = QUIC_FIFO_SIZE;
2487   u32 num_threads, i;
2488
2489   num_threads = 1 /* main thread */  + vtm->n_threads;
2490
2491   memset (a, 0, sizeof (*a));
2492   memset (options, 0, sizeof (options));
2493
2494   a->session_cb_vft = &quic_app_cb_vft;
2495   a->api_client_index = APP_INVALID_INDEX;
2496   a->options = options;
2497   a->name = format (0, "quic");
2498   a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
2499   a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
2500   a->options[APP_OPTIONS_RX_FIFO_SIZE] = fifo_size;
2501   a->options[APP_OPTIONS_TX_FIFO_SIZE] = fifo_size;
2502   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
2503   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
2504   a->options[APP_OPTIONS_FLAGS] |= APP_OPTIONS_FLAGS_IS_TRANSPORT_APP;
2505
2506   if (vnet_application_attach (a))
2507     {
2508       clib_warning ("failed to attach quic app");
2509       return clib_error_return (0, "failed to attach quic app");
2510     }
2511
2512   vec_validate (qm->ctx_pool, num_threads - 1);
2513   vec_validate (qm->wrk_ctx, num_threads - 1);
2514   /*  Timer wheels, one per thread. */
2515   for (i = 0; i < num_threads; i++)
2516     {
2517       tw = &qm->wrk_ctx[i].timer_wheel;
2518       tw_timer_wheel_init_1t_3w_1024sl_ov (tw, quic_expired_timers_dispatch,
2519                                            1e-3 /* timer period 1ms */ , ~0);
2520       tw->last_run_time = vlib_time_now (vlib_get_main ());
2521     }
2522
2523   clib_bihash_init_16_8 (&qm->connection_hash, "quic connections", 1024,
2524                          4 << 20);
2525
2526
2527   qm->app_index = a->app_index;
2528   qm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock
2529     / QUIC_TSTAMP_RESOLUTION;
2530
2531   transport_register_protocol (TRANSPORT_PROTO_QUIC, &quic_proto,
2532                                FIB_PROTOCOL_IP4, ~0);
2533   transport_register_protocol (TRANSPORT_PROTO_QUIC, &quic_proto,
2534                                FIB_PROTOCOL_IP6, ~0);
2535
2536   vec_free (a->name);
2537   return 0;
2538 }
2539
2540 VLIB_INIT_FUNCTION (quic_init);
2541
2542 /* *INDENT-OFF* */
2543 VLIB_PLUGIN_REGISTER () =
2544 {
2545   .version = VPP_BUILD_VER,
2546   .description = "Quic transport protocol",
2547 };
2548 /* *INDENT-ON* */
2549
2550 /*
2551  * fd.io coding-style-patch-verification: ON
2552  *
2553  * Local Variables:
2554  * eval: (c-set-style "gnu")
2555  * End:
2556  */