Package com.sun.jmx.snmp.daemon

Source Code of com.sun.jmx.snmp.daemon.SnmpAdaptorServer

/*
* @(#)file      SnmpAdaptorServer.java
* @(#)author    Sun Microsystems, Inc.
* @(#)version   4.99
* @(#)date      09/10/11
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*/


package com.sun.jmx.snmp.daemon;


// java imports
//
import java.util.Vector;
import java.util.Enumeration;
import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.InterruptedIOException;


// jmx imports
//
import javax.management.MBeanServer;
import javax.management.MBeanRegistration;
import javax.management.ObjectName;
import javax.management.InstanceAlreadyExistsException;
import com.sun.jmx.snmp.SnmpIpAddress;
import com.sun.jmx.snmp.SnmpMessage;
import com.sun.jmx.snmp.SnmpOid;
import com.sun.jmx.snmp.SnmpPduFactory;
import com.sun.jmx.snmp.SnmpPduPacket;
import com.sun.jmx.snmp.SnmpPduRequest;
import com.sun.jmx.snmp.SnmpPduTrap;
import com.sun.jmx.snmp.SnmpTimeticks;
import com.sun.jmx.snmp.SnmpVarBind;
import com.sun.jmx.snmp.SnmpVarBindList;
import com.sun.jmx.snmp.SnmpDefinitions;
import com.sun.jmx.snmp.SnmpStatusException;
import com.sun.jmx.snmp.SnmpTooBigException;
import com.sun.jmx.snmp.InetAddressAcl;
import com.sun.jmx.snmp.SnmpPeer;
import com.sun.jmx.snmp.SnmpParameters;
// SNMP Runtime imports
//
import com.sun.jmx.snmp.SnmpPduFactoryBER;
import com.sun.jmx.snmp.agent.SnmpMibAgent;
import com.sun.jmx.snmp.agent.SnmpMibHandler;
import com.sun.jmx.snmp.agent.SnmpUserDataFactory;
import com.sun.jmx.snmp.agent.SnmpErrorHandlerAgent;

import com.sun.jmx.snmp.IPAcl.SnmpAcl;

import com.sun.jmx.snmp.tasks.ThreadService;

/**
* Implements an adaptor on top of the SNMP protocol.
* <P>
* When this SNMP protocol adaptor is started it creates a datagram socket
* and is able to receive requests and send traps or inform requests.
* When it is stopped, the socket is closed and neither requests
* and nor traps/inform request are processed.
* <P>
* The default port number of the socket is 161. This default value can be
* changed by specifying a port number:
* <UL>
* <LI>in the object constructor</LI>
* <LI>using the {@link com.sun.jmx.snmp.daemon.CommunicatorServer#setPort
*     setPort} method before starting the adaptor</LI>
* </UL>
* The default object name is defined by {@link
* com.sun.jmx.snmp.ServiceName#DOMAIN com.sun.jmx.snmp.ServiceName.DOMAIN}
* and {@link com.sun.jmx.snmp.ServiceName#SNMP_ADAPTOR_SERVER
* com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_SERVER}.
* <P>
* The SNMP protocol adaptor supports versions 1 and 2 of the SNMP protocol
* in a stateless way: when it receives a v1 request, it replies with a v1
* response, when it receives a v2 request it replies with a v2 response.
* <BR>The method {@link #snmpV1Trap snmpV1Trap} sends traps using SNMP v1
* format.
* The method {@link #snmpV2Trap snmpV2Trap} sends traps using SNMP v2 format.
* The method {@link #snmpInformRequest snmpInformRequest} sends inform
* requests using SNMP v2 format.
* <P>
* To receive data packets, the SNMP protocol adaptor uses a buffer
* which size can be configured using the property <CODE>bufferSize</CODE>
* (default value is 1024).
* Packets which do not fit into the buffer are rejected.
* Increasing <CODE>bufferSize</CODE> allows the exchange of bigger packets.
* However, the underlying networking system may impose a limit on the size
* of UDP packets.
* Packets which size exceed this limit will be rejected, no matter what
* the value of <CODE>bufferSize</CODE> actually is.
* <P>
* An SNMP protocol adaptor may serve several managers concurrently. The
* number of concurrent managers can be limited using the property
* <CODE>maxActiveClientCount</CODE>.
* <p>
* The SNMP protocol adaptor specifies a default value (10) for the
* <CODE>maxActiveClientCount</CODE> property. When the adaptor is stopped,
* the active requests are interrupted and an error result is sent to
* the managers.
* <p><b>This API is a Sun Microsystems internal API  and is subject
* to change without notice.</b></p>
*/

public class SnmpAdaptorServer extends CommunicatorServer
    implements SnmpAdaptorServerMBean, MBeanRegistration, SnmpDefinitions,
         SnmpMibHandler {
   
    // PRIVATE VARIABLES
    //------------------
   
    /**
     * Port number for sending SNMP traps.
     * <BR>The default value is 162.
     */
    private int                 trapPort = 162;
   
    /**
     * Port number for sending SNMP inform requests.
     * <BR>The default value is 162.
     */
    private int                 informPort = 162;
   
    /**
     * The <CODE>InetAddress</CODE> used when creating the datagram socket.
     * <BR>It is specified when creating the SNMP protocol adaptor.
     * If not specified, the local host machine is used.
     */
    InetAddress address = null;

    /**
     * The IP address based ACL used by this SNMP protocol adaptor.
     */
    private Object ipacl = null;

    /**
     * The factory object.
     */
    private SnmpPduFactory pduFactory = null;
   
    /**
     * The user-data factory object.
     */   
    private SnmpUserDataFactory userDataFactory = null;

    /**
     * Indicates if the SNMP protocol adaptor sends a response in case
     * of authentication failure
     */
    private boolean authRespEnabled = true;

    /**
     * Indicates if authentication traps are enabled.
     */
    private boolean authTrapEnabled = true;
   
    /**
     * The enterprise OID.
     * <BR>The default value is "1.3.6.1.4.1.42".
     */
    private SnmpOid enterpriseOid = new SnmpOid("1.3.6.1.4.1.42");
   
    /**
     * The buffer size of the SNMP protocol adaptor.
     * This buffer size is used for both incoming request and outgoing
     * inform requests.
     * <BR>The default value is 1024.
     */
    int bufferSize = 1024;
   
    private transient long            startUpTime     = 0;
    private transient DatagramSocket  socket          = null;
    transient DatagramSocket          trapSocket      = null;
    private transient SnmpSession     informSession   = null;
    private transient DatagramPacket  packet          = null;
    transient Vector                  mibs            = new Vector();
    private transient SnmpMibTree     root;

    /**
     * Whether ACL must be used.
     */
    private transient boolean         useAcl = true;

   
    // SENDING SNMP INFORMS STUFF
    //---------------------------
     
    /**
     * Number of times to try an inform request before giving up.
     * The default number is 3.
     */
    private int maxTries = 3 ;

    /**
     * The amount of time to wait for an inform response from the manager.
     * The default amount of time is 3000 millisec.
     */
    private int timeout = 3 * 1000 ;
       
    // VARIABLES REQUIRED FOR IMPLEMENTING SNMP GROUP (MIBII)
    //-------------------------------------------------------
   
    /**
     * The <CODE>snmpOutTraps</CODE> value defined in MIB-II.
     */
    int snmpOutTraps=0;
   
    /**
     * The <CODE>snmpOutGetResponses</CODE> value defined in MIB-II.
     */
    private int snmpOutGetResponses=0;

    /**
     * The <CODE>snmpOutGenErrs</CODE> value defined in MIB-II.
     */
    private int snmpOutGenErrs=0;

    /**
     * The <CODE>snmpOutBadValues</CODE> value defined in MIB-II.
     */
    private int snmpOutBadValues=0;

    /**
     * The <CODE>snmpOutNoSuchNames</CODE> value defined in MIB-II.
     */
    private int snmpOutNoSuchNames=0;

    /**
     * The <CODE>snmpOutTooBigs</CODE> value defined in MIB-II.
     */
    private int snmpOutTooBigs=0;

    /**
     * The <CODE>snmpOutPkts</CODE> value defined in MIB-II.
     */
    int snmpOutPkts=0;

    /**
     * The <CODE>snmpInASNParseErrs</CODE> value defined in MIB-II.
     */
    private int snmpInASNParseErrs=0;

    /**
     * The <CODE>snmpInBadCommunityUses</CODE> value defined in MIB-II.
     */
    private int snmpInBadCommunityUses=0;

    /**
     * The <CODE>snmpInBadCommunityNames</CODE> value defined in MIB-II.
     */
    private int snmpInBadCommunityNames=0;

    /**
     * The <CODE>snmpInBadVersions</CODE> value defined in MIB-II.
     */
    private int snmpInBadVersions=0;

    /**
     * The <CODE>snmpInGetRequests</CODE> value defined in MIB-II.
     */
    private int snmpInGetRequests=0;

    /**
     * The <CODE>snmpInGetNexts</CODE> value defined in MIB-II.
     */
    private int snmpInGetNexts=0;

    /**
     * The <CODE>snmpInSetRequests</CODE> value defined in MIB-II.
     */
    private int snmpInSetRequests=0;

    /**
     * The <CODE>snmpInPkts</CODE> value defined in MIB-II.
     */
    private int snmpInPkts=0;

    /**
     * The <CODE>snmpInTotalReqVars</CODE> value defined in MIB-II.
     */
    private int snmpInTotalReqVars=0;

    /**
     * The <CODE>snmpInTotalSetVars</CODE> value defined in MIB-II.
     */
    private int snmpInTotalSetVars=0;

    /**
     * The <CODE>snmpInTotalSetVars</CODE> value defined in rfc 1907 MIB-II.
     */
    private int snmpSilentDrops=0;
   
    private static final String InterruptSysCallMsg =
  "Interrupted system call";
    static final SnmpOid sysUpTimeOid = new SnmpOid("1.3.6.1.2.1.1.3.0") ;
    static final SnmpOid snmpTrapOidOid = new SnmpOid("1.3.6.1.6.3.1.1.4.1.0");
       
    private ThreadService threadService;

    private static int threadNumber = 6;

    static {
  String s = System.getProperty("com.sun.jmx.snmp.threadnumber");

  if (s != null) {
      try {
    threadNumber = Integer.parseInt(System.getProperty(s));
      } catch (Exception e) {
    // ???
    System.err.println("Got wrong value for " +
           "com.sun.jmx.snmp.threadnumber: "+s);
    System.err.println("Use the default value: "+threadNumber);
      }
  }
    }

    // PUBLIC CONSTRUCTORS
    //--------------------
   
    /**
     * Initializes this SNMP protocol adaptor using the default port (161).
     * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
     * implementation of the <CODE>InetAddressAcl</CODE> interface.
     */
    public SnmpAdaptorServer() {
        this(true, null, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
       null) ;
    }

    /**
     * Initializes this SNMP protocol adaptor using the specified port.
     * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
     * implementation of the <CODE>InetAddressAcl</CODE> interface.
     *
     * @param port The port number for sending SNMP responses.
     */
    public SnmpAdaptorServer(int port) {
        this(true, null, port, null) ;
    }

    /**
     * Initializes this SNMP protocol adaptor using the default port (161)
     * and the specified IP address based ACL implementation.
     *
     * @param acl The <CODE>InetAddressAcl</CODE> implementation.
     *        <code>null</code> means no ACL - everybody is authorized.
     *
     * @since 1.5
     */
    public SnmpAdaptorServer(InetAddressAcl acl) {
        this(false, acl, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
       null) ;
    }

    /**
     * Initializes this SNMP protocol adaptor using the default port (161)
     * and the
     * specified <CODE>InetAddress</CODE>.
     * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
     * implementation of the <CODE>InetAddressAcl</CODE> interface.
     *
     * @param addr The IP address to bind.
     */
    public SnmpAdaptorServer(InetAddress addr) {
        this(true, null, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
       addr) ;
    }
   
    /**
     * Initializes this SNMP protocol adaptor using the specified port and the
     * specified IP address based ACL implementation.
     *
     * @param acl The <CODE>InetAddressAcl</CODE> implementation.
     *        <code>null</code> means no ACL - everybody is authorized.
     * @param port The port number for sending SNMP responses.
     *
     * @since 1.5
     */
    public SnmpAdaptorServer(InetAddressAcl acl, int port) {
        this(false, acl, port, null) ;
    }

    /**
     * Initializes this SNMP protocol adaptor using the specified port and the
     * specified <CODE>InetAddress</CODE>.
     * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
     * implementation of the <CODE>InetAddressAcl</CODE> interface.
     *
     * @param port The port number for sending SNMP responses.
     * @param addr The IP address to bind.
     */
    public SnmpAdaptorServer(int port, InetAddress addr) {
        this(true, null, port, addr) ;
    }
     
    /**
     * Initializes this SNMP protocol adaptor using the specified IP
     * address based ACL implementation and the specified
     * <CODE>InetAddress</CODE>.
     *
     * @param acl The <CODE>InetAddressAcl</CODE> implementation.
     * @param addr The IP address to bind.
     *
     * @since 1.5
     */
    public SnmpAdaptorServer(InetAddressAcl acl, InetAddress addr) {
        this(false, acl, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
       addr) ;
    }

    /**
     * Initializes this SNMP protocol adaptor using the specified port, the
     * specified  address based ACL implementation and the specified
     * <CODE>InetAddress</CODE>.
     *
     * @param acl The <CODE>InetAddressAcl</CODE> implementation.
     * @param port The port number for sending SNMP responses.
     * @param addr The IP address to bind.
     *
     * @since 1.5
     */
    public SnmpAdaptorServer(InetAddressAcl acl, int port, InetAddress addr) {
        this(false, acl, port, addr);
    }

    /**
     * Initializes this SNMP protocol adaptor using the specified port and the
     * specified <CODE>InetAddress</CODE>.
     * This constructor allows to initialize an SNMP adaptor without using
     * the ACL mechanism (by setting the <CODE>useAcl</CODE> parameter to
     * false).
     * <br>This constructor must be used in particular with a platform that
     * does not support the <CODE>java.security.acl</CODE> package like pJava.
     *
     * @param useAcl Specifies if this new SNMP adaptor uses the ACL mechanism.
     * If the specified parameter is set to <CODE>true</CODE>, this
     * constructor is equivalent to
     * <CODE>SnmpAdaptorServer((int)port,(InetAddress)addr)</CODE>.
     * @param port The port number for sending SNMP responses.
     * @param addr The IP address to bind.
     */
    public SnmpAdaptorServer(boolean useAcl, int port, InetAddress addr) {
  this(useAcl,null,port,addr);
    }

    // If forceAcl is `true' and InetAddressAcl is null, then a default
    // SnmpAcl object is created.
    //
    private SnmpAdaptorServer(boolean forceAcl, InetAddressAcl acl,
            int port, InetAddress addr) {
        super(CommunicatorServer.SNMP_TYPE) ;
 
       
        // Initialize the ACL implementation.
        //
        if (acl == null && forceAcl) {
            try {
                acl = (InetAddressAcl)
        new SnmpAcl("SNMP protocol adaptor IP ACL");
            } catch (UnknownHostException e) {
                if (isDebugOn()) {
                    debug("constructor",
        "UnknowHostException when creating ACL");
                    debug("constructor", e);
                }
            }
        } else {
      this.useAcl = (acl!=null) || forceAcl;
  }

        init(acl, port, addr) ;
    }
     
    // GETTERS AND SETTERS
    //--------------------

    /**
     * Gets the number of managers that have been processed by this
     * SNMP protocol adaptor  since its creation.
     *
     * @return The number of managers handled by this SNMP protocol adaptor
     * since its creation. This counter is not reset by the <CODE>stop</CODE>
     * method.
     */
    public int getServedClientCount() {
        return super.getServedClientCount();
    }

    /**
     * Gets the number of managers currently being processed by this
     * SNMP protocol adaptor.
     *
     * @return The number of managers currently being processed by this
     * SNMP protocol adaptor.
     */
    public int getActiveClientCount() {
        return super.getActiveClientCount();
    }

    /**
     * Gets the maximum number of managers that this SNMP protocol adaptor can
     * process concurrently.
     *
     * @return The maximum number of managers that this SNMP protocol adaptor
     *         can process concurrently.
     */
    public int getMaxActiveClientCount() {
        return super.getMaxActiveClientCount();
    }

    /**
     * Sets the maximum number of managers this SNMP protocol adaptor can
     * process concurrently.
     *
     * @param c The number of managers.
     *
     * @exception java.lang.IllegalStateException This method has been invoked
     * while the communicator was <CODE>ONLINE</CODE> or <CODE>STARTING</CODE>.
     */
    public void setMaxActiveClientCount(int c)
  throws java.lang.IllegalStateException {
  super.setMaxActiveClientCount(c);
    }
   
    /**
     * Returns the Ip address based ACL used by this SNMP protocol adaptor.
     * @return The <CODE>InetAddressAcl</CODE> implementation.
     *
     * @since 1.5
     */
    public InetAddressAcl getInetAddressAcl() {
  return (InetAddressAcl)ipacl; 
    }

    /**
     * Returns the port used by this SNMP protocol adaptor for sending traps.
     * By default, port 162 is used.
     *
     * @return The port number for sending SNMP traps.
     */
    public Integer getTrapPort() {
        return new Integer(trapPort) ;
    }
 
    /**
     * Sets the port used by this SNMP protocol adaptor for sending traps.
     *
     * @param port The port number for sending SNMP traps.
     */
    public void setTrapPort(Integer port) {
        setTrapPort(port.intValue());
    }
 
    /**
     * Sets the port used by this SNMP protocol adaptor for sending traps.
     *
     * @param port The port number for sending SNMP traps.
     */
    public void setTrapPort(int port) {
        int val= port ;
        if (val < 0) throw new
            IllegalArgumentException("Trap port cannot be a negative value");
        trapPort= val ;
    }
 
    /**
     * Returns the port used by this SNMP protocol adaptor for sending
     * inform requests. By default, port 162 is used.
     *
     * @return The port number for sending SNMP inform requests.
     */
    public int getInformPort() {
        return informPort;
    }
 
    /**
     * Sets the port used by this SNMP protocol adaptor for sending
     * inform requests.
     *
     * @param port The port number for sending SNMP inform requests.
     */
    public void setInformPort(int port) {
        if (port < 0)
            throw new IllegalArgumentException("Inform request port "+
                 "cannot be a negative value");
        informPort= port ;
    }
   
    /**
     * Returns the protocol of this SNMP protocol adaptor.
     *
     * @return The string "snmp".
     */
    public String getProtocol() {
        return "snmp";
    }
 
    /**
     * Returns the buffer size of this SNMP protocol adaptor.
     * This buffer size is used for both incoming request and outgoing
     * inform requests.
     * By default, buffer size 1024 is used.
     *
     * @return The buffer size.
     */
    public Integer getBufferSize() {
        return new Integer(bufferSize) ;
    }

    /**
     * Sets the buffer size of this SNMP protocol adaptor.
     * This buffer size is used for both incoming request and outgoing
     * inform requests.
     *
     * @param s The buffer size.
     *
     * @exception java.lang.IllegalStateException This method has been invoked
     * while the communicator was <CODE>ONLINE</CODE> or <CODE>STARTING</CODE>.
     */
    public void setBufferSize(Integer s)
  throws java.lang.IllegalStateException {
        if ((state == ONLINE) || (state == STARTING)) {
            throw new IllegalStateException("Stop server before carrying out"+
              " this operation");
        }
        bufferSize = s.intValue() ;
    }
 
    /**
     * Gets the number of times to try sending an inform request before
     * giving up.
     * By default, a maximum of 3 tries is used.
     * @return The maximun number of tries.
     */
    final public int getMaxTries() {
        return maxTries;
    }
   
    /**
     * Changes the maximun number of times to try sending an inform
     * request before giving up.
     * @param newMaxTries The maximun number of tries.
     */
    final public synchronized void setMaxTries(int newMaxTries) {
        if (newMaxTries < 0)
            throw new IllegalArgumentException();
        maxTries = newMaxTries;
    }
   
    /**
     * Gets the timeout to wait for an inform response from the manager.
     * By default, a timeout of 3 seconds is used.
     * @return The value of the timeout property.
     */
    final public int getTimeout() {
        return timeout;
    }
   
    /**
     * Changes the timeout to wait for an inform response from the manager.
     * @param newTimeout The timeout (in milliseconds).
     */
    final public synchronized void setTimeout(int newTimeout) {
        if (newTimeout < 0)
            throw new IllegalArgumentException();
        timeout= newTimeout;
    }
   
    /**
     * Returns the message factory of this SNMP protocol adaptor.
     *
     * @return The factory object.
     */
    public SnmpPduFactory getPduFactory() {
        return pduFactory ;
    }
   
    /**
     * Sets the message factory of this SNMP protocol adaptor.
     *
     * @param factory The factory object (null means the default factory).
     */
    public void setPduFactory(SnmpPduFactory factory) {
        if (factory == null)
            pduFactory = new SnmpPduFactoryBER() ;
        else
            pduFactory = factory ;
    }
 
    /**
     * Set the user-data factory of this SNMP protocol adaptor.
     *
     * @param factory The factory object (null means no factory).
     * @see com.sun.jmx.snmp.agent.SnmpUserDataFactory
     */
    public void setUserDataFactory(SnmpUserDataFactory factory) {
  userDataFactory = factory ;
    }
 
    /**
     * Get the user-data factory associated with this SNMP protocol adaptor.
     *
     * @return The factory object (null means no factory).
     * @see com.sun.jmx.snmp.agent.SnmpUserDataFactory
     */
    public SnmpUserDataFactory getUserDataFactory() {
  return userDataFactory;
    }
 
    /**
     * Returns <CODE>true</CODE> if authentication traps are enabled.
     * <P>
     * When this feature is enabled, the SNMP protocol adaptor sends
     * an <CODE>authenticationFailure</CODE> trap each time an
     * authentication fails.
     * <P>
     * The default behaviour is to send authentication traps.
     *
     * @return <CODE>true</CODE> if authentication traps are enabled,
     *         <CODE>false</CODE> otherwise.
     */
    public boolean getAuthTrapEnabled() {
        return authTrapEnabled ;
    }
 
    /**
     * Sets the flag indicating if traps need to be sent in case of
     * authentication failure.
     *
     * @param enabled Flag indicating if traps need to be sent.
     */
    public void setAuthTrapEnabled(boolean enabled) {
        authTrapEnabled = enabled ;
    }

    /**
     * Returns <code>true</code> if this SNMP protocol adaptor sends a
     * response in case of authentication failure.
     * <P>
     * When this feature is enabled, the SNMP protocol adaptor sends a
     * response with <CODE>noSuchName</CODE> or <CODE>readOnly</CODE> when
     * the authentication failed. If the flag is disabled, the
     * SNMP protocol adaptor trashes the PDU silently.
     * <P>
     * The default behavior is to send responses.
     *
     * @return <CODE>true</CODE> if responses are sent.
     */
    public boolean getAuthRespEnabled() {
        return authRespEnabled ;
    }

    /**
     * Sets the flag indicating if responses need to be sent in case of
     * authentication failure.
     *
     * @param enabled Flag indicating if responses need to be sent.
     */
    public void setAuthRespEnabled(boolean enabled) {
        authRespEnabled = enabled ;
    }
   
    /**
     * Returns the enterprise OID. It is used by
     * {@link #snmpV1Trap snmpV1Trap} to fill the 'enterprise' field of the
     * trap request.
     *
     * @return The OID in string format "x.x.x.x".
     */
    public String getEnterpriseOid() {
        return enterpriseOid.toString() ;
    }

    /**
     * Sets the enterprise OID.
     *
     * @param oid The OID in string format "x.x.x.x".
     *
     * @exception IllegalArgumentException The string format is incorrect
     */
    public void setEnterpriseOid(String oid) throws IllegalArgumentException {
        enterpriseOid = new SnmpOid(oid) ;
    }
   
    /**
     * Returns the names of the MIBs available in this SNMP protocol adaptor.
     *
     * @return An array of MIB names.
     */
    public String[] getMibs() {
        String[] result = new String[mibs.size()] ;
        int i = 0 ;
        for (Enumeration e = mibs.elements() ; e.hasMoreElements() ;) {
            SnmpMibAgent mib = (SnmpMibAgent)e.nextElement() ;
            result[i++] = mib.getMibName();
        }
        return result ;
    }
   
    // GETTERS FOR SNMP GROUP (MIBII)
    //-------------------------------
   
    /**
     * Returns the <CODE>snmpOutTraps</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpOutTraps</CODE> value.
     */
    public Long getSnmpOutTraps() {
        return new Long(snmpOutTraps);
    }
 
    /**
     * Returns the <CODE>snmpOutGetResponses</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpOutGetResponses</CODE> value.
     */
    public Long getSnmpOutGetResponses() {
        return new Long(snmpOutGetResponses);
    }
 
    /**
     * Returns the <CODE>snmpOutGenErrs</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpOutGenErrs</CODE> value.
     */
    public Long getSnmpOutGenErrs() {
        return new Long(snmpOutGenErrs);
    }
 
    /**
     * Returns the <CODE>snmpOutBadValues</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpOutBadValues</CODE> value.
     */
    public Long getSnmpOutBadValues() {
        return new Long(snmpOutBadValues);
    }
 
    /**
     * Returns the <CODE>snmpOutNoSuchNames</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpOutNoSuchNames</CODE> value.
     */
    public Long getSnmpOutNoSuchNames() {
        return new Long(snmpOutNoSuchNames);
    }
 
    /**
     * Returns the <CODE>snmpOutTooBigs</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpOutTooBigs</CODE> value.
     */
    public Long getSnmpOutTooBigs() {
        return new Long(snmpOutTooBigs);
    }
 
    /**
     * Returns the <CODE>snmpInASNParseErrs</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInASNParseErrs</CODE> value.
     */
    public Long getSnmpInASNParseErrs() {
        return new Long(snmpInASNParseErrs);
    }
 
    /**
     * Returns the <CODE>snmpInBadCommunityUses</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInBadCommunityUses</CODE> value.
     */
    public Long getSnmpInBadCommunityUses() {
        return new Long(snmpInBadCommunityUses);
    }
 
    /**
     * Returns the <CODE>snmpInBadCommunityNames</CODE> value defined in
     * MIB-II.
     *
     * @return The <CODE>snmpInBadCommunityNames</CODE> value.
     */
    public Long getSnmpInBadCommunityNames() {
        return new Long(snmpInBadCommunityNames);
    }
 
    /**
     * Returns the <CODE>snmpInBadVersions</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInBadVersions</CODE> value.
     */
    public Long getSnmpInBadVersions() {
        return new Long(snmpInBadVersions);
    }
 
    /**
     * Returns the <CODE>snmpOutPkts</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpOutPkts</CODE> value.
     */
    public Long getSnmpOutPkts() {
        return new Long(snmpOutPkts);
    }
 
    /**
     * Returns the <CODE>snmpInPkts</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInPkts</CODE> value.
     */
    public Long getSnmpInPkts() {
        return new Long(snmpInPkts);
    }
 
    /**
     * Returns the <CODE>snmpInGetRequests</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInGetRequests</CODE> value.
     */
    public Long getSnmpInGetRequests() {
        return new Long(snmpInGetRequests);
    }
 
    /**
     * Returns the <CODE>snmpInGetNexts</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInGetNexts</CODE> value.
     */
    public Long getSnmpInGetNexts() {
        return new Long(snmpInGetNexts);
    }
 
    /**
     * Returns the <CODE>snmpInSetRequests</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInSetRequests</CODE> value.
     */
    public Long getSnmpInSetRequests() {
        return new Long(snmpInSetRequests);
    }
 
    /**
     * Returns the <CODE>snmpInTotalSetVars</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInTotalSetVars</CODE> value.
     */
    public Long getSnmpInTotalSetVars() {
        return new Long(snmpInTotalSetVars);
    }
 
    /**
     * Returns the <CODE>snmpInTotalReqVars</CODE> value defined in MIB-II.
     *
     * @return The <CODE>snmpInTotalReqVars</CODE> value.
     */
    public Long getSnmpInTotalReqVars() {
        return new Long(snmpInTotalReqVars);
    }
   
    /**
     * Returns the <CODE>snmpSilentDrops</CODE> value defined in RFC
     * 1907 NMPv2-MIB .
     *
     * @return The <CODE>snmpSilentDrops</CODE> value.
     *
     * @since 1.5
     */
    public Long getSnmpSilentDrops() {
        return new Long(snmpSilentDrops);
    }

    /**
     * Returns the <CODE>snmpProxyDrops</CODE> value defined in RFC
     * 1907 NMPv2-MIB .
     *
     * @return The <CODE>snmpProxyDrops</CODE> value.
     *
     * @since 1.5
     */
    public Long getSnmpProxyDrops() {
        return new Long(0);
    }
   
   
    // PUBLIC METHODS
    //---------------
    /**
     * Allows the MBean to perform any operations it needs before being
     * registered in the MBean server.
     * If the name of the SNMP protocol adaptor MBean is not specified,
     * it is initialized with the default value:
     * {@link com.sun.jmx.snmp.ServiceName#DOMAIN
     *   com.sun.jmx.snmp.ServiceName.DOMAIN}:{@link
     * com.sun.jmx.snmp.ServiceName#SNMP_ADAPTOR_SERVER
     * com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_SERVER}.
     * If any exception is raised, the SNMP protocol adaptor MBean will
     * not be registered in the MBean server.
     *
     * @param server The MBean server to register the service with.
     * @param name The object name.
     *
     * @return The name of the SNMP protocol adaptor registered.
     *
     * @exception java.lang.Exception
     */
    public ObjectName preRegister(MBeanServer server, ObjectName name)
  throws java.lang.Exception {

        if (name == null) {
            name = new ObjectName(server.getDefaultDomain() + ":" +
           com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_SERVER);
        }
        return (super.preRegister(server, name));
    }
           
    /**
     * Not used in this context.
     */
    public void postRegister (Boolean registrationDone) {
        super.postRegister(registrationDone);
    }

    /**
     * Not used in this context.
     */
    public void preDeregister() throws java.lang.Exception {
        super.preDeregister();
    }

    /**
     * Not used in this context.
     */
    public void postDeregister() {
        super.postDeregister();
    }

    /**
     * Adds a new MIB in the SNMP MIB handler.
     *
     * @param mib The MIB to add.
     *
     * @return A reference to the SNMP MIB handler.
     *
     * @exception IllegalArgumentException If the parameter is null.
     */
    public SnmpMibHandler addMib(SnmpMibAgent mib)
  throws IllegalArgumentException {
        if (mib == null) {
            throw new IllegalArgumentException() ;
        }
 
  if(!mibs.contains(mib))
      mibs.addElement(mib);

        root.register(mib);
   
        return this;
    }
   
    /**
     * Adds a new MIB in the SNMP MIB handler.
     * This method is to be called to set a specific agent to a specific OID.
     * This can be useful when dealing with MIB overlapping.
     * Some OID can be implemented in more than one MIB. In this case,
     * the OID nearer agent will be used on SNMP operations.
     *
     * @param mib The MIB to add.
     * @param oids The set of OIDs this agent implements.
     *
     * @return A reference to the SNMP MIB handler.
     *
     * @exception IllegalArgumentException If the parameter is null.
     *
     * @since 1.5
     */
    public SnmpMibHandler addMib(SnmpMibAgent mib, SnmpOid[] oids)
  throws IllegalArgumentException {
  if (mib == null) {
      throw new IllegalArgumentException() ;
  }
 
  //If null oid array, just add it to the mib.
  if(oids == null)
      return addMib(mib);
 
  if(!mibs.contains(mib))
      mibs.addElement(mib);
 
  for (int i = 0; i < oids.length; i++) {
      root.register(mib, oids[i].longValue());
  }
  return this;
    }

    /**
     * Adds a new MIB in the SNMP MIB handler. In SNMP V1 and V2 the
     * <CODE>contextName</CODE> is useless and this method
     * is equivalent to <CODE>addMib(SnmpMibAgent mib)</CODE>.
     *
     * @param mib The MIB to add.
     * @param contextName The MIB context name.
     * @return A reference on the SNMP MIB handler.
     *
     * @exception IllegalArgumentException If the parameter is null.
     *
     * @since 1.5
     */
    public SnmpMibHandler addMib(SnmpMibAgent mib, String contextName)
  throws IllegalArgumentException {
  return addMib(mib);
    }
   
    /**
     * Adds a new MIB in the SNMP MIB handler. In SNMP V1 and V2 the
     * <CODE>contextName</CODE> is useless and this method
     * is equivalent to <CODE>addMib(SnmpMibAgent mib, SnmpOid[] oids)</CODE>.
     *
     * @param mib The MIB to add.
     * @param contextName The MIB context. If null is passed, will be
     *        registered in the default context.
     * @param oids The set of OIDs this agent implements.
     *
     * @return A reference to the SNMP MIB handler.
     *
     * @exception IllegalArgumentException If the parameter is null.
     *
     * @since 1.5
     */
    public SnmpMibHandler addMib(SnmpMibAgent mib,
         String contextName,
         SnmpOid[] oids)
        throws IllegalArgumentException {
  return addMib(mib, oids);
    }
   
    /**
     * Removes the specified MIB from the SNMP protocol adaptor.
     * In SNMP V1 and V2 the <CODE>contextName</CODE> is useless and this
     * method is equivalent to <CODE>removeMib(SnmpMibAgent mib)</CODE>.
     *
     * @param mib The MIB to be removed.
     * @param contextName The context name used at registration time.
     *
     * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was
     * a MIB included in the SNMP MIB handler, <CODE>false</CODE>
     * otherwise.
     *
     * @since 1.5
     */
    public boolean removeMib(SnmpMibAgent mib, String contextName) {
  return removeMib(mib);
    }

    /**
     * Removes the specified MIB from the SNMP protocol adaptor.
     *
     * @param mib The MIB to be removed.
     *
     * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was a MIB
     *         included in the SNMP MIB handler, <CODE>false</CODE> otherwise.
     */
    public boolean removeMib(SnmpMibAgent mib) {
        root.unregister(mib);
        return (mibs.removeElement(mib)) ;
    }

    /**
     * Removes the specified MIB from the SNMP protocol adaptor.
     *
     * @param mib The MIB to be removed.
     * @param oids The oid the MIB was previously registered for.
     * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was
     * a MIB included in the SNMP MIB handler, <CODE>false</CODE>
     * otherwise.
     *
     * @since 1.5
     */
    public boolean removeMib(SnmpMibAgent mib, SnmpOid[] oids) {
  root.unregister(mib, oids);
  return (mibs.removeElement(mib)) ;
    }

     /**
     * Removes the specified MIB from the SNMP protocol adaptor.
     *
     * @param mib The MIB to be removed.
     * @param contextName The context name used at registration time.
     * @param oids The oid the MIB was previously registered for.
     * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was
     * a MIB included in the SNMP MIB handler, <CODE>false</CODE>
     * otherwise.
     *
     * @since 1.5
     */
    public boolean removeMib(SnmpMibAgent mib,
           String contextName,
           SnmpOid[] oids) {
  return removeMib(mib, oids);
    }

    // SUBCLASSING OF COMMUNICATOR SERVER
    //-----------------------------------
   
    /**
     * Creates the datagram socket.
     */
    protected void doBind()
  throws CommunicationException, InterruptedException {

        try {
      synchronized (this) {
    socket = new DatagramSocket(port, address) ;
      }
      dbgTag = makeDebugTag();
        } catch (SocketException e) {
            if (e.getMessage().equals(InterruptSysCallMsg))
                throw new InterruptedException(e.toString()) ;
            else {
                if (isDebugOn()) {
                    debug("doBind", "cannot bind on port " + port);
                }
                throw new CommunicationException(e) ;
            }
        }
    }

    /**
     * Return the actual port to which the adaptor is bound.
     * Can be different from the port given at construction time if
     * that port number was 0.
     * @return the actual port to which the adaptor is bound.
     **/
    public int getPort() {
  synchronized (this) {
      if (socket != null) return socket.getLocalPort();
  }
  return super.getPort();
    }

    /**
     * Closes the datagram socket.
     */
    protected void doUnbind()
  throws CommunicationException, InterruptedException {
        if (isTraceOn()) {
            trace("doUnbind","Finally close the socket");
        }
  synchronized (this) {
      if (socket != null) {
    socket.close() ;
    socket = null ;
    // Important to inform finalize() that the socket is closed...
      }
  }
        closeTrapSocketIfNeeded() ;
        closeInformSocketIfNeeded() ;
    }
   
    void createSnmpRequestHandler(SnmpAdaptorServer server, int id,
          DatagramSocket s, DatagramPacket p,
          SnmpMibTree tree, Vector m, Object a,
          SnmpPduFactory factory,
          SnmpUserDataFactory dataFactory,
          MBeanServer f, ObjectName n) {
  final SnmpRequestHandler handler =
      new SnmpRequestHandler(this, id, s, p, tree, m, a, factory,
           dataFactory, f, n);
  threadService.submitTask(handler);
    }

    /**
     * Reads a packet from the datagram socket and creates a request
     * handler which decodes and processes the request.
     */
    protected void doReceive()
  throws CommunicationException, InterruptedException {

        // Let's wait for something to be received.
        //
        try {
            packet = new DatagramPacket(new byte[bufferSize], bufferSize) ;
            socket.receive(packet);
      int state = getState();
     
      if(state != ONLINE) {
    if (isTraceOn()) {
        trace("doReceive",
           "received a message but state not online, returning.");
    }
    return;
      }
     
      createSnmpRequestHandler(this, servedClientCount, socket,
             packet, root, mibs, ipacl, pduFactory,
             userDataFactory, topMBS, objectName);
        } catch (SocketException e) {
            // Let's check if we have been interrupted by stop().
            //
            if (e.getMessage().equals(InterruptSysCallMsg))
                throw new InterruptedException(e.toString()) ;
            else
                throw new CommunicationException(e) ;
        } catch (InterruptedIOException e) {
            throw new InterruptedException(e.toString()) ;
        } catch (CommunicationException e) {
            throw e ;
        } catch (Exception e) {
            throw new CommunicationException(e) ;
        }
        if (isTraceOn()) {
            trace("doReceive", "received a message");
        }
    }
 
    protected void doError(Exception e) throws CommunicationException {
        return;
    }
   
    /**
     * Not used in this context.
     */
    protected void doProcess()
  throws CommunicationException, InterruptedException {
    }
   

    /**
     * The number of times the communicator server will attempt
     * to bind before giving up.
     * We attempt only once...
     * @return 1
     **/
    protected int getBindTries() {
  return 1;
    }

    /**
     * Stops this SNMP protocol adaptor.
     * Closes the datagram socket.
     * <p>
     * Has no effect if this SNMP protocol adaptor is <CODE>OFFLINE</CODE> or
     * <CODE>STOPPING</CODE>.
     */
    public void stop(){
       
  final int port = getPort();
        if (isTraceOn()) {
            trace("stop", "Stopping: using port " + port);
        }
        if ((state == ONLINE) || (state == STARTING)){
            super.stop();
            try {
    DatagramSocket sn = new DatagramSocket(0);
    try {
        byte[] ob = new byte[1];
       
        DatagramPacket pk;
        if (address != null)
      pk = new DatagramPacket(ob , 1, address, port);
        else
      pk = new DatagramPacket(ob , 1,
         java.net.InetAddress.getLocalHost(), port);
                               
        if (isTraceOn()) {
      trace("stop", "Sending: using port " + port);
        }
        sn.send(pk);
    } finally {
        sn.close();
    }
            } catch (Throwable e){
                if (isDebugOn()) {
                    debug("stop", e);
                }
            }
        }
    }
   
    // SENDING SNMP TRAPS STUFF
    //-------------------------
   
    /**
     * Sends a trap using SNMP V1 trap format.
     * <BR>The trap is sent to each destination defined in the ACL file
     * (if available).
     * If no ACL file or no destinations are available, the trap is sent
     * to the local host.
     *
     * @param generic The generic number of the trap.
     * @param specific The specific number of the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit defined
     *            by <CODE>bufferSize</CODE>.
     */
    public void snmpV1Trap(int generic, int specific,
         SnmpVarBindList varBindList)
        throws IOException, SnmpStatusException {

        if (isTraceOn()) {
            trace("snmpV1Trap", "generic=" + generic +
      ", specific=" + specific);
        }
       
        // First, make an SNMP V1 trap pdu
        //
        SnmpPduTrap pdu = new SnmpPduTrap() ;
        pdu.address = null ;
        pdu.port = trapPort ;
        pdu.type = pduV1TrapPdu ;
        pdu.version = snmpVersionOne ;
        pdu.community = null ;
        pdu.enterprise = enterpriseOid ;
        pdu.genericTrap = generic ;
        pdu.specificTrap = specific ;
        pdu.timeStamp = getSysUpTime();
   
        if (varBindList != null) {
            pdu.varBindList = new SnmpVarBind[varBindList.size()] ;
            varBindList.copyInto(pdu.varBindList);
        }
        else
            pdu.varBindList = null ;
     
        // If the local host cannot be determined, we put 0.0.0.0 in agentAddr
        try {
            if (address != null)
                pdu.agentAddr = handleMultipleIpVersion(address.getAddress());
            else pdu.agentAddr =
              handleMultipleIpVersion(InetAddress.getLocalHost().getAddress());
        } catch (UnknownHostException e) {
      byte[] zeroedAddr = new byte[4];
            pdu.agentAddr = handleMultipleIpVersion(zeroedAddr) ;
        }
   
        // Next, send the pdu to all destinations defined in ACL
        //
        sendTrapPdu(pdu) ;
    }
   
    private SnmpIpAddress handleMultipleIpVersion(byte[] address) {
  if(address.length == 4)
    return new SnmpIpAddress(address);
  else {
      if(isDebugOn())
    debug("handleMultipleIPVersion",
          "Not an IPv4 address, return null");
      return null;
  }
    }

    /**
     * Sends a trap using SNMP V1 trap format.
     * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
     * destination using the specified community string (and the ACL file
     * is not used).
     *
     * @param addr The <CODE>InetAddress</CODE> destination of the trap.
     * @param cs The community string to be used for the trap.
     * @param generic The generic number of the trap.
     * @param specific The specific number of the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit defined
     *            by <CODE>bufferSize</CODE>.
     */
    public void snmpV1Trap(InetAddress addr, String cs, int generic,
         int specific, SnmpVarBindList varBindList)
        throws IOException, SnmpStatusException {
 
        if (isTraceOn()) {
            trace("snmpV1Trap", "generic=" + generic + ", specific=" +
      specific);
        }
       
        // First, make an SNMP V1 trap pdu
        //
        SnmpPduTrap pdu = new SnmpPduTrap() ;
        pdu.address = null ;
        pdu.port = trapPort ;
        pdu.type = pduV1TrapPdu ;
        pdu.version = snmpVersionOne ;
 
  if(cs != null)
      pdu.community = cs.getBytes();
  else
      pdu.community = null ;
 
        pdu.enterprise = enterpriseOid ;
        pdu.genericTrap = generic ;
        pdu.specificTrap = specific ;
        pdu.timeStamp = getSysUpTime();
   
        if (varBindList != null) {
            pdu.varBindList = new SnmpVarBind[varBindList.size()] ;
            varBindList.copyInto(pdu.varBindList);
        }
        else
            pdu.varBindList = null ;
     
        // If the local host cannot be determined, we put 0.0.0.0 in agentAddr
        try {
            if (address != null)
                pdu.agentAddr = handleMultipleIpVersion(address.getAddress());
            else pdu.agentAddr =
        handleMultipleIpVersion(InetAddress.getLocalHost().getAddress());
        } catch (UnknownHostException e) {
      byte[] zeroedAddr = new byte[4];
            pdu.agentAddr = handleMultipleIpVersion(zeroedAddr) ;
        }
 
        // Next, send the pdu to the specified destination
        //
  if(addr != null)
      sendTrapPdu(addr, pdu) ;
  else
      sendTrapPdu(pdu);
    }
   
    /**
     * Sends a trap using SNMP V1 trap format.
     * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
     * destination using the specified parameters (and the ACL file is not
     * used).
     * Note that if the specified <CODE>InetAddress</CODE> destination is null,
     * then the ACL file mechanism is used.
     *
     * @param addr The <CODE>InetAddress</CODE> destination of the trap.
     * @param agentAddr The agent address to be used for the trap.
     * @param cs The community string to be used for the trap.
     * @param enterpOid The enterprise OID to be used for the trap.
     * @param generic The generic number of the trap.
     * @param specific The specific number of the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     * @param time The time stamp (overwrite the current time).
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit defined
     *            by <CODE>bufferSize</CODE>.
     *
     * @since 1.5
     */
    public void snmpV1Trap(InetAddress addr,
                           SnmpIpAddress agentAddr,
                           String cs,
                           SnmpOid enterpOid,
                           int generic,
                           int specific,
                           SnmpVarBindList varBindList,
                           SnmpTimeticks time)
        throws IOException, SnmpStatusException {
  snmpV1Trap(addr,
       trapPort,
       agentAddr,
       cs,
       enterpOid,
       generic,
       specific,
       varBindList,
       time);
    }

    /**
     * Sends a trap using SNMP V1 trap format.
     * <BR>The trap is sent to the specified <CODE>SnmpPeer</CODE> destination.
     * The community string used is the one located in the
     * <CODE>SnmpPeer</CODE> parameters
     * (<CODE>SnmpParameters.getRdCommunity() </CODE>).
     *
     * @param peer The <CODE>SnmpPeer</CODE> destination of the trap.
     * @param agentAddr The agent address to be used for the trap.
     * @param enterpOid The enterprise OID to be used for the trap.
     * @param generic The generic number of the trap.
     * @param specific The specific number of the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     * @param time The time stamp (overwrite the current time).
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit
     * defined by <CODE>bufferSize</CODE>.
     *
     * @since 1.5
     */
    public void snmpV1Trap(SnmpPeer peer,
         SnmpIpAddress agentAddr,
         SnmpOid enterpOid,
         int generic,
         int specific,
         SnmpVarBindList varBindList,
         SnmpTimeticks time)
  throws IOException, SnmpStatusException {
  SnmpParameters p = (SnmpParameters) peer.getParams();
  snmpV1Trap(peer.getDestAddr(),
       peer.getDestPort(),
       agentAddr,
       p.getRdCommunity(),
       enterpOid,
       generic,
       specific,
       varBindList,
       time);
    }
   
    private void snmpV1Trap(InetAddress addr,
          int port,
          SnmpIpAddress agentAddr,
          String cs,
          SnmpOid enterpOid,
          int generic,
          int specific,
          SnmpVarBindList varBindList,
          SnmpTimeticks time)
  throws IOException, SnmpStatusException {
 
  if (isTraceOn()) {
            trace("snmpV1Trap", "generic=" + generic + ", specific=" +
      specific);
        }
       
        // First, make an SNMP V1 trap pdu
        //
        SnmpPduTrap pdu = new SnmpPduTrap() ;
        pdu.address = null ;
        pdu.port = port ;
        pdu.type = pduV1TrapPdu ;
        pdu.version = snmpVersionOne ;
 
        //Diff start
        if(cs != null)
            pdu.community = cs.getBytes();
        else
            pdu.community = null ;
        //Diff end

        // Diff start
        if(enterpOid != null)
            pdu.enterprise = enterpOid;
        else
            pdu.enterprise = enterpriseOid ;
        //Diff end
        pdu.genericTrap = generic ;
        pdu.specificTrap = specific ;
        //Diff start
        if(time != null)
            pdu.timeStamp = time.longValue();
        else
            pdu.timeStamp = getSysUpTime();
        //Diff end
   
        if (varBindList != null) {
            pdu.varBindList = new SnmpVarBind[varBindList.size()] ;
            varBindList.copyInto(pdu.varBindList);
        }
        else
            pdu.varBindList = null ;
     
        if (agentAddr == null) {
            // If the local host cannot be determined,
            // we put 0.0.0.0 in agentAddr
            try {
    final InetAddress inetAddr =
        (address!=null)?address:InetAddress.getLocalHost();
    agentAddr = handleMultipleIpVersion(inetAddr.getAddress());
            catch (UnknownHostException e) {
    byte[] zeroedAddr = new byte[4];
    agentAddr = handleMultipleIpVersion(zeroedAddr);
            }
        }

  pdu.agentAddr = agentAddr;
 
        // Next, send the pdu to the specified destination
        //
        // Diff start
        if(addr != null)
            sendTrapPdu(addr, pdu) ;
        else
            sendTrapPdu(pdu);

        //End diff
    }
         
    /**
     * Sends a trap using SNMP V2 trap format.
     * <BR>The trap is sent to the specified <CODE>SnmpPeer</CODE> destination.
     * <BR>The community string used is the one located in the
     * <CODE>SnmpPeer</CODE> parameters
     * (<CODE>SnmpParameters.getRdCommunity() </CODE>).
     * <BR>The variable list included in the outgoing trap is composed of
     * the following items:
     * <UL>
     * <LI><CODE>sysUpTime.0</CODE> with the value specified by
     *     <CODE>time</CODE></LI>
     * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
     *     <CODE>trapOid</CODE></LI>
     * <LI><CODE>all the (oid,values)</CODE> from the specified
     *     <CODE>varBindList</CODE></LI>
     * </UL>
     *
     * @param peer The <CODE>SnmpPeer</CODE> destination of the trap.
     * @param trapOid The OID identifying the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     * @param time The time stamp (overwrite the current time).
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit
     * defined by <CODE>bufferSize</CODE>.
     *
     * @since 1.5
     */
    public void snmpV2Trap(SnmpPeer peer,
         SnmpOid trapOid,
         SnmpVarBindList varBindList,
         SnmpTimeticks time)
  throws IOException, SnmpStatusException {
  SnmpParameters p = (SnmpParameters) peer.getParams();
  snmpV2Trap(peer.getDestAddr(),
       peer.getDestPort(),
       p.getRdCommunity(),
       trapOid,
       varBindList,
       time);
    }

    /**
     * Sends a trap using SNMP V2 trap format.
     * <BR>The trap is sent to each destination defined in the ACL file
     * (if available). If no ACL file or no destinations are available,
     * the trap is sent to the local host.
     * <BR>The variable list included in the outgoing trap is composed of
     * the following items:
     * <UL>
     * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
     * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
     *     <CODE>trapOid</CODE></LI>
     * <LI><CODE>all the (oid,values)</CODE> from the specified
     *     <CODE>varBindList</CODE></LI>
     * </UL>
     *
     * @param trapOid The OID identifying the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit defined
     *            by <CODE>bufferSize</CODE>.
     */
    public void snmpV2Trap(SnmpOid trapOid, SnmpVarBindList varBindList)
        throws IOException, SnmpStatusException {

        if (isTraceOn()) {
            trace("snmpV2Trap", "trapOid=" + trapOid);
        }
       
        // First, make an SNMP V2 trap pdu
        // We clone varBindList and insert sysUpTime and snmpTrapOid
        //
        SnmpPduRequest pdu = new SnmpPduRequest() ;
        pdu.address = null ;
        pdu.port = trapPort ;
        pdu.type = pduV2TrapPdu ;
        pdu.version = snmpVersionTwo ;
        pdu.community = null ;

        SnmpVarBindList fullVbl ;   
        if (varBindList != null)
            fullVbl = (SnmpVarBindList)varBindList.clone() ;
        else
            fullVbl = new SnmpVarBindList(2) ;
        SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
        fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
        fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
        0);
        pdu.varBindList = new SnmpVarBind[fullVbl.size()] ;
        fullVbl.copyInto(pdu.varBindList) ;
     
        // Next, send the pdu to all destinations defined in ACL
        //
        sendTrapPdu(pdu) ;
    }

    /**
     * Sends a trap using SNMP V2 trap format.
     * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
     * destination using the specified community string (and the ACL file
     * is not used).
     * <BR>The variable list included in the outgoing trap is composed of
     * the following items:
     * <UL>
     * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
     * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
     *     <CODE>trapOid</CODE></LI>
     * <LI><CODE>all the (oid,values)</CODE> from the specified
     *     <CODE>varBindList</CODE></LI>
     * </UL>
     *
     * @param addr The <CODE>InetAddress</CODE> destination of the trap.
     * @param cs The community string to be used for the trap.
     * @param trapOid The OID identifying the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit
     *            defined by <CODE>bufferSize</CODE>.
     */
    public void snmpV2Trap(InetAddress addr, String cs, SnmpOid trapOid,
         SnmpVarBindList varBindList)
        throws IOException, SnmpStatusException {
 
        if (isTraceOn()) {
            trace("snmpV2Trap", "trapOid=" + trapOid);
        }
       
        // First, make an SNMP V2 trap pdu
        // We clone varBindList and insert sysUpTime and snmpTrapOid
        //
        SnmpPduRequest pdu = new SnmpPduRequest() ;
        pdu.address = null ;
        pdu.port = trapPort ;
        pdu.type = pduV2TrapPdu ;
        pdu.version = snmpVersionTwo ;

  if(cs != null)
            pdu.community = cs.getBytes();
        else
            pdu.community = null;
 
        SnmpVarBindList fullVbl ;   
        if (varBindList != null)
            fullVbl = (SnmpVarBindList)varBindList.clone() ;
        else
            fullVbl = new SnmpVarBindList(2) ;
        SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
        fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
        fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
        0);
        pdu.varBindList = new SnmpVarBind[fullVbl.size()] ;
        fullVbl.copyInto(pdu.varBindList) ;
     
        // Next, send the pdu to the specified destination
        //
  if(addr != null)
      sendTrapPdu(addr, pdu);
  else
      sendTrapPdu(pdu);
    }
   
    /**
     * Sends a trap using SNMP V2 trap format.
     * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
     * destination using the specified parameters (and the ACL file is not
     * used).
     * Note that if the specified <CODE>InetAddress</CODE> destination is null,
     * then the ACL file mechanism is used.
     * <BR>The variable list included in the outgoing trap is composed of the
     * following items:
     * <UL>
     * <LI><CODE>sysUpTime.0</CODE> with the value specified by
     *     <CODE>time</CODE></LI>
     * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
     *     <CODE>trapOid</CODE></LI>
     * <LI><CODE>all the (oid,values)</CODE> from the specified
     *     <CODE>varBindList</CODE></LI>
     * </UL>
     *
     * @param addr The <CODE>InetAddress</CODE> destination of the trap.
     * @param cs The community string to be used for the trap.
     * @param trapOid The OID identifying the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     * @param time The time stamp (overwrite the current time).
     *
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit
     * defined by <CODE>bufferSize</CODE>.
     *
     * @since 1.5
     */
    public void snmpV2Trap(InetAddress addr,
                           String cs,
                           SnmpOid trapOid,
                           SnmpVarBindList varBindList,
                           SnmpTimeticks time)
        throws IOException, SnmpStatusException {
     
  snmpV2Trap(addr,
       trapPort,
       cs,
       trapOid,
       varBindList,
       time);
    }
   
    private void snmpV2Trap(InetAddress addr,
          int port,
          String cs,
          SnmpOid trapOid,
          SnmpVarBindList varBindList,
          SnmpTimeticks time)
        throws IOException, SnmpStatusException {
 
        if (isTraceOn()) {
            trace("snmpV2Trap", "trapOid=" + trapOid +
                  "\ncommunity=" + cs + "\naddr=" + addr +
                  "\nvarBindList=" + varBindList + "\ntime=" + time +
                  "\ntrapPort=" + port);
        }
       
        // First, make an SNMP V2 trap pdu
        // We clone varBindList and insert sysUpTime and snmpTrapOid
        //
        SnmpPduRequest pdu = new SnmpPduRequest() ;
        pdu.address = null ;
        pdu.port = port ;
        pdu.type = pduV2TrapPdu ;
        pdu.version = snmpVersionTwo ;
 
  if(cs != null)
            pdu.community = cs.getBytes();
        else
            pdu.community = null;

        SnmpVarBindList fullVbl ;   
        if (varBindList != null)
            fullVbl = (SnmpVarBindList)varBindList.clone() ;
        else
            fullVbl = new SnmpVarBindList(2) ;

        // Only difference with other
        SnmpTimeticks sysUpTimeValue = null;
        if(time != null)
            sysUpTimeValue = time;
        else
            sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
        //End of diff

        fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
        fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
        0);
        pdu.varBindList = new SnmpVarBind[fullVbl.size()] ;
        fullVbl.copyInto(pdu.varBindList) ;
     
        // Next, send the pdu to the specified destination
        //
        // Diff start
        if(addr != null)
            sendTrapPdu(addr, pdu) ;
        else
            sendTrapPdu(pdu);
        //End diff
    }

    /**
     * Send the specified trap PDU to the passed <CODE>InetAddress</CODE>.
     * @param address The destination address.
     * @param pdu The pdu to send.
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit
     * defined by <CODE>bufferSize</CODE>.
     *
     * @since 1.5
     */
    public void snmpPduTrap(InetAddress address, SnmpPduPacket pdu)
      throws IOException, SnmpStatusException {

        if(address != null)
            sendTrapPdu(address, pdu);
        else
            sendTrapPdu(pdu);
    }
   
    /**
     * Send the specified trap PDU to the passed <CODE>SnmpPeer</CODE>.
     * @param peer The destination peer. The Read community string is used of
     * <CODE>SnmpParameters</CODE> is used as the trap community string.
     * @param pdu The pdu to send.
     * @exception IOException An I/O error occurred while sending the trap.
     * @exception SnmpStatusException If the trap exceeds the limit defined
     * by <CODE>bufferSize</CODE>.
     * @since 1.5
     */
    public void snmpPduTrap(SnmpPeer peer,
          SnmpPduPacket pdu)
        throws IOException, SnmpStatusException {
  if(peer != null) {
      pdu.port = peer.getDestPort();
      sendTrapPdu(peer.getDestAddr(), pdu);
  }
  else {
      pdu.port = getTrapPort().intValue();
      sendTrapPdu(pdu);  
  }
    }
   
    /**
     * Send the specified trap PDU to every destinations from the ACL file.
     */
    private void sendTrapPdu(SnmpPduPacket pdu)
     throws SnmpStatusException, IOException {
 
        // Make an SNMP message from the pdu
        //
        SnmpMessage msg = null ;
        try {
            msg = (SnmpMessage)pduFactory.encodeSnmpPdu(pdu, bufferSize) ;
            if (msg == null) {
                throw new SnmpStatusException(
        SnmpDefinitions.snmpRspAuthorizationError) ;
            }
        }
        catch (SnmpTooBigException x) {
            if (isDebugOn()) {
                debug("sendTrapPdu", "trap pdu is too big");
                debug("sendTrapPdu", "trap hasn't been sent to anyone");
            }
            throw new SnmpStatusException(SnmpDefinitions.snmpRspTooBig) ;
            // FIXME: is the right exception to throw ?
            // We could simply forward SnmpTooBigException ?
        }
   
        // Now send the SNMP message to each destination
        //
        int sendingCount = 0 ;
        openTrapSocketIfNeeded() ;
        if (ipacl != null) {
            Enumeration ed = ((InetAddressAcl)ipacl).getTrapDestinations() ;
            while (ed.hasMoreElements()) {
                msg.address = (InetAddress)ed.nextElement() ;
                Enumeration ec = ((InetAddressAcl)ipacl).
        getTrapCommunities(msg.address) ;
                while (ec.hasMoreElements()) {
                    msg.community = ((String)ec.nextElement()).getBytes() ;
                    try {
                        sendTrapMessage(msg) ;
                        sendingCount++ ;
                    }
                    catch (SnmpTooBigException x) {
                        if (isDebugOn()) {
                            debug("sendTrapPdu", "trap pdu is too big");
                            debug("sendTrapPdu", "trap hasn't been sent to "+
          msg.address);
                        }
                    }
                }
            }
        }
   
        // If there is no destination defined or if everything has failed
        // we tried to send the trap to the local host (as suggested by
        // mister Olivier Reisacher).
        //
        if (sendingCount == 0) {
            try {
                msg.address = InetAddress.getLocalHost() ;
                sendTrapMessage(msg) ;
            } catch (SnmpTooBigException x) {
                if (isDebugOn()) {
                    debug("sendTrapPdu", "trap pdu is too big");
                    debug("sendTrapPdu", "trap hasn't been sent");
                }
            } catch (UnknownHostException e) {
                if (isDebugOn()) {
                    debug("sendTrapPdu", "cannot get the local host");
                    debug("sendTrapPdu", "trap hasn't been sent");
                }
            }
        }
   
        closeTrapSocketIfNeeded() ;
    }

    /**
     * Send the specified trap PDU to the specified destination.
     */
    private void sendTrapPdu(InetAddress addr, SnmpPduPacket pdu)
  throws SnmpStatusException, IOException {
 
        // Make an SNMP message from the pdu
        //
        SnmpMessage msg = null ;
        try {
            msg = (SnmpMessage)pduFactory.encodeSnmpPdu(pdu, bufferSize) ;
            if (msg == null) {
                throw new SnmpStatusException(
                          SnmpDefinitions.snmpRspAuthorizationError) ;
            }
        } catch (SnmpTooBigException x) {
            if (isDebugOn()) {
                debug("sendTrapPdu", "trap pdu is too big");
                debug("sendTrapPdu",
          "trap hasn't been sent to the specified host");
            }
            throw new SnmpStatusException(SnmpDefinitions.snmpRspTooBig) ;
            // FIXME: is the right exception to throw ?
            // We could simply forward SnmpTooBigException ?
        }
   
        // Now send the SNMP message to specified destination
        //
        openTrapSocketIfNeeded() ;
        if (addr != null) {
            msg.address = addr;
            try {
                sendTrapMessage(msg) ;
            } catch (SnmpTooBigException x) {
                if (isDebugOn()) {
                    debug("sendTrapPdu", "trap pdu is too big");
                    debug("sendTrapPdu", "trap hasn't been sent to " +
        msg.address);
                }
            }
        }
   
        closeTrapSocketIfNeeded() ;
    }
   
    /**
     * Send the specified message on trapSocket.
     */
    private void sendTrapMessage(SnmpMessage msg)
  throws IOException, SnmpTooBigException {
        byte[] buffer = new byte[bufferSize] ;
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length) ;
        int encodingLength = msg.encodeMessage(buffer) ;
        packet.setLength(encodingLength) ;
        packet.setAddress(msg.address) ;
        packet.setPort(msg.port) ;
        if (isTraceOn()) {
            trace("sendTrapMessage", "sending trap to " + msg.address + ":" +
      msg.port);
        }
        trapSocket.send(packet) ;
        if (isTraceOn()) {
            trace("sendTrapMessage", "sent to " + msg.address + ":" +
      msg.port);
        }
        snmpOutTraps++;
        snmpOutPkts++;
    }
 
    /**
     * Open trapSocket if it's not already done.
     */
    synchronized void openTrapSocketIfNeeded() throws SocketException {
        if (trapSocket == null) {
            trapSocket = new DatagramSocket(0, address) ;
            if (isTraceOn()) {
                trace("openTrapSocketIfNeeded", "using port " +
          trapSocket.getLocalPort() + " to send traps");
            }
        }
    }

    /**
     * Close trapSocket if the SNMP protocol adaptor is not ONLINE.
     */
    synchronized void closeTrapSocketIfNeeded() {
        if ((trapSocket != null) && (state != ONLINE)) {
            trapSocket.close() ;
            trapSocket = null ;
        }
    }
   
    // SENDING SNMP INFORMS STUFF
    //---------------------------
   
    /**
     * Sends an inform using SNMP V2 inform request format.
     * <BR>The inform request is sent to each destination defined in the ACL
     * file (if available).
     * If no ACL file or no destinations are available, the inform request is
     * sent to the local host.
     * <BR>The variable list included in the outgoing inform is composed of
     * the following items:
     * <UL>
     * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
     * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
     *     <CODE>trapOid</CODE></LI>
     * <LI><CODE>all the (oid,values)</CODE> from the specified
     *     <CODE>varBindList</CODE></LI>
     * </UL>
     * To send an inform request, the SNMP adaptor server must be active.
     *
     * @param cb The callback that is invoked when a request is complete.
     * @param trapOid The OID identifying the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     *
     * @return A vector of {@link com.sun.jmx.snmp.daemon.SnmpInformRequest}
     *         objects.
     *         <P>If there is no destination host for this inform request,
     *         the returned vector will be empty.
     *
     * @exception IllegalStateException  This method has been invoked while
     *            the SNMP adaptor server was not active.
     * @exception IOException An I/O error occurred while sending the
     *            inform request.
     * @exception SnmpStatusException If the inform request exceeds the
     *            limit defined by <CODE>bufferSize</CODE>.
     */
    public Vector snmpInformRequest(SnmpInformHandler cb, SnmpOid trapOid,
            SnmpVarBindList varBindList)
        throws IllegalStateException, IOException, SnmpStatusException {
 
        if (!isActive()) {
            throw new IllegalStateException(
               "Start SNMP adaptor server before carrying out this operation");
        }
        if (isTraceOn()) {
            trace("snmpInformRequest", "trapOid=" + trapOid);
        }
       
        // First, make an SNMP inform pdu:
        // We clone varBindList and insert sysUpTime and snmpTrapOid variables.
        //
        SnmpVarBindList fullVbl ;   
        if (varBindList != null)
            fullVbl = (SnmpVarBindList)varBindList.clone() ;
        else
            fullVbl = new SnmpVarBindList(2) ;
        SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
        fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
        fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
        0);
       
        // Next, send the pdu to the specified destination
        //
        openInformSocketIfNeeded() ;
       
        // Now send the SNMP message to each destination
        //
        Vector informReqList = new Vector();
        InetAddress addr = null;
        String cs = null;
        if (ipacl != null) {
            Enumeration ed = ((InetAddressAcl)ipacl).getInformDestinations() ;
            while (ed.hasMoreElements()) {
                addr = (InetAddress)ed.nextElement() ;
                Enumeration ec = ((InetAddressAcl)ipacl).
        getInformCommunities(addr) ;
                while (ec.hasMoreElements()) {
                    cs = (String)ec.nextElement() ;
                    informReqList.addElement(
           informSession.makeAsyncRequest(addr, cs, cb,
                fullVbl,getInformPort())) ;
                }
            }
        }
 
        return informReqList ;
    }
   
    /**
     * Sends an inform using SNMP V2 inform request format.
     * <BR>The inform is sent to the specified <CODE>InetAddress</CODE>
     * destination
     * using the specified community string.
     * <BR>The variable list included in the outgoing inform is composed
     *     of the following items:
     * <UL>
     * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
     * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
     *      <CODE>trapOid</CODE></LI>
     * <LI><CODE>all the (oid,values)</CODE> from the specified
     *     <CODE>varBindList</CODE></LI>
     * </UL>
     * To send an inform request, the SNMP adaptor server must be active.
     *
     * @param addr The <CODE>InetAddress</CODE> destination for this inform
     *             request.
     * @param cs The community string to be used for the inform request.
     * @param cb The callback that is invoked when a request is complete.
     * @param trapOid The OID identifying the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     *
     * @return The inform request object.
     *
     * @exception IllegalStateException  This method has been invoked
     *            while the SNMP adaptor server was not active.
     * @exception IOException An I/O error occurred while sending the
     *            inform request.
     * @exception SnmpStatusException If the inform request exceeds the
     *            limit defined by <CODE>bufferSize</CODE>.
     */
    public SnmpInformRequest snmpInformRequest(InetAddress addr,
                 String cs,
                 SnmpInformHandler cb,
                                               SnmpOid trapOid,
                 SnmpVarBindList varBindList)
        throws IllegalStateException, IOException, SnmpStatusException {
 
  return snmpInformRequest(addr,
         getInformPort(),
         cs,
         cb,
         trapOid,
         varBindList);
    }
   
    /**
     * Sends an inform using SNMP V2 inform request format.
     * <BR>The inform is sent to the specified <CODE>SnmpPeer</CODE>
     *     destination.
     * <BR>The community string used is the one located in the
     *     <CODE>SnmpPeer</CODE> parameters
     *     (<CODE>SnmpParameters.getInformCommunity() </CODE>).
     * <BR>The variable list included in the outgoing inform is composed
     *     of the following items:
     * <UL>
     * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
     * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
     *     <CODE>trapOid</CODE></LI>
     * <LI><CODE>all the (oid,values)</CODE> from the specified
     *     <CODE>varBindList</CODE></LI>
     * </UL>
     * To send an inform request, the SNMP adaptor server must be active.
     *
     * @param peer The <CODE>SnmpPeer</CODE> destination for this inform
     *             request.
     * @param cb The callback that is invoked when a request is complete.
     * @param trapOid The OID identifying the trap.
     * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
     *
     * @return The inform request object.
     *
     * @exception IllegalStateException  This method has been invoked while
     *            the SNMP adaptor server was not active.
     * @exception IOException An I/O error occurred while sending the
     *            inform request.
     * @exception SnmpStatusException If the inform request exceeds the
     *            limit defined by <CODE>bufferSize</CODE>.
     *
     * @since 1.5
     */
    public SnmpInformRequest snmpInformRequest(SnmpPeer peer,
                 SnmpInformHandler cb,
                 SnmpOid trapOid,
                 SnmpVarBindList varBindList)
  throws IllegalStateException, IOException, SnmpStatusException {
  SnmpParameters p = (SnmpParameters) peer.getParams();
  return snmpInformRequest(peer.getDestAddr(),
         peer.getDestPort(),
         p.getInformCommunity(),
         cb,
         trapOid,
         varBindList);
    }
   
    /**
     * Method that maps an SNMP error status in the passed protocolVersion
     * according to the provided pdu type.
     * @param errorStatus The error status to convert.
     * @param protocolVersion The protocol version.
     * @param reqPduType The pdu type.
     */
    public static final int mapErrorStatus(int errorStatus,
             int protocolVersion,
             int reqPduType) {
  return SnmpSubRequestHandler.mapErrorStatus(errorStatus,
                protocolVersion,
                reqPduType);
    }
   
    private SnmpInformRequest snmpInformRequest(InetAddress addr,
            int port,
            String cs,
            SnmpInformHandler cb,
            SnmpOid trapOid,
            SnmpVarBindList varBindList)
        throws IllegalStateException, IOException, SnmpStatusException {
  if (!isActive()) {
            throw new IllegalStateException(
        "Start SNMP adaptor server before carrying out this operation");
        }
        if (isTraceOn()) {
            trace("snmpInformRequest", "trapOid=" + trapOid);
        }
       
        // First, make an SNMP inform pdu:
        // We clone varBindList and insert sysUpTime and snmpTrapOid variables.
        //
        SnmpVarBindList fullVbl ;   
        if (varBindList != null)
            fullVbl = (SnmpVarBindList)varBindList.clone() ;
        else
            fullVbl = new SnmpVarBindList(2) ;
        SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
        fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
        fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
        0);
               
        // Next, send the pdu to the specified destination
        //
        openInformSocketIfNeeded() ;
        return informSession.makeAsyncRequest(addr, cs, cb, fullVbl, port) ;
    }

   
    /**
     * Open informSocket if it's not already done.
     */
    synchronized void openInformSocketIfNeeded() throws SocketException {
        if (informSession == null) {
            informSession = new SnmpSession(this) ;
            if (isTraceOn()) {
                trace("openInformSocketIfNeeded",
          "to send inform requests and receive inform responses");
            }
        }
    }

    /**
     * Close informSocket if the SNMP protocol adaptor is not ONLINE.
     */
    synchronized void closeInformSocketIfNeeded() {
        if ((informSession != null) && (state != ONLINE)) {
            informSession.destroySession() ;
            informSession = null ;
        }
    }
   
    /**
     * Gets the IP address to bind.
     * This getter is used to initialize the DatagramSocket in the
     * SnmpSocket object created for the inform request stuff.
     */
    InetAddress getAddress() {
        return address;
    }
   
   
    // PROTECTED METHODS
    //------------------
   
    /**
     * Finalizer of the SNMP protocol adaptor objects.
     * This method is called by the garbage collector on an object
     * when garbage collection determines that there are no more
     * references to the object.
     * <P>Closes the datagram socket associated to this SNMP protocol adaptor.
     */
    protected void finalize() {
  try {
      if (socket != null) {
    socket.close() ;
    socket = null ;
      }

      threadService.terminate();
  } catch (Exception e) {
      trace("finalize","Exception in finalizer: " +e);
  }
    }
   
    // PACKAGE METHODS
    //----------------
   
    /**
     * Returns the string used in debug traces.
     */
    String makeDebugTag() {
        return "SnmpAdaptorServer["+ getProtocol() + ":" + getPort() + "]";   
    }
   
    void updateRequestCounters(int pduType) {
        switch(pduType)  {
           
        case pduGetRequestPdu:
            snmpInGetRequests++;
            break;
        case pduGetNextRequestPdu:
            snmpInGetNexts++;
            break;
        case pduSetRequestPdu:
            snmpInSetRequests++;
            break;
        default:
            break;
        }
        snmpInPkts++ ;
    }
 
    void updateErrorCounters(int errorStatus) {
        switch(errorStatus) {
           
        case snmpRspNoError:
            snmpOutGetResponses++;
            break;
        case snmpRspGenErr:
            snmpOutGenErrs++;
            break;
        case snmpRspBadValue:
            snmpOutBadValues++;
            break;
        case snmpRspNoSuchName:
            snmpOutNoSuchNames++;
            break;
        case snmpRspTooBig:
            snmpOutTooBigs++;
            break;
        default:
            break;
        }
        snmpOutPkts++ ;
    }
 
    void updateVarCounters(int pduType, int n) {
        switch(pduType) {
           
        case pduGetRequestPdu:
        case pduGetNextRequestPdu:
        case pduGetBulkRequestPdu:
            snmpInTotalReqVars += n ;
            break ;
        case pduSetRequestPdu:
            snmpInTotalSetVars += n ;
            break ;
        }
    }
 
    void incSnmpInASNParseErrs(int n) {
        snmpInASNParseErrs += n ;
    }
 
    void incSnmpInBadVersions(int n) {
        snmpInBadVersions += n ;
    }
 
    void incSnmpInBadCommunityUses(int n) {
        snmpInBadCommunityUses += n ;
    }
 
    void incSnmpInBadCommunityNames(int n) {
        snmpInBadCommunityNames += n ;
    }
   
    void incSnmpSilentDrops(int n) {
        snmpSilentDrops += n ;
    }
    // PRIVATE METHODS
    //----------------
 
    /**
     * Returns the time (in hundreths of second) elapsed since the SNMP
     * protocol adaptor startup.
     */
    long getSysUpTime() {
        return (System.currentTimeMillis() - startUpTime) / 10 ;
    }
 
    /**
     * Control the way the SnmpAdaptorServer service is deserialized.
     */
    private void readObject(ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
     
        // Call the default deserialization of the object.
        //
        stream.defaultReadObject();
     
        // Call the specific initialization for the SnmpAdaptorServer service.
        // This is for transient structures to be initialized to specific
  // default values.
        //
        mibs      = new Vector() ;
    }
 
    /**
     * Common initializations.
     */
    private void init(Object acl, int p, InetAddress a) {
 
        root= new SnmpMibTree();

  // The default Agent is initialized with a SnmpErrorHandlerAgent agent.
  root.setDefaultAgent(new SnmpErrorHandlerAgent());

        // For the trap time, use the time the agent started ...
        //
        startUpTime= java.lang.System.currentTimeMillis();
        maxActiveClientCount = 10;
   
        // Create the default message factory
        pduFactory = new SnmpPduFactoryBER() ;

        port = p ;
        ipacl = acl ;
        address = a ;
   
        if ((ipacl == null) && (useAcl == true))
            throw new IllegalArgumentException("ACL object cannot be null") ;

  threadService = new ThreadService(threadNumber);
    }

    SnmpMibAgent getAgentMib(SnmpOid oid) {
  return root.getAgentMib(oid);
    }

    protected Thread createMainThread() {
  final Thread t = super.createMainThread();
  t.setDaemon(true);
  return t;
    }

}
TOP

Related Classes of com.sun.jmx.snmp.daemon.SnmpAdaptorServer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.