+ 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);
+ }