From 9d4820150451c48b0219798c0120314e37db1403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michel?= Date: Mon, 10 Jul 2023 08:37:20 +0000 Subject: [PATCH] add generic transport trait --- Cargo.toml | 1 + transport/Cargo.toml | 22 ++++++ transport/src/lib.rs | 174 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 transport/Cargo.toml create mode 100644 transport/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 20c5996..bfe7c31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ members = [ "moq-transport-quinn", "moq-demo", "moq-warp", + "transport", ] diff --git a/transport/Cargo.toml b/transport/Cargo.toml new file mode 100644 index 0000000..1378e37 --- /dev/null +++ b/transport/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "moq-generic-transport" +description = "Media over QUIC" +authors = [ "Luke Curley" ] +repository = "https://github.com/kixelated/moq-rs" +license = "MIT OR Apache-2.0" + +version = "0.1.0" +edition = "2021" + +keywords = [ "quic", "http3", "webtransport", "media", "live" ] +categories = [ "multimedia", "network-programming", "web-programming" ] + + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bytes = "1" +thiserror = "1.0.21" +log = "0.4" + +anyhow = "1.0.70" diff --git a/transport/src/lib.rs b/transport/src/lib.rs new file mode 100644 index 0000000..19472dd --- /dev/null +++ b/transport/src/lib.rs @@ -0,0 +1,174 @@ +// Coming from https://github.com/hyperium/h3, the goal is to +// do a PR with the changes afterwards + +use std::task::{self, Poll}; +use bytes::Buf; +use anyhow::Error; + +type ErrorCode = u64; +type StreamId = u64; + +/// Trait representing a QUIC connection. +pub trait Connection { + /// The type produced by `poll_accept_bidi()` + type BidiStream: SendStream + RecvStream; + /// The type of the sending part of `BidiStream` + type SendStream: SendStream; + /// The type produced by `poll_accept_recv()` + type RecvStream: RecvStream; + /// A producer of outgoing Unidirectional and Bidirectional streams. + type OpenStreams: OpenStreams< + B, + SendStream = Self::SendStream, + RecvStream = Self::RecvStream, + BidiStream = Self::BidiStream, + >; + /// Error type yielded by this trait methods + type Error: Into>; + + /// Accept an incoming unidirectional stream + /// + /// Returning `None` implies the connection is closing or closed. + fn poll_accept_recv( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll, Self::Error>>; + + /// Accept an incoming bidirectional stream + /// + /// Returning `None` implies the connection is closing or closed. + fn poll_accept_bidi( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll, Self::Error>>; + + /// Poll the connection to create a new bidirectional stream. + fn poll_open_bidi( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll>; + + /// Poll the connection to create a new unidirectional stream. + fn poll_open_send( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll>; + + /// Get an object to open outgoing streams. + fn opener(&self) -> Self::OpenStreams; + + /// Close the connection immediately + fn close(&mut self, code: ErrorCode, reason: &[u8]); +} + +/// Extends the `Connection` trait for receiving datagrams +/// +/// See: +pub trait RecvDatagramExt { + /// The type of `Buf` for *raw* datagrams (without the stream_id decoded) + type Buf: Buf; + /// The error type that can occur when receiving a datagram + type Error: Into>; + + /// Poll the connection for incoming datagrams. + fn poll_accept_datagram( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll, Self::Error>>; +} + +/// Trait for opening outgoing streams +pub trait OpenStreams { + /// The type produced by `poll_open_bidi()` + type BidiStream: SendStream + RecvStream; + /// The type produced by `poll_open_send()` + type SendStream: SendStream; + /// The type of the receiving part of `BidiStream` + type RecvStream: RecvStream; + /// Error type yielded by these trait methods + type Error: Into>; + + /// Poll the connection to create a new bidirectional stream. + fn poll_open_bidi( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll>; + + /// Poll the connection to create a new unidirectional stream. + fn poll_open_send( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll>; + + /// Close the connection immediately + fn close(&mut self, code: ErrorCode, reason: &[u8]); +} + +/// A trait describing the "send" actions of a QUIC stream. +pub trait SendStream { + /// The error type returned by fallible send methods. + type Error: Into>; + + /// Polls if the stream can send more data. + fn poll_ready(&mut self, cx: &mut task::Context<'_>) -> Poll>; + + /// Send more data on the stream. + fn send_data(&mut self, data: T) -> Result<(), Self::Error>; + + /// Poll to finish the sending side of the stream. + fn poll_finish(&mut self, cx: &mut task::Context<'_>) -> Poll>; + + /// Send a QUIC reset code. + fn reset(&mut self, reset_code: u64); + + /// Get QUIC send stream id + fn send_id(&self) -> StreamId; +} + +/// Allows sending unframed pure bytes to a stream. Similar to [`AsyncWrite`](https://docs.rs/tokio/latest/tokio/io/trait.AsyncWrite.html) +pub trait SendStreamUnframed: SendStream { + /// Attempts write data into the stream. + /// + /// Returns the number of bytes written. + /// + /// `buf` is advanced by the number of bytes written. + fn poll_send( + &mut self, + cx: &mut task::Context<'_>, + buf: &mut D, + ) -> Poll>; +} + +/// A trait describing the "receive" actions of a QUIC stream. +pub trait RecvStream { + /// The type of `Buf` for data received on this stream. + type Buf: Buf; + /// The error type that can occur when receiving data. + type Error: Into>; + + /// Poll the stream for more data. + /// + /// When the receive side will no longer receive more data (such as because + /// the peer closed their sending side), this should return `None`. + fn poll_data( + &mut self, + cx: &mut task::Context<'_>, + ) -> Poll, Self::Error>>; + + /// Send a `STOP_SENDING` QUIC code. + fn stop_sending(&mut self, error_code: u64); + + /// Get QUIC send stream id + fn recv_id(&self) -> StreamId; +} + +/// Optional trait to allow "splitting" a bidirectional stream into two sides. +pub trait BidiStream: SendStream + RecvStream { + /// The type for the send half. + type SendStream: SendStream; + /// The type for the receive half. + type RecvStream: RecvStream; + + /// Split this stream into two halves. + fn split(self) -> (Self::SendStream, Self::RecvStream); +} \ No newline at end of file