Skip to main content

bacnet_network/router/
originate.rs

1//! The router's own application requests, sent through its engine (#1699).
2
3use std::fmt;
4
5use bacnet_router_core::router::{OriginateError, Request};
6
7use super::actions::drain;
8use super::BACnetRouter;
9
10/// Why [`BACnetRouter::originate`] queued nothing.
11///
12/// It is `#[non_exhaustive]`, so a new reason isn't a breaking change: a
13/// `match` needs a wildcard arm.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[non_exhaustive]
16pub enum OriginateFailure {
17    /// The engine refused the request, for this reason.
18    Refused(OriginateError),
19    /// The egress port's queue was full, or closing; the refusal is
20    /// counted in [`Counters::refused`](super::Counters::refused).
21    QueueFull,
22    /// The router has stopped.
23    Stopped,
24}
25
26impl fmt::Display for OriginateFailure {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        match self {
29            Self::Refused(error) => error.fmt(f),
30            Self::QueueFull => f.write_str("the egress port's queue refused the request"),
31            Self::Stopped => f.write_str("the router has stopped"),
32        }
33    }
34}
35
36impl std::error::Error for OriginateFailure {
37    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
38        match self {
39            Self::Refused(error) => Some(error),
40            _ => None,
41        }
42    }
43}
44
45impl From<OriginateError> for OriginateFailure {
46    fn from(error: OriginateError) -> Self {
47        Self::Refused(error)
48    }
49}
50
51impl BACnetRouter {
52    /// Send a request from the router's own application to another
53    /// network, routed by its table like any other traffic (#1699).
54    ///
55    /// The engine picks the route and writes the NPDU: toward the next
56    /// router with the DNET, DADR and a full hop count, or onto a directly
57    /// attached network to the DADR, with the source address
58    /// [`Request::source`] selects. By default that is the router's
59    /// address on the egress port, so a reply comes back to that port and
60    /// reaches the router's local APDU receiver as any APDU for the router
61    /// does. The NPDU goes on the egress port's queue at the request's
62    /// network priority, as any routed send does, with no data attributes.
63    /// `Ok` means it was queued, not sent.
64    ///
65    /// Synchronous: it takes the engine's lock for the call and its drain,
66    /// like a port's dispatch of one frame, and never waits. A network the
67    /// table lacks is refused with [`OriginateError::NoRoute`], and a
68    /// Who-Is-Router for it goes out on every port, once per cooldown;
69    /// retry once it is learned. After [`Self::stop`] every call fails with
70    /// [`OriginateFailure::Stopped`].
71    ///
72    /// A global broadcast (DNET 0xFFFF) has no path here yet and is refused
73    /// with [`OriginateError::ReservedNetwork`]: send a remote broadcast
74    /// (an empty DADR) to each network the router reaches instead, its own
75    /// ports' networks included, where each leaves as that port's local
76    /// broadcast.
77    pub fn originate(&self, request: &Request<'_>) -> Result<(), OriginateFailure> {
78        // Only the dispatch tasks own the queues: once `stop` has ended
79        // them, nothing is left to send on.
80        let outputs = self.outputs.upgrade().ok_or(OriginateFailure::Stopped)?;
81        let shared = &*self.shared;
82        let now = shared.engine.now();
83        let mut router = shared.engine.lock();
84        let result = router.originate(request, now);
85        // A search for a missing route is polled too. Only the request's
86        // own refusal fails it: a Router-Busy or search refused in the
87        // same drain doesn't.
88        let drained = drain(&mut router, &[], &outputs.send_txs, now);
89        drop(router);
90        result?;
91        if drained.originate_refused {
92            Err(OriginateFailure::QueueFull)
93        } else {
94            Ok(())
95        }
96    }
97}