hopr_protocol_session/lib.rs
1//! Contains implementation of a `Session` message protocol.
2//!
3//! The implementation in this crate follows
4//! the HOPR [`RFC-0007`](https://github.com/hoprnet/rfc/tree/main/rfcs/RFC-0007-session-protocol).
5//!
6//! # What is `Session` protocol?
7//! `Session` protocol is a simple protocol for unreliable networks that implements
8//! basic TCP-like features, such as segmentation, retransmission and acknowledgement.
9//!
10//! The goal of this protocol is to establish a read-write session between two parties,
11//! where one is a message sender and the other one is the receiver. The messages are called
12//! *frames* which are split and are delivered as *segments* from the sender to the recipient.
13//! The session has some reliability guarantees given by the retransmission and acknowledgement
14//! capabilities of individual segments.
15//!
16//! The [`UnreliableSocket`] acts as an unreliable Session protocol socket, taking care only of
17//! segmentation, reassembly and sequencing.
18//!
19//! The [`ReliableSocket`] has (in addition to segmentation, reassembly and sequencing) an
20//! internal state that allows acknowledging frames, retransmit unacknowledged frames and/or
21//! requesting of missing frame segments. It therefore offers data some delivery guarantees
22//! up to the pre-defined frame expiration time.
23//!
24//! The above sockets can be constructed on top of any transport that implements
25//! [`futures::io::AsyncRead`] and [`futures::io::AsyncWrite`],
26//! also using the [extension](SessionSocketExt) methods.
27//!
28//! ## Overview of the crate
29//! - Protocol messages are defined in the `protocol` submodule.
30//! - Socket-like Session interface is defined in `socket` submodule.
31//! - Frames and segments are defined in the `frames` module.
32//! - Segmentation, reassembly and sequencing are defined in the `processing` submodule.
33
34/// Contains errors thrown from this module.
35pub mod errors;
36#[allow(dead_code)]
37mod processing;
38mod protocol;
39mod socket;
40pub(crate) mod utils;
41
42pub use processing::types::FrameInspector;
43pub use protocol::{FrameAcknowledgements, FrameId, Segment, SegmentId, SegmentRequest, SeqIndicator};
44#[cfg(feature = "telemetry")]
45pub use socket::telemetry::{NoopTracker, SessionMessageDiscriminants, SessionTelemetryTracker};
46pub use socket::{
47 SessionSocket, SessionSocketConfig,
48 ack_state::{AcknowledgementMode, AcknowledgementState, AcknowledgementStateConfig},
49 state::{SocketComponents, SocketState, Stateless},
50};
51
52// Enable exports of additional Session protocol types
53#[cfg(feature = "session-types")]
54pub mod types {
55 pub use super::protocol::*;
56}
57
58/// Represents a stateless (and therefore unreliable) socket.
59pub type UnreliableSocket<const C: usize> = SessionSocket<C, Stateless<C>>;
60
61/// Represents a socket with reliable delivery.
62pub type ReliableSocket<const C: usize> = SessionSocket<C, AcknowledgementState<C>>;
63
64/// Computes the Session Socket MTU, given the MTU `C` of the underlying socket.
65pub const fn session_socket_mtu<const C: usize>() -> usize {
66 C - protocol::SessionMessage::<C>::SEGMENT_OVERHEAD
67}
68
69/// Adaptors for [`futures::io::AsyncRead`] + [`futures::io::AsyncWrite`] transport to use Session protocol.
70///
71/// Use `compat` first when the underlying transport is Tokio-based.
72pub trait SessionSocketExt: futures::io::AsyncRead + futures::io::AsyncWrite + Send + Unpin {
73 /// Runs a [reliable](ReliableSocket) Session protocol on self.
74 fn reliable_session<const MTU: usize>(
75 self,
76 ack: AcknowledgementState<MTU>,
77 cfg: SessionSocketConfig,
78 ) -> errors::Result<ReliableSocket<MTU>>
79 where
80 Self: Sized + 'static,
81 {
82 #[cfg(feature = "telemetry")]
83 {
84 SessionSocket::new(self, ack, cfg, NoopTracker)
85 }
86 #[cfg(not(feature = "telemetry"))]
87 {
88 SessionSocket::new(self, ack, cfg)
89 }
90 }
91
92 /// Runs [unreliable](UnreliableSocket) Session protocol on self.
93 fn unreliable_session<const MTU: usize>(
94 self,
95 id: &str,
96 cfg: SessionSocketConfig,
97 ) -> errors::Result<UnreliableSocket<MTU>>
98 where
99 Self: Sized + 'static,
100 {
101 #[cfg(feature = "telemetry")]
102 {
103 SessionSocket::new_stateless(id, self, cfg, NoopTracker)
104 }
105 #[cfg(not(feature = "telemetry"))]
106 {
107 SessionSocket::new_stateless(id, self, cfg)
108 }
109 }
110}
111
112impl<T: ?Sized> SessionSocketExt for T where T: futures::io::AsyncRead + futures::io::AsyncWrite + Send + Unpin {}