bacnet_network/
layer_ingress.rs1use std::sync::Arc;
11use std::sync::atomic::AtomicU64;
12use std::task::{Context, Poll, ready};
13
14use bacnet_router_core::node::Node;
15use bacnet_transport::port::ReceivedNpdu;
16use bacnet_transport::warn_throttle::WarnThrottle;
17use std::sync::{Mutex, MutexGuard, PoisonError};
18
19use tokio::sync::mpsc;
20use tracing::debug;
21
22use super::receive::{self, Inbound, NodeTotals};
23use super::{AdmissionSender, ReceivedApdu, ReceivedNetworkControl, next_ingress_sequence};
24
25pub(crate) struct Ingress {
28 node: Node,
29 totals: Arc<NodeTotals>,
30 drop_warning: WarnThrottle,
31 controls: Option<AdmissionSender<ReceivedNetworkControl>>,
32 control_sequence: Arc<AtomicU64>,
33}
34
35impl std::fmt::Debug for Ingress {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.debug_struct("Ingress")
38 .field("controls", &self.controls.is_some())
39 .finish_non_exhaustive()
40 }
41}
42
43impl Ingress {
44 pub(crate) fn new(
45 totals: Arc<NodeTotals>,
46 controls: Option<AdmissionSender<ReceivedNetworkControl>>,
47 control_sequence: Arc<AtomicU64>,
48 ) -> Self {
49 Self {
50 node: Node::new(),
51 totals,
52 drop_warning: WarnThrottle::default(),
53 controls,
54 control_sequence,
55 }
56 }
57
58 pub(crate) fn take(&mut self, mut received: ReceivedNpdu) -> Option<ReceivedApdu> {
62 let frame = std::mem::take(&mut received.npdu);
64 let inbound = receive::admit(
65 &mut self.node,
66 &self.totals,
67 &self.drop_warning,
68 &received.source_mac,
69 received.link_layer_group,
70 frame,
71 self.controls.is_some(),
72 );
73 match inbound {
74 Inbound::Apdu {
75 apdu,
76 source_network,
77 is_group,
78 global_broadcast,
79 } => Some(ReceivedApdu {
80 router_response: None,
81 direct_response: received.direct_response,
82 apdu,
83 source_mac: received.source_mac,
84 ingress_network: None,
85 source_network,
86 link_layer_group: received.link_layer_group,
87 is_group,
88 global_broadcast,
89 data_attributes: received.data_attributes,
90 provenance: received.provenance,
91 reply_tx: received.reply_tx,
92 }),
93 Inbound::Control(Some(npdu)) => {
94 let tx = self.controls.as_ref()?;
95 let control = ReceivedNetworkControl {
96 npdu,
97 source_mac: received.source_mac,
98 link_layer_group: received.link_layer_group,
99 data_attributes: received.data_attributes,
100 provenance: received.provenance,
101 ingress_sequence: next_ingress_sequence(&self.control_sequence),
102 };
103 if let Err(mpsc::error::TrySendError::Closed(_)) = tx.try_send(control) {
104 self.controls = None;
105 debug!("Network-control receiver closed; resuming discard behavior");
106 }
107 None
108 }
109 Inbound::Control(None) | Inbound::Dropped => None,
110 }
111 }
112}
113
114pub(crate) type SharedNpduQueue = Arc<Mutex<mpsc::Receiver<ReceivedNpdu>>>;
118
119#[derive(Debug)]
135pub struct ApduReceiver {
136 npdu_rx: SharedNpduQueue,
137 ingress: Ingress,
138}
139
140impl ApduReceiver {
141 pub(crate) fn new(npdu_rx: SharedNpduQueue, ingress: Ingress) -> Self {
142 Self { npdu_rx, ingress }
143 }
144
145 fn queue(&self) -> MutexGuard<'_, mpsc::Receiver<ReceivedNpdu>> {
146 self.npdu_rx.lock().unwrap_or_else(PoisonError::into_inner)
147 }
148
149 pub async fn recv(&mut self) -> Option<ReceivedApdu> {
157 std::future::poll_fn(|cx| self.poll_recv(cx)).await
158 }
159
160 pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<ReceivedApdu>> {
162 let mut queue = self.npdu_rx.lock().unwrap_or_else(PoisonError::into_inner);
163 loop {
164 let Some(received) = ready!(queue.poll_recv(cx)) else {
165 return Poll::Ready(None);
166 };
167 if let Some(apdu) = self.ingress.take(received) {
168 return Poll::Ready(Some(apdu));
169 }
170 }
171 }
172
173 pub fn try_recv(&mut self) -> Result<ReceivedApdu, mpsc::error::TryRecvError> {
177 let mut queue = self.npdu_rx.lock().unwrap_or_else(PoisonError::into_inner);
178 loop {
179 let received = queue.try_recv()?;
180 if let Some(apdu) = self.ingress.take(received) {
181 return Ok(apdu);
182 }
183 }
184 }
185
186 pub fn close(&mut self) {
189 self.queue().close();
190 }
191
192 pub fn is_closed(&self) -> bool {
195 self.queue().is_closed()
196 }
197}
198
199pub(crate) fn close_queue(queue: &std::sync::Weak<Mutex<mpsc::Receiver<ReceivedNpdu>>>) {
202 if let Some(queue) = queue.upgrade() {
203 queue.lock().unwrap_or_else(PoisonError::into_inner).close();
204 }
205}