confium_net/lib.rs
1#![allow(rustdoc::broken_intra_doc_links)]
2#![allow(rustdoc::bare_urls)]
3#![allow(rustdoc::redundant_explicit_links)]
4#![allow(rustdoc::private_intra_doc_links)]
5#![allow(rustdoc::invalid_html_tags)]
6
7//! Confium Network: transport abstraction for multi-party protocols.
8//!
9//! Threshold-cryptography sessions need reliable, ordered byte streams
10//! between parties. Confium supplies the transport so plugin authors
11//! don't roll their own socket code. Plugins request a transport by
12//! URL (`"inproc://session-42"`, `"tcp://1.2.3.4:443"`, ...); Confium
13//! dispatches to the registered [`TransportKind`] that owns the
14//! scheme.
15//!
16//! # Built-in transports
17//!
18//! This crate ships two built-in transports:
19//!
20//! - [`transports::inproc`] — in-process channels for tests and
21//! single-process TC simulation.
22//! - [`transports::mock`] — deterministic mock transport with
23//! drop/tamper fault injection for Byzantine-peer simulation.
24//!
25//! Production transports (`tcp`, `tcp+tls`, `quic`, `ws`, `wss`) live
26//! in separate crates (`confium-net-tcp`, etc.) and register via the
27//! same [`register_transport!`] macro.
28//!
29//! # Example
30//!
31//! ```
32//! use confium_net as net;
33//!
34//! // Listener must be set up before connect consumes it.
35//! let mut listener = net::listen("inproc://demo").unwrap();
36//! let mut client = net::connect("inproc://demo").unwrap();
37//! let mut server = listener.accept().unwrap();
38//!
39//! client.send(b"round-1").unwrap();
40//! let mut buf = [0u8; 16];
41//! let n = server.recv(&mut buf).unwrap();
42//! assert_eq!(&buf[..n], b"round-1");
43//! ```
44//!
45//! See `TODO.roadmap/05-networking-primitives.md` for the design.
46
47pub mod deadline;
48pub mod error;
49pub mod io;
50pub mod registry;
51pub mod transports;
52pub mod url;
53
54use ::url::Url;
55use snafu::OptionExt;
56
57pub use error::Error;
58pub use error::Result;
59pub use registry::TransportKind;
60// `register_transport!` is exported via `#[macro_export]`, so it is
61// already at the crate root and part of the public API.
62pub use transports::inproc;
63pub use transports::mock;
64pub use url::TransportUrl;
65
66use error::UnknownSchemeSnafu;
67
68/// A connected, reliable, ordered, bidirectional byte transport.
69///
70/// Implementations deliver complete protocol messages: one `send` is
71/// observed as exactly one `recv` payload. Callers provide a buffer to
72/// `recv`; if the buffer is smaller than the pending message, the
73/// transport fills what it can. Specific transports document how they
74/// handle undersized buffers (the built-in `inproc`/`mock` transports
75/// deliver a prefix and drop the remainder).
76pub trait Transport: Send {
77 /// Enqueue `data` for delivery to the peer.
78 fn send(&mut self, data: &[u8]) -> Result<()>;
79
80 /// Receive the next pending message into `buf`, returning the
81 /// number of bytes written.
82 fn recv(&mut self, buf: &mut [u8]) -> Result<usize>;
83
84 /// Tear down the transport. After this, `send` and `recv` return
85 /// [`Error::Closed`].
86 fn close(&mut self) -> Result<()>;
87}
88
89/// A listening endpoint that produces accepted [`Transport`]s.
90pub trait Listener: Send {
91 /// Block until a peer connects, then return the new transport.
92 fn accept(&mut self) -> Result<Box<dyn Transport>>;
93}
94
95/// Connect to the peer identified by `url_str`.
96///
97/// The URL scheme selects the transport kind via the link-time
98/// registry. The built-in `inproc` and `mock` schemes are always
99/// available; additional schemes require their transport crate to be
100/// linked into the final binary.
101pub fn connect(url_str: &str) -> Result<Box<dyn Transport>> {
102 let parsed = TransportUrl::parse(url_str)?;
103 let scheme = parsed.scheme();
104 let kind = registry::find(scheme).with_context(|| UnknownSchemeSnafu {
105 scheme: scheme.to_string(),
106 })?;
107 let url: &Url = parsed.as_url();
108 kind.connect(url)
109}
110
111/// Begin listening for inbound connections at the address in
112/// `url_str`.
113pub fn listen(url_str: &str) -> Result<Box<dyn Listener>> {
114 let parsed = TransportUrl::parse(url_str)?;
115 let scheme = parsed.scheme();
116 let kind = registry::find(scheme).with_context(|| UnknownSchemeSnafu {
117 scheme: scheme.to_string(),
118 })?;
119 let url: &Url = parsed.as_url();
120 kind.listen(url)
121}