Skip to main content

bacnet_server/server/
atomic_read_file_budget.rs

1//! Local AtomicReadFile request-count and logical service-ACK limits.
2use super::*;
3
4/// Positive local limits, independent of peer APDU size and segmentation.
5///
6/// Raw request counts are checked after existing handler validation, before the
7/// storage read. ACK bytes include every service field but exclude APDU/NPDU.
8/// This does not bound opaque storage work or its single owned read result;
9/// notably, a record-count limit is not a total storage-byte limit.
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11pub struct AtomicReadFileBudget {
12    /// Maximum raw requested stream octets (default 16384).
13    pub max_requested_stream_octets: usize,
14    /// Maximum raw requested records (default 256); the legacy read window remains.
15    pub max_requested_records: usize,
16    /// Maximum complete encoded service ACK bytes (default 16384).
17    pub max_service_ack_bytes: usize,
18}
19
20impl Default for AtomicReadFileBudget {
21    fn default() -> Self {
22        Self {
23            max_requested_stream_octets: 16384,
24            max_requested_records: 256,
25            max_service_ack_bytes: 16384,
26        }
27    }
28}
29
30impl AtomicReadFileBudget {
31    /// Reject zero configuration values before startup. Request counts may be zero.
32    pub fn validate(&self) -> Result<(), Error> {
33        for (name, value) in [
34            (
35                "atomic_read_file_max_requested_stream_octets",
36                self.max_requested_stream_octets,
37            ),
38            (
39                "atomic_read_file_max_requested_records",
40                self.max_requested_records,
41            ),
42            (
43                "atomic_read_file_max_service_ack_bytes",
44                self.max_service_ack_bytes,
45            ),
46        ] {
47            if value == 0 {
48                return Err(Error::Encoding(format!("{name} must be positive")));
49            }
50        }
51        Ok(())
52    }
53}
54
55impl<T: TransportPort + 'static> ServerBuilder<T> {
56    /// Set AtomicReadFile limits validated before transport startup.
57    pub fn atomic_read_file_budget(mut self, budget: AtomicReadFileBudget) -> Self {
58        self.config.atomic_read_file_budget = budget;
59        self
60    }
61}
62impl BipServerBuilder {
63    /// Set AtomicReadFile limits validated before transport startup.
64    pub fn atomic_read_file_budget(mut self, budget: AtomicReadFileBudget) -> Self {
65        self.config.atomic_read_file_budget = budget;
66        self
67    }
68}
69#[cfg(feature = "sc-tls")]
70impl ScServerBuilder {
71    /// Set AtomicReadFile limits validated before SC dialing.
72    pub fn atomic_read_file_budget(mut self, budget: AtomicReadFileBudget) -> Self {
73        self.config.atomic_read_file_budget = budget;
74        self
75    }
76}