1 | |
package net.sf.snmpadaptor4j.api.opennms; |
2 | |
|
3 | |
import java.net.InetAddress; |
4 | |
import java.util.Iterator; |
5 | |
import java.util.Map.Entry; |
6 | |
import net.sf.snmpadaptor4j.api.SnmpDaemon; |
7 | |
import net.sf.snmpadaptor4j.api.SnmpDaemonConfiguration; |
8 | |
import net.sf.snmpadaptor4j.api.SnmpException; |
9 | |
import net.sf.snmpadaptor4j.api.SnmpMib; |
10 | |
import net.sf.snmpadaptor4j.api.AttributeAccessor; |
11 | |
import net.sf.snmpadaptor4j.object.SnmpOid; |
12 | |
import org.apache.log4j.Level; |
13 | |
import org.opennms.protocols.snmp.SnmpAgentHandler; |
14 | |
import org.opennms.protocols.snmp.SnmpAgentSession; |
15 | |
import org.opennms.protocols.snmp.SnmpEndOfMibView; |
16 | |
import org.opennms.protocols.snmp.SnmpObjectId; |
17 | |
import org.opennms.protocols.snmp.SnmpOctetString; |
18 | |
import org.opennms.protocols.snmp.SnmpParameters; |
19 | |
import org.opennms.protocols.snmp.SnmpPduBulk; |
20 | |
import org.opennms.protocols.snmp.SnmpPduPacket; |
21 | |
import org.opennms.protocols.snmp.SnmpPduRequest; |
22 | |
import org.opennms.protocols.snmp.SnmpPeer; |
23 | |
import org.opennms.protocols.snmp.SnmpSMI; |
24 | |
import org.opennms.protocols.snmp.SnmpSyntax; |
25 | |
import org.opennms.protocols.snmp.SnmpVarBind; |
26 | |
import org.opennms.protocols.snmp.asn1.AsnEncodingException; |
27 | |
|
28 | |
|
29 | |
|
30 | |
|
31 | |
|
32 | |
public class OpennmsSnmpDaemon |
33 | |
extends OpennmsSupport |
34 | |
implements SnmpDaemon, SnmpAgentHandler { |
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
private final SnmpDaemonConfiguration configuration; |
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
protected final SnmpMib snmpMib; |
45 | |
|
46 | |
|
47 | |
|
48 | |
|
49 | 47 | private SnmpAgentSession snmpSession = null; |
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
OpennmsSnmpDaemon (final SnmpDaemonConfiguration configuration, final SnmpMib snmpMib) { |
58 | 47 | super(); |
59 | 47 | this.configuration = configuration; |
60 | 47 | this.snmpMib = snmpMib; |
61 | 47 | } |
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
public final synchronized void start () throws Exception { |
68 | 5 | if (this.snmpSession == null) { |
69 | 4 | this.logger.trace("SNMP daemon starting..."); |
70 | 4 | this.logger.debug("SNMP daemon will listen on " + this.configuration.getListenerAddress() + ":" + this.configuration.getListenerPort().intValue()); |
71 | 4 | final SnmpPeer peer = new SnmpPeer(InetAddress.getByName(this.configuration.getListenerAddress()), this.configuration.getListenerPort().intValue()); |
72 | 4 | final SnmpParameters params = peer.getParameters(); |
73 | 4 | switch (this.configuration.getListenerSnmpVersion().intValue()) { |
74 | |
case 1: |
75 | 1 | params.setVersion(SnmpSMI.SNMPV1); |
76 | 1 | break; |
77 | |
default: |
78 | 3 | params.setVersion(SnmpSMI.SNMPV2); |
79 | |
break; |
80 | |
} |
81 | 4 | params.setReadCommunity(this.configuration.getListenerReadCommunity()); |
82 | 4 | params.setWriteCommunity(this.configuration.getListenerWriteCommunity()); |
83 | 4 | this.snmpSession = new SnmpAgentSession(this, peer); |
84 | 4 | this.logger.info("SNMP daemon listen on " + this.configuration.getListenerAddress() + ":" + this.configuration.getListenerPort().intValue()); |
85 | 4 | this.logger.trace("SNMP daemon started"); |
86 | 4 | } |
87 | |
else { |
88 | 1 | this.logger.trace("SNMP daemon already started"); |
89 | |
} |
90 | 5 | } |
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | |
public final synchronized void stop () { |
97 | 40 | if (this.snmpSession != null) { |
98 | 4 | this.logger.trace("SNMP daemon stopping..."); |
99 | 4 | this.snmpSession.close(); |
100 | 4 | this.snmpSession = null; |
101 | 4 | this.logger.trace("SNMP daemon stopped"); |
102 | |
} |
103 | |
else { |
104 | 36 | this.logger.trace("SNMP daemon already stopped"); |
105 | |
} |
106 | 40 | } |
107 | |
|
108 | |
|
109 | |
|
110 | |
|
111 | |
|
112 | |
public final boolean isStarted () { |
113 | 15 | return (this.snmpSession != null); |
114 | |
} |
115 | |
|
116 | |
|
117 | |
|
118 | |
|
119 | |
|
120 | |
public final void SnmpAgentSessionError (final SnmpAgentSession session, final int error, final Object ref) { |
121 | 1 | throw new SnmpException(error); |
122 | |
} |
123 | |
|
124 | |
|
125 | |
|
126 | |
|
127 | |
|
128 | |
|
129 | |
public final void snmpReceivedPdu (final SnmpAgentSession session, final InetAddress manager, final int port, final SnmpOctetString community, |
130 | |
final SnmpPduPacket pdu) { |
131 | 11 | if (this.logger.isTraceEnabled()) { |
132 | 8 | this.logger.trace(pdu.getRequestId() + ": in treating by snmpReceivedPdu..."); |
133 | |
} |
134 | 11 | if (pdu instanceof SnmpPduBulk) { |
135 | 10 | final SnmpPduRequest response = new SnmpPduRequest(SnmpPduPacket.RESPONSE); |
136 | 10 | response.setRequestId(pdu.getRequestId()); |
137 | 10 | doBulk(pdu.toVarBindArray(), (SnmpPduBulk) pdu, response); |
138 | |
try { |
139 | 10 | sendPduPacket(session, new SnmpPeer(manager, port), response); |
140 | |
} |
141 | 2 | catch (final AsnEncodingException e) { |
142 | 2 | this.logger.error(pdu.getRequestId() + ": error " + SnmpPduPacket.ErrTooBig + " (response too big)"); |
143 | 2 | final SnmpPduRequest errorResponse = new SnmpPduRequest(SnmpPduPacket.RESPONSE); |
144 | 2 | errorResponse.setRequestId(pdu.getRequestId()); |
145 | 2 | errorResponse.setErrorStatus(SnmpPduPacket.ErrTooBig); |
146 | 2 | errorResponse.setErrorIndex(0); |
147 | |
try { |
148 | 2 | sendPduPacket(session, new SnmpPeer(manager, port), errorResponse); |
149 | |
} |
150 | 1 | catch (final Throwable e1) { |
151 | 1 | this.logger.error(pdu.getRequestId() + ": an error has occurred when the error response sending", e1); |
152 | 1 | } |
153 | |
} |
154 | 2 | catch (final Throwable e) { |
155 | 2 | this.logger.error(pdu.getRequestId() + ": error " + SnmpPduPacket.ErrGenError + " (general error)", e); |
156 | 2 | final SnmpPduRequest errorResponse = new SnmpPduRequest(SnmpPduPacket.RESPONSE); |
157 | 2 | errorResponse.setRequestId(pdu.getRequestId()); |
158 | 2 | errorResponse.setErrorStatus(SnmpPduPacket.ErrGenError); |
159 | 2 | errorResponse.setErrorIndex(0); |
160 | |
try { |
161 | 2 | sendPduPacket(session, new SnmpPeer(manager, port), errorResponse); |
162 | |
} |
163 | 1 | catch (final Throwable e1) { |
164 | 1 | this.logger.error(pdu.getRequestId() + ": an error has occurred when the error response sending", e1); |
165 | 1 | } |
166 | 8 | } |
167 | 10 | } |
168 | |
else { |
169 | 1 | this.logger.error(pdu.getRequestId() + ": request ignored (PDU " + pdu.getClass().getSimpleName() + " unhandled)"); |
170 | |
} |
171 | 11 | if (this.logger.isTraceEnabled()) { |
172 | 8 | this.logger.trace(pdu.getRequestId() + ": treated by snmpReceivedPdu"); |
173 | |
} |
174 | 11 | } |
175 | |
|
176 | |
|
177 | |
|
178 | |
|
179 | |
|
180 | |
|
181 | |
|
182 | |
|
183 | |
@SuppressWarnings("static-method") |
184 | |
protected void sendPduPacket (final SnmpAgentSession session, final SnmpPeer peer, final SnmpPduPacket pdu) throws Exception { |
185 | 0 | session.send(peer, pdu); |
186 | 0 | } |
187 | |
|
188 | |
|
189 | |
|
190 | |
|
191 | |
|
192 | |
public final SnmpPduRequest snmpReceivedGet (final SnmpPduPacket pdu, final boolean getNext) { |
193 | 14 | if (this.logger.isTraceEnabled()) { |
194 | 8 | this.logger.trace(pdu.getRequestId() + ": in treating by snmpReceivedGet..."); |
195 | |
} |
196 | 14 | final SnmpPduRequest response = new SnmpPduRequest(SnmpPduPacket.RESPONSE); |
197 | 14 | response.setRequestId(pdu.getRequestId()); |
198 | 14 | final SnmpVarBind[] binds = pdu.toVarBindArray(); |
199 | 14 | if (binds.length > 20) { |
200 | 1 | this.logger.error(pdu.getRequestId() + ": error " + SnmpPduPacket.ErrTooBig + " (too OIDs - limited to 20)"); |
201 | 1 | response.setErrorStatus(SnmpPduPacket.ErrTooBig); |
202 | 1 | response.setErrorIndex(0); |
203 | |
} |
204 | |
|
205 | |
|
206 | 13 | else if (pdu instanceof SnmpPduRequest) { |
207 | 8 | int resultIndex = 1; |
208 | |
try { |
209 | |
SnmpOid oid; |
210 | |
AttributeAccessor attributeAccessor; |
211 | 14 | for (final SnmpVarBind varBind : binds) { |
212 | 10 | oid = SnmpOid.newInstance(varBind.getName().getIdentifiers()); |
213 | 10 | if (getNext) { |
214 | 5 | attributeAccessor = this.snmpMib.next(oid); |
215 | 4 | if (attributeAccessor == null) { |
216 | 1 | response.addVarBind(new SnmpVarBind(varBind.getName())); |
217 | 1 | throw new SnmpException("none OID found after " + oid, SnmpPduPacket.ErrNoSuchName, Level.DEBUG); |
218 | |
} |
219 | 3 | if (this.logger.isDebugEnabled()) { |
220 | 1 | this.logger.debug(pdu.getRequestId() + ": " + oid + " --next--> " + attributeAccessor); |
221 | |
} |
222 | 3 | response.addVarBind(newSnmpVarBind(attributeAccessor)); |
223 | |
} |
224 | |
else { |
225 | 5 | attributeAccessor = this.snmpMib.find(oid); |
226 | 4 | if (attributeAccessor == null) { |
227 | 1 | response.addVarBind(new SnmpVarBind(varBind.getName())); |
228 | 1 | throw new SnmpException("OID " + oid + " not found", SnmpPduPacket.ErrNoSuchName, Level.DEBUG); |
229 | |
} |
230 | 3 | if (this.logger.isDebugEnabled()) { |
231 | 1 | this.logger.debug(pdu.getRequestId() + ": " + attributeAccessor); |
232 | |
} |
233 | 3 | varBind.setValue(newSnmpValue(attributeAccessor)); |
234 | 3 | response.addVarBind(varBind); |
235 | |
} |
236 | 6 | resultIndex++; |
237 | |
} |
238 | |
} |
239 | 3 | catch (final SnmpException e) { |
240 | 3 | this.logger.log(e.getLoggerLevel(), pdu.getRequestId() + ": " + e.getMessage(), e.getCause()); |
241 | 3 | response.setErrorStatus(e.getErrorStatus()); |
242 | 3 | response.setErrorIndex(resultIndex); |
243 | |
} |
244 | 1 | catch (final Throwable e) { |
245 | 1 | this.logger.error(pdu.getRequestId() + ": error " + SnmpPduPacket.ErrGenError + " (general error)", e); |
246 | 1 | response.setErrorStatus(SnmpPduPacket.ErrGenError); |
247 | 1 | response.setErrorIndex(resultIndex); |
248 | 7 | } |
249 | 8 | } |
250 | |
|
251 | |
|
252 | 5 | else if (pdu instanceof SnmpPduBulk) { |
253 | 4 | doBulk(binds, (SnmpPduBulk) pdu, response); |
254 | |
} |
255 | |
|
256 | |
else { |
257 | 1 | this.logger.error(pdu.getRequestId() + ": error " + SnmpPduPacket.ErrGenError + " (PDU " + pdu.getClass().getSimpleName() + " unhandled)"); |
258 | 1 | response.setErrorStatus(SnmpPduPacket.ErrGenError); |
259 | 1 | response.setErrorIndex(0); |
260 | |
} |
261 | 14 | if (this.logger.isTraceEnabled()) { |
262 | 8 | this.logger.trace(pdu.getRequestId() + ": treated by snmpReceivedGet"); |
263 | |
} |
264 | 14 | return response; |
265 | |
} |
266 | |
|
267 | |
|
268 | |
|
269 | |
|
270 | |
|
271 | |
|
272 | |
|
273 | |
private void doBulk (final SnmpVarBind binds[], final SnmpPduBulk bulk, final SnmpPduRequest response) { |
274 | 14 | int resultIndex = 1; |
275 | |
try { |
276 | |
SnmpOid oid; |
277 | |
AttributeAccessor attributeAccessor; |
278 | |
Iterator<Entry<SnmpOid, AttributeAccessor>> attributeAccessorEntryIterator; |
279 | |
int i; |
280 | 26 | for (final SnmpVarBind varBind : binds) { |
281 | 14 | oid = SnmpOid.newInstance(varBind.getName().getIdentifiers()); |
282 | 14 | if (resultIndex <= bulk.getNonRepeaters()) { |
283 | 6 | attributeAccessor = this.snmpMib.next(oid); |
284 | 6 | if (attributeAccessor != null) { |
285 | 2 | if (this.logger.isDebugEnabled()) { |
286 | 1 | this.logger.debug(bulk.getRequestId() + ": " + oid + " --next--> " + attributeAccessor); |
287 | |
} |
288 | 2 | response.addVarBind(newSnmpVarBind(attributeAccessor)); |
289 | |
} |
290 | |
else { |
291 | 4 | if (this.logger.isDebugEnabled()) { |
292 | 2 | this.logger.debug(bulk.getRequestId() + ": " + oid + " --next--> END OF MIB"); |
293 | |
} |
294 | 4 | response.addVarBind(new SnmpVarBind(varBind.getName(), new SnmpEndOfMibView())); |
295 | |
} |
296 | |
} |
297 | |
else { |
298 | 8 | attributeAccessorEntryIterator = this.snmpMib.nextSet(oid).entrySet().iterator(); |
299 | 6 | if (attributeAccessorEntryIterator.hasNext()) { |
300 | 4 | i = 0; |
301 | 10 | while (attributeAccessorEntryIterator.hasNext() && (i < bulk.getMaxRepititions())) { |
302 | 6 | attributeAccessor = attributeAccessorEntryIterator.next().getValue(); |
303 | 6 | if (this.logger.isDebugEnabled()) { |
304 | 3 | if (i == 0) { |
305 | 2 | this.logger.debug(bulk.getRequestId() + ": " + oid + " --next--> " + attributeAccessor); |
306 | |
} |
307 | |
else { |
308 | 1 | this.logger.debug(bulk.getRequestId() + ": " + String.format("%" + oid.toString().length() + "s", "") + " --next--> " |
309 | |
+ attributeAccessor); |
310 | |
} |
311 | |
} |
312 | 6 | response.addVarBind(newSnmpVarBind(attributeAccessor)); |
313 | 6 | i++; |
314 | |
} |
315 | 4 | if (i < bulk.getMaxRepititions()) { |
316 | 2 | if (this.logger.isDebugEnabled()) { |
317 | 1 | this.logger.debug(bulk.getRequestId() + ": " + oid + " --next--> .1.9: END OF MIB"); |
318 | |
} |
319 | 2 | response.addVarBind(new SnmpVarBind(".1.9", new SnmpEndOfMibView())); |
320 | |
} |
321 | |
} |
322 | |
else { |
323 | 2 | if (this.logger.isDebugEnabled()) { |
324 | 1 | this.logger.debug(bulk.getRequestId() + ": " + oid + " --next--> END OF MIB"); |
325 | |
} |
326 | 2 | response.addVarBind(new SnmpVarBind(varBind.getName(), new SnmpEndOfMibView())); |
327 | |
} |
328 | |
} |
329 | 12 | resultIndex++; |
330 | |
} |
331 | |
} |
332 | 1 | catch (final SnmpException e) { |
333 | 1 | this.logger.log(e.getLoggerLevel(), bulk.getRequestId() + ": " + e.getMessage(), e.getCause()); |
334 | 1 | response.setErrorStatus(e.getErrorStatus()); |
335 | 1 | response.setErrorIndex(resultIndex); |
336 | |
} |
337 | 1 | catch (final Throwable e) { |
338 | 1 | this.logger.error(bulk.getRequestId() + ": error " + SnmpPduPacket.ErrGenError + " (general error)", e); |
339 | 1 | response.setErrorStatus(SnmpPduPacket.ErrGenError); |
340 | 1 | response.setErrorIndex(resultIndex); |
341 | 13 | } |
342 | 14 | } |
343 | |
|
344 | |
|
345 | |
|
346 | |
|
347 | |
|
348 | |
public SnmpPduRequest snmpReceivedSet (final SnmpPduPacket pdu) { |
349 | 6 | if (this.logger.isTraceEnabled()) { |
350 | 5 | this.logger.trace(pdu.getRequestId() + ": in treating by snmpReceivedSet..."); |
351 | |
} |
352 | 6 | final SnmpPduRequest response = new SnmpPduRequest(SnmpPduPacket.RESPONSE); |
353 | 6 | response.setRequestId(pdu.getRequestId()); |
354 | 6 | final SnmpVarBind[] binds = pdu.toVarBindArray(); |
355 | 6 | if (binds.length > 20) { |
356 | 1 | this.logger.error(pdu.getRequestId() + ": error " + SnmpPduPacket.ErrTooBig + " (too OIDs - limited to 20)"); |
357 | 1 | response.setErrorStatus(SnmpPduPacket.ErrTooBig); |
358 | 1 | response.setErrorIndex(0); |
359 | |
} |
360 | |
else { |
361 | 5 | int resultIndex = 1; |
362 | |
try { |
363 | |
SnmpOid oid; |
364 | |
SnmpSyntax newValue; |
365 | |
AttributeAccessor attributeAccessor; |
366 | 8 | for (final SnmpVarBind varBind : binds) { |
367 | 6 | oid = SnmpOid.newInstance(varBind.getName().getIdentifiers()); |
368 | 6 | newValue = varBind.getValue(); |
369 | 6 | attributeAccessor = this.snmpMib.find(oid); |
370 | 4 | if (attributeAccessor == null) { |
371 | 1 | response.addVarBind(new SnmpVarBind(varBind.getName())); |
372 | 1 | throw new SnmpException("OID " + oid + " not found", SnmpPduPacket.ErrNoSuchName, Level.DEBUG); |
373 | |
} |
374 | 3 | if (this.logger.isDebugEnabled()) { |
375 | 1 | this.logger.debug(pdu.getRequestId() + ": old " + attributeAccessor); |
376 | |
} |
377 | 3 | setValue(attributeAccessor, newValue); |
378 | 3 | response.addVarBind(newSnmpVarBind(attributeAccessor)); |
379 | 3 | if (this.logger.isDebugEnabled()) { |
380 | 1 | this.logger.debug(pdu.getRequestId() + ": new " + attributeAccessor); |
381 | |
} |
382 | 3 | resultIndex++; |
383 | |
} |
384 | |
} |
385 | 2 | catch (final SnmpException e) { |
386 | 2 | this.logger.log(e.getLoggerLevel(), pdu.getRequestId() + ": " + e.getMessage(), e.getCause()); |
387 | 2 | response.setErrorStatus(e.getErrorStatus()); |
388 | 2 | response.setErrorIndex(resultIndex); |
389 | |
} |
390 | 1 | catch (final Throwable e) { |
391 | 1 | this.logger.error(pdu.getRequestId() + ": error " + SnmpPduPacket.ErrGenError + " (general error)", e); |
392 | 1 | response.setErrorStatus(SnmpPduPacket.ErrGenError); |
393 | 1 | response.setErrorIndex(resultIndex); |
394 | 4 | } |
395 | |
} |
396 | 6 | if (this.logger.isTraceEnabled()) { |
397 | 5 | this.logger.trace(pdu.getRequestId() + ": treated by snmpReceivedSet"); |
398 | |
} |
399 | 6 | return response; |
400 | |
} |
401 | |
|
402 | |
|
403 | |
|
404 | |
|
405 | |
|
406 | |
|
407 | |
|
408 | |
private SnmpVarBind newSnmpVarBind (final AttributeAccessor attributeAccessor) throws Exception { |
409 | 14 | return new SnmpVarBind(new SnmpObjectId(attributeAccessor.getOid().getOid()), newSnmpValue(attributeAccessor)); |
410 | |
} |
411 | |
|
412 | |
|
413 | |
|
414 | |
|
415 | |
|
416 | |
|
417 | |
|
418 | |
protected static SnmpSyntax newSnmpValue (final AttributeAccessor attributeAccessor) throws Exception { |
419 | 19 | if (!attributeAccessor.isReadable()) { |
420 | 1 | throw new SnmpException("MBean attribute is not readable", SnmpPduPacket.ErrNoAccess); |
421 | |
} |
422 | |
Object value; |
423 | |
try { |
424 | 18 | value = attributeAccessor.getValue(); |
425 | |
} |
426 | 1 | catch (final Throwable e) { |
427 | 1 | throw new SnmpException("Impossible to read the attribute due to error", SnmpPduPacket.ErrNoAccess, e); |
428 | 17 | } |
429 | 17 | return newSnmpValue(attributeAccessor.getSnmpDataType(), value); |
430 | |
} |
431 | |
|
432 | |
|
433 | |
|
434 | |
|
435 | |
|
436 | |
|
437 | |
|
438 | |
protected static void setValue (final AttributeAccessor attributeAccessor, final SnmpSyntax newValue) throws Exception { |
439 | 6 | if (!attributeAccessor.isReadable()) { |
440 | 1 | throw new SnmpException("MBean attribute is not readable", SnmpPduPacket.ErrNoAccess); |
441 | |
} |
442 | 5 | if (!attributeAccessor.isWritable()) { |
443 | 1 | throw new SnmpException("MBean attribute is not writable", SnmpPduPacket.ErrNotWritable); |
444 | |
} |
445 | 4 | final Object value = newJmxValue(attributeAccessor.getJmxDataType(), attributeAccessor.getSnmpDataType(), newValue); |
446 | |
try { |
447 | 4 | attributeAccessor.setValue(value); |
448 | |
} |
449 | 1 | catch (final Throwable e) { |
450 | 1 | throw new SnmpException("Impossible to write in the attribute due to error", SnmpPduPacket.ErrNotWritable, e); |
451 | 3 | } |
452 | 3 | } |
453 | |
|
454 | |
|
455 | |
|
456 | |
|
457 | |
|
458 | |
@Override |
459 | |
public String toString () { |
460 | 2 | return "SnmpDaemon:opennms[" + (this.configuration != null ? this.configuration.getListenerAddress() + ":" + this.configuration.getListenerPort() : "null") |
461 | |
+ "]"; |
462 | |
} |
463 | |
|
464 | |
} |