1pub(crate) mod balancer;
11pub mod counters;
12pub mod errors;
13pub mod flow_control;
14mod manager;
15#[cfg(feature = "telemetry")]
16mod telemetry;
17mod types;
18mod utils;
19
20pub use balancer::{AtomicSurbFlowEstimator, BalancerStateValues, MIN_BALANCER_SAMPLING_INTERVAL, SurbBalancerConfig};
21use hopr_api::types::internal::routing::RoutingOptions;
22pub use hopr_protocol_session::{AcknowledgementMode, flow_control::FlowControlConfig};
23pub use hopr_utils::network_types::types::*;
24pub use manager::{
25 DEFAULT_MAX_SSAS_PER_SSA_REQUEST, DEFAULT_SSAS_PER_SSA_REQUEST, DispatchResult, IncomingSessionPixConfig,
26 MAX_SSA_BATCH_SIZE, MIN_SURB_BUFFER_DURATION, PixToolbox, SessionManager, SessionManagerConfig,
27};
28#[cfg(any(test, feature = "testing"))]
29pub mod testing;
30pub use hopr_api::types::internal::routing::DestinationRouting;
31pub use hopr_protocol_app::prelude::{ApplicationDataIn, ApplicationDataOut};
32pub use hopr_protocol_pix::{InvalidPixParams, PixParams};
33#[cfg(feature = "telemetry")]
34pub use telemetry::{SessionAckMode, SessionLifecycleState};
35#[cfg(any(test, feature = "testing"))]
36pub use testing::{MsgSender as MockMsgSender, SendMsg, mock_packet_planning, msg_type, start_msg_match};
37pub use types::{
38 AgreedSsaQuota, DEFAULT_PIX_POLYS_PER_SSA, DEFAULT_PIX_SHARES_PER_POLY, DEFAULT_PIX_SSA_QUOTA,
39 DEFAULT_PIX_SURPLUS_SHARES, HoprSession, HoprSessionCapabilities, HoprSessionConfig, HoprSessionInPixEvent,
40 HoprSessionOutPixEvent, HoprStartProtocol, IncomingSession, LOCAL_PIX_SUITE, ServiceId, SessionId, SessionTarget,
41};
42#[cfg(feature = "runtime-tokio")]
43pub use utils::transfer_session;
44
45pub const SESSION_MTU: usize =
49 hopr_protocol_session::session_socket_mtu::<{ hopr_protocol_app::v1::ApplicationData::PAYLOAD_SIZE }>();
50
51pub const SURB_SIZE: usize = hopr_crypto_packet::HoprSurb::SIZE;
55
56flagset::flags! {
57 #[repr(u8)]
59 #[derive(PartialOrd, Ord, strum::EnumString, strum::Display, serde_repr::Serialize_repr, serde_repr::Deserialize_repr)]
60 pub enum Capability : u8 {
61 Segmentation = 0b0000_1000,
63 RetransmissionAck = 0b0000_1100,
67 RetransmissionNack = 0b000_1010,
71 NoDelay = 0b0000_1001,
75 NoRateControl = 0b0001_0000,
81 UsePIX = 0b0010_0000,
85 }
86}
87
88pub type Capabilities = flagset::FlagSet<Capability>;
90
91#[derive(Debug, PartialEq, Clone, smart_default::SmartDefault)]
96pub struct SessionClientConfig {
97 #[default(RoutingOptions::Hops(hopr_api::types::primitive::bounded::BoundedSize::MIN))]
99 pub forward_path_options: RoutingOptions,
100 #[default(RoutingOptions::Hops(hopr_api::types::primitive::bounded::BoundedSize::MIN))]
102 pub return_path_options: RoutingOptions,
103 #[default(_code = "Capability::Segmentation.into()")]
105 pub capabilities: Capabilities,
106 #[default(None)]
108 pub pseudonym: Option<hopr_api::types::internal::protocol::HoprPseudonym>,
109 #[default(Some(SurbBalancerConfig::default()))]
111 pub surb_management: Option<SurbBalancerConfig>,
112 #[default(false)]
122 pub always_max_out_surbs: bool,
123 pub pix_ssa_quota: Option<PixParams>,
144 #[default(None)]
151 pub flow_control: Option<FlowControlConfig>,
152 pub max_frames_behind_gap: Option<usize>,
165}
166
167#[cfg(test)]
168mod tests {
169 use hopr_api::types::{crypto_random::Randomizable, internal::prelude::HoprPseudonym};
170 use hopr_crypto_packet::prelude::HoprPacket;
171 use hopr_protocol_app::v1::ApplicationData;
172 use hopr_protocol_session::session_socket_mtu;
173 use hopr_protocol_start::{
174 ErrorIdentifier, KeepAliveMessage, StartChallenge, StartErrorReason, StartErrorType, StartEstablished,
175 StartInitiation,
176 };
177
178 use super::*;
179 use crate::types::HoprStartProtocol;
180
181 #[test]
182 fn test_session_mtu() {
183 assert_eq!(SESSION_MTU, session_socket_mtu::<{ ApplicationData::PAYLOAD_SIZE }>());
184 assert_eq!(1020, SESSION_MTU); }
186
187 #[test]
188 fn hopr_start_protocol_messages_must_fit_within_hopr_packet() -> anyhow::Result<()> {
189 let msg = HoprStartProtocol::StartSession(StartInitiation {
190 challenge: StartChallenge::MAX,
191 target: SessionTarget::TcpStream(SealedHost::Plain(
192 "example-of-a-very-very-long-second-level-name.on-a-very-very-long-domain-name.info:65530".parse()?,
193 )),
194 capabilities: Capabilities::full().into(),
195 additional_data: 0xffffffff,
196 });
197
198 assert!(
199 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
200 "StartSession must fit within {}",
201 HoprPacket::PAYLOAD_SIZE
202 );
203
204 let msg = HoprStartProtocol::SessionEstablished(StartEstablished {
205 orig_challenge: StartChallenge::MAX,
206 session_id: HoprPseudonym::random(),
207 });
208
209 assert!(
210 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
211 "SessionEstablished must fit within {}",
212 HoprPacket::PAYLOAD_SIZE
213 );
214
215 let msg = HoprStartProtocol::SessionError(StartErrorType {
216 identifier: ErrorIdentifier::Challenge(StartChallenge::MAX),
217 reason: StartErrorReason::NoSlotsAvailable,
218 });
219
220 assert!(
221 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
222 "SessionError must fit within {}",
223 HoprPacket::PAYLOAD_SIZE
224 );
225
226 let msg = HoprStartProtocol::KeepAlive(KeepAliveMessage {
227 session_id: HoprPseudonym::random(),
228 flags: None.into(),
229 additional_data: 0xffffffff,
230 });
231 assert!(
232 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
233 "KeepAlive must fit within {}",
234 HoprPacket::PAYLOAD_SIZE
235 );
236
237 Ok(())
238 }
239
240 #[test]
241 fn hopr_start_protocol_message_session_initiation_message_should_allow_for_at_least_one_surb() -> anyhow::Result<()>
242 {
243 let msg = HoprStartProtocol::StartSession(StartInitiation {
244 challenge: StartChallenge::MAX,
245 target: SessionTarget::TcpStream(SealedHost::Plain(
246 "example-of-a-very-very-long-second-level-name.on-a-very-very-long-domain-name.info:65530".parse()?,
247 )),
248 capabilities: Capabilities::full().into(),
249 additional_data: 0xffffffff,
250 });
251 let len = msg.encode()?.1.len();
252 assert!(
253 HoprPacket::max_surbs_with_message(len) >= 1,
254 "Hopr StartSession message size ({}) must allow for at least 1 SURB in packet",
255 len
256 );
257
258 Ok(())
259 }
260
261 #[test]
262 fn hopr_start_protocol_message_keep_alive_message_should_allow_for_maximum_surbs() -> anyhow::Result<()> {
263 let msg = HoprStartProtocol::KeepAlive(KeepAliveMessage {
264 session_id: HoprPseudonym::random(),
265 flags: None.into(),
266 additional_data: 0xffffffff,
267 });
268 let len = msg.encode()?.1.len();
269 assert_eq!(
270 KeepAliveMessage::<SessionId>::MIN_SURBS_PER_MESSAGE,
271 HoprPacket::MAX_SURBS_IN_PACKET
272 );
273 assert!(
274 HoprPacket::max_surbs_with_message(len) >= HoprPacket::MAX_SURBS_IN_PACKET,
275 "Hopr KeepAlive message size ({}) must allow for at least {} SURBs in packet",
276 len,
277 HoprPacket::MAX_SURBS_IN_PACKET
278 );
279
280 Ok(())
281 }
282}