1use std::{
8 collections::VecDeque,
9 future::Future,
10 net::SocketAddr,
11 sync::{Arc, Mutex, OnceLock, mpsc},
12 time::Duration,
13};
14
15use bytes::{Buf, BytesMut};
16use datum::{
17 NotUsed, Sink, Source, SourceRef, StreamCompletion, StreamError, StreamRefFrame, StreamRefId,
18 StreamRefMessage, StreamRefOutbound, StreamRefPayload, StreamRefPayloadBatch,
19 StreamRefProtoConsumer, StreamRefProtoEndpoint, StreamRefProtoProducer, StreamRefSettings,
20 StreamResult,
21 actor::stream_ref_proto::{StreamRefOutboundPoll, StreamRefProtoEndpointWake},
22};
23use tokio::{
24 io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt},
25 net::{TcpListener, TcpStream, ToSocketAddrs},
26 runtime::{Handle, Runtime},
27 sync::mpsc as tokio_mpsc,
28 task::JoinHandle,
29};
30
31use crate::QuicBidirectionalStream;
32
33const FRAME_LEN_BYTES: usize = 4;
34const MAX_STREAM_REF_FRAME_BYTES: usize = 16 * 1024 * 1024;
35const STREAM_REF_TCP_CHUNK_SIZE: usize = 8192;
36const STREAM_REF_QUIC_READ_BUFFER_BYTES: usize = 2048;
37const STREAM_REF_OUTBOUND_BATCH_FRAMES: usize = 64;
38const STREAM_REF_OUTBOUND_RECHECK_INTERVAL: Duration = Duration::from_millis(5);
39
40const COMPACT_FRAME_FLAG: u32 = 0x8000_0000;
44const COMPACT_FRAME_LEN_MASK: u32 = 0x7fff_ffff;
45const COMPACT_FRAME_VERSION: u8 = 1;
46const COMPACT_SEQUENCED_ON_NEXT_BATCH: u8 = 1;
47const COMPACT_BATCH_HEADER_BYTES: usize = 1 + 1 + 16 + 8 + 2;
48const COMPACT_BATCH_ELEMENT_LEN_BYTES: usize = 4;
49
50#[derive(Clone, Copy)]
51struct CarrierReadMode {
52 chunk_size: usize,
53 emit_available: bool,
54 fail_on_eof: bool,
55}
56
57impl CarrierReadMode {
58 fn new(chunk_size: usize, emit_available: bool, fail_on_eof: bool) -> Self {
59 assert!(chunk_size > 0, "chunk size must be greater than zero");
60 Self {
61 chunk_size,
62 emit_available,
63 fail_on_eof,
64 }
65 }
66}
67
68#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
71pub struct StreamRefProtocolMessageCounts {
72 pub cumulative_demand: u64,
73 pub sequenced_on_next: u64,
74 pub ack: u64,
75}
76
77#[derive(Clone, Default)]
83pub struct StreamRefProtocolDiagnostics {
84 counts: Arc<Mutex<StreamRefProtocolMessageCounts>>,
85}
86
87impl StreamRefProtocolDiagnostics {
88 #[must_use]
89 pub fn new() -> Self {
90 Self::default()
91 }
92
93 #[must_use]
94 pub fn snapshot(&self) -> StreamRefProtocolMessageCounts {
95 *self
96 .counts
97 .lock()
98 .unwrap_or_else(|poison| poison.into_inner())
99 }
100
101 fn record_counts(&self, delta: StreamRefProtocolMessageCounts) {
102 if delta == StreamRefProtocolMessageCounts::default() {
103 return;
104 }
105 let mut counts = self
106 .counts
107 .lock()
108 .unwrap_or_else(|poison| poison.into_inner());
109 counts.cumulative_demand = counts
110 .cumulative_demand
111 .saturating_add(delta.cumulative_demand);
112 counts.sequenced_on_next = counts
113 .sequenced_on_next
114 .saturating_add(delta.sequenced_on_next);
115 counts.ack = counts.ack.saturating_add(delta.ack);
116 }
117}
118
119fn outbound_counts(outbound: &StreamRefOutbound) -> StreamRefProtocolMessageCounts {
120 let mut counts = StreamRefProtocolMessageCounts::default();
121 match outbound {
122 StreamRefOutbound::Frame(frame) => match &frame.message {
123 StreamRefMessage::CumulativeDemand { .. } => {
124 counts.cumulative_demand = 1;
125 }
126 StreamRefMessage::SequencedOnNext { .. } => {
127 counts.sequenced_on_next = 1;
128 }
129 StreamRefMessage::Ack => {
130 counts.ack = 1;
131 }
132 StreamRefMessage::OnSubscribeHandshake
133 | StreamRefMessage::RemoteStreamCompleted { .. }
134 | StreamRefMessage::RemoteStreamFailure { .. } => {}
135 },
136 StreamRefOutbound::SequencedBatch(batch) => {
137 counts.sequenced_on_next = batch.count() as u64;
138 }
139 }
140 counts
141}
142
143#[derive(Clone, Copy)]
144struct PendingDiagnostic {
145 remaining: usize,
146 counts: StreamRefProtocolMessageCounts,
147}
148
149#[must_use = "wait for the QUIC StreamRefs carrier to observe completion or failure"]
151pub struct StreamRefQuicHandle {
152 completion: EndpointTaskCompletion,
153}
154
155impl StreamRefQuicHandle {
156 pub fn wait(self) -> StreamResult<NotUsed> {
157 self.completion.wait()
158 }
159
160 #[must_use]
161 pub fn try_wait(&self) -> Option<StreamResult<NotUsed>> {
162 self.completion.try_wait()
163 }
164
165 #[must_use]
166 pub fn is_finished(&self) -> bool {
167 self.completion.is_finished()
168 }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
173pub struct StreamRefTcpBinding {
174 local_addr: SocketAddr,
175}
176
177impl StreamRefTcpBinding {
178 #[must_use]
179 pub fn local_addr(&self) -> SocketAddr {
180 self.local_addr
181 }
182}
183
184#[must_use = "wait for the TCP StreamRefs carrier to observe completion or failure"]
186pub struct StreamRefTcpHandle {
187 completion: EndpointTaskCompletion,
188}
189
190impl StreamRefTcpHandle {
191 pub fn wait(self) -> StreamResult<NotUsed> {
192 self.completion.wait()
193 }
194
195 #[must_use]
196 pub fn try_wait(&self) -> Option<StreamResult<NotUsed>> {
197 self.completion.try_wait()
198 }
199
200 #[must_use]
201 pub fn is_finished(&self) -> bool {
202 self.completion.is_finished()
203 }
204}
205
206struct EndpointTaskCompletion {
207 receiver: mpsc::Receiver<StreamResult<NotUsed>>,
208 task: Option<JoinHandle<()>>,
209}
210
211impl EndpointTaskCompletion {
212 fn wait(mut self) -> StreamResult<NotUsed> {
213 let result = self
214 .receiver
215 .recv()
216 .unwrap_or(Err(StreamError::AbruptTermination));
217 self.task.take();
218 result
219 }
220
221 fn try_wait(&self) -> Option<StreamResult<NotUsed>> {
222 self.receiver.try_recv().ok()
223 }
224
225 fn is_finished(&self) -> bool {
226 self.task.as_ref().is_some_and(JoinHandle::is_finished)
227 }
228}
229
230impl Drop for EndpointTaskCompletion {
231 fn drop(&mut self) {
232 if let Some(task) = self.task.take() {
233 task.abort();
234 }
235 }
236}
237
238pub fn serve_source_ref_over_quic<T>(
240 stream: QuicBidirectionalStream,
241 source_ref: SourceRef<T>,
242 stream_ref_id: StreamRefId,
243 settings: StreamRefSettings,
244) -> StreamResult<StreamRefQuicHandle>
245where
246 T: StreamRefPayload,
247{
248 let producer = StreamRefProtoProducer::from_source_ref(source_ref, stream_ref_id, settings)?;
249 Ok(drive_stream_ref_endpoint_over_quic(stream, producer, None))
250}
251
252pub fn serve_source_over_quic<T, Mat>(
254 stream: QuicBidirectionalStream,
255 source: Source<T, Mat>,
256 stream_ref_id: StreamRefId,
257 settings: StreamRefSettings,
258) -> StreamResult<StreamRefQuicHandle>
259where
260 T: StreamRefPayload,
261 Mat: Send + 'static,
262{
263 let producer = StreamRefProtoProducer::from_source(source, stream_ref_id, settings)?;
264 Ok(drive_stream_ref_endpoint_over_quic(stream, producer, None))
265}
266
267pub fn source_ref_over_quic<T>(
269 stream: QuicBidirectionalStream,
270 stream_ref_id: StreamRefId,
271 settings: StreamRefSettings,
272) -> (Source<T, NotUsed>, StreamRefQuicHandle)
273where
274 T: StreamRefPayload,
275{
276 let consumer = StreamRefProtoConsumer::new(stream_ref_id, settings);
277 let source = consumer.source();
278 let handle = drive_stream_ref_endpoint_over_quic(stream, consumer, None);
279 (source, handle)
280}
281
282pub fn serve_sink_ref_over_quic<T>(
290 stream: QuicBidirectionalStream,
291 stream_ref_id: StreamRefId,
292 settings: StreamRefSettings,
293) -> (Source<T, NotUsed>, StreamRefQuicHandle)
294where
295 T: StreamRefPayload,
296{
297 let consumer = StreamRefProtoConsumer::new(stream_ref_id, settings);
298 let source = consumer.source();
299 let handle = drive_stream_ref_endpoint_over_quic(stream, consumer, None);
300 (source, handle)
301}
302
303pub fn sink_ref_over_quic<T>(
306 stream: QuicBidirectionalStream,
307 stream_ref_id: StreamRefId,
308 settings: StreamRefSettings,
309) -> (Sink<T, StreamCompletion<NotUsed>>, StreamRefQuicHandle)
310where
311 T: StreamRefPayload,
312{
313 let producer = StreamRefProtoProducer::new_lazy(stream_ref_id, settings);
314 let sink = producer.sink();
315 let handle = drive_stream_ref_endpoint_over_quic(stream, producer, None);
316 (sink, handle)
317}
318
319pub fn serve_source_ref_over_tcp<T, A>(
326 addr: A,
327 source_ref: SourceRef<T>,
328 stream_ref_id: StreamRefId,
329 settings: StreamRefSettings,
330) -> StreamResult<(StreamRefTcpBinding, StreamRefTcpHandle)>
331where
332 T: StreamRefPayload,
333 A: ToSocketAddrs + Send + 'static,
334{
335 serve_source_ref_over_tcp_with_diagnostics(addr, source_ref, stream_ref_id, settings, None)
336}
337
338pub fn serve_source_ref_over_tcp_with_diagnostics<T, A>(
339 addr: A,
340 source_ref: SourceRef<T>,
341 stream_ref_id: StreamRefId,
342 settings: StreamRefSettings,
343 diagnostics: Option<StreamRefProtocolDiagnostics>,
344) -> StreamResult<(StreamRefTcpBinding, StreamRefTcpHandle)>
345where
346 T: StreamRefPayload,
347 A: ToSocketAddrs + Send + 'static,
348{
349 let producer = StreamRefProtoProducer::from_source_ref(source_ref, stream_ref_id, settings)?;
350 let (listener, binding, handle) = bind_tcp_listener(addr)?;
351 Ok((
352 binding,
353 drive_stream_ref_endpoint_over_tcp_listener(listener, handle, producer, diagnostics),
354 ))
355}
356
357pub fn serve_source_ref_over_tcp_stream<T>(
363 stream: TcpStream,
364 source_ref: SourceRef<T>,
365 stream_ref_id: StreamRefId,
366 settings: StreamRefSettings,
367) -> StreamResult<StreamRefTcpHandle>
368where
369 T: StreamRefPayload,
370{
371 serve_source_ref_over_tcp_stream_with_diagnostics(
372 stream,
373 source_ref,
374 stream_ref_id,
375 settings,
376 None,
377 )
378}
379
380pub fn serve_source_ref_over_tcp_stream_with_diagnostics<T>(
381 stream: TcpStream,
382 source_ref: SourceRef<T>,
383 stream_ref_id: StreamRefId,
384 settings: StreamRefSettings,
385 diagnostics: Option<StreamRefProtocolDiagnostics>,
386) -> StreamResult<StreamRefTcpHandle>
387where
388 T: StreamRefPayload,
389{
390 let producer = StreamRefProtoProducer::from_source_ref(source_ref, stream_ref_id, settings)?;
391 let handle = current_tokio_handle()?;
392 Ok(drive_stream_ref_endpoint_over_tcp_stream(
393 stream,
394 handle,
395 producer,
396 diagnostics,
397 ))
398}
399
400pub fn source_ref_over_tcp<T, A>(
405 addr: A,
406 stream_ref_id: StreamRefId,
407 settings: StreamRefSettings,
408) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
409where
410 T: StreamRefPayload,
411 A: ToSocketAddrs + Send + 'static,
412{
413 source_ref_over_tcp_with_diagnostics(addr, stream_ref_id, settings, None)
414}
415
416pub fn source_ref_over_tcp_with_diagnostics<T, A>(
417 addr: A,
418 stream_ref_id: StreamRefId,
419 settings: StreamRefSettings,
420 diagnostics: Option<StreamRefProtocolDiagnostics>,
421) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
422where
423 T: StreamRefPayload,
424 A: ToSocketAddrs + Send + 'static,
425{
426 let consumer = StreamRefProtoConsumer::new(stream_ref_id, settings);
427 let source = consumer.source();
428 let (stream, handle) = connect_tcp_stream(addr)?;
429 let handle = drive_stream_ref_endpoint_over_tcp_stream(stream, handle, consumer, diagnostics);
430 Ok((source, handle))
431}
432
433pub fn source_ref_over_tcp_stream<T>(
436 stream: TcpStream,
437 stream_ref_id: StreamRefId,
438 settings: StreamRefSettings,
439) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
440where
441 T: StreamRefPayload,
442{
443 source_ref_over_tcp_stream_with_diagnostics(stream, stream_ref_id, settings, None)
444}
445
446pub fn source_ref_over_tcp_stream_with_diagnostics<T>(
447 stream: TcpStream,
448 stream_ref_id: StreamRefId,
449 settings: StreamRefSettings,
450 diagnostics: Option<StreamRefProtocolDiagnostics>,
451) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
452where
453 T: StreamRefPayload,
454{
455 let consumer = StreamRefProtoConsumer::new(stream_ref_id, settings);
456 let source = consumer.source();
457 let handle = current_tokio_handle()?;
458 let handle = drive_stream_ref_endpoint_over_tcp_stream(stream, handle, consumer, diagnostics);
459 Ok((source, handle))
460}
461
462pub fn serve_sink_ref_over_tcp<T, A>(
468 addr: A,
469 stream_ref_id: StreamRefId,
470 settings: StreamRefSettings,
471) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
472where
473 T: StreamRefPayload,
474 A: ToSocketAddrs + Send + 'static,
475{
476 serve_sink_ref_over_tcp_with_diagnostics(addr, stream_ref_id, settings, None)
477}
478
479pub fn serve_sink_ref_over_tcp_with_diagnostics<T, A>(
480 addr: A,
481 stream_ref_id: StreamRefId,
482 settings: StreamRefSettings,
483 diagnostics: Option<StreamRefProtocolDiagnostics>,
484) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
485where
486 T: StreamRefPayload,
487 A: ToSocketAddrs + Send + 'static,
488{
489 let consumer = StreamRefProtoConsumer::new(stream_ref_id, settings);
490 let source = consumer.source();
491 let (stream, handle) = connect_tcp_stream(addr)?;
492 let handle = drive_stream_ref_endpoint_over_tcp_stream(stream, handle, consumer, diagnostics);
493 Ok((source, handle))
494}
495
496pub fn serve_sink_ref_over_tcp_stream<T>(
499 stream: TcpStream,
500 stream_ref_id: StreamRefId,
501 settings: StreamRefSettings,
502) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
503where
504 T: StreamRefPayload,
505{
506 serve_sink_ref_over_tcp_stream_with_diagnostics(stream, stream_ref_id, settings, None)
507}
508
509pub fn serve_sink_ref_over_tcp_stream_with_diagnostics<T>(
510 stream: TcpStream,
511 stream_ref_id: StreamRefId,
512 settings: StreamRefSettings,
513 diagnostics: Option<StreamRefProtocolDiagnostics>,
514) -> StreamResult<(Source<T, NotUsed>, StreamRefTcpHandle)>
515where
516 T: StreamRefPayload,
517{
518 let consumer = StreamRefProtoConsumer::new(stream_ref_id, settings);
519 let source = consumer.source();
520 let handle = current_tokio_handle()?;
521 let handle = drive_stream_ref_endpoint_over_tcp_stream(stream, handle, consumer, diagnostics);
522 Ok((source, handle))
523}
524
525pub fn sink_ref_over_tcp<T, A>(
533 addr: A,
534 stream_ref_id: StreamRefId,
535 settings: StreamRefSettings,
536) -> StreamResult<(
537 Sink<T, StreamCompletion<NotUsed>>,
538 StreamRefTcpBinding,
539 StreamRefTcpHandle,
540)>
541where
542 T: StreamRefPayload,
543 A: ToSocketAddrs + Send + 'static,
544{
545 sink_ref_over_tcp_with_diagnostics(addr, stream_ref_id, settings, None)
546}
547
548pub fn sink_ref_over_tcp_with_diagnostics<T, A>(
549 addr: A,
550 stream_ref_id: StreamRefId,
551 settings: StreamRefSettings,
552 diagnostics: Option<StreamRefProtocolDiagnostics>,
553) -> StreamResult<(
554 Sink<T, StreamCompletion<NotUsed>>,
555 StreamRefTcpBinding,
556 StreamRefTcpHandle,
557)>
558where
559 T: StreamRefPayload,
560 A: ToSocketAddrs + Send + 'static,
561{
562 let producer = StreamRefProtoProducer::new_lazy(stream_ref_id, settings);
563 let sink = producer.sink();
564 let (listener, binding, handle) = bind_tcp_listener(addr)?;
565 let handle =
566 drive_stream_ref_endpoint_over_tcp_listener(listener, handle, producer, diagnostics);
567 Ok((sink, binding, handle))
568}
569
570pub fn sink_ref_over_tcp_stream<T>(
573 stream: TcpStream,
574 stream_ref_id: StreamRefId,
575 settings: StreamRefSettings,
576) -> StreamResult<(Sink<T, StreamCompletion<NotUsed>>, StreamRefTcpHandle)>
577where
578 T: StreamRefPayload,
579{
580 sink_ref_over_tcp_stream_with_diagnostics(stream, stream_ref_id, settings, None)
581}
582
583pub fn sink_ref_over_tcp_stream_with_diagnostics<T>(
584 stream: TcpStream,
585 stream_ref_id: StreamRefId,
586 settings: StreamRefSettings,
587 diagnostics: Option<StreamRefProtocolDiagnostics>,
588) -> StreamResult<(Sink<T, StreamCompletion<NotUsed>>, StreamRefTcpHandle)>
589where
590 T: StreamRefPayload,
591{
592 let producer = StreamRefProtoProducer::new_lazy(stream_ref_id, settings);
593 let sink = producer.sink();
594 let handle = current_tokio_handle()?;
595 let handle = drive_stream_ref_endpoint_over_tcp_stream(stream, handle, producer, diagnostics);
596 Ok((sink, handle))
597}
598
599fn drive_stream_ref_endpoint_over_quic<E>(
600 stream: QuicBidirectionalStream,
601 endpoint: E,
602 diagnostics: Option<StreamRefProtocolDiagnostics>,
603) -> StreamRefQuicHandle
604where
605 E: StreamRefProtoEndpointWake,
606{
607 let (reader, writer, handle, chunk_size, emit_available) = stream.into_stream_ref_parts();
608 let read_mode = CarrierReadMode::new(chunk_size, emit_available, false);
609 StreamRefQuicHandle {
610 completion: spawn_endpoint_task(&handle, async move {
611 run_stream_ref_endpoint_quic_task(reader, writer, endpoint, read_mode, diagnostics)
612 .await
613 }),
614 }
615}
616
617fn drive_stream_ref_endpoint_over_tcp_listener<E>(
618 listener: TcpListener,
619 handle: Handle,
620 endpoint: E,
621 diagnostics: Option<StreamRefProtocolDiagnostics>,
622) -> StreamRefTcpHandle
623where
624 E: StreamRefProtoEndpointWake,
625{
626 StreamRefTcpHandle {
627 completion: spawn_endpoint_task(&handle, async move {
628 let (stream, _) = listener.accept().await.map_err(io_error)?;
629 run_stream_ref_endpoint_tcp_task(stream, endpoint, diagnostics).await
630 }),
631 }
632}
633
634fn drive_stream_ref_endpoint_over_tcp_stream<E>(
635 stream: TcpStream,
636 handle: Handle,
637 endpoint: E,
638 diagnostics: Option<StreamRefProtocolDiagnostics>,
639) -> StreamRefTcpHandle
640where
641 E: StreamRefProtoEndpointWake,
642{
643 StreamRefTcpHandle {
644 completion: spawn_endpoint_task(&handle, async move {
645 run_stream_ref_endpoint_tcp_task(stream, endpoint, diagnostics).await
646 }),
647 }
648}
649
650async fn run_stream_ref_endpoint_quic_task<R, W, E>(
651 reader: R,
652 writer: W,
653 endpoint: E,
654 read_mode: CarrierReadMode,
655 diagnostics: Option<StreamRefProtocolDiagnostics>,
656) -> StreamResult<NotUsed>
657where
658 R: AsyncRead + Unpin + Send + 'static,
659 W: AsyncWrite + Unpin + Send + 'static,
660 E: StreamRefProtoEndpointWake,
661{
662 let (wake_sender, wake_receiver) = tokio_mpsc::channel(1);
663 endpoint.install_outbound_wake(wake_sender.clone());
664 let _ = wake_sender.try_send(());
665
666 let result = QuicEndpointTask {
667 reader,
668 writer,
669 endpoint: endpoint.clone(),
670 diagnostics,
671 read_mode,
672 decoder: FrameDecoder::default(),
673 read_buffer: vec![
674 0_u8;
675 read_mode
676 .chunk_size
677 .clamp(1, STREAM_REF_QUIC_READ_BUFFER_BYTES)
678 ],
679 pending_tail: Vec::new(),
680 write_buffer: BytesMut::new(),
681 encode_buffer: Vec::new(),
682 pending_diagnostics: VecDeque::new(),
683 read_closed: false,
684 inbound_seen: false,
685 outbound_written: false,
686 recheck_outbound: false,
687 outbound_closed: false,
688 write_shutdown: false,
689 wake_receiver,
690 }
691 .run()
692 .await;
693
694 endpoint.clear_outbound_wake();
695 if let Err(error) = &result {
696 endpoint.fail_connection(error.clone());
697 }
698 result
699}
700
701struct QuicEndpointTask<R, W, E>
702where
703 E: StreamRefProtoEndpointWake,
704{
705 reader: R,
706 writer: W,
707 endpoint: E,
708 diagnostics: Option<StreamRefProtocolDiagnostics>,
709 read_mode: CarrierReadMode,
710 decoder: FrameDecoder,
711 read_buffer: Vec<u8>,
712 pending_tail: Vec<u8>,
713 write_buffer: BytesMut,
714 encode_buffer: Vec<u8>,
715 pending_diagnostics: VecDeque<PendingDiagnostic>,
716 read_closed: bool,
717 inbound_seen: bool,
718 outbound_written: bool,
719 recheck_outbound: bool,
720 outbound_closed: bool,
721 write_shutdown: bool,
722 wake_receiver: tokio_mpsc::Receiver<()>,
723}
724
725impl<R, W, E> QuicEndpointTask<R, W, E>
726where
727 R: AsyncRead + Unpin,
728 W: AsyncWrite + Unpin,
729 E: StreamRefProtoEndpointWake,
730{
731 async fn run(mut self) -> StreamResult<NotUsed> {
732 loop {
733 if self.read_closed && self.write_shutdown {
734 return Ok(NotUsed);
735 }
736
737 self.drain_outbound()?;
738 if self.read_closed
739 && self.outbound_written
740 && !self.outbound_closed
741 && self.write_buffer.is_empty()
742 && self.recheck_outbound
743 {
744 return Err(StreamError::Failed(
745 "StreamRefs QUIC peer closed before remote terminal".to_owned(),
746 ));
747 }
748 if self.outbound_closed && self.write_buffer.is_empty() && !self.write_shutdown {
749 self.writer.shutdown().await.map_err(io_error)?;
750 self.write_shutdown = true;
751 continue;
752 }
753 tokio::select! {
754 biased;
755 wake = self.wake_receiver.recv(), if !self.outbound_closed => {
756 if wake.is_none() {
757 self.drain_outbound()?;
758 }
759 }
760 _ = tokio::time::sleep(STREAM_REF_OUTBOUND_RECHECK_INTERVAL), if self.recheck_outbound && !self.outbound_closed && self.write_buffer.is_empty() => {
761 self.drain_outbound()?;
762 }
763 written = self.writer.write(&self.write_buffer), if !self.write_buffer.is_empty() => {
764 self.handle_written(written)?;
765 }
766 read = self.reader.read(&mut self.read_buffer), if !self.read_closed => {
767 match read {
768 Ok(0) => self.handle_eof()?,
769 Ok(read) => {
770 self.feed_read_buffer(read)?;
771 self.drain_outbound()?;
772 }
773 Err(error) => {
774 let error = io_error(error);
775 if self.write_shutdown && is_quic_teardown_loss(&error) {
776 return Ok(NotUsed);
777 }
778 return Err(error);
779 }
780 }
781 }
782 }
783 }
784 }
785
786 fn drain_outbound(&mut self) -> StreamResult<()> {
787 self.recheck_outbound = false;
788 while !self.outbound_closed && self.write_buffer.len() < MAX_STREAM_REF_FRAME_BYTES {
789 match self
790 .endpoint
791 .try_next_outbound(STREAM_REF_OUTBOUND_BATCH_FRAMES, MAX_STREAM_REF_FRAME_BYTES)
792 {
793 StreamRefOutboundPoll::Ready(Ok(outbound)) => {
794 encode_carrier_outbound_into(&outbound, &mut self.encode_buffer)?;
795 let encoded_len = self.encode_buffer.len();
796 if encoded_len == 0 {
797 continue;
798 }
799 if self.diagnostics.is_some() {
800 self.pending_diagnostics.push_back(PendingDiagnostic {
801 remaining: encoded_len,
802 counts: outbound_counts(&outbound),
803 });
804 }
805 self.outbound_written = true;
806 self.write_buffer.extend_from_slice(&self.encode_buffer);
807 }
808 StreamRefOutboundPoll::Ready(Err(error)) => return Err(error),
809 StreamRefOutboundPoll::Pending => {
810 self.recheck_outbound =
811 !self.outbound_written || self.inbound_seen || self.read_closed;
812 break;
813 }
814 StreamRefOutboundPoll::Closed => {
815 self.outbound_closed = true;
816 break;
817 }
818 }
819 }
820 Ok(())
821 }
822
823 fn handle_written(&mut self, written: Result<usize, std::io::Error>) -> StreamResult<()> {
824 match written {
825 Ok(0) => Err(StreamError::Failed(
826 "StreamRefs QUIC stream accepted zero write bytes".to_owned(),
827 )),
828 Ok(written) => {
829 self.write_buffer.advance(written);
830 self.record_written_bytes(written);
831 Ok(())
832 }
833 Err(error) => Err(io_error(error)),
834 }
835 }
836
837 fn record_written_bytes(&mut self, mut written: usize) {
838 let Some(diagnostics) = &self.diagnostics else {
839 return;
840 };
841 while written > 0 {
842 let Some(front) = self.pending_diagnostics.front_mut() else {
843 return;
844 };
845 if written < front.remaining {
846 front.remaining -= written;
847 return;
848 }
849 written -= front.remaining;
850 let counts = front.counts;
851 self.pending_diagnostics.pop_front();
852 diagnostics.record_counts(counts);
853 }
854 }
855
856 fn feed_read_buffer(&mut self, read: usize) -> StreamResult<()> {
857 feed_read_bytes(
858 &mut self.decoder,
859 &self.endpoint,
860 self.read_mode,
861 &mut self.pending_tail,
862 &self.read_buffer[..read],
863 )?;
864 self.inbound_seen = true;
865 Ok(())
866 }
867
868 fn handle_eof(&mut self) -> StreamResult<()> {
869 if !self.pending_tail.is_empty() {
870 feed_inbound_chunk(&mut self.decoder, &self.endpoint, &self.pending_tail)?;
871 self.pending_tail.clear();
872 }
873 if self.read_mode.fail_on_eof {
874 self.endpoint
875 .fail_connection(StreamError::AbruptTermination);
876 }
877 self.read_closed = true;
878 self.recheck_outbound = true;
879 Ok(())
880 }
881}
882
883async fn run_stream_ref_endpoint_tcp_task<E>(
884 stream: TcpStream,
885 endpoint: E,
886 diagnostics: Option<StreamRefProtocolDiagnostics>,
887) -> StreamResult<NotUsed>
888where
889 E: StreamRefProtoEndpointWake,
890{
891 let (wake_sender, wake_receiver) = tokio_mpsc::channel(1);
892 endpoint.install_outbound_wake(wake_sender.clone());
893 let _ = wake_sender.try_send(());
894
895 let result = TcpEndpointTask {
896 stream,
897 endpoint: endpoint.clone(),
898 diagnostics,
899 read_mode: CarrierReadMode::new(STREAM_REF_TCP_CHUNK_SIZE, true, true),
900 decoder: FrameDecoder::default(),
901 read_buffer: BytesMut::with_capacity(STREAM_REF_TCP_CHUNK_SIZE),
902 pending_tail: Vec::with_capacity(STREAM_REF_TCP_CHUNK_SIZE),
903 write_buffer: BytesMut::with_capacity(STREAM_REF_TCP_CHUNK_SIZE),
904 encode_buffer: Vec::with_capacity(STREAM_REF_TCP_CHUNK_SIZE),
905 pending_diagnostics: VecDeque::new(),
906 outbound_closed: false,
907 write_shutdown: false,
908 wake_receiver,
909 }
910 .run()
911 .await;
912
913 endpoint.clear_outbound_wake();
914 if let Err(error) = &result {
915 endpoint.fail_connection(error.clone());
916 }
917 result
918}
919
920struct TcpEndpointTask<E>
921where
922 E: StreamRefProtoEndpointWake,
923{
924 stream: TcpStream,
925 endpoint: E,
926 diagnostics: Option<StreamRefProtocolDiagnostics>,
927 read_mode: CarrierReadMode,
928 decoder: FrameDecoder,
929 read_buffer: BytesMut,
930 pending_tail: Vec<u8>,
931 write_buffer: BytesMut,
932 encode_buffer: Vec<u8>,
933 pending_diagnostics: VecDeque<PendingDiagnostic>,
934 outbound_closed: bool,
935 write_shutdown: bool,
936 wake_receiver: tokio_mpsc::Receiver<()>,
937}
938
939impl<E> TcpEndpointTask<E>
940where
941 E: StreamRefProtoEndpointWake,
942{
943 async fn run(mut self) -> StreamResult<NotUsed> {
944 self.stream.set_nodelay(true).map_err(io_error)?;
945 loop {
946 self.drain_outbound()?;
947 if !self.write_buffer.is_empty() || (self.outbound_closed && !self.write_shutdown) {
948 self.flush_write_buffer().await?;
949 }
950
951 tokio::select! {
952 biased;
953 wake = self.wake_receiver.recv() => {
954 if wake.is_none() && !self.outbound_closed {
955 self.drain_outbound()?;
956 }
957 }
958 ready = self.stream.readable() => {
959 ready.map_err(io_error)?;
960 if self.read_available()? {
961 return Ok(NotUsed);
962 }
963 }
964 ready = self.stream.writable(), if !self.write_buffer.is_empty() || (self.outbound_closed && !self.write_shutdown) => {
965 ready.map_err(io_error)?;
966 self.flush_ready_write_buffer()?;
967 }
968 }
969 }
970 }
971
972 fn drain_outbound(&mut self) -> StreamResult<()> {
973 while !self.outbound_closed && self.write_buffer.len() < MAX_STREAM_REF_FRAME_BYTES {
974 match self
975 .endpoint
976 .try_next_outbound(STREAM_REF_OUTBOUND_BATCH_FRAMES, MAX_STREAM_REF_FRAME_BYTES)
977 {
978 StreamRefOutboundPoll::Ready(Ok(outbound)) => {
979 encode_carrier_outbound_into(&outbound, &mut self.encode_buffer)?;
980 let encoded_len = self.encode_buffer.len();
981 if encoded_len == 0 {
982 continue;
983 }
984 if self.diagnostics.is_some() {
985 self.pending_diagnostics.push_back(PendingDiagnostic {
986 remaining: encoded_len,
987 counts: outbound_counts(&outbound),
988 });
989 }
990 self.write_buffer.extend_from_slice(&self.encode_buffer);
991 }
992 StreamRefOutboundPoll::Ready(Err(error)) => return Err(error),
993 StreamRefOutboundPoll::Pending => break,
994 StreamRefOutboundPoll::Closed => {
995 self.outbound_closed = true;
996 break;
997 }
998 }
999 }
1000 Ok(())
1001 }
1002
1003 async fn flush_write_buffer(&mut self) -> StreamResult<()> {
1004 if !self.write_buffer.is_empty() {
1005 self.stream.writable().await.map_err(io_error)?;
1006 self.flush_ready_write_buffer()?;
1007 }
1008 if self.outbound_closed && self.write_buffer.is_empty() && !self.write_shutdown {
1009 self.stream.shutdown().await.map_err(io_error)?;
1010 self.write_shutdown = true;
1011 }
1012 Ok(())
1013 }
1014
1015 fn flush_ready_write_buffer(&mut self) -> StreamResult<()> {
1016 while !self.write_buffer.is_empty() {
1017 match self.stream.try_write(&self.write_buffer) {
1018 Ok(0) => {
1019 return Err(StreamError::Failed(
1020 "StreamRefs TCP socket accepted zero write bytes".to_owned(),
1021 ));
1022 }
1023 Ok(written) => {
1024 self.write_buffer.advance(written);
1025 self.record_written_bytes(written);
1026 }
1027 Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => return Ok(()),
1028 Err(error) => return Err(io_error(error)),
1029 }
1030 }
1031
1032 Ok(())
1033 }
1034
1035 fn record_written_bytes(&mut self, mut written: usize) {
1036 let Some(diagnostics) = &self.diagnostics else {
1037 return;
1038 };
1039 while written > 0 {
1040 let Some(front) = self.pending_diagnostics.front_mut() else {
1041 return;
1042 };
1043 if written < front.remaining {
1044 front.remaining -= written;
1045 return;
1046 }
1047 written -= front.remaining;
1048 let counts = front.counts;
1049 self.pending_diagnostics.pop_front();
1050 diagnostics.record_counts(counts);
1051 }
1052 }
1053
1054 fn read_available(&mut self) -> StreamResult<bool> {
1055 loop {
1056 self.read_buffer.reserve(self.read_mode.chunk_size);
1057 match self.stream.try_read_buf(&mut self.read_buffer) {
1058 Ok(0) => return self.handle_eof(),
1059 Ok(_) => {
1060 feed_read_bytes(
1061 &mut self.decoder,
1062 &self.endpoint,
1063 self.read_mode,
1064 &mut self.pending_tail,
1065 &self.read_buffer,
1066 )?;
1067 self.read_buffer.clear();
1068 self.drain_outbound()?;
1069 }
1070 Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => return Ok(false),
1071 Err(error) => return Err(io_error(error)),
1072 }
1073 }
1074 }
1075
1076 fn handle_eof(&mut self) -> StreamResult<bool> {
1077 if !self.pending_tail.is_empty() {
1078 feed_inbound_chunk(&mut self.decoder, &self.endpoint, &self.pending_tail)?;
1079 self.pending_tail.clear();
1080 }
1081 if self.read_mode.fail_on_eof {
1082 self.endpoint
1083 .fail_connection(StreamError::AbruptTermination);
1084 }
1085 Ok(true)
1086 }
1087}
1088
1089fn feed_read_bytes<E>(
1090 decoder: &mut FrameDecoder,
1091 endpoint: &E,
1092 read_mode: CarrierReadMode,
1093 pending_tail: &mut Vec<u8>,
1094 read_buffer: &[u8],
1095) -> StreamResult<()>
1096where
1097 E: StreamRefProtoEndpoint,
1098{
1099 if read_mode.emit_available {
1100 if !pending_tail.is_empty() {
1101 pending_tail.extend_from_slice(read_buffer);
1102 feed_inbound_chunk(decoder, endpoint, pending_tail)?;
1103 pending_tail.clear();
1104 return Ok(());
1105 }
1106 return feed_inbound_chunk(decoder, endpoint, read_buffer);
1107 }
1108
1109 let mut offset = 0;
1110 if !pending_tail.is_empty() {
1111 let needed = read_mode.chunk_size - pending_tail.len();
1112 let take = needed.min(read_buffer.len());
1113 pending_tail.extend_from_slice(&read_buffer[..take]);
1114 offset += take;
1115 if pending_tail.len() == read_mode.chunk_size {
1116 feed_inbound_chunk(decoder, endpoint, pending_tail)?;
1117 pending_tail.clear();
1118 }
1119 }
1120
1121 while offset + read_mode.chunk_size <= read_buffer.len() {
1122 let next = offset + read_mode.chunk_size;
1123 feed_inbound_chunk(decoder, endpoint, &read_buffer[offset..next])?;
1124 offset = next;
1125 }
1126
1127 if offset < read_buffer.len() {
1128 pending_tail.extend_from_slice(&read_buffer[offset..]);
1129 }
1130 Ok(())
1131}
1132
1133fn feed_inbound_chunk<E>(decoder: &mut FrameDecoder, endpoint: &E, chunk: &[u8]) -> StreamResult<()>
1134where
1135 E: StreamRefProtoEndpoint,
1136{
1137 decoder.push_chunk(chunk, endpoint)
1138}
1139
1140fn bind_tcp_listener<A>(addr: A) -> StreamResult<(TcpListener, StreamRefTcpBinding, Handle)>
1141where
1142 A: ToSocketAddrs + Send + 'static,
1143{
1144 let runtime = stream_ref_tcp_runtime()?;
1145 let listener = runtime
1146 .block_on(async { TcpListener::bind(addr).await })
1147 .map_err(io_error)?;
1148 let local_addr = listener.local_addr().map_err(io_error)?;
1149 Ok((
1150 listener,
1151 StreamRefTcpBinding { local_addr },
1152 runtime.handle().clone(),
1153 ))
1154}
1155
1156fn connect_tcp_stream<A>(addr: A) -> StreamResult<(TcpStream, Handle)>
1157where
1158 A: ToSocketAddrs + Send + 'static,
1159{
1160 let runtime = stream_ref_tcp_runtime()?;
1161 let stream = runtime
1162 .block_on(async { TcpStream::connect(addr).await })
1163 .map_err(io_error)?;
1164 stream.set_nodelay(true).map_err(io_error)?;
1165 Ok((stream, runtime.handle().clone()))
1166}
1167
1168fn stream_ref_tcp_runtime() -> StreamResult<&'static Runtime> {
1169 static RUNTIME: OnceLock<Result<Runtime, String>> = OnceLock::new();
1170 match RUNTIME.get_or_init(|| {
1171 tokio::runtime::Builder::new_multi_thread()
1172 .thread_name("datum-streamref-tcp")
1173 .enable_all()
1174 .build()
1175 .map_err(|error| error.to_string())
1176 }) {
1177 Ok(runtime) => Ok(runtime),
1178 Err(error) => Err(StreamError::Failed(format!(
1179 "failed to start StreamRefs TCP runtime: {error}"
1180 ))),
1181 }
1182}
1183
1184fn current_tokio_handle() -> StreamResult<Handle> {
1185 Handle::try_current().map_err(|error| {
1186 StreamError::Failed(format!(
1187 "StreamRefs TCP stream helper requires a current Tokio runtime: {error}"
1188 ))
1189 })
1190}
1191
1192fn io_error(error: std::io::Error) -> StreamError {
1193 StreamError::Failed(error.to_string())
1194}
1195
1196fn is_quic_teardown_loss(error: &StreamError) -> bool {
1197 matches!(error, StreamError::Failed(message) if message == "connection lost")
1198}
1199
1200fn spawn_endpoint_task<F>(handle: &Handle, run: F) -> EndpointTaskCompletion
1201where
1202 F: Future<Output = StreamResult<NotUsed>> + Send + 'static,
1203{
1204 let (sender, receiver) = mpsc::channel();
1205 let task = handle.spawn(async move {
1206 let result = run.await;
1207 let _ = sender.send(result);
1208 });
1209 EndpointTaskCompletion {
1210 receiver,
1211 task: Some(task),
1212 }
1213}
1214
1215fn encode_carrier_outbound_into(
1216 outbound: &StreamRefOutbound,
1217 bytes: &mut Vec<u8>,
1218) -> StreamResult<()> {
1219 bytes.clear();
1220 match outbound {
1221 StreamRefOutbound::Frame(frame) => append_protobuf_carrier_frame(frame, bytes)?,
1222 StreamRefOutbound::SequencedBatch(batch) => {
1223 append_compact_payload_batch(batch, bytes)?;
1224 }
1225 }
1226 Ok(())
1227}
1228
1229#[cfg(test)]
1230fn encode_carrier_frames(frames: &[StreamRefFrame]) -> StreamResult<Vec<u8>> {
1231 let mut bytes = Vec::new();
1232 let mut index = 0;
1233 while index < frames.len() {
1234 if sequenced_on_next(&frames[index]).is_some() {
1235 let end = sequenced_run_end(frames, index);
1236 append_compact_sequenced_batches(&frames[index..end], &mut bytes)?;
1237 index = end;
1238 } else {
1239 append_protobuf_carrier_frame(&frames[index], &mut bytes)?;
1240 index += 1;
1241 }
1242 }
1243 Ok(bytes)
1244}
1245
1246fn append_compact_payload_batch(
1247 batch: &StreamRefPayloadBatch,
1248 bytes: &mut Vec<u8>,
1249) -> StreamResult<()> {
1250 let mut start = 0;
1251 while start < batch.count() {
1252 let mut end = start;
1253 let mut payload_len = COMPACT_BATCH_HEADER_BYTES;
1254 while end < batch.count() {
1255 let element_len = COMPACT_BATCH_ELEMENT_LEN_BYTES
1256 .checked_add(batch.payload_len(end))
1257 .ok_or(StreamError::LimitExceeded {
1258 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1259 })?;
1260 let next_payload_len =
1261 payload_len
1262 .checked_add(element_len)
1263 .ok_or(StreamError::LimitExceeded {
1264 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1265 })?;
1266 if end > start
1267 && (next_payload_len > MAX_STREAM_REF_FRAME_BYTES
1268 || end - start >= u16::MAX as usize)
1269 {
1270 break;
1271 }
1272 if next_payload_len > MAX_STREAM_REF_FRAME_BYTES {
1273 return Err(StreamError::LimitExceeded {
1274 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1275 });
1276 }
1277 payload_len = next_payload_len;
1278 end += 1;
1279 }
1280 append_compact_payload_batch_slice(batch, start, end, payload_len, bytes)?;
1281 start = end;
1282 }
1283 Ok(())
1284}
1285
1286fn append_compact_payload_batch_slice(
1287 batch: &StreamRefPayloadBatch,
1288 start: usize,
1289 end: usize,
1290 payload_len: usize,
1291 bytes: &mut Vec<u8>,
1292) -> StreamResult<()> {
1293 let payload_len = u32::try_from(payload_len).map_err(|_| StreamError::LimitExceeded {
1294 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1295 })?;
1296 let count = u16::try_from(end - start).map_err(|_| StreamError::LimitExceeded {
1297 max: u16::MAX as u64,
1298 })?;
1299 let first_seq = batch
1300 .first_seq_nr()
1301 .checked_add(start as u64)
1302 .ok_or_else(|| StreamError::Failed("compact StreamRefs seq_nr overflow".to_owned()))?;
1303 bytes.extend((COMPACT_FRAME_FLAG | payload_len).to_be_bytes());
1304 bytes.push(COMPACT_FRAME_VERSION);
1305 bytes.push(COMPACT_SEQUENCED_ON_NEXT_BATCH);
1306 bytes.extend(batch.stream_ref_id().to_bytes());
1307 bytes.extend(first_seq.to_be_bytes());
1308 bytes.extend(count.to_be_bytes());
1309 for index in start..end {
1310 let payload = batch.payload(index);
1311 let payload_len = u32::try_from(payload.len()).map_err(|_| StreamError::LimitExceeded {
1312 max: u32::MAX as u64,
1313 })?;
1314 bytes.extend(payload_len.to_be_bytes());
1315 bytes.extend(payload);
1316 }
1317 Ok(())
1318}
1319
1320fn append_protobuf_carrier_frame(frame: &StreamRefFrame, bytes: &mut Vec<u8>) -> StreamResult<()> {
1321 let payload = frame.encode_to_vec();
1322 let len = u32::try_from(payload.len()).map_err(|_| StreamError::LimitExceeded {
1323 max: COMPACT_FRAME_LEN_MASK as u64,
1324 })?;
1325 if payload.len() > MAX_STREAM_REF_FRAME_BYTES || len > COMPACT_FRAME_LEN_MASK {
1326 return Err(StreamError::LimitExceeded {
1327 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1328 });
1329 }
1330 bytes.extend(len.to_be_bytes());
1331 bytes.extend(payload);
1332 Ok(())
1333}
1334
1335#[cfg(test)]
1336fn append_compact_sequenced_batches(
1337 frames: &[StreamRefFrame],
1338 bytes: &mut Vec<u8>,
1339) -> StreamResult<()> {
1340 let mut start = 0;
1341 while start < frames.len() {
1342 let mut end = start;
1343 let mut payload_len = COMPACT_BATCH_HEADER_BYTES;
1344 while end < frames.len() {
1345 let (_, payload) = sequenced_on_next(&frames[end]).expect("sequenced frame");
1346 let element_len = COMPACT_BATCH_ELEMENT_LEN_BYTES
1347 .checked_add(payload.len())
1348 .ok_or(StreamError::LimitExceeded {
1349 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1350 })?;
1351 let next_payload_len =
1352 payload_len
1353 .checked_add(element_len)
1354 .ok_or(StreamError::LimitExceeded {
1355 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1356 })?;
1357 if end > start
1358 && (next_payload_len > MAX_STREAM_REF_FRAME_BYTES
1359 || end - start >= u16::MAX as usize)
1360 {
1361 break;
1362 }
1363 if next_payload_len > MAX_STREAM_REF_FRAME_BYTES {
1364 return Err(StreamError::LimitExceeded {
1365 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1366 });
1367 }
1368 payload_len = next_payload_len;
1369 end += 1;
1370 }
1371 append_compact_sequenced_batch(&frames[start..end], payload_len, bytes)?;
1372 start = end;
1373 }
1374 Ok(())
1375}
1376
1377#[cfg(test)]
1378fn append_compact_sequenced_batch(
1379 frames: &[StreamRefFrame],
1380 payload_len: usize,
1381 bytes: &mut Vec<u8>,
1382) -> StreamResult<()> {
1383 let (first_seq, _) = sequenced_on_next(&frames[0]).expect("sequenced frame");
1384 let payload_len = u32::try_from(payload_len).map_err(|_| StreamError::LimitExceeded {
1385 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1386 })?;
1387 let count = u16::try_from(frames.len()).map_err(|_| StreamError::LimitExceeded {
1388 max: u16::MAX as u64,
1389 })?;
1390 bytes.extend((COMPACT_FRAME_FLAG | payload_len).to_be_bytes());
1391 bytes.push(COMPACT_FRAME_VERSION);
1392 bytes.push(COMPACT_SEQUENCED_ON_NEXT_BATCH);
1393 bytes.extend(frames[0].stream_ref_id.to_bytes());
1394 bytes.extend(first_seq.to_be_bytes());
1395 bytes.extend(count.to_be_bytes());
1396 for frame in frames {
1397 let (_, payload) = sequenced_on_next(frame).expect("sequenced frame");
1398 let payload_len = u32::try_from(payload.len()).map_err(|_| StreamError::LimitExceeded {
1399 max: u32::MAX as u64,
1400 })?;
1401 bytes.extend(payload_len.to_be_bytes());
1402 bytes.extend(payload);
1403 }
1404 Ok(())
1405}
1406
1407#[cfg(test)]
1408fn sequenced_run_end(frames: &[StreamRefFrame], start: usize) -> usize {
1409 let mut end = start + 1;
1410 while end < frames.len() {
1411 let Some((previous_seq, _)) = sequenced_on_next(&frames[end - 1]) else {
1412 break;
1413 };
1414 let Some((next_seq, _)) = sequenced_on_next(&frames[end]) else {
1415 break;
1416 };
1417 if frames[end].stream_ref_id != frames[start].stream_ref_id
1418 || next_seq != previous_seq.saturating_add(1)
1419 {
1420 break;
1421 }
1422 end += 1;
1423 }
1424 end
1425}
1426
1427#[cfg(test)]
1428fn sequenced_on_next(frame: &StreamRefFrame) -> Option<(u64, &[u8])> {
1429 match &frame.message {
1430 StreamRefMessage::SequencedOnNext { seq_nr, payload } => {
1431 Some((*seq_nr, payload.bytes.as_slice()))
1432 }
1433 _ => None,
1434 }
1435}
1436
1437#[derive(Default)]
1438struct FrameDecoder {
1439 buffer: BytesMut,
1440 offset: usize,
1441}
1442
1443impl FrameDecoder {
1444 fn push_chunk<E>(&mut self, chunk: &[u8], endpoint: &E) -> StreamResult<()>
1445 where
1446 E: StreamRefProtoEndpoint,
1447 {
1448 self.buffer.extend_from_slice(chunk);
1449 while let Some(header) = self.peek_header()? {
1450 if self.buffer.len().saturating_sub(self.offset) < FRAME_LEN_BYTES + header.len {
1451 break;
1452 }
1453 let payload_start = self.offset + FRAME_LEN_BYTES;
1454 let payload_end = payload_start + header.len;
1455 let payload = &self.buffer[payload_start..payload_end];
1456 match header.kind {
1457 CarrierFrameKind::Protobuf => {
1458 endpoint.handle_frame(StreamRefFrame::decode(payload)?)?;
1459 }
1460 CarrierFrameKind::Compact => {
1461 decode_compact_carrier_frame(payload, endpoint)?;
1462 }
1463 }
1464 self.offset = payload_end;
1465 }
1466 if self.offset > 0 && (self.offset == self.buffer.len() || self.offset >= 64 * 1024) {
1467 self.buffer.advance(self.offset);
1468 self.offset = 0;
1469 }
1470 Ok(())
1471 }
1472
1473 fn peek_header(&self) -> StreamResult<Option<CarrierFrameHeader>> {
1474 if self.buffer.len().saturating_sub(self.offset) < FRAME_LEN_BYTES {
1475 return Ok(None);
1476 }
1477 let len = self.buffer[self.offset..self.offset + FRAME_LEN_BYTES]
1478 .try_into()
1479 .expect("frame header length");
1480 let raw_len = u32::from_be_bytes(len);
1481 let kind = if raw_len & COMPACT_FRAME_FLAG == 0 {
1482 CarrierFrameKind::Protobuf
1483 } else {
1484 CarrierFrameKind::Compact
1485 };
1486 let len = (raw_len & COMPACT_FRAME_LEN_MASK) as usize;
1487 if len > MAX_STREAM_REF_FRAME_BYTES {
1488 return Err(StreamError::LimitExceeded {
1489 max: MAX_STREAM_REF_FRAME_BYTES as u64,
1490 });
1491 }
1492 Ok(Some(CarrierFrameHeader { kind, len }))
1493 }
1494}
1495
1496#[derive(Clone, Copy)]
1497struct CarrierFrameHeader {
1498 kind: CarrierFrameKind,
1499 len: usize,
1500}
1501
1502#[derive(Clone, Copy)]
1503enum CarrierFrameKind {
1504 Protobuf,
1505 Compact,
1506}
1507
1508fn decode_compact_carrier_frame<E>(payload: &[u8], endpoint: &E) -> StreamResult<()>
1509where
1510 E: StreamRefProtoEndpoint,
1511{
1512 if payload.len() < COMPACT_BATCH_HEADER_BYTES {
1513 return Err(StreamError::Failed(
1514 "compact StreamRefs carrier frame too short".to_owned(),
1515 ));
1516 }
1517 let version = payload[0];
1518 if version != COMPACT_FRAME_VERSION {
1519 return Err(StreamError::Failed(format!(
1520 "unsupported compact StreamRefs carrier frame version: {version}"
1521 )));
1522 }
1523 let kind = payload[1];
1524 if kind != COMPACT_SEQUENCED_ON_NEXT_BATCH {
1525 return Err(StreamError::Failed(format!(
1526 "unsupported compact StreamRefs carrier frame kind: {kind}"
1527 )));
1528 }
1529 let stream_ref_id = StreamRefId::from_bytes(&payload[2..18])?;
1530 let first_seq = u64::from_be_bytes(payload[18..26].try_into().expect("seq len"));
1531 let count = u16::from_be_bytes(payload[26..28].try_into().expect("count len")) as usize;
1532 if count == 0 {
1533 return Err(StreamError::Failed(
1534 "compact StreamRefs carrier batch is empty".to_owned(),
1535 ));
1536 }
1537
1538 let mut offset = COMPACT_BATCH_HEADER_BYTES;
1539 let mut payloads = Vec::with_capacity(count);
1540 for index in 0..count {
1541 if payload.len().saturating_sub(offset) < COMPACT_BATCH_ELEMENT_LEN_BYTES {
1542 return Err(StreamError::Failed(
1543 "compact StreamRefs carrier batch has truncated payload length".to_owned(),
1544 ));
1545 }
1546 let payload_len = u32::from_be_bytes(
1547 payload[offset..offset + COMPACT_BATCH_ELEMENT_LEN_BYTES]
1548 .try_into()
1549 .expect("payload len"),
1550 ) as usize;
1551 offset += COMPACT_BATCH_ELEMENT_LEN_BYTES;
1552 if payload.len().saturating_sub(offset) < payload_len {
1553 return Err(StreamError::Failed(
1554 "compact StreamRefs carrier batch has truncated payload".to_owned(),
1555 ));
1556 }
1557 first_seq
1558 .checked_add(index as u64)
1559 .ok_or_else(|| StreamError::Failed("compact StreamRefs seq_nr overflow".to_owned()))?;
1560 payloads.push(&payload[offset..offset + payload_len]);
1561 offset += payload_len;
1562 }
1563 if offset != payload.len() {
1564 return Err(StreamError::Failed(
1565 "compact StreamRefs carrier batch has trailing bytes".to_owned(),
1566 ));
1567 }
1568 endpoint.handle_sequenced_on_next_batch(stream_ref_id, first_seq, &payloads)
1569}
1570
1571#[cfg(test)]
1572mod tests {
1573 use super::*;
1574 use std::sync::{Arc, Mutex};
1575
1576 #[derive(Clone)]
1577 struct RecordingEndpoint {
1578 stream_ref_id: StreamRefId,
1579 frames: Arc<Mutex<Vec<StreamRefFrame>>>,
1580 }
1581
1582 impl RecordingEndpoint {
1583 fn new(stream_ref_id: StreamRefId) -> Self {
1584 Self {
1585 stream_ref_id,
1586 frames: Arc::new(Mutex::new(Vec::new())),
1587 }
1588 }
1589
1590 fn frames(&self) -> Vec<StreamRefFrame> {
1591 self.frames.lock().expect("recording endpoint").clone()
1592 }
1593 }
1594
1595 impl StreamRefProtoEndpoint for RecordingEndpoint {
1596 fn stream_ref_id(&self) -> StreamRefId {
1597 self.stream_ref_id
1598 }
1599
1600 fn next_frame(&self) -> Option<StreamResult<StreamRefFrame>> {
1601 None
1602 }
1603
1604 fn handle_frame(&self, frame: StreamRefFrame) -> StreamResult<()> {
1605 self.frames.lock().expect("recording endpoint").push(frame);
1606 Ok(())
1607 }
1608
1609 fn fail_connection(&self, _error: StreamError) {}
1610 }
1611
1612 #[test]
1613 fn carrier_frame_decoder_reassembles_split_frames() {
1614 let frame = StreamRefFrame::new(
1615 StreamRefId::from_u128(1),
1616 datum::StreamRefMessage::CumulativeDemand { seq_nr: 32 },
1617 );
1618 let bytes = encode_carrier_frames(std::slice::from_ref(&frame)).unwrap();
1619 let split = bytes.len() / 2;
1620 let mut decoder = FrameDecoder::default();
1621 let endpoint = RecordingEndpoint::new(StreamRefId::from_u128(1));
1622
1623 decoder.push_chunk(&bytes[..split], &endpoint).unwrap();
1624 assert!(endpoint.frames().is_empty());
1625 decoder.push_chunk(&bytes[split..], &endpoint).unwrap();
1626 assert_eq!(endpoint.frames(), vec![frame]);
1627 }
1628
1629 #[test]
1630 fn compact_carrier_batch_round_trips_sequenced_frames() {
1631 let frames = (0_u64..3)
1632 .map(|seq_nr| {
1633 StreamRefFrame::new(
1634 StreamRefId::from_u128(7),
1635 datum::StreamRefMessage::SequencedOnNext {
1636 seq_nr,
1637 payload: datum::StreamRefPayloadBytes {
1638 bytes: seq_nr.to_be_bytes().to_vec(),
1639 },
1640 },
1641 )
1642 })
1643 .collect::<Vec<_>>();
1644 let bytes = encode_carrier_frames(&frames).unwrap();
1645 let header = u32::from_be_bytes(bytes[..FRAME_LEN_BYTES].try_into().unwrap());
1646 assert_ne!(header & COMPACT_FRAME_FLAG, 0);
1647
1648 let mut decoder = FrameDecoder::default();
1649 let endpoint = RecordingEndpoint::new(StreamRefId::from_u128(7));
1650 decoder.push_chunk(&bytes, &endpoint).unwrap();
1651 assert_eq!(endpoint.frames(), frames);
1652 }
1653
1654 #[test]
1655 fn compact_carrier_batch_reassembles_split_frames() {
1656 let frames = (4_u64..8)
1657 .map(|seq_nr| {
1658 StreamRefFrame::new(
1659 StreamRefId::from_u128(8),
1660 datum::StreamRefMessage::SequencedOnNext {
1661 seq_nr,
1662 payload: datum::StreamRefPayloadBytes {
1663 bytes: vec![seq_nr as u8],
1664 },
1665 },
1666 )
1667 })
1668 .collect::<Vec<_>>();
1669 let bytes = encode_carrier_frames(&frames).unwrap();
1670 let split = FRAME_LEN_BYTES + 5;
1671 let mut decoder = FrameDecoder::default();
1672 let endpoint = RecordingEndpoint::new(StreamRefId::from_u128(8));
1673
1674 decoder.push_chunk(&bytes[..split], &endpoint).unwrap();
1675 assert!(endpoint.frames().is_empty());
1676 decoder.push_chunk(&bytes[split..], &endpoint).unwrap();
1677 assert_eq!(endpoint.frames(), frames);
1678 }
1679}