bacnet_bip_core/node/counters.rs
1//! What a [`Node`](super::Node) counts, drained by
2//! [`Node::take_counters`](super::Node::take_counters) into the host's own
3//! totals.
4
5use core::net::SocketAddrV4;
6
7use bacnet_bip_codec::BvlcResultCode;
8
9use super::exchange::Operation;
10use super::registration::AttemptOutcome;
11
12/// One operation's exchanges since the counters were last taken, manual
13/// and automatic alike. Counts saturate.
14#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
15#[non_exhaustive]
16pub struct ExchangeCounters {
17 /// Requests the caller reported sent.
18 pub sent: u32,
19 /// Matched, accepted table ACKs.
20 pub acknowledgements: u32,
21 /// Matched, well-formed BVLC-Results: success or the operation's NAK.
22 pub results: u32,
23 /// The newest of those results' codes.
24 pub last_result: Option<BvlcResultCode>,
25 /// Sent requests whose response timeout passed unanswered.
26 pub timeouts: u32,
27 /// Requests refused because their exchange's slot was taken.
28 pub busy: u32,
29 /// Requests whose send the caller reported failed.
30 pub local_errors: u32,
31 /// Malformed responses from the peer of a live exchange of this
32 /// operation, counted against the first such exchange in slot order.
33 pub malformed_responses: u32,
34}
35
36/// A Register-Foreign-Device attempt, manual or automatic, as it stands.
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38#[non_exhaustive]
39pub struct RegisterAttempt {
40 /// The BBMD it went to.
41 pub bbmd: SocketAddrV4,
42 /// The time-to-live it asked for.
43 pub ttl: u16,
44 /// What it came to.
45 pub outcome: AttemptOutcome,
46 /// The result code that answered it, when one did.
47 pub result: Option<BvlcResultCode>,
48}
49
50/// Everything a node counts, since the counters were last taken. Counts
51/// saturate; the `last_` fields hold the newest value seen since, if any.
52#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
53#[non_exhaustive]
54pub struct NodeCounters {
55 /// Read-Broadcast-Distribution-Table exchanges.
56 pub read_bdt: ExchangeCounters,
57 /// Write-Broadcast-Distribution-Table exchanges.
58 pub write_bdt: ExchangeCounters,
59 /// Read-Foreign-Device-Table exchanges.
60 pub read_fdt: ExchangeCounters,
61 /// Delete-Foreign-Device-Table-Entry exchanges.
62 pub delete_fdt_entry: ExchangeCounters,
63 /// Register-Foreign-Device exchanges.
64 pub register_foreign_device: ExchangeCounters,
65 /// Register-Foreign-Device attempts admitted, manual and automatic.
66 pub registration_attempts: u32,
67 /// Of those, answered with success.
68 pub registrations_accepted: u32,
69 /// Of those, answered with the Register-Foreign-Device NAK.
70 pub registrations_refused: u32,
71 /// The newest attempt, whenever it changed.
72 pub last_registration_attempt: Option<RegisterAttempt>,
73 /// Well-formed responses that matched no live exchange.
74 pub unmatched_responses: u32,
75 /// Of those, the ones within one response timeout of an exchange they
76 /// fit ending.
77 pub late_responses: u32,
78 /// The newest unmatched BVLC-Result's code.
79 pub last_unmatched_result: Option<BvlcResultCode>,
80 /// Malformed responses, matched or not: refused by the codec or by
81 /// [`Policy::accept_table`](super::Policy::accept_table).
82 pub malformed_responses: u32,
83 /// Distribute-Broadcast-To-Network NAKs from the foreign device's own
84 /// BBMD, taken as a sign it lost the registration: with
85 /// [`Retry::Backoff`](super::Retry::Backoff) only.
86 pub renewal_hints: u32,
87 /// Leases that ended with nothing newer proven.
88 pub lapses: u32,
89 /// Broadcasts held for the first registration attempt.
90 pub broadcasts_held: u32,
91 /// Held broadcasts released when that attempt succeeded or went
92 /// unanswered.
93 pub broadcasts_released: u32,
94 /// Held broadcasts discarded when the BBMD refused that attempt.
95 pub broadcasts_discarded: u32,
96 /// Broadcasts refused because the hold was full.
97 pub broadcasts_hold_full: u32,
98 /// Broadcasts sent while no lease was live.
99 pub broadcasts_unregistered: u32,
100}
101
102impl NodeCounters {
103 /// The counters of `operation`'s exchanges.
104 #[must_use]
105 pub const fn exchange(&self, operation: Operation) -> &ExchangeCounters {
106 match operation {
107 Operation::ReadBdt => &self.read_bdt,
108 Operation::WriteBdt => &self.write_bdt,
109 Operation::ReadFdt => &self.read_fdt,
110 Operation::DeleteFdtEntry => &self.delete_fdt_entry,
111 Operation::RegisterForeignDevice => &self.register_foreign_device,
112 }
113 }
114
115 pub(crate) fn exchange_mut(&mut self, operation: Operation) -> &mut ExchangeCounters {
116 match operation {
117 Operation::ReadBdt => &mut self.read_bdt,
118 Operation::WriteBdt => &mut self.write_bdt,
119 Operation::ReadFdt => &mut self.read_fdt,
120 Operation::DeleteFdtEntry => &mut self.delete_fdt_entry,
121 Operation::RegisterForeignDevice => &mut self.register_foreign_device,
122 }
123 }
124}
125
126/// Add one, saturating.
127pub(crate) fn bump(counter: &mut u32) {
128 *counter = counter.saturating_add(1);
129}
130
131/// Add `count`, saturating.
132pub(crate) fn add(counter: &mut u32, count: u16) {
133 *counter = counter.saturating_add(u32::from(count));
134}