1use alloc::boxed::Box;
2
3use umsh_core::{MicSize, PublicKey};
4use umsh_mac::SendOptions;
5
6pub const PING_MIC_SIZE: MicSize = MicSize::Mic8;
18
19use crate::node::{LocalNode, NodeError, Subscription, SubscriptionHandle};
20use crate::receive::ReceivedPacketRef;
21use crate::ticket::SendProgressTicket;
22use crate::transport::Transport;
23
24#[derive(Clone)]
29pub struct PeerConnection<T: Transport> {
30 transport: T,
31 peer: PublicKey,
32}
33
34impl<T: Transport> PeerConnection<T> {
35 pub(crate) fn new(transport: T, peer: PublicKey) -> Self {
37 Self { transport, peer }
38 }
39
40 pub fn peer(&self) -> &PublicKey {
42 &self.peer
43 }
44
45 pub async fn send(
47 &self,
48 payload: &[u8],
49 options: &SendOptions,
50 ) -> Result<SendProgressTicket, T::Error> {
51 self.transport.send(&self.peer, payload, options).await
52 }
53}
54
55impl<M: crate::mac::MacBackend> PeerConnection<LocalNode<M>> {
56 fn add_receive_handler<F>(&self, handler: F) -> SubscriptionHandle
57 where
58 F: FnMut(&ReceivedPacketRef<'_>) -> bool + 'static,
59 {
60 self.transport
61 .state()
62 .borrow_mut()
63 .peer_subscriptions_mut(self.peer)
64 .receive_handlers
65 .insert(Box::new(handler))
66 }
67
68 pub fn on_receive<F>(&self, handler: F) -> Subscription
69 where
70 F: FnMut(&ReceivedPacketRef<'_>) -> bool + 'static,
71 {
72 let handle = self.add_receive_handler(handler);
73 let state = self.transport.state().clone();
74 let peer = self.peer;
75 Subscription::new(move || {
76 let mut state = state.borrow_mut();
77 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
78 return false;
79 };
80 entry.receive_handlers.remove(handle)
81 })
82 }
83
84 fn add_ack_received_handler<F>(&self, handler: F) -> SubscriptionHandle
85 where
86 F: FnMut(crate::SendToken) + 'static,
87 {
88 self.transport
89 .state()
90 .borrow_mut()
91 .peer_subscriptions_mut(self.peer)
92 .ack_received_handlers
93 .insert(Box::new(handler))
94 }
95
96 pub fn on_ack_received<F>(&self, handler: F) -> Subscription
97 where
98 F: FnMut(crate::SendToken) + 'static,
99 {
100 let handle = self.add_ack_received_handler(handler);
101 let state = self.transport.state().clone();
102 let peer = self.peer;
103 Subscription::new(move || {
104 let mut state = state.borrow_mut();
105 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
106 return false;
107 };
108 entry.ack_received_handlers.remove(handle)
109 })
110 }
111
112 fn add_ack_timeout_handler<F>(&self, handler: F) -> SubscriptionHandle
113 where
114 F: FnMut(crate::SendToken) + 'static,
115 {
116 self.transport
117 .state()
118 .borrow_mut()
119 .peer_subscriptions_mut(self.peer)
120 .ack_timeout_handlers
121 .insert(Box::new(handler))
122 }
123
124 pub fn on_ack_timeout<F>(&self, handler: F) -> Subscription
125 where
126 F: FnMut(crate::SendToken) + 'static,
127 {
128 let handle = self.add_ack_timeout_handler(handler);
129 let state = self.transport.state().clone();
130 let peer = self.peer;
131 Subscription::new(move || {
132 let mut state = state.borrow_mut();
133 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
134 return false;
135 };
136 entry.ack_timeout_handlers.remove(handle)
137 })
138 }
139
140 pub fn on_pfs_established<F>(&self, handler: F) -> Subscription
141 where
142 F: FnMut() + 'static,
143 {
144 let handle = self
145 .transport
146 .state()
147 .borrow_mut()
148 .peer_subscriptions_mut(self.peer)
149 .pfs_established_handlers
150 .insert(Box::new(handler));
151 let state = self.transport.state().clone();
152 let peer = self.peer;
153 Subscription::new(move || {
154 let mut state = state.borrow_mut();
155 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
156 return false;
157 };
158 entry.pfs_established_handlers.remove(handle)
159 })
160 }
161
162 pub fn on_pfs_ended<F>(&self, handler: F) -> Subscription
163 where
164 F: FnMut() + 'static,
165 {
166 let handle = self
167 .transport
168 .state()
169 .borrow_mut()
170 .peer_subscriptions_mut(self.peer)
171 .pfs_ended_handlers
172 .insert(Box::new(handler));
173 let state = self.transport.state().clone();
174 let peer = self.peer;
175 Subscription::new(move || {
176 let mut state = state.borrow_mut();
177 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
178 return false;
179 };
180 entry.pfs_ended_handlers.remove(handle)
181 })
182 }
183
184 pub fn on_pong<F>(&self, handler: F) -> Subscription
185 where
186 F: FnMut(u64) + 'static,
187 {
188 let handle = self
189 .transport
190 .state()
191 .borrow_mut()
192 .peer_subscriptions_mut(self.peer)
193 .pong_handlers
194 .insert(Box::new(handler));
195 let state = self.transport.state().clone();
196 let peer = self.peer;
197 Subscription::new(move || {
198 let mut state = state.borrow_mut();
199 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
200 return false;
201 };
202 entry.pong_handlers.remove(handle)
203 })
204 }
205
206 pub fn on_ping_timeout<F>(&self, handler: F) -> Subscription
207 where
208 F: FnMut() + 'static,
209 {
210 let handle = self
211 .transport
212 .state()
213 .borrow_mut()
214 .peer_subscriptions_mut(self.peer)
215 .ping_timeout_handlers
216 .insert(Box::new(handler));
217 let state = self.transport.state().clone();
218 let peer = self.peer;
219 Subscription::new(move || {
220 let mut state = state.borrow_mut();
221 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
222 return false;
223 };
224 entry.ping_timeout_handlers.remove(handle)
225 })
226 }
227
228 pub async fn ping(
243 &self,
244 extra_bytes: usize,
245 options: &SendOptions,
246 timeout_ms: u64,
247 ) -> Result<crate::ticket::SendProgressTicket, NodeError<M>> {
248 let mut nonce_bytes = [0u8; 2];
250 self.transport.fill_random(&mut nonce_bytes).await;
251 let nonce = u16::from_be_bytes(nonce_bytes);
252
253 let total = (2 + extra_bytes).min(60);
255 let mut data = alloc::vec![0xA5u8; total];
256 data[0] = nonce_bytes[0];
257 data[1] = nonce_bytes[1];
258
259 let cmd = crate::mac_command::MacCommand::EchoRequest { data: &data };
264 let mut buf = [0u8; 128];
265 buf[0] = umsh_core::PayloadType::MacCommand as u8;
266 let n = crate::mac_command::encode(&cmd, &mut buf[1..])?;
267 let n = n + 1;
268
269 let sent_at_ms = self.transport.now_ms().await;
271 self.transport
272 .record_ping(nonce, self.peer, sent_at_ms, sent_at_ms + timeout_ms);
273
274 let opts = options.clone().with_ack_requested(false);
279 self.send(&buf[..n], &opts).await
280 }
281
282 pub async fn request_identity(
292 &self,
293 options: &SendOptions,
294 ) -> Result<SendProgressTicket, NodeError<M>> {
295 let mut nonce_bytes = [0u8; 4];
296 self.transport.fill_random(&mut nonce_bytes).await;
297 let nonce = u32::from_be_bytes(nonce_bytes);
298
299 let opts_block = crate::mac_command::IdentityRequestBuilder::new()
300 .nonce(nonce)?
301 .build();
302 let cmd = crate::mac_command::MacCommand::IdentityRequest {
303 options: &opts_block,
304 };
305 let mut buf = [0u8; 128];
306 buf[0] = umsh_core::PayloadType::MacCommand as u8;
307 let n = crate::mac_command::encode(&cmd, &mut buf[1..])? + 1;
308
309 self.send(&buf[..n], options).await
310 }
311
312 pub async fn route(&self) -> Option<umsh_mac::CachedRoute> {
314 self.transport.peer_route(&self.peer).await
315 }
316
317 pub async fn clear_route(&self) -> bool {
319 self.transport.clear_peer_route(&self.peer).await
320 }
321
322 #[cfg(feature = "software-crypto")]
323 pub async fn request_pfs(
324 &self,
325 duration_minutes: u16,
326 options: &SendOptions,
327 ) -> Result<SendProgressTicket, NodeError<M>> {
328 self.transport
329 .request_pfs(&self.peer, duration_minutes, options)
330 .await
331 }
332
333 #[cfg(feature = "software-crypto")]
334 pub async fn end_pfs(&self, options: &SendOptions) -> Result<(), NodeError<M>> {
335 self.transport.end_pfs(&self.peer, options).await
336 }
337
338 #[cfg(feature = "software-crypto")]
339 pub async fn pfs_status(&self) -> Result<crate::node::PfsStatus, NodeError<M>> {
340 self.transport.pfs_status(&self.peer).await
341 }
342}