liminal_server/link_udp/
streams.rs1use super::{Arrival, Datagram, LinkCancellation, Links, UdpCarrier, UdpError, send_datagram};
3use std::sync::{Arc, mpsc};
4use std::time::Instant;
5
6#[derive(Debug)]
8pub struct Inbox(mpsc::Receiver<Arrival>, LinkCancellation);
9impl Inbox {
10 pub(crate) fn cancellation(&self) -> LinkCancellation {
11 self.1.clone()
12 }
13 pub(crate) fn refuse_unsolicited(&self) -> Result<(), UdpError> {
14 match self.0.try_recv() {
15 Err(mpsc::TryRecvError::Empty) => Ok(()),
16 Err(mpsc::TryRecvError::Disconnected) => Err(UdpError::Stopped),
17 Ok(_) => Err(UdpError::InvalidDatagram),
18 }
19 }
20 pub fn receive(&self) -> Result<Datagram, UdpError> {
24 self.0
25 .recv()
26 .map_err(|_| UdpError::Stopped)?
27 .map(|(datagram, _)| datagram)
28 }
29 pub fn until(&self, deadline: Instant) -> Result<Datagram, UdpError> {
33 self.0
34 .recv_timeout(deadline.saturating_duration_since(Instant::now()))
35 .map_err(|error| match error {
36 mpsc::RecvTimeoutError::Timeout => UdpError::Deadline,
37 mpsc::RecvTimeoutError::Disconnected => UdpError::Stopped,
38 })?
39 .map(|(datagram, _)| datagram)
40 }
41}
42impl UdpCarrier {
43 pub fn subscribe(&self, index: u32) -> Result<Inbox, UdpError> {
47 let mut incoming = self
48 .incoming
49 .as_ref()
50 .ok_or(UdpError::Stopped)?
51 .lock()
52 .map_err(|_| UdpError::Poisoned)?;
53 let links = self.links.lock().map_err(|_| UdpError::Poisoned)?;
54 let link = links.get(&index).ok_or(UdpError::UnknownIndex)?;
55 let mut route = link
56 .acknowledgements
57 .route
58 .lock()
59 .map_err(|_| UdpError::Poisoned)?;
60 if link.acknowledgements.is_cancelled() {
61 return Err(UdpError::Stopped);
62 }
63 if route.is_some() {
64 return Err(UdpError::AcknowledgementsAlreadyWatched);
65 }
66 let (sender, receiver) = mpsc::sync_channel(64);
67 *route = Some(sender.clone());
68 let cancellation = LinkCancellation::new(Arc::clone(&link.acknowledgements));
69 let mut parked = std::mem::take(&mut incoming.parked);
70 for _ in 0..64 {
71 match incoming.receiver.try_recv() {
72 Ok(arrival) => parked.push_back(arrival),
73 Err(mpsc::TryRecvError::Empty | mpsc::TryRecvError::Disconnected) => break,
74 }
75 }
76 while let Some(arrival) = parked.pop_front() {
77 match arrival {
78 Ok((datagram, endpoint)) if datagram.receiver_index == index => {
79 if datagram.kind == 3 {
80 sender
81 .try_send(Ok((datagram, endpoint)))
82 .map_err(|_| UdpError::ObservationInProgress)?;
83 }
84 }
85 other => incoming.parked.push_back(other),
86 }
87 }
88 drop(route);
89 drop(links);
90 drop(incoming);
91 Ok(Inbox(receiver, cancellation))
92 }
93 pub fn reply(&self, index: u32, request: u64, plain: &[u8]) -> Result<(), UdpError> {
97 let datagram = self.seal(index, plain)?;
98 let mut links = self.links.lock().map_err(|_| UdpError::Poisoned)?;
99 let link = links.get_mut(&index).ok_or(UdpError::UnknownIndex)?;
100 let cached = link
101 .cached_acks
102 .iter_mut()
103 .find(|ack| ack.counter == request)
104 .ok_or(UdpError::InvalidAck)?;
105 cached.receipt = Some(datagram.clone());
106 let endpoint = link.endpoint;
107 drop(links);
108 send_datagram(self.socket.as_ref(), endpoint, &datagram)
109 }
110}
111pub(super) fn route_arrival(
112 links: &Links,
113 index: Option<u32>,
114 arrival: Arrival,
115 outgoing: &mpsc::SyncSender<Arrival>,
116) -> Result<bool, UdpError> {
117 let links = links.lock().map_err(|_| UdpError::Poisoned)?;
119 let route = index
120 .and_then(|index| links.get(&index))
121 .map(|link| {
122 link.acknowledgements
123 .route
124 .lock()
125 .map_err(|_| UdpError::Poisoned)
126 })
127 .transpose()?;
128 if let Some(sender) = route.as_ref().and_then(|route| route.as_ref()) {
129 match arrival {
130 Ok((datagram, endpoint)) if datagram.kind == 3 => {
131 match sender.try_send(Ok((datagram, endpoint))) {
132 Ok(()) => {}
133 Err(mpsc::TrySendError::Full(_)) => tracing::warn!(
134 "udp_application_queue_full; crossing must recover at its deadline"
135 ),
136 Err(mpsc::TrySendError::Disconnected(_)) => {
137 tracing::debug!("UDP application reader ended");
138 }
139 }
140 }
141 Ok(_) => {}
142 Err(error) => tracing::warn!(%error,"UDP application datagram refused"),
143 }
144 drop(route);
145 drop(links);
146 return Ok(true);
147 }
148 drop(route);
149 let result = match outgoing.try_send(arrival) {
150 Ok(()) => true,
151 Err(mpsc::TrySendError::Full(_)) => {
152 tracing::warn!("udp_open_queue_full; opening must refuse at its deadline");
153 true
154 }
155 Err(mpsc::TrySendError::Disconnected(_)) => false,
156 };
157 drop(links);
158 Ok(result)
159}