Skip to main content

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::atomic::{AtomicU64, Ordering};
12use std::sync::Arc;
13
14use bacnet_encoding::npdu::decode_npdu;
15use bacnet_transport::port::ReceivedNpdu;
16
17use super::BACnetRouter;
18use crate::layer::{next_ingress_sequence, AdmissionSender, ReceivedNetworkControl};
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    /// Offer the control `received` carries to the consumer. Like the
41    /// router's local APDU queue, a full or closed consumer drops the
42    /// arriving control and never holds up routing.
43    pub(super) fn deliver(&self, received: &ReceivedNpdu) {
44        let Some(tx) = self.tx.as_ref() else {
45            return;
46        };
47        // The engine parsed it already, and bacnet-encoding's decoder
48        // accepts exactly what the engine's view does.
49        let Ok(npdu) = decode_npdu(received.npdu.clone()) else {
50            return;
51        };
52        let _ = tx.try_send(ReceivedNetworkControl {
53            npdu,
54            source_mac: received.source_mac.clone(),
55            link_layer_group: received.link_layer_group,
56            data_attributes: received.data_attributes.clone(),
57            provenance: received.provenance,
58            ingress_sequence: next_ingress_sequence(&self.ingress_sequence),
59        });
60    }
61}
62
63impl BACnetRouter {
64    /// Sequence assigned to the most recent control offered to the receiver
65    /// from [`RouterOptions::network_control_receiver`](super::RouterOptions::network_control_receiver)
66    /// or [`RouterOptions::network_control_receiver_with_admission`](super::RouterOptions::network_control_receiver_with_admission),
67    /// including one the receiver dropped. Saturates at `u64::MAX`.
68    pub fn network_control_ingress_sequence(&self) -> u64 {
69        self.network_control_ingress_sequence.load(Ordering::SeqCst)
70    }
71}