0001: /*_############################################################################
0002: _##
0003: _## SNMP4J-Agent - CommandProcessor.java
0004: _##
0005: _## Copyright (C) 2005-2007 Frank Fock (SNMP4J.org)
0006: _##
0007: _## Licensed under the Apache License, Version 2.0 (the "License");
0008: _## you may not use this file except in compliance with the License.
0009: _## You may obtain a copy of the License at
0010: _##
0011: _## http://www.apache.org/licenses/LICENSE-2.0
0012: _##
0013: _## Unless required by applicable law or agreed to in writing, software
0014: _## distributed under the License is distributed on an "AS IS" BASIS,
0015: _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016: _## See the License for the specific language governing permissions and
0017: _## limitations under the License.
0018: _##
0019: _##########################################################################*/
0020:
0021: package org.snmp4j.agent;
0022:
0023: import java.util.*;
0024:
0025: import org.snmp4j.*;
0026: import org.snmp4j.agent.request.*;
0027: import org.snmp4j.agent.security.*;
0028: import org.snmp4j.event.*;
0029: import org.snmp4j.mp.*;
0030: import org.snmp4j.smi.*;
0031: import org.snmp4j.util.*;
0032: import org.snmp4j.agent.util.TemporaryList;
0033: import org.snmp4j.agent.mo.snmp.CoexistenceInfo;
0034: import org.snmp4j.agent.mo.snmp.CoexistenceInfoProvider;
0035: import org.snmp4j.log.LogAdapter;
0036: import org.snmp4j.log.LogFactory;
0037: import org.snmp4j.agent.mo.MOChangeEvent;
0038: import org.snmp4j.agent.mo.MOChangeListener;
0039:
0040: /**
0041: * The <code>CommandProcessor</code> is the central glue code that puts together
0042: * the various sub-systems of a SNMP agent.
0043: *
0044: * @author Frank Fock
0045: * @version 1.0
0046: */
0047: public class CommandProcessor implements CommandResponder,
0048: NotificationOriginator {
0049:
0050: private static final LogAdapter logger = LogFactory
0051: .getLogger(CommandProcessor.class);
0052:
0053: /**
0054: * The maximum request timeout supported by this command processor
0055: * (by default 60.000 ms = 1 min).
0056: */
0057: private static final int MAX_INTERNAL_REQUEST_TIMEOUT = 60000;
0058:
0059: protected ThreadPool threadPool = null;
0060: protected VACM vacm = null;
0061: protected Vector moServers;
0062: protected OctetString ownContextEngineID;
0063: protected Vector pduHandler;
0064: protected TemporaryList requestList;
0065: protected RequestFactory requestFactory;
0066: protected NotificationOriginator notificationOriginator;
0067: protected ProxyMap proxyForwarder;
0068: protected CoexistenceInfoProvider coexistenceProvider;
0069:
0070: private transient Vector counterListeners;
0071:
0072: public CommandProcessor(OctetString contextEngineID) {
0073: this .ownContextEngineID = contextEngineID;
0074: moServers = new Vector();
0075: requestList = new TemporaryList(MAX_INTERNAL_REQUEST_TIMEOUT);
0076: pduHandler = new Vector();
0077: pduHandler.add(new GetHandler());
0078: pduHandler.add(new GetNextHandler());
0079: pduHandler.add(new SetHandler());
0080: pduHandler.add(new GetBulkHandler());
0081: requestFactory = new DefaultRequestFactory();
0082: }
0083:
0084: public void processPdu(CommandResponderEvent event) {
0085: if (event.getPDU() != null) {
0086: CoexistenceInfo cinfo = null;
0087: OctetString sname = new OctetString(event.getSecurityName());
0088: if (event.getPDU() instanceof ScopedPDU) {
0089: ScopedPDU spdu = (ScopedPDU) event.getPDU();
0090: cinfo = new CoexistenceInfo(sname, spdu
0091: .getContextEngineID(), spdu.getContextName());
0092: } else if (coexistenceProvider != null) {
0093: cinfo = coexistenceProvider.getCoexistenceInfo(sname);
0094: if (cinfo != null) {
0095: if (!coexistenceProvider.passesFilter(event
0096: .getPeerAddress(), cinfo)) {
0097: logger
0098: .warn("Access attempt from "
0099: + event.getPeerAddress()
0100: + " denied because of source address filtering");
0101:
0102: fireIncrementCounter(new CounterEvent(this ,
0103: SnmpConstants.snmpInBadCommunityNames));
0104: return;
0105: }
0106: event.setMaxSizeResponsePDU(cinfo
0107: .getMaxMessageSize());
0108: } else {
0109: if (logger.isInfoEnabled()) {
0110: logger.info("Community name '" + sname
0111: + "' not found in SNMP-COMMUNITY-MIB");
0112: }
0113: fireIncrementCounter(new CounterEvent(this ,
0114: SnmpConstants.snmpInBadCommunityNames));
0115: return;
0116: }
0117: }
0118: if ((cinfo == null)
0119: || (ownContextEngineID.equals(cinfo
0120: .getContextEngineID()))) {
0121: event.setProcessed(true);
0122: Command command = new Command(event, cinfo);
0123: if (threadPool != null) {
0124: threadPool.execute(command);
0125: } else {
0126: command.run();
0127: }
0128: } else if (proxyForwarder != null) {
0129: ProxyForwardRequest request = new ProxyForwardRequest(
0130: event, cinfo);
0131: ProxyForwarder proxy = proxyForwarder.get(cinfo
0132: .getContextEngineID(), request.getProxyType());
0133: ProxyCommand command = new ProxyCommand(proxy, request);
0134: if (proxy != null) {
0135: if (logger.isDebugEnabled()) {
0136: logger
0137: .debug("Processsing proxy request with proxy forwarder "
0138: + proxy);
0139: }
0140: if (threadPool != null) {
0141: threadPool.execute(command);
0142: } else {
0143: command.run();
0144: }
0145: } else {
0146: fireIncrementCounter(new CounterEvent(this ,
0147: SnmpConstants.snmpProxyDrops));
0148: }
0149: } else {
0150: fireIncrementCounter(new CounterEvent(this ,
0151: SnmpConstants.snmpSilentDrops));
0152: }
0153: }
0154: }
0155:
0156: public void setThreadPool(ThreadPool threadPool) {
0157: this .threadPool = threadPool;
0158: }
0159:
0160: public VACM getVacm() {
0161: return vacm;
0162: }
0163:
0164: public void setVacm(VACM vacm) {
0165: this .vacm = vacm;
0166: }
0167:
0168: public OctetString getContextEngineID() {
0169: return ownContextEngineID;
0170: }
0171:
0172: public void setContextEngineID(OctetString contextEngineID) {
0173: this .ownContextEngineID = contextEngineID;
0174: }
0175:
0176: /**
0177: * Sends notification/inform messages to all registered targets. This method
0178: * uses the internal {@link ThreadPool} to send the message(s) via the
0179: * <code>NotificationOriginator</code>
0180: * (see {@link #getNotificationOriginator}) to the targets specified by the
0181: * SnmpTargetMIB and SnmpNotificationMIB instances supplied to the
0182: * notification originator.
0183: *
0184: * @param context
0185: * the context name of the context on whose behalf this notification has
0186: * been generated.
0187: * @param notificationID
0188: * the object ID that uniquely identifies this notification. For SNMPv1
0189: * traps, the notification ID has to be build using the rules provided
0190: * by RFC 2576.
0191: * @param vbs
0192: * an array of <code>VariableBinding</code> instances representing the
0193: * payload of the notification.
0194: * @return
0195: * an array of ResponseEvent instances or NotificationTask instance if
0196: * the notification has been send asynchronously. Since the
0197: * <code>NotificationOriginator</code> determines on behalf of the
0198: * SNMP-NOTIFICTON-MIB contents whether a notification is sent as
0199: * trap/notification or as inform request, the returned array will contain
0200: * an element for each addressed target, but only a response PDU for
0201: * inform targets.
0202: * <p>
0203: * <code>null</code> will be returned when sending the notification failed
0204: * because there is no {@link NotificationOriginator} set.
0205: * <p>
0206: * NOTE: If this command processor is using a ThreadPool then the returned
0207: * object will be {@link NotificationTask} instance. If all response have
0208: * been received {@link Object#notify()} will be called on the returned
0209: * <code>NotificationTask</code> object by the sending thread.
0210: */
0211: public Object notify(final OctetString context,
0212: final OID notificationID, final VariableBinding[] vbs) {
0213: return notify(context, notificationID, null, vbs);
0214: }
0215:
0216: public Object notify(OctetString context, OID notificationID,
0217: TimeTicks sysUpTime, VariableBinding[] vbs) {
0218: if (notificationOriginator != null) {
0219: NotificationTask notifyTask = new NotificationTask(
0220: notificationOriginator, context, notificationID,
0221: sysUpTime, vbs);
0222: if (threadPool != null) {
0223: threadPool.execute(notifyTask);
0224: return notifyTask;
0225: } else {
0226: notifyTask.run();
0227: return notifyTask.getResponses();
0228: }
0229: } else {
0230: logger.warn("Could not sent notification '"
0231: + notificationID + "'=" + Arrays.asList(vbs)
0232: + " because NotificationOriginator not set");
0233: }
0234: return null;
0235: }
0236:
0237: public void setNotificationOriginator(
0238: NotificationOriginator notificationOriginator) {
0239: this .notificationOriginator = notificationOriginator;
0240: }
0241:
0242: public void setCoexistenceProvider(
0243: CoexistenceInfoProvider coexistenceProvider) {
0244: this .coexistenceProvider = coexistenceProvider;
0245: }
0246:
0247: public ProxyForwarder addProxyForwarder(
0248: ProxyForwarder proxyForwarder, OctetString contextEngineID,
0249: int proxyType) {
0250: if (this .proxyForwarder == null) {
0251: this .proxyForwarder = new ProxyMap();
0252: }
0253: return this .proxyForwarder.add(proxyForwarder, contextEngineID,
0254: proxyType);
0255: }
0256:
0257: public ProxyForwarder removeProxyForwarder(
0258: OctetString contextEngineID, int proxyType) {
0259: if (proxyForwarder != null) {
0260: return proxyForwarder.remove(contextEngineID, proxyType);
0261: }
0262: return null;
0263: }
0264:
0265: protected RequestHandler getHandler(int pduType) {
0266: synchronized (pduHandler) {
0267: for (int i = 0; i < pduHandler.size(); i++) {
0268: RequestHandler handler = (RequestHandler) pduHandler
0269: .get(i);
0270: if (handler.isSupported(pduType)) {
0271: return handler;
0272: }
0273: }
0274: }
0275: return null;
0276: }
0277:
0278: protected void dispatchCommand(CommandResponderEvent command,
0279: CoexistenceInfo cinfo) {
0280: RequestHandler handler = getHandler(command.getPDU().getType());
0281: if (handler != null) {
0282: processRequest(command, cinfo, handler);
0283: } else {
0284: sendUnknownPDUHandlersReport(command);
0285: }
0286: }
0287:
0288: private void sendUnknownPDUHandlersReport(
0289: CommandResponderEvent command) {
0290: logger.info("No PDU handler found for request " + command);
0291: CounterEvent counter = new CounterEvent(this ,
0292: SnmpConstants.snmpUnknownPDUHandlers);
0293: fireIncrementCounter(counter);
0294: if ((command.getMessageProcessingModel() == MessageProcessingModel.MPv3)
0295: && (command.getPDU() instanceof ScopedPDU)) {
0296: ScopedPDU request = (ScopedPDU) command.getPDU();
0297: ScopedPDU report = new ScopedPDU();
0298: report.setContextEngineID(request.getContextEngineID());
0299: report.setContextName(request.getContextName());
0300: report.setType(PDU.REPORT);
0301: report.add(new VariableBinding(counter.getOid(), counter
0302: .getCurrentValue()));
0303: sendResponse(command, report);
0304: } else {
0305: PDU resp = (PDU) command.getPDU().clone();
0306: resp.setErrorStatus(PDU.genErr);
0307: sendResponse(command, resp);
0308: }
0309: }
0310:
0311: protected void processRequest(CommandResponderEvent command,
0312: CoexistenceInfo cinfo, RequestHandler handler) {
0313: Request req = requestFactory.createRequest(command, cinfo);
0314: requestList.add(req);
0315:
0316: MOServer server = null;
0317: OctetString context = req.getContext();
0318: OctetString viewName = getViewName(command, cinfo, req
0319: .getViewType());
0320: if (viewName == null) {
0321: setAuthorizationError(req, VACM.VACM_NO_SUCH_VIEW);
0322: } else {
0323: req.setViewName(viewName);
0324: server = getServer(context);
0325: processRequest(server, handler, req);
0326: }
0327: finalizeRequest(command, req, server);
0328: }
0329:
0330: protected void reprocessRequest(MOServer server, SnmpRequest req) {
0331: RequestHandler handler = getHandler(req.getInitiatingEvent()
0332: .getPDU().getType());
0333: if (handler != null) {
0334: req.resetProcessedStatus();
0335: req.incReprocessCounter();
0336: processRequest(server, handler, req);
0337: } else {
0338: sendUnknownPDUHandlersReport(req.getInitiatingEvent());
0339: }
0340: }
0341:
0342: /**
0343: * Processs (or re-process) a request and try to complete the request (thus
0344: * to complete any incomplete subrequests).
0345: *
0346: * @param server
0347: * the <code>MOServer</code> instance to use for accessing instrumentation.
0348: * @param handler
0349: * the <code>RequestHandler</code> to use to process the request.
0350: * @param req
0351: * the <code>Request</code>.
0352: */
0353: protected void processRequest(MOServer server,
0354: RequestHandler handler, Request req) {
0355:
0356: if (server == null) {
0357: logger.error("No server for " + req.getContext()
0358: + " found -> request cannot be processed");
0359: req.setErrorStatus(SnmpConstants.SNMP_ERROR_GENERAL_ERROR);
0360: } else {
0361: handler.processPdu(req, server);
0362: }
0363: }
0364:
0365: protected void finalizeRequest(CommandResponderEvent command,
0366: Request req, MOServer server) {
0367: if (req.isComplete()) {
0368: requestList.remove(req);
0369: // send response
0370: sendResponse(command, (PDU) req.getResponse());
0371: if (server != null) {
0372: release(server, req);
0373: }
0374: }
0375: }
0376:
0377: protected void release(MOServer server, Request req) {
0378: for (Iterator it = req.iterator(); it.hasNext();) {
0379: SubRequest sreq = (SubRequest) it.next();
0380: if (sreq.getTargetMO() != null) {
0381: server.unlock(req, sreq.getTargetMO());
0382: }
0383: }
0384: }
0385:
0386: protected void sendResponse(CommandResponderEvent requestEvent,
0387: PDU response) {
0388: MessageDispatcher disp = requestEvent.getMessageDispatcher();
0389: try {
0390: if (response.getBERLength() > requestEvent
0391: .getMaxSizeResponsePDU()) {
0392: // response is tooBig
0393: if (response.getType() != PDU.REPORT) {
0394: if (requestEvent.getPDU().getType() == PDU.GETBULK) {
0395: while ((response.size() > 0)
0396: && (response.getBERLength() > requestEvent
0397: .getMaxSizeResponsePDU())) {
0398: response.trim();
0399: }
0400: } else {
0401: response.clear();
0402: response.setRequestID(requestEvent.getPDU()
0403: .getRequestID());
0404: response.setErrorStatus(PDU.tooBig);
0405: }
0406: }
0407: if (response.getBERLength() > requestEvent
0408: .getMaxSizeResponsePDU()) {
0409: fireIncrementCounter(new CounterEvent(this ,
0410: SnmpConstants.snmpSilentDrops));
0411: return;
0412: }
0413: }
0414: StatusInformation status = new StatusInformation();
0415: requestEvent.getStateReference().setTransportMapping(
0416: requestEvent.getTransportMapping());
0417: disp.returnResponsePdu(requestEvent
0418: .getMessageProcessingModel(), requestEvent
0419: .getSecurityModel(),
0420: requestEvent.getSecurityName(), requestEvent
0421: .getSecurityLevel(), response, requestEvent
0422: .getMaxSizeResponsePDU(), requestEvent
0423: .getStateReference(), status);
0424: } catch (MessageException ex) {
0425: logger.error("Failed to send response to request "
0426: + requestEvent, ex);
0427: }
0428: }
0429:
0430: protected void setAuthorizationError(Request req, int vacmStatus) {
0431: if (req.size() > 0) {
0432: SubRequest sreq = (SubRequest) req.iterator().next();
0433: sreq.getStatus().setErrorStatus(PDU.authorizationError);
0434: } else {
0435: req.setErrorStatus(PDU.authorizationError);
0436: }
0437: }
0438:
0439: public void addPduHandler(RequestHandler handler) {
0440: pduHandler.add(handler);
0441: }
0442:
0443: public void removePduHandler(RequestHandler handler) {
0444: pduHandler.remove(handler);
0445: }
0446:
0447: public void addMOServer(MOServer server) {
0448: moServers.add(server);
0449: }
0450:
0451: public void removeMOServer(MOServer server) {
0452: moServers.remove(server);
0453: }
0454:
0455: public MOServer getServer(OctetString context) {
0456: for (int i = 0; i < moServers.size(); i++) {
0457: MOServer s = (MOServer) moServers.get(i);
0458: if (s.isContextSupported(context)) {
0459: return s;
0460: }
0461: }
0462: return null;
0463: }
0464:
0465: public TemporaryList getRequestList() {
0466: return requestList;
0467: }
0468:
0469: public NotificationOriginator getNotificationOriginator() {
0470: return notificationOriginator;
0471: }
0472:
0473: public ProxyMap getProxyForwarder() {
0474: return proxyForwarder;
0475: }
0476:
0477: public CoexistenceInfoProvider getCoexistenceProvider() {
0478: return coexistenceProvider;
0479: }
0480:
0481: class Command implements Runnable {
0482:
0483: private CommandResponderEvent request;
0484: private CoexistenceInfo cinfo;
0485:
0486: public Command(CommandResponderEvent event,
0487: CoexistenceInfo cinfo) {
0488: this .request = event;
0489: this .cinfo = cinfo;
0490: }
0491:
0492: public void run() {
0493: dispatchCommand(request, cinfo);
0494: }
0495: }
0496:
0497: class ProxyCommand implements Runnable {
0498:
0499: private ProxyForwardRequest request;
0500: private ProxyForwarder forwarder;
0501:
0502: public ProxyCommand(ProxyForwarder forwarder,
0503: ProxyForwardRequest event) {
0504: this .forwarder = forwarder;
0505: this .request = event;
0506: }
0507:
0508: public void run() {
0509: if (forwarder.forward(request)) {
0510: PDU response = request.getResponsePDU();
0511: if (response != null) {
0512: sendResponse(request.getCommandEvent(), response);
0513: }
0514: } else if (request.getProxyType() != ProxyForwarder.PROXY_TYPE_NOTIFY) {
0515: // proxy drop
0516: CounterEvent cevent = new CounterEvent(this ,
0517: SnmpConstants.snmpProxyDrops);
0518: fireIncrementCounter(cevent);
0519: if (request.getCommandEvent()
0520: .getMessageProcessingModel() == MPv3.ID) {
0521: ScopedPDU reportPDU = new ScopedPDU();
0522: reportPDU.setType(PDU.REPORT);
0523: reportPDU.setContextEngineID(request
0524: .getContextEngineID());
0525: reportPDU.setContextName(request.getContext());
0526: reportPDU.add(new VariableBinding(
0527: SnmpConstants.snmpProxyDrops, cevent
0528: .getCurrentValue()));
0529: sendResponse(request.getCommandEvent(), reportPDU);
0530: }
0531: }
0532: }
0533: }
0534:
0535: protected OctetString getViewName(CommandResponderEvent req,
0536: CoexistenceInfo cinfo, int viewType) {
0537: OctetString viewName = vacm.getViewName(cinfo.getContextName(),
0538: cinfo.getSecurityName(), req.getSecurityModel(), req
0539: .getSecurityLevel(), viewType);
0540: return viewName;
0541: }
0542:
0543: protected void processNextSubRequest(Request request,
0544: MOServer server, OctetString context, SubRequest sreq)
0545: throws NoSuchElementException {
0546: // We can be sure to have a default context scope here because
0547: // the inner class SnmpSubRequest creates it!
0548: DefaultMOContextScope scope = (DefaultMOContextScope) sreq
0549: .getScope();
0550: MOQuery query = sreq.getQuery();
0551: if (query == null) {
0552: query = new VACMQuery(context, scope.getLowerBound(), scope
0553: .isLowerIncluded(), scope.getUpperBound(), scope
0554: .isUpperIncluded(), request.getViewName());
0555: sreq.setQuery(query);
0556: }
0557: while (!sreq.getStatus().isProcessed()) {
0558: ManagedObject mo = server.lookup(query);
0559: if (mo == null) {
0560: if (logger.isDebugEnabled()) {
0561: logger.debug("EndOfMibView at scope=" + scope
0562: + " and query " + query);
0563: }
0564: sreq.getVariableBinding()
0565: .setVariable(Null.endOfMibView);
0566: sreq.getStatus().setPhaseComplete(true);
0567: continue;
0568: }
0569: try {
0570: if (logger.isDebugEnabled()) {
0571: logger.debug("Processing NEXT query " + query
0572: + " with " + mo
0573: + " sub-request with index "
0574: + sreq.getIndex());
0575: }
0576: if ((!mo.next(sreq))
0577: || ((request.getMessageProcessingModel() == MPv1.ID) && (sreq
0578: .getVariableBinding().getSyntax() == SMIConstants.SYNTAX_COUNTER64))) {
0579: sreq.getVariableBinding()
0580: .setVariable(Null.instance);
0581: scope.substractScope(mo.getScope());
0582: // don't forget to update VACM query:
0583: query.substractScope(mo.getScope());
0584: }
0585: } catch (Exception moex) {
0586: if (logger.isDebugEnabled()) {
0587: moex.printStackTrace();
0588: }
0589: logger.error(
0590: "Exception occurred while executing NEXT query: "
0591: + moex.getMessage(), moex);
0592: if (sreq.getStatus().getErrorStatus() == PDU.noError) {
0593: sreq.getStatus().setErrorStatus(PDU.genErr);
0594: }
0595: if (SNMP4JSettings.isFowardRuntimeExceptions()) {
0596: throw new RuntimeException(moex);
0597: }
0598: }
0599: }
0600: }
0601:
0602: public synchronized void addCounterListener(CounterListener l) {
0603: if (counterListeners == null) {
0604: counterListeners = new Vector(2);
0605: }
0606: counterListeners.add(l);
0607: }
0608:
0609: public synchronized void removeCounterListener(CounterListener l) {
0610: if (counterListeners != null) {
0611: counterListeners.remove(l);
0612: }
0613: }
0614:
0615: protected void fireIncrementCounter(CounterEvent event) {
0616: if (counterListeners != null) {
0617: Vector listeners = counterListeners;
0618: int count = listeners.size();
0619: for (int i = 0; i < count; i++) {
0620: ((CounterListener) listeners.elementAt(i))
0621: .incrementCounter(event);
0622: }
0623: }
0624: }
0625:
0626: private static void initRequestPhase(Request request) {
0627: if (request.getPhase() == Request.PHASE_INIT) {
0628: request.nextPhase();
0629: }
0630: }
0631:
0632: class GetNextHandler implements RequestHandler {
0633:
0634: public void processPdu(Request request, MOServer server) {
0635: initRequestPhase(request);
0636: OctetString context = request.getContext();
0637: try {
0638: SubRequestIterator it = (SubRequestIterator) request
0639: .iterator();
0640: while (it.hasNext()) {
0641: SubRequest sreq = it.nextSubRequest();
0642: processNextSubRequest(request, server, context,
0643: sreq);
0644: }
0645: } catch (NoSuchElementException nsex) {
0646: if (logger.isDebugEnabled()) {
0647: nsex.printStackTrace();
0648: }
0649: logger.error("SubRequest not found");
0650: request.setErrorStatus(PDU.genErr);
0651: }
0652: }
0653:
0654: public boolean isSupported(int pduType) {
0655: return (pduType == PDU.GETNEXT);
0656: }
0657:
0658: }
0659:
0660: class SetHandler implements RequestHandler {
0661:
0662: public void prepare(OctetString context, Request request,
0663: MOServer server) {
0664: try {
0665: SubRequestIterator it = (SubRequestIterator) request
0666: .iterator();
0667: while ((!request.isPhaseComplete()) && (it.hasNext())) {
0668: SubRequest sreq = it.nextSubRequest();
0669: if (sreq.isComplete()) {
0670: continue;
0671: }
0672: MOScope scope = sreq.getScope();
0673: MOQuery query = sreq.getQuery();
0674: if (query == null) {
0675: // create a query for write access
0676: query = new VACMQuery(context, scope
0677: .getLowerBound(), scope
0678: .isLowerIncluded(), scope
0679: .getUpperBound(), scope
0680: .isUpperIncluded(), request
0681: .getViewName());
0682: sreq.setQuery(query);
0683: }
0684: if (!query.getScope().isCovered(
0685: new DefaultMOContextScope(context, scope))) {
0686: sreq.getStatus().setErrorStatus(PDU.noAccess);
0687: } else {
0688: ManagedObject mo = server.lookup(query);
0689: if (mo == null) {
0690: if ((query instanceof VACMQuery)
0691: && (!((VACMQuery) query)
0692: .isAccessAllowed(scope
0693: .getLowerBound()))) {
0694: sreq.getStatus().setErrorStatus(
0695: PDU.noAccess);
0696: } else {
0697: sreq.getStatus().setErrorStatus(
0698: PDU.notWritable);
0699: }
0700: break;
0701: }
0702: sreq.setTargetMO(mo);
0703: server.lock(sreq.getRequest(), mo);
0704: try {
0705: mo.prepare(sreq);
0706: } catch (Exception moex) {
0707: logger.error("Set request " + request
0708: + " failed with exception", moex);
0709: if (sreq.getStatus().getErrorStatus() == PDU.noError) {
0710: sreq.getStatus().setErrorStatus(
0711: PDU.genErr);
0712: }
0713: if (SNMP4JSettings
0714: .isFowardRuntimeExceptions()) {
0715: throw new RuntimeException(moex);
0716: }
0717: }
0718: }
0719: }
0720: } catch (NoSuchElementException nsex) {
0721: if (logger.isDebugEnabled()) {
0722: nsex.printStackTrace();
0723: }
0724: logger.error("Cannot find sub-request: ", nsex);
0725: request.setErrorStatus(PDU.genErr);
0726: }
0727: }
0728:
0729: public void processPdu(Request request, MOServer server) {
0730: OctetString context = request.getContext();
0731: try {
0732: while (request.getPhase() < Request.PHASE_2PC_CLEANUP) {
0733: int phase = request.nextPhase();
0734: switch (phase) {
0735: case Request.PHASE_2PC_PREPARE: {
0736: prepare(context, request, server);
0737: break;
0738: }
0739: case Request.PHASE_2PC_COMMIT: {
0740: commit(context, request, server);
0741: break;
0742: }
0743: case Request.PHASE_2PC_UNDO: {
0744: undo(context, request, server);
0745: break;
0746: }
0747: case Request.PHASE_2PC_CLEANUP: {
0748: cleanup(context, request, server);
0749: return;
0750: }
0751: }
0752: if (!request.isPhaseComplete()) {
0753: // request needs to be reprocessed later!
0754: return;
0755: }
0756: }
0757: } catch (Exception ex) {
0758: if (logger.isDebugEnabled()) {
0759: ex.printStackTrace();
0760: }
0761: logger
0762: .error(
0763: "Failed to process SET request, trying to clean it up...",
0764: ex);
0765: if (SNMP4JSettings.isFowardRuntimeExceptions()) {
0766: throw new RuntimeException(ex);
0767: }
0768: }
0769: cleanup(context, request, server);
0770: }
0771:
0772: protected void undo(OctetString context, Request request,
0773: MOServer server) {
0774: try {
0775: SubRequestIterator it = (SubRequestIterator) request
0776: .iterator();
0777: while (it.hasNext()) {
0778: SubRequest sreq = it.nextSubRequest();
0779: if (sreq.isComplete()) {
0780: continue;
0781: }
0782: OID oid = sreq.getVariableBinding().getOid();
0783: ManagedObject mo = sreq.getTargetMO();
0784: if (mo == null) {
0785: DefaultMOContextScope scope = new DefaultMOContextScope(
0786: context, oid, true, oid, true);
0787: mo = server.lookup(new DefaultMOQuery(scope,
0788: true, request));
0789: }
0790: if (mo == null) {
0791: sreq.getStatus().setErrorStatus(PDU.undoFailed);
0792: continue;
0793: }
0794: try {
0795: mo.undo(sreq);
0796: } catch (Exception moex) {
0797: if (logger.isDebugEnabled()) {
0798: moex.printStackTrace();
0799: }
0800: logger.error(moex);
0801: if (sreq.getStatus().getErrorStatus() == PDU.noError) {
0802: sreq.getStatus().setErrorStatus(
0803: PDU.undoFailed);
0804: }
0805: if (SNMP4JSettings.isFowardRuntimeExceptions()) {
0806: throw new RuntimeException(moex);
0807: }
0808: }
0809: }
0810: } catch (NoSuchElementException nsex) {
0811: if (logger.isDebugEnabled()) {
0812: nsex.printStackTrace();
0813: }
0814: logger.error("Cannot find sub-request: ", nsex);
0815: request.setErrorStatus(PDU.genErr);
0816: }
0817: }
0818:
0819: protected void commit(OctetString context, Request request,
0820: MOServer server) {
0821: try {
0822: SubRequestIterator it = (SubRequestIterator) request
0823: .iterator();
0824: while ((request.getErrorStatus() == PDU.noError)
0825: && (it.hasNext())) {
0826: SubRequest sreq = it.nextSubRequest();
0827: if (sreq.isComplete()) {
0828: continue;
0829: }
0830: OID oid = sreq.getVariableBinding().getOid();
0831: ManagedObject mo = sreq.getTargetMO();
0832: if (mo == null) {
0833: DefaultMOContextScope scope = new DefaultMOContextScope(
0834: context, oid, true, oid, true);
0835: mo = server.lookup(new DefaultMOQuery(scope,
0836: true, request));
0837: }
0838: if (mo == null) {
0839: sreq.getStatus().setErrorStatus(
0840: PDU.commitFailed);
0841: continue;
0842: }
0843: try {
0844: mo.commit(sreq);
0845: } catch (Exception moex) {
0846: if (logger.isDebugEnabled()) {
0847: moex.printStackTrace();
0848: }
0849: logger.error(moex);
0850: if (sreq.getStatus().getErrorStatus() == PDU.noError) {
0851: sreq.getStatus().setErrorStatus(
0852: PDU.commitFailed);
0853: }
0854: if (SNMP4JSettings.isFowardRuntimeExceptions()) {
0855: throw new RuntimeException(moex);
0856: }
0857: }
0858: }
0859: } catch (NoSuchElementException nsex) {
0860: if (logger.isDebugEnabled()) {
0861: nsex.printStackTrace();
0862: }
0863: logger.error("Cannot find sub-request: ", nsex);
0864: request.setErrorStatus(PDU.genErr);
0865: }
0866: }
0867:
0868: protected void cleanup(OctetString context, Request request,
0869: MOServer server) {
0870: try {
0871: SubRequestIterator it = (SubRequestIterator) request
0872: .iterator();
0873: while (it.hasNext()) {
0874: SubRequest sreq = it.nextSubRequest();
0875: if (sreq.isComplete()) {
0876: continue;
0877: }
0878: OID oid = sreq.getVariableBinding().getOid();
0879: ManagedObject mo = sreq.getTargetMO();
0880: if (mo == null) {
0881: DefaultMOContextScope scope = new DefaultMOContextScope(
0882: context, oid, true, oid, true);
0883: mo = server.lookup(new DefaultMOQuery(scope));
0884: }
0885: if (mo == null) {
0886: sreq.completed();
0887: continue;
0888: }
0889: server.unlock(sreq.getRequest(), mo);
0890: try {
0891: mo.cleanup(sreq);
0892: sreq.getStatus().setPhaseComplete(true);
0893: } catch (Exception moex) {
0894: if (logger.isDebugEnabled()) {
0895: moex.printStackTrace();
0896: }
0897: logger.error(moex);
0898: if (SNMP4JSettings.isFowardRuntimeExceptions()) {
0899: throw new RuntimeException(moex);
0900: }
0901: }
0902: }
0903: } catch (NoSuchElementException nsex) {
0904: logger.error("Cannot find sub-request: ", nsex);
0905: if (logger.isDebugEnabled()) {
0906: nsex.printStackTrace();
0907: }
0908: }
0909: }
0910:
0911: public boolean isSupported(int pduType) {
0912: return (pduType == PDU.SET);
0913: }
0914:
0915: }
0916:
0917: class GetHandler implements RequestHandler {
0918:
0919: public boolean isSupported(int pduType) {
0920: return (pduType == PDU.GET);
0921: }
0922:
0923: public void processPdu(Request request, MOServer server) {
0924: initRequestPhase(request);
0925: OctetString context = request.getContext();
0926: try {
0927: SubRequestIterator it = (SubRequestIterator) request
0928: .iterator();
0929: while (it.hasNext()) {
0930: SubRequest sreq = it.nextSubRequest();
0931: MOScope scope = sreq.getScope();
0932: MOQuery query = sreq.getQuery();
0933: if (query == null) {
0934: query = new VACMQuery(context, scope
0935: .getLowerBound(), scope
0936: .isLowerIncluded(), scope
0937: .getUpperBound(), scope
0938: .isUpperIncluded(), request
0939: .getViewName());
0940: sreq.setQuery(query);
0941: }
0942: ManagedObject mo = server.lookup(query);
0943: if (mo == null) {
0944: sreq.getVariableBinding().setVariable(
0945: Null.noSuchObject);
0946: sreq.getStatus().setPhaseComplete(true);
0947: continue;
0948: }
0949: try {
0950: mo.get(sreq);
0951: if ((request.getMessageProcessingModel() == MPv1.ID)
0952: && (sreq.getVariableBinding()
0953: .getSyntax() == SMIConstants.SYNTAX_COUNTER64)) {
0954: sreq.getVariableBinding().setVariable(
0955: Null.noSuchInstance);
0956: }
0957: } catch (Exception moex) {
0958: if (logger.isDebugEnabled()) {
0959: moex.printStackTrace();
0960: }
0961: logger.warn(moex);
0962: if (sreq.getStatus().getErrorStatus() == PDU.noError) {
0963: sreq.getStatus().setErrorStatus(PDU.genErr);
0964: }
0965: if (SNMP4JSettings.isFowardRuntimeExceptions()) {
0966: throw new RuntimeException(moex);
0967: }
0968: }
0969: }
0970: } catch (NoSuchElementException nsex) {
0971: if (logger.isDebugEnabled()) {
0972: nsex.printStackTrace();
0973: }
0974: logger.error("SubRequest not found");
0975: request.setErrorStatus(PDU.genErr);
0976: }
0977: }
0978:
0979: }
0980:
0981: class GetBulkHandler implements RequestHandler {
0982:
0983: public boolean isSupported(int pduType) {
0984: return (pduType == PDU.GETBULK);
0985: }
0986:
0987: public void processPdu(Request request, MOServer server) {
0988: initRequestPhase(request);
0989: OctetString context = request.getContext();
0990: SnmpRequest req = (SnmpRequest) request;
0991: int nonRep = req.getNonRepeaters();
0992: try {
0993: SubRequestIterator it = (SubRequestIterator) request
0994: .iterator();
0995: int i = 0;
0996: // non repeaters
0997: for (; ((i < nonRep) && it.hasNext()); i++) {
0998: SubRequest sreq = it.nextSubRequest();
0999: if (!sreq.isComplete()) {
1000: processNextSubRequest(request, server, context,
1001: sreq);
1002: }
1003: }
1004: // repetitions
1005: for (; it.hasNext(); i++) {
1006: SubRequest sreq = it.nextSubRequest();
1007: if (!sreq.isComplete()) {
1008: processNextSubRequest(request, server, context,
1009: sreq);
1010: sreq.updateNextRepetition();
1011: }
1012: }
1013: } catch (NoSuchElementException nsex) {
1014: if (logger.isDebugEnabled()) {
1015: nsex.printStackTrace();
1016: }
1017: logger.error("SubRequest not found");
1018: request.setErrorStatus(PDU.genErr);
1019: }
1020: }
1021: }
1022:
1023: class VACMQuery extends DefaultMOQuery {
1024:
1025: private OctetString viewName;
1026:
1027: /**
1028: * Creates a VACMQuery for read-only access.
1029: * @param context
1030: * the context for the query, an empty OctetString denotes the default
1031: * context.
1032: * @param lowerBound
1033: * the lower bound OID.
1034: * @param isLowerIncluded
1035: * indicates whether the lower bound should be included or not.
1036: * @param upperBound
1037: * the upper bound OID or <code>null</code> if no upper bound is
1038: * specified.
1039: * @param isUpperIncluded
1040: * indicates whether the upper bound should be included or not.
1041: * @param viewName
1042: * the view name to use for the query.
1043: * @deprecated
1044: * Use a constructor with <code>source</code> reference parameter instead.
1045: */
1046: public VACMQuery(OctetString context, OID lowerBound,
1047: boolean isLowerIncluded, OID upperBound,
1048: boolean isUpperIncluded, OctetString viewName) {
1049: super (new DefaultMOContextScope(context, lowerBound,
1050: isLowerIncluded, upperBound, isUpperIncluded));
1051: this .viewName = viewName;
1052: }
1053:
1054: /**
1055: * Creates a VACMQuery for read-only access.
1056: * @param context
1057: * the context for the query, an empty OctetString denotes the default
1058: * context.
1059: * @param lowerBound
1060: * the lower bound OID.
1061: * @param isLowerIncluded
1062: * indicates whether the lower bound should be included or not.
1063: * @param upperBound
1064: * the upper bound OID or <code>null</code> if no upper bound is
1065: * specified.
1066: * @param isUpperIncluded
1067: * indicates whether the upper bound should be included or not.
1068: * @param viewName
1069: * the view name to use for the query.
1070: * @param isWriteAccessIntended
1071: * indicates if this query is issued on behalf of a SNMP SET request
1072: * or not.
1073: * @param source
1074: * the source ({@link Request}) object on whose behalf this query is
1075: * executed.
1076: * @since 1.1
1077: */
1078: public VACMQuery(OctetString context, OID lowerBound,
1079: boolean isLowerIncluded, OID upperBound,
1080: boolean isUpperIncluded, OctetString viewName,
1081: boolean isWriteAccessIntended, Object source) {
1082: super (new DefaultMOContextScope(context, lowerBound,
1083: isLowerIncluded, upperBound, isUpperIncluded),
1084: isWriteAccessIntended, source);
1085: this .viewName = viewName;
1086: }
1087:
1088: public boolean isSearchQuery() {
1089: MOContextScope scope = getScope();
1090: return ((!scope.isLowerIncluded()) && ((scope
1091: .getUpperBound() == null) || (!scope
1092: .getUpperBound().equals(scope.getLowerBound()))));
1093: }
1094:
1095: public boolean matchesQuery(ManagedObject managedObject) {
1096: OID oid;
1097: if (isSearchQuery()) {
1098: oid = managedObject.find(getScope());
1099: if (oid == null) {
1100: return false;
1101: }
1102: } else {
1103: oid = getScope().getLowerBound();
1104: }
1105: return (vacm.isAccessAllowed(viewName, oid) == VACM.VACM_OK);
1106: }
1107:
1108: public boolean isAccessAllowed(OID oid) {
1109: return (vacm.isAccessAllowed(viewName, oid) == VACM.VACM_OK);
1110: }
1111:
1112: public String toString() {
1113: return super .toString() + "[viewName=" + viewName + "]";
1114: }
1115:
1116: }
1117:
1118: static class DefaultRequestFactory implements RequestFactory {
1119: public Request createRequest(EventObject initiatingEvent,
1120: CoexistenceInfo cinfo) {
1121: return new SnmpRequest(
1122: (CommandResponderEvent) initiatingEvent, cinfo);
1123: }
1124:
1125: }
1126:
1127: }
|