hopr_transport_session/
lib.rs1pub(crate) mod balancer;
11pub mod errors;
12mod manager;
13#[cfg(feature = "telemetry")]
14mod telemetry;
15mod types;
16mod utils;
17
18pub use balancer::{AtomicSurbFlowEstimator, BalancerStateValues, MIN_BALANCER_SAMPLING_INTERVAL, SurbBalancerConfig};
19pub use hopr_network_types::types::*;
20pub use hopr_protocol_session::AcknowledgementMode;
21use hopr_types::internal::routing::RoutingOptions;
22pub use manager::{DispatchResult, MIN_SURB_BUFFER_DURATION, SessionManager, SessionManagerConfig};
23#[cfg(feature = "telemetry")]
24pub use telemetry::{SessionAckMode, SessionLifecycleState};
25pub use types::{
26 ByteCapabilities, HoprSession, HoprSessionConfig, IncomingSession, ServiceId, SessionId, SessionTarget,
27};
28#[cfg(feature = "runtime-tokio")]
29pub use utils::transfer_session;
30
31pub const SESSION_MTU: usize =
35 hopr_protocol_session::session_socket_mtu::<{ hopr_protocol_app::v1::ApplicationData::PAYLOAD_SIZE }>();
36
37pub const SURB_SIZE: usize = hopr_crypto_packet::HoprSurb::SIZE;
41
42flagset::flags! {
43 #[repr(u8)]
45 #[derive(PartialOrd, Ord, strum::EnumString, strum::Display, serde_repr::Serialize_repr, serde_repr::Deserialize_repr)]
46 pub enum Capability : u8 {
47 Segmentation = 0b0000_1000,
49 RetransmissionAck = 0b0000_1100,
53 RetransmissionNack = 0b000_1010,
57 NoDelay = 0b0000_1001,
61 NoRateControl = 0b0001_0000,
65 }
66}
67
68pub type Capabilities = flagset::FlagSet<Capability>;
70
71#[derive(Debug, PartialEq, Clone, smart_default::SmartDefault)]
76pub struct SessionClientConfig {
77 #[default(RoutingOptions::Hops(hopr_types::primitive::bounded::BoundedSize::MIN))]
79 pub forward_path_options: RoutingOptions,
80 #[default(RoutingOptions::Hops(hopr_types::primitive::bounded::BoundedSize::MIN))]
82 pub return_path_options: RoutingOptions,
83 #[default(_code = "Capability::Segmentation.into()")]
85 pub capabilities: Capabilities,
86 #[default(None)]
88 pub pseudonym: Option<hopr_types::internal::protocol::HoprPseudonym>,
89 #[default(Some(SurbBalancerConfig::default()))]
91 pub surb_management: Option<SurbBalancerConfig>,
92 #[default(false)]
102 pub always_max_out_surbs: bool,
103}
104
105#[cfg(test)]
106mod tests {
107 use hopr_crypto_packet::prelude::HoprPacket;
108 use hopr_protocol_app::v1::ApplicationData;
109 use hopr_protocol_session::session_socket_mtu;
110 use hopr_protocol_start::{
111 KeepAliveMessage, StartChallenge, StartErrorReason, StartErrorType, StartEstablished, StartInitiation,
112 };
113 use hopr_types::{crypto_random::Randomizable, internal::prelude::HoprPseudonym};
114
115 use super::*;
116 use crate::types::HoprStartProtocol;
117
118 #[test]
119 fn test_session_mtu() {
120 assert_eq!(SESSION_MTU, session_socket_mtu::<{ ApplicationData::PAYLOAD_SIZE }>());
121 assert_eq!(1018, SESSION_MTU);
122 }
123
124 #[test]
125 fn hopr_start_protocol_messages_must_fit_within_hopr_packet() -> anyhow::Result<()> {
126 let msg = HoprStartProtocol::StartSession(StartInitiation {
127 challenge: StartChallenge::MAX,
128 target: SessionTarget::TcpStream(SealedHost::Plain(
129 "example-of-a-very-very-long-second-level-name.on-a-very-very-long-domain-name.info:65530".parse()?,
130 )),
131 capabilities: Capabilities::full().into(),
132 additional_data: 0xffffffff,
133 });
134
135 assert!(
136 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
137 "StartSession must fit within {}",
138 HoprPacket::PAYLOAD_SIZE
139 );
140
141 let msg = HoprStartProtocol::SessionEstablished(StartEstablished {
142 orig_challenge: StartChallenge::MAX,
143 session_id: SessionId::new(u64::MAX, HoprPseudonym::random()),
144 });
145
146 assert!(
147 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
148 "SessionEstablished must fit within {}",
149 HoprPacket::PAYLOAD_SIZE
150 );
151
152 let msg = HoprStartProtocol::SessionError(StartErrorType {
153 challenge: StartChallenge::MAX,
154 reason: StartErrorReason::NoSlotsAvailable,
155 });
156
157 assert!(
158 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
159 "SessionError must fit within {}",
160 HoprPacket::PAYLOAD_SIZE
161 );
162
163 let msg = HoprStartProtocol::KeepAlive(KeepAliveMessage {
164 session_id: SessionId::new(u64::MAX, HoprPseudonym::random()),
165 flags: None.into(),
166 additional_data: 0xffffffff,
167 });
168 assert!(
169 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
170 "KeepAlive must fit within {}",
171 HoprPacket::PAYLOAD_SIZE
172 );
173
174 Ok(())
175 }
176
177 #[test]
178 fn hopr_start_protocol_message_session_initiation_message_should_allow_for_at_least_one_surb() -> anyhow::Result<()>
179 {
180 let msg = HoprStartProtocol::StartSession(StartInitiation {
181 challenge: StartChallenge::MAX,
182 target: SessionTarget::TcpStream(SealedHost::Plain(
183 "example-of-a-very-very-long-second-level-name.on-a-very-very-long-domain-name.info:65530".parse()?,
184 )),
185 capabilities: Capabilities::full().into(),
186 additional_data: 0xffffffff,
187 });
188 let len = msg.encode()?.1.len();
189 assert!(
190 HoprPacket::max_surbs_with_message(len) >= 1,
191 "Hopr StartSession message size ({}) must allow for at least 1 SURB in packet",
192 len
193 );
194
195 Ok(())
196 }
197
198 #[test]
199 fn hopr_start_protocol_message_keep_alive_message_should_allow_for_maximum_surbs() -> anyhow::Result<()> {
200 let msg = HoprStartProtocol::KeepAlive(KeepAliveMessage {
201 session_id: SessionId::new(u64::MAX, HoprPseudonym::random()),
202 flags: None.into(),
203 additional_data: 0xffffffff,
204 });
205 let len = msg.encode()?.1.len();
206 assert_eq!(
207 KeepAliveMessage::<SessionId>::MIN_SURBS_PER_MESSAGE,
208 HoprPacket::MAX_SURBS_IN_PACKET
209 );
210 assert!(
211 HoprPacket::max_surbs_with_message(len) >= HoprPacket::MAX_SURBS_IN_PACKET,
212 "Hopr KeepAlive message size ({}) must allow for at least {} SURBs in packet",
213 len,
214 HoprPacket::MAX_SURBS_IN_PACKET
215 );
216
217 Ok(())
218 }
219}