hopr_transport_session/
lib.rs1pub(crate) mod balancer;
11pub mod errors;
12mod manager;
13mod types;
14mod utils;
15
16pub use balancer::{MIN_BALANCER_SAMPLING_INTERVAL, SurbBalancerConfig};
17pub use hopr_network_types::types::*;
18pub use manager::{DispatchResult, MIN_SURB_BUFFER_DURATION, SessionManager, SessionManagerConfig};
19pub use types::{ByteCapabilities, IncomingSession, ServiceId, Session, SessionId, SessionTarget};
20#[cfg(feature = "runtime-tokio")]
21pub use utils::transfer_session;
22
23pub const SESSION_MTU: usize =
25 hopr_protocol_session::session_socket_mtu::<{ hopr_protocol_app::v1::ApplicationData::PAYLOAD_SIZE }>();
26
27pub const SURB_SIZE: usize = hopr_crypto_packet::HoprSurb::SIZE;
31
32flagset::flags! {
33 #[repr(u8)]
35 #[derive(PartialOrd, Ord, strum::EnumString, strum::Display, serde_repr::Serialize_repr, serde_repr::Deserialize_repr)]
36 pub enum Capability : u8 {
37 Segmentation = 0b0000_1000,
39 RetransmissionAck = 0b0000_1100,
43 RetransmissionNack = 0b000_1010,
47 NoDelay = 0b0000_1001,
51 NoRateControl = 0b0001_0000,
55 }
56}
57
58pub type Capabilities = flagset::FlagSet<Capability>;
60
61#[derive(Debug, PartialEq, Clone, smart_default::SmartDefault)]
66pub struct SessionClientConfig {
67 #[default(RoutingOptions::Hops(hopr_primitive_types::bounded::BoundedSize::MIN))]
69 pub forward_path_options: RoutingOptions,
70 #[default(RoutingOptions::Hops(hopr_primitive_types::bounded::BoundedSize::MIN))]
72 pub return_path_options: RoutingOptions,
73 #[default(_code = "Capability::Segmentation.into()")]
75 pub capabilities: Capabilities,
76 #[default(None)]
78 pub pseudonym: Option<hopr_internal_types::protocol::HoprPseudonym>,
79 #[default(Some(SurbBalancerConfig::default()))]
81 pub surb_management: Option<SurbBalancerConfig>,
82}
83
84#[cfg(test)]
85mod tests {
86 use hopr_crypto_packet::prelude::HoprPacket;
87 use hopr_crypto_random::Randomizable;
88 use hopr_internal_types::prelude::HoprPseudonym;
89 use hopr_protocol_app::v1::ApplicationData;
90 use hopr_protocol_session::session_socket_mtu;
91 use hopr_protocol_start::{
92 KeepAliveMessage, StartChallenge, StartErrorReason, StartErrorType, StartEstablished, StartInitiation,
93 };
94
95 use super::*;
96 use crate::types::HoprStartProtocol;
97
98 #[test]
99 fn test_session_mtu() {
100 assert_eq!(SESSION_MTU, session_socket_mtu::<{ ApplicationData::PAYLOAD_SIZE }>());
101 assert_eq!(1002, SESSION_MTU);
102 }
103
104 #[test]
105 fn hopr_start_protocol_messages_must_fit_within_hopr_packet() -> anyhow::Result<()> {
106 let msg = HoprStartProtocol::StartSession(StartInitiation {
107 challenge: StartChallenge::MAX,
108 target: SessionTarget::TcpStream(SealedHost::Plain(
109 "example-of-a-very-very-long-second-level-name.on-a-very-very-long-domain-name.info:65530".parse()?,
110 )),
111 capabilities: Capabilities::full().into(),
112 additional_data: 0xffffffff,
113 });
114
115 assert!(
116 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
117 "StartSession must fit within {}",
118 HoprPacket::PAYLOAD_SIZE
119 );
120
121 let msg = HoprStartProtocol::SessionEstablished(StartEstablished {
122 orig_challenge: StartChallenge::MAX,
123 session_id: SessionId::new(u64::MAX, HoprPseudonym::random()),
124 });
125
126 assert!(
127 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
128 "SessionEstablished must fit within {}",
129 HoprPacket::PAYLOAD_SIZE
130 );
131
132 let msg = HoprStartProtocol::SessionError(StartErrorType {
133 challenge: StartChallenge::MAX,
134 reason: StartErrorReason::NoSlotsAvailable,
135 });
136
137 assert!(
138 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
139 "SessionError must fit within {}",
140 HoprPacket::PAYLOAD_SIZE
141 );
142
143 let msg = HoprStartProtocol::KeepAlive(KeepAliveMessage {
144 session_id: SessionId::new(u64::MAX, HoprPseudonym::random()),
145 flags: 0xff,
146 additional_data: 0xffffffff,
147 });
148 assert!(
149 msg.encode()?.1.len() <= HoprPacket::PAYLOAD_SIZE,
150 "KeepAlive must fit within {}",
151 HoprPacket::PAYLOAD_SIZE
152 );
153
154 Ok(())
155 }
156
157 #[test]
158 fn hopr_start_protocol_message_session_initiation_message_should_allow_for_at_least_one_surb() -> anyhow::Result<()>
159 {
160 let msg = HoprStartProtocol::StartSession(StartInitiation {
161 challenge: StartChallenge::MAX,
162 target: SessionTarget::TcpStream(SealedHost::Plain(
163 "example-of-a-very-very-long-second-level-name.on-a-very-very-long-domain-name.info:65530".parse()?,
164 )),
165 capabilities: Capabilities::full().into(),
166 additional_data: 0xffffffff,
167 });
168 let len = msg.encode()?.1.len();
169 assert!(
170 HoprPacket::max_surbs_with_message(len) >= 1,
171 "Hopr StartSession message size ({}) must allow for at least 1 SURB in packet",
172 len
173 );
174
175 Ok(())
176 }
177
178 #[test]
179 fn hopr_start_protocol_message_keep_alive_message_should_allow_for_maximum_surbs() -> anyhow::Result<()> {
180 let msg = HoprStartProtocol::KeepAlive(KeepAliveMessage {
181 session_id: SessionId::new(u64::MAX, HoprPseudonym::random()),
182 flags: 0xff,
183 additional_data: 0xffffffff,
184 });
185 let len = msg.encode()?.1.len();
186 assert_eq!(
187 KeepAliveMessage::<SessionId>::MIN_SURBS_PER_MESSAGE,
188 HoprPacket::MAX_SURBS_IN_PACKET
189 );
190 assert!(
191 HoprPacket::max_surbs_with_message(len) >= HoprPacket::MAX_SURBS_IN_PACKET,
192 "Hopr KeepAlive message size ({}) must allow for at least {} SURBs in packet",
193 len,
194 HoprPacket::MAX_SURBS_IN_PACKET
195 );
196
197 Ok(())
198 }
199}