/*_############################################################################
_##
_## SNMP4J-AgentX - AgentXCommandProcessor.java
_##
_## Copyright (C) 2005-2009 Frank Fock (SNMP4J.org)
_##
_## This program is free software; you can redistribute it and/or modify
_## it under the terms of the GNU General Public License version 2 as
_## published by the Free Software Foundation.
_##
_## This program 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 this program; if not, write to the Free Software
_## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
_## MA 02110-1301 USA
_##
_##########################################################################*/
package org.snmp4j.agent.agentx.master;
import java.io.IOException;
import java.util.*;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.PDU;
import org.snmp4j.TransportMapping;
import org.snmp4j.agent.*;
import org.snmp4j.agent.agentx.*;
import org.snmp4j.agent.agentx.master.AgentXQueue.AgentXQueueEntry;
import org.snmp4j.agent.agentx.master.index.AgentXIndexRegistry;
import org.snmp4j.agent.mo.snmp.AgentCapabilityList;
import org.snmp4j.agent.mo.snmp.SNMPv2MIB.SysUpTimeImpl;
import org.snmp4j.agent.mo.snmp.SysUpTime;
import org.snmp4j.agent.request.*;
import org.snmp4j.agent.security.VACM;
import org.snmp4j.log.LogAdapter;
import org.snmp4j.log.LogFactory;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.*;
import org.snmp4j.transport.ConnectionOrientedTransportMapping;
import org.snmp4j.transport.TransportStateEvent;
import org.snmp4j.transport.TransportStateListener;
public class AgentXCommandProcessor extends CommandProcessor implements
AgentXCommandListener, TransportStateListener,
AgentXResponseListener {
public static final int MAX_REPROCESSING_DEFAULT = 100;
private static final LogAdapter LOGGER =
LogFactory.getLogger(AgentXCommandProcessor.class);
private static final OctetString DEFAULT_CONTEXT = new OctetString();
private AgentXQueue agentXQueue;
private AgentX agentX;
private Map sessions = new HashMap();
private Map peers = new HashMap(10);
private Set registrations = new TreeSet(new AgentXRegEntryComparator());
private int nextSessionID = 1;
private byte defaultTimeout = AgentXProtocol.DEFAULT_TIMEOUT_SECONDS;
private int maxConsecutiveTimeouts =
AgentXProtocol.DEFAULT_MAX_CONSECUTIVE_TIMEOUTS;
private int maxParseErrors =
AgentXProtocol.DEFAULT_MAX_PARSE_ERRORS;
private Map contextInfo = new HashMap(10);
private boolean acceptNewContexts = false;
private int nextPacketID = 0;
protected AgentXIndexRegistry indexRegistry = new AgentXIndexRegistry();
private transient Vector agentXMasterListeners;
private int maxReprocessing = MAX_REPROCESSING_DEFAULT;
public AgentXCommandProcessor(OctetString contextEngineID,
AgentXQueue queue,
AgentX agentX,
MOServer[] server) {
super(contextEngineID);
this.agentXQueue = queue;
this.agentX = agentX;
for (int i=0; i<server.length; i++) {
super.addMOServer(server[i]);
}
if (this.agentXQueue.getServer4BulkOptimization() == null) {
this.agentXQueue.setServer4BulkOptimization(server);
}
}
private synchronized int createNextPacketID() {
return nextPacketID++;
}
public void setMaxReprocessing(int maxReprocessing) {
this.maxReprocessing = maxReprocessing;
}
public int getMaxReprocessing() {
return maxReprocessing;
}
/**
* Sets the maximum number of parse errors allowed per peer. If this number
* is exceeded then the peer will be closed with reason
* {@link AgentXProtocol#REASON_PARSE_ERROR}.
*
* @param maxParseErrors
* a positive value (including zero) sets the upper limit of parse errors
* tolerated per peer. If the number of parse errors exceeds this limit,
* all sessions with that peer will be closed. A negative value deactivates
* any limit.
* @since 1.0.1
*/
public void setMaxParseErrors(int maxParseErrors) {
this.maxParseErrors = maxParseErrors;
}
/**
* Gets the upper limit for parse errors for an AgentX peer.
* @return
* a positive value (including zero) indicates the upper limit of parse
* errors tolerated per peer. A negative value indicates that there is no
* limit.
* @since 1.0.1
*/
public int getMaxParseErrors() {
return maxParseErrors;
}
protected void finalizeRequest(CommandResponderEvent command,
Request req,
MOServer server) {
boolean complete = req.isComplete();
AgentXQueueEntry entry = agentXQueue.get(req.getTransactionID());
boolean waitingForResponse = false;
if (entry != null) {
Collection pending = entry.getPending();
entry.updateTimestamp();
for (Iterator it = pending.iterator(); it.hasNext(); ) {
AgentXPending p = (AgentXPending) it.next();
if (pending != null) {
AgentXPDU agentXPDU = p.getAgentXPDU();
AgentXMasterSession session = p.getSession();
agentXPDU.setSessionID(session.getSessionID());
agentXPDU.setTransactionID(req.getTransactionID());
agentXPDU.setPacketID(createNextPacketID());
p.updateTimestamp();
boolean expectResponse = true;
if (agentXPDU.getType() != AgentXPDU.AGENTX_CLEANUPSET_PDU) {
waitingForResponse = true;
}
else {
p.setPending(false);
complete = req.isComplete();
expectResponse = false;
}
try {
agentX.send(agentXPDU,
session.createAgentXTarget(),
session.getPeer().getTransport(),
(expectResponse) ? p : null,
(expectResponse) ? this : null);
}
catch (IOException ex) {
LOGGER.error("Failed to send AgentX subrequest: " +
ex.getMessage());
((SubRequest) p.getReferences().next()).
getStatus().setErrorStatus(PDU.genErr);
break;
}
}
}
}
if ((entry == null) || (!waitingForResponse)) {
if (complete) {
agentXQueue.removeAll(req.getTransactionID());
}
else {
// there are still incomplete sub-requests -> reprocess them
if (req.getReprocessCounter() < this.maxReprocessing) {
reprocessRequest(server, (SnmpRequest)req);
}
else {
req.setErrorStatus(PDU.genErr);
LOGGER.warn("The following request has been repeocessed "+
req.getReprocessCounter()+" which exceeds the agent's "+
"upper limit of "+this.maxReprocessing+": "+
req);
}
}
super.finalizeRequest(command, req, server);
}
}
protected synchronized int getNextSessionID() {
return nextSessionID++;
}
/**
* Gets the default server (for the <code>null</code> context).
* @return
* the default server instance.
* @deprecated
* Use {@link #getServer(OctetString context)} instead.
*/
public MOServer getServer() {
return super.getServer(null);
}
public byte getDefaultTimeout() {
return defaultTimeout;
}
/**
* Gets the maximum number of consecutive timeouts allowed per session.
* @return
* the maximum number of consecutive timeouts allowed per session
*/
public int getMaxConsecutiveTimeouts() {
return maxConsecutiveTimeouts;
}
/**
* Indicates whether subagents can register contexts that are not yet
* supported by this master agent.
* @return
* <code>true</code> if subagents can register objects for new contexts.
*/
public boolean isAcceptNewContexts() {
return acceptNewContexts;
}
public void setDefaultTimeout(byte defaultTimeout) {
this.defaultTimeout = defaultTimeout;
}
/**
* Sets the maximum number of timeouts allowed per session. If the number
* is exceeded then the session will be closed with reason
* {@link AgentXProtocol#REASON_TIMEOUTS}.
* @param maxConsecutiveTimeouts
* the maximum number of timeouts (should be greater than zero).
*/
public void setMaxConsecutiveTimeouts(int maxConsecutiveTimeouts) {
this.maxConsecutiveTimeouts = maxConsecutiveTimeouts;
}
/**
* Enables or disables accepting new contexts from subagents.
* @param acceptNewContexts
* <code>true</code> if subagents are allowed to register objects for new
* contexts, <code>false</code> otherwise. Default is <code>false</code>.
*/
public void setAcceptNewContexts(boolean acceptNewContexts) {
this.acceptNewContexts = acceptNewContexts;
}
public void processCommand(AgentXCommandEvent event) {
boolean pendingClose = false;
if (event.isException()) {
AgentXPeer peer = getPeer(event.getPeerAddress());
if (peer != null) {
peer.incParseErrors();
LOGGER.warn("AgentX parse exception from peer '"+peer+
"' : " + event.getException());
if ((maxParseErrors >= 0) && (peer.getParseErrors() > maxParseErrors)) {
LOGGER.warn("Removing peer due to excessive parse errors: " +peer);
closePeer(peer.getAddress(), AgentXProtocol.REASON_PARSE_ERROR);
}
}
else {
LOGGER.error("AgentX parse exception from unknown peer '"+
event.getPeerAddress()+
"' : " + event.getException());
}
}
else {
AgentXPDU pdu = event.getCommand();
AgentXMasterSession session = getSession(pdu);
AgentXResponsePDU response = null;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Processing AgentX PDU "+pdu+" for session "+session);
}
switch (pdu.getType()) {
case AgentXPDU.AGENTX_RESPONSE_PDU: {
LOGGER.error(
"Internal error: received AgentX response without request");
return;
}
case AgentXPDU.AGENTX_OPEN_PDU: {
response = openSession((AgentXOpenPDU) pdu, event);
session = getSession(response.getSessionID());
break;
}
case AgentXPDU.AGENTX_CLOSE_PDU: {
response = closeSession((AgentXClosePDU)pdu, session);
pendingClose = true;
break;
}
case AgentXPDU.AGENTX_REGISTER_PDU: {
response = register((AgentXRegisterPDU)pdu, event, session);
break;
}
case AgentXPDU.AGENTX_UNREGISTER_PDU: {
response = unregister((AgentXUnregisterPDU)pdu, event, session);
break;
}
case AgentXPDU.AGENTX_ADDAGENTCAPS_PDU: {
response = addAgentCaps((AgentXAddAgentCapsPDU)pdu, session);
break;
}
case AgentXPDU.AGENTX_REMOVEAGENTCAPS_PDU: {
response = removeAgentCaps((AgentXRemoveAgentCapsPDU)pdu, session);
break;
}
case AgentXPDU.AGENTX_NOTIFY_PDU: {
response = notify((AgentXNotifyPDU)pdu, session);
break;
}
case AgentXPDU.AGENTX_PING_PDU: {
response = ping((AgentXPingPDU)pdu, session);
break;
}
case AgentXPDU.AGENTX_INDEXALLOCATE_PDU: {
response = indexAllocate((AgentXIndexAllocatePDU)pdu, session);
break;
}
case AgentXPDU.AGENTX_INDEXDEALLOCATE_PDU: {
response = indexDeallocate((AgentXIndexDeallocatePDU)pdu, session);
break;
}
default:
LOGGER.warn("Unknown AgentX PDU type received: " + pdu);
}
if ((response != null) && (session != null)) {
sendResponse(response, session);
}
if (pendingClose) {
if (session != null) {
closePeer(session.getPeer());
}
}
}
event.setProcessed(true);
}
private void closePeer(AgentXPeer peer) {
TransportMapping transport = peer.getTransport();
if (transport instanceof ConnectionOrientedTransportMapping) {
try {
if (((ConnectionOrientedTransportMapping)
transport).close(peer.getAddress())) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Closed sub-agent connection to " +
peer.getAddress());
}
}
else {
LOGGER.warn("Failed to close sub-agent connection to " +
peer.getAddress());
}
}
catch (IOException ex) {
LOGGER.error("Failed to close transport mapping "+
peer.getTransport()+" because: "+
ex.getMessage(), ex);
}
}
}
public AgentXResponsePDU indexDeallocate(AgentXIndexDeallocatePDU pdu,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
boolean contextSupported = isContextSupported(pdu.getContext());
if (contextSupported) {
VariableBinding[] vbs = pdu.getVariableBindings();
// test index allocation
deallocateIndexes(response, pdu, session, vbs, true);
if (response.getErrorStatus() == AgentXProtocol.AGENTX_SUCCESS) {
// do it on success
deallocateIndexes(response, pdu, session, vbs, false);
response.setVariableBindings(vbs);
}
}
else {
response.setErrorStatus(AgentXProtocol.AGENTX_UNSUPPORTED_CONTEXT);
}
return response;
}
private boolean isContextSupported(OctetString context) {
MOServer s = getServer(context);
boolean contextSupported =
(s != null) && (s.isContextSupported(context));
return contextSupported;
}
private boolean checkIfContextIsSupported(OctetString context) {
boolean contextSupported = isContextSupported(context);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Checking context '"+context+"' is supported");
}
if (isAcceptNewContexts() && !contextSupported) {
MOServer server = getServer(null);
if (server != null) {
server.addContext(context);
contextSupported = server.isContextSupported(context);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Adding new context '" + context +
"' on subagent request returned: " + contextSupported);
}
}
else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Adding new context '" + context +
"' on subagent request failed "+
"because no default server found");
}
}
}
return contextSupported;
}
public AgentXResponsePDU indexAllocate(AgentXIndexAllocatePDU pdu,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
response.setVariableBindings(pdu.getVariableBindings());
boolean contextSupported = checkIfContextIsSupported(pdu.getContext());
if (contextSupported) {
VariableBinding[] vbs = pdu.getVariableBindings();
// test index allocation
allocateIndexes(response, pdu, session, vbs, true);
if (response.getErrorStatus() == AgentXProtocol.AGENTX_SUCCESS) {
// do it on success
allocateIndexes(response, pdu, session, vbs, false);
response.setVariableBindings(vbs);
}
}
else {
response.setErrorStatus(AgentXProtocol.AGENTX_UNSUPPORTED_CONTEXT);
}
return response;
}
private int allocateIndexes(AgentXResponsePDU response,
AgentXIndexAllocatePDU pdu,
AgentXMasterSession session,
VariableBinding[] vbs,
boolean testOnly) {
int status = AgentXProtocol.AGENTX_SUCCESS;
int i=0;
for (; (i<vbs.length) && (status == AgentXProtocol.AGENTX_SUCCESS); i++) {
VariableBinding vb = vbs[i];
if (pdu.isFlagSet(AgentXProtocol.FLAG_ANY_INDEX)) {
status = indexRegistry.anyIndex(session.getSessionID(),
pdu.getContext(), vb, testOnly);
}
else if (pdu.isFlagSet(AgentXProtocol.FLAG_NEW_INDEX)) {
status = indexRegistry.newIndex(session.getSessionID(),
pdu.getContext(), vb, testOnly);
}
else {
status = indexRegistry.allocate(session.getSessionID(),
pdu.getContext(), vb, testOnly);
}
}
response.setErrorStatus(status);
if (status != AgentXProtocol.AGENTX_SUCCESS) {
response.setErrorIndex(i);
}
return status;
}
private int deallocateIndexes(AgentXResponsePDU response,
AgentXIndexDeallocatePDU pdu,
AgentXMasterSession session,
VariableBinding[] vbs,
boolean testOnly) {
int status = AgentXProtocol.AGENTX_SUCCESS;
int i=0;
for (; (i<vbs.length) && (status == AgentXProtocol.AGENTX_SUCCESS); i++) {
VariableBinding vb = vbs[i];
status = indexRegistry.release(session.getSessionID(),
pdu.getContext(), vb, testOnly);
}
response.setErrorStatus(status);
if (status != AgentXProtocol.AGENTX_SUCCESS) {
response.setErrorIndex(i);
}
return status;
}
protected void processAgentXSearchResponse(AgentXPending pending,
AgentXResponsePDU pdu) {
if (pdu.getErrorStatus() != PDU.noError) {
processsErrorResponse(pending, pdu);
}
else {
// no error -> normal processing
if (pending.getAgentXPDU().getType() == AgentXPDU.AGENTX_GETBULK_PDU) {
processAgentXNextResponse(pending, pdu, Integer.MAX_VALUE);
}
else {
processAgentXNextResponse(pending, pdu,
((AgentXRequestPDU)pending.getAgentXPDU()).
getRanges().length);
}
}
}
private SubRequestIterator
processAgentXNextResponse(AgentXPending pending,
AgentXResponsePDU pdu,
int subRequestIndexUpperBound) throws
NoSuchElementException
{
VariableBinding[] vbs = pdu.getVariableBindings();
AgentXRequestPDU axReqPDU = (AgentXRequestPDU) pending.getAgentXPDU();
SubRequestIterator subRequests = pending.getReferences();
for (int i=0; (i<subRequestIndexUpperBound) && subRequests.hasNext(); i++) {
SnmpSubRequest sreq = (SnmpSubRequest) subRequests.nextSubRequest();
processNextSubRequest(vbs, axReqPDU, i, i, sreq);
}
return subRequests;
}
private void processNextSubRequest(VariableBinding[] vbs,
AgentXRequestPDU axReqPDU,
int vbIndex,
int rangeIndex,
SnmpSubRequest sreq) {
MOScope srange = axReqPDU.getRanges()[rangeIndex];
if (vbIndex < vbs.length) {
VariableBinding vb = vbs[vbIndex];
if (vb.getSyntax() == SMIConstants.EXCEPTION_END_OF_MIB_VIEW) {
processEndOfMibView(sreq, srange, vb.getOid());
}
else if (!srange.covers(vb.getOid())) {
processEndOfMibView(sreq, srange, null);
}
else if ((vb.isException()) ||
(super.vacm.isAccessAllowed(sreq.getSnmpRequest().
getViewName(),
vb.getOid()) != VACM.VACM_OK)) {
DefaultMOContextScope nscope = (DefaultMOContextScope) sreq.getScope();
nscope.substractScope(srange);
nscope.setUpperBound(null);
nscope.setUpperIncluded(true);
// reset query because scope changed!
sreq.setQuery(null);
sreq.getStatus().setProcessed(false);
}
else {
sreq.getVariableBinding().setOid(vb.getOid());
sreq.getVariableBinding().setVariable(vb.getVariable());
sreq.getStatus().setPhaseComplete(true);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Assigned next subrequest "+sreq);
}
// Not needed here because bulk processing does it anyway:
sreq.updateNextRepetition();
}
}
else {
// less VBs than expected
processEndOfMibView(sreq, srange, null);
}
}
private static void processEndOfMibView(SnmpSubRequest sreq, MOScope srange,
OID oid) {
if (srange.getUpperBound() == null) {
// unbounded
// set also all following repetitions to endOfMibView
SubRequestIterator tail = sreq.repetitions();
while (tail.hasNext()) {
SubRequest sr = tail.nextSubRequest();
if (oid == null) {
sr.getVariableBinding().setOid(srange.getLowerBound());
}
else {
sreq.getVariableBinding().setOid(oid);
}
sr.getVariableBinding().setVariable(Null.endOfMibView);
sr.getStatus().setPhaseComplete(true);
}
return;
}
else {
sreq.getStatus().setProcessed(false);
}
DefaultMOContextScope nscope = (DefaultMOContextScope) sreq.getScope();
nscope.substractScope(srange);
nscope.setUpperBound(null);
nscope.setUpperIncluded(true);
// reset query because scope changed!
sreq.setQuery(null);
}
protected void processAgentXBulkResponse(AgentXPending pending,
AgentXResponsePDU pdu) {
if (pdu.getErrorStatus() != PDU.noError) {
processsErrorResponse(pending, pdu);
}
else {
AgentXGetBulkPDU requestPDU = (AgentXGetBulkPDU) pending.getAgentXPDU();
VariableBinding[] vbs = pdu.getVariableBindings();
int numBindings = vbs.length;
int repeaters =
requestPDU.getRanges().length - requestPDU.getNonRepeaters();
if (numBindings - requestPDU.getNonRepeaters() >
requestPDU.getMaxRepetitions() * repeaters) {
LOGGER.warn("Bulk response with more repetitions ("+
((numBindings - requestPDU.getNonRepeaters())/ repeaters)+
") than max rep. "+requestPDU.getMaxRepetitions());
numBindings = requestPDU.getMaxRepetitions() * repeaters
+ requestPDU.getNonRepeaters();
}
if (numBindings == 0) {
// this is IMHO outside the AgentX/SNMP spec but it is in fact
// needed to be interoperable with NET-SNMP sub-agent
AgentXRequestPDU axReqPDU = (AgentXRequestPDU) pending.getAgentXPDU();
SubRequestIterator subRequests = pending.getReferences();
for (int i=0; subRequests.hasNext(); i++) {
SnmpSubRequest sreq = (SnmpSubRequest) subRequests.nextSubRequest();
MOScope srange = axReqPDU.getRanges()[i];
processEndOfMibView(sreq, srange, null);
}
}
else {
// process non repeaters first
SubRequestIterator it =
processAgentXNextResponse(pending, pdu, requestPDU.getNonRepeaters());
int nonRep = requestPDU.getNonRepeaters();
for (int c = 0;
(c+nonRep < requestPDU.getRanges().length) && it.hasNext(); c++) {
int rangeIndex = c + nonRep;
SnmpSubRequest sreq = (SnmpSubRequest) it.nextSubRequest();
SubRequestIterator rsreq = sreq.repetitions();
for (int r = 0; (nonRep + (r * repeaters) + c < numBindings) &&
rsreq.hasNext(); r++) {
SnmpSubRequest repetition = (SnmpSubRequest) rsreq.nextSubRequest();
/*
System.err.println("nr="+nonRep+",r="+r+",repeaters="+repeaters+
",c="+c+",rangeIndex="+rangeIndex+",rep="+repetition);
*/
processNextSubRequest(vbs, requestPDU, nonRep + (r * repeaters) + c,
rangeIndex, repetition);
}
}
}
}
}
protected static void processsErrorResponse(AgentXPending pending,
AgentXResponsePDU pdu) throws
NoSuchElementException
{
SubRequestIterator subRequests = pending.getReferences();
for (int i=1; i<pdu.getErrorIndex(); i++) {
if (subRequests.hasNext()) {
subRequests.next();
}
else {
pending.getRequest().setErrorStatus(PDU.genErr);
return;
}
}
if (subRequests.hasNext()) {
SubRequest sreq = subRequests.nextSubRequest();
RequestStatus status = sreq.getStatus();
status.setErrorStatus(pdu.getErrorStatus());
}
else {
pending.getRequest().setErrorStatus(PDU.genErr);
}
}
private static boolean checkAgentXResponse(AgentXResponsePDU pdu,
AgentXPending pending) {
switch (pending.getAgentXPDU().getType()) {
case AgentXPDU.AGENTX_GET_PDU:
case AgentXPDU.AGENTX_GETNEXT_PDU: {
if (((AgentXRequestPDU) pending.getAgentXPDU()).getRanges().length !=
pdu.size()) {
pending.getRequest().setErrorStatus(PDU.genErr);
return false;
}
break;
}
default: {
// no check?
}
}
return true;
}
protected AgentXResponsePDU ping(AgentXPingPDU pdu,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
if (!checkIfContextIsSupported(pdu.getContext())) {
response.setErrorStatus(AgentXProtocol.AGENTX_UNSUPPORTED_CONTEXT);
return response;
}
return response;
}
protected AgentXResponsePDU notify(AgentXNotifyPDU pdu,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
if (session != null) {
if (!checkIfContextIsSupported(pdu.getContext())) {
response.setErrorStatus(AgentXProtocol.AGENTX_UNSUPPORTED_CONTEXT);
return response;
}
VariableBinding[] vbs = pdu.getVariableBindings();
response.setVariableBindings(vbs);
int payloadIndex = 1;
OID trapoid = null;
TimeTicks timestamp = new TimeTicks(getContextSysUpTime(DEFAULT_CONTEXT));
if (vbs.length >= 1) {
if (SnmpConstants.sysUpTime.equals(vbs[0].getOid())) {
payloadIndex++;
if ((vbs.length < 2) ||
(!SnmpConstants.snmpTrapOID.equals(vbs[1].getOid()))) {
response.setErrorStatus(AgentXProtocol.AGENTX_PROCESSING_ERROR);
response.setErrorIndex(2);
}
else {
timestamp = (TimeTicks) vbs[0].getVariable();
trapoid = (OID) vbs[1].getVariable();
}
}
else if (SnmpConstants.snmpTrapOID.equals(vbs[0].getOid())) {
trapoid = (OID) vbs[0].getVariable();
}
else {
response.setErrorStatus(AgentXProtocol.AGENTX_PROCESSING_ERROR);
response.setErrorIndex(1);
}
}
if (trapoid != null) {
VariableBinding[] pvbs = new VariableBinding[vbs.length - payloadIndex];
System.arraycopy(vbs, payloadIndex, pvbs, 0, pvbs.length);
notify(pdu.getContext(), trapoid, timestamp, pvbs);
}
}
return response;
}
protected TimeTicks getContextSysUpTime(OctetString context) {
MasterContextInfo info = (MasterContextInfo) contextInfo.get(context);
SysUpTime contextSysUpTime;
if (info == null) {
MOContextScope scope =
new DefaultMOContextScope(context,
SnmpConstants.sysUpTime, true,
SnmpConstants.sysUpTime, true);
ManagedObject mo = getManagedObject(context, new DefaultMOQuery(scope));
if (mo instanceof SysUpTime) {
contextSysUpTime = (SysUpTime) mo;
}
else {
/**@todo May be we can use an integer of the found object to
* initialize the time?
*/
LOGGER.warn("SysUpTime could not be found in '"+context+
"' context, using a new instance instead");
contextSysUpTime = new SysUpTimeImpl();
}
contextInfo.put(context,
new MasterContextInfo(context, contextSysUpTime));
}
else {
contextSysUpTime = info.getUpTime();
}
if (contextSysUpTime != null) {
return contextSysUpTime.get();
}
return null;
}
public AgentXResponsePDU addAgentCaps(AgentXAddAgentCapsPDU pdu,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
if (session != null) {
if (!checkIfContextIsSupported(pdu.getContext())) {
response.setErrorStatus(AgentXProtocol.AGENTX_UNSUPPORTED_CONTEXT);
return response;
}
AgentCapabilityList agentCaps = getAgentCaps(pdu.getContext());
if (agentCaps != null) {
OID index = agentCaps.addSysOREntry(pdu.getId(), pdu.getDescr());
session.addAgentCaps(pdu.getId(), index);
}
}
return response;
}
protected AgentCapabilityList getAgentCaps(OctetString contextName) {
MOContextScope scope =
new DefaultMOContextScope(contextName,
SnmpConstants.sysOREntry, true,
SnmpConstants.sysOREntry, true);
ManagedObject mo = getManagedObject(contextName, new DefaultMOQuery(scope));
if (mo instanceof AgentCapabilityList) {
return (AgentCapabilityList)mo;
}
else {
LOGGER.warn("SysOREntry managed object for context "+contextName+
" not found, instead found: "+mo);
}
return null;
}
private ManagedObject getManagedObject(OctetString contextName,
MOQuery query) {
ManagedObject mo = null;
MOServer server = getServer(contextName);
if (server != null) {
mo = server.lookup(query);
}
return mo;
}
public AgentXResponsePDU removeAgentCaps(AgentXRemoveAgentCapsPDU pdu,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
if (session != null) {
OID index = session.removeAgentCaps(pdu.getId());
AgentCapabilityList agentCaps = getAgentCaps(pdu.getContext());
if (agentCaps != null) {
Object ac = agentCaps.removeSysOREntry(index);
if (ac == null) {
response.setErrorStatus(AgentXProtocol.AGENTX_UNKNOWN_AGENTCAPS);
}
}
else {
response.setErrorStatus(AgentXProtocol.AGENTX_UNKNOWN_AGENTCAPS);
}
}
return response;
}
public AgentXResponsePDU closeSession(AgentXClosePDU pdu,
AgentXMasterSession session) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Subagent is closing session "+session+
" because "+pdu.getReason());
}
AgentXResponsePDU response = createResponse(pdu, session);
if (session != null) {
removeSession(session.getSessionID());
removeAllRegistrations(session);
session.setClosed(true);
}
return response;
}
public void closeSession(AgentXMasterSession session,
byte reason) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Closing sub-agent session "+session+" because "+reason);
}
AgentXClosePDU closePDU = new AgentXClosePDU(reason);
try {
agentX.send(closePDU,
session.createAgentXTarget(),
session.getPeer().getTransport(),
new AgentXPendingClose(session, closePDU), this);
}
catch (IOException ex) {
LOGGER.error("Failed to send CloseSessionPDU to close session "+session+
": "+ex.getMessage(), ex);
}
removeSession(session.getSessionID());
removeAllRegistrations(session);
session.setClosed(true);
}
protected synchronized void removeAllRegistrations(AgentXMasterSession session) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removing all registrations (out of "+registrations.size()+
") of session "+session);
}
for (Iterator it = registrations.iterator(); it.hasNext(); ) {
AgentXRegEntry r = (AgentXRegEntry) it.next();
if (r.getSession().equals(session)) {
removeRegistration(r, it);
}
}
}
protected AgentXMasterSession getSession(int sessionID) {
return (AgentXMasterSession) sessions.get(new Integer(sessionID));
}
protected synchronized AgentXMasterSession getSession(AgentXPDU pdu) {
int sessionID = pdu.getSessionID();
return getSession(sessionID);
}
protected AgentXResponsePDU register(AgentXRegisterPDU pdu,
AgentXCommandEvent command,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
if (session != null) {
if (!checkIfContextIsSupported(pdu.getContext())) {
response.setErrorStatus(AgentXProtocol.AGENTX_UNSUPPORTED_CONTEXT);
return response;
}
AgentXRegEntry regEntry =
new AgentXRegEntry(session,
pdu.getRegion(),
pdu.getPriority(),
pdu.getContext(),
pdu.getTimeout());
if (isDuplicate(regEntry)) {
response.setErrorStatus(AgentXProtocol.AGENTX_DUPLICATE_REGISTRATION);
return response;
}
AgentXMasterEvent event =
new AgentXMasterEvent(this, AgentXMasterEvent.REGISTRATION_TO_ADD,
regEntry);
fireMasterChanged(event);
if (event.getVetoReason() == AgentXProtocol.AGENTX_SUCCESS) {
try {
addRegistration(regEntry);
}
catch (DuplicateRegistrationException drex) {
if (LOGGER.isDebugEnabled()) {
drex.printStackTrace();
}
response.setErrorStatus(AgentXProtocol.AGENTX_DUPLICATE_REGISTRATION);
return response;
}
}
else {
response.setErrorStatus(event.getVetoReason());
}
}
return response;
}
protected AgentXResponsePDU unregister(AgentXUnregisterPDU pdu,
AgentXCommandEvent event,
AgentXMasterSession session) {
AgentXResponsePDU response = createResponse(pdu, session);
if (session != null) {
AgentXRegEntry regEntry =
new AgentXRegEntry(session,
pdu.getRegion(),
pdu.getPriority(),
pdu.getContext(),
pdu.getTimeout());
boolean found = false;
for (Iterator it = registrations.iterator(); it.hasNext(); ) {
AgentXRegEntry r = (AgentXRegEntry) it.next();
if (r.equals(regEntry)) {
found = true;
if (!removeRegistration(r, it)) {
response.setErrorStatus(AgentXProtocol.AGENTX_UNKNOWN_REGISTRATION);
}
break;
}
}
if (!found) {
response.setErrorStatus(AgentXProtocol.AGENTX_UNKNOWN_REGISTRATION);
}
}
return response;
}
protected synchronized boolean isDuplicate(AgentXRegEntry registration) {
if (registrations.contains(registration)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Identical registration attempt for "+registration);
}
return true;
}
AgentXNodeQuery query =
new AgentXNodeQuery(registration.getContext(),
registration.getRegion(),
AgentXNodeQuery.QUERY_NON_AGENTX_NODES);
ManagedObject mo = getManagedObject(registration.getContext(), query);
if (mo != null) {
// overlaps non AgentX --> return duplicate region error
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("New registration is rejected as duplicate because it "+
"overlaps with non AgentX managed object: "+mo);
}
return true;
}
return false;
}
protected synchronized void addRegistration(AgentXRegEntry registration)
throws DuplicateRegistrationException
{
registrations.add(registration);
if (registration.getRegion().isRange()) {
AgentXRegion r = registration.getRegion();
long start = r.getLowerBoundSubID() & 0xFFFFFFFFL;
long stop = r.getUpperBoundSubID() & 0xFFFFFFFFL;
if (start > stop) {
LOGGER.warn("Empty range registration "+registration);
}
else {
for (long s = start; s <= stop; s++) {
OID root = new OID(r.getLowerBound());
root.set(r.getRangeSubID()-1, (int)s);
AgentXRegion sr = new AgentXRegion(root, root.nextPeer());
addRegion(registration, sr);
}
}
}
else {
addRegion(registration, registration.getRegion());
}
AgentXMasterEvent e =
new AgentXMasterEvent(this, AgentXMasterEvent.REGISTRATION_ADDED,
registration);
fireMasterChanged(e);
}
private static AgentXNodeQuery nextQuery(AgentXNodeQuery lastQuery,
AgentXNode lastNode) {
if (lastNode != null) {
lastQuery.getMutableScope().setLowerBound(
lastNode.getScope().getUpperBound());
lastQuery.getMutableScope().setLowerIncluded(
!lastNode.getScope().isUpperIncluded());
}
return lastQuery;
}
protected synchronized void addRegion(AgentXRegEntry registration,
AgentXRegion region) throws
DuplicateRegistrationException
{
if (region.isRange()) {
String errText = "Regions with range cannot be added";
LOGGER.error(errText);
throw new IllegalArgumentException(errText);
}
AgentXNodeQuery query =
new AgentXNodeQuery(registration.getContext(),
region,
AgentXNodeQuery.QUERY_AGENTX_NODES);
AgentXNode lastNode = null;
MOServer server = getServer(registration.getContext());
AgentXNode node = (AgentXNode)server.lookup(query);
if (node != null) {
LinkedList splitted = new LinkedList();
AgentXRegion r1 = new AgentXRegion(region);
for (; (node != null);
node = (AgentXNode) server.lookup(nextQuery(query, lastNode))) {
AgentXRegion r2 = new AgentXRegion(node.getScope().getLowerBound(),
node.getScope().getUpperBound());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Affected region r2="+r2+
" from registered region r1="+r1);
}
if (r2.covers(r1)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Region r2 covers r1 (r1="+r1+",r2="+r2+")");
}
oldRegionCoversNew(registration, node, splitted, r1, r2);
r1 = null;
}
else if (r1.covers(r2)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Region r1 covers r2 (r1="+r1+",r2="+r2+")");
}
r1 = newRegionCoversOld(registration, lastNode,
node, splitted, r1, r2);
}
else if ((r1.isOverlapping(r2)) &&
(r2.getLowerBound().compareTo(r1.getLowerBound()) < 0)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Region r1 ovelaps r2 and r2 < r1 (r1="+r1+
",r2="+r2+")");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Shrinking node "+node+
" to "+r1.getLowerBound());
}
node.shrink(r1.getLowerBound());
AgentXNode r2b =
node.getClone(new AgentXRegion(r1.getLowerBound(),
r2.getUpperBound()));
r2b.addRegistration(registration);
splitted.add(r2b);
r1 = new AgentXRegion(r2.getUpperBound(), r1.getLowerBound());
}
// r1.overlaps(r2) and (r1.get_lower() < r2.get_lower())
else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Region r1 ovelaps r2 and r1 < r2 (r1="+
r1+",r2="+r2+")");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Shrinking node "+node+
" to "+r1.getUpperBound());
}
node.shrink(r1.getUpperBound());
AgentXNode r2b =
node.getClone(new AgentXRegion(r1.getUpperBound(),
r2.getUpperBound()));
node.addRegistration(registration);
splitted.add(r2b);
AgentXNode r1a =
new AgentXNode(new AgentXRegion(r1.getLowerBound(),
r2.getLowerBound()), registration);
splitted.add(r1a);
r1 = null;
}
if (r1 != null) {
if (r1.isEmpty()) {
splitted.add(new AgentXNode(region, registration));
}
else {
splitted.add(new AgentXNode(r1, registration));
}
}
lastNode = node;
}
for (Iterator it = splitted.iterator(); it.hasNext(); ) {
AgentXNode n = (AgentXNode) it.next();
server.register(n, registration.getContext());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Registered splitted AgentX node: "+n);
}
}
}
else {
node = new AgentXNode(region, registration);
server.register(node, registration.getContext());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Registered AgentX node: "+node);
}
}
}
protected boolean removeRegistration(AgentXRegEntry registration,
Iterator regIterator) {
LinkedList remove = new LinkedList();
AgentXRegion queryRegion = new AgentXRegion(registration.getRegion());
queryRegion.setUpperIncluded(true);
AgentXNodeQuery query =
new AgentXNodeQuery(registration.getContext(),
queryRegion,
AgentXNodeQuery.QUERY_AGENTX_NODES);
AgentXNode lastNode = null;
MOServer server = getServer(registration.getContext());
AgentXNode node = (AgentXNode)server.lookup(query);
if (node != null) {
for (; (node != null);
node = (AgentXNode) server.lookup(nextQuery(query, lastNode))) {
if (node == lastNode) {
break;
}
if ((node.removeRegistration(registration)) &&
(node.getRegistrationCount() == 0)) {
remove.add(node);
}
else {
if ((lastNode != null) &&
(lastNode.getRegistrationCount() == 1) &&
(node.getRegistrationCount() == 1) &&
(lastNode.getScope().getUpperBound().equals(
node.getScope().getLowerBound())) &&
(node.getActiveRegistration().equals(
lastNode.getActiveRegistration()))) {
AgentXRegion r =
new AgentXRegion(node.getScope().getLowerBound(),
lastNode.getScope().getUpperBound());
if (node.getActiveRegistration().getRegion().covers(r)) {
remove.add(node);
lastNode.expand(node.getScope().getUpperBound(), false);
}
}
}
lastNode = node;
}
}
else {
LOGGER.warn("A registration is removed with not associated subtree: "+
registration);
}
for (Iterator it = remove.iterator(); it.hasNext(); ) {
AgentXNode rnode = (AgentXNode) it.next();
server.unregister(rnode, registration.getContext());
}
if (regIterator != null) {
regIterator.remove();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removed registration "+registration+
" by session close, "+registrations.size()+" left.");
}
fireMasterChanged(new AgentXMasterEvent(this,
AgentXMasterEvent.REGISTRATION_REMOVED,
registration));
return true;
}
else if (registrations.remove(registration)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Removed registration "+registration+
", "+registrations.size()+" left.");
}
fireMasterChanged(new AgentXMasterEvent(this,
AgentXMasterEvent.REGISTRATION_REMOVED,
registration));
return true;
}
return false;
}
private static AgentXRegion newRegionCoversOld(AgentXRegEntry registration,
AgentXNode lastNode,
AgentXNode node,
LinkedList splitted,
AgentXRegion r1,
AgentXRegion r2) {
AgentXNode r1a = null;
if (lastNode != null) {
AgentXRegion r =
new AgentXRegion(lastNode.getScope().getUpperBound(),
r2.getLowerBound());
r1a = new AgentXNode(r, registration);
}
else {
AgentXRegion r =
new AgentXRegion(r1.getLowerBound(), r2.getLowerBound());
r1a = new AgentXNode(r, registration);
}
if (!splitted.isEmpty()) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Shrinking node "+splitted.getLast()+
" to "+r2.getLowerBound());
}
((AgentXNode)splitted.getLast()).shrink(r2.getLowerBound());
}
node.addRegistration(registration);
if ((r1.getLowerBound().equals(r2.getLowerBound())) ||
((!splitted.isEmpty()) &&
(((AgentXNode)splitted.getLast()).
getScope().equals(r1a.getScope())))) {
r1a = null;
}
else {
splitted.add(r1a);
}
return new AgentXRegion(r2.getUpperBound(), r1.getUpperBound());
}
private static void oldRegionCoversNew(AgentXRegEntry registration,
AgentXNode node,
List splitted,
AgentXRegion r1,
AgentXRegion r2) {
AgentXRegion r = new AgentXRegion(r1.getUpperBound(),
node.getScope().getUpperBound());
AgentXNode r2c = node.getClone(r);
if (r2.getLowerBound().equals(r1.getLowerBound())) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Shrinking node "+node+" to "+r1.getUpperBound());
}
node.shrink(r1.getUpperBound());
node.addRegistration(registration);
}
else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Shrinking node "+node+" to "+r1.getLowerBound());
}
node.shrink(r1.getLowerBound());
AgentXNode r2b = node.getClone(r1);
r2b.addRegistration(registration);
splitted.add(r2b);
}
splitted.add(r2c);
}
public AgentXResponsePDU openSession(AgentXOpenPDU pdu,
AgentXCommandEvent event) {
AgentXMasterSession session =
new AgentXMasterSession(getNextSessionID(), agentXQueue,
pdu.getSubagentID(), pdu.getSubagentDescr());
AgentXPeer peer = getPeer(event.getPeerAddress());
if (peer == null) {
peer = new AgentXPeer(event.getPeerTransport(), event.getPeerAddress());
addPeer(peer);
LOGGER.warn("Added peer during session opening: "+peer+
" (peer should have been there already due "+
"to connection setup)");
}
session.setPeer(peer);
session.setAgentXVersion(pdu.getVersion() & 0xFF);
if (pdu.getTimeout() != 0) {
session.setTimeout(pdu.getTimeout());
}
else {
session.setTimeout(defaultTimeout);
}
int sessionAccepted = acceptSession(session);
if (sessionAccepted == AgentXProtocol.AGENTX_SUCCESS) {
addSession(session);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Session " + session + " opened from "+peer.getAddress());
}
}
else {
LOGGER.warn("Session open rejected because "+sessionAccepted+" for "+
session+" from "+event.getPeerAddress());
}
AgentXResponsePDU response = createResponse(pdu, session);
response.setErrorStatus((short)sessionAccepted);
return response;
}
protected synchronized void addPeer(AgentXPeer peer) {
peers.put(peer.getAddress(), peer);
fireMasterChanged(new AgentXMasterEvent(this,
AgentXMasterEvent.PEER_ADDED,
peer));
}
protected synchronized AgentXPeer getPeer(Address address) {
return (AgentXPeer) peers.get(address);
}
protected int acceptSession(AgentXMasterSession session) {
AgentXMasterEvent event =
new AgentXMasterEvent(this, AgentXMasterEvent.SESSION_ADDED, session);
fireMasterChanged(event);
return event.getVetoReason();
}
protected synchronized void addSession(AgentXMasterSession session) {
sessions.put(new Integer(session.getSessionID()), session);
fireMasterChanged(new AgentXMasterEvent(this,
AgentXMasterEvent.SESSION_ADDED,
session));
}
protected synchronized AgentXMasterSession removeSession(int sessionID) {
AgentXMasterSession session =
(AgentXMasterSession) sessions.remove(new Integer(sessionID));
if (session != null) {
fireMasterChanged(new AgentXMasterEvent(this,
AgentXMasterEvent.SESSION_REMOVED,
session));
}
return session;
}
protected AgentXResponsePDU createResponse(AgentXPDU request,
AgentXSession session) {
OctetString context = DEFAULT_CONTEXT;
if (request instanceof AgentXContextPDU) {
OctetString reqContext = ((AgentXContextPDU) request).getContext();
MOServer server = getServer(reqContext);
if ((server != null) && server.isContextSupported(reqContext)) {
context = reqContext;
}
}
AgentXResponsePDU response =
new AgentXResponsePDU(getContextSysUpTime(context).toInt(),
(short)0, (short)0);
if (session == null) {
response.setSessionID(request.getSessionID());
response.setErrorStatus(AgentXProtocol.AGENTX_NOT_OPEN);
}
else {
response.setSessionID(session.getSessionID());
}
response.setPacketID(request.getPacketID());
response.setTransactionID(request.getTransactionID());
response.setByteOrder(request.getByteOrder());
return response;
}
protected void sendResponse(AgentXPDU response, AgentXSession session) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Sending AgentX response "+response+" to session "+session);
}
try {
agentX.send(response,
session.createAgentXTarget(), session.getPeer().getTransport());
}
catch (IOException ex) {
if (LOGGER.isDebugEnabled()) {
ex.printStackTrace();
}
LOGGER.error("Failed to send AgentX response "+response+" to session "+
session+" because: "+ex.getMessage(), ex);
}
}
public synchronized void connectionStateChanged(TransportStateEvent change) {
Address peerAddress = change.getPeerAddress();
switch (change.getNewState()) {
case TransportStateEvent.STATE_CLOSED:
case TransportStateEvent.STATE_DISCONNECTED_REMOTELY:
case TransportStateEvent.STATE_DISCONNECTED_TIMEOUT: {
AgentXPeer removedPeer = removePeer(peerAddress);
fireMasterChanged(new AgentXMasterEvent(this,
AgentXMasterEvent.PEER_REMOVED,
removedPeer));
break;
}
default: {
AgentXPeer newPeer =
new AgentXPeer((TransportMapping)change.getSource(), peerAddress);
addPeer(newPeer);
}
}
}
protected synchronized AgentXPeer removePeer(Address peerAddress) {
AgentXPeer peer = (AgentXPeer) peers.remove(peerAddress);
if (peer != null) {
peer.setClosing(true);
for (Iterator it = sessions.values().iterator(); it.hasNext(); ) {
AgentXMasterSession session = (AgentXMasterSession) it.next();
if (session.getPeer().equals(peer)) {
it.remove();
fireMasterChanged(new AgentXMasterEvent(this,
AgentXMasterEvent.SESSION_REMOVED,
session));
indexRegistry.release(session.getSessionID());
removeAllRegistrations(session);
session.setClosed(true);
if (peer.getTransport() instanceof ConnectionOrientedTransportMapping) {
try {
((ConnectionOrientedTransportMapping)peer.getTransport()).
close(peer.getAddress());
}
catch (IOException iox) {
LOGGER.warn("Caught exception while closing transport: " +
iox.getMessage());
}
}
}
}
/* Optional code for debugging of registry issues:
if (LOGGER.isDebugEnabled()) {
if (server instanceof DefaultMOServer) {
SortedMap registry = ((DefaultMOServer) server).getRegistry();
System.err.println(registry.toString());
}
}
*/
}
else {
LOGGER.warn("Tried to remove peer with address "+peerAddress+
" which is not part of peer list: "+peers);
}
return peer;
}
protected synchronized AgentXPeer closePeer(Address peerAddress, byte reason) {
AgentXPeer peer = (AgentXPeer) peers.remove(peerAddress);
if (peer != null) {
peer.setClosing(true);
Map s = new HashMap(sessions);
for (Iterator it = s.values().iterator(); it.hasNext(); ) {
AgentXMasterSession session = (AgentXMasterSession) it.next();
if (session.getPeer().equals(peer)) {
closeSession(session, reason);
if (peer.getTransport() instanceof ConnectionOrientedTransportMapping) {
try {
((ConnectionOrientedTransportMapping)peer.getTransport()).
close(peer.getAddress());
}
catch (IOException iox) {
LOGGER.warn("Caught exception while closing transport: " +
iox.getMessage());
}
}
}
}
}
else {
LOGGER.warn("Tried to remove peer with address "+peerAddress+
" which is not part of peer list: "+peers);
}
return peer;
}
public byte getAgentXVersion() {
return AgentXProtocol.VERSION_1_0;
}
public synchronized void addAgentXMasterListener(AgentXMasterListener l) {
if (agentXMasterListeners == null) {
agentXMasterListeners = new Vector(2);
}
agentXMasterListeners.add(l);
}
public synchronized void removeAgentXMasterListener(AgentXMasterListener l) {
if (agentXMasterListeners != null) {
agentXMasterListeners.remove(l);
}
}
protected void fireMasterChanged(AgentXMasterEvent event) {
if (agentXMasterListeners != null) {
Vector listeners = agentXMasterListeners;
int count = listeners.size();
for (int i = 0; i < count; i++) {
try {
((AgentXMasterListener) listeners.get(i)).masterChanged(event);
}
catch (Exception ex) {
LOGGER.error("AgentXMasterListener "+listeners.get(i)+
" threw exception on "+event+": "+ex.getMessage(), ex);
}
}
}
}
protected static class AgentXRegEntryComparator implements Comparator {
public int compare(Object o1, Object o2) {
AgentXRegEntry a = (AgentXRegEntry)o1;
AgentXRegEntry b = (AgentXRegEntry)o2;
int c = a.getRegion().compareTo(b.getRegion());
if (c == 0) {
c = a.getContext().compareTo(b.getContext());
}
return c;
}
}
public void onResponse(AgentXResponseEvent event) {
AgentXResponsePDU pdu = event.getResponse();
AgentXPending pending = (AgentXPending) event.getUserObject();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Processing AgentX response "+pdu+" for request "+pending);
}
if (pending.getRequest() != null) {
AgentXPending p =
agentXQueue.remove(pending.getAgentXPDU().getSessionID(),
pending.getRequest().getTransactionID());
if (p == null) {
LOGGER.warn("Pending AgentX request not found (may be timed out already): " +
"Received AgentX response from " + event.getPeerAddress() +
" for request " + event.getUserObject() +
" does not match any pending request:" + pdu);
return;
}
}
if ((pdu == null) &&
(pending.getAgentXPDU().getType() != AgentXPDU.AGENTX_CLOSE_PDU)) {
pending.getSession().incConsecutiveTimeouts();
pending.getReferences().
nextSubRequest().getStatus().setErrorStatus(PDU.genErr);
if (pending.getSession().getConsecutiveTimeouts() >
maxConsecutiveTimeouts) {
closeSession(pending.getSession(), AgentXProtocol.REASON_TIMEOUTS);
}
}
if (pdu != null) {
pending.getSession().clearConsecutiveTimeouts();
}
if (pending.getRequest() != null) {
MOServer server = getServer(pending.getRequest().getContext());
if (requestList.contains(pending.getRequest())) {
if (pdu != null) {
if (checkAgentXResponse(pdu, pending)) {
switch (pending.getAgentXPDU().getType()) {
case AgentXPDU.AGENTX_GET_PDU: {
processAgentXGetResponse(pending, pdu);
break;
}
case AgentXPDU.AGENTX_GETNEXT_PDU: {
processAgentXGetNextResponse(pending, pdu);
break;
}
case AgentXPDU.AGENTX_GETBULK_PDU: {
processAgentXBulkResponse(pending, pdu);
break;
}
case AgentXPDU.AGENTX_CLEANUPSET_PDU:
case AgentXPDU.AGENTX_UNDOSET_PDU:
case AgentXPDU.AGENTX_COMMITSET_PDU:
case AgentXPDU.AGENTX_TESTSET_PDU: {
processAgentXSetResponse(pending, pdu);
break;
}
default: {
LOGGER.warn("Unhandled AgentX response " + pdu);
}
}
}
else {
LOGGER.warn("Invalid AgentX response " + pdu +
" on request " + pending);
}
}
// reprocess SNMP request
if (!pending.getRequest().isComplete()) {
reprocessRequest(server, pending.getRequest());
}
finalizeRequest((CommandResponderEvent)
pending.getRequest().getSource(), pending.getRequest(),
server);
}
else {
if (pending.getAgentXPDU().getType() == AgentXPDU.AGENTX_CLOSE_PDU) {
if (pdu != null) {
LOGGER.info("Subagent " + event.getPeerAddress() +
" confirmed close, disconnection transport now");
}
else {
LOGGER.info("Subagent " + event.getPeerAddress() +
" did not answered on session close, " +
"disconnection now");
}
AgentXPeer peer = pending.getSession().getPeer();
if (peer != null) {
closePeer(peer);
}
}
else {
LOGGER.info("Received late response " + pdu + " on AgentX request: " +
pending);
super.release(server, pending.getRequest());
}
}
}
}
protected void processAgentXGetResponse(AgentXPending pending,
AgentXResponsePDU pdu) {
if (pdu.getErrorStatus() != PDU.noError) {
processsErrorResponse(pending, pdu);
}
else {
VariableBinding[] vbs = pdu.getVariableBindings();
SubRequestIterator subRequests = pending.getReferences();
for (int i=0; (i<pending.getRequest().size()) &&
subRequests.hasNext(); i++) {
SnmpSubRequest sreq = (SnmpSubRequest) subRequests.nextSubRequest();
sreq.getVariableBinding().setVariable(vbs[i].getVariable());
sreq.getStatus().setPhaseComplete(true);
}
}
}
protected void processAgentXGetNextResponse(AgentXPending pending,
AgentXResponsePDU pdu) {
if (pdu.getErrorStatus() != PDU.noError) {
processsErrorResponse(pending, pdu);
}
else {
processAgentXNextResponse(pending, pdu, pending.getRequest().size());
}
}
protected void processAgentXSetResponse(AgentXPending pending,
AgentXResponsePDU pdu) {
if (pdu.getErrorStatus() != PDU.noError) {
processsErrorResponse(pending, pdu);
}
else {
SubRequestIterator it = pending.getReferences();
while (it.hasNext()) {
SubRequest sreq = it.nextSubRequest();
sreq.getStatus().setPhaseComplete(true);
}
}
}
}