/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.protocols.snmp;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.LinkedList;
import java.util.ListIterator;
import org.opennms.protocols.snmp.asn1.ASN1;
import org.opennms.protocols.snmp.asn1.AsnEncoder;
import org.opennms.protocols.snmp.asn1.AsnEncodingException;
/**
* <P>
* The SnmpSession is the main connection between the SNMP manager and the SNMP
* Agent. All the request flow through this class. To use the SnmpSession class
* a SnmpHandler class must be defined to process any errors or responses
* through the library.
* </P>
*
* <P>
* Once the session is created the creator must call <EM>close()</EM> to
* ensure an orderly release of threads and resources.
* </P>
*
* @author <A HREF="mailto:weave@oculan.com">Brian Weaver </A>
* @author <A HREF="http://www.opennms.org/">OpenNMS </A>
*
* @version 1.1.1.1 2001/11/11 17:27:22
*
* @see SnmpHandler
* @see SnmpPacketHandler
* @see SnmpPortal
*/
public class SnmpSession extends Object {
/**
* This is the command passed to the SnmpHandler if a timeout occurs. All
* errors are less than zero.
*
* @see SnmpHandler
*/
public static final int ERROR_TIMEOUT = -1;
/**
* This is the command passed to the SnmpHandler if an IOException occurs
* while attempting to transmit the request
*
* @see SnmpHandler
*/
public static final int ERROR_IOEXCEPTION = -2;
/**
* This is the command passed to the SnmpHandler if an encoding exception is
* generated when attempting to send an SnmpPduRequest message
*
* @see SnmpHandler
*/
public static final int ERROR_ENCODING = -3;
/**
* Used to contain a list of outstanding request for the session. The list
* should only contain SnmpRequest objects!
*/
private LinkedList<SnmpRequest> m_requests;
/**
* The SNMP peer to whom this session will communicate with. The peer
* contains the parameters also.
*
* @see SnmpParameters
*/
private SnmpPeer m_peer;
/**
* The timer object used to schedule the SnmpRequest timeouts. It is also
* used to schedule the cleanup of the m_requests list.
*
* @see org.opennms.protocols.snmp.SnmpSession.CleanupRequest
* @see SnmpRequest
*/
private SnmpTimer m_timer;
/**
* The default SNMP callback handler. If this is not set and it is needed
* then an SnmpHandlerNotDefinedException is thrown.
*/
private SnmpHandler m_defHandler;
/**
* ASN encoder
*/
AsnEncoder m_encoder;
//
// thread related stuff
//
/**
* Provides a synchronization point
*/
private Object m_sync;
/**
* If the boolean variable is set then the destroy() method must have been
* called
*/
private boolean m_stopRun;
/**
* the receiver thread
*/
private SnmpPortal m_portal;
/**
* If this boolean value is set then the receiver thread is terminated due
* to an exception that was generated in either a handler or a socket error.
* This is considered a fatal exception.
*/
private boolean m_threadException;
/**
* This is the saved fatal excetion that can be rethrown by the application
*/
private Throwable m_why;
/**
* Inner class SessionHandler implements the interface SnmpPacketHandler to
* handle callbacks from the SnmpPortal
*/
private class SessionHandler implements SnmpPacketHandler {
public void processSnmpMessage(InetAddress agent, int port, SnmpInt32 version, SnmpOctetString community, int pduType, SnmpPduPacket pdu) throws SnmpPduEncodingException {
//
// now find the request and
// inform
//
boolean isExpired = false;
SnmpRequest req = null;
synchronized (m_requests) {
//
// ensures that we get the proper
// state information
//
req = findRequest(pdu);
if (req != null)
isExpired = req.m_expired;
}
if (isExpired == false) {
int cmd = -1;
if (req != null && req.m_pdu instanceof SnmpPduPacket)
cmd = ((SnmpPduPacket) req.m_pdu).getCommand();
else {
cmd = pdu.getCommand();
pdu.setPeer(new SnmpPeer(agent, port));
}
switch (cmd) {
case SnmpPduPacket.SET: {
String tst = new String(community.getString());
String wr = m_peer.getParameters().getWriteCommunity();
if (!tst.equals(wr)) {
throw new SnmpPduEncodingException("Invalid community string");
}
}
break;
case SnmpPduPacket.GET:
case SnmpPduPacket.GETNEXT:
case SnmpPduPacket.RESPONSE:
case SnmpPduPacket.INFORM:
case SnmpPduPacket.GETBULK:
case SnmpPduPacket.REPORT: {
String tst = new String(community.getString());
String rd = m_peer.getParameters().getReadCommunity();
if (!tst.equals(rd)) {
throw new SnmpPduEncodingException("Invalid community string");
}
}
break;
default:
throw new SnmpPduEncodingException("Invalid PDU Type for session received");
}
if (req != null) {
req.m_expired = true; // mark it as expired
req.m_handler.snmpReceivedPdu(req.m_session, ((SnmpPduRequest) pdu).getCommand(), (SnmpPduRequest) pdu);
} else {
if (m_defHandler != null)
m_defHandler.snmpReceivedPdu(null, cmd, pdu);
}
}
}
public void processSnmpTrap(InetAddress agent, int port, SnmpOctetString community, SnmpPduTrap pdu) throws SnmpPduEncodingException {
throw new SnmpPduEncodingException("Invalid PDU Type for session");
}
public void processBadDatagram(DatagramPacket p) {
// do nothing - discard?
}
public void processException(Exception e) {
// do nothing - discard?
}
}
/**
* This class is used to periodically cleanup the outstanding request that
* have expired. The cleanup interval is nominally once every 5 to 10
* seconds. It's used like the garbage collector for the m_requests list.
* This is used in hopes of minimizing the contention for the request array
*
*/
private class CleanupRequest implements Runnable {
/**
* Preforms the actual removal of the expired SnmpRequest elements.
*
* @see SnmpRequest
*
*/
public void run() {
synchronized (m_requests) {
if (m_requests.size() > 0) {
ListIterator<SnmpRequest> iter = m_requests.listIterator(0);
while (iter.hasNext()) {
SnmpRequest req = iter.next();
if (req.m_expired)
iter.remove();
}
}
}
//
// reschedule
//
if (!m_stopRun && !m_threadException)
m_timer.schedule(this, 1000);
}
}
/**
* <P>
* Encapsulates a byte array and the number of bytes of valid data in the
* array. The length passed to the constructor is normally less then the
* length of the encapsulated array.
* </P>
*
*/
private static class ByteArrayInfo {
/**
* The buffer
*/
private byte[] m_buf;
/**
* The valid length of the buffer
*/
private int m_length;
/**
* Builds an encapuslated array with the passed buffer and its <EM>
* valid</EM> length set to <EM>length</EM>.
*
* @param buf
* The buffer.
* @param length
* The valid length of the buffer.
*/
public ByteArrayInfo(byte[] buf, int length) {
m_buf = buf;
m_length = length;
}
/**
* returns the encapsulated array
*/
public byte[] array() {
return m_buf;
}
/**
* Returns the valid length of the encapsulate array
*/
public int size() {
return m_length;
}
}
/**
* <P>
* This method is used to encode the passed protocol data unit and return
* the encoding. The encoding is performed using the default encoder for the
* session and limits the size to a 16K buffer.
* </P>
*
* @param pdu
* The pdu to encode
*
* @return The encoded pdu request
*
* @exception SnmpPduEncodingException
* Thrown if an encoding exception occurs at the session
* level
* @exception org.opennms.protocols.snmp.asn1.AsnEncodingException
* Thrown if an encoding exception occurs in the AsnEncoder
* object.
*/
private ByteArrayInfo encode(SnmpPduPacket pdu) throws SnmpPduEncodingException, AsnEncodingException {
SnmpPeer peer = m_peer;
SnmpParameters parms = peer.getParameters();
//
// Get the encoder and start
// the encoding process
//
// get a suitable buffer (16k)
//
int offset = 0;
byte[] buf = new byte[16 * 1024];
//
// encode the SNMP version
//
SnmpInt32 version = new SnmpInt32(parms.getVersion());
offset = version.encodeASN(buf, offset, m_encoder);
//
// get the correct community string. The
// SET command uses the write community, all
// others use the read community
//
SnmpOctetString community;
if (pdu.getCommand() == SnmpPduPacket.SET) {
String wrComm = parms.getWriteCommunity();
if (wrComm == null)
throw new SnmpPduEncodingException("Requested SET but there is no write community");
community = new SnmpOctetString(wrComm.getBytes());
} else {
community = new SnmpOctetString(parms.getReadCommunity().getBytes());
}
//
// encode the community strings
//
offset = community.encodeASN(buf, offset, m_encoder);
offset = pdu.encodeASN(buf, offset, m_encoder);
//
// build the header, don't forget to mark the
// pivot point
//
int pivot = offset;
offset = m_encoder.buildHeader(buf, offset, (byte) (ASN1.SEQUENCE | ASN1.CONSTRUCTOR), pivot);
//
// rotate the buffer around the pivot point
//
SnmpUtil.rotate(buf, 0, pivot, offset);
return new ByteArrayInfo(buf, offset);
}
/**
* <P>
* This method is used to encode the passed protocol data unit and return
* the encoding. The encoding is performed using the default encoder for the
* session and limits the size to a 16K buffer.
* </P>
*
* @param pdu
* The pdu to encode
*
* @return The encoded pdu request
*
* @exception SnmpPduEncodingException
* Thrown if an encoding exception occurs at the session
* level
* @exception org.opennms.protocols.snmp.asn1.AsnEncodingException
* Thrown if an encoding exception occurs in the AsnEncoder
* object.
*/
private ByteArrayInfo encode(SnmpPduTrap pdu) throws SnmpPduEncodingException, AsnEncodingException {
SnmpPeer peer = m_peer;
SnmpParameters parms = peer.getParameters();
//
// get a suitable buffer (16k)
//
int offset = 0;
byte[] buf = new byte[16 * 1024];
//
// encode the SNMP version
//
SnmpInt32 version = new SnmpInt32(parms.getVersion());
offset = version.encodeASN(buf, offset, m_encoder);
//
// get the correct community string. The
// SET command uses the write community, all
// others use the read community
//
SnmpOctetString community = new SnmpOctetString(parms.getReadCommunity().getBytes());
//
// encode the community strings
//
offset = community.encodeASN(buf, offset, m_encoder);
offset = pdu.encodeASN(buf, offset, m_encoder);
//
// build the header, don't forget to mark the
// pivot point
//
int pivot = offset;
offset = m_encoder.buildHeader(buf, offset, (byte) (ASN1.SEQUENCE | ASN1.CONSTRUCTOR), pivot);
//
// rotate the buffer around the pivot point
//
SnmpUtil.rotate(buf, 0, pivot, offset);
return new ByteArrayInfo(buf, offset);
}
/**
* Adds an outstanding request to the session. The access to the list is
* synchronized on the actual list of request. This is done to allow
* synchronization between addRequest(), removeRequest(), and findRequest()
*
* @param req
* The request reference to add (not cloned)
*/
void addRequest(SnmpRequest req) {
synchronized (m_requests) {
m_requests.addLast(req);
}
}
/**
* Removes an outstanding request from the session. The method uses the
* Object.equals() to find a matching request. If the SnmpRequest object
* does not override the equals() method the a "by reference" equality is
* used.
*
* @param req
* The request to remove. All matching request are removed.
*/
void removeRequest(SnmpRequest req) {
synchronized (m_requests) {
if (m_requests.size() > 0) {
ListIterator<SnmpRequest> iter = m_requests.listIterator(0);
while (iter.hasNext()) {
SnmpRequest cmp = iter.next();
if (req.equals(cmp)) {
req.m_expired = true;
iter.remove();
}
}
}
}
}
/**
* Finds the first matching request in the list of outstanding request and
* returns it to the caller. The matching is done by means using the SNMP
* Protocol Data Unit's request id. If no match is found then a null is
* returned
*
* @param pdu
* The source pdu for the search.
*
* @return Returns a SnmpRequest if a match is found. Otherwise a null is
* returned.
*
*/
SnmpRequest findRequest(SnmpPduPacket pdu) {
synchronized (m_requests) {
if (m_requests.size() > 0) {
ListIterator<SnmpRequest> iter = m_requests.listIterator(0);
while (iter.hasNext()) {
SnmpRequest req = iter.next();
if (!req.m_expired && req.m_pdu instanceof SnmpPduPacket && ((SnmpPduPacket) req.m_pdu).getRequestId() == pdu.getRequestId()) {
return req;
}
}
}
}
return null;
}
/**
* Returns the internal timer object for the SNMP Session.
*
* @return The internal timer object
*
*/
SnmpTimer getTimer() {
return m_timer;
}
/**
* Transmits the specified SnmpRequest to the SnmpPeer defined by the
* session. First the SnmpPdu contained within the request is encoded using
* the session AsnEncoder, as defined by the SnmpParameters. Once the packet
* is encoded it is transmitted to the agent defined by SnmpPeer. If an
* error occurs an appropiate exception is generated.
*
* @param req
* The SnmpRequest to transmit
*
* @exception SnmpPduEncodingException
* Thrown if an encoding exception occurs at the session
* level
* @exception org.opennms.protocols.snmp.asn1.AsnEncodingException
* Thrown if an encoding exception occurs in the AsnEncoder
* object.
* @exception java.io.IOException
* Thrown if an error occurs sending the encoded datagram
*
* @see SnmpRequest
* @see SnmpParameters
* @see SnmpPeer
*
*/
void transmit(SnmpRequest req) throws SnmpPduEncodingException, AsnEncodingException, java.io.IOException {
//
// break down the pieces into usable variables
//
SnmpPduPacket pdu = null;
SnmpPduTrap trap = null;
SnmpPeer peer = m_peer;
SnmpParameters parms = peer.getParameters();
if (req.m_pdu instanceof SnmpPduPacket)
pdu = (SnmpPduPacket) req.m_pdu;
if (req.m_pdu instanceof SnmpPduTrap)
trap = (SnmpPduTrap) req.m_pdu;
//
// verify that for a SNMPV1 session that no
// SNMPV2 packets are transmitted!
//
if (pdu != null) {
switch (pdu.getCommand()) {
case SnmpPduPacket.INFORM:
case SnmpPduPacket.V2TRAP:
case SnmpPduPacket.REPORT:
case SnmpPduPacket.GETBULK:
if (parms.getVersion() < SnmpSMI.SNMPV2) {
throw new SnmpPduEncodingException("Cannot send pdu, invalid SNMP version");
}
}
//
// transmit the datagram
//
ByteArrayInfo msg = encode(pdu);
if (pdu.getPeer() == null)
m_portal.send(m_peer, msg.array(), msg.size());
else
m_portal.send(pdu.getPeer(), msg.array(), msg.size());
} else if (trap != null) {
ByteArrayInfo msg = encode(trap);
m_portal.send(m_peer, msg.array(), msg.size());
} else {
throw new SnmpPduEncodingException("Invalid PDU type passed to method");
}
}
/**
* The default SnmpSession constructor. The object is constructed with a
* default SnmpPeer object.
*
* @param peer
* The peer agent
*
* @see SnmpPeer
*
* @exception java.net.SocketException
* If thrown it is from the creation of a DatagramSocket.
*
*/
public SnmpSession(InetAddress peer) throws SocketException {
m_sync = new Object();
m_requests = new LinkedList<SnmpRequest>();
m_peer = new SnmpPeer(peer);
m_timer = new SnmpTimer();
m_defHandler = null;
m_stopRun = false;
m_encoder = (new SnmpParameters()).getEncoder();
m_portal = new SnmpPortal(new SessionHandler(), m_encoder, 0);
m_threadException = false;
m_why = null;
m_timer.schedule(new CleanupRequest(), 1000);
}
/**
* Constructs the SnmpSession with the specific SnmpPeer.
*
* @param peer
* The SnmpPeer used to configure this session
*
* @see SnmpPeer
*
* @exception java.net.SocketException
* If thrown it is from the creation of a DatagramSocket.
*
*/
public SnmpSession(SnmpPeer peer) throws SocketException {
m_requests = new LinkedList<SnmpRequest>();
m_timer = new SnmpTimer();
m_defHandler = null;
m_sync = new Object();
m_stopRun = false;
m_encoder = peer.getParameters().getEncoder();
m_portal = new SnmpPortal(new SessionHandler(), m_encoder, peer.getServerPort());
m_threadException = false;
m_why = null;
m_peer = peer;
m_timer.schedule(new CleanupRequest(), 5000);
}
/**
* Constructs the SnmpSession with the specific parameters. The parameters
* are associated with the default SnmpPeer object.
*
* @param peer
* The peer address for agent
* @param params
* The SnmpParameters to configure with this session
*
* @see SnmpPeer
* @see SnmpParameters
*
* @exception java.net.SocketException
* If thrown it is from the creation of a DatagramSocket.
*
*/
public SnmpSession(InetAddress peer, SnmpParameters params) throws SocketException {
this(peer);
m_peer.setParameters(params);
}
/**
* Gets the default SnmpHandler for the session. If the handler has never
* been set via the setDefaultHandler() method then a null will be returned.
*
* @return The default SnmpHandler, a null if one has never been registered.
*
*/
public SnmpHandler getDefaultHandler() {
return m_defHandler;
}
/**
* Sets the default SnmpHandler.
*
* @param hdl
* The new default handler
*
*/
public void setDefaultHandler(SnmpHandler hdl) {
m_defHandler = hdl;
}
/**
* Gets the current peer object.
*
* @return The current SnmpPeer object
*
*/
public SnmpPeer getPeer() {
return m_peer;
}
/**
* Sets the passed SnmpPeer object to the one used for all new SNMP
* communications. This includes any outstanding retries.
*
* @param peer
* The SnmpPeer object for the sesison
*
*/
public void setPeer(SnmpPeer peer) {
m_peer = peer;
setAsnEncoder(peer.getParameters().getEncoder());
}
/**
* Returns the number of outstanding request for the agent. An outstanding
* request is one that has no yet responded to the query.
*
* @return The number of outstanding request
*
* @throws java.lang.IllegalStateException
* Throw if the session has been closed.
*/
public int getOutstandingCount() {
//
// check to ensure that the session is still open
//
synchronized (m_sync) {
if (m_stopRun) // session has been closed!
throw new IllegalStateException("illegal operation, the session has been closed");
}
synchronized (m_requests) {
//
// need to do cleanup in order
// to make this happen!
//
if (m_requests.size() > 0) {
ListIterator<SnmpRequest> iter = m_requests.listIterator();
while (iter.hasNext()) {
SnmpRequest req = iter.next();
if (req.m_expired)
iter.remove();
}
}
return m_requests.size();
}
}
/**
* Cancels the current outstanding reqeust as defined by the SnmpPduPacket's
* requestId method.
*
* @param requestId
* The request to cancel
*
* @see SnmpPduPacket
*
* @throws java.lang.IllegalStateException
* Throw if the session has been closed.
*/
public void cancel(int requestId) {
//
// check to ensure that the session is still open
//
synchronized (m_sync) {
if (m_stopRun) // session has been closed!
throw new IllegalStateException("illegal operation, the session has been closed");
}
synchronized (m_requests) {
if (m_requests.size() > 0) {
ListIterator<SnmpRequest> iter = m_requests.listIterator();
while (iter.hasNext()) {
//
// While the method owns the lock remove any expired
// request and any request with a matching request id
//
SnmpRequest req = iter.next();
if (req.m_expired || (req.m_pdu instanceof SnmpPduPacket && ((SnmpPduPacket) req.m_pdu).getRequestId() == requestId)) {
req.m_expired = true;
iter.remove();
}
}
}
}
}
/**
* Send the SNMP PDU to the remote agent and invokes the specified handler
* when the packet is recieve. This is a non-blocking call.
*
* @param pdu
* The pdu to encode and send
* @param handler
* The handler object for this request
*
* @return The request identifier for the newly sent PDU.
*
* @exception SnmpHandlerNotDefinedException
* Thrown if the handler is null
* @exception java.lang.IllegalStateException
* Thrown if the session has been closed.
*/
public int send(SnmpPduPacket pdu, SnmpHandler handler) {
if (handler == null)
throw new SnmpHandlerNotDefinedException("No Handler Defined");
//
// check to ensure that the session is still open
//
synchronized (m_sync) {
if (m_stopRun) // session has been closed!
throw new IllegalStateException("illegal operation, the session has been closed");
}
SnmpRequest req = new SnmpRequest(this, pdu, handler);
if (pdu.getCommand() != SnmpPduPacket.V2TRAP || pdu.getPeer() == null) // traps
// and
// responses
// don't
// get
// answers!
addRequest(req);
req.run();
if (req.m_expired == true) {
return 0;
}
return ((SnmpPduPacket) req.m_pdu).getRequestId();
}
/**
* Sends the SNMP PDU to the remote agent and uses the default SnmpHandler
* to process the request. This is a non-blocking call
*
* @param pdu
* The pdu to encode and send
*
* @return The request identifier for the newly sent PDU.
*
* @exception SnmpHandlerNotDefinedException
* Thrown if the handler is null
* @exception java.lang.IllegalStateException
* Thrown if the session has been closed.
*/
public int send(SnmpPduPacket pdu) {
if (m_defHandler == null)
throw new SnmpHandlerNotDefinedException("No Handler Defined");
return send(pdu, m_defHandler);
}
/**
* Send the SNMP PDU Trap to the remote agent. This is a non-blocking call.
*
* @param pdu
* The pdu to encode and send
* @param handler
* The handler object for this request
*
* @return The request identifier for the newly sent PDU.
*
* @exception SnmpHandlerNotDefinedException
* Thrown if the handler is null
* @exception java.lang.IllegalStateException
* Thrown if the session has been closed.
*/
public int send(SnmpPduTrap pdu, SnmpHandler handler) {
if (handler == null)
throw new SnmpHandlerNotDefinedException("No Handler Defined");
//
// check to ensure that the session is still open
//
synchronized (m_sync) {
if (m_stopRun) // session has been closed!
throw new IllegalStateException("illegal operation, the session has been closed");
}
SnmpRequest req = new SnmpRequest(this, pdu, handler);
req.run();
return 0;
}
/**
* Sends the SNMP PDU Trap to the remote agent. This is a non-blocking call
*
* @param pdu
* The pdu to encode and send
*
* @return The request identifier for the newly sent PDU.
*
* @exception SnmpHandlerNotDefinedException
* Thrown if the handler is null
* @exception java.lang.IllegalStateException
* Thrown if the session has been closed.
*/
public int send(SnmpPduTrap pdu) {
if (m_defHandler == null)
throw new SnmpHandlerNotDefinedException("No Handler Defined");
return send(pdu, m_defHandler);
}
/**
* Returns true if the <CODE>close</CODE> method has been called. The
* session cannot be used to send request after <CODE>close</CODE> has
* been executed.
*
*/
public boolean isClosed() {
synchronized (m_sync) {
return m_stopRun;
}
}
/**
* Used to close the session. Once called the session should be considered
* invalid and unusable.
*
* @exception java.lang.IllegalStateException
* Thrown if the session has already been closed by another
* thread.
*/
public void close() {
synchronized (m_sync) {
//
// only allow close to be called once
//
if (m_stopRun)
throw new IllegalStateException("The session is already closed");
m_stopRun = true;
m_timer.cancel();
}
m_portal.close();
//
// remove all items from the list
//
synchronized (m_requests) {
m_requests.clear();
}
}
/**
* If an exception occurs in the SNMP receiver thread then raise() will
* rethrow the exception.
*
* @exception java.lang.Throwable
* The base for thrown exceptions.
*/
public void raise() throws Throwable {
synchronized (m_sync) {
if (m_threadException)
throw m_why;
}
}
/**
* Sets the default encoder.
*
* @param encoder
* The new encoder
*
*/
public void setAsnEncoder(AsnEncoder encoder) {
m_encoder = encoder;
m_portal.setAsnEncoder(encoder);
}
/**
* Gets the AsnEncoder for the session.
*
* @return the AsnEncoder
*/
public AsnEncoder getAsnEncoder() {
return m_encoder;
}
/**
* Allows library users to register new ASN.1 types with the SNMP library.
* The object must support all methods of the SnmpSyntax interface. The
* object is registered globally with the library and is visible to all
* session after it is registered.
*
* @param object
* The new SnmpSyntax object to register
*/
public static void registerSyntaxObject(SnmpSyntax object) {
SnmpUtil.registerSyntax(object);
}
public SnmpSyntax getNext(SnmpObjectId oid) {
return getResult(SnmpPduPacket.GETNEXT, oid);
}
public SnmpSyntax[] getNext(SnmpObjectId[] oids) {
return getResults(SnmpPduPacket.GETNEXT, oids);
}
public SnmpSyntax get(SnmpObjectId oid) {
return getResult(SnmpPduPacket.GET, oid);
}
public SnmpSyntax set(SnmpObjectId oid, SnmpSyntax value) {
return getResult(SnmpPduPacket.SET, oid, value);
}
public SnmpSyntax[] set(SnmpObjectId[] oids, SnmpSyntax[] values) {
return getResults(SnmpPduPacket.SET, oids, values);
}
public SnmpSyntax[] get(SnmpObjectId[] oids) {
return getResults(SnmpPduPacket.GET, oids);
}
public SnmpSyntax[] getBulk(int nonRepeaters, int maxReptitions, SnmpObjectId id) {
return getBulk(nonRepeaters, maxReptitions, new SnmpObjectId[] { id });
}
public SnmpSyntax[] getBulk(int nonRepeaters, int maxRepititions, SnmpObjectId[] oids) {
SnmpVarBind[] varbinds = createVarBinds(oids);
SnmpPduPacket request = new SnmpPduBulk(nonRepeaters, maxRepititions, varbinds);
return getResults(request);
}
private SnmpSyntax getResult(int requestType, SnmpObjectId oid) {
SnmpSyntax[] result = getResults(requestType, new SnmpObjectId[] { oid });
return (result == null || result.length <= 0 ? null : result[0]);
}
private SnmpSyntax getResult(int requestType, SnmpObjectId oid, SnmpSyntax value) {
SnmpSyntax[] result = getResults(requestType, new SnmpObjectId[] { oid }, new SnmpSyntax[] { oid });
return (result == null || result.length <= 0 ? null : result[0]);
}
private SnmpSyntax[] getResults(int requestType, SnmpObjectId[] oids) {
SnmpVarBind[] varbinds = createVarBinds(oids);
SnmpPduPacket request = new SnmpPduRequest(requestType, varbinds);
return getResults(request);
}
private SnmpSyntax[] getResults(int requestType, SnmpObjectId[] oids, SnmpSyntax[] values) {
SnmpVarBind[] varbinds = createVarBinds(oids,values);
SnmpPduPacket request = new SnmpPduRequest(requestType, varbinds);
return getResults(request);
}
private SnmpVarBind[] createVarBinds(SnmpObjectId[] oids) {
SnmpVarBind[] varbinds = new SnmpVarBind[oids.length];
for(int i = 0; i < oids.length; i++) {
varbinds[i] = new SnmpVarBind(oids[i]);
}
return varbinds;
}
private SnmpVarBind[] createVarBinds(SnmpObjectId[] oids, SnmpSyntax[] values) {
SnmpVarBind[] varbinds = new SnmpVarBind[oids.length];
for(int i = 0; i < oids.length; i++) {
varbinds[i] = new SnmpVarBind(oids[i],values[i]);
}
return varbinds;
}
private SnmpSyntax[] getResults(SnmpPduPacket request) {
SnmpPduPacket response = getResponse(request);
if (response == null)
return null;
SnmpSyntax[] vals = new SnmpSyntax[response.getLength()];
for(int i = 0; i < response.getLength(); i++) {
vals[i] = response.getVarBindAt(i).getValue();
}
return vals;
}
public SnmpPduPacket getResponse(SnmpPduPacket request) {
SnmpResponseHandler handler = new SnmpResponseHandler();
synchronized (handler) {
send(request, handler);
try {
handler.wait((long) ((getPeer().getRetries() + 1) * getPeer().getTimeout()));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
SnmpPduPacket response = handler.getResponse();
return response;
}
} // end of SnmpSession class