1+ using Microsoft . Extensions . Logging ;
2+ using SnmpSharpNet ;
3+
4+ namespace SampleApp ;
5+
6+ public class HighLevelSnmpClient ( UdpTarget target , IAgentParameters parameters , ILogger ? logger )
7+ {
8+ private const int SnmpTimeout = 4000 ;
9+
10+ public AsnType QuerySingleValueAsync ( Oid oid )
11+ {
12+ var pdu = new Pdu ( PduType . Get )
13+ {
14+ RequestId = Random . Shared . Next ( )
15+ } ;
16+
17+ pdu . VbList . Add ( oid ) ;
18+
19+ SnmpPacket ? result ;
20+ try
21+ {
22+ result = target . Request ( pdu , parameters ) ;
23+ if ( result == null )
24+ {
25+ logger ? . LogWarning ( "Unintelligible SNMP packet returned from {Address}" , target . Address ) ;
26+ throw new IOException ( $ "Unrecognized SNMP packet received from { target . Address } ") ;
27+ }
28+ }
29+ catch ( Exception e )
30+ {
31+ Log ( pdu , e ) ;
32+ logger ? . LogDebug ( "SNMP Get request failed for {Oid} on {Address}: {Exception}" , oid , target . Address , e ) ;
33+ throw new TimeoutException ( ) ;
34+ }
35+
36+ // ErrorStatus other than 0 is an error returned by
37+ // the Agent - see SnmpConstants for error definitions
38+ if ( result . Pdu . ErrorStatus != 0 )
39+ {
40+ // agent reported an error with the request
41+ logger ? . LogWarning ( "Error in SNMP Get reply. Error {Status} index {Index}" , result . Pdu . ErrorStatus ,
42+ result . Pdu . ErrorIndex ) ;
43+ throw new IOException ( $ "SNMP error: { result . Pdu . ErrorStatus } ({ result . Pdu . ErrorIndex } )") ;
44+ }
45+
46+ Log ( pdu , result ) ;
47+
48+ return result . Pdu . VbList . Single ( ) . Value ! ;
49+ }
50+
51+ public Vb [ ] QueryMultipleValues ( params IEnumerable < Oid > oids )
52+ {
53+ var pdu = new Pdu ( PduType . Get )
54+ {
55+ RequestId = Random . Shared . Next ( )
56+ } ;
57+ foreach ( var oid in oids )
58+ {
59+ pdu . VbList . Add ( oid ) ;
60+ }
61+
62+ SnmpPacket ? result ;
63+ var start = DateTime . UtcNow ;
64+ try
65+ {
66+ result = target . Request ( pdu , parameters ) ;
67+ if ( result == null )
68+ {
69+ logger ? . LogWarning ( "Unintelligible SNMP packet returned from {Address}" , target . Address ) ;
70+ throw new IOException ( $ "Unrecognized SNMP packet received from { target . Address } ") ;
71+ }
72+ }
73+ catch ( OperationCanceledException ex )
74+ {
75+ Log ( pdu , ex ) ;
76+ logger ? . LogWarning (
77+ "SnmpClient.QueryMultipleValuesAsync was cancelled. CancellationToken.IsCancellationRequested = {CancellationState}" ,
78+ false ) ;
79+ var end = DateTime . UtcNow - start ;
80+ if ( end . TotalMilliseconds >= SnmpTimeout )
81+ {
82+ throw new TimeoutException ( ) ;
83+ }
84+
85+ throw ;
86+ }
87+ catch ( Exception e )
88+ {
89+ Log ( pdu , e ) ;
90+ logger ? . LogDebug ( "SNMP Get multiple requests failed for {{ {PDU} }} on {Address}: {ErrorMessage}" , pdu ,
91+ target . Address ,
92+ e ) ;
93+ throw new TimeoutException ( ) ;
94+ }
95+
96+ // ErrorStatus other than 0 is an error returned by
97+ // the Agent - see SnmpConstants for error definitions
98+ if ( result . Pdu . ErrorStatus != 0 )
99+ {
100+ // agent reported an error with the request
101+ // However, in some case we get answers, but one of the values in the returned array is wrong.
102+ // Any errors in the returned values are handled by the caller of this function.
103+
104+ logger ? . LogWarning ( "Error in SNMP Get reply. Error {ErrorStatus} index {ErrorIndex}" ,
105+ result . Pdu . ErrorStatus , result . Pdu . ErrorIndex ) ;
106+ }
107+
108+ Log ( pdu , result ) ;
109+
110+ return result . Pdu . VbList . ToArray ( ) ;
111+ }
112+
113+ private void Log ( Pdu pdu , Exception exception )
114+ {
115+ logger ? . LogDebug ( "SNMP Error for {address}: {ErrorMessage}: {PDU}" , target . Address , exception . Message , pdu ) ;
116+ }
117+
118+ private void Log ( Pdu pdu , SnmpPacket snmpPacket )
119+ {
120+ logger ? . LogDebug ( "SNMP Response for {address}: {Status}:\n Request: {PDU}\n Response:{Packet}" , target . Address ,
121+ snmpPacket . Pdu . ErrorStatus == 0 ? "Good" : "Bad" , pdu , snmpPacket ) ;
122+ }
123+
124+ public IDictionary < Oid , AsnType ? > WalkTree ( Oid oid )
125+ {
126+ var treeData = new Dictionary < Oid , AsnType ? > ( ) ;
127+ var rootOid = oid ;
128+ var lastOid = ( Oid ) rootOid . Clone ( ) ;
129+
130+ var pdu = new Pdu ( PduType . GetBulk )
131+ {
132+ NonRepeaters = 0 ,
133+ MaxRepetitions = 30
134+ } ;
135+
136+ // Loop through results
137+ while ( lastOid is not null )
138+ {
139+ pdu . RequestId = Random . Shared . Next ( ) ;
140+ pdu . VbList . Clear ( ) ;
141+ pdu . VbList . Add ( lastOid ) ;
142+
143+ // Make SNMP request
144+ SnmpPacket ? result ;
145+ try
146+ {
147+ result = target . Request ( pdu , parameters ) ;
148+ }
149+ catch ( Exception e )
150+ {
151+ logger ? . LogDebug ( "SNMP request failed for {Root} on {Address}: {ErrorMessage}" , rootOid , target . Address ,
152+ e . Message ) ;
153+ throw ;
154+ }
155+
156+ // If result is null then agent didn't reply or we couldn't parse the reply.
157+ if ( result == null )
158+ {
159+ logger ? . LogWarning ( "No response received from SNMP agent." ) ;
160+ break ;
161+ }
162+
163+ // ErrorStatus other then 0 is an error returned by
164+ // the Agent - see SnmpConstants for error definitions
165+ if ( result . Pdu . ErrorStatus != 0 )
166+ {
167+ // agent reported an error with the request
168+ logger ? . LogWarning ( "Error in SNMP reply. Error {ErrorStatus} index {ErrorIndex}" ,
169+ result . Pdu . ErrorStatus , result . Pdu . ErrorIndex ) ;
170+ break ;
171+ }
172+
173+ // Walk through returned variable bindings
174+ foreach ( var vb in result . Pdu . VbList )
175+ {
176+ // Check that retrieved Oid is "child" of the root OID
177+ if ( rootOid . IsRootOf ( vb . Oid ! ) )
178+ {
179+ treeData [ vb . Oid ! ] = vb . Value ;
180+
181+ // Done?
182+ lastOid = vb . Value ! . Type == SnmpConstants . SMI_ENDOFMIBVIEW
183+ ? null
184+ : vb . Oid ;
185+ }
186+ else
187+ {
188+ lastOid = null ;
189+ }
190+ }
191+ }
192+
193+ return treeData ;
194+ }
195+ }
0 commit comments