/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.protocols.snmp;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.opennms.protocols.snmp.asn1.AsnDecodingException;
import org.opennms.protocols.snmp.asn1.AsnEncoder;
/**
* <p>
* This SnmpIPAddress is used to extend the SNMP Octet String SMI class. This is
* normally used to transmit IP Addresses with a length of 4 bytes.
* </p>
*
* <p>
* Most of the management of the data is handled by the base class.
* </p>
*
* @author <a href="mailto:weave@oculan.com">Brian Weaver </a>
*
*/
public class SnmpIPAddress extends SnmpOctetString {
/**
* Required for evolving serialization format.
*/
static final long serialVersionUID = -4375760318106654741L;
/**
* Defines the ASN.1 type for this object.
*/
public static final byte ASNTYPE = SnmpSMI.SMI_APPSTRING;
/**
* Constructs a default object with a length of zero. See the super class
* constructor for more details.
*
*/
public SnmpIPAddress() {
byte[] tmp = { 0, 0, 0, 0 };
super.assumeString(tmp);
}
/**
* Constructs an Application String with the passed data. The data is
* managed by the base class.
*
* @param data
* The application string to manage (UTF-8)
*
* @throws java.security.InvalidParameterException
* Thrown if the passed buffer is not exactly 4 octets in size.
*/
public SnmpIPAddress(byte[] data) {
super(data);
if (data.length < 4)
throw new java.security.InvalidParameterException("Buffer underflow error converting IP address");
else if (data.length > 4)
throw new java.security.InvalidParameterException("Buffer overflow error converting IP address");
}
/**
* Copy constructor. Constructs a duplicate object based on the passed
* application string object.
*
* @param second
* The object to copy.
*
*/
public SnmpIPAddress(SnmpIPAddress second) {
super(second);
}
/**
* Copy constructor based on the base class.
*
* @param second
* The object to copy
*
* @throws java.security.InvalidParameterException
* Thrown if the passed buffer is not exactly 4 octets in size.
*/
public SnmpIPAddress(SnmpOctetString second) {
super(second);
if (getLength() < 4)
throw new java.security.InvalidParameterException("Buffer underflow error converting IP address");
else if (getLength() > 4)
throw new java.security.InvalidParameterException("Buffer overflow error converting IP address");
}
/**
* Constructs a new instance of the class with the IP Address recovered from
* the passed address object.
*
* @param inetAddr
* The internet address instance that contains the IP Address.
*
*/
public SnmpIPAddress(InetAddress inetAddr) {
this(inetAddr.getAddress());
}
/**
* Constructs a new instance of the class with the IP address of the
* evaluated argument. The argument is evaluated by the
* {@link java.net.InetAddress#getByName InetAddress}class and the returned
* address is encoded in this instance.
*
* @param inetAddr
* The string encoded IP Address to encapsulate.
*
* @exception SnmpBadConversionException
* Thrown if the string address cannot be converted to an IP
* Address.
*/
public SnmpIPAddress(String inetAddr) throws SnmpBadConversionException {
try {
byte[] data = InetAddress.getByName(inetAddr).getAddress();
super.assumeString(data);
} catch (UnknownHostException uhE) {
throw new SnmpBadConversionException(uhE);
}
}
/**
* Returns the ASN.1 type for this object.
*
* @return The ASN.1 value for this object.
*
*/
public byte typeId() {
return SnmpSMI.SMI_APPSTRING;
}
/**
* Create a new object that is a duplicate of the current object.
*
* @return A newly created duplicate object.
*
*/
public SnmpSyntax duplicate() {
return new SnmpIPAddress(this);
}
/**
* Create a new object that is a duplicate of the current object.
*
* @return A newly created duplicate object.
*
*/
public Object clone() {
return new SnmpIPAddress(this);
}
/**
* <p>
* Sets the internal string array so that it is identical to the passed
* array. The array is actually copied so that changes to data after the
* construction of the object are not reflected in the SnmpOctetString
* Object.
* </p>
*
* <p>
* If the buffer is not valid according to the SNMP SMI then an exception is
* thrown and the object is not modified.
* </p>
*
* @param data
* The new octet string data.
*
* @throws java.security.InvalidParameterException
* Thrown if the passed buffer is not valid against the SMI
* definition.
*/
public void setString(byte[] data) {
if (data == null || data.length < 4)
throw new java.security.InvalidParameterException("Buffer underflow error converting IP address");
else if (data.length > 4)
throw new java.security.InvalidParameterException("Buffer overflow error converting IP address");
// use setString instead of assumeString to ensure
// that a duplicate copy of the buffer is made.
//
super.setString(data);
}
/**
* <p>
* Sets the internal octet string equal to the converted stirng via the
* method getBytes(). This may cause some data corruption since the
* conversion is platform specific.
* </p>
*
* <p>
* If the buffer is not valid according to the SNMP SMI then an exception is
* thrown and the object is not modified.
* </p>
*
* @param data
* The new octet string data.
*
* @throws java.security.InvalidParameterException
* Thrown if the passed buffer is not valid against the SMI
* definition.
*
* @see java.lang.String#getBytes()
*/
public void setString(String data) {
byte[] bdata = (data == null ? null : data.getBytes());
if (bdata == null || bdata.length < 4)
throw new java.security.InvalidParameterException("Buffer underflow error converting IP address");
else if (bdata.length > 4)
throw new java.security.InvalidParameterException("Buffer overflow error converting IP address");
super.assumeString(bdata);
}
/**
* Decodes the ASN.1 octet string from the passed buffer. If an error occurs
* during the decoding sequence then an AsnDecodingException is thrown by
* the method. The value is decoded using the AsnEncoder passed to the
* object.
*
* @param buf
* The encode buffer
* @param offset
* The offset byte to begin decoding
* @param encoder
* The decoder object.
*
* @return The index of the byte immediantly after the last decoded byte of
* information.
*
* @exception AsnDecodingException
* Thrown by the encoder if an error occurs trying to decode
* the data buffer.
*/
public int decodeASN(byte[] buf, int offset, AsnEncoder encoder) throws AsnDecodingException {
Object[] rVals = encoder.parseString(buf, offset);
if (((Byte) rVals[1]).byteValue() != typeId())
throw new AsnDecodingException("Invalid ASN.1 type");
byte[] data = (byte[]) rVals[2];
if (data.length < 4)
throw new AsnDecodingException("Buffer Underflow Exception, length = " + data.length);
else if (data.length > 4)
throw new AsnDecodingException("Buffer Overflow Exception, length = " + data.length);
super.assumeString(data);
return ((Integer) rVals[0]).intValue();
}
/**
* Converts the current Application String to an IPv4Address object. If the
* length is not four bytes in length or an error occurs during the
* conversion then an exception is thrown.
*
* @return The IPv4Address converted from the appliation string
*
* @exception SnmpBadConversionException
* Thrown if the length of the string is invalid. Must be
* equal to four
*
*/
public InetAddress convertToIpAddress() {
byte[] data = getString();
byte addr[] = new byte[4];
addr[0] = data[0];
addr[1] = data[1];
addr[2] = data[2];
addr[3] = data[3];
try {
return InetAddress.getByAddress(addr);
} catch (UnknownHostException e) {
throw new RuntimeException("Unable to convert "+this+" to an InetAddress", e);
}
}
/**
* Returns the application string as a IPv4 dotted decimal address
*/
public String toString() {
byte[] data = getString();
StringBuffer buf = new StringBuffer();
buf.append((int) (data[0] < 0 ? 256 + data[0] : data[0])).append('.');
buf.append((int) (data[1] < 0 ? 256 + data[1] : data[1])).append('.');
buf.append((int) (data[2] < 0 ? 256 + data[2] : data[2])).append('.');
buf.append((int) (data[3] < 0 ? 256 + data[3] : data[3]));
return buf.toString();
}
public static InetAddress toInetAddress(SnmpIPAddress val) {
return (val == null ? null : val.convertToIpAddress());
}
}