async_snmp/handler/
mod.rs

1//! Handler types and traits for SNMP MIB operations.
2//!
3//! This module provides the interface for implementing SNMP agent handlers:
4//!
5//! - [`MibHandler`] - Trait for handling GET, GETNEXT, and SET operations
6//! - [`RequestContext`] - Information about the incoming request
7//! - [`GetResult`], [`GetNextResult`], [`SetResult`] - Operation results
8//! - [`OidTable`] - Helper for implementing GETNEXT with sorted OID storage
9//!
10//! # Overview
11//!
12//! Handlers are registered with an [`Agent`](crate::agent::Agent) using a prefix OID.
13//! When the agent receives a request, it dispatches to the handler with the longest
14//! matching prefix. Each handler implements the [`MibHandler`] trait to respond to
15//! GET, GETNEXT, and optionally SET operations.
16//!
17//! # Basic Handler Example
18//!
19//! A minimal handler that provides two scalar values:
20//!
21//! ```rust
22//! use async_snmp::handler::{MibHandler, RequestContext, GetResult, GetNextResult, BoxFuture};
23//! use async_snmp::{Oid, Value, VarBind, oid};
24//!
25//! struct MyHandler;
26//!
27//! impl MibHandler for MyHandler {
28//!     fn get<'a>(&'a self, _ctx: &'a RequestContext, oid: &'a Oid) -> BoxFuture<'a, GetResult> {
29//!         Box::pin(async move {
30//!             if oid == &oid!(1, 3, 6, 1, 4, 1, 99999, 1, 0) {
31//!                 return GetResult::Value(Value::Integer(42));
32//!             }
33//!             GetResult::NoSuchObject
34//!         })
35//!     }
36//!
37//!     fn get_next<'a>(&'a self, _ctx: &'a RequestContext, oid: &'a Oid) -> BoxFuture<'a, GetNextResult> {
38//!         Box::pin(async move {
39//!             let my_oid = oid!(1, 3, 6, 1, 4, 1, 99999, 1, 0);
40//!             if oid < &my_oid {
41//!                 return GetNextResult::Value(VarBind::new(my_oid, Value::Integer(42)));
42//!             }
43//!             GetNextResult::EndOfMibView
44//!         })
45//!     }
46//! }
47//! ```
48//!
49//! # SET Operations and Two-Phase Commit
50//!
51//! SET operations follow a two-phase commit protocol as defined in RFC 3416:
52//!
53//! 1. **Test Phase**: [`MibHandler::test_set`] is called for ALL varbinds before any
54//!    commits. If any test fails, no changes are made and the appropriate error is
55//!    returned.
56//!
57//! 2. **Commit Phase**: [`MibHandler::commit_set`] is called for each varbind in order.
58//!    If a commit fails, [`MibHandler::undo_set`] is called for all previously committed
59//!    varbinds in reverse order.
60//!
61//! By default, handlers are read-only (returning [`SetResult::NotWritable`]).
62//! See [`MibHandler`] documentation for implementation details.
63//!
64//! # Using OidTable for GETNEXT
65//!
66//! For handlers with static or slowly-changing data, [`OidTable`] simplifies
67//! GETNEXT implementation by maintaining OIDs in sorted order:
68//!
69//! ```rust
70//! use async_snmp::handler::{MibHandler, RequestContext, GetResult, GetNextResult, OidTable, BoxFuture};
71//! use async_snmp::{Oid, Value, VarBind, oid};
72//!
73//! struct StaticHandler {
74//!     table: OidTable<Value>,
75//! }
76//!
77//! impl StaticHandler {
78//!     fn new() -> Self {
79//!         let mut table = OidTable::new();
80//!         table.insert(oid!(1, 3, 6, 1, 4, 1, 99999, 1, 0), Value::Integer(100));
81//!         table.insert(oid!(1, 3, 6, 1, 4, 1, 99999, 2, 0), Value::OctetString("test".into()));
82//!         Self { table }
83//!     }
84//! }
85//!
86//! impl MibHandler for StaticHandler {
87//!     fn get<'a>(&'a self, _ctx: &'a RequestContext, oid: &'a Oid) -> BoxFuture<'a, GetResult> {
88//!         Box::pin(async move {
89//!             self.table.get(oid)
90//!                 .cloned()
91//!                 .map(GetResult::Value)
92//!                 .unwrap_or(GetResult::NoSuchObject)
93//!         })
94//!     }
95//!
96//!     fn get_next<'a>(&'a self, _ctx: &'a RequestContext, oid: &'a Oid) -> BoxFuture<'a, GetNextResult> {
97//!         Box::pin(async move {
98//!             self.table.get_next(oid)
99//!                 .map(|(o, v)| GetNextResult::Value(VarBind::new(o.clone(), v.clone())))
100//!                 .unwrap_or(GetNextResult::EndOfMibView)
101//!         })
102//!     }
103//! }
104
105mod context;
106mod oid_table;
107mod results;
108mod traits;
109
110pub use context::RequestContext;
111pub use oid_table::OidTable;
112pub use results::{GetNextResult, GetResult, Response, SetResult};
113pub use traits::{BoxFuture, MibHandler};
114
115// Re-export SecurityModel from agent::vacm for convenience
116pub use crate::agent::vacm::SecurityModel;