1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package com.sun.jmx.snmp.daemon;
  28 
  29 
  30 // java imports
  31 //
  32 import java.util.Vector;
  33 import java.util.Enumeration;
  34 import java.util.logging.Level;
  35 import java.net.DatagramSocket;
  36 import java.net.DatagramPacket;
  37 import java.net.InetAddress;
  38 import java.net.SocketException;
  39 import java.net.UnknownHostException;
  40 import java.io.ObjectInputStream;
  41 import java.io.IOException;
  42 import java.io.InterruptedIOException;
  43 
  44 
  45 // jmx imports
  46 //
  47 import javax.management.MBeanServer;
  48 import javax.management.MBeanRegistration;
  49 import javax.management.ObjectName;
  50 import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
  51 import com.sun.jmx.snmp.SnmpIpAddress;
  52 import com.sun.jmx.snmp.SnmpMessage;
  53 import com.sun.jmx.snmp.SnmpOid;
  54 import com.sun.jmx.snmp.SnmpPduFactory;
  55 import com.sun.jmx.snmp.SnmpPduPacket;
  56 import com.sun.jmx.snmp.SnmpPduRequest;
  57 import com.sun.jmx.snmp.SnmpPduTrap;
  58 import com.sun.jmx.snmp.SnmpTimeticks;
  59 import com.sun.jmx.snmp.SnmpVarBind;
  60 import com.sun.jmx.snmp.SnmpVarBindList;
  61 import com.sun.jmx.snmp.SnmpDefinitions;
  62 import com.sun.jmx.snmp.SnmpStatusException;
  63 import com.sun.jmx.snmp.SnmpTooBigException;
  64 import com.sun.jmx.snmp.InetAddressAcl;
  65 import com.sun.jmx.snmp.SnmpPeer;
  66 import com.sun.jmx.snmp.SnmpParameters;
  67 // SNMP Runtime imports
  68 //
  69 import com.sun.jmx.snmp.SnmpPduFactoryBER;
  70 import com.sun.jmx.snmp.agent.SnmpMibAgent;
  71 import com.sun.jmx.snmp.agent.SnmpMibHandler;
  72 import com.sun.jmx.snmp.agent.SnmpUserDataFactory;
  73 import com.sun.jmx.snmp.agent.SnmpErrorHandlerAgent;
  74 
  75 import com.sun.jmx.snmp.IPAcl.SnmpAcl;
  76 
  77 import com.sun.jmx.snmp.tasks.ThreadService;
  78 
  79 /**
  80  * Implements an adaptor on top of the SNMP protocol.
  81  * <P>
  82  * When this SNMP protocol adaptor is started it creates a datagram socket
  83  * and is able to receive requests and send traps or inform requests.
  84  * When it is stopped, the socket is closed and neither requests
  85  * and nor traps/inform request are processed.
  86  * <P>
  87  * The default port number of the socket is 161. This default value can be
  88  * changed by specifying a port number:
  89  * <UL>
  90  * <LI>in the object constructor</LI>
  91  * <LI>using the {@link com.sun.jmx.snmp.daemon.CommunicatorServer#setPort
  92  *     setPort} method before starting the adaptor</LI>
  93  * </UL>
  94  * The default object name is defined by {@link
  95  * com.sun.jmx.snmp.ServiceName#DOMAIN com.sun.jmx.snmp.ServiceName.DOMAIN}
  96  * and {@link com.sun.jmx.snmp.ServiceName#SNMP_ADAPTOR_SERVER
  97  * com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_SERVER}.
  98  * <P>
  99  * The SNMP protocol adaptor supports versions 1 and 2 of the SNMP protocol
 100  * in a stateless way: when it receives a v1 request, it replies with a v1
 101  * response, when it receives a v2 request it replies with a v2 response.
 102  * <BR>The method {@link #snmpV1Trap snmpV1Trap} sends traps using SNMP v1
 103  * format.
 104  * The method {@link #snmpV2Trap snmpV2Trap} sends traps using SNMP v2 format.
 105  * The method {@link #snmpInformRequest snmpInformRequest} sends inform
 106  * requests using SNMP v2 format.
 107  * <P>
 108  * To receive data packets, the SNMP protocol adaptor uses a buffer
 109  * which size can be configured using the property <CODE>bufferSize</CODE>
 110  * (default value is 1024).
 111  * Packets which do not fit into the buffer are rejected.
 112  * Increasing <CODE>bufferSize</CODE> allows the exchange of bigger packets.
 113  * However, the underlying networking system may impose a limit on the size
 114  * of UDP packets.
 115  * Packets which size exceed this limit will be rejected, no matter what
 116  * the value of <CODE>bufferSize</CODE> actually is.
 117  * <P>
 118  * An SNMP protocol adaptor may serve several managers concurrently. The
 119  * number of concurrent managers can be limited using the property
 120  * <CODE>maxActiveClientCount</CODE>.
 121  * <p>
 122  * The SNMP protocol adaptor specifies a default value (10) for the
 123  * <CODE>maxActiveClientCount</CODE> property. When the adaptor is stopped,
 124  * the active requests are interrupted and an error result is sent to
 125  * the managers.
 126  * <p><b>This API is a Sun Microsystems internal API  and is subject
 127  * to change without notice.</b></p>
 128  */
 129 
 130 public class SnmpAdaptorServer extends CommunicatorServer
 131     implements SnmpAdaptorServerMBean, MBeanRegistration, SnmpDefinitions,
 132                SnmpMibHandler {
 133 
 134     // PRIVATE VARIABLES
 135     //------------------
 136 
 137     /**
 138      * Port number for sending SNMP traps.
 139      * <BR>The default value is 162.
 140      */
 141     private int                 trapPort = 162;
 142 
 143     /**
 144      * Port number for sending SNMP inform requests.
 145      * <BR>The default value is 162.
 146      */
 147     private int                 informPort = 162;
 148 
 149     /**
 150      * The <CODE>InetAddress</CODE> used when creating the datagram socket.
 151      * <BR>It is specified when creating the SNMP protocol adaptor.
 152      * If not specified, the local host machine is used.
 153      */
 154     InetAddress address = null;
 155 
 156     /**
 157      * The IP address based ACL used by this SNMP protocol adaptor.
 158      */
 159     private InetAddressAcl ipacl = null;
 160 
 161     /**
 162      * The factory object.
 163      */
 164     private SnmpPduFactory pduFactory = null;
 165 
 166     /**
 167      * The user-data factory object.
 168      */
 169     private SnmpUserDataFactory userDataFactory = null;
 170 
 171     /**
 172      * Indicates if the SNMP protocol adaptor sends a response in case
 173      * of authentication failure
 174      */
 175     private boolean authRespEnabled = true;
 176 
 177     /**
 178      * Indicates if authentication traps are enabled.
 179      */
 180     private boolean authTrapEnabled = true;
 181 
 182     /**
 183      * The enterprise OID.
 184      * <BR>The default value is "1.3.6.1.4.1.42".
 185      */
 186     private SnmpOid enterpriseOid = new SnmpOid("1.3.6.1.4.1.42");
 187 
 188     /**
 189      * The buffer size of the SNMP protocol adaptor.
 190      * This buffer size is used for both incoming request and outgoing
 191      * inform requests.
 192      * <BR>The default value is 1024.
 193      */
 194     int bufferSize = 1024;
 195 
 196     private transient long            startUpTime     = 0;
 197     private transient DatagramSocket  socket          = null;
 198     transient DatagramSocket          trapSocket      = null;
 199     private transient SnmpSession     informSession   = null;
 200     private transient DatagramPacket  packet          = null;
 201     transient Vector<SnmpMibAgent>    mibs            = new Vector<>();
 202     private transient SnmpMibTree     root;
 203 
 204     /**
 205      * Whether ACL must be used.
 206      */
 207     private transient boolean         useAcl = true;
 208 
 209 
 210     // SENDING SNMP INFORMS STUFF
 211     //---------------------------
 212 
 213     /**
 214      * Number of times to try an inform request before giving up.
 215      * The default number is 3.
 216      */
 217     private int maxTries = 3 ;
 218 
 219     /**
 220      * The amount of time to wait for an inform response from the manager.
 221      * The default amount of time is 3000 millisec.
 222      */
 223     private int timeout = 3 * 1000 ;
 224 
 225     // VARIABLES REQUIRED FOR IMPLEMENTING SNMP GROUP (MIBII)
 226     //-------------------------------------------------------
 227 
 228     /**
 229      * The <CODE>snmpOutTraps</CODE> value defined in MIB-II.
 230      */
 231     int snmpOutTraps=0;
 232 
 233     /**
 234      * The <CODE>snmpOutGetResponses</CODE> value defined in MIB-II.
 235      */
 236     private int snmpOutGetResponses=0;
 237 
 238     /**
 239      * The <CODE>snmpOutGenErrs</CODE> value defined in MIB-II.
 240      */
 241     private int snmpOutGenErrs=0;
 242 
 243     /**
 244      * The <CODE>snmpOutBadValues</CODE> value defined in MIB-II.
 245      */
 246     private int snmpOutBadValues=0;
 247 
 248     /**
 249      * The <CODE>snmpOutNoSuchNames</CODE> value defined in MIB-II.
 250      */
 251     private int snmpOutNoSuchNames=0;
 252 
 253     /**
 254      * The <CODE>snmpOutTooBigs</CODE> value defined in MIB-II.
 255      */
 256     private int snmpOutTooBigs=0;
 257 
 258     /**
 259      * The <CODE>snmpOutPkts</CODE> value defined in MIB-II.
 260      */
 261     int snmpOutPkts=0;
 262 
 263     /**
 264      * The <CODE>snmpInASNParseErrs</CODE> value defined in MIB-II.
 265      */
 266     private int snmpInASNParseErrs=0;
 267 
 268     /**
 269      * The <CODE>snmpInBadCommunityUses</CODE> value defined in MIB-II.
 270      */
 271     private int snmpInBadCommunityUses=0;
 272 
 273     /**
 274      * The <CODE>snmpInBadCommunityNames</CODE> value defined in MIB-II.
 275      */
 276     private int snmpInBadCommunityNames=0;
 277 
 278     /**
 279      * The <CODE>snmpInBadVersions</CODE> value defined in MIB-II.
 280      */
 281     private int snmpInBadVersions=0;
 282 
 283     /**
 284      * The <CODE>snmpInGetRequests</CODE> value defined in MIB-II.
 285      */
 286     private int snmpInGetRequests=0;
 287 
 288     /**
 289      * The <CODE>snmpInGetNexts</CODE> value defined in MIB-II.
 290      */
 291     private int snmpInGetNexts=0;
 292 
 293     /**
 294      * The <CODE>snmpInSetRequests</CODE> value defined in MIB-II.
 295      */
 296     private int snmpInSetRequests=0;
 297 
 298     /**
 299      * The <CODE>snmpInPkts</CODE> value defined in MIB-II.
 300      */
 301     private int snmpInPkts=0;
 302 
 303     /**
 304      * The <CODE>snmpInTotalReqVars</CODE> value defined in MIB-II.
 305      */
 306     private int snmpInTotalReqVars=0;
 307 
 308     /**
 309      * The <CODE>snmpInTotalSetVars</CODE> value defined in MIB-II.
 310      */
 311     private int snmpInTotalSetVars=0;
 312 
 313     /**
 314      * The <CODE>snmpInTotalSetVars</CODE> value defined in rfc 1907 MIB-II.
 315      */
 316     private int snmpSilentDrops=0;
 317 
 318     private static final String InterruptSysCallMsg =
 319         "Interrupted system call";
 320     static final SnmpOid sysUpTimeOid = new SnmpOid("1.3.6.1.2.1.1.3.0") ;
 321     static final SnmpOid snmpTrapOidOid = new SnmpOid("1.3.6.1.6.3.1.1.4.1.0");
 322 
 323     private ThreadService threadService;
 324 
 325     private static int threadNumber = 6;
 326 
 327     static {
 328         String s = System.getProperty("com.sun.jmx.snmp.threadnumber");
 329 
 330         if (s != null) {
 331             try {
 332                 threadNumber = Integer.parseInt(System.getProperty(s));
 333             } catch (Exception e) {
 334                 SNMP_ADAPTOR_LOGGER.logp(Level.FINER,
 335                         SnmpAdaptorServer.class.getName(),
 336                         "<static init>",
 337                         "Got wrong value for com.sun.jmx.snmp.threadnumber: " +
 338                         s + ". Use the default value: " + threadNumber);
 339             }
 340         }
 341     }
 342 
 343     // PUBLIC CONSTRUCTORS
 344     //--------------------
 345 
 346     /**
 347      * Initializes this SNMP protocol adaptor using the default port (161).
 348      * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
 349      * implementation of the <CODE>InetAddressAcl</CODE> interface.
 350      */
 351     public SnmpAdaptorServer() {
 352         this(true, null, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
 353              null) ;
 354     }
 355 
 356     /**
 357      * Initializes this SNMP protocol adaptor using the specified port.
 358      * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
 359      * implementation of the <CODE>InetAddressAcl</CODE> interface.
 360      *
 361      * @param port The port number for sending SNMP responses.
 362      */
 363     public SnmpAdaptorServer(int port) {
 364         this(true, null, port, null) ;
 365     }
 366 
 367     /**
 368      * Initializes this SNMP protocol adaptor using the default port (161)
 369      * and the specified IP address based ACL implementation.
 370      *
 371      * @param acl The <CODE>InetAddressAcl</CODE> implementation.
 372      *        <code>null</code> means no ACL - everybody is authorized.
 373      *
 374      * @since 1.5
 375      */
 376     public SnmpAdaptorServer(InetAddressAcl acl) {
 377         this(false, acl, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
 378              null) ;
 379     }
 380 
 381     /**
 382      * Initializes this SNMP protocol adaptor using the default port (161)
 383      * and the
 384      * specified <CODE>InetAddress</CODE>.
 385      * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
 386      * implementation of the <CODE>InetAddressAcl</CODE> interface.
 387      *
 388      * @param addr The IP address to bind.
 389      */
 390     public SnmpAdaptorServer(InetAddress addr) {
 391         this(true, null, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
 392              addr) ;
 393     }
 394 
 395     /**
 396      * Initializes this SNMP protocol adaptor using the specified port and the
 397      * specified IP address based ACL implementation.
 398      *
 399      * @param acl The <CODE>InetAddressAcl</CODE> implementation.
 400      *        <code>null</code> means no ACL - everybody is authorized.
 401      * @param port The port number for sending SNMP responses.
 402      *
 403      * @since 1.5
 404      */
 405     public SnmpAdaptorServer(InetAddressAcl acl, int port) {
 406         this(false, acl, port, null) ;
 407     }
 408 
 409     /**
 410      * Initializes this SNMP protocol adaptor using the specified port and the
 411      * specified <CODE>InetAddress</CODE>.
 412      * Use the {@link com.sun.jmx.snmp.IPAcl.SnmpAcl} default
 413      * implementation of the <CODE>InetAddressAcl</CODE> interface.
 414      *
 415      * @param port The port number for sending SNMP responses.
 416      * @param addr The IP address to bind.
 417      */
 418     public SnmpAdaptorServer(int port, InetAddress addr) {
 419         this(true, null, port, addr) ;
 420     }
 421 
 422     /**
 423      * Initializes this SNMP protocol adaptor using the specified IP
 424      * address based ACL implementation and the specified
 425      * <CODE>InetAddress</CODE>.
 426      *
 427      * @param acl The <CODE>InetAddressAcl</CODE> implementation.
 428      * @param addr The IP address to bind.
 429      *
 430      * @since 1.5
 431      */
 432     public SnmpAdaptorServer(InetAddressAcl acl, InetAddress addr) {
 433         this(false, acl, com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_PORT,
 434              addr) ;
 435     }
 436 
 437     /**
 438      * Initializes this SNMP protocol adaptor using the specified port, the
 439      * specified  address based ACL implementation and the specified
 440      * <CODE>InetAddress</CODE>.
 441      *
 442      * @param acl The <CODE>InetAddressAcl</CODE> implementation.
 443      * @param port The port number for sending SNMP responses.
 444      * @param addr The IP address to bind.
 445      *
 446      * @since 1.5
 447      */
 448     public SnmpAdaptorServer(InetAddressAcl acl, int port, InetAddress addr) {
 449         this(false, acl, port, addr);
 450     }
 451 
 452     /**
 453      * Initializes this SNMP protocol adaptor using the specified port and the
 454      * specified <CODE>InetAddress</CODE>.
 455      * This constructor allows to initialize an SNMP adaptor without using
 456      * the ACL mechanism (by setting the <CODE>useAcl</CODE> parameter to
 457      * false).
 458      * <br>This constructor must be used in particular with a platform that
 459      * does not support the <CODE>java.security.acl</CODE> package like pJava.
 460      *
 461      * @param useAcl Specifies if this new SNMP adaptor uses the ACL mechanism.
 462      * If the specified parameter is set to <CODE>true</CODE>, this
 463      * constructor is equivalent to
 464      * <CODE>SnmpAdaptorServer((int)port,(InetAddress)addr)</CODE>.
 465      * @param port The port number for sending SNMP responses.
 466      * @param addr The IP address to bind.
 467      */
 468     public SnmpAdaptorServer(boolean useAcl, int port, InetAddress addr) {
 469         this(useAcl,null,port,addr);
 470     }
 471 
 472     // If forceAcl is `true' and InetAddressAcl is null, then a default
 473     // SnmpAcl object is created.
 474     //
 475     private SnmpAdaptorServer(boolean forceAcl, InetAddressAcl acl,
 476                               int port, InetAddress addr) {
 477         super(CommunicatorServer.SNMP_TYPE) ;
 478 
 479 
 480         // Initialize the ACL implementation.
 481         //
 482         if (acl == null && forceAcl) {
 483             try {
 484                 acl = new SnmpAcl("SNMP protocol adaptor IP ACL");
 485             } catch (UnknownHostException e) {
 486                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
 487                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
 488                         "constructor", "UnknowHostException when creating ACL",e);
 489                 }
 490             }
 491         } else {
 492             this.useAcl = (acl!=null) || forceAcl;
 493         }
 494 
 495         init(acl, port, addr) ;
 496     }
 497 
 498     // GETTERS AND SETTERS
 499     //--------------------
 500 
 501     /**
 502      * Gets the number of managers that have been processed by this
 503      * SNMP protocol adaptor  since its creation.
 504      *
 505      * @return The number of managers handled by this SNMP protocol adaptor
 506      * since its creation. This counter is not reset by the <CODE>stop</CODE>
 507      * method.
 508      */
 509     @Override
 510     public int getServedClientCount() {
 511         return super.getServedClientCount();
 512     }
 513 
 514     /**
 515      * Gets the number of managers currently being processed by this
 516      * SNMP protocol adaptor.
 517      *
 518      * @return The number of managers currently being processed by this
 519      * SNMP protocol adaptor.
 520      */
 521     @Override
 522     public int getActiveClientCount() {
 523         return super.getActiveClientCount();
 524     }
 525 
 526     /**
 527      * Gets the maximum number of managers that this SNMP protocol adaptor can
 528      * process concurrently.
 529      *
 530      * @return The maximum number of managers that this SNMP protocol adaptor
 531      *         can process concurrently.
 532      */
 533     @Override
 534     public int getMaxActiveClientCount() {
 535         return super.getMaxActiveClientCount();
 536     }
 537 
 538     /**
 539      * Sets the maximum number of managers this SNMP protocol adaptor can
 540      * process concurrently.
 541      *
 542      * @param c The number of managers.
 543      *
 544      * @exception java.lang.IllegalStateException This method has been invoked
 545      * while the communicator was <CODE>ONLINE</CODE> or <CODE>STARTING</CODE>.
 546      */
 547     @Override
 548     public void setMaxActiveClientCount(int c)
 549         throws java.lang.IllegalStateException {
 550         super.setMaxActiveClientCount(c);
 551     }
 552 
 553     /**
 554      * Returns the Ip address based ACL used by this SNMP protocol adaptor.
 555      * @return The <CODE>InetAddressAcl</CODE> implementation.
 556      *
 557      * @since 1.5
 558      */
 559     @Override
 560     public InetAddressAcl getInetAddressAcl() {
 561         return ipacl;
 562     }
 563 
 564     /**
 565      * Returns the port used by this SNMP protocol adaptor for sending traps.
 566      * By default, port 162 is used.
 567      *
 568      * @return The port number for sending SNMP traps.
 569      */
 570     @Override
 571     public Integer getTrapPort() {
 572         return new Integer(trapPort) ;
 573     }
 574 
 575     /**
 576      * Sets the port used by this SNMP protocol adaptor for sending traps.
 577      *
 578      * @param port The port number for sending SNMP traps.
 579      */
 580     @Override
 581     public void setTrapPort(Integer port) {
 582         setTrapPort(port.intValue());
 583     }
 584 
 585     /**
 586      * Sets the port used by this SNMP protocol adaptor for sending traps.
 587      *
 588      * @param port The port number for sending SNMP traps.
 589      */
 590     public void setTrapPort(int port) {
 591         int val= port ;
 592         if (val < 0) throw new
 593             IllegalArgumentException("Trap port cannot be a negative value");
 594         trapPort= val ;
 595     }
 596 
 597     /**
 598      * Returns the port used by this SNMP protocol adaptor for sending
 599      * inform requests. By default, port 162 is used.
 600      *
 601      * @return The port number for sending SNMP inform requests.
 602      */
 603     @Override
 604     public int getInformPort() {
 605         return informPort;
 606     }
 607 
 608     /**
 609      * Sets the port used by this SNMP protocol adaptor for sending
 610      * inform requests.
 611      *
 612      * @param port The port number for sending SNMP inform requests.
 613      */
 614     @Override
 615     public void setInformPort(int port) {
 616         if (port < 0)
 617             throw new IllegalArgumentException("Inform request port "+
 618                                                "cannot be a negative value");
 619         informPort= port ;
 620     }
 621 
 622     /**
 623      * Returns the protocol of this SNMP protocol adaptor.
 624      *
 625      * @return The string "snmp".
 626      */
 627     @Override
 628     public String getProtocol() {
 629         return "snmp";
 630     }
 631 
 632     /**
 633      * Returns the buffer size of this SNMP protocol adaptor.
 634      * This buffer size is used for both incoming request and outgoing
 635      * inform requests.
 636      * By default, buffer size 1024 is used.
 637      *
 638      * @return The buffer size.
 639      */
 640     @Override
 641     public Integer getBufferSize() {
 642         return new Integer(bufferSize) ;
 643     }
 644 
 645     /**
 646      * Sets the buffer size of this SNMP protocol adaptor.
 647      * This buffer size is used for both incoming request and outgoing
 648      * inform requests.
 649      *
 650      * @param s The buffer size.
 651      *
 652      * @exception java.lang.IllegalStateException This method has been invoked
 653      * while the communicator was <CODE>ONLINE</CODE> or <CODE>STARTING</CODE>.
 654      */
 655     @Override
 656     public void setBufferSize(Integer s)
 657         throws java.lang.IllegalStateException {
 658         if ((state == ONLINE) || (state == STARTING)) {
 659             throw new IllegalStateException("Stop server before carrying out"+
 660                                             " this operation");
 661         }
 662         bufferSize = s.intValue() ;
 663     }
 664 
 665     /**
 666      * Gets the number of times to try sending an inform request before
 667      * giving up.
 668      * By default, a maximum of 3 tries is used.
 669      * @return The maximun number of tries.
 670      */
 671     @Override
 672     final public int getMaxTries() {
 673         return maxTries;
 674     }
 675 
 676     /**
 677      * Changes the maximun number of times to try sending an inform
 678      * request before giving up.
 679      * @param newMaxTries The maximun number of tries.
 680      */
 681     @Override
 682     final public synchronized void setMaxTries(int newMaxTries) {
 683         if (newMaxTries < 0)
 684             throw new IllegalArgumentException();
 685         maxTries = newMaxTries;
 686     }
 687 
 688     /**
 689      * Gets the timeout to wait for an inform response from the manager.
 690      * By default, a timeout of 3 seconds is used.
 691      * @return The value of the timeout property.
 692      */
 693     @Override
 694     final public int getTimeout() {
 695         return timeout;
 696     }
 697 
 698     /**
 699      * Changes the timeout to wait for an inform response from the manager.
 700      * @param newTimeout The timeout (in milliseconds).
 701      */
 702     @Override
 703     final public synchronized void setTimeout(int newTimeout) {
 704         if (newTimeout < 0)
 705             throw new IllegalArgumentException();
 706         timeout= newTimeout;
 707     }
 708 
 709     /**
 710      * Returns the message factory of this SNMP protocol adaptor.
 711      *
 712      * @return The factory object.
 713      */
 714     @Override
 715     public SnmpPduFactory getPduFactory() {
 716         return pduFactory ;
 717     }
 718 
 719     /**
 720      * Sets the message factory of this SNMP protocol adaptor.
 721      *
 722      * @param factory The factory object (null means the default factory).
 723      */
 724     @Override
 725     public void setPduFactory(SnmpPduFactory factory) {
 726         if (factory == null)
 727             pduFactory = new SnmpPduFactoryBER() ;
 728         else
 729             pduFactory = factory ;
 730     }
 731 
 732     /**
 733      * Set the user-data factory of this SNMP protocol adaptor.
 734      *
 735      * @param factory The factory object (null means no factory).
 736      * @see com.sun.jmx.snmp.agent.SnmpUserDataFactory
 737      */
 738     @Override
 739     public void setUserDataFactory(SnmpUserDataFactory factory) {
 740         userDataFactory = factory ;
 741     }
 742 
 743     /**
 744      * Get the user-data factory associated with this SNMP protocol adaptor.
 745      *
 746      * @return The factory object (null means no factory).
 747      * @see com.sun.jmx.snmp.agent.SnmpUserDataFactory
 748      */
 749     @Override
 750     public SnmpUserDataFactory getUserDataFactory() {
 751         return userDataFactory;
 752     }
 753 
 754     /**
 755      * Returns <CODE>true</CODE> if authentication traps are enabled.
 756      * <P>
 757      * When this feature is enabled, the SNMP protocol adaptor sends
 758      * an <CODE>authenticationFailure</CODE> trap each time an
 759      * authentication fails.
 760      * <P>
 761      * The default behaviour is to send authentication traps.
 762      *
 763      * @return <CODE>true</CODE> if authentication traps are enabled,
 764      *         <CODE>false</CODE> otherwise.
 765      */
 766     @Override
 767     public boolean getAuthTrapEnabled() {
 768         return authTrapEnabled ;
 769     }
 770 
 771     /**
 772      * Sets the flag indicating if traps need to be sent in case of
 773      * authentication failure.
 774      *
 775      * @param enabled Flag indicating if traps need to be sent.
 776      */
 777     @Override
 778     public void setAuthTrapEnabled(boolean enabled) {
 779         authTrapEnabled = enabled ;
 780     }
 781 
 782     /**
 783      * Returns <code>true</code> if this SNMP protocol adaptor sends a
 784      * response in case of authentication failure.
 785      * <P>
 786      * When this feature is enabled, the SNMP protocol adaptor sends a
 787      * response with <CODE>noSuchName</CODE> or <CODE>readOnly</CODE> when
 788      * the authentication failed. If the flag is disabled, the
 789      * SNMP protocol adaptor trashes the PDU silently.
 790      * <P>
 791      * The default behavior is to send responses.
 792      *
 793      * @return <CODE>true</CODE> if responses are sent.
 794      */
 795     @Override
 796     public boolean getAuthRespEnabled() {
 797         return authRespEnabled ;
 798     }
 799 
 800     /**
 801      * Sets the flag indicating if responses need to be sent in case of
 802      * authentication failure.
 803      *
 804      * @param enabled Flag indicating if responses need to be sent.
 805      */
 806     @Override
 807     public void setAuthRespEnabled(boolean enabled) {
 808         authRespEnabled = enabled ;
 809     }
 810 
 811     /**
 812      * Returns the enterprise OID. It is used by
 813      * {@link #snmpV1Trap snmpV1Trap} to fill the 'enterprise' field of the
 814      * trap request.
 815      *
 816      * @return The OID in string format "x.x.x.x".
 817      */
 818     @Override
 819     public String getEnterpriseOid() {
 820         return enterpriseOid.toString() ;
 821     }
 822 
 823     /**
 824      * Sets the enterprise OID.
 825      *
 826      * @param oid The OID in string format "x.x.x.x".
 827      *
 828      * @exception IllegalArgumentException The string format is incorrect
 829      */
 830     @Override
 831     public void setEnterpriseOid(String oid) throws IllegalArgumentException {
 832         enterpriseOid = new SnmpOid(oid) ;
 833     }
 834 
 835     /**
 836      * Returns the names of the MIBs available in this SNMP protocol adaptor.
 837      *
 838      * @return An array of MIB names.
 839      */
 840     @Override
 841     public String[] getMibs() {
 842         String[] result = new String[mibs.size()] ;
 843         int i = 0 ;
 844         for (Enumeration<SnmpMibAgent> e = mibs.elements() ; e.hasMoreElements() ;) {
 845             SnmpMibAgent mib = e.nextElement() ;
 846             result[i++] = mib.getMibName();
 847         }
 848         return result ;
 849     }
 850 
 851     // GETTERS FOR SNMP GROUP (MIBII)
 852     //-------------------------------
 853 
 854     /**
 855      * Returns the <CODE>snmpOutTraps</CODE> value defined in MIB-II.
 856      *
 857      * @return The <CODE>snmpOutTraps</CODE> value.
 858      */
 859     @Override
 860     public Long getSnmpOutTraps() {
 861         return (long)snmpOutTraps;
 862     }
 863 
 864     /**
 865      * Returns the <CODE>snmpOutGetResponses</CODE> value defined in MIB-II.
 866      *
 867      * @return The <CODE>snmpOutGetResponses</CODE> value.
 868      */
 869     @Override
 870     public Long getSnmpOutGetResponses() {
 871         return (long)snmpOutGetResponses;
 872     }
 873 
 874     /**
 875      * Returns the <CODE>snmpOutGenErrs</CODE> value defined in MIB-II.
 876      *
 877      * @return The <CODE>snmpOutGenErrs</CODE> value.
 878      */
 879     @Override
 880     public Long getSnmpOutGenErrs() {
 881         return (long) snmpOutGenErrs;
 882     }
 883 
 884     /**
 885      * Returns the <CODE>snmpOutBadValues</CODE> value defined in MIB-II.
 886      *
 887      * @return The <CODE>snmpOutBadValues</CODE> value.
 888      */
 889     @Override
 890     public Long getSnmpOutBadValues() {
 891         return (long)snmpOutBadValues;
 892     }
 893 
 894     /**
 895      * Returns the <CODE>snmpOutNoSuchNames</CODE> value defined in MIB-II.
 896      *
 897      * @return The <CODE>snmpOutNoSuchNames</CODE> value.
 898      */
 899     @Override
 900     public Long getSnmpOutNoSuchNames() {
 901         return (long)snmpOutNoSuchNames;
 902     }
 903 
 904     /**
 905      * Returns the <CODE>snmpOutTooBigs</CODE> value defined in MIB-II.
 906      *
 907      * @return The <CODE>snmpOutTooBigs</CODE> value.
 908      */
 909     @Override
 910     public Long getSnmpOutTooBigs() {
 911         return (long)snmpOutTooBigs;
 912     }
 913 
 914     /**
 915      * Returns the <CODE>snmpInASNParseErrs</CODE> value defined in MIB-II.
 916      *
 917      * @return The <CODE>snmpInASNParseErrs</CODE> value.
 918      */
 919     @Override
 920     public Long getSnmpInASNParseErrs() {
 921         return (long)snmpInASNParseErrs;
 922     }
 923 
 924     /**
 925      * Returns the <CODE>snmpInBadCommunityUses</CODE> value defined in MIB-II.
 926      *
 927      * @return The <CODE>snmpInBadCommunityUses</CODE> value.
 928      */
 929     @Override
 930     public Long getSnmpInBadCommunityUses() {
 931         return (long)snmpInBadCommunityUses;
 932     }
 933 
 934     /**
 935      * Returns the <CODE>snmpInBadCommunityNames</CODE> value defined in
 936      * MIB-II.
 937      *
 938      * @return The <CODE>snmpInBadCommunityNames</CODE> value.
 939      */
 940     @Override
 941     public Long getSnmpInBadCommunityNames() {
 942         return (long)snmpInBadCommunityNames;
 943     }
 944 
 945     /**
 946      * Returns the <CODE>snmpInBadVersions</CODE> value defined in MIB-II.
 947      *
 948      * @return The <CODE>snmpInBadVersions</CODE> value.
 949      */
 950     @Override
 951     public Long getSnmpInBadVersions() {
 952         return (long)snmpInBadVersions;
 953     }
 954 
 955     /**
 956      * Returns the <CODE>snmpOutPkts</CODE> value defined in MIB-II.
 957      *
 958      * @return The <CODE>snmpOutPkts</CODE> value.
 959      */
 960     @Override
 961     public Long getSnmpOutPkts() {
 962         return (long)snmpOutPkts;
 963     }
 964 
 965     /**
 966      * Returns the <CODE>snmpInPkts</CODE> value defined in MIB-II.
 967      *
 968      * @return The <CODE>snmpInPkts</CODE> value.
 969      */
 970     @Override
 971     public Long getSnmpInPkts() {
 972         return (long)snmpInPkts;
 973     }
 974 
 975     /**
 976      * Returns the <CODE>snmpInGetRequests</CODE> value defined in MIB-II.
 977      *
 978      * @return The <CODE>snmpInGetRequests</CODE> value.
 979      */
 980     @Override
 981     public Long getSnmpInGetRequests() {
 982         return (long)snmpInGetRequests;
 983     }
 984 
 985     /**
 986      * Returns the <CODE>snmpInGetNexts</CODE> value defined in MIB-II.
 987      *
 988      * @return The <CODE>snmpInGetNexts</CODE> value.
 989      */
 990     @Override
 991     public Long getSnmpInGetNexts() {
 992         return (long)snmpInGetNexts;
 993     }
 994 
 995     /**
 996      * Returns the <CODE>snmpInSetRequests</CODE> value defined in MIB-II.
 997      *
 998      * @return The <CODE>snmpInSetRequests</CODE> value.
 999      */
1000     @Override
1001     public Long getSnmpInSetRequests() {
1002         return (long)snmpInSetRequests;
1003     }
1004 
1005     /**
1006      * Returns the <CODE>snmpInTotalSetVars</CODE> value defined in MIB-II.
1007      *
1008      * @return The <CODE>snmpInTotalSetVars</CODE> value.
1009      */
1010     @Override
1011     public Long getSnmpInTotalSetVars() {
1012         return (long)snmpInTotalSetVars;
1013     }
1014 
1015     /**
1016      * Returns the <CODE>snmpInTotalReqVars</CODE> value defined in MIB-II.
1017      *
1018      * @return The <CODE>snmpInTotalReqVars</CODE> value.
1019      */
1020     @Override
1021     public Long getSnmpInTotalReqVars() {
1022         return (long)snmpInTotalReqVars;
1023     }
1024 
1025     /**
1026      * Returns the <CODE>snmpSilentDrops</CODE> value defined in RFC
1027      * 1907 NMPv2-MIB .
1028      *
1029      * @return The <CODE>snmpSilentDrops</CODE> value.
1030      *
1031      * @since 1.5
1032      */
1033     @Override
1034     public Long getSnmpSilentDrops() {
1035         return (long)snmpSilentDrops;
1036     }
1037 
1038     /**
1039      * Returns the <CODE>snmpProxyDrops</CODE> value defined in RFC
1040      * 1907 NMPv2-MIB .
1041      *
1042      * @return The <CODE>snmpProxyDrops</CODE> value.
1043      *
1044      * @since 1.5
1045      */
1046     @Override
1047     public Long getSnmpProxyDrops() {
1048         return 0L;
1049     }
1050 
1051 
1052     // PUBLIC METHODS
1053     //---------------
1054 
1055     /**
1056      * Allows the MBean to perform any operations it needs before being
1057      * registered in the MBean server.
1058      * If the name of the SNMP protocol adaptor MBean is not specified,
1059      * it is initialized with the default value:
1060      * {@link com.sun.jmx.snmp.ServiceName#DOMAIN
1061      *   com.sun.jmx.snmp.ServiceName.DOMAIN}:{@link
1062      * com.sun.jmx.snmp.ServiceName#SNMP_ADAPTOR_SERVER
1063      * com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_SERVER}.
1064      * If any exception is raised, the SNMP protocol adaptor MBean will
1065      * not be registered in the MBean server.
1066      *
1067      * @param server The MBean server to register the service with.
1068      * @param name The object name.
1069      *
1070      * @return The name of the SNMP protocol adaptor registered.
1071      *
1072      * @exception java.lang.Exception
1073      */
1074     @Override
1075     public ObjectName preRegister(MBeanServer server, ObjectName name)
1076         throws java.lang.Exception {
1077 
1078         if (name == null) {
1079             name = new ObjectName(server.getDefaultDomain() + ":" +
1080                              com.sun.jmx.snmp.ServiceName.SNMP_ADAPTOR_SERVER);
1081         }
1082         return (super.preRegister(server, name));
1083     }
1084 
1085     /**
1086      * Not used in this context.
1087      */
1088     @Override
1089     public void postRegister (Boolean registrationDone) {
1090         super.postRegister(registrationDone);
1091     }
1092 
1093     /**
1094      * Not used in this context.
1095      */
1096     @Override
1097     public void preDeregister() throws java.lang.Exception {
1098         super.preDeregister();
1099     }
1100 
1101     /**
1102      * Not used in this context.
1103      */
1104     @Override
1105     public void postDeregister() {
1106         super.postDeregister();
1107     }
1108 
1109     /**
1110      * Adds a new MIB in the SNMP MIB handler.
1111      *
1112      * @param mib The MIB to add.
1113      *
1114      * @return A reference to the SNMP MIB handler.
1115      *
1116      * @exception IllegalArgumentException If the parameter is null.
1117      */
1118     @Override
1119     public SnmpMibHandler addMib(SnmpMibAgent mib)
1120         throws IllegalArgumentException {
1121         if (mib == null) {
1122             throw new IllegalArgumentException() ;
1123         }
1124 
1125         if(!mibs.contains(mib))
1126             mibs.addElement(mib);
1127 
1128         root.register(mib);
1129 
1130         return this;
1131     }
1132 
1133     /**
1134      * Adds a new MIB in the SNMP MIB handler.
1135      * This method is to be called to set a specific agent to a specific OID.
1136      * This can be useful when dealing with MIB overlapping.
1137      * Some OID can be implemented in more than one MIB. In this case,
1138      * the OID nearer agent will be used on SNMP operations.
1139      *
1140      * @param mib The MIB to add.
1141      * @param oids The set of OIDs this agent implements.
1142      *
1143      * @return A reference to the SNMP MIB handler.
1144      *
1145      * @exception IllegalArgumentException If the parameter is null.
1146      *
1147      * @since 1.5
1148      */
1149     @Override
1150     public SnmpMibHandler addMib(SnmpMibAgent mib, SnmpOid[] oids)
1151         throws IllegalArgumentException {
1152         if (mib == null) {
1153             throw new IllegalArgumentException() ;
1154         }
1155 
1156         //If null oid array, just add it to the mib.
1157         if(oids == null)
1158             return addMib(mib);
1159 
1160         if(!mibs.contains(mib))
1161             mibs.addElement(mib);
1162 
1163         for (int i = 0; i < oids.length; i++) {
1164             root.register(mib, oids[i].longValue());
1165         }
1166         return this;
1167     }
1168 
1169     /**
1170      * Adds a new MIB in the SNMP MIB handler. In SNMP V1 and V2 the
1171      * <CODE>contextName</CODE> is useless and this method
1172      * is equivalent to <CODE>addMib(SnmpMibAgent mib)</CODE>.
1173      *
1174      * @param mib The MIB to add.
1175      * @param contextName The MIB context name.
1176      * @return A reference on the SNMP MIB handler.
1177      *
1178      * @exception IllegalArgumentException If the parameter is null.
1179      *
1180      * @since 1.5
1181      */
1182     @Override
1183     public SnmpMibHandler addMib(SnmpMibAgent mib, String contextName)
1184         throws IllegalArgumentException {
1185         return addMib(mib);
1186     }
1187 
1188     /**
1189      * Adds a new MIB in the SNMP MIB handler. In SNMP V1 and V2 the
1190      * <CODE>contextName</CODE> is useless and this method
1191      * is equivalent to <CODE>addMib(SnmpMibAgent mib, SnmpOid[] oids)</CODE>.
1192      *
1193      * @param mib The MIB to add.
1194      * @param contextName The MIB context. If null is passed, will be
1195      *        registered in the default context.
1196      * @param oids The set of OIDs this agent implements.
1197      *
1198      * @return A reference to the SNMP MIB handler.
1199      *
1200      * @exception IllegalArgumentException If the parameter is null.
1201      *
1202      * @since 1.5
1203      */
1204     @Override
1205     public SnmpMibHandler addMib(SnmpMibAgent mib,
1206                                  String contextName,
1207                                  SnmpOid[] oids)
1208         throws IllegalArgumentException {
1209 
1210         return addMib(mib, oids);
1211     }
1212 
1213     /**
1214      * Removes the specified MIB from the SNMP protocol adaptor.
1215      * In SNMP V1 and V2 the <CODE>contextName</CODE> is useless and this
1216      * method is equivalent to <CODE>removeMib(SnmpMibAgent mib)</CODE>.
1217      *
1218      * @param mib The MIB to be removed.
1219      * @param contextName The context name used at registration time.
1220      *
1221      * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was
1222      * a MIB included in the SNMP MIB handler, <CODE>false</CODE>
1223      * otherwise.
1224      *
1225      * @since 1.5
1226      */
1227     @Override
1228     public boolean removeMib(SnmpMibAgent mib, String contextName) {
1229         return removeMib(mib);
1230     }
1231 
1232     /**
1233      * Removes the specified MIB from the SNMP protocol adaptor.
1234      *
1235      * @param mib The MIB to be removed.
1236      *
1237      * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was a MIB
1238      *         included in the SNMP MIB handler, <CODE>false</CODE> otherwise.
1239      */
1240     @Override
1241     public boolean removeMib(SnmpMibAgent mib) {
1242         root.unregister(mib);
1243         return (mibs.removeElement(mib)) ;
1244     }
1245 
1246     /**
1247      * Removes the specified MIB from the SNMP protocol adaptor.
1248      *
1249      * @param mib The MIB to be removed.
1250      * @param oids The oid the MIB was previously registered for.
1251      * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was
1252      * a MIB included in the SNMP MIB handler, <CODE>false</CODE>
1253      * otherwise.
1254      *
1255      * @since 1.5
1256      */
1257     @Override
1258     public boolean removeMib(SnmpMibAgent mib, SnmpOid[] oids) {
1259         root.unregister(mib, oids);
1260         return (mibs.removeElement(mib)) ;
1261     }
1262 
1263      /**
1264      * Removes the specified MIB from the SNMP protocol adaptor.
1265      *
1266      * @param mib The MIB to be removed.
1267      * @param contextName The context name used at registration time.
1268      * @param oids The oid the MIB was previously registered for.
1269      * @return <CODE>true</CODE> if the specified <CODE>mib</CODE> was
1270      * a MIB included in the SNMP MIB handler, <CODE>false</CODE>
1271      * otherwise.
1272      *
1273      * @since 1.5
1274      */
1275     @Override
1276     public boolean removeMib(SnmpMibAgent mib,
1277                              String contextName,
1278                              SnmpOid[] oids) {
1279         return removeMib(mib, oids);
1280     }
1281 
1282     // SUBCLASSING OF COMMUNICATOR SERVER
1283     //-----------------------------------
1284 
1285     /**
1286      * Creates the datagram socket.
1287      */
1288     @Override
1289     protected void doBind()
1290         throws CommunicationException, InterruptedException {
1291 
1292         try {
1293             synchronized (this) {
1294                 socket = new DatagramSocket(port, address) ;
1295             }
1296             dbgTag = makeDebugTag();
1297         } catch (SocketException e) {
1298             if (e.getMessage().equals(InterruptSysCallMsg))
1299                 throw new InterruptedException(e.toString()) ;
1300             else {
1301                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
1302                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
1303                         "doBind", "cannot bind on port " + port);
1304                 }
1305                 throw new CommunicationException(e) ;
1306             }
1307         }
1308     }
1309 
1310     /**
1311      * Return the actual port to which the adaptor is bound.
1312      * Can be different from the port given at construction time if
1313      * that port number was 0.
1314      * @return the actual port to which the adaptor is bound.
1315      **/
1316     @Override
1317     public int getPort() {
1318         synchronized (this) {
1319             if (socket != null) return socket.getLocalPort();
1320         }
1321         return super.getPort();
1322     }
1323 
1324     /**
1325      * Closes the datagram socket.
1326      */
1327     @Override
1328     protected void doUnbind()
1329         throws CommunicationException, InterruptedException {
1330         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1331             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1332                 "doUnbind","Finally close the socket");
1333         }
1334         synchronized (this) {
1335             if (socket != null) {
1336                 socket.close() ;
1337                 socket = null ;
1338                 // Important to inform finalize() that the socket is closed...
1339             }
1340         }
1341         closeTrapSocketIfNeeded() ;
1342         closeInformSocketIfNeeded() ;
1343     }
1344 
1345     private void createSnmpRequestHandler(SnmpAdaptorServer server,
1346                                           int id,
1347                                           DatagramSocket s,
1348                                           DatagramPacket p,
1349                                           SnmpMibTree tree,
1350                                           Vector<SnmpMibAgent> m,
1351                                           InetAddressAcl a,
1352                                           SnmpPduFactory factory,
1353                                           SnmpUserDataFactory dataFactory,
1354                                           MBeanServer f,
1355                                           ObjectName n) {
1356         final SnmpRequestHandler handler =
1357             new SnmpRequestHandler(this, id, s, p, tree, m, a, factory,
1358                                    dataFactory, f, n);
1359         threadService.submitTask(handler);
1360     }
1361 
1362     /**
1363      * Reads a packet from the datagram socket and creates a request
1364      * handler which decodes and processes the request.
1365      */
1366     @Override
1367     protected void doReceive()
1368         throws CommunicationException, InterruptedException {
1369 
1370         // Let's wait for something to be received.
1371         //
1372         try {
1373             packet = new DatagramPacket(new byte[bufferSize], bufferSize) ;
1374             socket.receive(packet);
1375             int state = getState();
1376 
1377             if(state != ONLINE) {
1378                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1379                     SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1380                         "doReceive","received a message but state not online, returning.");
1381                 }
1382                 return;
1383             }
1384 
1385             createSnmpRequestHandler(this, servedClientCount, socket,
1386                                      packet, root, mibs, ipacl, pduFactory,
1387                                      userDataFactory, topMBS, objectName);
1388         } catch (SocketException e) {
1389             // Let's check if we have been interrupted by stop().
1390             //
1391             if (e.getMessage().equals(InterruptSysCallMsg))
1392                 throw new InterruptedException(e.toString()) ;
1393             else
1394                 throw new CommunicationException(e) ;
1395         } catch (InterruptedIOException e) {
1396             throw new InterruptedException(e.toString()) ;
1397         } catch (CommunicationException e) {
1398             throw e ;
1399         } catch (Exception e) {
1400             throw new CommunicationException(e) ;
1401         }
1402         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1403             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1404                 "doReceive", "received a message");
1405         }
1406     }
1407 
1408     @Override
1409     protected void doError(Exception e) throws CommunicationException {
1410     }
1411 
1412     /**
1413      * Not used in this context.
1414      */
1415     @Override
1416     protected void doProcess()
1417         throws CommunicationException, InterruptedException {
1418     }
1419 
1420 
1421     /**
1422      * The number of times the communicator server will attempt
1423      * to bind before giving up.
1424      * We attempt only once...
1425      * @return 1
1426      **/
1427     @Override
1428     protected int getBindTries() {
1429         return 1;
1430     }
1431 
1432     /**
1433      * Stops this SNMP protocol adaptor.
1434      * Closes the datagram socket.
1435      * <p>
1436      * Has no effect if this SNMP protocol adaptor is <CODE>OFFLINE</CODE> or
1437      * <CODE>STOPPING</CODE>.
1438      */
1439     @Override
1440     public void stop(){
1441 
1442         final int port = getPort();
1443         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1444             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1445                 "stop", "Stopping: using port " + port);
1446         }
1447         if ((state == ONLINE) || (state == STARTING)){
1448             super.stop();
1449             try {
1450                 DatagramSocket sn = new DatagramSocket(0);
1451                 try {
1452                     byte[] ob = new byte[1];
1453 
1454                     DatagramPacket pk;
1455                     if (address != null)
1456                         pk = new DatagramPacket(ob , 1, address, port);
1457                     else
1458                         pk = new DatagramPacket(ob , 1,
1459                                  java.net.InetAddress.getLocalHost(), port);
1460 
1461                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1462                         SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1463                             "stop", "Sending: using port " + port);
1464                     }
1465                     sn.send(pk);
1466                 } finally {
1467                     sn.close();
1468                 }
1469             } catch (Throwable e){
1470                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
1471                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
1472                         "stop", "Got unexpected Throwable", e);
1473                 }
1474             }
1475         }
1476     }
1477 
1478     // SENDING SNMP TRAPS STUFF
1479     //-------------------------
1480 
1481     /**
1482      * Sends a trap using SNMP V1 trap format.
1483      * <BR>The trap is sent to each destination defined in the ACL file
1484      * (if available).
1485      * If no ACL file or no destinations are available, the trap is sent
1486      * to the local host.
1487      *
1488      * @param generic The generic number of the trap.
1489      * @param specific The specific number of the trap.
1490      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1491      *
1492      * @exception IOException An I/O error occurred while sending the trap.
1493      * @exception SnmpStatusException If the trap exceeds the limit defined
1494      *            by <CODE>bufferSize</CODE>.
1495      */
1496     @Override
1497     public void snmpV1Trap(int generic, int specific,
1498                            SnmpVarBindList varBindList)
1499         throws IOException, SnmpStatusException {
1500 
1501         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1502             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1503                 "snmpV1Trap", "generic=" + generic +
1504                   ", specific=" + specific);
1505         }
1506 
1507         // First, make an SNMP V1 trap pdu
1508         //
1509         SnmpPduTrap pdu = new SnmpPduTrap() ;
1510         pdu.address = null ;
1511         pdu.port = trapPort ;
1512         pdu.type = pduV1TrapPdu ;
1513         pdu.version = snmpVersionOne ;
1514         pdu.community = null ;
1515         pdu.enterprise = enterpriseOid ;
1516         pdu.genericTrap = generic ;
1517         pdu.specificTrap = specific ;
1518         pdu.timeStamp = getSysUpTime();
1519 
1520         if (varBindList != null) {
1521             pdu.varBindList = new SnmpVarBind[varBindList.size()] ;
1522             varBindList.copyInto(pdu.varBindList);
1523         }
1524         else
1525             pdu.varBindList = null ;
1526 
1527         // If the local host cannot be determined, we put 0.0.0.0 in agentAddr
1528         try {
1529             if (address != null)
1530                 pdu.agentAddr = handleMultipleIpVersion(address.getAddress());
1531             else pdu.agentAddr =
1532               handleMultipleIpVersion(InetAddress.getLocalHost().getAddress());
1533         } catch (UnknownHostException e) {
1534             byte[] zeroedAddr = new byte[4];
1535             pdu.agentAddr = handleMultipleIpVersion(zeroedAddr) ;
1536         }
1537 
1538         // Next, send the pdu to all destinations defined in ACL
1539         //
1540         sendTrapPdu(pdu) ;
1541     }
1542 
1543     private SnmpIpAddress handleMultipleIpVersion(byte[] address) {
1544         if(address.length == 4)
1545           return new SnmpIpAddress(address);
1546         else {
1547             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
1548                 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
1549                     "handleMultipleIPVersion",
1550                       "Not an IPv4 address, return null");
1551             }
1552             return null;
1553         }
1554     }
1555 
1556     /**
1557      * Sends a trap using SNMP V1 trap format.
1558      * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
1559      * destination using the specified community string (and the ACL file
1560      * is not used).
1561      *
1562      * @param addr The <CODE>InetAddress</CODE> destination of the trap.
1563      * @param cs The community string to be used for the trap.
1564      * @param generic The generic number of the trap.
1565      * @param specific The specific number of the trap.
1566      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1567      *
1568      * @exception IOException An I/O error occurred while sending the trap.
1569      * @exception SnmpStatusException If the trap exceeds the limit defined
1570      *            by <CODE>bufferSize</CODE>.
1571      */
1572     @Override
1573     public void snmpV1Trap(InetAddress addr, String cs, int generic,
1574                            int specific, SnmpVarBindList varBindList)
1575         throws IOException, SnmpStatusException {
1576 
1577         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1578             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1579                 "snmpV1Trap", "generic=" + generic + ", specific=" +
1580                   specific);
1581         }
1582 
1583         // First, make an SNMP V1 trap pdu
1584         //
1585         SnmpPduTrap pdu = new SnmpPduTrap() ;
1586         pdu.address = null ;
1587         pdu.port = trapPort ;
1588         pdu.type = pduV1TrapPdu ;
1589         pdu.version = snmpVersionOne ;
1590 
1591         if(cs != null)
1592             pdu.community = cs.getBytes();
1593         else
1594             pdu.community = null ;
1595 
1596         pdu.enterprise = enterpriseOid ;
1597         pdu.genericTrap = generic ;
1598         pdu.specificTrap = specific ;
1599         pdu.timeStamp = getSysUpTime();
1600 
1601         if (varBindList != null) {
1602             pdu.varBindList = new SnmpVarBind[varBindList.size()] ;
1603             varBindList.copyInto(pdu.varBindList);
1604         }
1605         else
1606             pdu.varBindList = null ;
1607 
1608         // If the local host cannot be determined, we put 0.0.0.0 in agentAddr
1609         try {
1610             if (address != null)
1611                 pdu.agentAddr = handleMultipleIpVersion(address.getAddress());
1612             else pdu.agentAddr =
1613               handleMultipleIpVersion(InetAddress.getLocalHost().getAddress());
1614         } catch (UnknownHostException e) {
1615             byte[] zeroedAddr = new byte[4];
1616             pdu.agentAddr = handleMultipleIpVersion(zeroedAddr) ;
1617         }
1618 
1619         // Next, send the pdu to the specified destination
1620         //
1621         if(addr != null)
1622             sendTrapPdu(addr, pdu) ;
1623         else
1624             sendTrapPdu(pdu);
1625     }
1626 
1627     /**
1628      * Sends a trap using SNMP V1 trap format.
1629      * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
1630      * destination using the specified parameters (and the ACL file is not
1631      * used).
1632      * Note that if the specified <CODE>InetAddress</CODE> destination is null,
1633      * then the ACL file mechanism is used.
1634      *
1635      * @param addr The <CODE>InetAddress</CODE> destination of the trap.
1636      * @param agentAddr The agent address to be used for the trap.
1637      * @param cs The community string to be used for the trap.
1638      * @param enterpOid The enterprise OID to be used for the trap.
1639      * @param generic The generic number of the trap.
1640      * @param specific The specific number of the trap.
1641      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1642      * @param time The time stamp (overwrite the current time).
1643      *
1644      * @exception IOException An I/O error occurred while sending the trap.
1645      * @exception SnmpStatusException If the trap exceeds the limit defined
1646      *            by <CODE>bufferSize</CODE>.
1647      *
1648      * @since 1.5
1649      */
1650     public void snmpV1Trap(InetAddress addr,
1651                            SnmpIpAddress agentAddr,
1652                            String cs,
1653                            SnmpOid enterpOid,
1654                            int generic,
1655                            int specific,
1656                            SnmpVarBindList varBindList,
1657                            SnmpTimeticks time)
1658         throws IOException, SnmpStatusException {
1659         snmpV1Trap(addr,
1660                    trapPort,
1661                    agentAddr,
1662                    cs,
1663                    enterpOid,
1664                    generic,
1665                    specific,
1666                    varBindList,
1667                    time);
1668     }
1669 
1670     /**
1671      * Sends a trap using SNMP V1 trap format.
1672      * <BR>The trap is sent to the specified <CODE>SnmpPeer</CODE> destination.
1673      * The community string used is the one located in the
1674      * <CODE>SnmpPeer</CODE> parameters
1675      * (<CODE>SnmpParameters.getRdCommunity() </CODE>).
1676      *
1677      * @param peer The <CODE>SnmpPeer</CODE> destination of the trap.
1678      * @param agentAddr The agent address to be used for the trap.
1679      * @param enterpOid The enterprise OID to be used for the trap.
1680      * @param generic The generic number of the trap.
1681      * @param specific The specific number of the trap.
1682      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1683      * @param time The time stamp (overwrite the current time).
1684      *
1685      * @exception IOException An I/O error occurred while sending the trap.
1686      * @exception SnmpStatusException If the trap exceeds the limit
1687      * defined by <CODE>bufferSize</CODE>.
1688      *
1689      * @since 1.5
1690      */
1691     @Override
1692     public void snmpV1Trap(SnmpPeer peer,
1693                            SnmpIpAddress agentAddr,
1694                            SnmpOid enterpOid,
1695                            int generic,
1696                            int specific,
1697                            SnmpVarBindList varBindList,
1698                            SnmpTimeticks time)
1699         throws IOException, SnmpStatusException {
1700 
1701         SnmpParameters p = (SnmpParameters) peer.getParams();
1702         snmpV1Trap(peer.getDestAddr(),
1703                    peer.getDestPort(),
1704                    agentAddr,
1705                    p.getRdCommunity(),
1706                    enterpOid,
1707                    generic,
1708                    specific,
1709                    varBindList,
1710                    time);
1711     }
1712 
1713     private void snmpV1Trap(InetAddress addr,
1714                             int port,
1715                             SnmpIpAddress agentAddr,
1716                             String cs,
1717                             SnmpOid enterpOid,
1718                             int generic,
1719                             int specific,
1720                             SnmpVarBindList varBindList,
1721                             SnmpTimeticks time)
1722         throws IOException, SnmpStatusException {
1723 
1724         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1725             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1726                 "snmpV1Trap", "generic=" + generic + ", specific=" +
1727                   specific);
1728         }
1729 
1730         // First, make an SNMP V1 trap pdu
1731         //
1732         SnmpPduTrap pdu = new SnmpPduTrap() ;
1733         pdu.address = null ;
1734         pdu.port = port ;
1735         pdu.type = pduV1TrapPdu ;
1736         pdu.version = snmpVersionOne ;
1737 
1738         //Diff start
1739         if(cs != null)
1740             pdu.community = cs.getBytes();
1741         else
1742             pdu.community = null ;
1743         //Diff end
1744 
1745         // Diff start
1746         if(enterpOid != null)
1747             pdu.enterprise = enterpOid;
1748         else
1749             pdu.enterprise = enterpriseOid ;
1750         //Diff end
1751         pdu.genericTrap = generic ;
1752         pdu.specificTrap = specific ;
1753         //Diff start
1754         if(time != null)
1755             pdu.timeStamp = time.longValue();
1756         else
1757             pdu.timeStamp = getSysUpTime();
1758         //Diff end
1759 
1760         if (varBindList != null) {
1761             pdu.varBindList = new SnmpVarBind[varBindList.size()] ;
1762             varBindList.copyInto(pdu.varBindList);
1763         }
1764         else
1765             pdu.varBindList = null ;
1766 
1767         if (agentAddr == null) {
1768             // If the local host cannot be determined,
1769             // we put 0.0.0.0 in agentAddr
1770             try {
1771                 final InetAddress inetAddr =
1772                     (address!=null)?address:InetAddress.getLocalHost();
1773                 agentAddr = handleMultipleIpVersion(inetAddr.getAddress());
1774             }  catch (UnknownHostException e) {
1775                 byte[] zeroedAddr = new byte[4];
1776                 agentAddr = handleMultipleIpVersion(zeroedAddr);
1777             }
1778         }
1779 
1780         pdu.agentAddr = agentAddr;
1781 
1782         // Next, send the pdu to the specified destination
1783         //
1784         // Diff start
1785         if(addr != null)
1786             sendTrapPdu(addr, pdu) ;
1787         else
1788             sendTrapPdu(pdu);
1789 
1790         //End diff
1791     }
1792 
1793     /**
1794      * Sends a trap using SNMP V2 trap format.
1795      * <BR>The trap is sent to the specified <CODE>SnmpPeer</CODE> destination.
1796      * <BR>The community string used is the one located in the
1797      * <CODE>SnmpPeer</CODE> parameters
1798      * (<CODE>SnmpParameters.getRdCommunity() </CODE>).
1799      * <BR>The variable list included in the outgoing trap is composed of
1800      * the following items:
1801      * <UL>
1802      * <LI><CODE>sysUpTime.0</CODE> with the value specified by
1803      *     <CODE>time</CODE></LI>
1804      * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
1805      *     <CODE>trapOid</CODE></LI>
1806      * <LI><CODE>all the (oid,values)</CODE> from the specified
1807      *     <CODE>varBindList</CODE></LI>
1808      * </UL>
1809      *
1810      * @param peer The <CODE>SnmpPeer</CODE> destination of the trap.
1811      * @param trapOid The OID identifying the trap.
1812      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1813      * @param time The time stamp (overwrite the current time).
1814      *
1815      * @exception IOException An I/O error occurred while sending the trap.
1816      * @exception SnmpStatusException If the trap exceeds the limit
1817      * defined by <CODE>bufferSize</CODE>.
1818      *
1819      * @since 1.5
1820      */
1821     @Override
1822     public void snmpV2Trap(SnmpPeer peer,
1823                            SnmpOid trapOid,
1824                            SnmpVarBindList varBindList,
1825                            SnmpTimeticks time)
1826         throws IOException, SnmpStatusException {
1827 
1828         SnmpParameters p = (SnmpParameters) peer.getParams();
1829         snmpV2Trap(peer.getDestAddr(),
1830                    peer.getDestPort(),
1831                    p.getRdCommunity(),
1832                    trapOid,
1833                    varBindList,
1834                    time);
1835     }
1836 
1837     /**
1838      * Sends a trap using SNMP V2 trap format.
1839      * <BR>The trap is sent to each destination defined in the ACL file
1840      * (if available). If no ACL file or no destinations are available,
1841      * the trap is sent to the local host.
1842      * <BR>The variable list included in the outgoing trap is composed of
1843      * the following items:
1844      * <UL>
1845      * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
1846      * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
1847      *     <CODE>trapOid</CODE></LI>
1848      * <LI><CODE>all the (oid,values)</CODE> from the specified
1849      *     <CODE>varBindList</CODE></LI>
1850      * </UL>
1851      *
1852      * @param trapOid The OID identifying the trap.
1853      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1854      *
1855      * @exception IOException An I/O error occurred while sending the trap.
1856      * @exception SnmpStatusException If the trap exceeds the limit defined
1857      *            by <CODE>bufferSize</CODE>.
1858      */
1859     @Override
1860     public void snmpV2Trap(SnmpOid trapOid, SnmpVarBindList varBindList)
1861         throws IOException, SnmpStatusException {
1862 
1863         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1864             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1865                 "snmpV2Trap", "trapOid=" + trapOid);
1866         }
1867 
1868         // First, make an SNMP V2 trap pdu
1869         // We clone varBindList and insert sysUpTime and snmpTrapOid
1870         //
1871         SnmpPduRequest pdu = new SnmpPduRequest() ;
1872         pdu.address = null ;
1873         pdu.port = trapPort ;
1874         pdu.type = pduV2TrapPdu ;
1875         pdu.version = snmpVersionTwo ;
1876         pdu.community = null ;
1877 
1878         SnmpVarBindList fullVbl ;
1879         if (varBindList != null)
1880             fullVbl = varBindList.clone() ;
1881         else
1882             fullVbl = new SnmpVarBindList(2) ;
1883         SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
1884         fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
1885         fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
1886                                 0);
1887         pdu.varBindList = new SnmpVarBind[fullVbl.size()] ;
1888         fullVbl.copyInto(pdu.varBindList) ;
1889 
1890         // Next, send the pdu to all destinations defined in ACL
1891         //
1892         sendTrapPdu(pdu) ;
1893     }
1894 
1895     /**
1896      * Sends a trap using SNMP V2 trap format.
1897      * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
1898      * destination using the specified community string (and the ACL file
1899      * is not used).
1900      * <BR>The variable list included in the outgoing trap is composed of
1901      * the following items:
1902      * <UL>
1903      * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
1904      * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
1905      *     <CODE>trapOid</CODE></LI>
1906      * <LI><CODE>all the (oid,values)</CODE> from the specified
1907      *     <CODE>varBindList</CODE></LI>
1908      * </UL>
1909      *
1910      * @param addr The <CODE>InetAddress</CODE> destination of the trap.
1911      * @param cs The community string to be used for the trap.
1912      * @param trapOid The OID identifying the trap.
1913      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1914      *
1915      * @exception IOException An I/O error occurred while sending the trap.
1916      * @exception SnmpStatusException If the trap exceeds the limit
1917      *            defined by <CODE>bufferSize</CODE>.
1918      */
1919     @Override
1920     public void snmpV2Trap(InetAddress addr, String cs, SnmpOid trapOid,
1921                            SnmpVarBindList varBindList)
1922         throws IOException, SnmpStatusException {
1923 
1924         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
1925             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
1926                 "snmpV2Trap", "trapOid=" + trapOid);
1927         }
1928 
1929         // First, make an SNMP V2 trap pdu
1930         // We clone varBindList and insert sysUpTime and snmpTrapOid
1931         //
1932         SnmpPduRequest pdu = new SnmpPduRequest() ;
1933         pdu.address = null ;
1934         pdu.port = trapPort ;
1935         pdu.type = pduV2TrapPdu ;
1936         pdu.version = snmpVersionTwo ;
1937 
1938         if(cs != null)
1939             pdu.community = cs.getBytes();
1940         else
1941             pdu.community = null;
1942 
1943         SnmpVarBindList fullVbl ;
1944         if (varBindList != null)
1945             fullVbl = varBindList.clone() ;
1946         else
1947             fullVbl = new SnmpVarBindList(2) ;
1948         SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
1949         fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
1950         fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
1951                                 0);
1952         pdu.varBindList = new SnmpVarBind[fullVbl.size()] ;
1953         fullVbl.copyInto(pdu.varBindList) ;
1954 
1955         // Next, send the pdu to the specified destination
1956         //
1957         if(addr != null)
1958             sendTrapPdu(addr, pdu);
1959         else
1960             sendTrapPdu(pdu);
1961     }
1962 
1963     /**
1964      * Sends a trap using SNMP V2 trap format.
1965      * <BR>The trap is sent to the specified <CODE>InetAddress</CODE>
1966      * destination using the specified parameters (and the ACL file is not
1967      * used).
1968      * Note that if the specified <CODE>InetAddress</CODE> destination is null,
1969      * then the ACL file mechanism is used.
1970      * <BR>The variable list included in the outgoing trap is composed of the
1971      * following items:
1972      * <UL>
1973      * <LI><CODE>sysUpTime.0</CODE> with the value specified by
1974      *     <CODE>time</CODE></LI>
1975      * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
1976      *     <CODE>trapOid</CODE></LI>
1977      * <LI><CODE>all the (oid,values)</CODE> from the specified
1978      *     <CODE>varBindList</CODE></LI>
1979      * </UL>
1980      *
1981      * @param addr The <CODE>InetAddress</CODE> destination of the trap.
1982      * @param cs The community string to be used for the trap.
1983      * @param trapOid The OID identifying the trap.
1984      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
1985      * @param time The time stamp (overwrite the current time).
1986      *
1987      * @exception IOException An I/O error occurred while sending the trap.
1988      * @exception SnmpStatusException If the trap exceeds the limit
1989      * defined by <CODE>bufferSize</CODE>.
1990      *
1991      * @since 1.5
1992      */
1993     public void snmpV2Trap(InetAddress addr,
1994                            String cs,
1995                            SnmpOid trapOid,
1996                            SnmpVarBindList varBindList,
1997                            SnmpTimeticks time)
1998         throws IOException, SnmpStatusException {
1999 
2000         snmpV2Trap(addr,
2001                    trapPort,
2002                    cs,
2003                    trapOid,
2004                    varBindList,
2005                    time);
2006     }
2007 
2008     private void snmpV2Trap(InetAddress addr,
2009                             int port,
2010                             String cs,
2011                             SnmpOid trapOid,
2012                             SnmpVarBindList varBindList,
2013                             SnmpTimeticks time)
2014         throws IOException, SnmpStatusException {
2015 
2016         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2017             final StringBuilder strb = new StringBuilder()
2018                 .append("trapOid=").append(trapOid)
2019                 .append("\ncommunity=").append(cs)
2020                 .append("\naddr=").append(addr)
2021                 .append("\nvarBindList=").append(varBindList)
2022                 .append("\ntime=").append(time)
2023                 .append("\ntrapPort=").append(port);
2024             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2025                 "snmpV2Trap", strb.toString());
2026         }
2027 
2028         // First, make an SNMP V2 trap pdu
2029         // We clone varBindList and insert sysUpTime and snmpTrapOid
2030         //
2031         SnmpPduRequest pdu = new SnmpPduRequest() ;
2032         pdu.address = null ;
2033         pdu.port = port ;
2034         pdu.type = pduV2TrapPdu ;
2035         pdu.version = snmpVersionTwo ;
2036 
2037         if(cs != null)
2038             pdu.community = cs.getBytes();
2039         else
2040             pdu.community = null;
2041 
2042         SnmpVarBindList fullVbl ;
2043         if (varBindList != null)
2044             fullVbl = varBindList.clone() ;
2045         else
2046             fullVbl = new SnmpVarBindList(2) ;
2047 
2048         // Only difference with other
2049         SnmpTimeticks sysUpTimeValue;
2050         if(time != null)
2051             sysUpTimeValue = time;
2052         else
2053             sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
2054         //End of diff
2055 
2056         fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
2057         fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
2058                                 0);
2059         pdu.varBindList = new SnmpVarBind[fullVbl.size()] ;
2060         fullVbl.copyInto(pdu.varBindList) ;
2061 
2062         // Next, send the pdu to the specified destination
2063         //
2064         // Diff start
2065         if(addr != null)
2066             sendTrapPdu(addr, pdu) ;
2067         else
2068             sendTrapPdu(pdu);
2069         //End diff
2070     }
2071 
2072     /**
2073      * Send the specified trap PDU to the passed <CODE>InetAddress</CODE>.
2074      * @param address The destination address.
2075      * @param pdu The pdu to send.
2076      * @exception IOException An I/O error occurred while sending the trap.
2077      * @exception SnmpStatusException If the trap exceeds the limit
2078      * defined by <CODE>bufferSize</CODE>.
2079      *
2080      * @since 1.5
2081      */
2082     @Override
2083     public void snmpPduTrap(InetAddress address, SnmpPduPacket pdu)
2084             throws IOException, SnmpStatusException {
2085 
2086         if(address != null)
2087             sendTrapPdu(address, pdu);
2088         else
2089             sendTrapPdu(pdu);
2090     }
2091 
2092     /**
2093      * Send the specified trap PDU to the passed <CODE>SnmpPeer</CODE>.
2094      * @param peer The destination peer. The Read community string is used of
2095      * <CODE>SnmpParameters</CODE> is used as the trap community string.
2096      * @param pdu The pdu to send.
2097      * @exception IOException An I/O error occurred while sending the trap.
2098      * @exception SnmpStatusException If the trap exceeds the limit defined
2099      * by <CODE>bufferSize</CODE>.
2100      * @since 1.5
2101      */
2102     @Override
2103     public void snmpPduTrap(SnmpPeer peer,
2104                             SnmpPduPacket pdu)
2105         throws IOException, SnmpStatusException {
2106         if(peer != null) {
2107             pdu.port = peer.getDestPort();
2108             sendTrapPdu(peer.getDestAddr(), pdu);
2109         }
2110         else {
2111             pdu.port = getTrapPort().intValue();
2112             sendTrapPdu(pdu);
2113         }
2114     }
2115 
2116     /**
2117      * Send the specified trap PDU to every destinations from the ACL file.
2118      */
2119     private void sendTrapPdu(SnmpPduPacket pdu)
2120      throws SnmpStatusException, IOException {
2121 
2122         // Make an SNMP message from the pdu
2123         //
2124         SnmpMessage msg = null ;
2125         try {
2126             msg = (SnmpMessage)pduFactory.encodeSnmpPdu(pdu, bufferSize) ;
2127             if (msg == null) {
2128                 throw new SnmpStatusException(
2129                           SnmpDefinitions.snmpRspAuthorizationError) ;
2130             }
2131         }
2132         catch (SnmpTooBigException x) {
2133             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
2134                 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
2135                     "sendTrapPdu", "Trap pdu is too big. " +
2136                      "Trap hasn't been sent to anyone" );
2137             }
2138             throw new SnmpStatusException(SnmpDefinitions.snmpRspTooBig) ;
2139             // FIXME: is the right exception to throw ?
2140             // We could simply forward SnmpTooBigException ?
2141         }
2142 
2143         // Now send the SNMP message to each destination
2144         //
2145         int sendingCount = 0 ;
2146         openTrapSocketIfNeeded() ;
2147         if (ipacl != null) {
2148             Enumeration<InetAddress> ed = ipacl.getTrapDestinations() ;
2149             while (ed.hasMoreElements()) {
2150                 msg.address = ed.nextElement() ;
2151                 Enumeration<String> ec = ipacl.getTrapCommunities(msg.address) ;
2152                 while (ec.hasMoreElements()) {
2153                     msg.community = ec.nextElement().getBytes() ;
2154                     try {
2155                         sendTrapMessage(msg) ;
2156                         sendingCount++ ;
2157                     }
2158                     catch (SnmpTooBigException x) {
2159                         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
2160                             SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
2161                                 "sendTrapPdu", "Trap pdu is too big. " +
2162                                  "Trap hasn't been sent to "+msg.address);
2163                         }
2164                     }
2165                 }
2166             }
2167         }
2168 
2169         // If there is no destination defined or if everything has failed
2170         // we tried to send the trap to the local host (as suggested by
2171         // mister Olivier Reisacher).
2172         //
2173         if (sendingCount == 0) {
2174             try {
2175                 msg.address = InetAddress.getLocalHost() ;
2176                 sendTrapMessage(msg) ;
2177             } catch (SnmpTooBigException x) {
2178                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
2179                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
2180                         "sendTrapPdu", "Trap pdu is too big. " +
2181                          "Trap hasn't been sent.");
2182                 }
2183             } catch (UnknownHostException e) {
2184                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
2185                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
2186                         "sendTrapPdu", "Trap pdu is too big. " +
2187                          "Trap hasn't been sent.");
2188                 }
2189             }
2190         }
2191 
2192         closeTrapSocketIfNeeded() ;
2193     }
2194 
2195     /**
2196      * Send the specified trap PDU to the specified destination.
2197      */
2198     private void sendTrapPdu(InetAddress addr, SnmpPduPacket pdu)
2199         throws SnmpStatusException, IOException {
2200 
2201         // Make an SNMP message from the pdu
2202         //
2203         SnmpMessage msg = null ;
2204         try {
2205             msg = (SnmpMessage)pduFactory.encodeSnmpPdu(pdu, bufferSize) ;
2206             if (msg == null) {
2207                 throw new SnmpStatusException(
2208                           SnmpDefinitions.snmpRspAuthorizationError) ;
2209             }
2210         } catch (SnmpTooBigException x) {
2211             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
2212                 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
2213                     "sendTrapPdu", "Trap pdu is too big. " +
2214                      "Trap hasn't been sent to the specified host.");
2215             }
2216             throw new SnmpStatusException(SnmpDefinitions.snmpRspTooBig) ;
2217             // FIXME: is the right exception to throw ?
2218             // We could simply forward SnmpTooBigException ?
2219         }
2220 
2221         // Now send the SNMP message to specified destination
2222         //
2223         openTrapSocketIfNeeded() ;
2224         if (addr != null) {
2225             msg.address = addr;
2226             try {
2227                 sendTrapMessage(msg) ;
2228             } catch (SnmpTooBigException x) {
2229                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
2230                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
2231                         "sendTrapPdu", "Trap pdu is too big. " +
2232                          "Trap hasn't been sent to " +  msg.address);
2233                 }
2234             }
2235         }
2236 
2237         closeTrapSocketIfNeeded() ;
2238     }
2239 
2240     /**
2241      * Send the specified message on trapSocket.
2242      */
2243     private void sendTrapMessage(SnmpMessage msg)
2244         throws IOException, SnmpTooBigException {
2245 
2246         byte[] buffer = new byte[bufferSize] ;
2247         DatagramPacket packet = new DatagramPacket(buffer, buffer.length) ;
2248         int encodingLength = msg.encodeMessage(buffer) ;
2249         packet.setLength(encodingLength) ;
2250         packet.setAddress(msg.address) ;
2251         packet.setPort(msg.port) ;
2252         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2253             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2254                 "sendTrapMessage", "sending trap to " + msg.address + ":" +
2255                   msg.port);
2256         }
2257         trapSocket.send(packet) ;
2258         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2259             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2260                 "sendTrapMessage", "sent to " + msg.address + ":" +
2261                   msg.port);
2262         }
2263         snmpOutTraps++;
2264         snmpOutPkts++;
2265     }
2266 
2267     /**
2268      * Open trapSocket if it's not already done.
2269      */
2270     synchronized void openTrapSocketIfNeeded() throws SocketException {
2271         if (trapSocket == null) {
2272             trapSocket = new DatagramSocket(0, address) ;
2273             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2274                 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2275                     "openTrapSocketIfNeeded", "using port " +
2276                       trapSocket.getLocalPort() + " to send traps");
2277             }
2278         }
2279     }
2280 
2281     /**
2282      * Close trapSocket if the SNMP protocol adaptor is not ONLINE.
2283      */
2284     synchronized void closeTrapSocketIfNeeded() {
2285         if ((trapSocket != null) && (state != ONLINE)) {
2286             trapSocket.close() ;
2287             trapSocket = null ;
2288         }
2289     }
2290 
2291     // SENDING SNMP INFORMS STUFF
2292     //---------------------------
2293 
2294     /**
2295      * Sends an inform using SNMP V2 inform request format.
2296      * <BR>The inform request is sent to each destination defined in the ACL
2297      * file (if available).
2298      * If no ACL file or no destinations are available, the inform request is
2299      * sent to the local host.
2300      * <BR>The variable list included in the outgoing inform is composed of
2301      * the following items:
2302      * <UL>
2303      * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
2304      * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
2305      *     <CODE>trapOid</CODE></LI>
2306      * <LI><CODE>all the (oid,values)</CODE> from the specified
2307      *     <CODE>varBindList</CODE></LI>
2308      * </UL>
2309      * To send an inform request, the SNMP adaptor server must be active.
2310      *
2311      * @param cb The callback that is invoked when a request is complete.
2312      * @param trapOid The OID identifying the trap.
2313      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
2314      *
2315      * @return A vector of {@link com.sun.jmx.snmp.daemon.SnmpInformRequest}
2316      *         objects.
2317      *         <P>If there is no destination host for this inform request,
2318      *         the returned vector will be empty.
2319      *
2320      * @exception IllegalStateException  This method has been invoked while
2321      *            the SNMP adaptor server was not active.
2322      * @exception IOException An I/O error occurred while sending the
2323      *            inform request.
2324      * @exception SnmpStatusException If the inform request exceeds the
2325      *            limit defined by <CODE>bufferSize</CODE>.
2326      */
2327     @Override
2328     public Vector<SnmpInformRequest> snmpInformRequest(SnmpInformHandler cb,
2329                                                        SnmpOid trapOid,
2330                                                        SnmpVarBindList varBindList)
2331         throws IllegalStateException, IOException, SnmpStatusException {
2332 
2333         if (!isActive()) {
2334             throw new IllegalStateException(
2335                "Start SNMP adaptor server before carrying out this operation");
2336         }
2337         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2338             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2339                 "snmpInformRequest", "trapOid=" + trapOid);
2340         }
2341 
2342         // First, make an SNMP inform pdu:
2343         // We clone varBindList and insert sysUpTime and snmpTrapOid variables.
2344         //
2345         SnmpVarBindList fullVbl ;
2346         if (varBindList != null)
2347             fullVbl = varBindList.clone() ;
2348         else
2349             fullVbl = new SnmpVarBindList(2) ;
2350         SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
2351         fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
2352         fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
2353                                 0);
2354 
2355         // Next, send the pdu to the specified destination
2356         //
2357         openInformSocketIfNeeded() ;
2358 
2359         // Now send the SNMP message to each destination
2360         //
2361         Vector<SnmpInformRequest> informReqList = new Vector<>();
2362         InetAddress addr;
2363         String cs;
2364         if (ipacl != null) {
2365             Enumeration<InetAddress> ed = ipacl.getInformDestinations() ;
2366             while (ed.hasMoreElements()) {
2367                 addr = ed.nextElement() ;
2368                 Enumeration<String> ec = ipacl.getInformCommunities(addr) ;
2369                 while (ec.hasMoreElements()) {
2370                     cs = ec.nextElement() ;
2371                     informReqList.addElement(
2372                        informSession.makeAsyncRequest(addr, cs, cb,
2373                                               fullVbl,getInformPort())) ;
2374                 }
2375             }
2376         }
2377 
2378         return informReqList ;
2379     }
2380 
2381     /**
2382      * Sends an inform using SNMP V2 inform request format.
2383      * <BR>The inform is sent to the specified <CODE>InetAddress</CODE>
2384      * destination
2385      * using the specified community string.
2386      * <BR>The variable list included in the outgoing inform is composed
2387      *     of the following items:
2388      * <UL>
2389      * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
2390      * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
2391      *      <CODE>trapOid</CODE></LI>
2392      * <LI><CODE>all the (oid,values)</CODE> from the specified
2393      *     <CODE>varBindList</CODE></LI>
2394      * </UL>
2395      * To send an inform request, the SNMP adaptor server must be active.
2396      *
2397      * @param addr The <CODE>InetAddress</CODE> destination for this inform
2398      *             request.
2399      * @param cs The community string to be used for the inform request.
2400      * @param cb The callback that is invoked when a request is complete.
2401      * @param trapOid The OID identifying the trap.
2402      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
2403      *
2404      * @return The inform request object.
2405      *
2406      * @exception IllegalStateException  This method has been invoked
2407      *            while the SNMP adaptor server was not active.
2408      * @exception IOException An I/O error occurred while sending the
2409      *            inform request.
2410      * @exception SnmpStatusException If the inform request exceeds the
2411      *            limit defined by <CODE>bufferSize</CODE>.
2412      */
2413     @Override
2414     public SnmpInformRequest snmpInformRequest(InetAddress addr,
2415                                                String cs,
2416                                                SnmpInformHandler cb,
2417                                                SnmpOid trapOid,
2418                                                SnmpVarBindList varBindList)
2419         throws IllegalStateException, IOException, SnmpStatusException {
2420 
2421         return snmpInformRequest(addr,
2422                                  getInformPort(),
2423                                  cs,
2424                                  cb,
2425                                  trapOid,
2426                                  varBindList);
2427     }
2428 
2429     /**
2430      * Sends an inform using SNMP V2 inform request format.
2431      * <BR>The inform is sent to the specified <CODE>SnmpPeer</CODE>
2432      *     destination.
2433      * <BR>The community string used is the one located in the
2434      *     <CODE>SnmpPeer</CODE> parameters
2435      *     (<CODE>SnmpParameters.getInformCommunity() </CODE>).
2436      * <BR>The variable list included in the outgoing inform is composed
2437      *     of the following items:
2438      * <UL>
2439      * <LI><CODE>sysUpTime.0</CODE> with its current value</LI>
2440      * <LI><CODE>snmpTrapOid.0</CODE> with the value specified by
2441      *     <CODE>trapOid</CODE></LI>
2442      * <LI><CODE>all the (oid,values)</CODE> from the specified
2443      *     <CODE>varBindList</CODE></LI>
2444      * </UL>
2445      * To send an inform request, the SNMP adaptor server must be active.
2446      *
2447      * @param peer The <CODE>SnmpPeer</CODE> destination for this inform
2448      *             request.
2449      * @param cb The callback that is invoked when a request is complete.
2450      * @param trapOid The OID identifying the trap.
2451      * @param varBindList A list of <CODE>SnmpVarBind</CODE> instances or null.
2452      *
2453      * @return The inform request object.
2454      *
2455      * @exception IllegalStateException  This method has been invoked while
2456      *            the SNMP adaptor server was not active.
2457      * @exception IOException An I/O error occurred while sending the
2458      *            inform request.
2459      * @exception SnmpStatusException If the inform request exceeds the
2460      *            limit defined by <CODE>bufferSize</CODE>.
2461      *
2462      * @since 1.5
2463      */
2464     @Override
2465     public SnmpInformRequest snmpInformRequest(SnmpPeer peer,
2466                                                SnmpInformHandler cb,
2467                                                SnmpOid trapOid,
2468                                                SnmpVarBindList varBindList)
2469         throws IllegalStateException, IOException, SnmpStatusException {
2470 
2471         SnmpParameters p = (SnmpParameters) peer.getParams();
2472         return snmpInformRequest(peer.getDestAddr(),
2473                                  peer.getDestPort(),
2474                                  p.getInformCommunity(),
2475                                  cb,
2476                                  trapOid,
2477                                  varBindList);
2478     }
2479 
2480     /**
2481      * Method that maps an SNMP error status in the passed protocolVersion
2482      * according to the provided pdu type.
2483      * @param errorStatus The error status to convert.
2484      * @param protocolVersion The protocol version.
2485      * @param reqPduType The pdu type.
2486      */
2487     public static int mapErrorStatus(int errorStatus,
2488                                      int protocolVersion,
2489                                      int reqPduType) {
2490         return SnmpSubRequestHandler.mapErrorStatus(errorStatus,
2491                                                     protocolVersion,
2492                                                     reqPduType);
2493     }
2494 
2495     private SnmpInformRequest snmpInformRequest(InetAddress addr,
2496                                                 int port,
2497                                                 String cs,
2498                                                 SnmpInformHandler cb,
2499                                                 SnmpOid trapOid,
2500                                                 SnmpVarBindList varBindList)
2501         throws IllegalStateException, IOException, SnmpStatusException {
2502 
2503         if (!isActive()) {
2504             throw new IllegalStateException(
2505               "Start SNMP adaptor server before carrying out this operation");
2506         }
2507         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2508             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2509                 "snmpInformRequest", "trapOid=" + trapOid);
2510         }
2511 
2512         // First, make an SNMP inform pdu:
2513         // We clone varBindList and insert sysUpTime and snmpTrapOid variables.
2514         //
2515         SnmpVarBindList fullVbl ;
2516         if (varBindList != null)
2517             fullVbl = varBindList.clone() ;
2518         else
2519             fullVbl = new SnmpVarBindList(2) ;
2520         SnmpTimeticks sysUpTimeValue = new SnmpTimeticks(getSysUpTime()) ;
2521         fullVbl.insertElementAt(new SnmpVarBind(snmpTrapOidOid, trapOid), 0) ;
2522         fullVbl.insertElementAt(new SnmpVarBind(sysUpTimeOid, sysUpTimeValue),
2523                                 0);
2524 
2525         // Next, send the pdu to the specified destination
2526         //
2527         openInformSocketIfNeeded() ;
2528         return informSession.makeAsyncRequest(addr, cs, cb, fullVbl, port) ;
2529     }
2530 
2531 
2532     /**
2533      * Open informSocket if it's not already done.
2534      */
2535     synchronized void openInformSocketIfNeeded() throws SocketException {
2536         if (informSession == null) {
2537             informSession = new SnmpSession(this) ;
2538             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2539                 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2540                    "openInformSocketIfNeeded",
2541                       "to send inform requests and receive inform responses");
2542             }
2543         }
2544     }
2545 
2546     /**
2547      * Close informSocket if the SNMP protocol adaptor is not ONLINE.
2548      */
2549     synchronized void closeInformSocketIfNeeded() {
2550         if ((informSession != null) && (state != ONLINE)) {
2551             informSession.destroySession() ;
2552             informSession = null ;
2553         }
2554     }
2555 
2556     /**
2557      * Gets the IP address to bind.
2558      * This getter is used to initialize the DatagramSocket in the
2559      * SnmpSocket object created for the inform request stuff.
2560      */
2561     InetAddress getAddress() {
2562         return address;
2563     }
2564 
2565 
2566     // PROTECTED METHODS
2567     //------------------
2568 
2569     /**
2570      * Finalizer of the SNMP protocol adaptor objects.
2571      * This method is called by the garbage collector on an object
2572      * when garbage collection determines that there are no more
2573      * references to the object.
2574      * <P>Closes the datagram socket associated to this SNMP protocol adaptor.
2575      */
2576     @Override
2577     protected void finalize() {
2578         try {
2579             if (socket != null) {
2580                 socket.close() ;
2581                 socket = null ;
2582             }
2583 
2584             threadService.terminate();
2585         } catch (Exception e) {
2586             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
2587                 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,
2588                    "finalize", "Exception in finalizer", e);
2589             }
2590         }
2591     }
2592 
2593     // PACKAGE METHODS
2594     //----------------
2595 
2596     /**
2597      * Returns the string used in debug traces.
2598      */
2599     @Override
2600     String makeDebugTag() {
2601         return "SnmpAdaptorServer["+ getProtocol() + ":" + getPort() + "]";
2602     }
2603 
2604     void updateRequestCounters(int pduType) {
2605         switch(pduType)  {
2606 
2607         case pduGetRequestPdu:
2608             snmpInGetRequests++;
2609             break;
2610         case pduGetNextRequestPdu:
2611             snmpInGetNexts++;
2612             break;
2613         case pduSetRequestPdu:
2614             snmpInSetRequests++;
2615             break;
2616         default:
2617             break;
2618         }
2619         snmpInPkts++ ;
2620     }
2621 
2622     void updateErrorCounters(int errorStatus) {
2623         switch(errorStatus) {
2624 
2625         case snmpRspNoError:
2626             snmpOutGetResponses++;
2627             break;
2628         case snmpRspGenErr:
2629             snmpOutGenErrs++;
2630             break;
2631         case snmpRspBadValue:
2632             snmpOutBadValues++;
2633             break;
2634         case snmpRspNoSuchName:
2635             snmpOutNoSuchNames++;
2636             break;
2637         case snmpRspTooBig:
2638             snmpOutTooBigs++;
2639             break;
2640         default:
2641             break;
2642         }
2643         snmpOutPkts++ ;
2644     }
2645 
2646     void updateVarCounters(int pduType, int n) {
2647         switch(pduType) {
2648 
2649         case pduGetRequestPdu:
2650         case pduGetNextRequestPdu:
2651         case pduGetBulkRequestPdu:
2652             snmpInTotalReqVars += n ;
2653             break ;
2654         case pduSetRequestPdu:
2655             snmpInTotalSetVars += n ;
2656             break ;
2657         }
2658     }
2659 
2660     void incSnmpInASNParseErrs(int n) {
2661         snmpInASNParseErrs += n ;
2662     }
2663 
2664     void incSnmpInBadVersions(int n) {
2665         snmpInBadVersions += n ;
2666     }
2667 
2668     void incSnmpInBadCommunityUses(int n) {
2669         snmpInBadCommunityUses += n ;
2670     }
2671 
2672     void incSnmpInBadCommunityNames(int n) {
2673         snmpInBadCommunityNames += n ;
2674     }
2675 
2676     void incSnmpSilentDrops(int n) {
2677         snmpSilentDrops += n ;
2678     }
2679     // PRIVATE METHODS
2680     //----------------
2681 
2682     /**
2683      * Returns the time (in hundreths of second) elapsed since the SNMP
2684      * protocol adaptor startup.
2685      */
2686     long getSysUpTime() {
2687         return (System.currentTimeMillis() - startUpTime) / 10 ;
2688     }
2689 
2690     /**
2691      * Control the way the SnmpAdaptorServer service is deserialized.
2692      */
2693     private void readObject(ObjectInputStream stream)
2694         throws IOException, ClassNotFoundException {
2695 
2696         // Call the default deserialization of the object.
2697         //
2698         stream.defaultReadObject();
2699 
2700         // Call the specific initialization for the SnmpAdaptorServer service.
2701         // This is for transient structures to be initialized to specific
2702         // default values.
2703         //
2704         mibs      = new Vector<>() ;
2705     }
2706 
2707     /**
2708      * Common initializations.
2709      */
2710     private void init(InetAddressAcl acl, int p, InetAddress a) {
2711 
2712         root= new SnmpMibTree();
2713 
2714         // The default Agent is initialized with a SnmpErrorHandlerAgent agent.
2715         root.setDefaultAgent(new SnmpErrorHandlerAgent());
2716 
2717         // For the trap time, use the time the agent started ...
2718         //
2719         startUpTime= java.lang.System.currentTimeMillis();
2720         maxActiveClientCount = 10;
2721 
2722         // Create the default message factory
2723         pduFactory = new SnmpPduFactoryBER() ;
2724 
2725         port = p ;
2726         ipacl = acl ;
2727         address = a ;
2728 
2729         if ((ipacl == null) && (useAcl == true))
2730             throw new IllegalArgumentException("ACL object cannot be null") ;
2731 
2732         threadService = new ThreadService(threadNumber);
2733     }
2734 
2735     SnmpMibAgent getAgentMib(SnmpOid oid) {
2736         return root.getAgentMib(oid);
2737     }
2738 
2739     @Override
2740     protected Thread createMainThread() {
2741         final Thread t = super.createMainThread();
2742         t.setDaemon(true);
2743         return t;
2744     }
2745 
2746 }