All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snmp4j.Snmp Maven / Gradle / Ivy

The newest version!
/*_############################################################################
  _##
  _##  SNMP4J - Snmp.java
  _##
  _##  Copyright (C) 2003-2009  Frank Fock and Jochen Katz (SNMP4J.org)
  _##
  _##  Licensed under the Apache License, Version 2.0 (the "License");
  _##  you may not use this file except in compliance with the License.
  _##  You may obtain a copy of the License at
  _##
  _##      http://www.apache.org/licenses/LICENSE-2.0
  _##
  _##  Unless required by applicable law or agreed to in writing, software
  _##  distributed under the License is distributed on an "AS IS" BASIS,
  _##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  _##  See the License for the specific language governing permissions and
  _##  limitations under the License.
  _##
  _##########################################################################*/

package org.snmp4j;

import java.io.*;
import java.util.*;

import org.snmp4j.event.*;
import org.snmp4j.log.*;
import org.snmp4j.mp.*;
import org.snmp4j.security.*;
import org.snmp4j.smi.*;
import org.snmp4j.transport.*;
import org.snmp4j.util.*;

/**
 * The Snmp class is the core of SNMP4J. It provides functions to
 * send and receive SNMP PDUs. All SNMP PDU types can be send. Confirmed
 * PDUs can be sent synchronously and asynchronously.
 * 

* The Snmp class is transport protocol independent. Support for * a specific {@link TransportMapping} instance is added by calling the * {@link #addTransportMapping(TransportMapping transportMapping)} method or * creating a Snmp instance by using the non-default constructor * with the corresponding transport mapping. Transport mappings are used * for incoming and outgoing messages. *

* To setup a default SNMP session for UDP transport and with SNMPv3 support * the following code snippet can be used: *

*

 *   Address targetAddress = GenericAddress.parse("udp:127.0.0.1/161");
 *   TransportMapping transport = new DefaultUdpTransportMapping();
 *   snmp = new Snmp(transport);
 *   USM usm = new USM(SecurityProtocols.getInstance(),
 *                     new OctetString(MPv3.createLocalEngineID()), 0);
 *   SecurityModels.getInstance().addSecurityModel(usm);
 *   transport.listen();
 * 
*

* How a synchronous SNMPv3 message with authentication and privacy is then * sent illustrates the following code snippet: *

*

 *   // add user to the USM
 *   snmp.getUSM().addUser(new OctetString("MD5DES"),
 *                         new UsmUser(new OctetString("MD5DES"),
 *                                     AuthMD5.ID,
 *                                     new OctetString("MD5DESUserAuthPassword"),
 *                                     PrivDES.ID,
 *                                     new OctetString("MD5DESUserPrivPassword")));
 *   // create the target
 *   UserTarget target = new UserTarget();
 *   target.setAddress(targetAddress);
 *   target.setRetries(1);
 *   target.setTimeout(5000);
 *   target.setVersion(SnmpConstants.version3);
 *   target.setSecurityLevel(SecurityLevel.AUTH_PRIV);
 *   target.setSecurityName(new OctetString("MD5DES"));
 *
 *   // create the PDU
 *   PDU pdu = new ScopedPDU();
 *   pdu.add(new VariableBinding(new OID("1.3.6")));
 *   pdu.setType(PDU.GETNEXT);
 *
 *   // send the PDU
 *   ResponseEvent response = snmp.send(pdu, target);
 *   // extract the response PDU (could be null if timed out)
 *   PDU responsePDU = response.getResponse();
 *   // extract the address used by the agent to send the response:
 *   Address peerAddress = response.getPeerAddress();
 * 
*

* An asynchronous SNMPv1 request is sent by the following code: *

 *   // setting up target
 *   CommunityTarget target = new CommunityTarget();
 *   target.setCommunity(new OctetString("public"));
 *   target.setAddress(targetAddress);
 *   target.setRetries(2);
 *   target.setTimeout(1500);
 *   target.setVersion(SnmpConstants.version1);
 *   // creating PDU
 *   PDU pdu = new PDU();
 *   pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,1})));
 *   pdu.add(new VariableBinding(new OID(new int[] {1,3,6,1,2,1,1,2})));
 *   pdu.setType(PDU.GETNEXT);
 *   // sending request
 *   ResponseListener listener = new ResponseListener() {
 *     public void onResponse(ResponseEvent event) {
 *       // Always cancel async request when response has been received
 *       // otherwise a memory leak is created! Not canceling a request
 *       // immediately can be useful when sending a request to a broadcast
 *       // address.
 *       ((Snmp)event.getSource()).cancel(event.getRequest(), this);
 *       System.out.println("Received response PDU is: "+event.getResponse());
 *     }
 *   };
 *   snmp.sendPDU(pdu, target, null, listener);
 * 
*

* Traps (notifications) and other SNMP PDUs can be received by adding the * folling code to the first code snippet above: *
 *   CommandResponder trapPrinter = new CommandResponder() {
 *     public synchronized void processPdu(CommandResponderEvent e) {
 *       PDU command = e.getPDU();
 *       if (command != null) {
 *         System.out.println(command.toString());
 *       }
 *     }
 *   };
 *   snmp.addCommandResponder(trapPrinter);
 * 
*

* * @author Frank Fock * @version 1.10 */ public class Snmp implements Session, CommandResponder { private static final LogAdapter logger = LogFactory.getLogger(Snmp.class); private static final int DEFAULT_MAX_REQUEST_STATUS = 2; private static final int ENGINE_ID_DISCOVERY_MAX_REQUEST_STATUS = 0; // Message processing implementation private MessageDispatcher messageDispatcher; /** * The pendingRequests table contains pending requests * accessed trough the key PduHandle */ private Map pendingRequests = new Hashtable(50); /** * The asyncRequests table contains pending requests * accessed trough the key userObject */ private Map asyncRequests = new Hashtable(50); // Timer for retrying pending requests private CommonTimer timer; // Listeners for request and trap PDUs private transient Vector commandResponderListeners; private TimeoutModel timeoutModel = new DefaultTimeoutModel(); // Dispatcher for notification listeners - not needed by default private NotificationDispatcher notificationDispatcher = null; // Default ReportHandler private ReportHandler reportHandler = new ReportProcessor(); /** * Creates a Snmp instance that uses a * MessageDispatcherImpl with no message processing * models and no security protols (by default). You will have to add * those by calling the appropriate methods on * {@link #getMessageDispatcher()}. *

* At least one transport mapping has to be added before {@link #listen()} * is called in order to be able to send and receive SNMP messages. *

* To initialize a Snmp instance created with this constructor * follow this sample code: *

   * Transport transport = ...;
   * Snmp snmp = new Snmp();
   * SecurityProtocols.getInstance().addDefaultProtocols();
   * MessageDispatcher disp = snmp.getMessageDispatcher();
   * disp.addMessageProcessingModel(new MPv1());
   * disp.addMessageProcessingModel(new MPv2c());
   * snmp.addTransportMapping(transport);
   * OctetString localEngineID = new OctetString(
   *    MPv3.createLocalEngineID());
   *    // For command generators, you may use the following code to avoid
   *    // engine ID clashes:
   *    // MPv3.createLocalEngineID(
   *    //   new OctetString("MyUniqueID"+System.currentTimeMillis())));
   * USM usm = new USM(SecurityProtocols.getInstance(), localEngineID, 0);
   * disp.addMessageProcessingModel(new MPv3(usm));
   * snmp.listen();
   * 
*/ public Snmp() { this.messageDispatcher = new MessageDispatcherImpl(); } /** * Interface for handling reports. * * @author Frank Fock * @version 1.6 * @since 1.6 */ public static interface ReportHandler { void processReport(PduHandle pduHandle, CommandResponderEvent event); } protected final void initMessageDispatcher() { this.messageDispatcher.addCommandResponder(this); this.messageDispatcher.addMessageProcessingModel(new MPv2c()); this.messageDispatcher.addMessageProcessingModel(new MPv1()); this.messageDispatcher.addMessageProcessingModel(new MPv3()); SecurityProtocols.getInstance().addDefaultProtocols(); } /** * Creates a Snmp instance that uses a * MessageDispatcherImpl with all supported message processing * models and the default security protols for dispatching. *

* To initialize a Snmp instance created with this constructor * follow this sample code: *

   * Transport transport = ...;
   * Snmp snmp = new Snmp(transport);
   * OctetString localEngineID =
   *   new OctetString(snmp.getMPv3().getLocalEngineID());
   * USM usm = new USM(SecurityProtocols.getInstance(), localEngineID, 0);
   * SecurityModels.getInstance().addSecurityModel(usm);
   * snmp.listen();
   * 
* * @param transportMapping TransportMapping * the initial TransportMapping. You can add more or remove * the same later. */ public Snmp(TransportMapping transportMapping) { this(); initMessageDispatcher(); if (transportMapping != null) { addTransportMapping(transportMapping); } } /** * Creates a Snmp instance by supplying a * MessageDispatcher and a TransportMapping. *

* As of version 1.1, the supplied message dispatcher is not altered * in terms of adding any message processing models to it. This has to be * done now outside the Snmp class. *

* To initialize a Snmp instance created with this constructor * follow this sample code: *

   * Transport transport = ...;
   * SecurityProtocols.getInstance().addDefaultProtocols();
   * MessageDispatcher disp = new MessageDispatcherImpl();
   * disp.addMessageProcessingModel(new MPv1());
   * disp.addMessageProcessingModel(new MPv2c());
   * Snmp snmp = new Snmp(disp, transport);
   * OctetString localEngineID = new OctetString(
   *    MPv3.createLocalEngineID());
   *    // For command generators, you may use the following code to avoid
   *    // engine ID clashes:
   *    // MPv3.createLocalEngineID(
   *    //   new OctetString("MyUniqueID"+System.currentTimeMillis())));
   * USM usm = new USM(SecurityProtocols.getInstance(), localEngineID, 0);
   * disp.addMessageProcessingModel(new MPv3(usm));
   * snmp.listen();
   * 
* @param messageDispatcher * a MessageDispatcher instance that will be used to * dispatch incoming and outgoing messages. * @param transportMapping * the initial TransportMapping, * which may be null. You can add or remove transport * mappings later using {@link #addTransportMapping} and * {@link #removeTransportMapping} respectively. */ public Snmp(MessageDispatcher messageDispatcher, TransportMapping transportMapping) { this.messageDispatcher = messageDispatcher; this.messageDispatcher.addCommandResponder(this); if (transportMapping != null) { addTransportMapping(transportMapping); } } /** * Creates a Snmp instance by supplying a * MessageDispatcher. *

* The supplied message dispatcher is not altered * in terms of adding any message processing models to it. This has to be * done now outside the Snmp class. *

*

* Do not forget to add at least one transport mapping before calling the * listen method! *

* To initialize a Snmp instance created with this constructor * follow this sample code: *

   * Transport transport = ...;
   * SecurityProtocols.getInstance().addDefaultProtocols();
   * MessageDispatcher disp = new MessageDispatcherImpl();
   * disp.addMessageProcessingModel(new MPv1());
   * disp.addMessageProcessingModel(new MPv2c());
   * Snmp snmp = new Snmp(disp);
   * snmp.addTransportMapping(transport);
   * OctetString localEngineID = new OctetString(
   *    MPv3.createLocalEngineID());
   *    // For command generators, you may use the following code to avoid
   *    // engine ID clashes:
   *    // MPv3.createLocalEngineID(
   *    //   new OctetString("MyUniqueID"+System.currentTimeMillis())));
   * USM usm = new USM(SecurityProtocols.getInstance(), localEngineID, 0);
   * disp.addMessageProcessingModel(new MPv3(usm));
   * snmp.listen();
   * 
* * @param messageDispatcher * a MessageDispatcher instance that will be used to * dispatch incoming and outgoing messages. * @since 1.5 */ public Snmp(MessageDispatcher messageDispatcher) { this.messageDispatcher = messageDispatcher; this.messageDispatcher.addCommandResponder(this); } /** * Returns the message dispatcher associated with this SNMP session. * @return * a MessageDispatcher instance. * @since 1.1 */ public MessageDispatcher getMessageDispatcher() { return messageDispatcher; } /** * Adds a TransportMapping to this SNMP session. * @param transportMapping * a TransportMapping instance. */ public void addTransportMapping(TransportMapping transportMapping) { // connect transport mapping with message dispatcher messageDispatcher.addTransportMapping(transportMapping); transportMapping.addTransportListener(messageDispatcher); } /** * Removes the specified transport mapping from this SNMP session. * If the transport mapping is not currently part of this SNMP session, * this method will have no effect. * @param transportMapping * a previously added TransportMapping. */ public void removeTransportMapping(TransportMapping transportMapping) { messageDispatcher.removeTransportMapping(transportMapping); transportMapping.removeTransportListener(messageDispatcher); } /** * Adds a notification listener to this Snmp instance. Calling this method * will create a transport mapping for the specified listening address and * registers the provided CommandResponder with the internal * NotificationDispatcher. * * @param listenAddress * the Address denoting the transport end-point * (interface and port) to listen for incoming notifications. * @param listener * the CommandResponder instance that should handle * the received notifications. * @return * true if registration was successful and false * if, for example, the transport mapping for the listen address could not * be created. * @since 1.6 */ public synchronized boolean addNotificationListener(Address listenAddress, CommandResponder listener) { TransportMapping tm = TransportMappings.getInstance().createTransportMapping(listenAddress); if (tm == null) { if (logger.isInfoEnabled()) { logger.info("Failed to add notification listener for address: "+ listenAddress); } return false; } if (tm instanceof ConnectionOrientedTransportMapping) { ((ConnectionOrientedTransportMapping)tm).setConnectionTimeout(0); } tm.addTransportListener(messageDispatcher); if (notificationDispatcher == null) { notificationDispatcher = new NotificationDispatcher(); addCommandResponder(notificationDispatcher); } notificationDispatcher.addNotificationListener(listenAddress, tm, listener); try { tm.listen(); if (logger.isInfoEnabled()) { logger.info("Added notification listener for address: "+ listenAddress); } return true; } catch (IOException ex) { logger.warn("Failed to initialize notification listener for address '"+ listenAddress+"': "+ex.getMessage()); return false; } } /** * Removes (deletes) the notification listener for the specified transport * endpoint. * @param listenAddress * the listen Address to be removed. * @return * true if the notification listener has been removed * successfully. */ public synchronized boolean removeNotificationListener(Address listenAddress) { if (notificationDispatcher != null) { if (logger.isInfoEnabled()) { logger.info("Removing notification listener for address: "+ listenAddress); } return notificationDispatcher.removeNotificationListener(listenAddress); } else { return false; } } /** * Puts all associated transport mappings into listen mode. * @throws IOException * if a transport mapping throws an IOException when its * {@link TransportMapping#listen()} method has been called. */ public void listen() throws IOException { for (Iterator it = messageDispatcher.getTransportMappings().iterator(); it.hasNext(); ) { TransportMapping tm = (TransportMapping) it.next(); if (!tm.isListening()) { tm.listen(); } } } /** * Gets the next unique request ID. The returned ID is unique across * the last 2^31-1 IDs generated by this message dispatcher. * @return * an integer value in the range 1..2^31-1. The returned ID can be used * to map responses to requests send through this message dispatcher. * @since 1.1 * @see MessageDispatcher#getNextRequestID */ public int getNextRequestID() { return messageDispatcher.getNextRequestID(); } /** * Closes the session and frees any allocated resources, i.e. sockets and * the internal thread for processing request timeouts. *

* If there are any pending requests, the {@link ResponseListener} associated * with the pending requests, will be called with a null * response and a {@link InterruptedException} in the error member of the * {@link ResponseEvent} returned. *

* After a Session has been closed it must not be used anymore. * @throws IOException * if a transport mapping cannot be closed successfully. */ public void close() throws IOException { for (Iterator it = messageDispatcher.getTransportMappings().iterator(); it.hasNext(); ) { TransportMapping tm = (TransportMapping) it.next(); if (tm.isListening()) { tm.close(); } } CommonTimer t = timer; timer = null; if (t != null) { t.cancel(); } // close all notification listeners if (notificationDispatcher != null) { notificationDispatcher.closeAll(); } List pr; synchronized (pendingRequests) { pr = new ArrayList(pendingRequests.values()); } for (Iterator it = pr.iterator(); it.hasNext(); ) { PendingRequest pending = (PendingRequest) it.next(); ResponseEvent e = new ResponseEvent(this, null, pending.pdu, null, pending.userObject, new InterruptedException( "Snmp session has been closed")); ResponseListener l = pending.listener; if (l != null) { l.onResponse(e); } } } /** * Sends a GET request to a target. This method sets the PDU's type to * {@link PDU#GET} and then sends a synchronous request to the supplied * target. * @param pdu * a PDU instance. For SNMPv3 messages, the supplied PDU * instance has to be a ScopedPDU instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @return * the received response encapsulated in a ResponseEvent * instance. To obtain the received response PDU call * {@link ResponseEvent#getResponse()}. If the request timed out, * that method will return null. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public ResponseEvent get(PDU pdu, Target target) throws IOException { pdu.setType(PDU.GET); return send(pdu, target); } /** * Asynchronously sends a GET request PDU to the given target. * The response is then returned by calling the supplied * ResponseListener instance. * * @param pdu * the PDU instance to send. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @param userHandle * an user defined handle that is returned when the request is returned * via the listener object. * @param listener * a ResponseListener instance that is called when * pdu is a confirmed PDU and the request is either answered * or timed out. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public void get(PDU pdu, Target target, Object userHandle, ResponseListener listener) throws IOException { pdu.setType(PDU.GET); send(pdu, target, userHandle, listener); } /** * Sends a GETNEXT request to a target. This method sets the PDU's type to * {@link PDU#GETNEXT} and then sends a synchronous request to the supplied * target. This method is a convenience wrapper for the * {@link #send(PDU pdu, Target target)} method. * @param pdu * a PDU instance. For SNMPv3 messages, the supplied PDU * instance has to be a ScopedPDU instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @return * the received response encapsulated in a ResponseEvent * instance. To obtain the received response PDU call * {@link ResponseEvent#getResponse()}. If the request timed out, * that method will return null. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public ResponseEvent getNext(PDU pdu, Target target) throws IOException { pdu.setType(PDU.GETNEXT); return send(pdu, target); } /** * Asynchronously sends a GETNEXT request PDU to the given * target. The response is then returned by calling the supplied * ResponseListener instance. * * @param pdu * the PDU instance to send. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @param userHandle * an user defined handle that is returned when the request is returned * via the listener object. * @param listener * a ResponseListener instance that is called when * pdu is a confirmed PDU and the request is either answered * or timed out. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public void getNext(PDU pdu, Target target, Object userHandle, ResponseListener listener) throws IOException { pdu.setType(PDU.GETNEXT); send(pdu, target, userHandle, listener); } /** * Sends a GETBULK request to a target. This method sets the PDU's type to * {@link PDU#GETBULK} and then sends a synchronous request to the supplied * target. This method is a convenience wrapper for the * {@link #send(PDU pdu, Target target)} method. * @param pdu * a PDU instance. For SNMPv3 messages, the supplied PDU * instance has to be a ScopedPDU instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @return * the received response encapsulated in a ResponseEvent * instance. To obtain the received response PDU call * {@link ResponseEvent#getResponse()}. If the request timed out, * that method will return null. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public ResponseEvent getBulk(PDU pdu, Target target) throws IOException { pdu.setType(PDU.GETBULK); return send(pdu, target); } /** * Asynchronously sends a GETBULK request PDU to the given * target. The response is then returned by calling the supplied * ResponseListener instance. * * @param pdu * the PDU instance to send. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @param userHandle * an user defined handle that is returned when the request is returned * via the listener object. * @param listener * a ResponseListener instance that is called when * pdu is a confirmed PDU and the request is either answered * or timed out. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public void getBulk(PDU pdu, Target target, Object userHandle, ResponseListener listener) throws IOException { pdu.setType(PDU.GETBULK); send(pdu, target, userHandle, listener); } /** * Sends an INFORM request to a target. This method sets the PDU's type to * {@link PDU#INFORM} and then sends a synchronous request to the supplied * target. This method is a convenience wrapper for the * {@link #send(PDU pdu, Target target)} method. * @param pdu * a PDU instance. For SNMPv3 messages, the supplied PDU * instance has to be a ScopedPDU instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @return * the received response encapsulated in a ResponseEvent * instance. To obtain the received response PDU call * {@link ResponseEvent#getResponse()}. If the request timed out, * that method will return null. * @throws IOException * if the inform request could not be send to the specified target. * @since 1.1 */ public ResponseEvent inform(PDU pdu, Target target) throws IOException { pdu.setType(PDU.INFORM); return send(pdu, target); } /** * Asynchronously sends an INFORM request PDU to the given * target. The response is then returned by calling the supplied * ResponseListener instance. * * @param pdu * the PDU instance to send. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @param userHandle * an user defined handle that is returned when the request is returned * via the listener object. * @param listener * a ResponseListener instance that is called when * pdu is a confirmed PDU and the request is either answered * or timed out. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public void inform(PDU pdu, Target target, Object userHandle, ResponseListener listener) throws IOException { pdu.setType(PDU.INFORM); send(pdu, target, userHandle, listener); } /** * Sends a SNMPv1 trap to a target. This method sets the PDU's type to * {@link PDU#V1TRAP} and then sends it to the supplied target. This method * is a convenience wrapper for the {@link #send(PDU pdu, Target target)} * method. * @param pdu * a PDUv1 instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. The selected SNMP protocol version for the * target must be {@link SnmpConstants#version1}. * @throws IOException * if the trap cannot be sent. * @since 1.1 */ public void trap(PDUv1 pdu, Target target) throws IOException { if (target.getVersion() != SnmpConstants.version1) { throw new IllegalArgumentException( "SNMPv1 trap PDU must be used with SNMPv1"); } pdu.setType(PDU.V1TRAP); send(pdu, target); } /** * Sends a SNMPv2c or SNMPv3 notification to a target. This method sets the * PDU's type to {@link PDU#NOTIFICATION} and then sends it to the supplied * target. This method is a convenience wrapper for the * {@link #send(PDU pdu, Target target)} method. * @param pdu * a PDUv1 instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. The selected SNMP protocol version for the * target must be {@link SnmpConstants#version2c} or * {@link SnmpConstants#version2c}. * @throws IOException * if the notification cannot be sent. * @since 1.1 */ public void notify(PDU pdu, Target target) throws IOException { if (target.getVersion() == SnmpConstants.version1) { throw new IllegalArgumentException( "Notifications PDUs cannot be used with SNMPv1"); } pdu.setType(PDU.NOTIFICATION); send(pdu, target); } /** * Sends a SET request to a target. This method sets the PDU's type to * {@link PDU#SET} and then sends a synchronous request to the supplied * target. * @param pdu * a PDU instance. For SNMPv3 messages, the supplied PDU * instance has to be a ScopedPDU instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @return * the received response encapsulated in a ResponseEvent * instance. To obtain the received response PDU call * {@link ResponseEvent#getResponse()}. If the request timed out, * that method will return null. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public ResponseEvent set(PDU pdu, Target target) throws IOException { pdu.setType(PDU.SET); return send(pdu, target); } /** * Asynchronously sends a SET request PDU to the given target. * The response is then returned by calling the supplied * ResponseListener instance. * * @param pdu * the PDU instance to send. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @param userHandle * an user defined handle that is returned when the request is returned * via the listener object. * @param listener * a ResponseListener instance that is called when * pdu is a confirmed PDU and the request is either answered * or timed out. * @throws IOException * if the PDU cannot be sent to the target. * @since 1.1 */ public void set(PDU pdu, Target target, Object userHandle, ResponseListener listener) throws IOException { pdu.setType(PDU.SET); send(pdu, target, userHandle, listener); } public ResponseEvent send(PDU pdu, Target target) throws IOException { return send(pdu, target, null); } /** * Sends a PDU to the given target and if the PDU * is a confirmed request, then the received response is returned * synchronously. * @param pdu * a PDU instance. When sending a SNMPv1 trap PDU, the * supplied PDU instance must be a PDUv1. For all types of * SNMPv3 messages, the supplied PDU instance has to be a * ScopedPDU instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @param transport * specifies the TransportMapping to be used when sending * the PDU. If transport is null, the associated * message dispatcher will try to determine the transport mapping by the * target's address. * @return * the received response encapsulated in a ResponseEvent * instance. To obtain the received response PDU call * {@link ResponseEvent#getResponse()}. If the request timed out, * that method will return null. If the sent pdu * is an unconfirmed PDU (notification, response, or report), then * null will be returned. * @throws IOException * if the message could not be sent. * @see PDU * @see ScopedPDU * @see PDUv1 */ public ResponseEvent send(PDU pdu, Target target, TransportMapping transport) throws IOException { return send(pdu, target, transport, DEFAULT_MAX_REQUEST_STATUS); } private ResponseEvent send(PDU pdu, Target target, TransportMapping transport, int maxRequestStatus) throws IOException { if (!pdu.isConfirmedPdu()) { sendMessage(pdu, target, transport, null); return null; } if (timer == null) { createPendingTimer(); } SyncResponseListener syncResponse = new SyncResponseListener(); PendingRequest retryRequest = null; synchronized (syncResponse) { PduHandle handle = null; PendingRequest request = new PendingRequest(syncResponse, target, pdu, target, transport); request.maxRequestStatus = maxRequestStatus; handle = sendMessage(pdu, target, transport, request); long totalTimeout = timeoutModel.getRequestTimeout(target.getRetries(), target.getTimeout()); long stopTime = System.currentTimeMillis()+totalTimeout; try { while ((syncResponse.getResponse() == null) && (System.currentTimeMillis() < stopTime)) { syncResponse.wait(totalTimeout); } retryRequest = (PendingRequest) pendingRequests.remove(handle); if (logger.isDebugEnabled()) { logger.debug("Removed pending request with handle: " + handle); } request.setFinished(); request.cancel(); } catch (InterruptedException iex) { logger.warn(iex); // cleanup request request.setFinished(); request.cancel(); retryRequest = (PendingRequest) pendingRequests.remove(handle); if (retryRequest != null) { retryRequest.setFinished(); retryRequest.cancel(); } Thread.currentThread().interrupt(); } finally { if (!request.finished) { // free resources retryRequest = (PendingRequest) pendingRequests.remove(handle); if (retryRequest != null) { retryRequest.setFinished(); retryRequest.cancel(); } } } } if (retryRequest != null) { retryRequest.setFinished(); retryRequest.cancel(); } if (syncResponse.getResponse() == null) { syncResponse.response = new ResponseEvent(Snmp.this, null, pdu, null, null); } return syncResponse.response; } private synchronized void createPendingTimer() { if (timer == null) { timer = SNMP4JSettings.getTimerFactory().createTimer(); } } public void send(PDU pdu, Target target, Object userHandle, ResponseListener listener) throws IOException { send(pdu, target, null, userHandle, listener); } public void send(PDU pdu, Target target, TransportMapping transport, Object userHandle, ResponseListener listener) throws IOException { if (!pdu.isConfirmedPdu()) { sendMessage(pdu, target, transport, null); return; } if (timer == null) { createPendingTimer(); } PendingRequest request = new AsyncPendingRequest(listener, userHandle, pdu, target, transport); sendMessage(pdu, target, transport, request); } /** * Sends a PDU to the given target and returns the received * response PDU. * @param pdu * a PDU instance. When sending a SNMPv1 trap PDU, the * supplied PDU instance must be a PDUv1. For all types of * SNMPv3 messages, the supplied PDU instance has to be a * ScopedPDU instance. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @return * the received response PDU or null * if the request timed out and if the PDU type of pdu * is an unconfirmed PDU (i.e., trap or notification). * @throws IOException * if the message could not be sent. * @see PDU * @see ScopedPDU * @see PDUv1 * @deprecated This method has been deprecated because it does not return * the transport address of the entity (target) that sent the response. * Please use {@link #send(PDU pdu, Target target)} instead. It returns * a {@link ResponseEvent} object holding the response PDU and transport * address of a successfully received response. This method will be supported * until v2.0. */ public PDU sendPDU(PDU pdu, Target target) throws IOException { ResponseEvent e = send(pdu, target); if (e != null) { return e.getResponse(); } // pdu sent is unconfirmed one return null; } /** * Asynchronously sends a PDU to the given target. The response * is then returned by calling the supplied ResponseListener * instance. * * @param pdu * the PDU instance to send. * @param target * the Target instance representing the target SNMP engine where to send * the pdu. * @param userHandle * an user defined handle that is returned when the request is returned * via the listener object. * @param listener * a ResponseListener instance that is called when * pdu is a confirmed PDU and the request is either answered * or timed out. * @deprecated Please use {@link #send(PDU pdu, Target target, Object * userHandle, ResponseListener listener)} instead. It has exactly * the same function but follows the new naming scheme. This method * will be supported until v2.0. * @throws IOException * if the PDU could not be sent to the specified target. */ public void sendPDU(PDU pdu, Target target, Object userHandle, ResponseListener listener) throws IOException { send(pdu, target, userHandle, listener); } /** * Actually sends a PDU to a target and returns a handle for the sent PDU. * @param pdu * the PDU instance to be sent. * @param target * a Target instance denoting the target SNMP entity. * @param transport * the (optional) transport mapping to be used to send the request. * If transport is null a suitable transport * mapping is determined from the target address. * @param pduHandleCallback * callback for newly created PDU handles before the request is sent out. * @throws IOException * if the transport fails to send the PDU or the if the message cannot * be BER encoded. * @return PduHandle * that uniquely identifies the sent PDU for further reference. */ protected PduHandle sendMessage(PDU pdu, Target target, TransportMapping transport, PduHandleCallback pduHandleCallback) throws IOException { PduHandle handle = null; if (target instanceof SecureTarget) { SecureTarget secureTarget = (SecureTarget) target; handle = messageDispatcher.sendPdu(transport, secureTarget.getAddress(), secureTarget.getVersion(), secureTarget.getSecurityModel(), secureTarget.getSecurityName(). getValue(), secureTarget.getSecurityLevel(), pdu, true, pduHandleCallback); } else if (target instanceof CommunityTarget) { CommunityTarget communityTarget = (CommunityTarget) target; int securityModel = SecurityModel.SECURITY_MODEL_SNMPv2c; if (communityTarget.getVersion() == SnmpConstants.version1) { securityModel = SecurityModel.SECURITY_MODEL_SNMPv1; } handle = messageDispatcher.sendPdu(transport, communityTarget.getAddress(), communityTarget.getVersion(), securityModel, communityTarget.getCommunity(). getValue(), SecurityLevel.NOAUTH_NOPRIV, pdu, true, pduHandleCallback); } return handle; } public void cancel(PDU request, ResponseListener listener) { AsyncRequestKey key = new AsyncRequestKey(request, listener); PduHandle pending = (PduHandle) asyncRequests.remove(key); if (logger.isDebugEnabled()) { logger.debug("Cancelling pending request with handle " + pending); } if (pending != null) { PendingRequest pendingRequest = (PendingRequest) pendingRequests.remove(pending); if (pendingRequest != null) { synchronized (pendingRequest) { pendingRequest.setFinished(); pendingRequest.cancel(); } } } } /** * Sets the local engine ID for the SNMP entity represented by this * Snmp instance. This is a convenience method that sets * the local engine ID in the associated MPv3 and * USM. * @param engineID * a byte array containing the local engine ID. The length and content * has to comply with the constraints defined in the SNMP-FRAMEWORK-MIB. * @param engineBoots * the number of boots of this SNMP engine (zero based). * @param engineTime * the number of seconds since the value of engineBoots last changed. * @see MPv3 * @see USM */ public void setLocalEngine(byte[] engineID, int engineBoots, int engineTime) { MPv3 mpv3 = getMPv3(); mpv3.setLocalEngineID(engineID); USM usm = (USM) mpv3.getSecurityModel(SecurityModel.SECURITY_MODEL_USM); usm.setLocalEngine(new OctetString(engineID), engineBoots, engineTime); } /** * Gets the local engine ID if the MPv3 is available, otherwise a runtime * exception is thrown. * @return byte[] * the local engine ID. */ public byte[] getLocalEngineID() { return getMPv3().getLocalEngineID(); } private MPv3 getMPv3() { MPv3 mpv3 = (MPv3) getMessageProcessingModel(MessageProcessingModel.MPv3); if (mpv3 == null) { throw new NoSuchElementException("MPv3 not available"); } return mpv3; } /** * Discovers the engine ID of the SNMPv3 entity denoted by the supplied * address. This method does not need to be called for normal operation, * because SNMP4J automatically discovers authoritative engine IDs and * also automatically synchronize engine time values. *

* For this method to operate succesfully, the discover engine IDs * flag in {@link USM} must be true (which is the default). * * @param address * an Address instance representing the transport address of the SNMPv3 * entity for which its authoritative engine ID should be discovered. * @param timeout * the maximum time in milliseconds to wait for a response. * @return * a byte array containing the authoritative engine ID or null * if it could not be discovered. * @see USM#setEngineDiscoveryEnabled(boolean enableEngineDiscovery) */ public byte[] discoverAuthoritativeEngineID(Address address, long timeout) { MPv3 mpv3 = getMPv3(); // We need to remove the engine ID explicitly to be sure that it is updated OctetString engineID = mpv3.removeEngineID(address); // Now try to remove the engine as well if (engineID != null) { USM usm = getUSM(); if (usm != null) { usm.removeEngineTime(engineID); } } ScopedPDU scopedPDU = new ScopedPDU(); scopedPDU.setType(PDU.GET); SecureTarget target = new UserTarget(); target.setTimeout(timeout); target.setAddress(address); target.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV); try { send(scopedPDU, target, null, ENGINE_ID_DISCOVERY_MAX_REQUEST_STATUS); OctetString authoritativeEngineID = mpv3.getEngineID(address); if (authoritativeEngineID == null) { return null; } // we copy the byte array here, so we are sure nobody can modify the // internal cache. return new OctetString(authoritativeEngineID.getValue()).getValue(); } catch (IOException ex) { logger.error( "IO error while trying to discover authoritative engine ID: " + ex); return null; } } /** * Gets the User Based Security Model (USM). This is a convenience method * that uses the {@link MPv3#getSecurityModel} method of the associated MPv3 * instance to get the USM. * @return * the USM instance associated with the MPv3 bound to this * Snmp instance, or null otherwise. */ public USM getUSM() { MPv3 mp = (MPv3) getMessageProcessingModel(MPv3.ID); if (mp != null) { return (USM)mp.getSecurityModel(SecurityModel.SECURITY_MODEL_USM); } return null; } /** * Gets the message processing model for the supplied ID. * @param messageProcessingModel * a mesage processing model ID as defined in {@link MessageProcessingModel}. * @return MessageProcessingModel * a MessageProcessingModel if * messageProcessingModel has been registered with the * message dispatcher associated with this SNMP session. */ public MessageProcessingModel getMessageProcessingModel(int messageProcessingModel) { return messageDispatcher.getMessageProcessingModel(messageProcessingModel); } /** * Process an incoming request or notification PDU. * * @param event * a CommandResponderEvent with the decoded incoming PDU as * dispatched to this method call by the associated message dispatcher. */ public void processPdu(CommandResponderEvent event) { PduHandle handle = event.getPduHandle(); PDU pdu = event.getPDU(); if (pdu.getType() == PDU.RESPONSE) { event.setProcessed(true); PendingRequest request; if (logger.isDebugEnabled()) { logger.debug("Looking up pending request with handle " + handle); } synchronized (pendingRequests) { request = (PendingRequest) pendingRequests.get(handle); if (request != null) { request.responseReceived(); } } if (request == null) { if (logger.isWarnEnabled()) { logger.warn("Received response that cannot be matched to any " + "outstanding request, address=" + event.getPeerAddress() + ", requestID=" + pdu.getRequestID()); } } else { ResponseListener l = request.listener; if (l != null) { l.onResponse(new ResponseEvent(this, event.getPeerAddress(), request.pdu, pdu, request.userObject)); } } } else if (pdu.getType() == PDU.REPORT) { event.setProcessed(true); reportHandler.processReport(handle, event); } else { if (logger.isDebugEnabled()) { logger.debug("Fire process PDU event: " + event.toString()); } fireProcessPdu(event); } } class ReportProcessor implements ReportHandler { public void processReport(PduHandle handle, CommandResponderEvent e) { PDU pdu = e.getPDU(); logger.debug("Searching pending request with handle" + handle); PendingRequest request = (PendingRequest) pendingRequests.get(handle); if (request == null) { logger.warn("Unmatched report PDU received from " + e.getPeerAddress()); return; } if (pdu.size() == 0) { logger.error("Illegal report PDU received from " + e.getPeerAddress() + " missing report variable binding"); return; } VariableBinding vb = pdu.get(0); if (vb == null) { logger.error("Received illegal REPORT PDU from " + e.getPeerAddress()); return; } OID firstOID = vb.getOid(); boolean resend = false; if (request.requestStatus < request.maxRequestStatus) { switch (request.requestStatus) { case 0: if (SnmpConstants.usmStatsUnknownEngineIDs.equals(firstOID)) { resend = true; } else if (SnmpConstants.usmStatsNotInTimeWindows.equals(firstOID)) { request.requestStatus++; resend = true; } break; case 1: if (SnmpConstants.usmStatsNotInTimeWindows.equals(firstOID)) { resend = true; } break; } } // if legal report PDU received, then resend request if (resend) { logger.debug("Send new request after report."); request.requestStatus++; try { // We need no callback here because we already have an equivalent // handle registered. PduHandle resentHandle = sendMessage(request.pdu, request.target, e.getTransportMapping(), null); // make sure reference to handle is hold until request is finished, // because otherwise cache information may get lost (WeakHashMap) request.key = resentHandle; } catch (IOException iox) { logger.error("Failed to send message to " + request.target + ": " + iox.getMessage()); return; } } else { boolean intime; // Get the request members needed before canceling the request // which resets it ResponseListener reqListener = request.listener; PDU reqPDU = request.pdu; Object reqUserObject = request.userObject; synchronized (request) { intime = request.cancel(); } // remove pending request // (sync is not needed as request is already canceled) pendingRequests.remove(handle); if (intime && (reqListener != null)) { // return report reqListener.onResponse(new ResponseEvent(this, e.getPeerAddress(), reqPDU, pdu, reqUserObject)); } else { // silently drop late report if (logger.isInfoEnabled()) { logger.info("Received late report from " + e.getPeerAddress() + " with request ID " + pdu.getRequestID()); } } } } } /** * Removes a CommandResponder from this SNMP session. * @param listener * a previously added CommandResponder instance. */ public synchronized void removeCommandResponder(CommandResponder listener) { if (commandResponderListeners != null && commandResponderListeners.contains(listener)) { Vector v = (Vector) commandResponderListeners.clone(); v.removeElement(listener); commandResponderListeners = v; } } /** * Adds a CommandResponder to this SNMP session. * The command responder will then be informed about incoming SNMP PDUs of * any kind that are not related to any outstanding requests of this SNMP * session. * * @param listener * the CommandResponder instance to be added. */ public synchronized void addCommandResponder(CommandResponder listener) { Vector v = (commandResponderListeners == null) ? new Vector(2) : (Vector) commandResponderListeners.clone(); if (!v.contains(listener)) { v.addElement(listener); commandResponderListeners = v; } } /** * Fires a CommandResponderEvent event to inform listeners about * a received PDU. If a listener has marked the event as processed further * listeners will not be informed about the event. * @param event * a CommandResponderEvent. */ protected void fireProcessPdu(CommandResponderEvent event) { if (commandResponderListeners != null) { Vector listeners = commandResponderListeners; int count = listeners.size(); for (int i = 0; i < count; i++) { ((CommandResponder) listeners.get(i)).processPdu(event); // if event is marked as processed the event is not forwarded to // remaining listeners if (event.isProcessed()) { return; } } } } /** * Gets the timeout model associated with this SNMP session. * @return * a TimeoutModel instance (never null). * @see #setTimeoutModel(TimeoutModel timeoutModel) */ public TimeoutModel getTimeoutModel() { return timeoutModel; } /** * Returns the report handler which is used internally to process reports * received from command responders. * @return * the ReportHandler instance. * @since 1.6 */ public ReportHandler getReportHandler() { return reportHandler; } /** * Sets the timeout model for this SNMP session. The default timeout model * sends retries whenever the time specified by the timeout * parameter of the target has elapsed without a response beeing received for * the request. By specifying a different timeout model this behaviour can * be changed. * @param timeoutModel * a TimeoutModel instance (must not be null). */ public void setTimeoutModel(TimeoutModel timeoutModel) { if (timeoutModel == null) { throw new NullPointerException("Timeout model cannot be null"); } this.timeoutModel = timeoutModel; } /** * Sets the report handler and overrides the default report handler. * @param reportHandler * a ReportHandler instance which must not be * null. * @since 1.6 */ public void setReportHandler(ReportHandler reportHandler) { if (reportHandler == null) { throw new IllegalArgumentException("ReportHandler must not be null"); } this.reportHandler = reportHandler; } class PendingRequest extends TimerTask implements PduHandleCallback { private PduHandle key; protected int retryCount; protected ResponseListener listener; protected Object userObject; protected PDU pdu; protected Target target; protected TransportMapping transport; private int requestStatus = 0; // Maximum request status - allows to receive up to two reports and then // send the original request again. A value of 0 is used for discovery. private int maxRequestStatus = DEFAULT_MAX_REQUEST_STATUS; private volatile boolean finished = false; private volatile boolean responseReceived = false; private volatile boolean pendingRetry = false; private volatile boolean cancelled = false; public PendingRequest(ResponseListener listener, Object userObject, PDU pdu, Target target, TransportMapping transport) { this.userObject = userObject; this.listener = listener; this.retryCount = target.getRetries(); this.pdu = pdu; this.target = (Target) target.clone(); this.transport = transport; } private PendingRequest(PendingRequest other) { this.userObject = other.userObject; this.listener = other.listener; this.retryCount = other.retryCount - 1; this.pdu = other.pdu; this.target = other.target; this.requestStatus = other.requestStatus; this.responseReceived = other.responseReceived; this.transport = other.transport; } protected void registerRequest(PduHandle handle) { // overwritten by subclasses } public void responseReceived() { this.responseReceived = true; } public synchronized void pduHandleAssigned(PduHandle handle, Object pdu) { if (key == null) { key = handle; // get pointer to target before adding request to pending list // to make sure that this retry is not being cancelled before we // got the target pointer. Target t = target; if ((t != null) && (!cancelled)) { pendingRequests.put(handle, this); registerRequest(handle); if (logger.isDebugEnabled()) { logger.debug("Running pending " + ((listener instanceof SyncResponseListener) ? "sync" : "async") + " request with handle " + handle + " and retry count left " + retryCount); } long delay = timeoutModel.getRetryTimeout(t.getRetries() - retryCount, t.getRetries(), t.getTimeout()); if ((!finished) && (!responseReceived) && (!cancelled)) { try { timer.schedule(this, delay); } catch (IllegalStateException isex) { // ignore } } else { pendingRequests.remove(handle); } } } } /** * Process retries of a pending request. */ public synchronized void run() { PduHandle m_key = key; PDU m_pdu = pdu; Target m_target = target; TransportMapping m_transport = transport; ResponseListener m_listener = listener; Object m_userObject = userObject; if ((m_key == null) || (m_pdu == null) || (m_target == null) || (m_listener == null)) { if (logger.isDebugEnabled()) { logger.debug("PendingRequest canceled key="+m_key+", pdu="+m_pdu+ ", target="+m_target+", transport="+m_transport+", listener="+ m_listener); } return; } try { synchronized (pendingRequests) { this.pendingRetry = (!finished) && (retryCount > 0) && (!responseReceived); } if (this.pendingRetry) { try { PendingRequest nextRetry = new PendingRequest(this); sendMessage(m_pdu, m_target, m_transport, nextRetry); this.pendingRetry = false; } catch (IOException ex) { ResponseListener l = listener; finished = true; logger.error("Failed to send SNMP message to " + m_target + ": " + ex.getMessage()); messageDispatcher.releaseStateReference(m_target.getVersion(), m_key); if (l != null) { listener.onResponse(new ResponseEvent(Snmp.this, null, m_pdu, null, m_userObject, ex)); } } } else if (!finished) { finished = true; pendingRequests.remove(m_key); if (!cancelled) { // request timed out if (logger.isDebugEnabled()) { logger.debug("Request timed out: " + m_key.getTransactionID()); } messageDispatcher.releaseStateReference(m_target.getVersion(), m_key); m_listener.onResponse(new ResponseEvent(Snmp.this, null, m_pdu, null, m_userObject)); } } else { // make sure pending request is removed even if response listener // failed to call Snmp.cancel pendingRequests.remove(m_key); } } catch (RuntimeException ex) { logger.error("Failed to process pending request " + m_key + " because " + ex.getMessage(), ex); throw ex; } catch (Error er) { logger.fatal("Failed to process pending request " + m_key + " because " + er.getMessage(), er); throw er; } } public boolean setFinished() { boolean currentState = finished; this.finished = true; return currentState; } public void setMaxRequestStatus(int maxRequestStatus) { this.maxRequestStatus = maxRequestStatus; } public int getMaxRequestStatus() { return maxRequestStatus; } public boolean isResponseReceived() { return responseReceived; } /** * Cancels the request and clears all internal fields by setting them * to null. * @return * true if cancellation was successful. */ public boolean cancel(){ cancelled = true; boolean result = super.cancel(); // free objects early if (!pendingRetry) { key = null; pdu = null; target = null; transport = null; listener = null; userObject = null; } return result; } } class AsyncPendingRequest extends PendingRequest { public AsyncPendingRequest(ResponseListener listener, Object userObject, PDU pdu, Target target, TransportMapping transport) { super(listener, userObject, pdu, target, transport); } protected void registerRequest(PduHandle handle) { AsyncRequestKey key = new AsyncRequestKey(super.pdu, super.listener); asyncRequests.put(key, handle); } } static class AsyncRequestKey { private PDU request; private ResponseListener listener; public AsyncRequestKey(PDU request, ResponseListener listener) { this.request = request; this.listener = listener; } /** * Indicates whether some other object is "equal to" this one. * * @param obj the reference object with which to compare. * @return true if this object is the same as the obj argument; * false otherwise. */ public boolean equals(Object obj) { if (obj instanceof AsyncRequestKey) { AsyncRequestKey other = (AsyncRequestKey) obj; return (request.equals(other.request) && listener.equals(other.listener)); } return false; } public int hashCode() { return request.hashCode(); } } static class SyncResponseListener implements ResponseListener { private ResponseEvent response = null; public synchronized void onResponse(ResponseEvent event) { this.response = event; this.notify(); } public ResponseEvent getResponse() { return response; } } /** * The NotificationDispatcher dispatches traps, notifications, * and to registered listeners. * * @author Frank Fock * @version 1.6 * @since 1.6 */ class NotificationDispatcher implements CommandResponder { // A mapping of transport addresses to transport mappings of notification // listeners private Hashtable notificationListeners = new Hashtable(10); private Hashtable notificationTransports = new Hashtable(10); protected NotificationDispatcher() { } public synchronized void addNotificationListener(Address listenAddress, TransportMapping transport, CommandResponder listener){ notificationListeners.put(listenAddress, transport); notificationTransports.put(transport, listener); } public synchronized boolean removeNotificationListener(Address listenAddress) { TransportMapping tm = (TransportMapping)notificationListeners.remove(listenAddress); if (tm == null) { return false; } tm.removeTransportListener(messageDispatcher); notificationTransports.remove(tm); try { tm.close(); } catch (IOException ex) { logger.error(ex); if (logger.isDebugEnabled()) { ex.printStackTrace(); } } return true; } public synchronized void closeAll() { notificationTransports.clear(); for (Iterator it = notificationListeners.values().iterator(); it.hasNext();) { TransportMapping tm = (TransportMapping) it.next(); try { tm.close(); } catch (IOException ex) { logger.error(ex); if (logger.isDebugEnabled()) { ex.printStackTrace(); } } } notificationListeners.clear(); } public synchronized void processPdu(CommandResponderEvent event) { CommandResponder listener = (CommandResponder) notificationTransports.get(event.getTransportMapping()); if ((event.getPDU() != null) && (event.getPDU().getType() == PDU.INFORM)) { // try to send INFORM response try { sendInformResponse(event); } catch (MessageException mex) { if (logger.isWarnEnabled()) { logger.warn("Failed to send response on INFORM PDU event (" + event + "): " + mex.getMessage()); } } } if (listener != null) { listener.processPdu(event); } } /** * Sends a RESPONSE PDU to the source address of a INFORM request. * @param event * the CommandResponderEvent with the INFORM request. * @throws * MessageException if the response could not be created and sent. */ protected void sendInformResponse(CommandResponderEvent event) throws MessageException { PDU responsePDU = (PDU) event.getPDU().clone(); responsePDU.setType(PDU.RESPONSE); responsePDU.setErrorStatus(PDU.noError); responsePDU.setErrorIndex(0); messageDispatcher.returnResponsePdu(event.getMessageProcessingModel(), event.getSecurityModel(), event.getSecurityName(), event.getSecurityLevel(), responsePDU, event.getMaxSizeResponsePDU(), event.getStateReference(), new StatusInformation()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy