bacnet_network/router/local_control.rs
1//! The router's own network-control consumer (#1175).
2//!
3//! Most network messages a router receives are for its routing table, and it
4//! handles them inline. A Reject-Message-To-Network addressed to the router
5//! itself also answers something the router's own side sent, so besides
6//! updating the table it goes to the opt-in stream that
7//! [`RouterOptions::network_control_receiver`](super::RouterOptions::network_control_receiver)
8//! asks for. Its records are the [`ReceivedNetworkControl`] a non-router
9//! [`NetworkLayer`](crate::layer::NetworkLayer) hands its own consumer.
10
11use std::sync::Arc;
12use std::sync::atomic::{AtomicU64, Ordering};
13
14use bacnet_encoding::npdu::Npdu;
15use bacnet_transport::port::ReceivedNpdu;
16
17use super::BACnetRouter;
18use crate::layer::{AdmissionSender, ReceivedNetworkControl, next_ingress_sequence};
19
20/// Where network controls addressed to this router go.
21#[derive(Default)]
22pub(super) struct LocalControl {
23 /// The opted-in consumer, if any.
24 tx: Option<AdmissionSender<ReceivedNetworkControl>>,
25 /// Source of [`ReceivedNetworkControl::ingress_sequence`].
26 ingress_sequence: Arc<AtomicU64>,
27}
28
29impl LocalControl {
30 pub(super) fn new(
31 tx: Option<AdmissionSender<ReceivedNetworkControl>>,
32 ingress_sequence: Arc<AtomicU64>,
33 ) -> Self {
34 Self {
35 tx,
36 ingress_sequence,
37 }
38 }
39
40 /// Whether a consumer asked for these controls, so the dispatch reads
41 /// the control's header only for one.
42 pub(super) fn wanted(&self) -> bool {
43 self.tx.is_some()
44 }
45
46 /// Offer the control `received` carries to the consumer: `header` is
47 /// its control information, which the dispatch read from the engine's
48 /// view with [`Npdu::header_from`], and its data starts at `offset` in
49 /// the frame. The frame isn't decoded again, and the data shares its
50 /// buffer. Like the router's local APDU queue, a full or closed
51 /// consumer drops the arriving control and never holds up routing.
52 pub(super) fn deliver(&self, mut header: Npdu, offset: usize, received: &ReceivedNpdu) {
53 let Some(tx) = self.tx.as_ref() else {
54 return;
55 };
56 header.payload = received.npdu.slice(offset..);
57 let _ = tx.try_send(ReceivedNetworkControl {
58 npdu: header,
59 source_mac: received.source_mac.clone(),
60 link_layer_group: received.link_layer_group,
61 data_attributes: received.data_attributes.clone(),
62 provenance: received.provenance.clone(),
63 ingress_sequence: next_ingress_sequence(&self.ingress_sequence),
64 });
65 }
66}
67
68impl BACnetRouter {
69 /// Sequence assigned to the most recent control offered to the receiver
70 /// from [`RouterOptions::network_control_receiver`](super::RouterOptions::network_control_receiver)
71 /// or [`RouterOptions::network_control_receiver_with_admission`](super::RouterOptions::network_control_receiver_with_admission),
72 /// including one the receiver dropped. Saturates at `u64::MAX`.
73 pub fn network_control_ingress_sequence(&self) -> u64 {
74 self.network_control_ingress_sequence.load(Ordering::SeqCst)
75 }
76}