/* * RHQ Management Platform * Copyright (C) 2005-2012 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.plugins.www.snmp; import java.io.IOException; import java.net.InetAddress; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Vector; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jetbrains.annotations.NotNull; import org.snmp4j.CommunityTarget; import org.snmp4j.PDU; import org.snmp4j.Snmp; import org.snmp4j.event.ResponseEvent; import org.snmp4j.mp.SnmpConstants; import org.snmp4j.smi.Address; import org.snmp4j.smi.GenericAddress; import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; import org.snmp4j.smi.UdpAddress; import org.snmp4j.smi.VariableBinding; import org.snmp4j.transport.DefaultUdpTransportMapping; import org.snmp4j.util.DefaultPDUFactory; import org.snmp4j.util.TreeEvent; import org.snmp4j.util.TreeUtils; /** * Implements a the SNMPSession interface for SNMPv1 sessions. * * @author Ian Springer */ class SNMPSession_v1 implements SNMPSession { protected static Snmp session; protected int version; protected CommunityTarget target; private final Log log = LogFactory.getLog(this.getClass()); private static final String ANY_LOCAL_ADDRESS = "0.0.0.0"; private static final int ANY_FREE_PORT = 0; private static final int GETBULK_MAX_REPETITIONS = 10; private static final int GETBULK_NON_REPEATERS = 0; private static final String PING_OID = "1"; private static final String PING_MIB_NAME = "iso"; /** * Should only be called by SNMPClient. To get an instance of this class, use SNMPClient.startSession(). * * @see SNMPClient#startSession */ SNMPSession_v1() { this.version = SnmpConstants.version1; } /** * Initializes the SNMP session. * * @param host host name or IP address of SNMP agent * @param port TCP port of SNMP agent * @param community SNMP community of SNMP agent * @param timeout the timeout, in milliseconds, for requests * @param retries the number of times to retry requests that have timed out * * @throws SNMPException on error */ void init(String host, int port, String community, long timeout, int retries) throws SNMPException { if (session == null) { session = initSession(); } Address address = GenericAddress.parse("udp:" + host + "/" + port); this.target = new CommunityTarget(); this.target.setAddress(address); this.target.setCommunity(new OctetString(community)); this.target.setVersion(this.version); this.target.setRetries(retries); this.target.setTimeout(timeout); } public void close() { if (session != null) { try { session.close(); } catch (Exception e) { log.warn("Failed to close the SNMP session. Cause: " + e); } finally { session = null; } } } @NotNull public SNMPValue getSingleValue(String name) throws SNMPException { return getValue(name, PDU.GET); } @NotNull public SNMPValue getNextValue(String name) throws SNMPException { return getValue(name, PDU.GETNEXT); } @NotNull public List<SNMPValue> getColumn(String mibName) throws SNMPException { List<SNMPValue> values = new ArrayList<SNMPValue>(); OID oid = SNMPClient.getMibOID(mibName); TreeUtils treeUtils = new TreeUtils(session, new DefaultPDUFactory()); treeUtils.setMaxRepetitions(GETBULK_MAX_REPETITIONS); List<TreeEvent> events = treeUtils.getSubtree(this.target, oid); for (TreeEvent event : events) { if (event.isError()) { throw new SNMPException("Error occurred while retrieving column " + mibName + "(" + oid + "): " + event.getErrorMessage(), event.getException()); } VariableBinding[] varBindings = event.getVariableBindings(); if (varBindings != null) { for (VariableBinding varBinding : varBindings) { values.add(new SNMPValue(varBinding)); } } } return values; } @NotNull public Map<String, SNMPValue> getTable(String mibName, int index) throws SNMPException { Map<String, SNMPValue> map = new LinkedHashMap<String, SNMPValue>(); OID rootOid = new OID(SNMPClient.getMibOID(mibName)); // copy before modifying, since the OIDs are cached by SNMPClient rootOid.append(index); List<SNMPValue> values = getColumn(rootOid.toString()); for (SNMPValue value : values) { OID leafOid = new OID(value.getOID()); OID suffixOid = new OID(leafOid.getValue(), rootOid.size(), leafOid.size() - rootOid.size()); map.put(suffixOid.toString(), value); } return map; } @NotNull public List<SNMPValue> getBulk(String mibName) throws SNMPException { List<SNMPValue> values = new ArrayList<SNMPValue>(); PDU request = createPDU(mibName, PDU.GETBULK); request.setMaxRepetitions(GETBULK_MAX_REPETITIONS); request.setNonRepeaters(GETBULK_NON_REPEATERS); PDU response = sendRequest(request, mibName); Vector<VariableBinding> varBindings = response.getVariableBindings(); for (VariableBinding varBinding : varBindings) { values.add(new SNMPValue(varBinding)); } return values; } public boolean ping() { PDU response; try { PDU pdu = createPDU(PING_OID, PDU.GETNEXT); response = sendRequest(pdu, PING_MIB_NAME); } catch (SNMPException e) { if (e instanceof SNMPTimeoutException) { long timeoutMillis = target.getTimeout() * (target.getRetries() + 1); log.debug("Timed out after " + timeoutMillis + " while pinging " + this.version + " agent at " + this + "."); } else { log.debug("Error while pinging SNMP " + this.version + " agent at " + this + ". SNMP GETNEXT request for iso(1) failed: " + e); } return false; } boolean errorOccurred = (response.getErrorStatus() != PDU.noError); if (errorOccurred) { log.error("Error while pinging SNMP " + this.version + " agent at " + this + ". SNMP GETNEXT request for iso(1) failed: " + response.getErrorStatusText()); } return !errorOccurred; } @Override public String toString() { return target.getAddress() + "/" + this.target.getCommunity(); } protected PDU createPDU(String mibName, int type) throws MIBLookupException { PDU pdu = new DefaultPDUFactory().createPDU(this.target); pdu.setType(type); OID oid = SNMPClient.getMibOID(mibName); pdu.add(new VariableBinding(oid)); return pdu; } private Snmp initSession() throws SNMPException { try { InetAddress host = InetAddress.getByName(ANY_LOCAL_ADDRESS); int port = ANY_FREE_PORT; UdpAddress addr = new UdpAddress(host, port); session = new Snmp(new DefaultUdpTransportMapping(addr)); session.listen(); } catch (IOException e) { throw new SNMPException("Failed to initialize SNMP session.", e); } return session; } private SNMPValue getValue(String mibName, int pduType) throws SNMPException { PDU request = createPDU(mibName, pduType); PDU response = sendRequest(request, mibName); return new SNMPValue(response.get(GETBULK_NON_REPEATERS)); } @NotNull private PDU sendRequest(PDU request, String mibName) throws SNMPException { String requestType = PDU.getTypeString(request.getType()); ResponseEvent responseEvent; try { responseEvent = session.send(request, this.target); } catch (IOException e) { throw new SNMPException("Failed to send " + requestType + " request for [" + mibName + "]", e); } if (responseEvent == null) { throw new SNMPException("No response to " + requestType + " request for [" + mibName + "]."); } PDU response = responseEvent.getResponse(); if (response == null) { throw new SNMPTimeoutException(requestType + " request for [" + mibName + "] timed out."); } return response; } }