Java SNMP Package Introduction

This provides an introduction to the Java SNMP package , an open-source implementation of the SNMP protocol in a Java package. It provides support for basic SNMP client operations as defined in SNMP versions 1 and 2 (excluding the security model proposed as part of SNMP version 2, which was never widely accept or deployed). The package provides a mechanism for "getting and setting" SNMP object identifier (OID) values through a simple communication interface, and represents SNMP structures and datatypes as corresponding Java objects. The package assumes familiarity with the SNMP protocol as detailed in RFC's 1157, 1155, 1212, etc.; however, some simple examples are provided which illustrate its use for simple get/set operations (though a knowledge of the concepts of OIDs and SNMP datatypes is still required).

The complete API documentation for the package is provided through JavaDoc documentation . This introduction is intended to provide an overview of the package, with particular focus on the classes an end user will need to directly interface with to incorporate the package into a project.
 

Main Interface: the SNMPv1CommunicationInterface Class


Much of the top-level user functionality is provided by the class SNMPv1CommunicationInterface. This constructor for this class opens a datagram socket to a specified host for SNMP communication on the standard port (192). Several methods of the class then provide a means to retrieve and set the value of SNMP variables on the remote device by supplying a string specifying an object identifier and an appropriate SNMP object for set operations. The example program listed below (Listing 1 ) illustrates the use of the communication interface class to open a connection to a remote device, get the value of two variables corresponding to OIDs 1.3.6.1.2.1.1.1.0 and 1.3.6.1.2.1.1.3.0, and set the value of a third variable. The source code for the SNMP Inquisitor ( Listing 2 , included in the package) shows the use of the package in a general-purpose utility which permits SNMP querying and modification of a remote device.

The constructor for the SNMPv1CommunicationInterface takes three parameters: an integer giving the SNMP version in use (generally always 0), the remote device address supplied as an InetAddress object, and a string giving the SNMP community to be used for the operations.
 

Getting and Setting Variable Values

Once the communication interface has been created to communicate with a device, the values of SNMP variables can be retrieved with calls to the getMIBEntry( ) method. This takes as argument a string with the variable's OID; the return value is somewhat complex, due to SNMP's ability to query multiple variables in a single message (though this particular method retrieves only one value at a time) and to support the getNextMIBEntry( ) method (describesd below). The return value is of type SNMPVarBindList, a subclass of SNMPSequence which holds a sequence of (OID, value) pairs. Thus the retrieved SNMP value is accessed as follows: The result of this (somewhat protracted) process is an SNMPObject subclass. The class of the returned value depends on the OID which was requested, and can be determined with the getClass( ) method defined in the Java Object universal base class (though generally the return class will be known in advance from knowledge of the OID being retrieved).

The internal Java value can be retrieved from the SNMPObject subclass using the getValue( ) method, which returns a subclass of java.lang.Object that is appropriate to represent the value. The Java Object subclass which stores the value internally in each SNMPObject subclass is given in Table 1 .

The process of setting the value of an SNMP variable uses the setMIBEntry( ) method of the communication interface. This takes as arguments a String specifying the OID of the variable whose value is to be set, and an appropriate SNMPObject (of appropriate subclass) with the new value. The SNMP object can be constructed using an appropriate constructor for the object type.

The code in Listing 1 illustrates the above get and set operations.

The communication interface also provides a method getNextMIBEntry( ). This is used identically to the getMIBEntry( ) method, but retrieves the OID and value of the variable numerically following the supplied OID in the device's list of variables. When this method is used, the OID will in general need to be extracted from the returned (OID, value) pair along with the value itself, to see which variable has been retrieved, since different devices will maintain different sets of variables. This can easily be obtained as the first element of the returned (OID, value) pair with the getSNMPObjectAt( ) method of the SNMPSequence class. This method is useful for performing a "treewalk" to retrieve the values of all of the variables maintained on a device, by calling the method successively using the last-retrieved OID to get the next one. The SNMP Inquisitor illustrates the use of this method in its run( ) method (Listing 2 ) used by its treewalk thread. Note that different devices seem to react differently when there are no more variables available; some will respond with an error indication, which is reported by the SNMPv1CommunicationInterface as an SNMPGetException (see below), while others just return the MIB entry corresponding to that requested rather than the (nonexistent) next one. The SNMP Inquisitor code thus tests to see if the OID received is different from that sent, and breaks if they're equal.
 
 

Exceptions

The Java SNMP package defines a number of exceptions to indicate problems with SNMP object construction, retrieval, and setting. An SNMPBadValueException is thrown if a constructor or setValue( ) method of an SNMP data object is supplied with a Java object of inappropriate type. The getMIBEntry( ) method of the communication interface class throws an SNMPGetException when an attempt to get the value of a variable receives an error message in response. The reason for the error could be that the specified variable is not supported by the device, or that the supplied community name has insufficient privileges to read the value; a message string supplied in the exception generally provides information specifying the reason. The setMIBEntry( ) similarly throws an SNMPSetException if a set operation fails. In addition, since the communication interface uses datagram sockets for communication, a number of standard exceptions may be thrown by methods (e.g., IOException, SocketException, etc.). The JavaDoc documentation details which exceptions are thrown by which methods.
 
 

SNMP Datatypes and Corresponding Java Classes

A number of classes in the Java SNMP package serve to represent the standard SNMP datatypes as Java classes, with each datatype represented by a subclass of the abstract base class SNMPObject. The data is stored internally in an appropriate standard Java object, which may be retrieved for inspection or set to a new value. For example, the SNMP Integer datatype is represented by the snmp.SNMPInteger class, which stores the value internally in a java.math.BigInteger object (a BigInteger object is used rather than a regular Integer to correctly address the fact that there is no express upper limit placed on the size of the SNMP Integer datatype). Similarly, the SNMP octet string type is represented by the snmp.SNMPOctetString class, which has an internal byte array holding the raw octet string data.

The only compound datatype in SNMP is the sequence, which holds a list of SNMP data elements (including nested sequences). THis is represented by the class snmp.SNMPSequence, which has an internal Vector to hold the list of SNMP objects.

Each concrete subclass defines public functions (declared in the abstract base class) for getting and setting the internal (Java object) value, getValue( ) and setValue( ) (the latter throws an SNMPBadValueException if the wrong object type is supplied), as well as appropriate constructors, and a toString( ) method which returns a human-readable representation of the SNMP object.

The following table lists the Java class corresponding to each standard SNMP datatype, and the class used to represent the value internally. Note that most of the Java classes use the name of the corresponding SNMP type with "SNMP" prefixed.
 

Table 1: SNMP datatypes, corresponding Java SNMP classes, and internal value representations



SNMP Datatype Java SNMP Class Java SNMP Base Class Internal value representation
Integer SNMPInteger SNMPObject BigInteger
Uinteger32 SNMPUInteger32 SNMPInteger BigInteger (but value "wraps" at 2^32)
Gauge SNMPGauge32 SNMPInteger BigInteger (but value "pegs" at 2^32 - 1)
Counter32 SNMPCounter32 SNMPInteger BigInteger (but value "wraps" at 2^32)
Counter64 SNMPCounter64 SNMPInteger BigInteger (but value "wraps" at 2^64)
TimeTicks SNMPTimeTicks SNMPInteger BigInteger
Octet string SNMPOctetString SNMPObject byte[ ]
IP address SNMPIPAddress SNMPOctetString byte[4] 
NSAP address (MAC address) SNMPNSAPAddress SNMPOctetString byte[6]
Object identifier SNMPObjectIdentifier SNMPObject long[ ] (contains the components of the dotted-integer representation of the OID)
(Note: represented as int[ ] in versions prior to 1.4)
Sequence SNMPSequence SNMPObject Vector
VarBind SNMPVariablePair SNMPSequence Vector
VarBindList SNMPVarBindList SNMPSequence Vector
Null SNMPNull SNMPObject

 


Listing 1: SNMPSample.java source code


import snmp.*;
import java.util.*;
import java.math.*;
import java.net.*;
 
 

public class SNMPSample
{

    public static void main(String args[])
    {

        try
        {

            // create a communications interface to a remote SNMP-capable device;
            // need to provide the remote host's InetAddress and the community
            // name for the device; in addition, need to  supply the version number
            // for the SNMP messages to be sent (the value 0 corresponding to SNMP
            // version 1)
            InetAddress hostAddress = InetAddress.getByName("10.0.1.1");
            String community = "public";
            int version = 0;    // SNMPv1

            SNMPv1CommunicationInterface comInterface = new SNMPv1CommunicationInterface(version, hostAddress, community);
 
 

            // now send an SNMP GET request to retrieve the value of the SNMP variable
            // corresponding to OID 1.3.6.1.2.1.1.1.0; this is the OID corresponding to
            // the device identifying string, and the type is thus SNMPOctetString
            String itemID = "1.3.6.1.2.1.1.1.0";

            System.out.println("Retrieving value corresponding to OID " + itemID);

            // the getMIBEntry method of the communications interface returns an SNMPVarBindList
            // object; this is essentially a Vector of SNMP (OID,value) pairs. In this case, the
            // returned Vector has just one pair inside it.
            SNMPVarBindList newVars = comInterface.getMIBEntry(itemID);

            // extract the (OID,value) pair from the SNMPVarBindList; the pair is just a two-element
            // SNMPSequence
            SNMPSequence pair = (SNMPSequence)(newVars.getSNMPObjectAt(0));

            // extract the object identifier from the pair; it's the first element in the sequence
            SNMPObjectIdentifier snmpOID = (SNMPObjectIdentifier)pair.getSNMPObjectAt(0);

            // extract the corresponding value from the pair; it's the second element in the sequence
            SNMPObject snmpValue = pair.getSNMPObjectAt(1);

            // print out the String representation of the retrieved value
            System.out.println("Retrieved value: type " + snmpValue.getClass().getName() + ", value " + snmpValue.toString());

            // the retrieved value can be obtained from the SNMPObject using the getValue method;
            // the return type of the method is the generic base class Object, and must be cast to
            // the appropriate actual Java type; in this case, for an SNMPOctetString, the underlying
            // Java type is a byte array[]
            byte[] javaByteArrayValue = (byte[])snmpValue.getValue();
 
 

            // now send an SNMP GET request to retrieve the value of the SNMP variable
            // corresponding to OID 1.3.6.1.2.1.1.3.0; this is the OID corresponding to
            // the uptime of the device, and the return type is thus SNMPTimeTicks
            itemID = "1.3.6.1.2.1.1.3.0";

            System.out.println("Retrieving value corresponding to OID " + itemID);

            // the getMIBEntry method of the communications interface returns an SNMPVarBindList
            // object; this is essentially a Vector of SNMP (OID,value) pairs. In this case, the
            // returned Vector has just one pair inside it.
            newVars = comInterface.getMIBEntry(itemID);

            // extract the (OID,value) pair from the SNMPVarBindList; the pair is just a two-element
            // SNMPSequence
            pair = (SNMPSequence)(newVars.getSNMPObjectAt(0));

            // extract the object identifier from the pair; it's the first element in the sequence
            snmpOID = (SNMPObjectIdentifier)pair.getSNMPObjectAt(0);

            // extract the corresponding value from the pair; it's the second element in the sequence
            snmpValue = pair.getSNMPObjectAt(1);

            // print out the String representation of the retrieved value
            System.out.println("Retrieved value: type " + snmpValue.getClass().getName() + ", value " + snmpValue.toString());

            // the retrieved value can be obtained from the SNMPObject using the getValue method;
            // the return type of the method is the generic base class Object, and must be cast to
            // the appropriate actual Java type; in this case, for SNMPTimeTicks, which is a subclass
            // of SNMPInteger, the actual type is BigInteger (which permits arbitrarily large values to
            // be represented).
            BigInteger javaIntegerValue = (BigInteger)snmpValue.getValue();
 
 

            // now send an SNMP SET request to set the value of the SNMP variable
            // corresponding to OID 1.3.6.1.2.1.1.1.0; this is the OID corresponding to
            // the device identifying string, and the type is thus SNMPOctetString;
            // to set a new value, a string is supplied
            itemID = "1.3.6.1.2.1.1.1.0";

            SNMPOctetString newValue = new SNMPOctetString("New device name");

            System.out.println("Setting value corresponding to OID " + itemID);
            System.out.println("New value: " + newValue.toString());

            // the setMIBEntry method of the communications interface returns the SNMPVarBindList
            // corresponding to the supplied OID and value
            // This call will probably cause an SNMPSetException to be thrown, since the
            // community name "public" is probably not the read/write password of the device
            newVars = comInterface.setMIBEntry(itemID, newValue);
 
 

        }
        catch(Exception e)
        {
            System.out.println("Exception during SNMP operation:  " + e + "\n");
        }

    }

}



Questions/comments: jsevy@cs.drexel.edu