You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1092 lines
42 KiB
1092 lines
42 KiB
/*
|
|
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
package com.sun.jmx.snmp.agent;
|
|
|
|
import java.util.Vector;
|
|
import java.util.Hashtable;
|
|
import java.util.Enumeration;
|
|
import java.util.Iterator;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Arrays;
|
|
import java.util.logging.Level;
|
|
|
|
import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
|
|
import com.sun.jmx.snmp.SnmpVarBind;
|
|
import com.sun.jmx.snmp.SnmpStatusException;
|
|
import com.sun.jmx.snmp.SnmpDefinitions;
|
|
import com.sun.jmx.snmp.SnmpOid;
|
|
import com.sun.jmx.snmp.SnmpPdu;
|
|
import com.sun.jmx.snmp.SnmpEngine;
|
|
|
|
// XXX: things to do: use SnmpOid rather than `instance' for future
|
|
// evolutions.
|
|
// XXX: Maybe use hashlists rather than vectors for entries?
|
|
// => in that case, the key should be SnmpOid.toString()
|
|
//
|
|
/**
|
|
* This class is used to register varbinds from a SNMP varbind list with
|
|
* the SnmpMibNode responsible for handling the requests concerning that
|
|
* varbind.
|
|
* This class holds a hashtable of Handler nodes, whith the involved
|
|
* SnmpMibNode as a key.
|
|
* When the involved SnmpMibNode is a group, the sublist of varbind is
|
|
* directly stored in the Handler node.
|
|
* When the involved SnmpMibNode is a table, the sublist is stored in a
|
|
* sorted array indexed by the OID of the entry involved.
|
|
*/
|
|
final class SnmpRequestTree {
|
|
|
|
// Constructor:
|
|
// @param req The SnmpMibRequest that will be segmented in this
|
|
// tree. It holds the original varbind vector passed
|
|
// by the SnmpSubRequestHandler to this MIB. This
|
|
// varbind vector is used to retrieve the "real"
|
|
// position of a varbind in the vector. There is no other easy
|
|
// way to do this - since as a result of the segmentation the
|
|
// original positions will be lost.
|
|
// @param creationflag indicates whether the operation involved
|
|
// allows for entry creation (ie: it is a SET request).
|
|
// @param pdutype indicates the type of the request PDU as defined
|
|
// in SnmpDefinitions
|
|
//
|
|
SnmpRequestTree(SnmpMibRequest req, boolean creationflag, int pdutype) {
|
|
this.request = req;
|
|
this.version = req.getVersion();
|
|
this.creationflag = creationflag;
|
|
this.hashtable = new Hashtable<>();
|
|
setPduType(pdutype);
|
|
}
|
|
|
|
public static int mapSetException(int errorStatus, int version)
|
|
throws SnmpStatusException {
|
|
|
|
final int errorCode = errorStatus;
|
|
|
|
if (version == SnmpDefinitions.snmpVersionOne)
|
|
return errorCode;
|
|
|
|
int mappedErrorCode = errorCode;
|
|
|
|
// Now take care of V2 errorCodes that can be stored
|
|
// in the varbind itself:
|
|
if (errorCode == SnmpStatusException.noSuchObject)
|
|
// noSuchObject => notWritable
|
|
mappedErrorCode = SnmpStatusException.snmpRspNotWritable;
|
|
|
|
else if (errorCode == SnmpStatusException.noSuchInstance)
|
|
// noSuchInstance => notWritable
|
|
mappedErrorCode = SnmpStatusException.snmpRspNotWritable;
|
|
|
|
return mappedErrorCode;
|
|
}
|
|
|
|
public static int mapGetException(int errorStatus, int version)
|
|
throws SnmpStatusException {
|
|
|
|
final int errorCode = errorStatus;
|
|
if (version == SnmpDefinitions.snmpVersionOne)
|
|
return errorCode;
|
|
|
|
int mappedErrorCode = errorCode;
|
|
|
|
// Now take care of V2 errorCodes that can be stored
|
|
// in the varbind itself:
|
|
if (errorCode ==
|
|
SnmpStatusException.noSuchObject)
|
|
// noSuchObject => noSuchObject
|
|
mappedErrorCode = errorCode;
|
|
|
|
else if (errorCode ==
|
|
SnmpStatusException.noSuchInstance)
|
|
// noSuchInstance => noSuchInstance
|
|
mappedErrorCode = errorCode;
|
|
|
|
// Now we're going to try to transform every other
|
|
// global code in either noSuchInstance or noSuchObject,
|
|
// so that the get can return a partial result.
|
|
//
|
|
// Only noSuchInstance or noSuchObject can be stored
|
|
// in the varbind itself.
|
|
//
|
|
|
|
// According to RFC 1905: noAccess is emitted when the
|
|
// the access is denied because it is not in the MIB view...
|
|
//
|
|
else if (errorCode ==
|
|
SnmpStatusException.noAccess)
|
|
// noAccess => noSuchInstance
|
|
mappedErrorCode = SnmpStatusException.noSuchInstance;
|
|
|
|
// According to RFC 1905: (my interpretation because it is not
|
|
// really clear) The specified variable name exists - but the
|
|
// variable does not exists and cannot be created under the
|
|
// present circumstances (probably because the request specifies
|
|
// another variable/value which is incompatible, or because the
|
|
// value of some other variable in the MIB prevents the creation)
|
|
//
|
|
// Note that this error should never be raised in a GET context
|
|
// but who knows?
|
|
//
|
|
else if (errorCode == SnmpStatusException.snmpRspInconsistentName)
|
|
// inconsistentName => noSuchInstance
|
|
mappedErrorCode = SnmpStatusException.noSuchInstance;
|
|
|
|
// All the errors comprised between snmpRspWrongType and
|
|
// snmpRspInconsistentValue concern values: so we're going
|
|
// to assume the OID was correct, and reply with noSuchInstance.
|
|
//
|
|
// Note that this error should never be raised in a GET context
|
|
// but who knows?
|
|
//
|
|
else if ((errorCode >= SnmpStatusException.snmpRspWrongType) &&
|
|
(errorCode <= SnmpStatusException.snmpRspInconsistentValue))
|
|
mappedErrorCode = SnmpStatusException.noSuchInstance;
|
|
|
|
// We're going to assume the OID was correct, and reply
|
|
// with noSuchInstance.
|
|
//
|
|
else if (errorCode == SnmpStatusException.readOnly)
|
|
mappedErrorCode = SnmpStatusException.noSuchInstance;
|
|
|
|
// For all other errors but genErr, we're going to reply with
|
|
// noSuchObject
|
|
//
|
|
else if (errorCode != SnmpStatusException.snmpRspAuthorizationError &&
|
|
errorCode != SnmpStatusException.snmpRspGenErr)
|
|
mappedErrorCode = SnmpStatusException.noSuchObject;
|
|
|
|
// Only genErr will abort the GET and be returned as global
|
|
// error.
|
|
//
|
|
return mappedErrorCode;
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// This class is a package implementation of the enumeration of
|
|
// SnmSubRequest associated with an Handler node.
|
|
//-------------------------------------------------------------------
|
|
|
|
static final class Enum implements Enumeration<SnmpMibSubRequest> {
|
|
Enum(SnmpRequestTree hlist,Handler h) {
|
|
handler = h;
|
|
this.hlist = hlist;
|
|
size = h.getSubReqCount();
|
|
}
|
|
private final Handler handler;
|
|
private final SnmpRequestTree hlist;
|
|
private int entry = 0;
|
|
private int iter = 0;
|
|
private int size = 0;
|
|
|
|
@Override
|
|
public boolean hasMoreElements() {
|
|
return iter < size;
|
|
}
|
|
|
|
@Override
|
|
public SnmpMibSubRequest nextElement() throws NoSuchElementException {
|
|
if (iter == 0) {
|
|
if (handler.sublist != null) {
|
|
iter++;
|
|
return hlist.getSubRequest(handler);
|
|
}
|
|
}
|
|
iter ++;
|
|
if (iter > size) throw new NoSuchElementException();
|
|
SnmpMibSubRequest result = hlist.getSubRequest(handler,entry);
|
|
entry++;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// This class is a package implementation of the SnmpMibSubRequest
|
|
// interface. It can only be instantiated by SnmpRequestTree.
|
|
//-------------------------------------------------------------------
|
|
|
|
static final class SnmpMibSubRequestImpl implements SnmpMibSubRequest {
|
|
SnmpMibSubRequestImpl(SnmpMibRequest global, Vector<SnmpVarBind> sublist,
|
|
SnmpOid entryoid, boolean isnew,
|
|
boolean getnextflag, SnmpVarBind rs) {
|
|
this.global = global;
|
|
varbinds = sublist;
|
|
this.version = global.getVersion();
|
|
this.entryoid = entryoid;
|
|
this.isnew = isnew;
|
|
this.getnextflag = getnextflag;
|
|
this.statusvb = rs;
|
|
}
|
|
|
|
final private Vector<SnmpVarBind> varbinds;
|
|
final private SnmpMibRequest global;
|
|
final private int version;
|
|
final private boolean isnew;
|
|
final private SnmpOid entryoid;
|
|
final private boolean getnextflag;
|
|
final private SnmpVarBind statusvb;
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibRequest interface.
|
|
// See SnmpMibRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public Enumeration<SnmpVarBind> getElements() {
|
|
return varbinds.elements();
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibRequest interface.
|
|
// See SnmpMibRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public Vector<SnmpVarBind> getSubList() {
|
|
return varbinds;
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibRequest interface.
|
|
// See SnmpMibRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public final int getSize() {
|
|
if (varbinds == null) return 0;
|
|
return varbinds.size();
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibRequest interface.
|
|
// See SnmpMibRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public void addVarBind(SnmpVarBind varbind) {
|
|
// XXX not sure we must also add the varbind in the global
|
|
// request? or whether we should raise an exception:
|
|
// in principle, this method should not be called!
|
|
varbinds.addElement(varbind);
|
|
global.addVarBind(varbind);
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibSubRequest interface.
|
|
// See SnmpMibSubRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public boolean isNewEntry() {
|
|
return isnew;
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibSubRequest interface.
|
|
// See SnmpMibSubRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public SnmpOid getEntryOid() {
|
|
return entryoid;
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibRequest interface.
|
|
// See SnmpMibRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public int getVarIndex(SnmpVarBind varbind) {
|
|
if (varbind == null) return 0;
|
|
return global.getVarIndex(varbind);
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibRequest interface.
|
|
// See SnmpMibRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public Object getUserData() { return global.getUserData(); }
|
|
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibSubRequest interface.
|
|
// See SnmpMibSubRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
|
|
@Override
|
|
public void registerGetException(SnmpVarBind var,
|
|
SnmpStatusException exception)
|
|
throws SnmpStatusException {
|
|
// The index in the exception must correspond to
|
|
// the SNMP index ...
|
|
//
|
|
if (version == SnmpDefinitions.snmpVersionOne)
|
|
throw new SnmpStatusException(exception, getVarIndex(var)+1);
|
|
|
|
if (var == null)
|
|
throw exception;
|
|
|
|
// If we're doing a getnext ==> endOfMibView
|
|
if (getnextflag) {
|
|
var.value = SnmpVarBind.endOfMibView;
|
|
return;
|
|
}
|
|
|
|
final int errorCode = mapGetException(exception.getStatus(),
|
|
version);
|
|
|
|
// Now take care of V2 errorCodes that can be stored
|
|
// in the varbind itself:
|
|
if (errorCode ==
|
|
SnmpStatusException.noSuchObject)
|
|
// noSuchObject => noSuchObject
|
|
var.value= SnmpVarBind.noSuchObject;
|
|
|
|
else if (errorCode ==
|
|
SnmpStatusException.noSuchInstance)
|
|
// noSuchInstance => noSuchInstance
|
|
var.value= SnmpVarBind.noSuchInstance;
|
|
|
|
else
|
|
throw new SnmpStatusException(errorCode, getVarIndex(var)+1);
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibSubRequest interface.
|
|
// See SnmpMibSubRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public void registerSetException(SnmpVarBind var,
|
|
SnmpStatusException exception)
|
|
throws SnmpStatusException {
|
|
// The index in the exception must correspond to
|
|
// the SNMP index ...
|
|
//
|
|
if (version == SnmpDefinitions.snmpVersionOne)
|
|
throw new SnmpStatusException(exception, getVarIndex(var)+1);
|
|
|
|
// Although the first pass of check() did not fail,
|
|
// the set() phase could not be carried out correctly.
|
|
// Since we don't know how to make an "undo", and some
|
|
// assignation may already have been performed, we're going
|
|
// to throw an snmpRspUndoFailed.
|
|
//
|
|
throw new SnmpStatusException(SnmpDefinitions.snmpRspUndoFailed,
|
|
getVarIndex(var)+1);
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibSubRequest interface.
|
|
// See SnmpMibSubRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public void registerCheckException(SnmpVarBind var,
|
|
SnmpStatusException exception)
|
|
throws SnmpStatusException {
|
|
// The index in the exception must correspond to
|
|
// the SNMP index ...
|
|
//
|
|
// We throw the exception in order to abort the SET operation
|
|
// in an atomic way.
|
|
final int errorCode = exception.getStatus();
|
|
final int mappedErrorCode = mapSetException(errorCode,
|
|
version);
|
|
|
|
if (errorCode != mappedErrorCode)
|
|
throw new
|
|
SnmpStatusException(mappedErrorCode, getVarIndex(var)+1);
|
|
else
|
|
throw new SnmpStatusException(exception, getVarIndex(var)+1);
|
|
}
|
|
|
|
// -------------------------------------------------------------
|
|
// Implements the method defined in SnmpMibRequest interface.
|
|
// See SnmpMibRequest for the java doc.
|
|
// -------------------------------------------------------------
|
|
@Override
|
|
public int getVersion() {
|
|
return version;
|
|
}
|
|
|
|
@Override
|
|
public SnmpVarBind getRowStatusVarBind() {
|
|
return statusvb;
|
|
}
|
|
|
|
@Override
|
|
public SnmpPdu getPdu() {
|
|
return global.getPdu();
|
|
}
|
|
|
|
@Override
|
|
public int getRequestPduVersion() {
|
|
return global.getRequestPduVersion();
|
|
}
|
|
|
|
@Override
|
|
public SnmpEngine getEngine() {
|
|
return global.getEngine();
|
|
}
|
|
|
|
@Override
|
|
public String getPrincipal() {
|
|
return global.getPrincipal();
|
|
}
|
|
|
|
@Override
|
|
public int getSecurityLevel() {
|
|
return global.getSecurityLevel();
|
|
}
|
|
|
|
@Override
|
|
public int getSecurityModel() {
|
|
return global.getSecurityModel();
|
|
}
|
|
|
|
@Override
|
|
public byte[] getContextName() {
|
|
return global.getContextName();
|
|
}
|
|
|
|
@Override
|
|
public byte[] getAccessContextName() {
|
|
return global.getAccessContextName();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// This class implements a node in the SnmpRequestTree.
|
|
// It stores:
|
|
// o The SnmpMibNode involved (key)
|
|
// o The sublist of varbind directly handled by this node
|
|
// o A vector of sublists concerning the entries (existing or not)
|
|
// of the SnmpMIbNode (when it is a table).
|
|
//-------------------------------------------------------------------
|
|
|
|
static final class Handler {
|
|
SnmpMibNode meta; // The meta which handles the sublist.
|
|
int depth; // The depth of the meta node.
|
|
Vector<SnmpVarBind> sublist; // The sublist of varbinds to be handled.
|
|
// List entryoids; // Sorted array of entry oids
|
|
// List entrylists; // Sorted array of entry lists
|
|
// List isentrynew; // Sorted array of booleans
|
|
SnmpOid[] entryoids = null; // Sorted array of entry oids
|
|
Vector<SnmpVarBind>[] entrylists = null; // Sorted array of entry lists
|
|
boolean[] isentrynew = null; // Sorted array of booleans
|
|
SnmpVarBind[] rowstatus = null; // RowStatus varbind, if any
|
|
int entrycount = 0;
|
|
int entrysize = 0;
|
|
|
|
final int type; // request PDU type as defined in SnmpDefinitions
|
|
final private static int Delta = 10;
|
|
|
|
public Handler(int pduType) {
|
|
this.type = pduType;
|
|
}
|
|
|
|
/**
|
|
* Adds a varbind in this node sublist.
|
|
*/
|
|
public void addVarbind(SnmpVarBind varbind) {
|
|
if (sublist == null) sublist = new Vector<>();
|
|
sublist.addElement(varbind);
|
|
}
|
|
|
|
/**
|
|
* register an entry for the given oid at the given position with
|
|
* the given sublist.
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
// We need this because of new Vector[n] instead of
|
|
// new Vector<SnmpVarBind>[n], which is illegal.
|
|
void add(int pos,SnmpOid oid, Vector<SnmpVarBind> v, boolean isnew,
|
|
SnmpVarBind statusvb) {
|
|
|
|
if (entryoids == null) {
|
|
// Vectors are null: Allocate new vectors
|
|
|
|
entryoids = new SnmpOid[Delta];
|
|
entrylists = (Vector<SnmpVarBind>[])new Vector<?>[Delta];
|
|
isentrynew = new boolean[Delta];
|
|
rowstatus = new SnmpVarBind[Delta];
|
|
entrysize = Delta;
|
|
pos = 0;
|
|
|
|
} else if (pos >= entrysize || entrycount == entrysize) {
|
|
// Vectors must be enlarged
|
|
|
|
// Save old vectors
|
|
SnmpOid[] olde = entryoids;
|
|
Vector[] oldl = entrylists;
|
|
boolean[] oldn = isentrynew;
|
|
SnmpVarBind[] oldr = rowstatus;
|
|
|
|
// Allocate larger vectors
|
|
entrysize += Delta;
|
|
entryoids = new SnmpOid[entrysize];
|
|
entrylists = (Vector<SnmpVarBind>[])new Vector<?>[entrysize];
|
|
isentrynew = new boolean[entrysize];
|
|
rowstatus = new SnmpVarBind[entrysize];
|
|
|
|
// Check pos validity
|
|
if (pos > entrycount) pos = entrycount;
|
|
if (pos < 0) pos = 0;
|
|
|
|
final int l1 = pos;
|
|
final int l2 = entrycount - pos;
|
|
|
|
// Copy original vectors up to `pos'
|
|
if (l1 > 0) {
|
|
java.lang.System.arraycopy(olde,0,entryoids,
|
|
0,l1);
|
|
java.lang.System.arraycopy(oldl,0,entrylists,
|
|
0,l1);
|
|
java.lang.System.arraycopy(oldn,0,isentrynew,
|
|
0,l1);
|
|
java.lang.System.arraycopy(oldr,0,rowstatus,
|
|
0,l1);
|
|
}
|
|
|
|
// Copy original vectors from `pos' to end, leaving
|
|
// an empty room at `pos' in the new vectors.
|
|
if (l2 > 0) {
|
|
final int l3 = l1+1;
|
|
java.lang.System.arraycopy(olde,l1,entryoids,
|
|
l3,l2);
|
|
java.lang.System.arraycopy(oldl,l1,entrylists,
|
|
l3,l2);
|
|
java.lang.System.arraycopy(oldn,l1,isentrynew,
|
|
l3,l2);
|
|
java.lang.System.arraycopy(oldr,l1,rowstatus,
|
|
l3,l2);
|
|
}
|
|
|
|
|
|
} else if (pos < entrycount) {
|
|
// Vectors are large enough to accommodate one additional
|
|
// entry.
|
|
//
|
|
// Shift vectors, making an empty room at `pos'
|
|
final int l1 = pos+1;
|
|
final int l2 = entrycount - pos;
|
|
|
|
java.lang.System.arraycopy(entryoids,pos,entryoids,
|
|
l1,l2);
|
|
java.lang.System.arraycopy(entrylists,pos,entrylists,
|
|
l1,l2);
|
|
java.lang.System.arraycopy(isentrynew,pos,isentrynew,
|
|
l1,l2);
|
|
java.lang.System.arraycopy(rowstatus,pos,rowstatus,
|
|
l1,l2);
|
|
}
|
|
|
|
// Fill the gap at `pos'
|
|
entryoids[pos] = oid;
|
|
entrylists[pos] = v;
|
|
isentrynew[pos] = isnew;
|
|
rowstatus[pos] = statusvb;
|
|
entrycount++;
|
|
}
|
|
|
|
public void addVarbind(SnmpVarBind varbind, SnmpOid entryoid,
|
|
boolean isnew, SnmpVarBind statusvb)
|
|
throws SnmpStatusException {
|
|
Vector<SnmpVarBind> v = null;
|
|
SnmpVarBind rs = statusvb;
|
|
|
|
if (entryoids == null) {
|
|
// entryoids = new ArrayList();
|
|
// entrylists = new ArrayList();
|
|
// isentrynew = new ArrayList();
|
|
v = new Vector<>();
|
|
// entryoids.add(entryoid);
|
|
// entrylists.add(v);
|
|
// isentrynew.add(new Boolean(isnew));
|
|
add(0,entryoid,v,isnew,rs);
|
|
} else {
|
|
// int pos = findOid(entryoids,entryoid);
|
|
// int pos = findOid(entryoids,entrycount,entryoid);
|
|
final int pos =
|
|
getInsertionPoint(entryoids,entrycount,entryoid);
|
|
if (pos > -1 && pos < entrycount &&
|
|
entryoid.compareTo(entryoids[pos]) == 0) {
|
|
v = entrylists[pos];
|
|
rs = rowstatus[pos];
|
|
} else {
|
|
// if (pos == -1 || pos >= entryoids.size() ) {
|
|
// if (pos == -1 || pos >= entrycount ) {
|
|
// pos = getInsertionPoint(entryoids,entryoid);
|
|
// pos = getInsertionPoint(entryoids,entrycount,entryoid);
|
|
v = new Vector<>();
|
|
// entryoids.add(pos,entryoid);
|
|
// entrylists.add(pos,v);
|
|
// isentrynew.add(pos,new Boolean(isnew));
|
|
add(pos,entryoid,v,isnew,rs);
|
|
}
|
|
// } else v = (Vector) entrylists.get(pos);
|
|
// } else v = entrylists[pos];
|
|
if (statusvb != null) {
|
|
if ((rs != null) && (rs != statusvb) &&
|
|
((type == SnmpDefinitions.pduWalkRequest) ||
|
|
(type == SnmpDefinitions.pduSetRequestPdu))) {
|
|
throw new SnmpStatusException(
|
|
SnmpStatusException.snmpRspInconsistentValue);
|
|
}
|
|
rowstatus[pos] = statusvb;
|
|
}
|
|
}
|
|
|
|
// We do not include the status variable in the varbind,
|
|
// because we're going to set it separately...
|
|
//
|
|
if (statusvb != varbind)
|
|
v.addElement(varbind);
|
|
}
|
|
|
|
public int getSubReqCount() {
|
|
int count = 0;
|
|
if (sublist != null) count++;
|
|
// if (entryoids != null) count += entryoids.size();
|
|
if (entryoids != null) count += entrycount;
|
|
return count;
|
|
}
|
|
|
|
public Vector<SnmpVarBind> getSubList() {
|
|
return sublist;
|
|
}
|
|
|
|
public int getEntryPos(SnmpOid entryoid) {
|
|
// return findOid(entryoids,entryoid);
|
|
return findOid(entryoids,entrycount,entryoid);
|
|
}
|
|
|
|
public SnmpOid getEntryOid(int pos) {
|
|
if (entryoids == null) return null;
|
|
// if (pos == -1 || pos >= entryoids.size() ) return null;
|
|
if (pos == -1 || pos >= entrycount ) return null;
|
|
// return (SnmpOid) entryoids.get(pos);
|
|
return entryoids[pos];
|
|
}
|
|
|
|
public boolean isNewEntry(int pos) {
|
|
if (entryoids == null) return false;
|
|
// if (pos == -1 || pos >= entryoids.size() ) return false;
|
|
if (pos == -1 || pos >= entrycount ) return false;
|
|
// return ((Boolean)isentrynew.get(pos)).booleanValue();
|
|
return isentrynew[pos];
|
|
}
|
|
|
|
public SnmpVarBind getRowStatusVarBind(int pos) {
|
|
if (entryoids == null) return null;
|
|
// if (pos == -1 || pos >= entryoids.size() ) return false;
|
|
if (pos == -1 || pos >= entrycount ) return null;
|
|
// return ((Boolean)isentrynew.get(pos)).booleanValue();
|
|
return rowstatus[pos];
|
|
}
|
|
|
|
public Vector<SnmpVarBind> getEntrySubList(int pos) {
|
|
if (entrylists == null) return null;
|
|
// if (pos == -1 || pos >= entrylists.size() ) return null;
|
|
if (pos == -1 || pos >= entrycount ) return null;
|
|
// return (Vector) entrylists.get(pos);
|
|
return entrylists[pos];
|
|
}
|
|
|
|
public Iterator<SnmpOid> getEntryOids() {
|
|
if (entryoids == null) return null;
|
|
// return entryoids.iterator();
|
|
return Arrays.asList(entryoids).iterator();
|
|
}
|
|
|
|
public int getEntryCount() {
|
|
if (entryoids == null) return 0;
|
|
// return entryoids.size();
|
|
return entrycount;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
//-------------------------------------------------------------------
|
|
// Public interface
|
|
//-------------------------------------------------------------------
|
|
//-------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------
|
|
// Returns the contextual object containing user-data allocated
|
|
// through the SnmpUserDataFactory for this request.
|
|
//-------------------------------------------------------------------
|
|
|
|
public Object getUserData() { return request.getUserData(); }
|
|
|
|
//-------------------------------------------------------------------
|
|
// Tells whether creation of new entries is allowed with respect
|
|
// to the operation involved (GET=>false/SET=>true)
|
|
//-------------------------------------------------------------------
|
|
|
|
public boolean isCreationAllowed() {
|
|
return creationflag;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Tells whether we are currently processing a SET request (check/set)
|
|
//-------------------------------------------------------------------
|
|
|
|
public boolean isSetRequest() {
|
|
return setreqflag;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Returns the protocol version in which the original request is
|
|
// evaluated.
|
|
//-------------------------------------------------------------------
|
|
|
|
public int getVersion() {
|
|
return version;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Returns the actual protocol version of the request PDU.
|
|
//-------------------------------------------------------------------
|
|
|
|
public int getRequestPduVersion() {
|
|
return request.getRequestPduVersion();
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Returns the SnmpMibNode associated with the given handler
|
|
//-------------------------------------------------------------------
|
|
|
|
public SnmpMibNode getMetaNode(Handler handler) {
|
|
return handler.meta;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Indicates the depth of the arc in the OID that identifies the
|
|
// SnmpMibNode associated with the given handler
|
|
//-------------------------------------------------------------------
|
|
|
|
public int getOidDepth(Handler handler) {
|
|
return handler.depth;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// returns an enumeration of the SnmpMibSubRequest's to be invoked on
|
|
// the SnmpMibNode associated with a given Handler node.
|
|
// If this node is a group, there will be a single subrequest.
|
|
// If it is a table, there will be one subrequest per entry involved.
|
|
//-------------------------------------------------------------------
|
|
|
|
public Enumeration<SnmpMibSubRequest> getSubRequests(Handler handler) {
|
|
return new Enum(this,handler);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// returns an enumeration of the Handlers stored in the Hashtable.
|
|
//-------------------------------------------------------------------
|
|
|
|
public Enumeration<Handler> getHandlers() {
|
|
return hashtable.elements();
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// adds a varbind to a handler node sublist
|
|
//-------------------------------------------------------------------
|
|
|
|
public void add(SnmpMibNode meta, int depth, SnmpVarBind varbind)
|
|
throws SnmpStatusException {
|
|
registerNode(meta,depth,null,varbind,false,null);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// adds an entry varbind to a handler node sublist
|
|
//-------------------------------------------------------------------
|
|
|
|
public void add(SnmpMibNode meta, int depth, SnmpOid entryoid,
|
|
SnmpVarBind varbind, boolean isnew)
|
|
throws SnmpStatusException {
|
|
registerNode(meta,depth,entryoid,varbind,isnew,null);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// adds an entry varbind to a handler node sublist - specifying the
|
|
// varbind which holds the row status
|
|
//-------------------------------------------------------------------
|
|
|
|
public void add(SnmpMibNode meta, int depth, SnmpOid entryoid,
|
|
SnmpVarBind varbind, boolean isnew,
|
|
SnmpVarBind statusvb)
|
|
throws SnmpStatusException {
|
|
registerNode(meta,depth,entryoid,varbind,isnew,statusvb);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
//-------------------------------------------------------------------
|
|
// Protected interface
|
|
//-------------------------------------------------------------------
|
|
//-------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------
|
|
// Type of the request (see SnmpDefinitions)
|
|
//-------------------------------------------------------------------
|
|
|
|
void setPduType(int pduType) {
|
|
type = pduType;
|
|
setreqflag = ((pduType == SnmpDefinitions.pduWalkRequest) ||
|
|
(pduType == SnmpDefinitions.pduSetRequestPdu));
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// We deal with a GET-NEXT request
|
|
//-------------------------------------------------------------------
|
|
|
|
void setGetNextFlag() {
|
|
getnextflag = true;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Tell whether creation is allowed.
|
|
//-------------------------------------------------------------------
|
|
void switchCreationFlag(boolean flag) {
|
|
creationflag = flag;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// Returns the subrequest handled by the SnmpMibNode itself
|
|
// (in principle, only for Groups)
|
|
//-------------------------------------------------------------------
|
|
|
|
SnmpMibSubRequest getSubRequest(Handler handler) {
|
|
if (handler == null) return null;
|
|
return new SnmpMibSubRequestImpl(request,handler.getSubList(),
|
|
null,false,getnextflag,null);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Returns the subrequest associated with the entry identified by
|
|
// the given entry (only for tables)
|
|
//-------------------------------------------------------------------
|
|
|
|
SnmpMibSubRequest getSubRequest(Handler handler, SnmpOid oid) {
|
|
if (handler == null) return null;
|
|
final int pos = handler.getEntryPos(oid);
|
|
if (pos == -1) return null;
|
|
return new SnmpMibSubRequestImpl(request,
|
|
handler.getEntrySubList(pos),
|
|
handler.getEntryOid(pos),
|
|
handler.isNewEntry(pos),
|
|
getnextflag,
|
|
handler.getRowStatusVarBind(pos));
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Returns the subrequest associated with the entry identified by
|
|
// the given entry (only for tables). The `entry' parameter is an
|
|
// index relative to the position of the entry in the handler sublist.
|
|
//-------------------------------------------------------------------
|
|
|
|
SnmpMibSubRequest getSubRequest(Handler handler, int entry) {
|
|
if (handler == null) return null;
|
|
return new
|
|
SnmpMibSubRequestImpl(request,handler.getEntrySubList(entry),
|
|
handler.getEntryOid(entry),
|
|
handler.isNewEntry(entry),getnextflag,
|
|
handler.getRowStatusVarBind(entry));
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
//-------------------------------------------------------------------
|
|
// Private section
|
|
//-------------------------------------------------------------------
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// stores a handler node in the Hashtable
|
|
//-------------------------------------------------------------------
|
|
|
|
private void put(Object key, Handler handler) {
|
|
if (handler == null) return;
|
|
if (key == null) return;
|
|
if (hashtable == null) hashtable = new Hashtable<Object, Handler>();
|
|
hashtable.put(key,handler);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// finds a handler node in the Hashtable
|
|
//-------------------------------------------------------------------
|
|
|
|
private Handler get(Object key) {
|
|
if (key == null) return null;
|
|
if (hashtable == null) return null;
|
|
return hashtable.get(key);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Search for the given oid in `oids'. If none is found, returns -1
|
|
// otherwise, returns the index at which the oid is located.
|
|
//-------------------------------------------------------------------
|
|
|
|
private static int findOid(SnmpOid[] oids, int count, SnmpOid oid) {
|
|
final int size = count;
|
|
int low= 0;
|
|
int max= size - 1;
|
|
int curr= low + (max-low)/2;
|
|
//System.out.println("Try to retrieve: " + oid.toString());
|
|
while (low <= max) {
|
|
|
|
final SnmpOid pos = oids[curr];
|
|
|
|
//System.out.println("Compare with" + pos.toString());
|
|
// never know ...we might find something ...
|
|
//
|
|
final int comp = oid.compareTo(pos);
|
|
if (comp == 0)
|
|
return curr;
|
|
|
|
if (oid.equals(pos)) {
|
|
return curr;
|
|
}
|
|
if (comp > 0) {
|
|
low = curr + 1;
|
|
} else {
|
|
max = curr - 1;
|
|
}
|
|
curr = low + (max-low)/2;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Return the index at which the given oid should be inserted in the
|
|
// `oids' array.
|
|
//-------------------------------------------------------------------
|
|
|
|
private static int getInsertionPoint(SnmpOid[] oids, int count,
|
|
SnmpOid oid) {
|
|
final SnmpOid[] localoids = oids;
|
|
final int size = count;
|
|
int low= 0;
|
|
int max= size - 1;
|
|
int curr= low + (max-low)/2;
|
|
|
|
|
|
while (low <= max) {
|
|
|
|
final SnmpOid pos = localoids[curr];
|
|
|
|
// never know ...we might find something ...
|
|
//
|
|
final int comp= oid.compareTo(pos);
|
|
|
|
// In the calling method we will have to check for this case...
|
|
// if (comp == 0)
|
|
// return -1;
|
|
// Returning curr instead of -1 avoids having to call
|
|
// findOid() first and getInsertionPoint() afterwards.
|
|
// We can simply call getInsertionPoint() and then checks whether
|
|
// there's an OID at the returned position which equals the
|
|
// given OID.
|
|
if (comp == 0)
|
|
return curr;
|
|
|
|
if (comp>0) {
|
|
low= curr +1;
|
|
} else {
|
|
max= curr -1;
|
|
}
|
|
curr= low + (max-low)/2;
|
|
}
|
|
return curr;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// adds a varbind in a handler node sublist
|
|
//-------------------------------------------------------------------
|
|
|
|
private void registerNode(SnmpMibNode meta, int depth, SnmpOid entryoid,
|
|
SnmpVarBind varbind, boolean isnew,
|
|
SnmpVarBind statusvb)
|
|
throws SnmpStatusException {
|
|
if (meta == null) {
|
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
|
|
SnmpRequestTree.class.getName(),
|
|
"registerNode", "meta-node is null!");
|
|
return;
|
|
}
|
|
if (varbind == null) {
|
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
|
|
SnmpRequestTree.class.getName(),
|
|
"registerNode", "varbind is null!");
|
|
return ;
|
|
}
|
|
|
|
final Object key = meta;
|
|
|
|
// retrieve the handler node associated with the given meta,
|
|
// if any
|
|
Handler handler = get(key);
|
|
|
|
// If no handler node was found for that meta, create one.
|
|
if (handler == null) {
|
|
// if (isDebugOn())
|
|
// debug("registerNode", "adding node for " +
|
|
// varbind.oid.toString());
|
|
handler = new Handler(type);
|
|
handler.meta = meta;
|
|
handler.depth = depth;
|
|
put(key,handler);
|
|
}
|
|
// else {
|
|
// if (isDebugOn())
|
|
// debug("registerNode","found node for " +
|
|
// varbind.oid.toString());
|
|
// }
|
|
|
|
// Adds the varbind in the handler node's sublist.
|
|
if (entryoid == null)
|
|
handler.addVarbind(varbind);
|
|
else
|
|
handler.addVarbind(varbind,entryoid,isnew,statusvb);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// private variables
|
|
//-------------------------------------------------------------------
|
|
|
|
private Hashtable<Object, Handler> hashtable = null;
|
|
// Hashtable of Handler objects
|
|
private SnmpMibRequest request = null; // The original list of varbinds
|
|
private int version = 0; // The protocol version
|
|
private boolean creationflag = false; // Does the operation allow
|
|
// creation of entries
|
|
private boolean getnextflag = false; // Does the operation allow
|
|
// creation of entries
|
|
private int type = 0; // Request PDU type as defined
|
|
// in SnmpDefinitions
|
|
private boolean setreqflag = false; // True if we're processing a
|
|
// SET request (check/set).
|
|
}
|