1use crate::layer::ReceivedApdu;
3use bacnet_encoding::npdu::{Npdu, NpduAddress, encode_npdu};
4use bacnet_npdu::NetworkPriority;
5use bacnet_transport::port::{DirectResponse, TransportProvenance};
6use bacnet_types::error::Error;
7use bytes::{Bytes, BytesMut};
8
9#[cfg(test)]
10#[path = "response_encode_tests.rs"]
11mod encode_tests;
12
13#[cfg(test)]
14#[path = "response_budget_tests.rs"]
15mod budget_tests;
16
17#[cfg(test)]
18mod size_tests {
19 use super::*;
20 use bacnet_transport::port::ReceivedNpdu;
21
22 #[test]
28 fn received_envelopes_and_routes_stay_small() {
29 let sizes = [
30 ("ReceivedApdu", std::mem::size_of::<ReceivedApdu>(), 208),
31 ("ReceivedNpdu", std::mem::size_of::<ReceivedNpdu>(), 160),
32 ("ResponseRoute", std::mem::size_of::<ResponseRoute>(), 64),
33 ];
34 for (name, size, limit) in sizes {
35 assert!(size <= limit, "{name} is {size} bytes, over {limit}");
36 }
37 }
38}
39
40#[derive(Clone, Debug)]
47pub struct ResponseRoute {
48 provenance: TransportProvenance,
49 direct: Option<DirectResponse>,
50 router: Option<crate::router::RouterResponse>,
51}
52
53impl ResponseRoute {
54 pub fn new(provenance: TransportProvenance, direct: Option<DirectResponse>) -> Self {
57 Self {
58 provenance,
59 direct,
60 router: None,
61 }
62 }
63
64 pub fn unverified() -> Self {
66 Self::new(TransportProvenance::unverified(), None)
67 }
68
69 pub fn provenance(&self) -> TransportProvenance {
71 self.provenance.clone()
72 }
73
74 pub fn max_apdu_length(
79 &self,
80 apdu_limit: u16,
81 destination: Option<&NpduAddress>,
82 ) -> Result<u16, Error> {
83 let direct = self.direct()?;
84 let header = self.header_len(destination)?;
85 let mut npdu_limit = usize::MAX;
86 if let Some(router) = &self.router {
87 npdu_limit = usize::from(router.max_npdu());
88 }
89 if let Some(direct) = direct {
90 npdu_limit = npdu_limit.min(direct.max_npdu_length());
91 }
92 Ok(usize::from(apdu_limit).min(npdu_limit.saturating_sub(header)) as u16)
93 }
94
95 fn header_len(&self, destination: Option<&NpduAddress>) -> Result<usize, Error> {
99 let mut scratch = [0u8; 64];
100 let written = match &self.router {
101 Some(router) => router
102 .plan()
103 .npdu(&[], false, NetworkPriority::Normal)
104 .encode_into(&mut scratch),
105 None => {
106 check_response_destination(destination)?;
107 response_npdu(&[], destination, false, NetworkPriority::Normal)
108 .encode_into(&mut scratch)
109 }
110 };
111 match written {
112 Ok(len) => Ok(len),
113 Err(_) => self
114 .encode(&[], destination, false, NetworkPriority::Normal)
115 .map(|header| header.len()),
116 }
117 }
118
119 pub fn requires_direct_response(&self) -> bool {
122 self.provenance.is_direct_peer() || self.direct.is_some()
123 }
124
125 pub fn requires_original_route(&self) -> bool {
127 self.router.is_some() || self.provenance.is_direct_peer() || self.direct.is_some()
128 }
129
130 pub fn same_origin(&self, other: &Self) -> bool {
135 self.provenance == other.provenance
136 && match (&self.router, &other.router) {
137 (Some(a), Some(b)) => a.same_origin(b),
138 (None, None) => true,
139 _ => false,
140 }
141 }
142
143 pub fn encode_reply_npdu(
147 &self,
148 apdu: &[u8],
149 destination: Option<&NpduAddress>,
150 expecting_reply: bool,
151 priority: NetworkPriority,
152 ) -> Result<BytesMut, Error> {
153 if self.direct()?.is_some() {
154 return Err(Error::Encoding(
155 "a direct response requires its original socket".into(),
156 ));
157 }
158 if let Some(router) = &self.router {
159 router.check()?;
160 }
161 self.encode(apdu, destination, expecting_reply, priority)
162 }
163
164 pub(crate) fn router(&self) -> Option<&crate::router::RouterResponse> {
165 self.router.as_ref()
166 }
167
168 pub(crate) fn encode(
170 &self,
171 apdu: &[u8],
172 destination: Option<&NpduAddress>,
173 expecting_reply: bool,
174 priority: NetworkPriority,
175 ) -> Result<BytesMut, Error> {
176 if let Some(router) = &self.router {
177 let npdu = router.plan().npdu(apdu, expecting_reply, priority);
178 let mut encoded = BytesMut::zeroed(npdu.encoded_len());
179 npdu.encode_into(&mut encoded)
180 .map_err(|error| Error::Encoding(error.to_string()))?;
181 return Ok(encoded);
182 }
183 encode_response_npdu(apdu, destination, expecting_reply, priority)
184 }
185
186 pub(crate) fn direct(&self) -> Result<Option<&DirectResponse>, bacnet_types::error::Error> {
187 match (self.provenance.direct_sc_identity(), self.direct.as_ref()) {
188 (Some(identity), Some(route)) if identity == route.identity() => Ok(Some(route)),
189 (None, None) => Ok(None),
190 _ => Err(bacnet_types::error::Error::Transport(std::io::Error::new(
191 std::io::ErrorKind::PermissionDenied,
192 "missing or mismatched original direct response capability",
193 ))),
194 }
195 }
196}
197
198impl ReceivedApdu {
199 pub fn set_response_route(&mut self, route: ResponseRoute) {
201 self.provenance = route.provenance;
202 self.direct_response = route.direct;
203 self.router_response = route.router;
204 }
205
206 pub fn response_route(&self) -> ResponseRoute {
208 ResponseRoute {
209 provenance: self.provenance.clone(),
210 direct: self.direct_response.clone(),
211 router: self.router_response.clone(),
212 }
213 }
214}
215
216pub(crate) fn encode_response_npdu(
218 apdu: &[u8],
219 destination: Option<&NpduAddress>,
220 expecting_reply: bool,
221 priority: NetworkPriority,
222) -> Result<BytesMut, Error> {
223 check_response_destination(destination)?;
224 encode_checked_response_npdu(apdu, destination, expecting_reply, priority)
225}
226
227pub(crate) fn check_response_destination(destination: Option<&NpduAddress>) -> Result<(), Error> {
229 match destination {
230 Some(destination) => crate::layer::check_destination(
231 destination.network,
232 "pass no destination (no DNET) for a local peer",
233 ),
234 None => Ok(()),
235 }
236}
237
238pub(crate) fn encode_checked_response_npdu(
240 apdu: &[u8],
241 destination: Option<&NpduAddress>,
242 expecting_reply: bool,
243 priority: NetworkPriority,
244) -> Result<BytesMut, Error> {
245 let npdu = response_npdu(apdu, destination, expecting_reply, priority);
248 let mut encoded = BytesMut::zeroed(npdu.encoded_len());
249 if npdu.encode_into(&mut encoded).is_ok() {
250 return Ok(encoded);
251 }
252 let npdu = Npdu {
254 destination: destination.cloned(),
255 expecting_reply,
256 priority,
257 payload: Bytes::copy_from_slice(apdu),
258 ..Npdu::default()
259 };
260 let mut encoded = BytesMut::new();
261 encode_npdu(&mut encoded, &npdu)?;
262 Ok(encoded)
263}
264
265fn response_npdu<'a>(
267 apdu: &'a [u8],
268 destination: Option<&'a NpduAddress>,
269 expecting_reply: bool,
270 priority: NetworkPriority,
271) -> bacnet_npdu::Npdu<'a> {
272 let mut npdu = bacnet_npdu::Npdu::apdu(apdu);
273 npdu.destination = destination.map(|destination| bacnet_npdu::Address {
274 network: destination.network,
275 mac: &destination.mac_address,
276 });
277 npdu.expecting_reply = expecting_reply;
278 npdu.priority = priority;
279 npdu
280}