From 22ecfc45a59382dc5711808c21cc402e38e84241 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Thu, 11 May 2023 11:43:06 +0300 Subject: [PATCH 01/34] start working on a quinn via interprocess option --- Cargo.lock | 159 ++++++++++++++++ Cargo.toml | 5 +- src/transport/interprocess.rs | 334 ++++++++++++++++++++++++++++++++++ src/transport/mod.rs | 2 + tests/interprocess.rs | 145 +++++++++++++++ 5 files changed, 644 insertions(+), 1 deletion(-) create mode 100644 src/transport/interprocess.rs create mode 100644 tests/interprocess.rs diff --git a/Cargo.lock b/Cargo.lock index cc7d354..94ec9b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,26 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -30,6 +50,18 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "async-task" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" + +[[package]] +name = "atomic-waker" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" + [[package]] name = "autocfg" version = "1.1.0" @@ -63,6 +95,21 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "blocking" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "log", +] + [[package]] name = "bumpalo" version = "3.12.2" @@ -102,6 +149,15 @@ dependencies = [ "types", ] +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -124,6 +180,15 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -162,6 +227,21 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "flume" version = "0.10.14" @@ -229,6 +309,21 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-macro" version = "0.3.28" @@ -385,6 +480,41 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "interprocess" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f2533f3be42fffe3b5e63b71aeca416c1c3bc33e4e27be018521e76b1f38fb" +dependencies = [ + "blocking", + "cfg-if", + "futures-core", + "futures-io", + "intmap", + "libc", + "once_cell", + "rustc_version", + "spinning", + "thiserror", + "to_method", + "winapi", +] + +[[package]] +name = "intmap" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" + [[package]] name = "itoa" version = "1.0.6" @@ -526,6 +656,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" + [[package]] name = "parking_lot" version = "0.12.1" @@ -618,8 +754,10 @@ dependencies = [ "flume", "futures", "hyper", + "interprocess", "pin-project", "quinn", + "quinn-udp", "rcgen", "rustls", "serde", @@ -973,6 +1111,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spinning" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" +dependencies = [ + "lock_api", +] + [[package]] name = "syn" version = "1.0.109" @@ -1062,6 +1209,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "to_method" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" + [[package]] name = "tokio" version = "1.28.1" @@ -1220,6 +1373,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index f3b8e34..a79d53d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ tokio = { version = "1", features = ["full"] } tokio-serde = { version = "0.8", features = ["bincode"], optional = true } tokio-util = { version = "0.7", features = ["codec"], optional = true } tracing = "0.1" +quinn-udp = { version = "0.4.0", optional = true } +interprocess = { version = "1.2.1", optional = true } [dependencies.educe] # This is an unused dependency, it is needed to make the minimal @@ -50,9 +52,10 @@ tracing-subscriber = "0.3.16" hyper-transport = ["flume", "hyper", "bincode", "bytes"] quinn-transport = ["flume", "quinn", "bincode", "tokio-serde", "tokio-util"] flume-transport = ["flume"] +interprocess-transport = ["quinn-transport", "quinn-udp", "interprocess", "bytes"] combined-transport = [] macros = [] -default = [] +default = ["interprocess-transport"] [[example]] name = "errors" diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs new file mode 100644 index 0000000..31cc660 --- /dev/null +++ b/src/transport/interprocess.rs @@ -0,0 +1,334 @@ +//! Custom quinn transport that uses the interprocess crate to provide +//! local interprocess communication via either Unix domain sockets or +//! Windows named pipes. +use std::{ + fmt::{self, Debug}, + io, + net::SocketAddr, + pin::Pin, + sync::{Arc, Mutex}, + task, +}; + +use bytes::{Buf, Bytes, BytesMut}; +use futures::{SinkExt, Stream, StreamExt}; +use quinn::{AsyncUdpSocket, Endpoint}; +use quinn_udp::RecvMeta; +use tokio::{ + io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, + select, + task::JoinHandle, +}; + +struct FlumeSocketInner { + local: SocketAddr, + receiver: flume::r#async::RecvStream<'static, Packet>, + sender: flume::r#async::SendSink<'static, Packet>, +} + +impl fmt::Debug for FlumeSocketInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("StreamSocketInner") + .field("local", &self.local) + .finish_non_exhaustive() + } +} + +/// A packet for the flume socket. +struct Packet { + from: SocketAddr, + to: SocketAddr, + data: Bytes, +} + +#[derive(Debug)] +pub(crate) struct FlumeSocket(Arc>); + +#[derive(Debug)] +pub(crate) struct LocalAddrHandle(Arc>); + +impl LocalAddrHandle { + pub fn set(&self, addr: SocketAddr) { + self.0.lock().unwrap().local = addr; + } + + pub fn get(&self) -> SocketAddr { + self.0.lock().unwrap().local + } +} + +impl AsyncUdpSocket for FlumeSocket { + fn poll_send( + &self, + state: &quinn_udp::UdpState, + cx: &mut task::Context, + transmits: &[quinn_udp::Transmit], + ) -> task::Poll> { + self.0.lock().unwrap().poll_send(state, cx, transmits) + } + + fn poll_recv( + &self, + cx: &mut task::Context, + bufs: &mut [io::IoSliceMut<'_>], + meta: &mut [RecvMeta], + ) -> task::Poll> { + self.0.lock().unwrap().poll_recv(cx, bufs, meta) + } + + fn local_addr(&self) -> io::Result { + self.0.lock().unwrap().local_addr() + } +} + +impl FlumeSocketInner { + /// Create a pair of connected sockets. + fn pair(local: SocketAddr, remote: SocketAddr) -> (Self, Self) { + let (tx1, rx1) = flume::unbounded(); + let (tx2, rx2) = flume::unbounded(); + + let a = Self { + receiver: rx1.into_stream(), + sender: tx2.into_sink(), + local, + }; + + let b = Self { + receiver: rx2.into_stream(), + sender: tx1.into_sink(), + local: remote, + }; + + (a, b) + } +} + +impl FlumeSocketInner { + fn poll_send( + &mut self, + _state: &quinn_udp::UdpState, + cx: &mut task::Context, + transmits: &[quinn_udp::Transmit], + ) -> task::Poll> { + if transmits.is_empty() { + return task::Poll::Ready(Ok(0)); + } + tracing::debug!("sending {} packets", transmits.len()); + let mut offset = 0; + let mut pending = false; + for transmit in transmits { + let item = Packet { + from: self.local, + to: transmit.destination, + data: transmit.contents.clone(), + }; + match self.sender.poll_ready_unpin(cx) { + task::Poll::Ready(Ok(())) => { + // ready to send + if self.sender.start_send_unpin(item).is_err() { + // disconnected + break; + } + } + task::Poll::Ready(Err(_)) => { + // disconneced + break; + } + task::Poll::Pending => { + // remember the offset of the first pending transmit + pending = true; + break; + } + } + offset += 1; + } + if offset > 0 { + // report how many transmits we sent + task::Poll::Ready(Ok(offset)) + } else if pending { + // only return pending if we got a pending for the first slot + task::Poll::Pending + } else { + task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "all receivers dropped", + ))) + } + } + + fn poll_recv( + &mut self, + cx: &mut std::task::Context, + bufs: &mut [io::IoSliceMut<'_>], + meta: &mut [quinn_udp::RecvMeta], + ) -> task::Poll> { + let n = bufs.len().min(meta.len()); + if n == 0 { + return task::Poll::Ready(Ok(0)); + } + let mut offset = 0; + let mut pending = false; + // try to fill as many slots as possible + while offset < n { + let packet = match Pin::new(&mut self.receiver).poll_next(cx) { + task::Poll::Ready(Some(recv)) => recv, + task::Poll::Ready(None) => break, + task::Poll::Pending => { + pending = true; + break; + } + }; + if packet.to == self.local { + let len = packet.data.len(); + bufs[offset][..len].copy_from_slice(&packet.data); + meta[offset] = quinn_udp::RecvMeta { + addr: packet.from, + len, + stride: len, + ecn: None, + dst_ip: Some(self.local.ip()), + }; + offset += 1; + } else { + // not for us, ignore + continue; + } + } + if offset > 0 { + // report how many slots we filled + tracing::debug!("received {} packets", n); + task::Poll::Ready(Ok(offset)) + } else if pending { + // only return pending if we got a pending for the first slot + task::Poll::Pending + } else { + task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "all senders dropped", + ))) + } + } + + fn local_addr(&self) -> std::io::Result { + Ok(self.local) + } +} + +fn make_endpoint( + socket: FlumeSocket, + server_config: Option, +) -> io::Result { + let config = quinn::EndpointConfig::default(); + quinn::Endpoint::new_with_abstract_socket( + config, + server_config, + socket, + Arc::new(quinn::TokioRuntime), + ) +} + +/// Create a pair of directly connected endpoints. +/// +/// Useful for testing. +pub fn endpoint_pair( + a: SocketAddr, + ac: Option, + b: SocketAddr, + bc: Option, +) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { + let (socket_a, socket_b) = FlumeSocketInner::pair(a, b); + let socket_a = FlumeSocket(Arc::new(Mutex::new(socket_a))); + let socket_b = FlumeSocket(Arc::new(Mutex::new(socket_b))); + Ok((make_endpoint(socket_a, ac)?, make_endpoint(socket_b, bc)?)) +} + +struct FrameIter<'a>(&'a mut BytesMut); + +impl<'a> Iterator for FrameIter<'a> { + type Item = Bytes; + + fn next(&mut self) -> Option { + if self.0.len() < 2 { + return None; + } + let len = u16::from_le_bytes([self.0[0], self.0[1]]) as usize; + if self.0.len() < len + 2 { + return None; + } + self.0.advance(2); + Some(self.0.split_to(len).freeze()) + } +} + +/// Wrap a tokio read/write pair as a quinn endpoint. +/// +/// The connection is assumed to be from `local` to `remote`. If you try to +/// connect to any other address, packets will be dropped. +pub fn tokio_io_endpoint( + mut r: R, + mut w: W, + local: SocketAddr, + remote: SocketAddr, + server_config: Option, +) -> io::Result<(Endpoint, JoinHandle>)> +where + R: AsyncRead + Send + Unpin + 'static, + W: AsyncWrite + Send + Unpin + 'static, +{ + let (out_send, out_recv) = flume::bounded::(32); + let (in_send, in_recv) = flume::bounded::(32); + let mut out_recv = out_recv.into_stream().ready_chunks(16); + let task = tokio::task::spawn(async move { + let mut buffer = BytesMut::with_capacity(65535); + loop { + buffer.reserve(1024 * 32); + select! { + biased; + // try to send all pending packets before reading more + Some(packets) = out_recv.next() => { + for packet in packets { + if packet.to == remote { + let len: u16 = packet.data.len().try_into().unwrap(); + w.write_all(&len.to_le_bytes()).await?; + w.write_all(&packet.data).await?; + } else { + // not for us, ignore + continue; + } + } + } + // read more data and split into frames + n = r.read_buf(&mut buffer) => { + if n? == 0 { + // eof + break; + } + // split into frames and send all full frames + for item in FrameIter(&mut buffer) { + let packet = Packet { + from: remote, + to: local, + data: item, + }; + if in_send.send_async(packet).await.is_err() { + // in_recv dropped + break; + } + } + } + else => { + // out_recv returned None, so out_send was dropped + break; + } + } + } + Ok(()) + }); + let socket = FlumeSocket(Arc::new(Mutex::new(FlumeSocketInner { + receiver: in_recv.into_stream(), + sender: out_send.into_sink(), + local, + }))); + let endpoint = make_endpoint(socket, server_config)?; + Ok((endpoint, task)) +} diff --git a/src/transport/mod.rs b/src/transport/mod.rs index d8e0f03..c282ecd 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -11,6 +11,8 @@ pub mod combined; pub mod flume; #[cfg(feature = "hyper-transport")] pub mod hyper; +#[cfg(feature = "interprocess-transport")] +pub mod interprocess; #[cfg(feature = "quinn-transport")] pub mod quinn; diff --git a/tests/interprocess.rs b/tests/interprocess.rs new file mode 100644 index 0000000..f4d3013 --- /dev/null +++ b/tests/interprocess.rs @@ -0,0 +1,145 @@ +#![cfg(feature = "quinn-transport")] +use std::{ + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + sync::Arc, +}; + +use quic_rpc::{RpcClient, RpcServer}; +use quinn::{ClientConfig, Endpoint, ServerConfig}; +use tokio::task::JoinHandle; + +mod math; +use math::*; +mod util; + +/// Constructs a QUIC endpoint configured for use a client only. +/// +/// ## Args +/// +/// - server_certs: list of trusted certificates. +#[allow(unused)] +pub fn make_client_endpoint( + bind_addr: SocketAddr, + server_certs: &[&[u8]], +) -> anyhow::Result { + let client_cfg = configure_client(server_certs)?; + let mut endpoint = Endpoint::client(bind_addr)?; + endpoint.set_default_client_config(client_cfg); + Ok(endpoint) +} + +/// Constructs a QUIC endpoint configured to listen for incoming connections on a certain address +/// and port. +/// +/// ## Returns +/// +/// - a stream of incoming QUIC connections +/// - server certificate serialized into DER format +#[allow(unused)] +pub fn make_server_endpoint(bind_addr: SocketAddr) -> anyhow::Result<(Endpoint, Vec)> { + let (server_config, server_cert) = configure_server()?; + let endpoint = Endpoint::server(server_config, bind_addr)?; + Ok((endpoint, server_cert)) +} + +/// Builds default quinn client config and trusts given certificates. +/// +/// ## Args +/// +/// - server_certs: a list of trusted certificates in DER format. +fn configure_client(server_certs: &[&[u8]]) -> anyhow::Result { + let mut certs = rustls::RootCertStore::empty(); + for cert in server_certs { + certs.add(&rustls::Certificate(cert.to_vec()))?; + } + Ok(ClientConfig::with_root_certificates(certs)) +} + +/// Returns default server configuration along with its certificate. +#[allow(clippy::field_reassign_with_default)] // https://github.com/rust-lang/rust-clippy/issues/6527 +fn configure_server() -> anyhow::Result<(ServerConfig, Vec)> { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()])?; + let cert_der = cert.serialize_der()?; + let priv_key = cert.serialize_private_key_der(); + let priv_key = rustls::PrivateKey(priv_key); + let cert_chain = vec![rustls::Certificate(cert_der.clone())]; + + let mut server_config = ServerConfig::with_single_cert(cert_chain, priv_key)?; + Arc::get_mut(&mut server_config.transport) + .unwrap() + .max_concurrent_uni_streams(0_u8.into()); + + Ok((server_config, cert_der)) +} + +pub struct Endpoints { + client: Endpoint, + server: Endpoint, + server_addr: SocketAddr, +} + +pub fn make_endpoints() -> anyhow::Result { + let server_addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1)); + let client_addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2)); + let (server_config, server_cert) = configure_server()?; + let client_config = configure_client(&[&server_cert])?; + let (server, mut client) = quic_rpc::transport::interprocess::endpoint_pair( + server_addr, + Some(server_config), + client_addr, + None, + ) + .unwrap(); + client.set_default_client_config(client_config); + Ok(Endpoints { + client, + server, + server_addr, + }) +} + +fn run_server(server: quinn::Endpoint) -> JoinHandle> { + tokio::task::spawn(async move { + let connection = quic_rpc::transport::quinn::QuinnServerEndpoint::new(server)?; + let server = RpcServer::::new(connection); + ComputeService::server(server).await?; + anyhow::Ok(()) + }) +} + +// #[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[tokio::test] +async fn quinn_interprocess_channel_bench() -> anyhow::Result<()> { + tracing_subscriber::fmt::try_init().ok(); + let Endpoints { + client, + server, + server_addr, + } = make_endpoints()?; + tracing::debug!("Starting server"); + let server_handle = run_server(server); + tracing::debug!("Starting client"); + let client = + quic_rpc::transport::quinn::QuinnConnection::new(client, server_addr, "localhost".into()); + let client = RpcClient::::new(client); + tracing::debug!("Starting benchmark"); + bench(client, 50000).await?; + server_handle.abort(); + Ok(()) +} + +#[tokio::test] +async fn quinn_interprocess_channel_smoke() -> anyhow::Result<()> { + tracing_subscriber::fmt::try_init().ok(); + let Endpoints { + client, + server, + server_addr, + } = make_endpoints()?; + let server_handle = run_server(server); + let client_connection = + quic_rpc::transport::quinn::QuinnConnection::new(client, server_addr, "localhost".into()); + smoke_test(client_connection).await?; + server_handle.abort(); + Ok(()) +} From d7b430fc41739813a975770d133f56af9f237da3 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 19 May 2023 19:01:37 +0300 Subject: [PATCH 02/34] WIP debug --- Cargo.lock | 7 ++++++ Cargo.toml | 1 + src/transport/interprocess.rs | 40 +++++++++++++++++++++++++++++------ tests/interprocess.rs | 34 +++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94ec9b3..2e90ae8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,6 +412,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "0.2.9" @@ -753,6 +759,7 @@ dependencies = [ "educe", "flume", "futures", + "hex", "hyper", "interprocess", "pin-project", diff --git a/Cargo.toml b/Cargo.toml index a79d53d..75518ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ tokio-util = { version = "0.7", features = ["codec"], optional = true } tracing = "0.1" quinn-udp = { version = "0.4.0", optional = true } interprocess = { version = "1.2.1", optional = true } +hex = "0.4.3" [dependencies.educe] # This is an unused dependency, it is needed to make the minimal diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 31cc660..73c3dc9 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -64,7 +64,10 @@ impl AsyncUdpSocket for FlumeSocket { cx: &mut task::Context, transmits: &[quinn_udp::Transmit], ) -> task::Poll> { - self.0.lock().unwrap().poll_send(state, cx, transmits) + tracing::debug!("poll_send"); + let res = self.0.lock().unwrap().poll_send(state, cx, transmits); + tracing::debug!("end poll_send"); + res } fn poll_recv( @@ -73,7 +76,10 @@ impl AsyncUdpSocket for FlumeSocket { bufs: &mut [io::IoSliceMut<'_>], meta: &mut [RecvMeta], ) -> task::Poll> { - self.0.lock().unwrap().poll_recv(cx, bufs, meta) + tracing::debug!("poll_recv"); + let res = self.0.lock().unwrap().poll_recv(cx, bufs, meta); + tracing::debug!("end poll_recv"); + res } fn local_addr(&self) -> io::Result { @@ -84,8 +90,8 @@ impl AsyncUdpSocket for FlumeSocket { impl FlumeSocketInner { /// Create a pair of connected sockets. fn pair(local: SocketAddr, remote: SocketAddr) -> (Self, Self) { - let (tx1, rx1) = flume::unbounded(); - let (tx2, rx2) = flume::unbounded(); + let (tx1, rx1) = flume::bounded(16); + let (tx2, rx2) = flume::bounded(16); let a = Self { receiver: rx1.into_stream(), @@ -110,13 +116,22 @@ impl FlumeSocketInner { cx: &mut task::Context, transmits: &[quinn_udp::Transmit], ) -> task::Poll> { + tracing::debug!("{} poll_send", self.local); if transmits.is_empty() { return task::Poll::Ready(Ok(0)); } - tracing::debug!("sending {} packets", transmits.len()); + for transmit in transmits.iter() { + tracing::debug!( + "{} sending packet to {} with ECN {:?}", + self.local, + transmit.destination, + transmit.ecn, + ); + } let mut offset = 0; let mut pending = false; for transmit in transmits { + println!("{} send {}", self.local, hex::encode(&transmit.contents)); let item = Packet { from: self.local, to: transmit.destination, @@ -144,9 +159,11 @@ impl FlumeSocketInner { } if offset > 0 { // report how many transmits we sent + tracing::debug!("{} poll_send returned ready {}", self.local, offset); task::Poll::Ready(Ok(offset)) } else if pending { // only return pending if we got a pending for the first slot + tracing::debug!("{} poll_send returned pending", self.local); task::Poll::Pending } else { task::Poll::Ready(Err(std::io::Error::new( @@ -162,6 +179,7 @@ impl FlumeSocketInner { bufs: &mut [io::IoSliceMut<'_>], meta: &mut [quinn_udp::RecvMeta], ) -> task::Poll> { + tracing::debug!("{} poll_recv", self.local); let n = bufs.len().min(meta.len()); if n == 0 { return task::Poll::Ready(Ok(0)); @@ -180,6 +198,7 @@ impl FlumeSocketInner { }; if packet.to == self.local { let len = packet.data.len(); + println!("{} recv {}", self.local, hex::encode(&packet.data)); bufs[offset][..len].copy_from_slice(&packet.data); meta[offset] = quinn_udp::RecvMeta { addr: packet.from, @@ -196,10 +215,19 @@ impl FlumeSocketInner { } if offset > 0 { // report how many slots we filled - tracing::debug!("received {} packets", n); + for i in 0..offset { + tracing::debug!( + "{} received packet to {:?} with ecn {:?}", + self.local, + meta[i].dst_ip, + meta[i].ecn + ); + } + tracing::debug!("{} poll_recv returned ready {}", self.local, offset); task::Poll::Ready(Ok(offset)) } else if pending { // only return pending if we got a pending for the first slot + tracing::debug!("{} poll_recv returned pending", self.local); task::Poll::Pending } else { task::Poll::Ready(Err(std::io::Error::new( diff --git a/tests/interprocess.rs b/tests/interprocess.rs index f4d3013..c2aec1d 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -107,6 +107,40 @@ fn run_server(server: quinn::Endpoint) -> JoinHandle> { }) } +#[tokio::test] +async fn quinn_interprocess_raw() -> anyhow::Result<()> { + tracing_subscriber::fmt::try_init().ok(); + let Endpoints { + client, + server, + server_addr, + } = make_endpoints()?; + tracing::debug!("Starting server"); + let server = tokio::spawn(async move { + while let Some(connecting) = server.accept().await { + tracing::info!("server accepted connection"); + let connection = connecting.await?; + loop { + let (mut send, mut recv) = connection.accept_bi().await?; + tracing::info!("server accepted bidi stream"); + tokio::io::copy(&mut recv, &mut send).await?; + } + } + anyhow::Ok(()) + }); + let client = tokio::spawn(async move { + let conn = client.connect(server_addr, "localhost".into())?.await?; + let (mut send, mut recv) = conn.open_bi().await?; + tokio::spawn(async move { tokio::io::copy(&mut recv, &mut tokio::io::stdout()).await }); + let test = vec![0u8; 1024]; + send.write_all(&test).await?; + anyhow::Ok(()) + }); + server.await??; + client.await??; + Ok(()) +} + // #[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test] async fn quinn_interprocess_channel_bench() -> anyhow::Result<()> { From 83307c02821f7b94580a4c59421d68b1668c811d Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 19 May 2023 19:47:07 +0300 Subject: [PATCH 03/34] hackish version of stripped down iroh Conn --- Cargo.lock | 5 +- src/transport/interprocess.rs | 285 +++++++++++++++++++++++++++++++++- tests/interprocess.rs | 2 +- 3 files changed, 284 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e90ae8..c42e9cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -778,9 +778,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea1a1124c5cf573f76bda8a1c25fd2c1689eb630cdc03fd2e9572f8b3bb1989" +checksum = "21252f1c0fc131f1b69182db8f34837e8a69737b8251dff75636a9be0518c324" dependencies = [ "bytes", "pin-project-lite", @@ -791,7 +791,6 @@ dependencies = [ "thiserror", "tokio", "tracing", - "webpki", ] [[package]] diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 73c3dc9..4dbbcd3 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -5,20 +5,197 @@ use std::{ fmt::{self, Debug}, io, net::SocketAddr, + ops::Deref, pin::Pin, sync::{Arc, Mutex}, - task, + task::{self, Context, Poll, Waker}, }; use bytes::{Buf, Bytes, BytesMut}; use futures::{SinkExt, Stream, StreamExt}; use quinn::{AsyncUdpSocket, Endpoint}; -use quinn_udp::RecvMeta; +use quinn_udp::{RecvMeta, Transmit}; use tokio::{ io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, select, + sync::mpsc, task::JoinHandle, }; +use tracing::{info, trace}; + +#[derive(Debug)] +pub(super) enum NetworkReadResult { + Error(io::Error), + Ok { + meta: quinn_udp::RecvMeta, + bytes: Bytes, + }, +} + +/// +#[derive(Debug)] +pub struct Inner { + /// Sends network messages. + network_sender: mpsc::Sender>, + /// Used for receiving DERP messages. + network_recv_ch: flume::Receiver, + /// Stores wakers, to be called when derp_recv_ch receives new data. + network_recv_wakers: std::sync::Mutex>, + pub(super) network_send_wakers: std::sync::Mutex>, + local_addr: SocketAddr, + name: String, +} + +/// +#[derive(Clone, Debug)] +pub struct Conn { + inner: Arc, +} + +impl Deref for Conn { + type Target = Inner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +/// A simple iterator to group [`Transmit`]s by destination. +struct TransmitIter<'a> { + transmits: &'a [quinn_udp::Transmit], + offset: usize, +} + +impl<'a> TransmitIter<'a> { + fn new(transmits: &'a [quinn_udp::Transmit]) -> Self { + TransmitIter { + transmits, + offset: 0, + } + } +} + +impl Iterator for TransmitIter<'_> { + type Item = Vec; + + fn next(&mut self) -> Option { + if self.offset == self.transmits.len() { + return None; + } + let current_dest = &self.transmits[self.offset].destination; + let mut end = self.offset; + for t in &self.transmits[self.offset..] { + if current_dest != &t.destination { + break; + } + end += 1; + } + + let out = self.transmits[self.offset..end].to_vec(); + self.offset = end; + Some(out) + } +} + +impl AsyncUdpSocket for Conn { + fn poll_send( + &self, + _udp_state: &quinn_udp::UdpState, + cx: &mut Context, + transmits: &[quinn_udp::Transmit], + ) -> Poll> { + let mut n = 0; + if transmits.is_empty() { + return Poll::Ready(Ok(n)); + } + + // Split up transmits by destination, as the rest of the code assumes single dest. + let groups = TransmitIter::new(transmits); + for group in groups { + match self.network_sender.try_reserve() { + Err(mpsc::error::TrySendError::Full(_)) => { + // TODO: add counter? + self.network_send_wakers + .lock() + .unwrap() + .replace(cx.waker().clone()); + break; + } + Err(mpsc::error::TrySendError::Closed(_)) => { + return Poll::Ready(Err(io::Error::new( + io::ErrorKind::NotConnected, + "connection closed", + ))); + } + Ok(permit) => { + n += group.len(); + permit.send(group); + } + } + } + if n > 0 { + return Poll::Ready(Ok(n)); + } + + Poll::Pending + } + + fn poll_recv( + &self, + cx: &mut Context, + bufs: &mut [io::IoSliceMut<'_>], + metas: &mut [quinn_udp::RecvMeta], + ) -> Poll> { + // FIXME: currently ipv4 load results in ipv6 traffic being ignored + debug_assert_eq!(bufs.len(), metas.len(), "non matching bufs & metas"); + trace!("{} poll_recv called {}", self.name, bufs.len()); + + let mut num_msgs = 0; + for (buf_out, meta_out) in bufs.iter_mut().zip(metas.iter_mut()) { + match self.network_recv_ch.try_recv() { + Err(flume::TryRecvError::Empty) => { + self.network_recv_wakers + .lock() + .unwrap() + .replace(cx.waker().clone()); + break; + } + Err(flume::TryRecvError::Disconnected) => { + return Poll::Ready(Err(io::Error::new( + io::ErrorKind::NotConnected, + "connection closed", + ))); + } + Ok(dm) => { + match dm { + NetworkReadResult::Error(err) => { + return Poll::Ready(Err(err)); + } + NetworkReadResult::Ok { bytes, meta } => { + buf_out[..bytes.len()].copy_from_slice(&bytes); + *meta_out = meta; + } + } + + num_msgs += 1; + } + } + } + + // If we have any msgs to report, they are in the first `num_msgs_total` slots + if num_msgs > 0 { + trace!("{} received {} msgs", self.name, num_msgs); + return Poll::Ready(Ok(num_msgs)); + } + + trace!("{} poll_recv pending", self.name); + Poll::Pending + } + + fn local_addr(&self) -> io::Result { + Ok(self.local_addr) + } +} struct FlumeSocketInner { local: SocketAddr, @@ -131,7 +308,7 @@ impl FlumeSocketInner { let mut offset = 0; let mut pending = false; for transmit in transmits { - println!("{} send {}", self.local, hex::encode(&transmit.contents)); + trace!("{} send {}", self.local, hex::encode(&transmit.contents)); let item = Packet { from: self.local, to: transmit.destination, @@ -198,7 +375,7 @@ impl FlumeSocketInner { }; if packet.to == self.local { let len = packet.data.len(); - println!("{} recv {}", self.local, hex::encode(&packet.data)); + trace!("{} recv {}", self.local, hex::encode(&packet.data)); bufs[offset][..len].copy_from_slice(&packet.data); meta[offset] = quinn_udp::RecvMeta { addr: packet.from, @@ -270,6 +447,106 @@ pub fn endpoint_pair( Ok((make_endpoint(socket_a, ac)?, make_endpoint(socket_b, bc)?)) } +fn make_endpoint_conn( + socket: Conn, + server_config: Option, +) -> io::Result { + let config = quinn::EndpointConfig::default(); + quinn::Endpoint::new_with_abstract_socket( + config, + server_config, + socket, + Arc::new(quinn::TokioRuntime), + ) +} + +/// Create a pair of directly connected endpoints. +/// +/// Useful for testing. +pub fn endpoint_pair_conn( + a: SocketAddr, + ac: Option, + b: SocketAddr, + bc: Option, +) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { + let (a_out_sender, mut a_out_receiver) = mpsc::channel::>(32); + let (b_out_sender, mut b_out_receiver) = mpsc::channel::>(32); + let (a_in_sender, a_in_receiver) = flume::bounded(32); + let (b_in_sender, b_in_receiver) = flume::bounded(32); + let socket_a = Conn { + inner: Arc::new(Inner { + network_sender: a_out_sender, + network_recv_ch: a_in_receiver, + network_recv_wakers: Mutex::new(None), + network_send_wakers: Mutex::new(None), + local_addr: a, + name: "a".to_string(), + }), + }; + let socket_b = Conn { + inner: Arc::new(Inner { + network_sender: b_out_sender, + network_recv_ch: b_in_receiver, + network_recv_wakers: Mutex::new(None), + network_send_wakers: Mutex::new(None), + local_addr: b, + name: "b".to_string(), + }), + }; + let socket_b2 = socket_b.clone(); + tokio::spawn(async move { + while let Some(msg) = a_out_receiver.recv().await { + for transmit in msg { + let len = transmit.contents.len(); + trace!("a -> b {}", len); + b_in_sender + .send(NetworkReadResult::Ok { + meta: RecvMeta { + addr: a, + len, + stride: len, + ecn: None, + dst_ip: Some(b.ip()), + }, + bytes: transmit.contents, + }) + .unwrap(); + } + if let Some(waker) = socket_b2.inner.network_recv_wakers.lock().unwrap().take() { + waker.wake(); + } + } + }); + let socket_a2 = socket_a.clone(); + tokio::spawn(async move { + while let Some(msg) = b_out_receiver.recv().await { + for transmit in msg { + trace!("b -> a {}", transmit.contents.len()); + let len = transmit.contents.len(); + a_in_sender + .send(NetworkReadResult::Ok { + meta: RecvMeta { + addr: b, + len, + stride: len, + ecn: None, + dst_ip: Some(a.ip()), + }, + bytes: transmit.contents, + }) + .unwrap(); + } + if let Some(waker) = socket_a2.inner.network_recv_wakers.lock().unwrap().take() { + waker.wake(); + } + } + }); + Ok(( + make_endpoint_conn(socket_a, ac)?, + make_endpoint_conn(socket_b, bc)?, + )) +} + struct FrameIter<'a>(&'a mut BytesMut); impl<'a> Iterator for FrameIter<'a> { diff --git a/tests/interprocess.rs b/tests/interprocess.rs index c2aec1d..1e2fbc5 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -83,7 +83,7 @@ pub fn make_endpoints() -> anyhow::Result { let client_addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2)); let (server_config, server_cert) = configure_server()?; let client_config = configure_client(&[&server_cert])?; - let (server, mut client) = quic_rpc::transport::interprocess::endpoint_pair( + let (server, mut client) = quic_rpc::transport::interprocess::endpoint_pair_conn( server_addr, Some(server_config), client_addr, From e63db9a0d0e9ed1192f2bddf2230f54399fcf745 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 19 May 2023 20:35:38 +0300 Subject: [PATCH 04/34] call flush on the sink --- src/transport/interprocess.rs | 99 ++++++++++++++++++++--------------- tests/interprocess.rs | 2 +- 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 4dbbcd3..e6b6cf4 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -21,7 +21,7 @@ use tokio::{ sync::mpsc, task::JoinHandle, }; -use tracing::{info, trace}; +use tracing::{debug, info, trace}; #[derive(Debug)] pub(super) enum NetworkReadResult { @@ -199,8 +199,8 @@ impl AsyncUdpSocket for Conn { struct FlumeSocketInner { local: SocketAddr, - receiver: flume::r#async::RecvStream<'static, Packet>, - sender: flume::r#async::SendSink<'static, Packet>, + receiver: Mutex>, + sender: Mutex>, } impl fmt::Debug for FlumeSocketInner { @@ -219,7 +219,7 @@ struct Packet { } #[derive(Debug)] -pub(crate) struct FlumeSocket(Arc>); +pub(crate) struct FlumeSocket(Arc); #[derive(Debug)] pub(crate) struct LocalAddrHandle(Arc>); @@ -242,7 +242,7 @@ impl AsyncUdpSocket for FlumeSocket { transmits: &[quinn_udp::Transmit], ) -> task::Poll> { tracing::debug!("poll_send"); - let res = self.0.lock().unwrap().poll_send(state, cx, transmits); + let res = self.0.poll_send(state, cx, transmits); tracing::debug!("end poll_send"); res } @@ -254,13 +254,13 @@ impl AsyncUdpSocket for FlumeSocket { meta: &mut [RecvMeta], ) -> task::Poll> { tracing::debug!("poll_recv"); - let res = self.0.lock().unwrap().poll_recv(cx, bufs, meta); + let res = self.0.poll_recv(cx, bufs, meta); tracing::debug!("end poll_recv"); res } fn local_addr(&self) -> io::Result { - self.0.lock().unwrap().local_addr() + self.0.local_addr() } } @@ -271,14 +271,14 @@ impl FlumeSocketInner { let (tx2, rx2) = flume::bounded(16); let a = Self { - receiver: rx1.into_stream(), - sender: tx2.into_sink(), + receiver: Mutex::new(rx1.into_stream()), + sender: Mutex::new(tx2.into_sink()), local, }; let b = Self { - receiver: rx2.into_stream(), - sender: tx1.into_sink(), + receiver: Mutex::new(rx2.into_stream()), + sender: Mutex::new(tx1.into_sink()), local: remote, }; @@ -288,12 +288,12 @@ impl FlumeSocketInner { impl FlumeSocketInner { fn poll_send( - &mut self, + &self, _state: &quinn_udp::UdpState, cx: &mut task::Context, transmits: &[quinn_udp::Transmit], ) -> task::Poll> { - tracing::debug!("{} poll_send", self.local); + tracing::debug!("{} poll_send {}", self.local, transmits.len()); if transmits.is_empty() { return task::Poll::Ready(Ok(0)); } @@ -314,10 +314,12 @@ impl FlumeSocketInner { to: transmit.destination, data: transmit.contents.clone(), }; - match self.sender.poll_ready_unpin(cx) { + debug!("calling poll_ready_unpin"); + let res = self.sender.lock().unwrap().poll_ready_unpin(cx); + match res { task::Poll::Ready(Ok(())) => { // ready to send - if self.sender.start_send_unpin(item).is_err() { + if self.sender.lock().unwrap().start_send_unpin(item).is_err() { // disconnected break; } @@ -335,6 +337,14 @@ impl FlumeSocketInner { offset += 1; } if offset > 0 { + // call poll_flush_unpin only once. + if let task::Poll::Ready(Err(_)) = self.sender.lock().unwrap().poll_flush_unpin(cx) { + // disconnected + return task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "all receivers dropped", + ))); + } // report how many transmits we sent tracing::debug!("{} poll_send returned ready {}", self.local, offset); task::Poll::Ready(Ok(offset)) @@ -351,13 +361,13 @@ impl FlumeSocketInner { } fn poll_recv( - &mut self, + &self, cx: &mut std::task::Context, bufs: &mut [io::IoSliceMut<'_>], meta: &mut [quinn_udp::RecvMeta], ) -> task::Poll> { - tracing::debug!("{} poll_recv", self.local); let n = bufs.len().min(meta.len()); + tracing::debug!("{} poll_recv {}", self.local, n); if n == 0 { return task::Poll::Ready(Ok(0)); } @@ -365,7 +375,7 @@ impl FlumeSocketInner { let mut pending = false; // try to fill as many slots as possible while offset < n { - let packet = match Pin::new(&mut self.receiver).poll_next(cx) { + let packet = match self.receiver.lock().unwrap().poll_next_unpin(cx) { task::Poll::Ready(Some(recv)) => recv, task::Poll::Ready(None) => break, task::Poll::Pending => { @@ -376,14 +386,15 @@ impl FlumeSocketInner { if packet.to == self.local { let len = packet.data.len(); trace!("{} recv {}", self.local, hex::encode(&packet.data)); - bufs[offset][..len].copy_from_slice(&packet.data); - meta[offset] = quinn_udp::RecvMeta { + let m = quinn_udp::RecvMeta { addr: packet.from, len, stride: len, ecn: None, dst_ip: Some(self.local.ip()), }; + bufs[offset][..len].copy_from_slice(&packet.data); + meta[offset] = m; offset += 1; } else { // not for us, ignore @@ -442,8 +453,8 @@ pub fn endpoint_pair( bc: Option, ) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { let (socket_a, socket_b) = FlumeSocketInner::pair(a, b); - let socket_a = FlumeSocket(Arc::new(Mutex::new(socket_a))); - let socket_b = FlumeSocket(Arc::new(Mutex::new(socket_b))); + let socket_a = FlumeSocket(Arc::new(socket_a)); + let socket_b = FlumeSocket(Arc::new(socket_b)); Ok((make_endpoint(socket_a, ac)?, make_endpoint(socket_b, bc)?)) } @@ -499,15 +510,18 @@ pub fn endpoint_pair_conn( for transmit in msg { let len = transmit.contents.len(); trace!("a -> b {}", len); + assert!(transmit.destination == b); + let meta = RecvMeta { + addr: a, + len, + stride: len, + ecn: None, + dst_ip: Some(b.ip()), + }; + println!("a -> b {:?}", meta); b_in_sender .send(NetworkReadResult::Ok { - meta: RecvMeta { - addr: a, - len, - stride: len, - ecn: None, - dst_ip: Some(b.ip()), - }, + meta, bytes: transmit.contents, }) .unwrap(); @@ -521,17 +535,20 @@ pub fn endpoint_pair_conn( tokio::spawn(async move { while let Some(msg) = b_out_receiver.recv().await { for transmit in msg { - trace!("b -> a {}", transmit.contents.len()); let len = transmit.contents.len(); + trace!("b -> a {}", len); + assert!(transmit.destination == a); + let meta = RecvMeta { + addr: b, + len, + stride: len, + ecn: None, + dst_ip: Some(a.ip()), + }; + println!("b -> a {:?}", meta); a_in_sender .send(NetworkReadResult::Ok { - meta: RecvMeta { - addr: b, - len, - stride: len, - ecn: None, - dst_ip: Some(a.ip()), - }, + meta, bytes: transmit.contents, }) .unwrap(); @@ -629,11 +646,11 @@ where } Ok(()) }); - let socket = FlumeSocket(Arc::new(Mutex::new(FlumeSocketInner { - receiver: in_recv.into_stream(), - sender: out_send.into_sink(), + let socket = FlumeSocket(Arc::new(FlumeSocketInner { + receiver: Mutex::new(in_recv.into_stream()), + sender: Mutex::new(out_send.into_sink()), local, - }))); + })); let endpoint = make_endpoint(socket, server_config)?; Ok((endpoint, task)) } diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 1e2fbc5..c2aec1d 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -83,7 +83,7 @@ pub fn make_endpoints() -> anyhow::Result { let client_addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2)); let (server_config, server_cert) = configure_server()?; let client_config = configure_client(&[&server_cert])?; - let (server, mut client) = quic_rpc::transport::interprocess::endpoint_pair_conn( + let (server, mut client) = quic_rpc::transport::interprocess::endpoint_pair( server_addr, Some(server_config), client_addr, From fb009c2a2de0844c3d1f1216e7088dfa630733d9 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Fri, 19 May 2023 20:50:06 +0300 Subject: [PATCH 05/34] remove iroh Conn again --- src/transport/interprocess.rs | 335 +++------------------------------- 1 file changed, 24 insertions(+), 311 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index e6b6cf4..e7ecda3 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -6,13 +6,12 @@ use std::{ io, net::SocketAddr, ops::Deref, - pin::Pin, sync::{Arc, Mutex}, task::{self, Context, Poll, Waker}, }; use bytes::{Buf, Bytes, BytesMut}; -use futures::{SinkExt, Stream, StreamExt}; +use futures::{SinkExt, StreamExt}; use quinn::{AsyncUdpSocket, Endpoint}; use quinn_udp::{RecvMeta, Transmit}; use tokio::{ @@ -21,186 +20,12 @@ use tokio::{ sync::mpsc, task::JoinHandle, }; -use tracing::{debug, info, trace}; - -#[derive(Debug)] -pub(super) enum NetworkReadResult { - Error(io::Error), - Ok { - meta: quinn_udp::RecvMeta, - bytes: Bytes, - }, -} - -/// -#[derive(Debug)] -pub struct Inner { - /// Sends network messages. - network_sender: mpsc::Sender>, - /// Used for receiving DERP messages. - network_recv_ch: flume::Receiver, - /// Stores wakers, to be called when derp_recv_ch receives new data. - network_recv_wakers: std::sync::Mutex>, - pub(super) network_send_wakers: std::sync::Mutex>, - local_addr: SocketAddr, - name: String, -} - -/// -#[derive(Clone, Debug)] -pub struct Conn { - inner: Arc, -} - -impl Deref for Conn { - type Target = Inner; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -/// A simple iterator to group [`Transmit`]s by destination. -struct TransmitIter<'a> { - transmits: &'a [quinn_udp::Transmit], - offset: usize, -} - -impl<'a> TransmitIter<'a> { - fn new(transmits: &'a [quinn_udp::Transmit]) -> Self { - TransmitIter { - transmits, - offset: 0, - } - } -} - -impl Iterator for TransmitIter<'_> { - type Item = Vec; - - fn next(&mut self) -> Option { - if self.offset == self.transmits.len() { - return None; - } - let current_dest = &self.transmits[self.offset].destination; - let mut end = self.offset; - for t in &self.transmits[self.offset..] { - if current_dest != &t.destination { - break; - } - end += 1; - } - - let out = self.transmits[self.offset..end].to_vec(); - self.offset = end; - Some(out) - } -} - -impl AsyncUdpSocket for Conn { - fn poll_send( - &self, - _udp_state: &quinn_udp::UdpState, - cx: &mut Context, - transmits: &[quinn_udp::Transmit], - ) -> Poll> { - let mut n = 0; - if transmits.is_empty() { - return Poll::Ready(Ok(n)); - } - - // Split up transmits by destination, as the rest of the code assumes single dest. - let groups = TransmitIter::new(transmits); - for group in groups { - match self.network_sender.try_reserve() { - Err(mpsc::error::TrySendError::Full(_)) => { - // TODO: add counter? - self.network_send_wakers - .lock() - .unwrap() - .replace(cx.waker().clone()); - break; - } - Err(mpsc::error::TrySendError::Closed(_)) => { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotConnected, - "connection closed", - ))); - } - Ok(permit) => { - n += group.len(); - permit.send(group); - } - } - } - if n > 0 { - return Poll::Ready(Ok(n)); - } - - Poll::Pending - } - - fn poll_recv( - &self, - cx: &mut Context, - bufs: &mut [io::IoSliceMut<'_>], - metas: &mut [quinn_udp::RecvMeta], - ) -> Poll> { - // FIXME: currently ipv4 load results in ipv6 traffic being ignored - debug_assert_eq!(bufs.len(), metas.len(), "non matching bufs & metas"); - trace!("{} poll_recv called {}", self.name, bufs.len()); - - let mut num_msgs = 0; - for (buf_out, meta_out) in bufs.iter_mut().zip(metas.iter_mut()) { - match self.network_recv_ch.try_recv() { - Err(flume::TryRecvError::Empty) => { - self.network_recv_wakers - .lock() - .unwrap() - .replace(cx.waker().clone()); - break; - } - Err(flume::TryRecvError::Disconnected) => { - return Poll::Ready(Err(io::Error::new( - io::ErrorKind::NotConnected, - "connection closed", - ))); - } - Ok(dm) => { - match dm { - NetworkReadResult::Error(err) => { - return Poll::Ready(Err(err)); - } - NetworkReadResult::Ok { bytes, meta } => { - buf_out[..bytes.len()].copy_from_slice(&bytes); - *meta_out = meta; - } - } - - num_msgs += 1; - } - } - } - - // If we have any msgs to report, they are in the first `num_msgs_total` slots - if num_msgs > 0 { - trace!("{} received {} msgs", self.name, num_msgs); - return Poll::Ready(Ok(num_msgs)); - } - - trace!("{} poll_recv pending", self.name); - Poll::Pending - } - - fn local_addr(&self) -> io::Result { - Ok(self.local_addr) - } -} +use tracing::{debug, trace}; struct FlumeSocketInner { local: SocketAddr, - receiver: Mutex>, - sender: Mutex>, + receiver: flume::r#async::RecvStream<'static, Packet>, + sender: flume::r#async::SendSink<'static, Packet>, } impl fmt::Debug for FlumeSocketInner { @@ -219,7 +44,7 @@ struct Packet { } #[derive(Debug)] -pub(crate) struct FlumeSocket(Arc); +pub(crate) struct FlumeSocket(Arc>); #[derive(Debug)] pub(crate) struct LocalAddrHandle(Arc>); @@ -241,10 +66,7 @@ impl AsyncUdpSocket for FlumeSocket { cx: &mut task::Context, transmits: &[quinn_udp::Transmit], ) -> task::Poll> { - tracing::debug!("poll_send"); - let res = self.0.poll_send(state, cx, transmits); - tracing::debug!("end poll_send"); - res + self.0.lock().unwrap().poll_send(state, cx, transmits) } fn poll_recv( @@ -253,14 +75,11 @@ impl AsyncUdpSocket for FlumeSocket { bufs: &mut [io::IoSliceMut<'_>], meta: &mut [RecvMeta], ) -> task::Poll> { - tracing::debug!("poll_recv"); - let res = self.0.poll_recv(cx, bufs, meta); - tracing::debug!("end poll_recv"); - res + self.0.lock().unwrap().poll_recv(cx, bufs, meta) } fn local_addr(&self) -> io::Result { - self.0.local_addr() + self.0.lock().unwrap().local_addr() } } @@ -271,14 +90,14 @@ impl FlumeSocketInner { let (tx2, rx2) = flume::bounded(16); let a = Self { - receiver: Mutex::new(rx1.into_stream()), - sender: Mutex::new(tx2.into_sink()), + receiver: rx1.into_stream(), + sender: tx2.into_sink(), local, }; let b = Self { - receiver: Mutex::new(rx2.into_stream()), - sender: Mutex::new(tx1.into_sink()), + receiver: rx2.into_stream(), + sender: tx1.into_sink(), local: remote, }; @@ -288,7 +107,7 @@ impl FlumeSocketInner { impl FlumeSocketInner { fn poll_send( - &self, + &mut self, _state: &quinn_udp::UdpState, cx: &mut task::Context, transmits: &[quinn_udp::Transmit], @@ -315,11 +134,11 @@ impl FlumeSocketInner { data: transmit.contents.clone(), }; debug!("calling poll_ready_unpin"); - let res = self.sender.lock().unwrap().poll_ready_unpin(cx); + let res = self.sender.poll_ready_unpin(cx); match res { task::Poll::Ready(Ok(())) => { // ready to send - if self.sender.lock().unwrap().start_send_unpin(item).is_err() { + if self.sender.start_send_unpin(item).is_err() { // disconnected break; } @@ -338,7 +157,7 @@ impl FlumeSocketInner { } if offset > 0 { // call poll_flush_unpin only once. - if let task::Poll::Ready(Err(_)) = self.sender.lock().unwrap().poll_flush_unpin(cx) { + if let task::Poll::Ready(Err(_)) = self.sender.poll_flush_unpin(cx) { // disconnected return task::Poll::Ready(Err(std::io::Error::new( std::io::ErrorKind::UnexpectedEof, @@ -361,7 +180,7 @@ impl FlumeSocketInner { } fn poll_recv( - &self, + &mut self, cx: &mut std::task::Context, bufs: &mut [io::IoSliceMut<'_>], meta: &mut [quinn_udp::RecvMeta], @@ -375,7 +194,7 @@ impl FlumeSocketInner { let mut pending = false; // try to fill as many slots as possible while offset < n { - let packet = match self.receiver.lock().unwrap().poll_next_unpin(cx) { + let packet = match self.receiver.poll_next_unpin(cx) { task::Poll::Ready(Some(recv)) => recv, task::Poll::Ready(None) => break, task::Poll::Pending => { @@ -453,117 +272,11 @@ pub fn endpoint_pair( bc: Option, ) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { let (socket_a, socket_b) = FlumeSocketInner::pair(a, b); - let socket_a = FlumeSocket(Arc::new(socket_a)); - let socket_b = FlumeSocket(Arc::new(socket_b)); + let socket_a = FlumeSocket(Arc::new(Mutex::new(socket_a))); + let socket_b = FlumeSocket(Arc::new(Mutex::new(socket_b))); Ok((make_endpoint(socket_a, ac)?, make_endpoint(socket_b, bc)?)) } -fn make_endpoint_conn( - socket: Conn, - server_config: Option, -) -> io::Result { - let config = quinn::EndpointConfig::default(); - quinn::Endpoint::new_with_abstract_socket( - config, - server_config, - socket, - Arc::new(quinn::TokioRuntime), - ) -} - -/// Create a pair of directly connected endpoints. -/// -/// Useful for testing. -pub fn endpoint_pair_conn( - a: SocketAddr, - ac: Option, - b: SocketAddr, - bc: Option, -) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { - let (a_out_sender, mut a_out_receiver) = mpsc::channel::>(32); - let (b_out_sender, mut b_out_receiver) = mpsc::channel::>(32); - let (a_in_sender, a_in_receiver) = flume::bounded(32); - let (b_in_sender, b_in_receiver) = flume::bounded(32); - let socket_a = Conn { - inner: Arc::new(Inner { - network_sender: a_out_sender, - network_recv_ch: a_in_receiver, - network_recv_wakers: Mutex::new(None), - network_send_wakers: Mutex::new(None), - local_addr: a, - name: "a".to_string(), - }), - }; - let socket_b = Conn { - inner: Arc::new(Inner { - network_sender: b_out_sender, - network_recv_ch: b_in_receiver, - network_recv_wakers: Mutex::new(None), - network_send_wakers: Mutex::new(None), - local_addr: b, - name: "b".to_string(), - }), - }; - let socket_b2 = socket_b.clone(); - tokio::spawn(async move { - while let Some(msg) = a_out_receiver.recv().await { - for transmit in msg { - let len = transmit.contents.len(); - trace!("a -> b {}", len); - assert!(transmit.destination == b); - let meta = RecvMeta { - addr: a, - len, - stride: len, - ecn: None, - dst_ip: Some(b.ip()), - }; - println!("a -> b {:?}", meta); - b_in_sender - .send(NetworkReadResult::Ok { - meta, - bytes: transmit.contents, - }) - .unwrap(); - } - if let Some(waker) = socket_b2.inner.network_recv_wakers.lock().unwrap().take() { - waker.wake(); - } - } - }); - let socket_a2 = socket_a.clone(); - tokio::spawn(async move { - while let Some(msg) = b_out_receiver.recv().await { - for transmit in msg { - let len = transmit.contents.len(); - trace!("b -> a {}", len); - assert!(transmit.destination == a); - let meta = RecvMeta { - addr: b, - len, - stride: len, - ecn: None, - dst_ip: Some(a.ip()), - }; - println!("b -> a {:?}", meta); - a_in_sender - .send(NetworkReadResult::Ok { - meta, - bytes: transmit.contents, - }) - .unwrap(); - } - if let Some(waker) = socket_a2.inner.network_recv_wakers.lock().unwrap().take() { - waker.wake(); - } - } - }); - Ok(( - make_endpoint_conn(socket_a, ac)?, - make_endpoint_conn(socket_b, bc)?, - )) -} - struct FrameIter<'a>(&'a mut BytesMut); impl<'a> Iterator for FrameIter<'a> { @@ -646,11 +359,11 @@ where } Ok(()) }); - let socket = FlumeSocket(Arc::new(FlumeSocketInner { - receiver: Mutex::new(in_recv.into_stream()), - sender: Mutex::new(out_send.into_sink()), + let socket = FlumeSocket(Arc::new(Mutex::new(FlumeSocketInner { + receiver: in_recv.into_stream(), + sender: out_send.into_sink(), local, - })); + }))); let endpoint = make_endpoint(socket, server_config)?; Ok((endpoint, task)) } From 09628eb5a9a7fa7dd51db168723355d4ee420bfd Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Mon, 22 May 2023 13:40:58 +0300 Subject: [PATCH 06/34] WIP rpc via quinn and interprocess stream test fails! --- Cargo.lock | 87 +++++++++++++- Cargo.toml | 7 +- src/transport/interprocess.rs | 34 +----- tests/interprocess.rs | 206 +++++++++++++++++++++++++++++++++- 4 files changed, 294 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c42e9cc..b7e4310 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,6 +227,27 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -412,6 +433,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -512,6 +539,7 @@ dependencies = [ "spinning", "thiserror", "to_method", + "tokio", "winapi", ] @@ -521,6 +549,17 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "itoa" version = "1.0.6" @@ -548,6 +587,12 @@ version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "lock_api" version = "0.4.9" @@ -640,7 +685,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -686,7 +731,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "windows-sys 0.45.0", ] @@ -768,6 +813,7 @@ dependencies = [ "rcgen", "rustls", "serde", + "tempfile", "thousands", "tokio", "tokio-serde", @@ -885,6 +931,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "ring" version = "0.16.20" @@ -915,6 +970,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.21.1" @@ -1148,6 +1217,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "thiserror" version = "1.0.40" @@ -1274,6 +1356,7 @@ checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 75518ff..8de9886 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,10 +25,10 @@ quinn = { version = "0.10", optional = true } serde = { version = "1.0.103" } tokio = { version = "1", features = ["full"] } tokio-serde = { version = "0.8", features = ["bincode"], optional = true } -tokio-util = { version = "0.7", features = ["codec"], optional = true } +tokio-util = { version = "0.7", features = ["codec", "compat"], optional = true } tracing = "0.1" quinn-udp = { version = "0.4.0", optional = true } -interprocess = { version = "1.2.1", optional = true } +interprocess = { version = "1.2.1", features = ["tokio_support"], optional = true } hex = "0.4.3" [dependencies.educe] @@ -48,12 +48,13 @@ rcgen = "0.10.0" rustls = "0.21" thousands = "0.2.0" tracing-subscriber = "0.3.16" +tempfile = "3.5.0" [features] hyper-transport = ["flume", "hyper", "bincode", "bytes"] quinn-transport = ["flume", "quinn", "bincode", "tokio-serde", "tokio-util"] flume-transport = ["flume"] -interprocess-transport = ["quinn-transport", "quinn-udp", "interprocess", "bytes"] +interprocess-transport = ["quinn-transport", "quinn-udp", "interprocess", "bytes", "tokio-util"] combined-transport = [] macros = [] default = ["interprocess-transport"] diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index e7ecda3..5a8cddd 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -5,22 +5,19 @@ use std::{ fmt::{self, Debug}, io, net::SocketAddr, - ops::Deref, sync::{Arc, Mutex}, - task::{self, Context, Poll, Waker}, + task, }; use bytes::{Buf, Bytes, BytesMut}; use futures::{SinkExt, StreamExt}; use quinn::{AsyncUdpSocket, Endpoint}; -use quinn_udp::{RecvMeta, Transmit}; +use quinn_udp::RecvMeta; use tokio::{ io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, select, - sync::mpsc, task::JoinHandle, }; -use tracing::{debug, trace}; struct FlumeSocketInner { local: SocketAddr, @@ -112,28 +109,17 @@ impl FlumeSocketInner { cx: &mut task::Context, transmits: &[quinn_udp::Transmit], ) -> task::Poll> { - tracing::debug!("{} poll_send {}", self.local, transmits.len()); if transmits.is_empty() { return task::Poll::Ready(Ok(0)); } - for transmit in transmits.iter() { - tracing::debug!( - "{} sending packet to {} with ECN {:?}", - self.local, - transmit.destination, - transmit.ecn, - ); - } let mut offset = 0; let mut pending = false; for transmit in transmits { - trace!("{} send {}", self.local, hex::encode(&transmit.contents)); let item = Packet { from: self.local, to: transmit.destination, data: transmit.contents.clone(), }; - debug!("calling poll_ready_unpin"); let res = self.sender.poll_ready_unpin(cx); match res { task::Poll::Ready(Ok(())) => { @@ -165,11 +151,9 @@ impl FlumeSocketInner { ))); } // report how many transmits we sent - tracing::debug!("{} poll_send returned ready {}", self.local, offset); task::Poll::Ready(Ok(offset)) } else if pending { // only return pending if we got a pending for the first slot - tracing::debug!("{} poll_send returned pending", self.local); task::Poll::Pending } else { task::Poll::Ready(Err(std::io::Error::new( @@ -186,7 +170,6 @@ impl FlumeSocketInner { meta: &mut [quinn_udp::RecvMeta], ) -> task::Poll> { let n = bufs.len().min(meta.len()); - tracing::debug!("{} poll_recv {}", self.local, n); if n == 0 { return task::Poll::Ready(Ok(0)); } @@ -204,7 +187,6 @@ impl FlumeSocketInner { }; if packet.to == self.local { let len = packet.data.len(); - trace!("{} recv {}", self.local, hex::encode(&packet.data)); let m = quinn_udp::RecvMeta { addr: packet.from, len, @@ -222,19 +204,9 @@ impl FlumeSocketInner { } if offset > 0 { // report how many slots we filled - for i in 0..offset { - tracing::debug!( - "{} received packet to {:?} with ecn {:?}", - self.local, - meta[i].dst_ip, - meta[i].ecn - ); - } - tracing::debug!("{} poll_recv returned ready {}", self.local, offset); task::Poll::Ready(Ok(offset)) } else if pending { // only return pending if we got a pending for the first slot - tracing::debug!("{} poll_recv returned pending", self.local); task::Poll::Pending } else { task::Poll::Ready(Err(std::io::Error::new( @@ -314,6 +286,7 @@ where let (in_send, in_recv) = flume::bounded::(32); let mut out_recv = out_recv.into_stream().ready_chunks(16); let task = tokio::task::spawn(async move { + tracing::debug!("{} running forwarder task to {}", local, remote); let mut buffer = BytesMut::with_capacity(65535); loop { buffer.reserve(1024 * 32); @@ -321,6 +294,7 @@ where biased; // try to send all pending packets before reading more Some(packets) = out_recv.next() => { + tracing::debug!("{} sending {} packets", local, packets.len()); for packet in packets { if packet.to == remote { let len: u16 = packet.data.len().try_into().unwrap(); diff --git a/tests/interprocess.rs b/tests/interprocess.rs index c2aec1d..5882180 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -4,9 +4,10 @@ use std::{ sync::Arc, }; -use quic_rpc::{RpcClient, RpcServer}; +use quic_rpc::{transport::interprocess::tokio_io_endpoint, RpcClient, RpcServer}; use quinn::{ClientConfig, Endpoint, ServerConfig}; -use tokio::task::JoinHandle; +use tokio::{io::AsyncWriteExt, task::JoinHandle}; +use tokio_util::compat::{FuturesAsyncReadCompatExt, FuturesAsyncWriteCompatExt}; mod math; use math::*; @@ -108,7 +109,7 @@ fn run_server(server: quinn::Endpoint) -> JoinHandle> { } #[tokio::test] -async fn quinn_interprocess_raw() -> anyhow::Result<()> { +async fn quinn_flume_socket_raw() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); let Endpoints { client, @@ -143,7 +144,7 @@ async fn quinn_interprocess_raw() -> anyhow::Result<()> { // #[tokio::test(flavor = "multi_thread", worker_threads = 2)] #[tokio::test] -async fn quinn_interprocess_channel_bench() -> anyhow::Result<()> { +async fn quinn_flume_channel_bench() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); let Endpoints { client, @@ -163,7 +164,7 @@ async fn quinn_interprocess_channel_bench() -> anyhow::Result<()> { } #[tokio::test] -async fn quinn_interprocess_channel_smoke() -> anyhow::Result<()> { +async fn quinn_flume_channel_smoke() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); let Endpoints { client, @@ -177,3 +178,198 @@ async fn quinn_interprocess_channel_smoke() -> anyhow::Result<()> { server_handle.abort(); Ok(()) } + +/// Basic test of the interprocess crate. +/// Just sends a message from client to server and back. +#[tokio::test] +async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { + tracing_subscriber::fmt::try_init().ok(); + use interprocess::local_socket::tokio::*; + let dir = tempfile::tempdir()?; + let socket_name = dir.path().join("interprocess.socket"); + let socket = LocalSocketListener::bind(socket_name.clone())?; + let socket_name_2 = socket_name.clone(); + let server = tokio::spawn(async move { + let stream = socket.accept().await?; + let (r, w) = stream.into_split(); + let mut r = r.compat(); + let mut w = w.compat_write(); + tokio::io::copy(&mut r, &mut w).await?; + anyhow::Ok(()) + }); + let client = tokio::spawn(async move { + let stream = LocalSocketStream::connect(socket_name_2.clone()).await?; + let (r, w) = stream.into_split(); + let mut r = r.compat(); + let mut w = w.compat_write(); + w.write_all(b"hello").await?; + w.write_all(b"world").await?; + let validator = tokio::spawn(async move { + let mut out = Vec::::new(); + tokio::io::copy(&mut r, &mut out).await?; + let pass = out == b"helloworld"; + anyhow::Ok(pass) + }); + drop(w); + validator.await? + }); + server.await??; + assert!(client.await??, "echo test failed"); + Ok(()) +} + +/// Test of quinn on top of interprocess. +/// Just sends a message from client to server and back. +#[tokio::test] +async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { + tracing_subscriber::fmt::try_init().ok(); + use interprocess::local_socket::tokio::*; + let (server_config, server_certs) = configure_server()?; + let client_config = configure_client(&[&server_certs])?; + tracing_subscriber::fmt::try_init().ok(); + let dir = tempfile::tempdir()?; + let socket_name = dir.path().join("interprocess.socket"); + let socket = LocalSocketListener::bind(socket_name.clone())?; + let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); + let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); + let server = tokio::spawn(async move { + let stream = socket.accept().await?; + let (r, w) = stream.into_split(); + let r = r.compat(); + let w = w.compat_write(); + let (endpoint, _task) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; + tracing::debug!("server accepting connection"); + let connection = endpoint.accept().await.unwrap().await?; + tracing::debug!("server accepted connection"); + let (mut send, mut recv) = connection.accept_bi().await?; + tracing::debug!("server accepted bi stream"); + tracing::debug!("server copying"); + let n = tokio::io::copy(&mut recv, &mut send).await?; + tracing::debug!("server done copying {} bytes", n); + // need to keep the connection alive until the client is done + anyhow::Ok(connection) + }); + let client = tokio::spawn(async move { + let stream = LocalSocketStream::connect(socket_name).await?; + let (r, w) = stream.into_split(); + let r = r.compat(); + let w = w.compat_write(); + let (mut endpoint, _task) = tokio_io_endpoint(r, w, local, remote, None)?; + endpoint.set_default_client_config(client_config); + tracing::debug!("client connecting to server at {} using localhost", remote); + let connection = endpoint.connect(remote, "localhost")?.await?; + tracing::debug!("client got connection"); + let (mut send, mut recv) = connection.open_bi().await?; + tracing::debug!("client got bi stream"); + let validator = tokio::spawn(async move { + let mut out = Vec::::new(); + tracing::debug!("client validator reading data"); + tokio::io::copy(&mut recv, &mut out).await.ok(); + tracing::debug!("client validator done reading data {}", out.len()); + let pass = out == b"helloworld"; + anyhow::Ok(pass) + }); + tracing::debug!("client sending data"); + send.write_all(b"hello").await?; + send.write_all(b"world").await?; + send.finish().await?; + tracing::debug!("client finished sending data"); + drop(send); + validator.await? + }); + let connection = server.await??; + assert!(client.await??, "echo test failed"); + drop(connection); + Ok(()) +} + +/// Smoke test of quinn on top of interprocess. +#[tokio::test] +async fn interprocess_quinn_smoke() -> anyhow::Result<()> { + tracing_subscriber::fmt::try_init().ok(); + use interprocess::local_socket::tokio::*; + let (server_config, server_certs) = configure_server()?; + let client_config = configure_client(&[&server_certs])?; + tracing_subscriber::fmt::try_init().ok(); + let dir = tempfile::tempdir()?; + let socket_name = dir.path().join("interprocess.socket"); + let socket = LocalSocketListener::bind(socket_name.clone())?; + let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); + let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); + let server = tokio::spawn(async move { + let stream = socket.accept().await?; + let (r, w) = stream.into_split(); + let r = r.compat(); + let w = w.compat_write(); + let (endpoint, _task) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; + // run rpc server on endpoint + tracing::debug!("creating test rpc server"); + let _server_task = run_server(endpoint); + anyhow::Ok(()) + }); + let client = tokio::spawn(async move { + let stream = LocalSocketStream::connect(socket_name).await?; + let (r, w) = stream.into_split(); + let r = r.compat(); + let w = w.compat_write(); + let (mut endpoint, _task) = tokio_io_endpoint(r, w, local, remote, None)?; + endpoint.set_default_client_config(client_config); + tracing::debug!( + "creating test rpc client, connecting to server at {} using localhost", + remote + ); + let client: quic_rpc::transport::quinn::QuinnConnection = + quic_rpc::transport::quinn::QuinnConnection::new(endpoint, remote, "localhost".into()); + smoke_test(client).await?; + anyhow::Ok(()) + }); + server.await??; + client.await??; + Ok(()) +} + +/// Bench test of quinn on top of interprocess. +#[tokio::test] +async fn interprocess_quinn_bench() -> anyhow::Result<()> { + tracing_subscriber::fmt::try_init().ok(); + use interprocess::local_socket::tokio::*; + let (server_config, server_certs) = configure_server()?; + let client_config = configure_client(&[&server_certs])?; + tracing_subscriber::fmt::try_init().ok(); + let dir = tempfile::tempdir()?; + let socket_name = dir.path().join("interprocess.socket"); + let socket = LocalSocketListener::bind(socket_name.clone())?; + let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); + let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); + let server = tokio::spawn(async move { + let stream = socket.accept().await?; + let (r, w) = stream.into_split(); + let r = r.compat(); + let w = w.compat_write(); + let (endpoint, _task) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; + // run rpc server on endpoint + tracing::debug!("creating test rpc server"); + let _server_task = run_server(endpoint); + anyhow::Ok(()) + }); + let client = tokio::spawn(async move { + let stream = LocalSocketStream::connect(socket_name).await?; + let (r, w) = stream.into_split(); + let r = r.compat(); + let w = w.compat_write(); + let (mut endpoint, _task) = tokio_io_endpoint(r, w, local, remote, None)?; + endpoint.set_default_client_config(client_config); + tracing::debug!( + "creating test rpc client, connecting to server at {} using localhost", + remote + ); + let client: quic_rpc::transport::quinn::QuinnConnection = + quic_rpc::transport::quinn::QuinnConnection::new(endpoint, remote, "localhost".into()); + let client = RpcClient::new(client); + bench(client, 50000).await?; + anyhow::Ok(()) + }); + server.await??; + client.await??; + Ok(()) +} From 596a426e20fd1e5ada2eebc2c2256d202700dc5d Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Mon, 14 Aug 2023 14:22:47 +0200 Subject: [PATCH 07/34] fix: do not use macros in tests macros are an optional feature --- tests/math.rs | 41 +++++++++++++++++++++++++++++++++++------ tests/slow_math.rs | 41 +++++++++++++++++++++++++++++++++++------ 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/tests/math.rs b/tests/math.rs index ab44b75..8ecac02 100644 --- a/tests/math.rs +++ b/tests/math.rs @@ -8,8 +8,12 @@ use async_stream::stream; use derive_more::{From, TryInto}; use futures::{SinkExt, Stream, StreamExt, TryStreamExt}; use quic_rpc::{ - declare_bidi_streaming, declare_client_streaming, declare_rpc, declare_server_streaming, - server::RpcServerError, RpcClient, RpcServer, Service, ServiceConnection, ServiceEndpoint, + message::{ + BidiStreaming, BidiStreamingMsg, ClientStreaming, ClientStreamingMsg, Msg, RpcMsg, + ServerStreaming, ServerStreamingMsg, + }, + server::RpcServerError, + RpcClient, RpcServer, Service, ServiceConnection, ServiceEndpoint, }; use serde::{Deserialize, Serialize}; use std::{ @@ -81,10 +85,35 @@ impl Service for ComputeService { type Res = ComputeResponse; } -declare_rpc!(ComputeService, Sqr, SqrResponse); -declare_client_streaming!(ComputeService, Sum, SumUpdate, SumResponse); -declare_server_streaming!(ComputeService, Fibonacci, FibonacciResponse); -declare_bidi_streaming!(ComputeService, Multiply, MultiplyUpdate, MultiplyResponse); +impl RpcMsg for Sqr { + type Response = SqrResponse; +} + +impl Msg for Sum { + type Pattern = ClientStreaming; +} + +impl ClientStreamingMsg for Sum { + type Update = SumUpdate; + type Response = SumResponse; +} + +impl Msg for Fibonacci { + type Pattern = ServerStreaming; +} + +impl ServerStreamingMsg for Fibonacci { + type Response = FibonacciResponse; +} + +impl Msg for Multiply { + type Pattern = BidiStreaming; +} + +impl BidiStreamingMsg for Multiply { + type Update = MultiplyUpdate; + type Response = MultiplyResponse; +} impl ComputeService { async fn sqr(self, req: Sqr) -> SqrResponse { diff --git a/tests/slow_math.rs b/tests/slow_math.rs index fca09c5..e68ec10 100644 --- a/tests/slow_math.rs +++ b/tests/slow_math.rs @@ -10,8 +10,12 @@ use async_stream::stream; use futures::{Stream, StreamExt}; use math::*; use quic_rpc::{ - declare_bidi_streaming, declare_client_streaming, declare_rpc, declare_server_streaming, - server::RpcServerError, RpcServer, Service, ServiceEndpoint, + message::{ + BidiStreaming, BidiStreamingMsg, ClientStreaming, ClientStreamingMsg, Msg, RpcMsg, + ServerStreaming, ServerStreamingMsg, + }, + server::RpcServerError, + RpcServer, Service, ServiceEndpoint, }; #[derive(Debug, Clone)] @@ -22,10 +26,35 @@ impl Service for ComputeService { type Res = ComputeResponse; } -declare_rpc!(ComputeService, Sqr, SqrResponse); -declare_client_streaming!(ComputeService, Sum, SumUpdate, SumResponse); -declare_server_streaming!(ComputeService, Fibonacci, FibonacciResponse); -declare_bidi_streaming!(ComputeService, Multiply, MultiplyUpdate, MultiplyResponse); +impl RpcMsg for Sqr { + type Response = SqrResponse; +} + +impl Msg for Sum { + type Pattern = ClientStreaming; +} + +impl ClientStreamingMsg for Sum { + type Update = SumUpdate; + type Response = SumResponse; +} + +impl Msg for Fibonacci { + type Pattern = ServerStreaming; +} + +impl ServerStreamingMsg for Fibonacci { + type Response = FibonacciResponse; +} + +impl Msg for Multiply { + type Pattern = BidiStreaming; +} + +impl BidiStreamingMsg for Multiply { + type Update = MultiplyUpdate; + type Response = MultiplyResponse; +} async fn sleep_ms(ms: u64) { tokio::time::sleep(std::time::Duration::from_millis(ms)).await; From 2e334f345d5d2a82bb425c993478772e63d11dfe Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Mon, 14 Aug 2023 14:29:03 +0200 Subject: [PATCH 08/34] fix: do two forwarder tasks select! is never going to work here because there are other awaits in each select branch. --- Cargo.toml | 4 +- src/transport/interprocess.rs | 96 +++++++++++++++++------------------ tests/interprocess.rs | 29 +++++++---- 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 847c879..e4edc13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,10 +54,10 @@ tempfile = "3.5.0" hyper-transport = ["flume", "hyper", "bincode", "bytes"] quinn-transport = ["flume", "quinn", "bincode", "tokio-serde", "tokio-util"] flume-transport = ["flume"] -interprocess-transport = ["quinn-transport", "quinn-udp", "interprocess", "bytes", "tokio-util"] +interprocess-transport = ["quinn-udp", "interprocess", "bytes", "tokio-util"] combined-transport = [] macros = [] -default = ["interprocess-transport"] +default = ["quinn-transport", "interprocess-transport"] [[example]] name = "errors" diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 5a8cddd..a3ac256 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -11,11 +11,10 @@ use std::{ use bytes::{Buf, Bytes, BytesMut}; use futures::{SinkExt, StreamExt}; -use quinn::{AsyncUdpSocket, Endpoint}; +use quinn::{AsyncUdpSocket, Endpoint, EndpointConfig}; use quinn_udp::RecvMeta; use tokio::{ io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, - select, task::JoinHandle, }; @@ -223,9 +222,9 @@ impl FlumeSocketInner { fn make_endpoint( socket: FlumeSocket, + config: EndpointConfig, server_config: Option, ) -> io::Result { - let config = quinn::EndpointConfig::default(); quinn::Endpoint::new_with_abstract_socket( config, server_config, @@ -239,14 +238,19 @@ fn make_endpoint( /// Useful for testing. pub fn endpoint_pair( a: SocketAddr, - ac: Option, + asc: Option, b: SocketAddr, - bc: Option, + bsc: Option, ) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { let (socket_a, socket_b) = FlumeSocketInner::pair(a, b); let socket_a = FlumeSocket(Arc::new(Mutex::new(socket_a))); let socket_b = FlumeSocket(Arc::new(Mutex::new(socket_b))); - Ok((make_endpoint(socket_a, ac)?, make_endpoint(socket_b, bc)?)) + let ac = EndpointConfig::default(); + let bc = EndpointConfig::default(); + Ok(( + make_endpoint(socket_a, ac, asc)?, + make_endpoint(socket_b, bc, bsc)?, + )) } struct FrameIter<'a>(&'a mut BytesMut); @@ -277,7 +281,7 @@ pub fn tokio_io_endpoint( local: SocketAddr, remote: SocketAddr, server_config: Option, -) -> io::Result<(Endpoint, JoinHandle>)> +) -> io::Result<(Endpoint, JoinHandle>, JoinHandle>)> where R: AsyncRead + Send + Unpin + 'static, W: AsyncWrite + Send + Unpin + 'static, @@ -285,48 +289,43 @@ where let (out_send, out_recv) = flume::bounded::(32); let (in_send, in_recv) = flume::bounded::(32); let mut out_recv = out_recv.into_stream().ready_chunks(16); - let task = tokio::task::spawn(async move { + let sender = tokio::task::spawn(async move { tracing::debug!("{} running forwarder task to {}", local, remote); + while let Some(packets) = out_recv.next().await { + for packet in packets { + if packet.to == remote { + let len: u16 = packet.data.len().try_into().unwrap(); + w.write_all(&len.to_le_bytes()).await?; + w.write_all(&packet.data).await?; + } else { + // not for us, ignore + continue; + } + } + } + Ok(()) + }); + let receiver = tokio::task::spawn(async move { let mut buffer = BytesMut::with_capacity(65535); loop { - buffer.reserve(1024 * 32); - select! { - biased; - // try to send all pending packets before reading more - Some(packets) = out_recv.next() => { - tracing::debug!("{} sending {} packets", local, packets.len()); - for packet in packets { - if packet.to == remote { - let len: u16 = packet.data.len().try_into().unwrap(); - w.write_all(&len.to_le_bytes()).await?; - w.write_all(&packet.data).await?; - } else { - // not for us, ignore - continue; - } - } - } - // read more data and split into frames - n = r.read_buf(&mut buffer) => { - if n? == 0 { - // eof - break; - } - // split into frames and send all full frames - for item in FrameIter(&mut buffer) { - let packet = Packet { - from: remote, - to: local, - data: item, - }; - if in_send.send_async(packet).await.is_err() { - // in_recv dropped - break; - } - } - } - else => { - // out_recv returned None, so out_send was dropped + // read more data and split into frames + let n = r.read_buf(&mut buffer).await; + + let n = n?; + if n == 0 { + // eof + break; + } + tracing::debug!("R {} read {} bytes {}", local, n, buffer.len()); + // split into frames and send all full frames + for item in FrameIter(&mut buffer) { + let packet = Packet { + from: remote, + to: local, + data: item, + }; + if in_send.send_async(packet).await.is_err() { + // in_recv dropped break; } } @@ -338,6 +337,7 @@ where sender: out_send.into_sink(), local, }))); - let endpoint = make_endpoint(socket, server_config)?; - Ok((endpoint, task)) + let config = EndpointConfig::default(); + let endpoint = make_endpoint(socket, config, server_config)?; + Ok((endpoint, sender, receiver)) } diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 5882180..240deaf 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -1,4 +1,4 @@ -#![cfg(feature = "quinn-transport")] +#![cfg(feature = "interprocess-transport")] use std::{ net::{Ipv4Addr, SocketAddr, SocketAddrV4}, sync::Arc, @@ -118,13 +118,14 @@ async fn quinn_flume_socket_raw() -> anyhow::Result<()> { } = make_endpoints()?; tracing::debug!("Starting server"); let server = tokio::spawn(async move { + tracing::info!("server started"); while let Some(connecting) = server.accept().await { tracing::info!("server accepted connection"); let connection = connecting.await?; - loop { - let (mut send, mut recv) = connection.accept_bi().await?; + while let Ok((mut send, mut recv)) = connection.accept_bi().await { tracing::info!("server accepted bidi stream"); tokio::io::copy(&mut recv, &mut send).await?; + tracing::info!("server done with bidi stream"); } } anyhow::Ok(()) @@ -132,9 +133,17 @@ async fn quinn_flume_socket_raw() -> anyhow::Result<()> { let client = tokio::spawn(async move { let conn = client.connect(server_addr, "localhost".into())?.await?; let (mut send, mut recv) = conn.open_bi().await?; - tokio::spawn(async move { tokio::io::copy(&mut recv, &mut tokio::io::stdout()).await }); + tracing::info!("client connected"); + tokio::spawn(async move { + tracing::info!("outputting data from server"); + tokio::io::copy(&mut recv, &mut tokio::io::stdout()).await?; + tracing::info!("outputting data from server done"); + anyhow::Ok(()) + }); + tracing::info!("sending data to be echoed"); let test = vec![0u8; 1024]; send.write_all(&test).await?; + tracing::info!("sending data done"); anyhow::Ok(()) }); server.await??; @@ -237,7 +246,7 @@ async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { let (r, w) = stream.into_split(); let r = r.compat(); let w = w.compat_write(); - let (endpoint, _task) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; + let (endpoint, _s, _r) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; tracing::debug!("server accepting connection"); let connection = endpoint.accept().await.unwrap().await?; tracing::debug!("server accepted connection"); @@ -254,7 +263,7 @@ async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { let (r, w) = stream.into_split(); let r = r.compat(); let w = w.compat_write(); - let (mut endpoint, _task) = tokio_io_endpoint(r, w, local, remote, None)?; + let (mut endpoint, _s, _r) = tokio_io_endpoint(r, w, local, remote, None)?; endpoint.set_default_client_config(client_config); tracing::debug!("client connecting to server at {} using localhost", remote); let connection = endpoint.connect(remote, "localhost")?.await?; @@ -301,7 +310,7 @@ async fn interprocess_quinn_smoke() -> anyhow::Result<()> { let (r, w) = stream.into_split(); let r = r.compat(); let w = w.compat_write(); - let (endpoint, _task) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; + let (endpoint, _s, _r) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; // run rpc server on endpoint tracing::debug!("creating test rpc server"); let _server_task = run_server(endpoint); @@ -312,7 +321,7 @@ async fn interprocess_quinn_smoke() -> anyhow::Result<()> { let (r, w) = stream.into_split(); let r = r.compat(); let w = w.compat_write(); - let (mut endpoint, _task) = tokio_io_endpoint(r, w, local, remote, None)?; + let (mut endpoint, _s, _r) = tokio_io_endpoint(r, w, local, remote, None)?; endpoint.set_default_client_config(client_config); tracing::debug!( "creating test rpc client, connecting to server at {} using localhost", @@ -346,7 +355,7 @@ async fn interprocess_quinn_bench() -> anyhow::Result<()> { let (r, w) = stream.into_split(); let r = r.compat(); let w = w.compat_write(); - let (endpoint, _task) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; + let (endpoint, _s, _r) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; // run rpc server on endpoint tracing::debug!("creating test rpc server"); let _server_task = run_server(endpoint); @@ -357,7 +366,7 @@ async fn interprocess_quinn_bench() -> anyhow::Result<()> { let (r, w) = stream.into_split(); let r = r.compat(); let w = w.compat_write(); - let (mut endpoint, _task) = tokio_io_endpoint(r, w, local, remote, None)?; + let (mut endpoint, _s, _r) = tokio_io_endpoint(r, w, local, remote, None)?; endpoint.set_default_client_config(client_config); tracing::debug!( "creating test rpc client, connecting to server at {} using localhost", From 33a2e3d92d8b1fdbdf8ae80b1a12937aad695343 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Mon, 14 Aug 2023 15:14:30 +0200 Subject: [PATCH 09/34] fmt --- src/transport/interprocess.rs | 21 +++++++++++++-------- tests/interprocess.rs | 14 +++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index a3ac256..7764dc3 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -46,10 +46,12 @@ pub(crate) struct FlumeSocket(Arc>); pub(crate) struct LocalAddrHandle(Arc>); impl LocalAddrHandle { + #[allow(dead_code)] pub fn set(&self, addr: SocketAddr) { self.0.lock().unwrap().local = addr; } + #[allow(dead_code)] pub fn get(&self) -> SocketAddr { self.0.lock().unwrap().local } @@ -237,19 +239,18 @@ fn make_endpoint( /// /// Useful for testing. pub fn endpoint_pair( - a: SocketAddr, - asc: Option, - b: SocketAddr, - bsc: Option, + s: SocketAddr, + c: SocketAddr, + sc: quinn::ServerConfig, ) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { - let (socket_a, socket_b) = FlumeSocketInner::pair(a, b); + let (socket_a, socket_b) = FlumeSocketInner::pair(s, c); let socket_a = FlumeSocket(Arc::new(Mutex::new(socket_a))); let socket_b = FlumeSocket(Arc::new(Mutex::new(socket_b))); let ac = EndpointConfig::default(); let bc = EndpointConfig::default(); Ok(( - make_endpoint(socket_a, ac, asc)?, - make_endpoint(socket_b, bc, bsc)?, + make_endpoint(socket_a, ac, Some(sc))?, + make_endpoint(socket_b, bc, None)?, )) } @@ -281,7 +282,11 @@ pub fn tokio_io_endpoint( local: SocketAddr, remote: SocketAddr, server_config: Option, -) -> io::Result<(Endpoint, JoinHandle>, JoinHandle>)> +) -> io::Result<( + Endpoint, + JoinHandle>, + JoinHandle>, +)> where R: AsyncRead + Send + Unpin + 'static, W: AsyncWrite + Send + Unpin + 'static, diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 240deaf..0937e8b 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -84,13 +84,9 @@ pub fn make_endpoints() -> anyhow::Result { let client_addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2)); let (server_config, server_cert) = configure_server()?; let client_config = configure_client(&[&server_cert])?; - let (server, mut client) = quic_rpc::transport::interprocess::endpoint_pair( - server_addr, - Some(server_config), - client_addr, - None, - ) - .unwrap(); + let (server, mut client) = + quic_rpc::transport::interprocess::endpoint_pair(server_addr, client_addr, server_config) + .unwrap(); client.set_default_client_config(client_config); Ok(Endpoints { client, @@ -122,7 +118,7 @@ async fn quinn_flume_socket_raw() -> anyhow::Result<()> { while let Some(connecting) = server.accept().await { tracing::info!("server accepted connection"); let connection = connecting.await?; - while let Ok((mut send, mut recv)) = connection.accept_bi().await { + while let Ok((mut send, mut recv)) = connection.accept_bi().await { tracing::info!("server accepted bidi stream"); tokio::io::copy(&mut recv, &mut send).await?; tracing::info!("server done with bidi stream"); @@ -134,7 +130,7 @@ async fn quinn_flume_socket_raw() -> anyhow::Result<()> { let conn = client.connect(server_addr, "localhost".into())?.await?; let (mut send, mut recv) = conn.open_bi().await?; tracing::info!("client connected"); - tokio::spawn(async move { + tokio::spawn(async move { tracing::info!("outputting data from server"); tokio::io::copy(&mut recv, &mut tokio::io::stdout()).await?; tracing::info!("outputting data from server done"); From a3571fa0027adaaa8dbf6e8dc9654933e9b47cf2 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Mon, 14 Aug 2023 15:36:40 +0200 Subject: [PATCH 10/34] multithreaded tests --- src/transport/interprocess.rs | 1 + tests/interprocess.rs | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 7764dc3..23dd404 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -276,6 +276,7 @@ impl<'a> Iterator for FrameIter<'a> { /// /// The connection is assumed to be from `local` to `remote`. If you try to /// connect to any other address, packets will be dropped. +#[allow(clippy::type_complexity)] pub fn tokio_io_endpoint( mut r: R, mut w: W, diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 0937e8b..b3b6cc1 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -127,7 +127,7 @@ async fn quinn_flume_socket_raw() -> anyhow::Result<()> { anyhow::Ok(()) }); let client = tokio::spawn(async move { - let conn = client.connect(server_addr, "localhost".into())?.await?; + let conn = client.connect(server_addr, "localhost")?.await?; let (mut send, mut recv) = conn.open_bi().await?; tracing::info!("client connected"); tokio::spawn(async move { @@ -147,8 +147,7 @@ async fn quinn_flume_socket_raw() -> anyhow::Result<()> { Ok(()) } -// #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -#[tokio::test] +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn quinn_flume_channel_bench() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); let Endpoints { @@ -168,7 +167,7 @@ async fn quinn_flume_channel_bench() -> anyhow::Result<()> { Ok(()) } -#[tokio::test] +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn quinn_flume_channel_smoke() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); let Endpoints { From 23a451d35994e5b301e253491c9bf57ad4369ff6 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 15 Aug 2023 10:19:01 +0200 Subject: [PATCH 11/34] remove interprocess from default features --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e4edc13..c55629f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ flume-transport = ["flume"] interprocess-transport = ["quinn-udp", "interprocess", "bytes", "tokio-util"] combined-transport = [] macros = [] -default = ["quinn-transport", "interprocess-transport"] +default = [] [[example]] name = "errors" From 748aa9a5103d817f32f49f929fe312c65004124d Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 15 Aug 2023 13:55:12 +0200 Subject: [PATCH 12/34] split packet using segment_size on send --- Cargo.lock | 91 +++++++++++++++++++++++++++++++++++ Cargo.toml | 3 +- src/transport/interprocess.rs | 56 +++++++++++++-------- 3 files changed, 129 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 309bfe5..0f913ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,18 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f768393e7fabd388fe8409b13faa4d93ab0fef35db1508438dfdb066918bcf38" +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "async-channel" version = "1.9.0" @@ -131,6 +143,29 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "blake3" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.3.1" @@ -197,6 +232,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "convert_case" version = "0.4.0" @@ -228,6 +269,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "deranged" version = "0.3.7" @@ -247,6 +298,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "educe" version = "0.4.22" @@ -437,6 +499,16 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -850,6 +922,7 @@ dependencies = [ "anyhow", "async-stream", "bincode", + "blake3", "bytes", "derive_more", "educe", @@ -1241,6 +1314,12 @@ dependencies = [ "lock_api", ] +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1481,6 +1560,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + [[package]] name = "types" version = "0.1.0" @@ -1509,6 +1594,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "waker-fn" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index c55629f..4008d47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ tracing = "0.1" quinn-udp = { version = "0.4.0", optional = true } interprocess = { version = "1.2.1", features = ["tokio_support"], optional = true } hex = "0.4.3" +blake3 = "1.4.1" [dependencies.educe] # This is an unused dependency, it is needed to make the minimal @@ -57,7 +58,7 @@ flume-transport = ["flume"] interprocess-transport = ["quinn-udp", "interprocess", "bytes", "tokio-util"] combined-transport = [] macros = [] -default = [] +default = ["interprocess-transport"] [[example]] name = "errors" diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 23dd404..2ca850d 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -116,28 +116,45 @@ impl FlumeSocketInner { let mut offset = 0; let mut pending = false; for transmit in transmits { - let item = Packet { - from: self.local, - to: transmit.destination, - data: transmit.contents.clone(), + let items = if let Some(segment_size) = transmit.segment_size { + (0..transmit.contents.len()) + .step_by(segment_size) + .map(|min| { + let max = (min + segment_size).min(transmit.contents.len()); + let data = transmit.contents.slice(min..max); + Packet { + from: self.local, + to: transmit.destination, + data, + } + }) + .collect::>() + } else { + vec![Packet { + from: self.local, + to: transmit.destination, + data: transmit.contents.clone(), + }] }; - let res = self.sender.poll_ready_unpin(cx); - match res { - task::Poll::Ready(Ok(())) => { - // ready to send - if self.sender.start_send_unpin(item).is_err() { - // disconnected + for item in items { + let res = self.sender.poll_ready_unpin(cx); + match res { + task::Poll::Ready(Ok(())) => { + // ready to send + if self.sender.start_send_unpin(item).is_err() { + // disconnected + break; + } + } + task::Poll::Ready(Err(_)) => { + // disconneced + break; + } + task::Poll::Pending => { + // remember the offset of the first pending transmit + pending = true; break; } - } - task::Poll::Ready(Err(_)) => { - // disconneced - break; - } - task::Poll::Pending => { - // remember the offset of the first pending transmit - pending = true; - break; } } offset += 1; @@ -322,7 +339,6 @@ where // eof break; } - tracing::debug!("R {} read {} bytes {}", local, n, buffer.len()); // split into frames and send all full frames for item in FrameIter(&mut buffer) { let packet = Packet { From e4105226d9380dac6e23fc60e6a6454d37bca9f9 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 15 Aug 2023 14:10:02 +0200 Subject: [PATCH 13/34] add segment_size to packet --- src/transport/interprocess.rs | 60 ++++++++++++++--------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 2ca850d..67a4df9 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -37,6 +37,7 @@ struct Packet { from: SocketAddr, to: SocketAddr, data: Bytes, + segment_size: Option, } #[derive(Debug)] @@ -116,46 +117,30 @@ impl FlumeSocketInner { let mut offset = 0; let mut pending = false; for transmit in transmits { - let items = if let Some(segment_size) = transmit.segment_size { - (0..transmit.contents.len()) - .step_by(segment_size) - .map(|min| { - let max = (min + segment_size).min(transmit.contents.len()); - let data = transmit.contents.slice(min..max); - Packet { - from: self.local, - to: transmit.destination, - data, - } - }) - .collect::>() - } else { - vec![Packet { - from: self.local, - to: transmit.destination, - data: transmit.contents.clone(), - }] + let item = Packet { + from: self.local, + to: transmit.destination, + data: transmit.contents.clone(), + segment_size: transmit.segment_size, }; - for item in items { - let res = self.sender.poll_ready_unpin(cx); - match res { - task::Poll::Ready(Ok(())) => { - // ready to send - if self.sender.start_send_unpin(item).is_err() { - // disconnected - break; - } - } - task::Poll::Ready(Err(_)) => { - // disconneced - break; - } - task::Poll::Pending => { - // remember the offset of the first pending transmit - pending = true; + let res = self.sender.poll_ready_unpin(cx); + match res { + task::Poll::Ready(Ok(())) => { + // ready to send + if self.sender.start_send_unpin(item).is_err() { + // disconnected break; } } + task::Poll::Ready(Err(_)) => { + // disconneced + break; + } + task::Poll::Pending => { + // remember the offset of the first pending transmit + pending = true; + break; + } } offset += 1; } @@ -208,7 +193,7 @@ impl FlumeSocketInner { let m = quinn_udp::RecvMeta { addr: packet.from, len, - stride: len, + stride: packet.segment_size.unwrap_or(len), ecn: None, dst_ip: Some(self.local.ip()), }; @@ -345,6 +330,7 @@ where from: remote, to: local, data: item, + segment_size: None, }; if in_send.send_async(packet).await.is_err() { // in_recv dropped From 520a122363dafa0538f0872537b2cc9467472ea7 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 15 Aug 2023 14:15:42 +0200 Subject: [PATCH 14/34] split packet when converting into stream --- src/transport/interprocess.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 67a4df9..5007d2c 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -302,9 +302,18 @@ where while let Some(packets) = out_recv.next().await { for packet in packets { if packet.to == remote { - let len: u16 = packet.data.len().try_into().unwrap(); - w.write_all(&len.to_le_bytes()).await?; - w.write_all(&packet.data).await?; + if let Some(segment_size) = packet.segment_size { + for min in (0..packet.data.len()).step_by(segment_size) { + let max = (min + segment_size).min(packet.data.len()); + let len: u16 = (max - min).try_into().unwrap(); + w.write_all(&len.to_le_bytes()).await?; + w.write_all(&packet.data[min..max]).await?; + } + } else { + let len: u16 = packet.data.len().try_into().unwrap(); + w.write_all(&len.to_le_bytes()).await?; + w.write_all(&packet.data).await?; + } } else { // not for us, ignore continue; From 7b95bd414723e6c5b354e963e308ea6737656997 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 15 Aug 2023 15:43:18 +0200 Subject: [PATCH 15/34] move the quinn flume socket into a separate optional module --- .github/workflows/ci.yml | 4 + Cargo.toml | 3 +- src/transport/interprocess.rs | 271 ++-------------------------- src/transport/mod.rs | 2 + src/transport/quinn_flume_socket.rs | 238 ++++++++++++++++++++++++ tests/interprocess.rs | 9 +- 6 files changed, 264 insertions(+), 263 deletions(-) create mode 100644 src/transport/quinn_flume_socket.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c26bfb5..ac0578d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,10 @@ env: RUST_BACKTRACE: 1 RUSTFLAGS: -Dwarnings +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: lint: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 909be69..a11be44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,8 +58,9 @@ quinn-transport = ["flume", "quinn", "bincode", "tokio-serde", "tokio-util"] flume-transport = ["flume"] interprocess-transport = ["quinn-udp", "interprocess", "bytes", "tokio-util"] combined-transport = [] +quinn-flume-socket = ["flume", "quinn", "quinn-udp", "bytes", "tokio-util"] macros = [] -default = ["interprocess-transport"] +default = [] [[example]] name = "errors" diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 5007d2c..9ffa723 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -1,261 +1,17 @@ //! Custom quinn transport that uses the interprocess crate to provide //! local interprocess communication via either Unix domain sockets or //! Windows named pipes. -use std::{ - fmt::{self, Debug}, - io, - net::SocketAddr, - sync::{Arc, Mutex}, - task, -}; +use std::{io, net::SocketAddr}; +use super::quinn_flume_socket::{make_endpoint, FlumeSocket, Packet}; use bytes::{Buf, Bytes, BytesMut}; -use futures::{SinkExt, StreamExt}; -use quinn::{AsyncUdpSocket, Endpoint, EndpointConfig}; -use quinn_udp::RecvMeta; +use futures::StreamExt; +use quinn::{Endpoint, EndpointConfig}; use tokio::{ io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, task::JoinHandle, }; -struct FlumeSocketInner { - local: SocketAddr, - receiver: flume::r#async::RecvStream<'static, Packet>, - sender: flume::r#async::SendSink<'static, Packet>, -} - -impl fmt::Debug for FlumeSocketInner { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("StreamSocketInner") - .field("local", &self.local) - .finish_non_exhaustive() - } -} - -/// A packet for the flume socket. -struct Packet { - from: SocketAddr, - to: SocketAddr, - data: Bytes, - segment_size: Option, -} - -#[derive(Debug)] -pub(crate) struct FlumeSocket(Arc>); - -#[derive(Debug)] -pub(crate) struct LocalAddrHandle(Arc>); - -impl LocalAddrHandle { - #[allow(dead_code)] - pub fn set(&self, addr: SocketAddr) { - self.0.lock().unwrap().local = addr; - } - - #[allow(dead_code)] - pub fn get(&self) -> SocketAddr { - self.0.lock().unwrap().local - } -} - -impl AsyncUdpSocket for FlumeSocket { - fn poll_send( - &self, - state: &quinn_udp::UdpState, - cx: &mut task::Context, - transmits: &[quinn_udp::Transmit], - ) -> task::Poll> { - self.0.lock().unwrap().poll_send(state, cx, transmits) - } - - fn poll_recv( - &self, - cx: &mut task::Context, - bufs: &mut [io::IoSliceMut<'_>], - meta: &mut [RecvMeta], - ) -> task::Poll> { - self.0.lock().unwrap().poll_recv(cx, bufs, meta) - } - - fn local_addr(&self) -> io::Result { - self.0.lock().unwrap().local_addr() - } -} - -impl FlumeSocketInner { - /// Create a pair of connected sockets. - fn pair(local: SocketAddr, remote: SocketAddr) -> (Self, Self) { - let (tx1, rx1) = flume::bounded(16); - let (tx2, rx2) = flume::bounded(16); - - let a = Self { - receiver: rx1.into_stream(), - sender: tx2.into_sink(), - local, - }; - - let b = Self { - receiver: rx2.into_stream(), - sender: tx1.into_sink(), - local: remote, - }; - - (a, b) - } -} - -impl FlumeSocketInner { - fn poll_send( - &mut self, - _state: &quinn_udp::UdpState, - cx: &mut task::Context, - transmits: &[quinn_udp::Transmit], - ) -> task::Poll> { - if transmits.is_empty() { - return task::Poll::Ready(Ok(0)); - } - let mut offset = 0; - let mut pending = false; - for transmit in transmits { - let item = Packet { - from: self.local, - to: transmit.destination, - data: transmit.contents.clone(), - segment_size: transmit.segment_size, - }; - let res = self.sender.poll_ready_unpin(cx); - match res { - task::Poll::Ready(Ok(())) => { - // ready to send - if self.sender.start_send_unpin(item).is_err() { - // disconnected - break; - } - } - task::Poll::Ready(Err(_)) => { - // disconneced - break; - } - task::Poll::Pending => { - // remember the offset of the first pending transmit - pending = true; - break; - } - } - offset += 1; - } - if offset > 0 { - // call poll_flush_unpin only once. - if let task::Poll::Ready(Err(_)) = self.sender.poll_flush_unpin(cx) { - // disconnected - return task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "all receivers dropped", - ))); - } - // report how many transmits we sent - task::Poll::Ready(Ok(offset)) - } else if pending { - // only return pending if we got a pending for the first slot - task::Poll::Pending - } else { - task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "all receivers dropped", - ))) - } - } - - fn poll_recv( - &mut self, - cx: &mut std::task::Context, - bufs: &mut [io::IoSliceMut<'_>], - meta: &mut [quinn_udp::RecvMeta], - ) -> task::Poll> { - let n = bufs.len().min(meta.len()); - if n == 0 { - return task::Poll::Ready(Ok(0)); - } - let mut offset = 0; - let mut pending = false; - // try to fill as many slots as possible - while offset < n { - let packet = match self.receiver.poll_next_unpin(cx) { - task::Poll::Ready(Some(recv)) => recv, - task::Poll::Ready(None) => break, - task::Poll::Pending => { - pending = true; - break; - } - }; - if packet.to == self.local { - let len = packet.data.len(); - let m = quinn_udp::RecvMeta { - addr: packet.from, - len, - stride: packet.segment_size.unwrap_or(len), - ecn: None, - dst_ip: Some(self.local.ip()), - }; - bufs[offset][..len].copy_from_slice(&packet.data); - meta[offset] = m; - offset += 1; - } else { - // not for us, ignore - continue; - } - } - if offset > 0 { - // report how many slots we filled - task::Poll::Ready(Ok(offset)) - } else if pending { - // only return pending if we got a pending for the first slot - task::Poll::Pending - } else { - task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::UnexpectedEof, - "all senders dropped", - ))) - } - } - - fn local_addr(&self) -> std::io::Result { - Ok(self.local) - } -} - -fn make_endpoint( - socket: FlumeSocket, - config: EndpointConfig, - server_config: Option, -) -> io::Result { - quinn::Endpoint::new_with_abstract_socket( - config, - server_config, - socket, - Arc::new(quinn::TokioRuntime), - ) -} - -/// Create a pair of directly connected endpoints. -/// -/// Useful for testing. -pub fn endpoint_pair( - s: SocketAddr, - c: SocketAddr, - sc: quinn::ServerConfig, -) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { - let (socket_a, socket_b) = FlumeSocketInner::pair(s, c); - let socket_a = FlumeSocket(Arc::new(Mutex::new(socket_a))); - let socket_b = FlumeSocket(Arc::new(Mutex::new(socket_b))); - let ac = EndpointConfig::default(); - let bc = EndpointConfig::default(); - Ok(( - make_endpoint(socket_a, ac, Some(sc))?, - make_endpoint(socket_b, bc, None)?, - )) -} - struct FrameIter<'a>(&'a mut BytesMut); impl<'a> Iterator for FrameIter<'a> { @@ -302,17 +58,18 @@ where while let Some(packets) = out_recv.next().await { for packet in packets { if packet.to == remote { + let contents = packet.contents.as_ref(); if let Some(segment_size) = packet.segment_size { - for min in (0..packet.data.len()).step_by(segment_size) { - let max = (min + segment_size).min(packet.data.len()); + for min in (0..contents.len()).step_by(segment_size) { + let max = (min + segment_size).min(contents.len()); let len: u16 = (max - min).try_into().unwrap(); w.write_all(&len.to_le_bytes()).await?; - w.write_all(&packet.data[min..max]).await?; + w.write_all(&contents[min..max]).await?; } } else { - let len: u16 = packet.data.len().try_into().unwrap(); + let len: u16 = contents.len().try_into().unwrap(); w.write_all(&len.to_le_bytes()).await?; - w.write_all(&packet.data).await?; + w.write_all(contents).await?; } } else { // not for us, ignore @@ -338,7 +95,7 @@ where let packet = Packet { from: remote, to: local, - data: item, + contents: item, segment_size: None, }; if in_send.send_async(packet).await.is_err() { @@ -349,11 +106,7 @@ where } Ok(()) }); - let socket = FlumeSocket(Arc::new(Mutex::new(FlumeSocketInner { - receiver: in_recv.into_stream(), - sender: out_send.into_sink(), - local, - }))); + let socket = FlumeSocket::new(local, out_send, in_recv); let config = EndpointConfig::default(); let endpoint = make_endpoint(socket, config, server_config)?; Ok((endpoint, sender, receiver)) diff --git a/src/transport/mod.rs b/src/transport/mod.rs index c282ecd..3332c8c 100644 --- a/src/transport/mod.rs +++ b/src/transport/mod.rs @@ -15,6 +15,8 @@ pub mod hyper; pub mod interprocess; #[cfg(feature = "quinn-transport")] pub mod quinn; +#[cfg(feature = "quinn-flume-socket")] +pub mod quinn_flume_socket; pub mod misc; diff --git a/src/transport/quinn_flume_socket.rs b/src/transport/quinn_flume_socket.rs new file mode 100644 index 0000000..84af27a --- /dev/null +++ b/src/transport/quinn_flume_socket.rs @@ -0,0 +1,238 @@ +//! Custom quinn transport that uses the interprocess crate to provide +//! local interprocess communication via either Unix domain sockets or +//! Windows named pipes. +use std::{ + fmt::{self, Debug}, + io, + net::SocketAddr, + sync::{Arc, Mutex}, + task, +}; + +use bytes::Bytes; +use futures::{SinkExt, StreamExt}; +use quinn::{AsyncUdpSocket, EndpointConfig}; +use quinn_udp::RecvMeta; + +struct FlumeSocketInner { + local: SocketAddr, + receiver: flume::r#async::RecvStream<'static, Packet>, + sender: flume::r#async::SendSink<'static, Packet>, +} + +impl fmt::Debug for FlumeSocketInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FlumeSocketInner") + .field("local", &self.local) + .finish_non_exhaustive() + } +} + +/// A packet for the flume socket. +#[derive(Debug)] +pub struct Packet { + /// The address the packet was sent from. + pub from: SocketAddr, + /// The address the packet is for. + pub to: SocketAddr, + /// The data in the packet. + pub contents: Bytes, + /// The segment size for the packet. + pub segment_size: Option, +} + +/// An implementation of [quinn::AsyncUdpSocket] that uses flume channels +#[derive(Debug)] +pub struct FlumeSocket(Arc>); + +impl FlumeSocket { + /// Create a new flume socket, with the given local address. + /// + /// Sent packets will have from set to the local address, and received packets + /// with to not set to the local address will be ignored. + pub fn new(local: SocketAddr, tx: flume::Sender, rx: flume::Receiver) -> Self { + let inner = FlumeSocketInner { + receiver: rx.into_stream(), + sender: tx.into_sink(), + local, + }; + Self(Arc::new(Mutex::new(inner))) + } +} + +impl AsyncUdpSocket for FlumeSocket { + fn poll_send( + &self, + state: &quinn_udp::UdpState, + cx: &mut task::Context, + transmits: &[quinn_udp::Transmit], + ) -> task::Poll> { + self.0.lock().unwrap().poll_send(state, cx, transmits) + } + + fn poll_recv( + &self, + cx: &mut task::Context, + bufs: &mut [io::IoSliceMut<'_>], + meta: &mut [RecvMeta], + ) -> task::Poll> { + self.0.lock().unwrap().poll_recv(cx, bufs, meta) + } + + fn local_addr(&self) -> io::Result { + self.0.lock().unwrap().local_addr() + } +} + +impl FlumeSocketInner { + fn poll_send( + &mut self, + _state: &quinn_udp::UdpState, + cx: &mut task::Context, + transmits: &[quinn_udp::Transmit], + ) -> task::Poll> { + if transmits.is_empty() { + return task::Poll::Ready(Ok(0)); + } + let mut offset = 0; + let mut pending = false; + for transmit in transmits { + let item = Packet { + from: self.local, + to: transmit.destination, + contents: transmit.contents.clone(), + segment_size: transmit.segment_size, + }; + let res = self.sender.poll_ready_unpin(cx); + match res { + task::Poll::Ready(Ok(())) => { + // ready to send + if self.sender.start_send_unpin(item).is_err() { + // disconnected + break; + } + } + task::Poll::Ready(Err(_)) => { + // disconneced + break; + } + task::Poll::Pending => { + // remember the offset of the first pending transmit + pending = true; + break; + } + } + offset += 1; + } + if offset > 0 { + // call poll_flush_unpin only once. + if let task::Poll::Ready(Err(_)) = self.sender.poll_flush_unpin(cx) { + // disconnected + return task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "all receivers dropped", + ))); + } + // report how many transmits we sent + task::Poll::Ready(Ok(offset)) + } else if pending { + // only return pending if we got a pending for the first slot + task::Poll::Pending + } else { + task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "all receivers dropped", + ))) + } + } + + fn poll_recv( + &mut self, + cx: &mut std::task::Context, + bufs: &mut [io::IoSliceMut<'_>], + meta: &mut [quinn_udp::RecvMeta], + ) -> task::Poll> { + let n = bufs.len().min(meta.len()); + if n == 0 { + return task::Poll::Ready(Ok(0)); + } + let mut offset = 0; + let mut pending = false; + // try to fill as many slots as possible + while offset < n { + let packet = match self.receiver.poll_next_unpin(cx) { + task::Poll::Ready(Some(recv)) => recv, + task::Poll::Ready(None) => break, + task::Poll::Pending => { + pending = true; + break; + } + }; + if packet.to == self.local { + let len = packet.contents.len(); + let m = quinn_udp::RecvMeta { + addr: packet.from, + len, + stride: packet.segment_size.unwrap_or(len), + ecn: None, + dst_ip: Some(self.local.ip()), + }; + bufs[offset][..len].copy_from_slice(&packet.contents); + meta[offset] = m; + offset += 1; + } else { + // not for us, ignore + continue; + } + } + if offset > 0 { + // report how many slots we filled + task::Poll::Ready(Ok(offset)) + } else if pending { + // only return pending if we got a pending for the first slot + task::Poll::Pending + } else { + task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "all senders dropped", + ))) + } + } + + fn local_addr(&self) -> std::io::Result { + Ok(self.local) + } +} + +pub(crate) fn make_endpoint( + socket: FlumeSocket, + config: EndpointConfig, + server_config: Option, +) -> io::Result { + quinn::Endpoint::new_with_abstract_socket( + config, + server_config, + socket, + Arc::new(quinn::TokioRuntime), + ) +} + +/// Create a pair of directly connected endpoints. +/// +/// Useful for testing. +pub fn endpoint_pair( + server_addr: SocketAddr, + client_addr: SocketAddr, + server_config: quinn::ServerConfig, +) -> io::Result<(quinn::Endpoint, quinn::Endpoint)> { + let (tx1, rx1) = flume::bounded(16); + let (tx2, rx2) = flume::bounded(16); + let server = FlumeSocket::new(server_addr, tx1, rx2); + let client = FlumeSocket::new(client_addr, tx2, rx1); + let ac = EndpointConfig::default(); + let bc = EndpointConfig::default(); + Ok(( + make_endpoint(server, ac, Some(server_config))?, + make_endpoint(client, bc, None)?, + )) +} diff --git a/tests/interprocess.rs b/tests/interprocess.rs index b3b6cc1..0d915fb 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -84,9 +84,12 @@ pub fn make_endpoints() -> anyhow::Result { let client_addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2)); let (server_config, server_cert) = configure_server()?; let client_config = configure_client(&[&server_cert])?; - let (server, mut client) = - quic_rpc::transport::interprocess::endpoint_pair(server_addr, client_addr, server_config) - .unwrap(); + let (server, mut client) = quic_rpc::transport::quinn_flume_socket::endpoint_pair( + server_addr, + client_addr, + server_config, + ) + .unwrap(); client.set_default_client_config(client_config); Ok(Endpoints { client, From 041440563fa294a987d8258bb5d6bd2fd5020a8c Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 15 Aug 2023 17:03:50 +0200 Subject: [PATCH 16/34] WIP --- Cargo.toml | 4 ++-- src/transport/quinn_flume_socket.rs | 1 + tests/math.rs | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a11be44..864793a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,11 +56,11 @@ proc-macro2 = "1.0.66" hyper-transport = ["flume", "hyper", "bincode", "bytes"] quinn-transport = ["flume", "quinn", "bincode", "tokio-serde", "tokio-util"] flume-transport = ["flume"] -interprocess-transport = ["quinn-udp", "interprocess", "bytes", "tokio-util"] +interprocess-transport = ["quinn-udp", "interprocess", "bytes", "tokio-util", "quinn-transport"] combined-transport = [] quinn-flume-socket = ["flume", "quinn", "quinn-udp", "bytes", "tokio-util"] macros = [] -default = [] +default = ["quinn-flume-socket", "interprocess-transport"] [[example]] name = "errors" diff --git a/src/transport/quinn_flume_socket.rs b/src/transport/quinn_flume_socket.rs index 84af27a..213a4c8 100644 --- a/src/transport/quinn_flume_socket.rs +++ b/src/transport/quinn_flume_socket.rs @@ -177,6 +177,7 @@ impl FlumeSocketInner { ecn: None, dst_ip: Some(self.local.ip()), }; + tracing::debug!("bufs {} bytes, {} slots", bufs[offset].len(), n); bufs[offset][..len].copy_from_slice(&packet.contents); meta[offset] = m; offset += 1; diff --git a/tests/math.rs b/tests/math.rs index 8ecac02..13b854b 100644 --- a/tests/math.rs +++ b/tests/math.rs @@ -1,7 +1,8 @@ #![cfg(any( feature = "flume-transport", feature = "hyper-transport", - feature = "quinn-transport" + feature = "quinn-transport", + feature = "interprocess-transport", ))] #![allow(dead_code)] use async_stream::stream; From 68c0ff3169b960eae8f760e2dfd9a04cc15e11e2 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Tue, 15 Aug 2023 17:26:08 +0200 Subject: [PATCH 17/34] WIP --- src/transport/quinn_flume_socket.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/transport/quinn_flume_socket.rs b/src/transport/quinn_flume_socket.rs index 213a4c8..3fcf3a7 100644 --- a/src/transport/quinn_flume_socket.rs +++ b/src/transport/quinn_flume_socket.rs @@ -96,6 +96,7 @@ impl FlumeSocketInner { } let mut offset = 0; let mut pending = false; + tracing::debug!("S {} transmits", transmits.len()); for transmit in transmits { let item = Packet { from: self.local, @@ -103,6 +104,7 @@ impl FlumeSocketInner { contents: transmit.contents.clone(), segment_size: transmit.segment_size, }; + tracing::debug!("S sending {} {:?}", transmit.contents.len(), transmit.segment_size); let res = self.sender.poll_ready_unpin(cx); match res { task::Poll::Ready(Ok(())) => { @@ -177,7 +179,7 @@ impl FlumeSocketInner { ecn: None, dst_ip: Some(self.local.ip()), }; - tracing::debug!("bufs {} bytes, {} slots", bufs[offset].len(), n); + tracing::debug!("R bufs {} bytes, {} slots", bufs[offset].len(), n); bufs[offset][..len].copy_from_slice(&packet.contents); meta[offset] = m; offset += 1; From ec3314c8410a07aa66cf2b1792262902b94caa95 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 13:04:42 +0100 Subject: [PATCH 18/34] fix: make socket name os comaptible --- tests/interprocess.rs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 0d915fb..c23890d 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -1,6 +1,8 @@ #![cfg(feature = "interprocess-transport")] use std::{ + ffi::OsString, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + path::Path, sync::Arc, }; @@ -29,6 +31,25 @@ pub fn make_client_endpoint( Ok(endpoint) } +// TODO: add to quic-rpc lib if this works +/// Automatically chooses name type based on OS support and preference. +fn new_socket_name(root: impl AsRef, id: &str) -> OsString { + let namespaced = { + use interprocess::local_socket::NameTypeSupport; + let nts = NameTypeSupport::query(); + match nts { + NameTypeSupport::OnlyPaths | NameTypeSupport::Both => false, + NameTypeSupport::OnlyNamespaced => true, + } + }; + + if namespaced { + format!("@quic-rpc-socket-{}.sock", id).into() + } else { + root.as_ref().join(format!("{id}.sock")).into() + } +} + /// Constructs a QUIC endpoint configured to listen for incoming connections on a certain address /// and port. /// @@ -193,7 +214,7 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); use interprocess::local_socket::tokio::*; let dir = tempfile::tempdir()?; - let socket_name = dir.path().join("interprocess.socket"); + let socket_name = new_socket_name(dir.path(), "interprocess"); let socket = LocalSocketListener::bind(socket_name.clone())?; let socket_name_2 = socket_name.clone(); let server = tokio::spawn(async move { @@ -235,7 +256,7 @@ async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { let client_config = configure_client(&[&server_certs])?; tracing_subscriber::fmt::try_init().ok(); let dir = tempfile::tempdir()?; - let socket_name = dir.path().join("interprocess.socket"); + let socket_name = new_socket_name(dir.path(), "interprocess"); let socket = LocalSocketListener::bind(socket_name.clone())?; let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); @@ -299,7 +320,7 @@ async fn interprocess_quinn_smoke() -> anyhow::Result<()> { let client_config = configure_client(&[&server_certs])?; tracing_subscriber::fmt::try_init().ok(); let dir = tempfile::tempdir()?; - let socket_name = dir.path().join("interprocess.socket"); + let socket_name = new_socket_name(dir.path(), "interprocess"); let socket = LocalSocketListener::bind(socket_name.clone())?; let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); @@ -344,7 +365,7 @@ async fn interprocess_quinn_bench() -> anyhow::Result<()> { let client_config = configure_client(&[&server_certs])?; tracing_subscriber::fmt::try_init().ok(); let dir = tempfile::tempdir()?; - let socket_name = dir.path().join("interprocess.socket"); + let socket_name = new_socket_name(dir.path(), "interprocess"); let socket = LocalSocketListener::bind(socket_name.clone())?; let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); From a9f9bf60cad6a67a71ec2b83d3136074c3434359 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 13:05:30 +0100 Subject: [PATCH 19/34] cargo fmt --- src/transport/quinn_flume_socket.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/transport/quinn_flume_socket.rs b/src/transport/quinn_flume_socket.rs index 3fcf3a7..4fd4cde 100644 --- a/src/transport/quinn_flume_socket.rs +++ b/src/transport/quinn_flume_socket.rs @@ -104,7 +104,11 @@ impl FlumeSocketInner { contents: transmit.contents.clone(), segment_size: transmit.segment_size, }; - tracing::debug!("S sending {} {:?}", transmit.contents.len(), transmit.segment_size); + tracing::debug!( + "S sending {} {:?}", + transmit.contents.len(), + transmit.segment_size + ); let res = self.sender.poll_ready_unpin(cx); match res { task::Poll::Ready(Ok(())) => { From 0c2bbbbb1e15b08e019fb72b76977c342d16017e Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 13:13:15 +0100 Subject: [PATCH 20/34] happy clippy --- tests/hyper.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/hyper.rs b/tests/hyper.rs index 6b26cd5..94a72c7 100644 --- a/tests/hyper.rs +++ b/tests/hyper.rs @@ -1,4 +1,6 @@ #![cfg(feature = "hyper-transport")] +#![allow(clippy::redundant_pattern_matching)] + use std::{net::SocketAddr, result}; use ::hyper::Uri; From 4f40732e33e812d40b97c3d031c3230096bd9ff9 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 13:15:26 +0100 Subject: [PATCH 21/34] cleanup: move socket name generation into the lib --- src/transport/interprocess.rs | 20 +++++++++++++++++++- tests/interprocess.rs | 26 ++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 9ffa723..8ec49b9 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -1,7 +1,7 @@ //! Custom quinn transport that uses the interprocess crate to provide //! local interprocess communication via either Unix domain sockets or //! Windows named pipes. -use std::{io, net::SocketAddr}; +use std::{ffi::OsString, io, net::SocketAddr, path::Path}; use super::quinn_flume_socket::{make_endpoint, FlumeSocket, Packet}; use bytes::{Buf, Bytes, BytesMut}; @@ -30,6 +30,24 @@ impl<'a> Iterator for FrameIter<'a> { } } +/// Automatically chooses name type based on OS support and preference. +pub fn new_socket_name(root: impl AsRef, id: &str) -> OsString { + let namespaced = { + use interprocess::local_socket::NameTypeSupport; + let nts = NameTypeSupport::query(); + match nts { + NameTypeSupport::OnlyPaths | NameTypeSupport::Both => false, + NameTypeSupport::OnlyNamespaced => true, + } + }; + + if namespaced { + format!("@quic-rpc-socket-{}.sock", id).into() + } else { + root.as_ref().join(format!("{id}.sock")).into() + } +} + /// Wrap a tokio read/write pair as a quinn endpoint. /// /// The connection is assumed to be from `local` to `remote`. If you try to diff --git a/tests/interprocess.rs b/tests/interprocess.rs index c23890d..b6b7892 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -1,12 +1,13 @@ #![cfg(feature = "interprocess-transport")] use std::{ - ffi::OsString, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, - path::Path, sync::Arc, }; -use quic_rpc::{transport::interprocess::tokio_io_endpoint, RpcClient, RpcServer}; +use quic_rpc::{ + transport::interprocess::{new_socket_name, tokio_io_endpoint}, + RpcClient, RpcServer, +}; use quinn::{ClientConfig, Endpoint, ServerConfig}; use tokio::{io::AsyncWriteExt, task::JoinHandle}; use tokio_util::compat::{FuturesAsyncReadCompatExt, FuturesAsyncWriteCompatExt}; @@ -31,25 +32,6 @@ pub fn make_client_endpoint( Ok(endpoint) } -// TODO: add to quic-rpc lib if this works -/// Automatically chooses name type based on OS support and preference. -fn new_socket_name(root: impl AsRef, id: &str) -> OsString { - let namespaced = { - use interprocess::local_socket::NameTypeSupport; - let nts = NameTypeSupport::query(); - match nts { - NameTypeSupport::OnlyPaths | NameTypeSupport::Both => false, - NameTypeSupport::OnlyNamespaced => true, - } - }; - - if namespaced { - format!("@quic-rpc-socket-{}.sock", id).into() - } else { - root.as_ref().join(format!("{id}.sock")).into() - } -} - /// Constructs a QUIC endpoint configured to listen for incoming connections on a certain address /// and port. /// From 60ccb093170503e316b7d88df45fff25aaff954c Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 13:36:34 +0100 Subject: [PATCH 22/34] fix writes --- tests/interprocess.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index b6b7892..aeb4d7d 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -4,12 +4,13 @@ use std::{ sync::Arc, }; +use futures::{io::BufReader, AsyncBufReadExt, AsyncWriteExt as _}; use quic_rpc::{ transport::interprocess::{new_socket_name, tokio_io_endpoint}, RpcClient, RpcServer, }; use quinn::{ClientConfig, Endpoint, ServerConfig}; -use tokio::{io::AsyncWriteExt, task::JoinHandle}; +use tokio::{io::AsyncWriteExt as _, task::JoinHandle}; use tokio_util::compat::{FuturesAsyncReadCompatExt, FuturesAsyncWriteCompatExt}; mod math; @@ -201,10 +202,13 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { let socket_name_2 = socket_name.clone(); let server = tokio::spawn(async move { let stream = socket.accept().await?; - let (r, w) = stream.into_split(); - let mut r = r.compat(); - let mut w = w.compat_write(); - tokio::io::copy(&mut r, &mut w).await?; + let (r, mut w) = stream.into_split(); + + let mut buffer = String::new(); + let mut reader = BufReader::new(r); + reader.read_line(&mut buffer).await?; + w.write_all(buffer.as_bytes()).await?; + anyhow::Ok(()) }); let client = tokio::spawn(async move { @@ -214,6 +218,7 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { let mut w = w.compat_write(); w.write_all(b"hello").await?; w.write_all(b"world").await?; + w.write_all(b"\n").await?; let validator = tokio::spawn(async move { let mut out = Vec::::new(); tokio::io::copy(&mut r, &mut out).await?; @@ -236,7 +241,7 @@ async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { use interprocess::local_socket::tokio::*; let (server_config, server_certs) = configure_server()?; let client_config = configure_client(&[&server_certs])?; - tracing_subscriber::fmt::try_init().ok(); + let dir = tempfile::tempdir()?; let socket_name = new_socket_name(dir.path(), "interprocess"); let socket = LocalSocketListener::bind(socket_name.clone())?; @@ -300,7 +305,7 @@ async fn interprocess_quinn_smoke() -> anyhow::Result<()> { use interprocess::local_socket::tokio::*; let (server_config, server_certs) = configure_server()?; let client_config = configure_client(&[&server_certs])?; - tracing_subscriber::fmt::try_init().ok(); + let dir = tempfile::tempdir()?; let socket_name = new_socket_name(dir.path(), "interprocess"); let socket = LocalSocketListener::bind(socket_name.clone())?; @@ -345,7 +350,7 @@ async fn interprocess_quinn_bench() -> anyhow::Result<()> { use interprocess::local_socket::tokio::*; let (server_config, server_certs) = configure_server()?; let client_config = configure_client(&[&server_certs])?; - tracing_subscriber::fmt::try_init().ok(); + let dir = tempfile::tempdir()?; let socket_name = new_socket_name(dir.path(), "interprocess"); let socket = LocalSocketListener::bind(socket_name.clone())?; From 26579fa4b5b403b98e9d258fd1c272d2962c82ed Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 13:44:37 +0100 Subject: [PATCH 23/34] debugging --- src/transport/interprocess.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 8ec49b9..2047ac1 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -86,6 +86,7 @@ where } } else { let len: u16 = contents.len().try_into().unwrap(); + tracing::debug!("sending {}bytes", len); w.write_all(&len.to_le_bytes()).await?; w.write_all(contents).await?; } @@ -102,8 +103,8 @@ where loop { // read more data and split into frames let n = r.read_buf(&mut buffer).await; - let n = n?; + tracing::debug!("read {}bytes", n); if n == 0 { // eof break; From 293817a425a12cf4482db41125b4ff15c9567cf5 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 14:16:15 +0100 Subject: [PATCH 24/34] avoid copy --- tests/interprocess.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index aeb4d7d..7d230d5 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -201,28 +201,34 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { let socket = LocalSocketListener::bind(socket_name.clone())?; let socket_name_2 = socket_name.clone(); let server = tokio::spawn(async move { + tracing::info!("spawning server"); let stream = socket.accept().await?; + tracing::info!("server: accepted"); let (r, mut w) = stream.into_split(); let mut buffer = String::new(); let mut reader = BufReader::new(r); reader.read_line(&mut buffer).await?; + tracing::info!("server: read: {:?}", buffer); w.write_all(buffer.as_bytes()).await?; anyhow::Ok(()) }); let client = tokio::spawn(async move { + tracing::info!("client: spawned"); let stream = LocalSocketStream::connect(socket_name_2.clone()).await?; let (r, w) = stream.into_split(); - let mut r = r.compat(); let mut w = w.compat_write(); w.write_all(b"hello").await?; w.write_all(b"world").await?; w.write_all(b"\n").await?; + tracing::info!("client: written"); let validator = tokio::spawn(async move { - let mut out = Vec::::new(); - tokio::io::copy(&mut r, &mut out).await?; - let pass = out == b"helloworld"; + let mut buffer = String::new(); + let mut reader = BufReader::new(r); + reader.read_line(&mut buffer).await?; + let pass = buffer == "helloworld\n"; + anyhow::Ok(pass) }); drop(w); From 76b15fb4b7c16b2fbf8771e713e1d7fb2a7b15cf Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 14:17:14 +0100 Subject: [PATCH 25/34] multithread --- tests/interprocess.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 7d230d5..98b4ca4 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -192,7 +192,7 @@ async fn quinn_flume_channel_smoke() -> anyhow::Result<()> { /// Basic test of the interprocess crate. /// Just sends a message from client to server and back. -#[tokio::test] +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); use interprocess::local_socket::tokio::*; From ebaa95b4bf52e54bda4b9ba3120a4cb239e1a5e4 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 14:18:28 +0100 Subject: [PATCH 26/34] more logs --- tests/interprocess.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 98b4ca4..e5c4614 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -201,13 +201,15 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { let socket = LocalSocketListener::bind(socket_name.clone())?; let socket_name_2 = socket_name.clone(); let server = tokio::spawn(async move { - tracing::info!("spawning server"); + tracing::info!("server: spawn"); let stream = socket.accept().await?; tracing::info!("server: accepted"); let (r, mut w) = stream.into_split(); let mut buffer = String::new(); let mut reader = BufReader::new(r); + + tracing::info!("server: reading"); reader.read_line(&mut buffer).await?; tracing::info!("server: read: {:?}", buffer); w.write_all(buffer.as_bytes()).await?; @@ -217,13 +219,16 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { let client = tokio::spawn(async move { tracing::info!("client: spawned"); let stream = LocalSocketStream::connect(socket_name_2.clone()).await?; + tracing::info!("client: connected"); let (r, w) = stream.into_split(); let mut w = w.compat_write(); + tracing::info!("client: writting"); w.write_all(b"hello").await?; w.write_all(b"world").await?; w.write_all(b"\n").await?; tracing::info!("client: written"); let validator = tokio::spawn(async move { + tracing::info!("client: reading response"); let mut buffer = String::new(); let mut reader = BufReader::new(r); reader.read_line(&mut buffer).await?; From e728efd2f146e4d4b6a5cd711baf539526933224 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 14:20:43 +0100 Subject: [PATCH 27/34] avoid compat --- tests/interprocess.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index e5c4614..55e2f66 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -10,7 +10,7 @@ use quic_rpc::{ RpcClient, RpcServer, }; use quinn::{ClientConfig, Endpoint, ServerConfig}; -use tokio::{io::AsyncWriteExt as _, task::JoinHandle}; +use tokio::task::JoinHandle; use tokio_util::compat::{FuturesAsyncReadCompatExt, FuturesAsyncWriteCompatExt}; mod math; @@ -220,8 +220,8 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { tracing::info!("client: spawned"); let stream = LocalSocketStream::connect(socket_name_2.clone()).await?; tracing::info!("client: connected"); - let (r, w) = stream.into_split(); - let mut w = w.compat_write(); + let (r, mut w) = stream.into_split(); + tracing::info!("client: writting"); w.write_all(b"hello").await?; w.write_all(b"world").await?; From be495d9d059547986139e649a2eb8845284ddad9 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 14:25:27 +0100 Subject: [PATCH 28/34] use futures split --- tests/interprocess.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 55e2f66..a75b05d 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -4,7 +4,7 @@ use std::{ sync::Arc, }; -use futures::{io::BufReader, AsyncBufReadExt, AsyncWriteExt as _}; +use futures::{io::BufReader, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt as _}; use quic_rpc::{ transport::interprocess::{new_socket_name, tokio_io_endpoint}, RpcClient, RpcServer, @@ -204,7 +204,7 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { tracing::info!("server: spawn"); let stream = socket.accept().await?; tracing::info!("server: accepted"); - let (r, mut w) = stream.into_split(); + let (r, mut w) = stream.split(); let mut buffer = String::new(); let mut reader = BufReader::new(r); @@ -220,7 +220,7 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { tracing::info!("client: spawned"); let stream = LocalSocketStream::connect(socket_name_2.clone()).await?; tracing::info!("client: connected"); - let (r, mut w) = stream.into_split(); + let (r, mut w) = stream.split(); tracing::info!("client: writting"); w.write_all(b"hello").await?; From f8df4ae207426f1c031889810e1116d345627c6f Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 14:32:13 +0100 Subject: [PATCH 29/34] update interprocess --- Cargo.lock | 619 +++++++++++++++--------------------------- Cargo.toml | 2 +- tests/interprocess.rs | 14 +- 3 files changed, 229 insertions(+), 406 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2173bf..2cb1fb5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "anyhow" -version = "1.0.73" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f768393e7fabd388fe8409b13faa4d93ab0fef35db1508438dfdb066918bcf38" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arrayref" @@ -35,26 +35,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener", -] - [[package]] name = "async-stream" version = "0.3.5" @@ -74,21 +54,9 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] -[[package]] -name = "async-task" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" - -[[package]] -name = "atomic-waker" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" - [[package]] name = "autocfg" version = "1.1.0" @@ -97,9 +65,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -118,9 +86,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bincode" @@ -139,65 +107,40 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "blake3" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" -dependencies = [ - "async-channel", - "async-lock", - "async-task", - "atomic-waker", - "fastrand 1.9.0", - "futures-lite", - "log", ] [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -223,15 +166,6 @@ dependencies = [ "types", ] -[[package]] -name = "concurrent-queue" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "constant_time_eq" version = "0.3.0" @@ -261,30 +195,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" +name = "deranged" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" dependencies = [ - "generic-array", - "typenum", + "powerfmt", ] -[[package]] -name = "deranged" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" - [[package]] name = "derive_more" version = "0.99.17" @@ -298,22 +216,11 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - [[package]] name = "educe" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "079044df30bb07de7d846d41a184c4b00e66ebdac93ee459253474f3a47e50ae" +checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" dependencies = [ "enum-ordinalize", "proc-macro2", @@ -323,58 +230,32 @@ dependencies = [ [[package]] name = "enum-ordinalize" -version = "3.1.13" +version = "3.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4f76552f53cefc9a7f64987c3701b99d982f7690606fd67de1d09712fbf52f1" +checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" dependencies = [ "num-bigint", "num-traits", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] name = "errno" -version = "0.3.2" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" +checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" dependencies = [ - "errno-dragonfly", "libc", "windows-sys", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "flume" @@ -397,9 +278,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -412,9 +293,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -422,15 +303,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -439,53 +320,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -499,21 +365,11 @@ dependencies = [ "slab", ] -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "js-sys", @@ -524,15 +380,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" dependencies = [ "bytes", "fnv", @@ -555,9 +411,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -616,7 +472,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -633,42 +489,22 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "interprocess" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f2533f3be42fffe3b5e63b71aeca416c1c3bc33e4e27be018521e76b1f38fb" +version = "2.0.0" +source = "git+https://github.com/kotauskas/interprocess?branch=main#77f471f7c7dc307300b3e3024a66de5835ba29a6" dependencies = [ - "blocking", "cfg-if", "futures-core", "futures-io", - "intmap", + "futures-util", "libc", - "once_cell", "rustc_version", - "spinning", - "thiserror", "to_method", "tokio", "winapi", ] -[[package]] -name = "intmap" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae52f28f45ac2bc96edb7714de995cffc174a395fb0abf5bff453587c980d7b9" - [[package]] name = "itoa" version = "1.0.9" @@ -677,9 +513,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -692,21 +528,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" -version = "0.4.5" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -720,9 +556,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "miniz_oxide" @@ -735,9 +571,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "wasi", @@ -765,9 +601,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -786,9 +622,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -805,9 +641,9 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] @@ -830,12 +666,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "parking" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" - [[package]] name = "parking_lot" version = "0.12.1" @@ -848,9 +678,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", @@ -885,14 +715,14 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -900,6 +730,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -908,9 +744,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -966,13 +802,13 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c8bb234e70c863204303507d841e7fa2295e95c822b2bb4ca8ebf57f17b1cb" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", "rand", - "ring", + "ring 0.16.20", "rustc-hash", "rustls", "rustls-native-certs", @@ -984,22 +820,22 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df19e284d93757a9fb91d63672f7741b129246a669db09d1c0063071debc0c0" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ "bytes", "libc", - "socket2 0.5.3", + "socket2 0.5.5", "tracing", "windows-sys", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1041,16 +877,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time", "yasna", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] @@ -1065,11 +901,25 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1093,11 +943,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.8" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", @@ -1106,12 +956,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.6" +version = "0.21.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", - "ring", + "ring 0.17.5", "rustls-webpki", "sct", ] @@ -1134,17 +984,17 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.3" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -1164,12 +1014,12 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.5", + "untrusted 0.9.0", ] [[package]] @@ -1197,28 +1047,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.183" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.183" +version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -1240,9 +1090,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -1258,24 +1108,24 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -1283,9 +1133,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys", @@ -1306,21 +1156,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spinning" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d4f0e86297cad2658d92a707320d87bf4e6ae1050287f51d19b67ef3f153a7b" -dependencies = [ - "lock_api", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - [[package]] name = "syn" version = "1.0.109" @@ -1334,9 +1169,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -1345,12 +1180,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.7.1" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", - "fastrand 2.0.0", + "fastrand", "redox_syscall", "rustix", "windows-sys", @@ -1358,22 +1193,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.45" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dedd246497092a89beedfe2c9f176d44c1b672ea6090edc20544ade01fbb7ea0" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.45" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d7b1fadccbbc7e19ea64708629f9d8dccd007c260d66485f20a6d41bc1cf4b3" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -1394,20 +1229,21 @@ dependencies = [ [[package]] name = "time" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", + "powerfmt", "serde", "time-core", ] [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "tinyvec" @@ -1432,9 +1268,9 @@ checksum = "c7c4ceeeca15c8384bbc3e011dbd8fccb7f068a440b752b7d9b32ceb0ca0e2e8" [[package]] name = "tokio" -version = "1.31.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ "backtrace", "bytes", @@ -1444,7 +1280,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.3", + "socket2 0.5.5", "tokio-macros", "windows-sys", ] @@ -1457,7 +1293,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] @@ -1477,9 +1313,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1498,11 +1334,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -1511,20 +1346,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -1532,12 +1367,12 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -1561,12 +1396,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - [[package]] name = "types" version = "0.1.0" @@ -1579,9 +1408,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "untrusted" @@ -1590,22 +1419,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "waker-fn" -version = "1.1.0" +name = "valuable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "want" @@ -1624,9 +1447,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1634,24 +1457,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1659,28 +1482,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -1719,9 +1542,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1734,45 +1557,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "yasna" diff --git a/Cargo.toml b/Cargo.toml index 864793a..0f09f6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ tokio-serde = { version = "0.8", features = ["bincode"], optional = true } tokio-util = { version = "0.7", features = ["codec", "compat"], optional = true } tracing = "0.1" quinn-udp = { version = "0.4.0", optional = true } -interprocess = { version = "1.2.1", features = ["tokio_support"], optional = true } +interprocess = { git = "https://github.com/kotauskas/interprocess", branch = "main", version = "2", features = ["tokio"], optional = true } hex = "0.4.3" blake3 = "1.4.1" diff --git a/tests/interprocess.rs b/tests/interprocess.rs index a75b05d..3b09bfc 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -4,7 +4,7 @@ use std::{ sync::Arc, }; -use futures::{io::BufReader, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt as _}; +use futures::{io::BufReader, AsyncBufReadExt, AsyncWriteExt as _}; use quic_rpc::{ transport::interprocess::{new_socket_name, tokio_io_endpoint}, RpcClient, RpcServer, @@ -260,7 +260,7 @@ async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); let server = tokio::spawn(async move { let stream = socket.accept().await?; - let (r, w) = stream.into_split(); + let (r, w) = stream.split(); let r = r.compat(); let w = w.compat_write(); let (endpoint, _s, _r) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; @@ -277,7 +277,7 @@ async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { }); let client = tokio::spawn(async move { let stream = LocalSocketStream::connect(socket_name).await?; - let (r, w) = stream.into_split(); + let (r, w) = stream.split(); let r = r.compat(); let w = w.compat_write(); let (mut endpoint, _s, _r) = tokio_io_endpoint(r, w, local, remote, None)?; @@ -324,7 +324,7 @@ async fn interprocess_quinn_smoke() -> anyhow::Result<()> { let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); let server = tokio::spawn(async move { let stream = socket.accept().await?; - let (r, w) = stream.into_split(); + let (r, w) = stream.split(); let r = r.compat(); let w = w.compat_write(); let (endpoint, _s, _r) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; @@ -335,7 +335,7 @@ async fn interprocess_quinn_smoke() -> anyhow::Result<()> { }); let client = tokio::spawn(async move { let stream = LocalSocketStream::connect(socket_name).await?; - let (r, w) = stream.into_split(); + let (r, w) = stream.split(); let r = r.compat(); let w = w.compat_write(); let (mut endpoint, _s, _r) = tokio_io_endpoint(r, w, local, remote, None)?; @@ -369,7 +369,7 @@ async fn interprocess_quinn_bench() -> anyhow::Result<()> { let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); let server = tokio::spawn(async move { let stream = socket.accept().await?; - let (r, w) = stream.into_split(); + let (r, w) = stream.split(); let r = r.compat(); let w = w.compat_write(); let (endpoint, _s, _r) = tokio_io_endpoint(r, w, remote, local, Some(server_config))?; @@ -380,7 +380,7 @@ async fn interprocess_quinn_bench() -> anyhow::Result<()> { }); let client = tokio::spawn(async move { let stream = LocalSocketStream::connect(socket_name).await?; - let (r, w) = stream.into_split(); + let (r, w) = stream.split(); let r = r.compat(); let w = w.compat_write(); let (mut endpoint, _s, _r) = tokio_io_endpoint(r, w, local, remote, None)?; From 85ba8887e5e77ba48cb9891845ecc6f221b8be44 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Wed, 8 Nov 2023 14:38:50 +0100 Subject: [PATCH 30/34] unique names --- tests/interprocess.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/interprocess.rs b/tests/interprocess.rs index 3b09bfc..23deeb1 100644 --- a/tests/interprocess.rs +++ b/tests/interprocess.rs @@ -197,7 +197,7 @@ async fn interprocess_accept_connect_raw() -> anyhow::Result<()> { tracing_subscriber::fmt::try_init().ok(); use interprocess::local_socket::tokio::*; let dir = tempfile::tempdir()?; - let socket_name = new_socket_name(dir.path(), "interprocess"); + let socket_name = new_socket_name(dir.path(), "interprocess-accept-connect-raw"); let socket = LocalSocketListener::bind(socket_name.clone())?; let socket_name_2 = socket_name.clone(); let server = tokio::spawn(async move { @@ -254,7 +254,7 @@ async fn interprocess_quinn_accept_connect_raw() -> anyhow::Result<()> { let client_config = configure_client(&[&server_certs])?; let dir = tempfile::tempdir()?; - let socket_name = new_socket_name(dir.path(), "interprocess"); + let socket_name = new_socket_name(dir.path(), "interprocess-quinn-accet-connect-raw"); let socket = LocalSocketListener::bind(socket_name.clone())?; let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); @@ -318,7 +318,7 @@ async fn interprocess_quinn_smoke() -> anyhow::Result<()> { let client_config = configure_client(&[&server_certs])?; let dir = tempfile::tempdir()?; - let socket_name = new_socket_name(dir.path(), "interprocess"); + let socket_name = new_socket_name(dir.path(), "interprocess-quinn-smoke"); let socket = LocalSocketListener::bind(socket_name.clone())?; let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); @@ -363,7 +363,7 @@ async fn interprocess_quinn_bench() -> anyhow::Result<()> { let client_config = configure_client(&[&server_certs])?; let dir = tempfile::tempdir()?; - let socket_name = new_socket_name(dir.path(), "interprocess"); + let socket_name = new_socket_name(dir.path(), "interprocess-quinn-bench"); let socket = LocalSocketListener::bind(socket_name.clone())?; let local = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 1).into(); let remote = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 2).into(); From 06047f5318388a67740d3f9476103bd8d5cd03c0 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Tue, 14 May 2024 19:56:26 +0200 Subject: [PATCH 31/34] update --- Cargo.lock | 3 ++- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc8b968..65e7ece 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,7 +512,8 @@ dependencies = [ [[package]] name = "interprocess" version = "2.1.0" -source = "git+https://github.com/kotauskas/interprocess?branch=main#b79d3636152158f7a8977f8043188e89446916c5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4d0250d41da118226e55b3d50ca3f0d9e0a0f6829b92f543ac0054aeea1572" dependencies = [ "futures-core", "libc", diff --git a/Cargo.toml b/Cargo.toml index 3dc248b..e802be1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ tokio-serde = { version = "0.8", features = ["bincode"], optional = true } tokio-util = { version = "0.7", features = ["codec", "compat"], optional = true } tracing = "0.1" quinn-udp = { package = "iroh-quinn-udp", version = "0.4.0", optional = true } -interprocess = { git = "https://github.com/kotauskas/interprocess", branch = "main", version = "2", features = ["tokio"], optional = true } +interprocess = { version = "2.1", features = ["tokio"], optional = true } hex = "0.4.3" blake3 = "1.4.1" futures = { version = "0.3.30", optional = true } From 4e8deef7c02d0e1b3a8dbfc1d5484636eadd9a21 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Tue, 14 May 2024 20:00:22 +0200 Subject: [PATCH 32/34] ci: fix merge issue --- .github/workflows/ci.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd1de52..49ba090 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,16 +13,12 @@ on: concurrency: group: tests-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true - + env: MSRV: "1.76" RUST_BACKTRACE: 1 RUSTFLAGS: -Dwarnings -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - jobs: lint: runs-on: ubuntu-latest From ca6546b2835c0503b35b84e770b5478eaa9e4157 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Wed, 15 May 2024 12:20:52 +0200 Subject: [PATCH 33/34] Use to_ns_name on windows this whole naming API is weird... --- src/transport/interprocess.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index 5673216..ffb7530 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -6,7 +6,7 @@ use std::{io, net::SocketAddr, path::Path}; use super::quinn_flume_socket::{make_endpoint, FlumeSocket, Packet}; use bytes::{Buf, Bytes, BytesMut}; use futures::StreamExt; -use interprocess::local_socket::{GenericFilePath, Name, ToFsName}; +use interprocess::local_socket::{GenericFilePath, GenericNamespaced, Name, ToFsName, ToNsName}; use quinn::{Endpoint, EndpointConfig}; use tokio::{ io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}, @@ -34,7 +34,7 @@ impl<'a> Iterator for FrameIter<'a> { /// Automatically chooses name type based on OS support and preference. pub fn new_socket_name(root: impl AsRef, id: &str) -> io::Result> { if cfg!(windows) { - format!("@quic-rpc-socket-{}.sock", id).to_fs_name::() + format!("@quic-rpc-socket-{}.sock", id).to_ns_name::() } else if cfg!(unix) { root.as_ref() .join(format!("{id}.sock")) From c7117e92be1d55a2a771c158a54616e56534c7a9 Mon Sep 17 00:00:00 2001 From: Ruediger Klaehn Date: Wed, 15 May 2024 13:15:35 +0200 Subject: [PATCH 34/34] Use explicit dep: for dependencies in Cargo.toml also dial down logging --- Cargo.lock | 1 - Cargo.toml | 15 +++++++-------- src/transport/interprocess.rs | 4 ++-- src/transport/quinn_flume_socket.rs | 6 +++--- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65e7ece..f2e7f5a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1342,7 +1342,6 @@ checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", - "futures-io", "futures-sink", "pin-project-lite", "tokio", diff --git a/Cargo.toml b/Cargo.toml index e802be1..4091e0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ quinn = { package = "iroh-quinn", version = "0.10", optional = true } serde = { version = "1.0.183", features = ["derive"] } tokio = { version = "1", default-features = false, features = ["macros", "sync"] } tokio-serde = { version = "0.8", features = ["bincode"], optional = true } -tokio-util = { version = "0.7", features = ["codec", "compat"], optional = true } +tokio-util = { version = "0.7", features = ["codec"], optional = true } tracing = "0.1" quinn-udp = { package = "iroh-quinn-udp", version = "0.4.0", optional = true } interprocess = { version = "2.1", features = ["tokio"], optional = true } @@ -58,15 +58,14 @@ proc-macro2 = "1.0.66" futures-buffered = "0.2.4" [features] -hyper-transport = ["flume", "hyper", "bincode", "bytes", "tokio-serde", "tokio-util"] -quinn-transport = ["flume", "quinn", "bincode", "tokio-serde", "tokio-util"] -flume-transport = ["flume"] -interprocess-transport = ["quinn-udp", "interprocess", "bytes", "tokio-util", "quinn-transport", "quinn-flume-socket", "futures"] +hyper-transport = ["dep:flume", "dep:hyper", "dep:bincode", "dep:bytes", "dep:tokio-serde", "dep:tokio-util"] +quinn-transport = ["dep:flume", "dep:quinn", "dep:bincode", "dep:tokio-serde", "dep:tokio-util"] +flume-transport = ["dep:flume"] +interprocess-transport = ["quinn-transport", "quinn-flume-socket", "dep:quinn-udp", "dep:interprocess", "dep:bytes", "dep:tokio-util", "dep:futures"] combined-transport = [] -quinn-flume-socket = ["flume", "quinn", "quinn-udp", "bytes", "tokio-util"] +quinn-flume-socket = ["dep:flume", "dep:quinn", "dep:quinn-udp", "dep:bytes", "dep:tokio-util"] macros = [] -default = ["flume-transport", "interprocess-transport"] -futures = ["dep:futures"] +default = ["flume-transport"] [package.metadata.docs.rs] all-features = true diff --git a/src/transport/interprocess.rs b/src/transport/interprocess.rs index ffb7530..3720296 100644 --- a/src/transport/interprocess.rs +++ b/src/transport/interprocess.rs @@ -82,7 +82,7 @@ where } } else { let len: u16 = contents.len().try_into().unwrap(); - tracing::debug!("sending {}bytes", len); + tracing::trace!("sending {} bytes", len); w.write_all(&len.to_le_bytes()).await?; w.write_all(contents).await?; } @@ -100,7 +100,7 @@ where // read more data and split into frames let n = r.read_buf(&mut buffer).await; let n = n?; - tracing::debug!("read {}bytes", n); + tracing::trace!("read {} bytes", n); if n == 0 { // eof break; diff --git a/src/transport/quinn_flume_socket.rs b/src/transport/quinn_flume_socket.rs index 4fd4cde..630a65c 100644 --- a/src/transport/quinn_flume_socket.rs +++ b/src/transport/quinn_flume_socket.rs @@ -96,7 +96,7 @@ impl FlumeSocketInner { } let mut offset = 0; let mut pending = false; - tracing::debug!("S {} transmits", transmits.len()); + tracing::trace!("S {} transmits", transmits.len()); for transmit in transmits { let item = Packet { from: self.local, @@ -104,7 +104,7 @@ impl FlumeSocketInner { contents: transmit.contents.clone(), segment_size: transmit.segment_size, }; - tracing::debug!( + tracing::trace!( "S sending {} {:?}", transmit.contents.len(), transmit.segment_size @@ -183,7 +183,7 @@ impl FlumeSocketInner { ecn: None, dst_ip: Some(self.local.ip()), }; - tracing::debug!("R bufs {} bytes, {} slots", bufs[offset].len(), n); + tracing::trace!("R bufs {} bytes, {} slots", bufs[offset].len(), n); bufs[offset][..len].copy_from_slice(&packet.contents); meta[offset] = m; offset += 1;