- for (i = 0; i != num_packets; ++i)
- {
- if ((err = quic_send_datagram (udp_session, packets[i])))
- goto quicly_error;
-
- quicly_context->packet_allocator->
- free_packet (quicly_context->packet_allocator, packets[i]);
- }
- }
- while (num_packets > 0 && num_packets == max_packets);
-
- if (svm_fifo_set_event (udp_session->tx_fifo))
- session_send_io_evt_to_thread (udp_session->tx_fifo, SESSION_IO_EVT_TX);
-
-stop_sending:
- quic_update_timer (ctx);
- return 0;
-
-quicly_error:
- if ((err != QUICLY_ERROR_PACKET_IGNORED) & (err !=
- QUICLY_ERROR_FREE_CONNECTION))
- clib_warning ("Quic error '%s'.", quic_format_err (err));
- quic_connection_closed (ctx->c_c_index, ctx->c_thread_index);
- return 1;
-}
-
-/*****************************************************************************
- * START QUICLY CALLBACKS
- * Called from QUIC lib
- *****************************************************************************/
-
-static void
-quic_on_stream_destroy (quicly_stream_t * stream, int err)
-{
- quic_stream_data_t *stream_data = (quic_stream_data_t *) stream->data;
- quic_ctx_t *sctx =
- quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
- session_t *stream_session =
- session_get (sctx->c_s_index, sctx->c_thread_index);
- QUIC_DBG (2, "DESTROYED_STREAM: session 0x%lx (code 0x%x)",
- session_handle (stream_session), err);
-
- stream_session->session_state = SESSION_STATE_CLOSED;
- session_transport_delete_notify (&sctx->connection);
-
- quic_ctx_free (sctx);
- free (stream->data);
-}
-
-static int
-quic_on_stop_sending (quicly_stream_t * stream, int err)
-{
-#if QUIC_DEBUG >= 2
- quic_stream_data_t *stream_data = (quic_stream_data_t *) stream->data;
- quic_ctx_t *sctx =
- quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
- session_t *stream_session =
- session_get (sctx->c_s_index, sctx->c_thread_index);
- clib_warning ("(NOT IMPLEMENTD) STOP_SENDING: session 0x%lx (code 0x%x)",
- session_handle (stream_session), err);
-#endif
- /* TODO : handle STOP_SENDING */
- return 0;
-}
-
-static int
-quic_on_receive_reset (quicly_stream_t * stream, int err)
-{
- quic_stream_data_t *stream_data = (quic_stream_data_t *) stream->data;
- quic_ctx_t *sctx =
- quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
-#if QUIC_DEBUG >= 2
- session_t *stream_session =
- session_get (sctx->c_s_index, sctx->c_thread_index);
- clib_warning ("RESET_STREAM: session 0x%lx (code 0x%x)",
- session_handle (stream_session), err);
-#endif
-
- session_transport_closing_notify (&sctx->connection);
- return 0;
-}
-
-static session_t *
-get_stream_session_from_stream (quicly_stream_t * stream)
-{
- quic_ctx_t *ctx;
- quic_stream_data_t *stream_data;
-
- stream_data = (quic_stream_data_t *) stream->data;
- ctx = quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
- return session_get (ctx->c_s_index, stream_data->thread_index);
-}
-
-static int
-quic_on_receive (quicly_stream_t * stream, size_t off, const void *src,
- size_t len)
-{
- QUIC_DBG (3, "received data: %lu bytes, offset %lu", len, off);
- u32 max_enq;
- quic_ctx_t *sctx;
- session_t *stream_session;
- app_worker_t *app_wrk;
- svm_fifo_t *f;
- quic_stream_data_t *stream_data;
- int rlen;
-
- stream_data = (quic_stream_data_t *) stream->data;
- sctx = quic_ctx_get (stream_data->ctx_id, stream_data->thread_index);
- stream_session = session_get (sctx->c_s_index, stream_data->thread_index);
- f = stream_session->rx_fifo;
-
- max_enq = svm_fifo_max_enqueue_prod (f);
- QUIC_DBG (3, "Enqueuing %u at off %u in %u space", len, off, max_enq);
- if (off + len > max_enq)
- {
- /* TODO : can we find a better solution, listening on RX fifo evts ? */
- QUIC_DBG (3, "Ingoring packet, RX fifo is full");
- return QUICLY_ERROR_PACKET_IGNORED;
- }
- if (off == 0)
- {
- rlen = svm_fifo_enqueue (f, len, (u8 *) src);
- ASSERT (rlen >= len);
-
- quicly_stream_sync_recvbuf (stream, rlen);
- app_wrk = app_worker_get_if_valid (stream_session->app_wrk_index);
- if (PREDICT_TRUE (app_wrk != 0))
- app_worker_lock_and_send_event (app_wrk, stream_session,
- SESSION_IO_EVT_RX);
- }
- else
- {
- rlen = svm_fifo_enqueue_with_offset (f, off, len, (u8 *) src);
- ASSERT (rlen == 0);
- }
- return 0;
-}
-
-void
-quic_fifo_egress_shift (quicly_stream_t * stream, size_t delta)
-{
- session_t *stream_session;
- svm_fifo_t *f;
-
- stream_session = get_stream_session_from_stream (stream);
- f = stream_session->tx_fifo;
-
- ASSERT (svm_fifo_dequeue_drop (f, delta) == delta);
- quicly_stream_sync_sendbuf (stream, 0);
-}
-
-int
-quic_fifo_egress_emit (quicly_stream_t * stream, size_t off, void *dst,
- size_t * len, int *wrote_all)
-{
- session_t *stream_session;
- svm_fifo_t *f;
- u32 deq_max, first_deq, max_rd_chunk, rem_offset;
-
- stream_session = get_stream_session_from_stream (stream);
- f = stream_session->tx_fifo;
-
- QUIC_DBG (3, "Emitting %u, offset %u", *len, off);
-
- deq_max = svm_fifo_max_dequeue_cons (f);
- ASSERT (off <= deq_max);
- if (off + *len < deq_max)
- {
- *wrote_all = 0;
- }
- else
- {
- QUIC_DBG (3, "Wrote ALL");
- *wrote_all = 1;
- *len = deq_max - off;
- }
-
- /* TODO, use something like : return svm_fifo_peek (f, off, *len, dst); */
- max_rd_chunk = svm_fifo_max_read_chunk (f);
-
- first_deq = 0;
- if (off < max_rd_chunk)
- {
- first_deq = clib_min (*len, max_rd_chunk - off);
- clib_memcpy_fast (dst, svm_fifo_head (f) + off, first_deq);
- }
-
- if (max_rd_chunk < off + *len)
- {
- rem_offset = max_rd_chunk < off ? off - max_rd_chunk : 0;
- clib_memcpy_fast (dst + first_deq, f->head_chunk->data + rem_offset,
- *len - first_deq);
- }
-
- return 0;
-}
-
-static const quicly_stream_callbacks_t quic_stream_callbacks = {
- .on_destroy = quic_on_stream_destroy,
- .on_send_shift = quic_fifo_egress_shift,
- .on_send_emit = quic_fifo_egress_emit,
- .on_send_stop = quic_on_stop_sending,
- .on_receive = quic_on_receive,
- .on_receive_reset = quic_on_receive_reset
-};
-
-static void
-quic_accept_stream (void *s)
-{
- quicly_stream_t *stream = (quicly_stream_t *) s;
- session_t *stream_session, *quic_session;
- quic_stream_data_t *stream_data;
- app_worker_t *app_wrk;
- quic_ctx_t *qctx, *sctx;
- u32 sctx_id;
- int rv;
-
- sctx_id = quic_ctx_alloc (vlib_get_thread_index ());
-
- qctx = quic_get_conn_ctx (stream->conn);
-
- stream_session = session_alloc (qctx->c_thread_index);
- QUIC_DBG (2, "Allocated stream_session, id %u, thread %u ctx %u",
- stream_session->session_index, stream_session->thread_index,
- sctx_id);
- sctx = quic_ctx_get (sctx_id, qctx->c_thread_index);
- sctx->c_quic_ctx_id.parent_app_wrk_id =
- qctx->c_quic_ctx_id.parent_app_wrk_id;
- sctx->c_quic_ctx_id.parent_app_id = qctx->c_quic_ctx_id.parent_app_id;
- sctx->c_quic_ctx_id.quic_connection_ctx_id = qctx->c_c_index;
- sctx->c_c_index = sctx_id;
- sctx->c_quic_ctx_id.is_stream = 1;
- sctx->c_s_index = stream_session->session_index;
- sctx->c_quic_ctx_id.stream = stream;
-
- stream_data = (quic_stream_data_t *) stream->data;
- stream_data->ctx_id = sctx_id;
- stream_data->thread_index = sctx->c_thread_index;
-
- sctx->c_s_index = stream_session->session_index;
- stream_session->session_state = SESSION_STATE_CREATED;
- stream_session->app_wrk_index = sctx->c_quic_ctx_id.parent_app_wrk_id;
- stream_session->connection_index = sctx->c_c_index;
- stream_session->session_type =
- session_type_from_proto_and_ip (TRANSPORT_PROTO_QUIC,
- qctx->c_quic_ctx_id.udp_is_ip4);
- quic_session = session_get (qctx->c_s_index, qctx->c_thread_index);
- stream_session->listener_handle = listen_session_get_handle (quic_session);
-
- app_wrk = app_worker_get (stream_session->app_wrk_index);
- if ((rv = app_worker_init_connected (app_wrk, stream_session)))
- {
- QUIC_DBG (1, "failed to allocate fifos");
- session_free (stream_session);
- quicly_reset_stream (stream, QUIC_APP_ALLOCATION_ERROR);
- return;
- }
-
- rv = app_worker_accept_notify (app_wrk, stream_session);
- if (rv)
- {
- QUIC_DBG (1, "failed to notify accept worker app");
- session_free_w_fifos (stream_session);
- quicly_reset_stream (stream, QUIC_APP_ACCEPT_NOTIFY_ERROR);
- return;
- }
- session_lookup_add_connection (&sctx->connection,
- session_handle (stream_session));
-}
-
-static int
-quic_on_stream_open (quicly_stream_open_t * self, quicly_stream_t * stream)
-{
- QUIC_DBG (2, "on_stream_open called");
- stream->data = malloc (sizeof (quic_stream_data_t));
- stream->callbacks = &quic_stream_callbacks;
- /* Notify accept on parent qsession, but only if this is not a locally
- * initiated stream */
- if (!quicly_stream_is_self_initiated (stream))
- {
- quic_accept_stream (stream);
- }
- return 0;
-}
-
-static quicly_stream_open_t on_stream_open = { &quic_on_stream_open };
-
-static void
-quic_on_conn_close (quicly_closed_by_peer_t * self, quicly_conn_t * conn,
- int code, uint64_t frame_type,
- const char *reason, size_t reason_len)
-{
- QUIC_DBG (2, "connection closed, reason: %.*s", reason, reason_len);
- quic_ctx_t *ctx = quic_get_conn_ctx (conn);
- session_transport_closing_notify (&ctx->connection);
-}
-
-static quicly_closed_by_peer_t on_closed_by_peer = { &quic_on_conn_close };
-
-
-/*****************************************************************************
- * END QUICLY CALLBACKS
- *****************************************************************************/
-
-/* single-entry session cache */
-struct st_util_session_cache_t
-{
- ptls_encrypt_ticket_t super;
- uint8_t id[32];
- ptls_iovec_t data;
-};
-
-static int
-encrypt_ticket_cb (ptls_encrypt_ticket_t * _self, ptls_t * tls,
- int is_encrypt, ptls_buffer_t * dst, ptls_iovec_t src)
-{
- struct st_util_session_cache_t *self = (void *) _self;
- int ret;
-
- if (is_encrypt)
- {
-
- /* replace the cached entry along with a newly generated session id */
- free (self->data.base);
- if ((self->data.base = malloc (src.len)) == NULL)
- return PTLS_ERROR_NO_MEMORY;
-
- ptls_get_context (tls)->random_bytes (self->id, sizeof (self->id));
- memcpy (self->data.base, src.base, src.len);
- self->data.len = src.len;
-
- /* store the session id in buffer */
- if ((ret = ptls_buffer_reserve (dst, sizeof (self->id))) != 0)
- return ret;
- memcpy (dst->base + dst->off, self->id, sizeof (self->id));
- dst->off += sizeof (self->id);
-
- }
- else
- {
-
- /* check if session id is the one stored in cache */
- if (src.len != sizeof (self->id))
- return PTLS_ERROR_SESSION_NOT_FOUND;
- if (memcmp (self->id, src.base, sizeof (self->id)) != 0)
- return PTLS_ERROR_SESSION_NOT_FOUND;
-
- /* return the cached value */
- if ((ret = ptls_buffer_reserve (dst, self->data.len)) != 0)
- return ret;
- memcpy (dst->base + dst->off, self->data.base, self->data.len);
- dst->off += self->data.len;
- }
-
- return 0;
-}
-
-/* *INDENT-OFF* */
-static struct st_util_session_cache_t sc = {
- .super = {
- .cb = encrypt_ticket_cb,
- },
-};
-
-static ptls_context_t quic_tlsctx = {
- .random_bytes = ptls_openssl_random_bytes,
- .get_time = &ptls_get_time,
- .key_exchanges = ptls_openssl_key_exchanges,
- .cipher_suites = ptls_openssl_cipher_suites,
- .certificates = {
- .list = NULL,
- .count = 0
- },
- .esni = NULL,
- .on_client_hello = NULL,
- .emit_certificate = NULL,
- .sign_certificate = NULL,
- .verify_certificate = NULL,
- .ticket_lifetime = 86400,
- .max_early_data_size = 8192,
- .hkdf_label_prefix__obsolete = NULL,
- .require_dhe_on_psk = 1,
- .encrypt_ticket = &sc.super,
-};
-/* *INDENT-ON* */
-
-static int
-ptls_compare_separator_line (const char *line, const char *begin_or_end,
- const char *label)
-{
- int ret = strncmp (line, "-----", 5);
- size_t text_index = 5;
-
- if (ret == 0)
- {
- size_t begin_or_end_length = strlen (begin_or_end);
- ret = strncmp (line + text_index, begin_or_end, begin_or_end_length);
- text_index += begin_or_end_length;
- }
-
- if (ret == 0)
- {
- ret = line[text_index] - ' ';
- text_index++;
- }
-
- if (ret == 0)
- {
- size_t label_length = strlen (label);
- ret = strncmp (line + text_index, label, label_length);
- text_index += label_length;
- }
-
- if (ret == 0)
- {
- ret = strncmp (line + text_index, "-----", 5);
- }
-
- return ret;
-}
-
-static int
-ptls_get_bio_pem_object (BIO * bio, const char *label, ptls_buffer_t * buf)
-{
- int ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND;
- char line[256];
- ptls_base64_decode_state_t state;
-
- /* Get the label on a line by itself */
- while (BIO_gets (bio, line, 256))
- {
- if (ptls_compare_separator_line (line, "BEGIN", label) == 0)
- {
- ret = 0;
- ptls_base64_decode_init (&state);
- break;
- }
- }
- /* Get the data in the buffer */
- while (ret == 0 && BIO_gets (bio, line, 256))
- {
- if (ptls_compare_separator_line (line, "END", label) == 0)
- {
- if (state.status == PTLS_BASE64_DECODE_DONE
- || (state.status == PTLS_BASE64_DECODE_IN_PROGRESS
- && state.nbc == 0))
- {
- ret = 0;
- }
- else
- {
- ret = PTLS_ERROR_INCORRECT_BASE64;
- }
- break;
- }
- else
- {
- ret = ptls_base64_decode (line, &state, buf);
- }
- }
-
- return ret;
-}
-
-static int
-ptls_load_bio_pem_objects (BIO * bio, const char *label, ptls_iovec_t * list,
- size_t list_max, size_t * nb_objects)
-{
- int ret = 0;
- size_t count = 0;
-
- *nb_objects = 0;