/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004-2010], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.snmp;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.snmp4j.AbstractTarget;
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.TcpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.AbstractTransportMapping;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.DefaultPDUFactory;
import org.snmp4j.util.TreeEvent;
import org.snmp4j.util.TreeUtils;
class SNMPSession_v1 implements SNMPSession {
protected int version;
protected AbstractTarget target;
protected Snmp session;
private Address address;
private static Snmp sessionInstance = null;
protected static Log log = LogFactory.getLog("SNMPSession");
private Snmp getSessionInstance() throws IOException {
if (sessionInstance == null) {
String listen = "0.0.0.0/0";
AbstractTransportMapping transport;
if (this.address instanceof TcpAddress) {
transport = new DefaultTcpTransportMapping(new TcpAddress(listen));
} else {
transport = new DefaultUdpTransportMapping(new UdpAddress(listen));
}
sessionInstance = new Snmp(transport);
sessionInstance.listen();
}
return sessionInstance;
}
SNMPSession_v1() {
this.version = SnmpConstants.version1;
}
protected void initSession(String address, String port, String transport, String retries, String timeout) throws SNMPException {
if (address == null) {
address = SNMPClient.DEFAULT_IP;
}
if (port == null) {
port = SNMPClient.DEFAULT_PORT_STRING;
}
this.address = GenericAddress.parse(transport + ":" + address + "/" + port);
this.target.setAddress(this.address);
this.target.setVersion(this.version);
this.target.setRetries(Integer.parseInt(retries));
this.target.setTimeout(Integer.parseInt(timeout));
try {
this.session = getSessionInstance();
} catch (IOException e) {
throw new SNMPException(e.getMessage(), e);
}
}
void init(String address, String port, String community, String transport, String retries, String timeout) throws SNMPException {
CommunityTarget target = new CommunityTarget();
if (community == null) {
community = SNMPClient.DEFAULT_COMMUNITY;
}
target.setCommunity(new OctetString(community));
this.target = target;
initSession(address, port, transport, retries, timeout);
}
protected static OID getOID(String name) throws MIBLookupException {
MIBTree mibTree = MIBTree.getInstance();
int[] oid = mibTree.getOID(name);
if (oid == null) {
String msg = "Failed to lookup OID for name=" + name;
String unfound = mibTree.getLastLookupFailure();
if (!name.equals(unfound)) {
msg += " (last lookup failure=" + unfound + ")";
}
throw new MIBLookupException(msg);
}
return new OID(oid);
}
protected PDU newPDU() {
return new PDU();
}
protected PDU getPDU(String oid, int type) throws MIBLookupException {
return getPDU(getOID(oid), type);
}
protected PDU getPDU(OID oid, int type) {
PDU pdu = newPDU();
pdu.setType(type);
if (type == PDU.GETBULK) {
pdu.setMaxRepetitions(10);
pdu.setNonRepeaters(0);
}
pdu.add(new VariableBinding(oid));
return pdu;
}
private boolean walk(OID rootOID, List values) throws IOException {
int requests = 0;
int vars = 0;
boolean isError = false;
TreeUtils treeUtils = new TreeUtils(this.session, new DefaultPDUFactory());
List events = treeUtils.getSubtree(this.target, rootOID);
for (int i = 0; i < events.size(); i++) {
TreeEvent e = (TreeEvent) events.get(i);
requests++;
if (e.isError()) {
isError = true;
log.debug(rootOID + " walk: " + e.getErrorMessage(), e.getException());
}
VariableBinding[] vb = e.getVariableBindings();
if (vb != null) {
vars += vb.length;
for (int j = 0; j < vb.length; j++) {
values.add(new SNMPValue(vb[j]));
}
}
}
if (log.isDebugEnabled()) {
log.debug(rootOID + " walk: " + requests + " requests, " + vars + " vars, avg=" + vars / requests);
}
return !isError;
}
private SNMPValue getValue(String name, int type) throws SNMPException {
PDU request = getPDU(name, type);
PDU response;
ResponseEvent event = null;
try {
event = this.session.send(request, this.target);
} catch (IOException e) {
throw new SNMPException("Failed to get " + name, e);
}
if (event == null) {
throw new SNMPException("No response for " + name);
}
response = event.getResponse();
validateResponsePDU(name, response);
VariableBinding var = response.get(0);
if (var.isException()) {
throw new MIBLookupException(name + ": " + var.getVariable().toString()); // e.g.
// noSuchObject
}
return new SNMPValue(var);
}
protected void validateResponsePDU(String name, PDU response)
throws SNMPException {
if (response == null) {
throw new SNMPException("No response PDU for " + name);
}
}
public SNMPValue getSingleValue(String name) throws SNMPException {
return getValue(name, PDU.GET);
}
public SNMPValue getNextValue(String name) throws SNMPException {
return getValue(name, PDU.GETNEXT);
}
public List getColumn(String name) throws SNMPException {
List values = new ArrayList();
try {
if (!walk(getOID(name), values)) {
throw new SNMPException("No response for " + name);
}
} catch (IOException e) {
throw new SNMPException(e.getMessage(), e);
}
return values;
}
private StringBuffer getSubId(OID oid1, int oid1Len, OID oid2) {
int oid2Len = oid2.getValue().length;
StringBuffer sb = new StringBuffer();
for (int x = oid1Len; x < oid2Len; x++) {
sb.append(oid2.get(x));
if (x < oid2Len - 1) {
sb.append('.');
}
}
return sb;
}
public Map getTable(String name, int index) throws SNMPException {
OID oid = (OID) getOID(name).clone();
oid.append(index);
HashMap map = new HashMap();
List column = getColumn(name);
for (int i = 0; i < column.size(); i++) {
SNMPValue value = (SNMPValue) column.get(i);
StringBuffer sb = getSubId(oid, oid.getValue().length, value.oid);
map.put(sb.toString(), new SNMPValue(value.oid, value.var));
}
return map;
}
public SNMPValue getTableValue(String name, int index, String leaf) throws SNMPException {
OID oid = (OID) getOID(name).clone();
oid.append(index);
oid.append(leaf);
PDU request = getPDU(oid, PDU.GET);
PDU response;
ResponseEvent event = null;
try {
event = this.session.send(request, this.target);
} catch (IOException e) {
throw new SNMPException("Failed to get " + name, e);
}
if (event == null) {
throw new SNMPException("No response for " + name);
}
response = event.getResponse();
if (response == null) {
throw new SNMPException("No response for " + name);
}
return new SNMPValue(response.get(0));
}
public List getBulk(String name) throws SNMPException {
return getColumn(name);
}
}