|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
package com.sun.jmx.snmp.daemon; |
|
|
|
|
|
|
|
// java import |
|
|
|
import java.util.logging.Level; |
|
import java.util.Vector; |
|
|
|
// jmx imports |
|
|
|
import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER; |
|
import com.sun.jmx.snmp.SnmpPdu; |
|
import com.sun.jmx.snmp.SnmpVarBind; |
|
import com.sun.jmx.snmp.SnmpDefinitions; |
|
import com.sun.jmx.snmp.SnmpStatusException; |
|
import com.sun.jmx.snmp.SnmpEngine; |
|
|
|
// SNMP Runtime import |
|
|
|
import com.sun.jmx.snmp.agent.SnmpMibAgent; |
|
import com.sun.jmx.snmp.agent.SnmpMibRequest; |
|
import com.sun.jmx.snmp.ThreadContext; |
|
import com.sun.jmx.snmp.internal.SnmpIncomingRequest; |
|
|
|
class SnmpSubRequestHandler implements SnmpDefinitions, Runnable { |
|
|
|
protected SnmpIncomingRequest incRequest = null; |
|
protected SnmpEngine engine = null; |
|
|
|
|
|
*/ |
|
protected SnmpSubRequestHandler(SnmpEngine engine, |
|
SnmpIncomingRequest incRequest, |
|
SnmpMibAgent agent, |
|
SnmpPdu req) { |
|
this(agent, req); |
|
init(engine, incRequest); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected SnmpSubRequestHandler(SnmpEngine engine, |
|
SnmpIncomingRequest incRequest, |
|
SnmpMibAgent agent, |
|
SnmpPdu req, |
|
boolean nouse) { |
|
this(agent, req, nouse); |
|
init(engine, incRequest); |
|
} |
|
|
|
|
|
*/ |
|
protected SnmpSubRequestHandler(SnmpMibAgent agent, SnmpPdu req) { |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(), |
|
"constructor", "creating instance for request " + String.valueOf(req.requestId)); |
|
} |
|
|
|
version= req.version; |
|
type= req.type; |
|
this.agent= agent; |
|
|
|
|
|
reqPdu = req; |
|
|
|
//Pre-allocate room for storing varbindlist and translation table. |
|
|
|
int length= req.varBindList.length; |
|
translation= new int[length]; |
|
varBind= new NonSyncVector<SnmpVarBind>(length); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("unchecked") |
|
protected SnmpSubRequestHandler(SnmpMibAgent agent, |
|
SnmpPdu req, |
|
boolean nouse) { |
|
this(agent,req); |
|
|
|
// The translation table is easy in this case ... |
|
|
|
int max= translation.length; |
|
SnmpVarBind[] list= req.varBindList; |
|
for(int i=0; i < max; i++) { |
|
translation[i]= i; |
|
((NonSyncVector<SnmpVarBind>)varBind).addNonSyncElement(list[i]); |
|
} |
|
} |
|
|
|
SnmpMibRequest createMibRequest(Vector<SnmpVarBind> vblist, |
|
int protocolVersion, |
|
Object userData) { |
|
|
|
// This is an optimization: |
|
// The SnmpMibRequest created in the check() phase is |
|
// reused in the set() phase. |
|
|
|
if (type == pduSetRequestPdu && mibRequest != null) |
|
return mibRequest; |
|
|
|
//This is a request comming from an SnmpV3AdaptorServer. |
|
|
|
SnmpMibRequest result = null; |
|
if(incRequest != null) { |
|
result = SnmpMibAgent.newMibRequest(engine, |
|
reqPdu, |
|
vblist, |
|
protocolVersion, |
|
userData, |
|
incRequest.getPrincipal(), |
|
incRequest.getSecurityLevel(), |
|
incRequest.getSecurityModel(), |
|
incRequest.getContextName(), |
|
incRequest.getAccessContext()); |
|
} else { |
|
result = SnmpMibAgent.newMibRequest(reqPdu, |
|
vblist, |
|
protocolVersion, |
|
userData); |
|
} |
|
// If we're doing the check() phase, we store the SnmpMibRequest |
|
// so that we can reuse it in the set() phase. |
|
|
|
if (type == pduWalkRequest) |
|
mibRequest = result; |
|
|
|
return result; |
|
} |
|
|
|
void setUserData(Object userData) { |
|
data = userData; |
|
} |
|
|
|
public void run() { |
|
|
|
try { |
|
final ThreadContext oldContext = |
|
ThreadContext.push("SnmpUserData",data); |
|
try { |
|
switch(type) { |
|
case pduGetRequestPdu: |
|
// Invoke a get operation |
|
|
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + |
|
"]:get operation on " + agent.getMibName()); |
|
} |
|
|
|
agent.get(createMibRequest(varBind,version,data)); |
|
break; |
|
|
|
case pduGetNextRequestPdu: |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + |
|
"]:getNext operation on " + agent.getMibName()); |
|
} |
|
|
|
agent.getNext(createMibRequest(varBind,version,data)); |
|
break; |
|
|
|
case pduSetRequestPdu: |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + |
|
"]:set operation on " + agent.getMibName()); |
|
} |
|
agent.set(createMibRequest(varBind,version,data)); |
|
break; |
|
|
|
case pduWalkRequest: |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + |
|
"]:check operation on " + agent.getMibName()); |
|
} |
|
agent.check(createMibRequest(varBind,version,data)); |
|
break; |
|
|
|
default: |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + |
|
"]:unknown operation (" + type + ") on " + |
|
agent.getMibName()); |
|
} |
|
errorStatus= snmpRspGenErr; |
|
errorIndex= 1; |
|
break; |
|
|
|
}// end of switch |
|
|
|
} finally { |
|
ThreadContext.restore(oldContext); |
|
} |
|
} catch(SnmpStatusException x) { |
|
errorStatus = x.getStatus() ; |
|
errorIndex= x.getErrorIndex(); |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + |
|
"]:an Snmp error occurred during the operation", x); |
|
} |
|
} |
|
catch(Exception x) { |
|
errorStatus = SnmpDefinitions.snmpRspGenErr ; |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + |
|
"]:a generic error occurred during the operation", x); |
|
} |
|
} |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(), |
|
"run", "[" + Thread.currentThread() + "]:operation completed"); |
|
} |
|
} |
|
|
|
// ------------------------------------------------------------- |
|
// |
|
// This function does a best-effort to map global error status |
|
// to SNMP v1 valid global error status. |
|
// |
|
// An SnmpStatusException can contain either: |
|
// <li> v2 local error codes (that should be stored in the varbind)</li> |
|
// <li> v2 global error codes </li> |
|
// <li> v1 global error codes </li> |
|
// |
|
// v2 local error codes (noSuchInstance, noSuchObject) are |
|
// transformed in a global v1 snmpRspNoSuchName error. |
|
// |
|
// v2 global error codes are transformed in the following way: |
|
// |
|
// If the request was a GET/GETNEXT then either |
|
// snmpRspNoSuchName or snmpRspGenErr is returned. |
|
// |
|
// Otherwise: |
|
// snmpRspNoAccess, snmpRspInconsistentName |
|
// => snmpRspNoSuchName |
|
// snmpRspAuthorizationError, snmpRspNotWritable, snmpRspNoCreation |
|
// => snmpRspReadOnly (snmpRspNoSuchName for GET/GETNEXT) |
|
// snmpRspWrong* |
|
// => snmpRspBadValue (snmpRspNoSuchName for GET/GETNEXT) |
|
// snmpRspResourceUnavailable, snmpRspRspCommitFailed, |
|
// snmpRspUndoFailed |
|
// => snmpRspGenErr |
|
// |
|
// ------------------------------------------------------------- |
|
|
|
static final int mapErrorStatusToV1(int errorStatus, int reqPduType) { |
|
// Map v2 codes onto v1 codes |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspNoError) |
|
return SnmpDefinitions.snmpRspNoError; |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspGenErr) |
|
return SnmpDefinitions.snmpRspGenErr; |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspNoSuchName) |
|
return SnmpDefinitions.snmpRspNoSuchName; |
|
|
|
if ((errorStatus == SnmpStatusException.noSuchInstance) || |
|
(errorStatus == SnmpStatusException.noSuchObject) || |
|
(errorStatus == SnmpDefinitions.snmpRspNoAccess) || |
|
(errorStatus == SnmpDefinitions.snmpRspInconsistentName) || |
|
(errorStatus == SnmpDefinitions.snmpRspAuthorizationError)){ |
|
|
|
return SnmpDefinitions.snmpRspNoSuchName; |
|
|
|
} else if ((errorStatus == |
|
SnmpDefinitions.snmpRspAuthorizationError) || |
|
(errorStatus == SnmpDefinitions.snmpRspNotWritable)) { |
|
|
|
if (reqPduType == SnmpDefinitions.pduWalkRequest) |
|
return SnmpDefinitions.snmpRspReadOnly; |
|
else |
|
return SnmpDefinitions.snmpRspNoSuchName; |
|
|
|
} else if ((errorStatus == SnmpDefinitions.snmpRspNoCreation)) { |
|
|
|
return SnmpDefinitions.snmpRspNoSuchName; |
|
|
|
} else if ((errorStatus == SnmpDefinitions.snmpRspWrongType) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongLength) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongEncoding) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongValue) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongLength) || |
|
(errorStatus == |
|
SnmpDefinitions.snmpRspInconsistentValue)) { |
|
|
|
if ((reqPduType == SnmpDefinitions.pduSetRequestPdu) || |
|
(reqPduType == SnmpDefinitions.pduWalkRequest)) |
|
return SnmpDefinitions.snmpRspBadValue; |
|
else |
|
return SnmpDefinitions.snmpRspNoSuchName; |
|
|
|
} else if ((errorStatus == |
|
SnmpDefinitions.snmpRspResourceUnavailable) || |
|
(errorStatus == |
|
SnmpDefinitions.snmpRspCommitFailed) || |
|
(errorStatus == SnmpDefinitions.snmpRspUndoFailed)) { |
|
|
|
return SnmpDefinitions.snmpRspGenErr; |
|
|
|
} |
|
|
|
// At this point we should have a V1 error code |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspTooBig) |
|
return SnmpDefinitions.snmpRspTooBig; |
|
|
|
if( (errorStatus == SnmpDefinitions.snmpRspBadValue) || |
|
(errorStatus == SnmpDefinitions.snmpRspReadOnly)) { |
|
if ((reqPduType == SnmpDefinitions.pduSetRequestPdu) || |
|
(reqPduType == SnmpDefinitions.pduWalkRequest)) |
|
return errorStatus; |
|
else |
|
return SnmpDefinitions.snmpRspNoSuchName; |
|
} |
|
|
|
// We have a snmpRspGenErr, or something which is not defined |
|
// in RFC1905 => return a snmpRspGenErr |
|
|
|
return SnmpDefinitions.snmpRspGenErr; |
|
|
|
} |
|
|
|
// ------------------------------------------------------------- |
|
// |
|
// This function does a best-effort to map global error status |
|
// to SNMP v2 valid global error status. |
|
// |
|
// An SnmpStatusException can contain either: |
|
// <li> v2 local error codes (that should be stored in the varbind)</li> |
|
// <li> v2 global error codes </li> |
|
// <li> v1 global error codes </li> |
|
// |
|
// v2 local error codes (noSuchInstance, noSuchObject) |
|
// should not raise this level: they should have been stored in the |
|
// varbind earlier. If they, do there is nothing much we can do except |
|
// to transform them into: |
|
// <li> a global snmpRspGenErr (if the request is a GET/GETNEXT) </li> |
|
// <li> a global snmpRspNoSuchName otherwise. </li> |
|
// |
|
// v2 global error codes are transformed in the following way: |
|
// |
|
// If the request was a GET/GETNEXT then snmpRspGenErr is returned. |
|
// (snmpRspGenErr is the only global error that is expected to be |
|
// raised by a GET/GETNEXT request). |
|
// |
|
// Otherwise the v2 code itself is returned |
|
// |
|
// v1 global error codes are transformed in the following way: |
|
// |
|
// snmpRspNoSuchName |
|
// => snmpRspNoAccess (snmpRspGenErr for GET/GETNEXT) |
|
// snmpRspReadOnly |
|
// => snmpRspNotWritable (snmpRspGenErr for GET/GETNEXT) |
|
// snmpRspBadValue |
|
// => snmpRspWrongValue (snmpRspGenErr for GET/GETNEXT) |
|
// |
|
// ------------------------------------------------------------- |
|
|
|
static final int mapErrorStatusToV2(int errorStatus, int reqPduType) { |
|
// Map v1 codes onto v2 codes |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspNoError) |
|
return SnmpDefinitions.snmpRspNoError; |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspGenErr) |
|
return SnmpDefinitions.snmpRspGenErr; |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspTooBig) |
|
return SnmpDefinitions.snmpRspTooBig; |
|
|
|
// For get / getNext / getBulk the only global error |
|
// (PDU-level) possible is genErr. |
|
|
|
if ((reqPduType != SnmpDefinitions.pduSetRequestPdu) && |
|
(reqPduType != SnmpDefinitions.pduWalkRequest)) { |
|
if(errorStatus == SnmpDefinitions.snmpRspAuthorizationError) |
|
return errorStatus; |
|
else |
|
return SnmpDefinitions.snmpRspGenErr; |
|
} |
|
|
|
// Map to noSuchName |
|
// if ((errorStatus == SnmpDefinitions.snmpRspNoSuchName) || |
|
// (errorStatus == SnmpStatusException.noSuchInstance) || |
|
// (errorStatus == SnmpStatusException.noSuchObject)) |
|
// return SnmpDefinitions.snmpRspNoSuchName; |
|
|
|
// SnmpStatusException.noSuchInstance and |
|
// SnmpStatusException.noSuchObject can't happen... |
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspNoSuchName) |
|
return SnmpDefinitions.snmpRspNoAccess; |
|
|
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspReadOnly) |
|
return SnmpDefinitions.snmpRspNotWritable; |
|
|
|
|
|
if (errorStatus == SnmpDefinitions.snmpRspBadValue) |
|
return SnmpDefinitions.snmpRspWrongValue; |
|
|
|
|
|
if ((errorStatus == SnmpDefinitions.snmpRspNoAccess) || |
|
(errorStatus == SnmpDefinitions.snmpRspInconsistentName) || |
|
(errorStatus == SnmpDefinitions.snmpRspAuthorizationError) || |
|
(errorStatus == SnmpDefinitions.snmpRspNotWritable) || |
|
(errorStatus == SnmpDefinitions.snmpRspNoCreation) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongType) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongLength) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongEncoding) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongValue) || |
|
(errorStatus == SnmpDefinitions.snmpRspWrongLength) || |
|
(errorStatus == SnmpDefinitions.snmpRspInconsistentValue) || |
|
(errorStatus == SnmpDefinitions.snmpRspResourceUnavailable) || |
|
(errorStatus == SnmpDefinitions.snmpRspCommitFailed) || |
|
(errorStatus == SnmpDefinitions.snmpRspUndoFailed)) |
|
return errorStatus; |
|
|
|
|
|
return SnmpDefinitions.snmpRspGenErr; |
|
} |
|
|
|
static final int mapErrorStatus(int errorStatus, |
|
int protocolVersion, |
|
int reqPduType) { |
|
if (errorStatus == SnmpDefinitions.snmpRspNoError) |
|
return SnmpDefinitions.snmpRspNoError; |
|
|
|
// Too bad, an error occurs ... we need to translate it ... |
|
|
|
if (protocolVersion == SnmpDefinitions.snmpVersionOne) |
|
return mapErrorStatusToV1(errorStatus,reqPduType); |
|
if (protocolVersion == SnmpDefinitions.snmpVersionTwo || |
|
protocolVersion == SnmpDefinitions.snmpVersionThree) |
|
return mapErrorStatusToV2(errorStatus,reqPduType); |
|
|
|
return SnmpDefinitions.snmpRspGenErr; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
protected int getErrorStatus() { |
|
if (errorStatus == snmpRspNoError) |
|
return snmpRspNoError; |
|
|
|
return mapErrorStatus(errorStatus,version,type); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected int getErrorIndex() { |
|
if (errorStatus == snmpRspNoError) |
|
return -1; |
|
|
|
// An error occurs. We need to be carefull because the index |
|
// we are getting is a valid SNMP index (so range starts at 1). |
|
// FIX ME: Shall we double-check the range here ? |
|
|
|
if ((errorIndex == 0) || (errorIndex == -1)) |
|
errorIndex = 1; |
|
|
|
return translation[errorIndex -1]; |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected void updateRequest(SnmpVarBind var, int pos) { |
|
int size= varBind.size(); |
|
translation[size]= pos; |
|
varBind.addElement(var); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void updateResult(SnmpVarBind[] result) { |
|
|
|
if (result == null) return; |
|
final int max=varBind.size(); |
|
final int len=result.length; |
|
for(int i= 0; i< max ; i++) { |
|
// bugId 4641694: must check position in order to avoid |
|
|
|
final int pos=translation[i]; |
|
if (pos < len) { |
|
result[pos] = |
|
(SnmpVarBind)((NonSyncVector)varBind).elementAtNonSync(i); |
|
} else { |
|
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { |
|
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(), |
|
"updateResult","Position `"+pos+"' is out of bound..."); |
|
} |
|
} |
|
} |
|
} |
|
|
|
private void init(SnmpEngine engine, |
|
SnmpIncomingRequest incRequest) { |
|
this.incRequest = incRequest; |
|
this.engine = engine; |
|
} |
|
|
|
// PRIVATE VARIABLES |
|
//------------------ |
|
|
|
|
|
|
|
*/ |
|
protected int version= snmpVersionOne; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected int type= 0; |
|
|
|
|
|
|
|
*/ |
|
protected SnmpMibAgent agent; |
|
|
|
|
|
|
|
*/ |
|
protected int errorStatus= snmpRspNoError; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected int errorIndex= -1; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected Vector<SnmpVarBind> varBind; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected int[] translation; |
|
|
|
|
|
|
|
**/ |
|
protected Object data; |
|
|
|
|
|
|
|
|
|
**/ |
|
private SnmpMibRequest mibRequest = null; |
|
|
|
|
|
|
|
|
|
**/ |
|
private SnmpPdu reqPdu = null; |
|
|
|
// All the methods of the Vector class are synchronized. |
|
// Synchronization is a very expensive operation. In our case it is not always |
|
// required... |
|
|
|
@SuppressWarnings("serial") |
|
class NonSyncVector<E> extends Vector<E> { |
|
|
|
public NonSyncVector(int size) { |
|
super(size); |
|
} |
|
|
|
final void addNonSyncElement(E obj) { |
|
ensureCapacity(elementCount + 1); |
|
elementData[elementCount++] = obj; |
|
} |
|
|
|
@SuppressWarnings("unchecked") |
|
final E elementAtNonSync(int index) { |
|
return (E) elementData[index]; |
|
} |
|
}; |
|
} |