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 Multi-Phase Protocol
50//!
51//! SET operations follow a multi-phase protocol as defined in RFC 3416, modeled
52//! after net-snmp's RESERVE/ACTION/COMMIT/FREE/UNDO phases:
53//!
54//! 1. **Test Phase**: [`MibHandler::test_set`] is called for ALL varbinds before any
55//! commits. If any test fails, [`MibHandler::free_set`] is called for all previously
56//! successful varbinds (in reverse order) to release resources, then the error is
57//! returned.
58//!
59//! 2. **Commit Phase**: [`MibHandler::commit_set`] is called for each varbind in order.
60//! If a commit fails, [`MibHandler::undo_set`] is called for all previously committed
61//! varbinds in reverse order.
62//!
63//! By default, handlers are read-only (returning [`SetResult::NotWritable`]).
64//! See [`MibHandler`] documentation for implementation details.
65//!
66//! # Using OidTable for GETNEXT
67//!
68//! For handlers with static or slowly-changing data, [`OidTable`] simplifies
69//! GETNEXT implementation by maintaining OIDs in sorted order:
70//!
71//! ```rust
72//! use async_snmp::handler::{MibHandler, RequestContext, GetResult, GetNextResult, OidTable, BoxFuture};
73//! use async_snmp::{Oid, Value, VarBind, oid};
74//!
75//! struct StaticHandler {
76//! table: OidTable<Value>,
77//! }
78//!
79//! impl StaticHandler {
80//! fn new() -> Self {
81//! let mut table = OidTable::new();
82//! table.insert(oid!(1, 3, 6, 1, 4, 1, 99999, 1, 0), Value::Integer(100));
83//! table.insert(oid!(1, 3, 6, 1, 4, 1, 99999, 2, 0), Value::OctetString("test".into()));
84//! Self { table }
85//! }
86//! }
87//!
88//! impl MibHandler for StaticHandler {
89//! fn get<'a>(&'a self, _ctx: &'a RequestContext, oid: &'a Oid) -> BoxFuture<'a, GetResult> {
90//! Box::pin(async move {
91//! self.table.get(oid)
92//! .cloned()
93//! .map(GetResult::Value)
94//! .unwrap_or(GetResult::NoSuchObject)
95//! })
96//! }
97//!
98//! fn get_next<'a>(&'a self, _ctx: &'a RequestContext, oid: &'a Oid) -> BoxFuture<'a, GetNextResult> {
99//! Box::pin(async move {
100//! self.table.get_next(oid)
101//! .map(|(o, v)| GetNextResult::Value(VarBind::new(o.clone(), v.clone())))
102//! .unwrap_or(GetNextResult::EndOfMibView)
103//! })
104//! }
105//! }
106
107mod context;
108mod oid_table;
109mod results;
110mod traits;
111
112pub use context::RequestContext;
113pub use oid_table::OidTable;
114pub use results::{GetNextResult, GetResult, Response, SetResult};
115pub use traits::{BoxFuture, MibHandler};
116
117/// Security model identifiers (RFC 3411).
118///
119/// Used to specify which SNMP version/security mechanism a mapping applies to.
120#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
121pub enum SecurityModel {
122 /// Wildcard for VACM matching (matches any model).
123 ///
124 /// Use this when the same mapping should apply regardless of SNMP version.
125 Any = 0,
126 /// SNMPv1.
127 V1 = 1,
128 /// SNMPv2c.
129 V2c = 2,
130 /// SNMPv3 User-based Security Model.
131 Usm = 3,
132}