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