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