1 /*
   2  * Copyright (c) 1998, 2013, 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 
  31 // java import
  32 //
  33 import java.util.Enumeration;
  34 import java.util.logging.Level;
  35 // jmx imports
  36 //
  37 import com.sun.jmx.snmp.SnmpPdu;
  38 import com.sun.jmx.snmp.SnmpVarBind;
  39 import com.sun.jmx.snmp.SnmpOid;
  40 import com.sun.jmx.snmp.SnmpValue;
  41 import com.sun.jmx.snmp.SnmpDefinitions;
  42 import com.sun.jmx.snmp.SnmpStatusException;
  43 import com.sun.jmx.snmp.SnmpEngine;
  44 // SNMP Runtime import
  45 //
  46 import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
  47 import com.sun.jmx.snmp.agent.SnmpMibAgent;
  48 import com.sun.jmx.snmp.internal.SnmpIncomingRequest;
  49 import com.sun.jmx.snmp.ThreadContext;
  50 
  51 class SnmpSubBulkRequestHandler extends SnmpSubRequestHandler {
  52     private SnmpAdaptorServer server = null;
  53 
  54     /**
  55      * The constructor initialize the subrequest with the whole varbind list contained
  56      * in the original request.
  57      */
  58     protected SnmpSubBulkRequestHandler(SnmpEngine engine,
  59                                         SnmpAdaptorServer server,
  60                                         SnmpIncomingRequest incRequest,
  61                                         SnmpMibAgent agent,
  62                                         SnmpPdu req,
  63                                         int nonRepeat,
  64                                         int maxRepeat,
  65                                         int R) {
  66         super(engine, incRequest, agent, req);
  67         init(server, req, nonRepeat, maxRepeat, R);
  68     }
  69 
  70     /**
  71      * The constructor initialize the subrequest with the whole varbind list contained
  72      * in the original request.
  73      */
  74     protected SnmpSubBulkRequestHandler(SnmpAdaptorServer server,
  75                                         SnmpMibAgent agent,
  76                                         SnmpPdu req,
  77                                         int nonRepeat,
  78                                         int maxRepeat,
  79                                         int R) {
  80         super(agent, req);
  81         init(server, req, nonRepeat, maxRepeat, R);
  82     }
  83 
  84     @Override
  85     public void run() {
  86 
  87         size= varBind.size();
  88 
  89         try {
  90             // Invoke a getBulk operation
  91             //
  92             /* NPCTE fix for bugId 4492741, esc 0, 16-August-2001 */
  93             final ThreadContext oldContext =
  94                 ThreadContext.push("SnmpUserData",data);
  95             try {
  96                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
  97                     SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
  98                         "run", "[" + Thread.currentThread() +
  99                         "]:getBulk operation on " + agent.getMibName());
 100                 }
 101                 agent.getBulk(createMibRequest(varBind,version,data),
 102                               nonRepeat, maxRepeat);
 103             } finally {
 104                 ThreadContext.restore(oldContext);
 105             }
 106             /* end of NPCTE fix for bugId 4492741 */
 107 
 108         } catch(SnmpStatusException x) {
 109             errorStatus = x.getStatus() ;
 110             errorIndex=  x.getErrorIndex();
 111             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
 112                 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(),
 113                     "run", "[" + Thread.currentThread() +
 114                     "]:an Snmp error occurred during the operation", x);
 115             }
 116         }
 117         catch(Exception x) {
 118             errorStatus = SnmpDefinitions.snmpRspGenErr ;
 119             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
 120                 SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(),
 121                     "run", "[" + Thread.currentThread() +
 122                     "]:a generic error occurred during the operation", x);
 123             }
 124         }
 125         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 126             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 127                 "run", "[" + Thread.currentThread() +
 128                   "]:operation completed");
 129         }
 130     }
 131 
 132     private void init(SnmpAdaptorServer server,
 133                       SnmpPdu req,
 134                       int nonRepeat,
 135                       int maxRepeat,
 136                       int R) {
 137         this.server = server;
 138         this.nonRepeat= nonRepeat;
 139         this.maxRepeat= maxRepeat;
 140         this.globalR= R;
 141 
 142         final int max= translation.length;
 143         final SnmpVarBind[] list= req.varBindList;
 144         final NonSyncVector<SnmpVarBind> nonSyncVarBind =
 145                 ((NonSyncVector<SnmpVarBind>)varBind);
 146         for(int i=0; i < max; i++) {
 147             translation[i]= i;
 148             // we need to allocate a new SnmpVarBind. Otherwise the first
 149             // sub request will modify the list...
 150             //
 151             final SnmpVarBind newVarBind =
 152                 new SnmpVarBind(list[i].oid, list[i].value);
 153             nonSyncVarBind.addNonSyncElement(newVarBind);
 154         }
 155     }
 156 
 157     /**
 158      * The method updates find out which element to use at update time. Handle oid overlapping as well
 159      */
 160     private SnmpVarBind findVarBind(SnmpVarBind element,
 161                                     SnmpVarBind result) {
 162 
 163         if (element == null) return null;
 164 
 165         if (result.oid == null) {
 166              return element;
 167         }
 168 
 169         if (element.value == SnmpVarBind.endOfMibView) return result;
 170 
 171         if (result.value == SnmpVarBind.endOfMibView) return element;
 172 
 173         final SnmpValue val = result.value;
 174 
 175         int comp = element.oid.compareTo(result.oid);
 176         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 177             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 178                 "findVarBind","Comparing OID element : " + element.oid +
 179                   " with result : " + result.oid);
 180             SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 181                 "findVarBind","Values element : " + element.value +
 182                   " result : " + result.value);
 183         }
 184         if (comp < 0) {
 185             // Take the smallest (lexicographically)
 186             //
 187             return element;
 188         }
 189         else {
 190             if(comp == 0) {
 191                 // Must compare agent used for reply
 192                 // Take the deeper within the reply
 193                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 194                     SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 195                         "findVarBind"," oid overlapping. Oid : " +
 196                           element.oid + "value :" + element.value);
 197                     SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 198                          "findVarBind","Already present varBind : " +
 199                           result);
 200                 }
 201                 SnmpOid oid = result.oid;
 202                 SnmpMibAgent deeperAgent = server.getAgentMib(oid);
 203 
 204                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 205                     SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 206                         "findVarBind","Deeper agent : " + deeperAgent);
 207                 }
 208                 if(deeperAgent == agent) {
 209                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 210                         SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 211                             "findVarBind","The current agent is the deeper one. Update the value with the current one");
 212                     }
 213                     return element;
 214                 } else {
 215                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 216                         SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 217                             "findVarBind","The current agent is not the deeper one. return the previous one.");
 218                     }
 219                     return result;
 220                 }
 221 
 222                 /*
 223                    Vector v = new Vector();
 224                    SnmpMibRequest getReq = createMibRequest(v,
 225                    version,
 226                    null);
 227                    SnmpVarBind realValue = new SnmpVarBind(oid);
 228                    getReq.addVarBind(realValue);
 229                    try {
 230                    deeperAgent.get(getReq);
 231                    } catch(SnmpStatusException e) {
 232                    e.printStackTrace();
 233                    }
 234 
 235                    if(isDebugOn())
 236                    trace("findVarBind", "Biggest priority value is : " +
 237                    realValue.value);
 238 
 239                    return realValue;
 240                 */
 241 
 242             }
 243             else {
 244                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 245                     SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 246                         "findVarBind","The right varBind is the already present one");
 247                 }
 248                 return result;
 249             }
 250         }
 251     }
 252     /**
 253      * The method updates a given var bind list with the result of a
 254      * previsouly invoked operation.
 255      * Prior to calling the method, one must make sure that the operation was
 256      * successful. As such the method getErrorIndex or getErrorStatus should be
 257      * called.
 258      */
 259     @Override
 260     protected void updateResult(SnmpVarBind[] result) {
 261         // we can assume that the run method is over ...
 262         //
 263 
 264         final Enumeration<SnmpVarBind> e= varBind.elements();
 265         final int max= result.length;
 266 
 267         // First go through all the values once ...
 268         for(int i=0; i < size; i++) {
 269             // May be we should control the position ...
 270             //
 271             if (e.hasMoreElements() == false)
 272                 return;
 273 
 274             // bugId 4641694: must check position in order to avoid
 275             //       ArrayIndexOutOfBoundException
 276             final int pos=translation[i];
 277             if (pos >= max) {
 278                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
 279                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpSubRequestHandler.class.getName(),
 280                         "updateResult","Position '"+pos+"' is out of bound...");
 281                 }
 282                 continue;
 283             }
 284 
 285             final SnmpVarBind element= e.nextElement();
 286 
 287             if (element == null) continue;
 288             if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 289                 SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 290                     "updateResult","Non repeaters Current element : " +
 291                       element + " from agent : " + agent);
 292             }
 293             final SnmpVarBind res = findVarBind(element,result[pos]);
 294 
 295             if(res == null) continue;
 296 
 297             result[pos] = res;
 298         }
 299 
 300         // Now update the values which have been repeated
 301         // more than once.
 302         int localR= size - nonRepeat;
 303         for (int i = 2 ; i <= maxRepeat ; i++) {
 304             for (int r = 0 ; r < localR ; r++) {
 305                 final int pos = (i-1)* globalR + translation[nonRepeat + r] ;
 306                 if (pos >= max)
 307                     return;
 308                 if (e.hasMoreElements() ==false)
 309                     return;
 310                 final SnmpVarBind element= e.nextElement();
 311 
 312                 if (element == null) continue;
 313                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {
 314                     SNMP_ADAPTOR_LOGGER.logp(Level.FINER, SnmpSubRequestHandler.class.getName(),
 315                         "updateResult","Repeaters Current element : " +
 316                           element + " from agent : " + agent);
 317                 }
 318                 final SnmpVarBind res = findVarBind(element, result[pos]);
 319 
 320                 if(res == null) continue;
 321 
 322                 result[pos] = res;
 323             }
 324         }
 325     }
 326 
 327     // PROTECTED VARIABLES
 328     //------------------
 329 
 330     /**
 331      * Specific to the sub request
 332      */
 333     protected int nonRepeat=0;
 334 
 335     protected int maxRepeat=0;
 336 
 337     /**
 338      * R as defined in RCF 1902 for the global request the sub-request is associated to.
 339      */
 340     protected int globalR=0;
 341 
 342     protected int size=0;
 343 }