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