pub type ReinitializeHandler = Arc<dyn Fn(&ReinitializeContext, &mut ObjectDatabase) -> Result<(), Error> + Send + Sync>;Expand description
Carries out a ReinitializeDevice request (Clause 16.4) on a full server or an endpoint session.
It is called only for a request that decoded, passed its password check
and names a state the clause defines. Ok(()) sends the SimpleACK; an
Err is sent in its place. The rules:
- Reply first, restart later. The SimpleACK goes out only after the
handler returns, so it must not restart the device inline. Accept or
refuse, prepare, and register the restart (or the backup or restore
step) with
ReinitializeContext::after_reply: Clause 16.4.2 has the device acknowledge the request before it shuts down. - The after-reply hook. It runs once the SimpleACK has been handed
to the transport (#1565). On MS/TP, handed off means queued: on the
reply channel or the transmit queue the frame still waits for the
token, so stopping the server or the port at once can drop the reply
there. Wait a short while (a few token rotations) first. It
never runs for a request answered
with an Error: the handler refused it or panicked, or the Network Port
activation below failed. Nor does it run when the reply could not be
handed over; the requester retries then.
BACnetServer::stopseals responses and aborts request tasks before joining them, so a restart path that stops the server starts from the hook, never from the handler. On a full server, accepted WARMSTART/COLDSTART ends DISABLE_INITIATION as the handler accepts (Clause 16.1.2), cancels its timer and resumes held COV, even if the reply later fails. - Be quick. It runs synchronously on a runtime worker with the object
database write-locked, so every other request waits for it. Hand slow
work, such as writing backup files, to a task. On an endpoint session a
blocking handler stalls the whole session. Never wait on another task
or thread from it (a
block_on, a channel receive, a join): if that work needs the database, the server deadlocks. - Database edits are raw. On a full server, changes made through the
&mut ObjectDatabaseskip whatBACnetServer::write_localadds around a write: the Object_Name uniqueness check, the COV fanout, the event pass, Schedule and Command follow-ups, and the Audit record. A change that needs them, as ACTIVATE_CHANGES work on Network Port or Device properties may, belongs inwrite_local, called after the reply from a task the handler schedules (for example by sending the change to the code that holds the server). - Network Port changes activate around it. For ACTIVATE_CHANGES or
WARMSTART the server first checks that the values written to Network
Port objects would still be taken
(
ObjectDatabase::check_network_port_changes), and refuses with PROPERTY / INVALID_CONFIGURATION_DATA (Clause 16.4.1.3.1) before the handler runs if not. Once the handler accepts, the server puts them into effect under the same lock and clears Changes_Pending (Clause 12.56.13), the transport’s BDT for one (ObjectDatabase::activate_network_port_changes): all or none per port, not across ports. A refusal then is answered the same way and leaves them pending. With no handler set, a registered port’s pending-activation rows refuse writes, since nothing could activate them. - Colour outputs on an in-process restart. A server start drives each
Color and Color Temperature output to its default (#1526). An
application that carries WARMSTART or COLDSTART out in process, without
building a new server, should do the same: call
start_outputon each colour object, which is safe to call again (a zero default then keeps the current value). It is a raw database edit, so it sends no COV notification of its own. - Audited once accepted. With Audit Reporters configured, an accepted
request (the handler accepted and any Network Port activation took)
records DEVICE_RESET, DEVICE_BACKUP or DEVICE_RESTORE from the
requester (Clause 19.6, Table 19-5, #1564); ACTIVATE_CHANGES, which
the table doesn’t list, and every refusal record nothing. Report a
reset made for the application’s own reasons with
BACnetServer::report_device_reset_local. - Gate the requester. Without
reinit_passwordany peer reaches the handler. NeitherMutationPolicynor theServerPolicycovers ReinitializeDevice, so check theReinitializeContextto restrict sources. - Refuse with
Error::protocol. Its class and code go back in an Error PDU, for example DEVICE / CONFIGURATION_IN_PROGRESS (Clause 16.4.1.3.1). Once the handler has run, the request may no longer be rejected (Clause 20.1.8), so anError::reject, or any error other than an Error PDU’sRemoteorStructured, is sent as SERVICES / OTHER. A panic is caught (with unwind builds) and also answered SERVICES / OTHER, since the handler may have partly acted.
Aliased Type§
pub struct ReinitializeHandler { /* private fields */ }