1 // NAME
2 // $RCSfile: Pdu.java,v $
3 // DESCRIPTION
4 // [given below in javadoc format]
5 // DELTA
6 // $Revision: 3.33 $
7 // CREATED
8 // $Date: 2008/12/12 14:55:51 $
9 // COPYRIGHT
10 // Westhawk Ltd
11 // TO DO
12 //
13
14 /*
15 * Copyright (C) 1995, 1996 by West Consulting BV
16 *
17 * Permission to use, copy, modify, and distribute this software
18 * for any purpose and without fee is hereby granted, provided
19 * that the above copyright notices appear in all copies and that
20 * both the copyright notice and this permission notice appear in
21 * supporting documentation.
22 * This software is provided "as is" without express or implied
23 * warranty.
24 * author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
25 */
26
27 /*
28 * Copyright (C) 1996 - 2006 by Westhawk Ltd
29 * <a href="www.westhawk.co.uk">www.westhawk.co.uk</a>
30 *
31 * Permission to use, copy, modify, and distribute this software
32 * for any purpose and without fee is hereby granted, provided
33 * that the above copyright notices appear in all copies and that
34 * both the copyright notice and this permission notice appear in
35 * supporting documentation.
36 * This software is provided "as is" without express or implied
37 * warranty.
38 * author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
39 */
40
41
42 package uk.co.westhawk.snmp.stack;
43
44 /*-
45 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
46 * SNMP Java Client
47 * ჻჻჻჻჻჻
48 * Copyright 2023 MetricsHub, Westhawk
49 * ჻჻჻჻჻჻
50 * This program is free software: you can redistribute it and/or modify
51 * it under the terms of the GNU Lesser General Public License as
52 * published by the Free Software Foundation, either version 3 of the
53 * License, or (at your option) any later version.
54 *
55 * This program is distributed in the hope that it will be useful,
56 * but WITHOUT ANY WARRANTY; without even the implied warranty of
57 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
58 * GNU General Lesser Public License for more details.
59 *
60 * You should have received a copy of the GNU General Lesser Public
61 * License along with this program. If not, see
62 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
63 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
64 */
65 import java.util.*;
66 import java.io.*;
67
68 import uk.co.westhawk.snmp.util.*;
69
70 /**
71 * This class represents the ASN PDU object, this is the equivalent of
72 * a GetRequest PDU.
73 *
74 * @author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
75 * @version $Revision: 3.33 $ $Date: 2008/12/12 14:55:51 $
76 */
77 public abstract class Pdu extends Observable {
78 private static final String version_id = "@(#)$Id: Pdu.java,v 3.33 2008/12/12 14:55:51 tpanton Exp $ Copyright Westhawk Ltd";
79
80 protected Vector reqVarbinds = null;
81 protected Vector respVarbinds = null;
82
83 private final static String TIMED_OUT = "Timed out";
84 private final static String[] errorStrings = {
85 "No error",
86 "Value too big error",
87 "No such name error",
88 "Bad value error",
89 "Read only error",
90 "General error",
91 "No access error",
92 "Wrong type error",
93 "Wrong length error",
94 "Wrong encoding error",
95 "Wrong value error",
96 "No creation error",
97 "Inconsistent value error",
98 "Resource unavailable error",
99 "Commit failed error",
100 "Undo failed error",
101 "Authorization error",
102 "Not writable error",
103 "Inconsistent name error",
104 };
105
106 private static int next_id = 1;
107 private static final Object NEXT_ID_LOCK = new Object();
108
109 private int retry_intervals[] = { 500, 1000, 2000, 5000, 5000 };
110
111 protected byte[] encodedPacket = null;
112 protected SnmpContextBasisFace context;
113 protected boolean added = false;
114 protected byte msg_type;
115
116 int req_id;
117 protected Integer snmpv3MsgId = null;
118 protected int errstat;
119 protected int errind;
120
121 private Transmitter trans = null;
122 private int retries;
123 protected boolean answered;
124 private boolean got = false;
125 private boolean isTimedOut;
126 private PduException respException = null;
127
128 /**
129 * The value of the response is set. This will be called by
130 * Pdu.fillin().
131 */
132 protected void new_value(int n, varbind res) {
133 }
134
135 /**
136 * This method notifies all observers.
137 * This will be called by Pdu.fillin().
138 *
139 * <p>
140 * The Object to the update() method of the Observer will be a varbind,
141 * unless an exception occurred.
142 * In the case of an exception, that exception will be passed.
143 * So watch out casting!
144 * </p>
145 */
146 protected void tell_them() {
147 notifyObservers();
148 }
149
150 /**
151 * Constructor.
152 *
153 * @param con The context of the PDU
154 * @see SnmpContext
155 * @see SnmpContextv2c
156 * @see SnmpContextv3
157 */
158 public Pdu(SnmpContextBasisFace con) {
159 context = con;
160
161 // TODO: would not work if we ever were to send response or report!
162 // TODO: We would have to set the req_id!
163
164 // Added NEXT_ID_LOCK on suggestion of
165 // Victor Kirk <Victor.Kirk@serco.com>
166 synchronized (NEXT_ID_LOCK) {
167 req_id = next_id++;
168 }
169 errstat = AsnObject.SNMP_ERR_NOERROR;
170 errind = 0x00;
171 reqVarbinds = new Vector(1, 1);
172 setMsgType(AsnObject.GET_REQ_MSG);
173 isTimedOut = false;
174
175 // if it is not set to false, PDUs that do not receive a response
176 // will not be filled in properly.
177 answered = false;
178 }
179
180 /**
181 * Returns the context of this PDU.
182 *
183 * @return The context
184 */
185 public SnmpContextBasisFace getContext() {
186 return context;
187 }
188
189 /**
190 * Sets the retry intervals of the PDU. The length of the array
191 * corresponds with the number of retries. Each entry in the array
192 * is the number of milliseconds of each try.
193 *
194 * <p>
195 * If used, please set before sending!
196 * </p>
197 *
198 * The default is {500, 1000, 2000, 5000, 5000}.
199 * It is good practice to make the interval bigger with each retry,
200 * if the numbers are the same the chance of collision is higher.
201 *
202 * @param rinterval The interval in msec of each retry
203 */
204 public void setRetryIntervals(int rinterval[]) {
205 retry_intervals = rinterval;
206 }
207
208 public int[] getRetryIntervals() {
209 return retry_intervals;
210 }
211
212 /**
213 * Sends the PDU.
214 * Note that all properties of the context have to be set before this
215 * point.
216 */
217 public boolean send() throws IOException, PduException {
218 return send(errstat, errind);
219 }
220
221 /**
222 * Sends the PDU. This method accommodates the GetBulk request.
223 *
224 * @param error_status The value of the error_status field.
225 * @param error_index The value of the error_index field.
226 * @see #send()
227 */
228 protected boolean send(int error_status, int error_index)
229 throws IOException, PduException {
230 if (added == false) {
231 // Moved this statement from the constructor because it
232 // conflicts with the way the SnmpContextXPool works.
233 added = context.addPdu(this);
234 }
235 Enumeration vbs = reqVarbinds.elements();
236 encodedPacket = context.encodePacket(msg_type, req_id, error_status,
237 error_index, vbs, snmpv3MsgId);
238 addToTrans();
239 return added;
240 }
241
242 /**
243 * Adds the PDU to its transmitter. The transmitter is the thread that
244 * will be sent the PDU and then waits for the answer.
245 *
246 * @see #send
247 */
248 protected void addToTrans() {
249 if (added && (trans != null)) {
250 // thanks to Ian Dowse <iedowse@iedowse.com> for synchronisation
251 synchronized (trans) {
252 trans.setPdu(this);
253 trans.stand();
254 }
255 }
256 }
257
258 /**
259 * Sends the actual packet and updates the retries.
260 *
261 * @see AbstractSnmpContext#sendPacket(byte[] p)
262 */
263 protected boolean sendme() {
264 context.sendPacket(encodedPacket);
265 retries++;
266
267 if (AsnObject.debug > 6) {
268 System.out.println(getClass().getName() + ".sendme(): Sent Pdu reqId=" + req_id + ", retries " + retries);
269 }
270 return (retries > 3);
271 }
272
273 /**
274 * Sends the PDU.
275 * For backwards compatibility only. Please use send() instead.
276 * The community name will be passed to the SnmpContext. If using
277 * SnmpContextv3, the community name will be ignored.
278 *
279 * @param com The community name of the PDU in SNMPv1 and SNMPv2c.
280 * @deprecated Community name has moved to SnmpContext. Use
281 * {@link SnmpContext#setCommunity(String)}.
282 *
283 * @see SnmpContext#setCommunity
284 * @see #send
285 */
286 public boolean send(String com) throws IOException, PduException {
287 if (context instanceof SnmpContext) {
288 ((SnmpContext) context).setCommunity(com);
289 }
290 return send();
291 }
292
293 /**
294 * Adds an OID (object identifier) to the PDU. The OID indicates which
295 * MIB variable we request for or which MIB variable should be set.
296 *
297 * @param oid The oid
298 * @see #addOid(varbind)
299 * @see varbind
300 */
301 public void addOid(String oid) {
302 varbind vb = new varbind(oid);
303 addOid(vb);
304 }
305
306 /**
307 * Adds an OID (object identifier) to the PDU. The OID indicates which
308 * MIB variable we request for or which MIB variable should be set.
309 *
310 * @param oid The oid
311 * @see #addOid(varbind)
312 * @see varbind
313 * @since 4_12
314 */
315 public void addOid(AsnObjectId oid) {
316 varbind vb = new varbind(oid);
317 addOid(vb);
318 }
319
320 /**
321 * Adds an OID (object identifier) to the PDU and the value that has
322 * to be set. This method has moved from SetPdu to this class in version 4_12.
323 *
324 * @param oid The oid
325 * @param val The value
326 * @see Pdu#addOid
327 * @see varbind
328 * @since 4_12
329 */
330 public void addOid(String oid, AsnObject val) {
331 varbind vb = new varbind(oid, val);
332 addOid(vb);
333 }
334
335 /**
336 * Adds an OID (object identifier) to the PDU and the value that has
337 * to be set.
338 *
339 * <p>
340 * Thanks to Eli Bishop (eli@graphesthesia.com) for the suggestion.
341 * </p>
342 *
343 * @param oid The oid
344 * @param val The value
345 * @see Pdu#addOid
346 * @see varbind
347 * @since 4_12
348 */
349 public void addOid(AsnObjectId oid, AsnObject val) {
350 varbind vb = new varbind(oid, val);
351 addOid(vb);
352 }
353
354 /**
355 * Adds an OID (object identifier) to the PDU.
356 *
357 * @param var The varbind
358 * @see #addOid(String)
359 */
360 public void addOid(varbind var) {
361 reqVarbinds.addElement(var);
362 }
363
364 /**
365 * Returns a copy of the varbinds used to build the request.
366 *
367 * @return the request varbinds of this PDU.
368 */
369 public varbind[] getRequestVarbinds() {
370 int sz = reqVarbinds.size();
371 varbind[] arr = new varbind[sz];
372 reqVarbinds.copyInto(arr);
373 return arr;
374 }
375
376 /**
377 * Returns a copy of the varbinds received in the response.
378 * If there was no response (yet), null will be returned.
379 *
380 * @return the response varbinds of this PDU.
381 * @exception PduException An agent or decoding exception occurred
382 * whilst receiving the response.
383 *
384 * @see #getErrorStatus
385 * @see #notifyObservers
386 */
387 public varbind[] getResponseVarbinds() throws PduException {
388 if (respException != null) {
389 throw respException;
390 }
391
392 varbind[] arr = null;
393 if (respVarbinds != null) {
394 int sz = respVarbinds.size();
395 arr = new varbind[sz];
396 respVarbinds.copyInto(arr);
397 }
398 return arr;
399 }
400
401 private void dump(Vector v, varbind[] array) {
402 int sz = v.size();
403 System.out.println("Vector: ");
404 for (int i = 0; i < sz; i++) {
405 System.out.println("\t" + v.elementAt(i));
406 }
407 System.out.println("Array: ");
408 for (int i = 0; i < array.length; i++) {
409 System.out.println("\t" + array[i]);
410 }
411 System.out.println("--");
412 }
413
414 void setResponseException(PduException exc) {
415 if (AsnObject.debug > 6) {
416 System.out.println(getClass().getName() + ".setResponseException(): reqId=" + req_id + exc.getMessage());
417 }
418 respException = exc;
419 }
420
421 /**
422 * Returns the request id of the PDU.
423 *
424 * @return The ID
425 */
426 public int getReqId() {
427 return req_id;
428 }
429
430 /**
431 * Returns the error index.
432 * The error index indicates which of the OIDs went wrong.
433 *
434 * @return the error index
435 * @see #getErrorStatus
436 */
437 public int getErrorIndex() {
438 return errind;
439 }
440
441 /**
442 * Returns the error status as indicated by the error-status field in
443 * the reponse PDU. The error index will indicated which OID caused the
444 * error.
445 * In case of a decoding exception the error status
446 * will be set to one of the decoding errors:
447 * <ul>
448 * <li>
449 * <code>SnmpConstants.SNMP_ERR_DECODING_EXC</code>.
450 * </li>
451 * <li>
452 * <code>SnmpConstants.SNMP_ERR_DECODINGASN_EXC</code>.
453 * </li>
454 * <li>
455 * <code>SnmpConstants.SNMP_ERR_DECODINGPKTLNGTH_EXC</code>.
456 * </li>
457 * </ul>
458 *
459 * <p>
460 * The actual exception will be passed to your
461 * <code>update(Observable ob, Object arg)</code>
462 * method via the the parameter
463 * <code>arg</code>.
464 * </p>
465 *
466 * @return the error status
467 * @see #notifyObservers
468 * @see #getResponseVarbinds
469 * @see SnmpConstants#SNMP_ERR_NOERROR
470 * @see SnmpConstants#SNMP_ERR_DECODING_EXC
471 * @see SnmpConstants#SNMP_ERR_DECODINGASN_EXC
472 * @see SnmpConstants#SNMP_ERR_DECODINGPKTLNGTH_EXC
473 * @see #getErrorStatusString
474 * @see #getErrorIndex
475 */
476 public int getErrorStatus() {
477 return errstat;
478 }
479
480 /**
481 * Returns the string representation of the error status.
482 *
483 * @return the error string
484 * @see #getErrorStatus
485 */
486 public String getErrorStatusString() {
487 String errString = "";
488 if (errstat >= 0) {
489 if (errstat < errorStrings.length) {
490 errString = errorStrings[errstat];
491
492 if (errstat == AsnObject.SNMP_ERR_GENERR
493 &&
494 isTimedOut() == true) {
495 errString = TIMED_OUT;
496 }
497 } else {
498 // they much be one of the DECODING*_EXC
499 if (respException != null) {
500 errString = respException.getMessage();
501 } else {
502 errString = "Decoding Exception";
503 }
504 }
505 }
506 return errString;
507 }
508
509 /**
510 * Returns whether or not this PDU is timed out, i.e. it did not get
511 * a response.
512 * Its errorStatus will be set to AsnObject.SNMP_ERR_GENERR.
513 *
514 * <p>
515 * Note that a SNMP agent can respond with an errorStatus of
516 * AsnObject.SNMP_ERR_GENERR as well, so getting a
517 * AsnObject.SNMP_ERR_GENERR does not necessarily mean that the request
518 * is timed out!
519 * </p>
520 *
521 * @return true is the PDU was timed out
522 * @see #getErrorStatus
523 * @see SnmpConstants#SNMP_ERR_GENERR
524 */
525 public boolean isTimedOut() {
526 return isTimedOut;
527 }
528
529 /**
530 * This method will wait until the answer is received, instead of
531 * continue with other stuff.
532 */
533 public boolean waitForSelf() {
534 // Add an extra second to the waiting. This gives the PDU a chance
535 // to handle the timeout correctly before this thread wakes up.
536 long del = 1000;
537 for (int i = 0; i < retry_intervals.length; i++) {
538 del += retry_intervals[i];
539 }
540 boolean res = waitForSelf(del);
541
542 if (AsnObject.debug > 6) {
543 System.out.println(getClass().getName() + ".waitForSelf(): reqId=" + req_id + " " + res);
544 }
545
546 // Should I??
547 if (!answered) {
548 handleNoAnswer();
549 }
550
551 return res;
552 }
553
554 /**
555 * Returns the string representation of the PDU.
556 *
557 * @return The string of the PDU
558 */
559 public String toString() {
560 return toString(false);
561 }
562
563 /**
564 * Returns the string representation of the PDU with or without the
565 * response varbinds.
566 *
567 * @param withRespVars Include the response varbinds or not
568 * @return The string of the PDU
569 */
570 protected String toString(boolean withRespVars) {
571 StringBuffer buffer = new StringBuffer(getClass().getName());
572 buffer.append("[");
573 buffer.append("context=").append(context);
574 buffer.append(", reqId=").append(req_id);
575 buffer.append(", msgType=0x").append(SnmpUtilities.toHex(msg_type));
576
577 buffer.append(", ");
578 buffer.append(printVars("reqVarbinds", reqVarbinds));
579
580 if (withRespVars == true) {
581 buffer.append(", ");
582 buffer.append(printVars("respVarbinds", respVarbinds));
583 }
584
585 buffer.append("]");
586 return buffer.toString();
587 }
588
589 /**
590 * Returns the string representation of the varbinds of the PDU.
591 *
592 * @see #toString(boolean)
593 * @since 4_14
594 */
595 protected StringBuffer printVars(String title, Vector vars) {
596 StringBuffer buffer = new StringBuffer();
597 buffer.append(title).append("=");
598 if (vars != null) {
599 int sz = vars.size();
600 buffer.append("[");
601 for (int i = 0; i < sz; i++) {
602 if (i > 0) {
603 buffer.append(", ");
604 }
605 varbind var = (varbind) vars.elementAt(i);
606 buffer.append(var.toString());
607 }
608 buffer.append("]");
609 } else {
610 buffer.append("null");
611 }
612 return buffer;
613 }
614
615 synchronized boolean waitForSelf(long delay) {
616 if (!got) {
617 try {
618 wait(delay);
619 } catch (InterruptedException ix) {
620 ;
621 }
622 }
623 return answered;
624 }
625
626 void transmit() {
627 transmit(true);
628 }
629
630 void transmit(boolean withRetries) {
631 if (withRetries == true) {
632 int n = 0;
633 answered = false;
634
635 while ((!context.isDestroyed()) && (!answered) && (n < retry_intervals.length)) {
636 sendme();
637
638 try {
639 Thread.sleep(retry_intervals[n]);
640 } catch (InterruptedException e) {
641 }
642 n++;
643 }
644
645 if (!answered) {
646 handleNoAnswer();
647 }
648 } else {
649 // just send it once. this will only happen if we are in a trap
650 // or response PDU.
651 sendme();
652 answered = true;
653 }
654
655 if (!context.removePdu(req_id)) {
656 if (AsnObject.debug > 6) {
657 System.out.println(getClass().getName() + ".transmit(): Failed to remove reqId " + req_id);
658 }
659 }
660 }
661
662 void setTrans(Transmitter t) {
663 trans = t;
664 }
665
666 /**
667 * Returns the message type, this will indicate what kind of request we
668 * are dealing with.
669 * By default it will be set to the GET_REQ_MSG
670 *
671 * @return The message type
672 */
673 public byte getMsgType() {
674 return msg_type;
675 }
676
677 /**
678 * Sets the message type, this will indicate what kind of request we
679 * are dealing with.
680 * By default it will be set to the GET_REQ_MSG
681 *
682 * @param type The message type
683 */
684 protected void setMsgType(byte type) {
685 msg_type = type;
686 }
687
688 /**
689 * Sets the error status, indicating what went wrong.
690 *
691 * @param err the error status
692 * @see #getErrorIndex
693 * @see #getErrorStatusString
694 * @see #getErrorStatus
695 */
696 protected void setErrorStatus(int err) {
697 errstat = err;
698 if (AsnObject.debug > 6) {
699 System.out.println(getClass().getName() + ".setErrorStatus(): reqId=" + req_id + " " + errstat);
700 }
701 if (errstat != AsnObject.SNMP_ERR_NOERROR) {
702 setResponseException(new AgentException(getErrorStatusString()));
703 }
704 }
705
706 /**
707 * Sets the error status and the exception, indicating what went wrong.
708 *
709 * @param err the error status
710 * @param exc the PDU Exception that was thrown whilst decoding
711 *
712 * @see #getErrorIndex
713 * @see #getErrorStatusString
714 * @see #getErrorStatus
715 */
716 protected void setErrorStatus(int err, PduException exc) {
717 errstat = err;
718 setResponseException(exc);
719 }
720
721 /**
722 * Sets the error index, this indicates which of the OIDs went wrong.
723 *
724 * @param ind the error index
725 * @see #setErrorStatus(int)
726 * @see #getErrorIndex
727 */
728 protected void setErrorIndex(int ind) {
729 errind = ind;
730 }
731
732 /**
733 * Returns whether or not this type of PDU is expecting some kind of response.
734 * This method is used in AbstractSnmpContext to help determine whether
735 * or not to start a thread that listens for a response when sending this
736 * PDU.
737 * The default is <em>true</em>.
738 *
739 * @return true if a response is expected, false if not.
740 * @since 4_14
741 */
742 protected boolean isExpectingResponse() {
743 return true;
744 }
745
746 /**
747 * This method is called when no answer is received after all
748 * retries.
749 * The application is notified of this.
750 * See also fillin()
751 */
752 private void handleNoAnswer() {
753 if (AsnObject.debug > 6) {
754 System.out.println(getClass().getName() + ".handleNoAnswer(): reqId=" + req_id);
755 }
756
757 // it's a lie, but it will prevent this method from
758 // being called twice
759 answered = true;
760
761 isTimedOut = true;
762 setErrorStatus(AsnObject.SNMP_ERR_GENERR);
763 setErrorIndex(0);
764
765 setChanged();
766 tell_them();
767 clearChanged();
768
769 synchronized (this) {
770 notify();
771 }
772 }
773
774 /**
775 * Fill in the received response.
776 *
777 * @see Pdu#getResponseVarbinds()
778 *
779 */
780 void fillin(AsnPduSequence seq) {
781 if (answered) {
782 if (AsnObject.debug > 6) {
783 System.out.println(getClass().getName() + ".fillin(): Got a second answer to reqId " + req_id);
784 }
785 return;
786 }
787
788 // fillin(null) can be called in case of a Decoding exception
789 if (seq != null) {
790 if (seq.isCorrect == true) {
791 int n = -1;
792 try {
793 // Fill in the request id
794 this.req_id = seq.getReqId();
795 setErrorStatus(seq.getWhatError());
796 setErrorIndex(seq.getWhereError());
797
798 // The varbinds from the response/report are set in a
799 // new Vector.
800 AsnSequence varBind = seq.getVarBind();
801 int size = varBind.getObjCount();
802 respVarbinds = new Vector(size, 1);
803 for (n = 0; n < size; n++) {
804 Object obj = varBind.getObj(n);
805 if (obj instanceof AsnSequence) {
806 AsnSequence varSeq = (AsnSequence) obj;
807 try {
808 varbind vb = new varbind(varSeq);
809 respVarbinds.addElement(vb);
810 new_value(n, vb);
811 } catch (IllegalArgumentException exc) {
812 }
813 }
814 }
815
816 // At this point, I don't know whether I received a
817 // response and should fill in only the respVarbind or
818 // whether I received a request (via ListeningContext)
819 // and I should fill in the reqVarbinds.
820 // So when reqVarbinds is empty, I clone the
821 // respVarbinds.
822 if (reqVarbinds.isEmpty()) {
823 reqVarbinds = (Vector) respVarbinds.clone();
824 }
825 } catch (Exception e) {
826 // it happens that an agent does not encode the varbind
827 // list properly. Since we try do decode as much as
828 // possible there may be wrong elements in this list.
829
830 DecodingException exc = new DecodingException(
831 "Incorrect varbind list, element " + n);
832 setErrorStatus(AsnObject.SNMP_ERR_DECODINGASN_EXC, exc);
833 }
834 } else {
835 // we couldn't read the whole message
836 // see AsnObject.AsnReadHeader, isCorrect
837
838 DecodingException exc = new DecodingException(
839 "Incorrect packet. No of bytes received less than packet length.");
840 setErrorStatus(AsnObject.SNMP_ERR_DECODINGPKTLNGTH_EXC, exc);
841 }
842 }
843
844 // always do 'setChanged', even if there are no varbinds.
845 setChanged();
846 tell_them();
847 clearChanged();
848
849 synchronized (this) {
850 got = true;
851 answered = true;
852 notify(); // see also handleNoAnswer()
853 if (trans != null) {
854 // free up the transmitter, since
855 // we are happy with the answer.
856 // trans may be null if we are receiving a trap.
857 trans.interruptMe();
858 }
859 }
860 }
861
862 /**
863 * Notify all observers. If a decoding exception had occurred, the argument
864 * will be replaced with the exception.
865 *
866 * <p>
867 * In the case of an exception, the error status
868 * will be set to one of the decoding errors (see
869 * <code>getErrorStatus</code>)
870 * and passed as the parameter
871 * <code>arg</code> in the
872 * <code>update(Observable obs, Object arg)</code>
873 * method.
874 * </p>
875 *
876 * @param arg The argument passed to update, can be a PduException.
877 * @see SnmpConstants#SNMP_ERR_DECODING_EXC
878 * @see #getErrorStatus
879 * @see #getResponseVarbinds
880 * @since 4.5
881 */
882 public void notifyObservers(Object arg) {
883 if (respException != null) {
884 super.notifyObservers(respException);
885 } else {
886 super.notifyObservers(arg);
887 }
888 }
889
890 }