1. /*
  2. * @(#)file SnmpRequestTree.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 1.26
  5. * @(#)date 04/09/15
  6. *
  7. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  8. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  9. */
  10. package com.sun.jmx.snmp.agent;
  11. import java.util.Vector;
  12. import java.util.ArrayList;
  13. import java.util.Hashtable;
  14. import java.util.Enumeration;
  15. import java.util.Iterator;
  16. import java.util.List;
  17. import java.util.NoSuchElementException;
  18. import java.util.Arrays;
  19. import com.sun.jmx.snmp.SnmpVarBind;
  20. import com.sun.jmx.snmp.SnmpStatusException;
  21. import com.sun.jmx.snmp.SnmpDefinitions;
  22. import com.sun.jmx.snmp.SnmpOid;
  23. import com.sun.jmx.snmp.SnmpPdu;
  24. import com.sun.jmx.snmp.SnmpEngine;
  25. import com.sun.jmx.trace.Trace;
  26. // XXX: things to do: use SnmpOid rather than `instance' for future
  27. // evolutions.
  28. // XXX: Maybe use hashlists rather than vectors for entries?
  29. // => in that case, the key should be SnmpOid.toString()
  30. //
  31. /**
  32. * This class is used to register varbinds from a SNMP varbind list with
  33. * the SnmpMibNode responsible for handling the requests concerning that
  34. * varbind.
  35. * This class holds a hashtable of Handler nodes, whith the involved
  36. * SnmpMibNode as a key.
  37. * When the involved SnmpMibNode is a group, the sublist of varbind is
  38. * directly stored in the Handler node.
  39. * When the involved SnmpMibNode is a table, the sublist is stored in a
  40. * sorted array indexed by the OID of the entry involved.
  41. */
  42. final class SnmpRequestTree {
  43. // Constructor:
  44. // @param req The SnmpMibRequest that will be segmented in this
  45. // tree. It holds the original varbind vector passed
  46. // by the SnmpSubRequestHandler to this MIB. This
  47. // varbind vector is used to retrieve the "real"
  48. // position of a varbind in the vector. There is no other easy
  49. // way to do this - since as a result of the segmentation the
  50. // original positions will be lost.
  51. // @param creationflag indicates whether the operation involved
  52. // allows for entry creation (ie: it is a SET request).
  53. // @param pdutype indicates the type of the request PDU as defined
  54. // in SnmpDefinitions
  55. //
  56. SnmpRequestTree(SnmpMibRequest req, boolean creationflag, int pdutype) {
  57. this.request = req;
  58. this.version = req.getVersion();
  59. this.creationflag = creationflag;
  60. this.hashtable = new Hashtable();
  61. setPduType(pdutype);
  62. }
  63. public static int mapSetException(int errorStatus, int version)
  64. throws SnmpStatusException {
  65. final int errorCode = errorStatus;
  66. if (version == SnmpDefinitions.snmpVersionOne)
  67. return errorCode;
  68. int mappedErrorCode = errorCode;
  69. // Now take care of V2 errorCodes that can be stored
  70. // in the varbind itself:
  71. if (errorCode == SnmpStatusException.noSuchObject)
  72. // noSuchObject => notWritable
  73. mappedErrorCode = SnmpStatusException.snmpRspNotWritable;
  74. else if (errorCode == SnmpStatusException.noSuchInstance)
  75. // noSuchInstance => notWritable
  76. mappedErrorCode = SnmpStatusException.snmpRspNotWritable;
  77. return mappedErrorCode;
  78. }
  79. public static int mapGetException(int errorStatus, int version)
  80. throws SnmpStatusException {
  81. final int errorCode = errorStatus;
  82. if (version == SnmpDefinitions.snmpVersionOne)
  83. return errorCode;
  84. int mappedErrorCode = errorCode;
  85. // Now take care of V2 errorCodes that can be stored
  86. // in the varbind itself:
  87. if (errorCode ==
  88. SnmpStatusException.noSuchObject)
  89. // noSuchObject => noSuchObject
  90. mappedErrorCode = errorCode;
  91. else if (errorCode ==
  92. SnmpStatusException.noSuchInstance)
  93. // noSuchInstance => noSuchInstance
  94. mappedErrorCode = errorCode;
  95. // Now we're going to try to transform every other
  96. // global code in either noSuchInstance or noSuchObject,
  97. // so that the get can return a partial result.
  98. //
  99. // Only noSuchInstance or noSuchObject can be stored
  100. // in the varbind itself.
  101. //
  102. // According to RFC 1905: noAccess is emitted when the
  103. // the access is denied because it is not in the MIB view...
  104. //
  105. else if (errorCode ==
  106. SnmpStatusException.noAccess)
  107. // noAccess => noSuchInstance
  108. mappedErrorCode = SnmpStatusException.noSuchInstance;
  109. // According to RFC 1905: (my interpretation because it is not
  110. // really clear) The specified variable name exists - but the
  111. // variable does not exists and cannot be created under the
  112. // present circumstances (probably because the request specifies
  113. // another variable/value which is incompatible, or because the
  114. // value of some other variable in the MIB prevents the creation)
  115. //
  116. // Note that this error should never be raised in a GET context
  117. // but who knows?
  118. //
  119. else if (errorCode == SnmpStatusException.snmpRspInconsistentName)
  120. // inconsistentName => noSuchInstance
  121. mappedErrorCode = SnmpStatusException.noSuchInstance;
  122. // All the errors comprised between snmpRspWrongType and
  123. // snmpRspInconsistentValue concern values: so we're going
  124. // to assume the OID was correct, and reply with noSuchInstance.
  125. //
  126. // Note that this error should never be raised in a GET context
  127. // but who knows?
  128. //
  129. else if ((errorCode >= SnmpStatusException.snmpRspWrongType) &&
  130. (errorCode <= SnmpStatusException.snmpRspInconsistentValue))
  131. mappedErrorCode = SnmpStatusException.noSuchInstance;
  132. // We're going to assume the OID was correct, and reply
  133. // with noSuchInstance.
  134. //
  135. else if (errorCode == SnmpStatusException.readOnly)
  136. mappedErrorCode = SnmpStatusException.noSuchInstance;
  137. // For all other errors but genErr, we're going to reply with
  138. // noSuchObject
  139. //
  140. else if (errorCode != SnmpStatusException.snmpRspAuthorizationError &&
  141. errorCode != SnmpStatusException.snmpRspGenErr)
  142. mappedErrorCode = SnmpStatusException.noSuchObject;
  143. // Only genErr will abort the GET and be returned as global
  144. // error.
  145. //
  146. return mappedErrorCode;
  147. }
  148. //-------------------------------------------------------------------
  149. // This class is a package implementation of the enumeration of
  150. // SnmSubRequest associated with an Handler node.
  151. //-------------------------------------------------------------------
  152. static final class Enum implements Enumeration {
  153. Enum(SnmpRequestTree hlist,Handler h) {
  154. handler = h;
  155. this.hlist = hlist;
  156. size = h.getSubReqCount();
  157. }
  158. private final Handler handler;
  159. private final SnmpRequestTree hlist;
  160. private int entry = 0;
  161. private int iter = 0;
  162. private int size = 0;
  163. public boolean hasMoreElements() {
  164. return iter < size;
  165. }
  166. public Object nextElement() throws NoSuchElementException {
  167. if (iter == 0) {
  168. if (handler.sublist != null) {
  169. iter++;
  170. return hlist.getSubRequest(handler);
  171. }
  172. }
  173. iter ++;
  174. if (iter > size) throw new NoSuchElementException();
  175. Object result = hlist.getSubRequest(handler,entry);
  176. entry++;
  177. return result;
  178. }
  179. }
  180. //-------------------------------------------------------------------
  181. // This class is a package implementation of the SnmpMibSubRequest
  182. // interface. It can only be instantiated by SnmpRequestTree.
  183. //-------------------------------------------------------------------
  184. static final class SnmpMibSubRequestImpl implements SnmpMibSubRequest {
  185. SnmpMibSubRequestImpl(SnmpMibRequest global, Vector sublist,
  186. SnmpOid entryoid, boolean isnew,
  187. boolean getnextflag, SnmpVarBind rs) {
  188. this.global = global;
  189. varbinds = sublist;
  190. this.version = global.getVersion();
  191. this.entryoid = entryoid;
  192. this.isnew = isnew;
  193. this.getnextflag = getnextflag;
  194. this.statusvb = rs;
  195. }
  196. final private Vector varbinds;
  197. final private SnmpMibRequest global;
  198. final private int version;
  199. final private boolean isnew;
  200. final private SnmpOid entryoid;
  201. final private boolean getnextflag;
  202. final private SnmpVarBind statusvb;
  203. // -------------------------------------------------------------
  204. // Implements the method defined in SnmpMibRequest interface.
  205. // See SnmpMibRequest for the java doc.
  206. // -------------------------------------------------------------
  207. public Enumeration getElements() {
  208. return varbinds.elements();
  209. }
  210. // -------------------------------------------------------------
  211. // Implements the method defined in SnmpMibRequest interface.
  212. // See SnmpMibRequest for the java doc.
  213. // -------------------------------------------------------------
  214. public Vector getSubList() {
  215. return varbinds;
  216. }
  217. // -------------------------------------------------------------
  218. // Implements the method defined in SnmpMibRequest interface.
  219. // See SnmpMibRequest for the java doc.
  220. // -------------------------------------------------------------
  221. public final int getSize() {
  222. if (varbinds == null) return 0;
  223. return varbinds.size();
  224. }
  225. // -------------------------------------------------------------
  226. // Implements the method defined in SnmpMibRequest interface.
  227. // See SnmpMibRequest for the java doc.
  228. // -------------------------------------------------------------
  229. public void addVarBind(SnmpVarBind varbind) {
  230. // XXX not sure we must also add the varbind in the global
  231. // request? or whether we should raise an exception:
  232. // in principle, this method should not be called!
  233. varbinds.addElement(varbind);
  234. global.addVarBind(varbind);
  235. }
  236. // -------------------------------------------------------------
  237. // Implements the method defined in SnmpMibSubRequest interface.
  238. // See SnmpMibSubRequest for the java doc.
  239. // -------------------------------------------------------------
  240. public boolean isNewEntry() {
  241. return isnew;
  242. }
  243. // -------------------------------------------------------------
  244. // Implements the method defined in SnmpMibSubRequest interface.
  245. // See SnmpMibSubRequest for the java doc.
  246. // -------------------------------------------------------------
  247. public SnmpOid getEntryOid() {
  248. return entryoid;
  249. }
  250. // -------------------------------------------------------------
  251. // Implements the method defined in SnmpMibRequest interface.
  252. // See SnmpMibRequest for the java doc.
  253. // -------------------------------------------------------------
  254. public int getVarIndex(SnmpVarBind varbind) {
  255. if (varbind == null) return 0;
  256. return global.getVarIndex(varbind);
  257. }
  258. // -------------------------------------------------------------
  259. // Implements the method defined in SnmpMibRequest interface.
  260. // See SnmpMibRequest for the java doc.
  261. // -------------------------------------------------------------
  262. public Object getUserData() { return global.getUserData(); }
  263. // -------------------------------------------------------------
  264. // Implements the method defined in SnmpMibSubRequest interface.
  265. // See SnmpMibSubRequest for the java doc.
  266. // -------------------------------------------------------------
  267. public void registerGetException(SnmpVarBind var,
  268. SnmpStatusException exception)
  269. throws SnmpStatusException {
  270. // The index in the exception must correspond to
  271. // the SNMP index ...
  272. //
  273. if (version == SnmpDefinitions.snmpVersionOne)
  274. throw new SnmpStatusException(exception, getVarIndex(var)+1);
  275. if (var == null)
  276. throw exception;
  277. // If we're doing a getnext ==> endOfMibView
  278. if (getnextflag) {
  279. var.value = SnmpVarBind.endOfMibView;
  280. return;
  281. }
  282. final int errorCode = mapGetException(exception.getStatus(),
  283. version);
  284. // Now take care of V2 errorCodes that can be stored
  285. // in the varbind itself:
  286. if (errorCode ==
  287. SnmpStatusException.noSuchObject)
  288. // noSuchObject => noSuchObject
  289. var.value= SnmpVarBind.noSuchObject;
  290. else if (errorCode ==
  291. SnmpStatusException.noSuchInstance)
  292. // noSuchInstance => noSuchInstance
  293. var.value= SnmpVarBind.noSuchInstance;
  294. else
  295. throw new SnmpStatusException(errorCode, getVarIndex(var)+1);
  296. }
  297. // -------------------------------------------------------------
  298. // Implements the method defined in SnmpMibSubRequest interface.
  299. // See SnmpMibSubRequest for the java doc.
  300. // -------------------------------------------------------------
  301. public void registerSetException(SnmpVarBind var,
  302. SnmpStatusException exception)
  303. throws SnmpStatusException {
  304. // The index in the exception must correspond to
  305. // the SNMP index ...
  306. //
  307. if (version == SnmpDefinitions.snmpVersionOne)
  308. throw new SnmpStatusException(exception, getVarIndex(var)+1);
  309. // Although the first pass of check() did not fail,
  310. // the set() phase could not be carried out correctly.
  311. // Since we don't know how to make an "undo", and some
  312. // assignation may already have been performed, we're going
  313. // to throw an snmpRspUndoFailed.
  314. //
  315. throw new SnmpStatusException(SnmpDefinitions.snmpRspUndoFailed,
  316. getVarIndex(var)+1);
  317. }
  318. // -------------------------------------------------------------
  319. // Implements the method defined in SnmpMibSubRequest interface.
  320. // See SnmpMibSubRequest for the java doc.
  321. // -------------------------------------------------------------
  322. public void registerCheckException(SnmpVarBind var,
  323. SnmpStatusException exception)
  324. throws SnmpStatusException {
  325. // The index in the exception must correspond to
  326. // the SNMP index ...
  327. //
  328. // We throw the exception in order to abort the SET operation
  329. // in an atomic way.
  330. final int errorCode = exception.getStatus();
  331. final int mappedErrorCode = mapSetException(errorCode,
  332. version);
  333. if (errorCode != mappedErrorCode)
  334. throw new
  335. SnmpStatusException(mappedErrorCode, getVarIndex(var)+1);
  336. else
  337. throw new SnmpStatusException(exception, getVarIndex(var)+1);
  338. }
  339. // -------------------------------------------------------------
  340. // Implements the method defined in SnmpMibRequest interface.
  341. // See SnmpMibRequest for the java doc.
  342. // -------------------------------------------------------------
  343. public int getVersion() {
  344. return version;
  345. }
  346. public SnmpVarBind getRowStatusVarBind() {
  347. return statusvb;
  348. }
  349. public SnmpPdu getPdu() {
  350. return global.getPdu();
  351. }
  352. public int getRequestPduVersion() {
  353. return global.getRequestPduVersion();
  354. }
  355. public SnmpEngine getEngine() {
  356. return global.getEngine();
  357. }
  358. public String getPrincipal() {
  359. return global.getPrincipal();
  360. }
  361. public int getSecurityLevel() {
  362. return global.getSecurityLevel();
  363. }
  364. public int getSecurityModel() {
  365. return global.getSecurityModel();
  366. }
  367. public byte[] getContextName() {
  368. return global.getContextName();
  369. }
  370. public byte[] getAccessContextName() {
  371. return global.getAccessContextName();
  372. }
  373. }
  374. //-------------------------------------------------------------------
  375. // This class implements a node in the SnmpRequestTree.
  376. // It stores:
  377. // o The SnmpMibNode involved (key)
  378. // o The sublist of varbind directly handled by this node
  379. // o A vector of sublists concerning the entries (existing or not)
  380. // of the SnmpMIbNode (when it is a table).
  381. //-------------------------------------------------------------------
  382. static final class Handler {
  383. SnmpMibNode meta; // The meta which handles the sublist.
  384. int depth; // The depth of the meta node.
  385. Vector sublist; // The sublist of varbinds to be handled.
  386. // List entryoids; // Sorted array of entry oids
  387. // List entrylists; // Sorted array of entry lists
  388. // List isentrynew; // Sorted array of booleans
  389. SnmpOid[] entryoids = null; // Sorted array of entry oids
  390. Vector[] entrylists = null; // Sorted array of entry lists
  391. boolean[] isentrynew = null; // Sorted array of booleans
  392. SnmpVarBind[] rowstatus = null; // RowStatus varbind, if any
  393. int entrycount = 0;
  394. int entrysize = 0;
  395. final int type; // request PDU type as defined in SnmpDefinitions
  396. final private static int Delta = 10;
  397. public Handler(int pduType) {
  398. this.type = pduType;
  399. }
  400. /**
  401. * Adds a varbind in this node sublist.
  402. */
  403. public void addVarbind(SnmpVarBind varbind) {
  404. if (sublist == null) sublist = new Vector();
  405. sublist.addElement(varbind);
  406. }
  407. /**
  408. * register an entry for the given oid at the given position with
  409. * the given sublist.
  410. */
  411. void add(int pos,SnmpOid oid, Vector v, boolean isnew,
  412. SnmpVarBind statusvb) {
  413. if (entryoids == null) {
  414. // Vectors are null: Allocate new vectors
  415. entryoids = new SnmpOid[Delta];
  416. entrylists = new Vector[Delta];
  417. isentrynew = new boolean[Delta];
  418. rowstatus = new SnmpVarBind[Delta];
  419. entrysize = Delta;
  420. pos = 0;
  421. } else if (pos >= entrysize || entrycount == entrysize) {
  422. // Vectors must be enlarged
  423. // Save old vectors
  424. SnmpOid[] olde = entryoids;
  425. Vector[] oldl = entrylists;
  426. boolean[] oldn = isentrynew;
  427. SnmpVarBind[] oldr = rowstatus;
  428. // Allocate larger vectors
  429. entrysize += Delta;
  430. entryoids = new SnmpOid[entrysize];
  431. entrylists = new Vector[entrysize];
  432. isentrynew = new boolean[entrysize];
  433. rowstatus = new SnmpVarBind[entrysize];
  434. // Check pos validity
  435. if (pos > entrycount) pos = entrycount;
  436. if (pos < 0) pos = 0;
  437. final int l1 = pos;
  438. final int l2 = entrycount - pos;
  439. // Copy original vectors up to `pos'
  440. if (l1 > 0) {
  441. java.lang.System.arraycopy(olde,0,entryoids,
  442. 0,l1);
  443. java.lang.System.arraycopy(oldl,0,entrylists,
  444. 0,l1);
  445. java.lang.System.arraycopy(oldn,0,isentrynew,
  446. 0,l1);
  447. java.lang.System.arraycopy(oldr,0,rowstatus,
  448. 0,l1);
  449. }
  450. // Copy original vectors from `pos' to end, leaving
  451. // an empty room at `pos' in the new vectors.
  452. if (l2 > 0) {
  453. final int l3 = l1+1;
  454. java.lang.System.arraycopy(olde,l1,entryoids,
  455. l3,l2);
  456. java.lang.System.arraycopy(oldl,l1,entrylists,
  457. l3,l2);
  458. java.lang.System.arraycopy(oldn,l1,isentrynew,
  459. l3,l2);
  460. java.lang.System.arraycopy(oldr,l1,rowstatus,
  461. l3,l2);
  462. }
  463. } else if (pos < entrycount) {
  464. // Vectors are large enough to accomodate one additional
  465. // entry.
  466. //
  467. // Shift vectors, making an empty room at `pos'
  468. final int l1 = pos+1;
  469. final int l2 = entrycount - pos;
  470. java.lang.System.arraycopy(entryoids,pos,entryoids,
  471. l1,l2);
  472. java.lang.System.arraycopy(entrylists,pos,entrylists,
  473. l1,l2);
  474. java.lang.System.arraycopy(isentrynew,pos,isentrynew,
  475. l1,l2);
  476. java.lang.System.arraycopy(rowstatus,pos,rowstatus,
  477. l1,l2);
  478. }
  479. // Fill the gap at `pos'
  480. entryoids[pos] = oid;
  481. entrylists[pos] = v;
  482. isentrynew[pos] = isnew;
  483. rowstatus[pos] = statusvb;
  484. entrycount++;
  485. }
  486. public void addVarbind(SnmpVarBind varbind, SnmpOid entryoid,
  487. boolean isnew, SnmpVarBind statusvb)
  488. throws SnmpStatusException {
  489. Vector v = null;
  490. SnmpVarBind rs = statusvb;
  491. if (entryoids == null) {
  492. // entryoids = new ArrayList();
  493. // entrylists = new ArrayList();
  494. // isentrynew = new ArrayList();
  495. v = new Vector();
  496. // entryoids.add(entryoid);
  497. // entrylists.add(v);
  498. // isentrynew.add(new Boolean(isnew));
  499. add(0,entryoid,v,isnew,rs);
  500. } else {
  501. // int pos = findOid(entryoids,entryoid);
  502. // int pos = findOid(entryoids,entrycount,entryoid);
  503. final int pos =
  504. getInsertionPoint(entryoids,entrycount,entryoid);
  505. if (pos > -1 && pos < entrycount &&
  506. entryoid.compareTo(entryoids[pos]) == 0) {
  507. v = entrylists[pos];
  508. rs = rowstatus[pos];
  509. } else {
  510. // if (pos == -1 || pos >= entryoids.size() ) {
  511. // if (pos == -1 || pos >= entrycount ) {
  512. // pos = getInsertionPoint(entryoids,entryoid);
  513. // pos = getInsertionPoint(entryoids,entrycount,entryoid);
  514. v = new Vector();
  515. // entryoids.add(pos,entryoid);
  516. // entrylists.add(pos,v);
  517. // isentrynew.add(pos,new Boolean(isnew));
  518. add(pos,entryoid,v,isnew,rs);
  519. }
  520. // } else v = (Vector) entrylists.get(pos);
  521. // } else v = entrylists[pos];
  522. if (statusvb != null) {
  523. if ((rs != null) && (rs != statusvb) &&
  524. ((type == SnmpDefinitions.pduWalkRequest) ||
  525. (type == SnmpDefinitions.pduSetRequestPdu))) {
  526. throw new SnmpStatusException(
  527. SnmpStatusException.snmpRspInconsistentValue);
  528. }
  529. rowstatus[pos] = statusvb;
  530. }
  531. }
  532. // We do not include the status variable in the varbind,
  533. // because we're going to set it separately...
  534. //
  535. if (statusvb != varbind)
  536. v.addElement(varbind);
  537. }
  538. public int getSubReqCount() {
  539. int count = 0;
  540. if (sublist != null) count++;
  541. // if (entryoids != null) count += entryoids.size();
  542. if (entryoids != null) count += entrycount;
  543. return count;
  544. }
  545. public Vector getSubList() {
  546. return sublist;
  547. }
  548. public int getEntryPos(SnmpOid entryoid) {
  549. // return findOid(entryoids,entryoid);
  550. return findOid(entryoids,entrycount,entryoid);
  551. }
  552. public SnmpOid getEntryOid(int pos) {
  553. if (entryoids == null) return null;
  554. // if (pos == -1 || pos >= entryoids.size() ) return null;
  555. if (pos == -1 || pos >= entrycount ) return null;
  556. // return (SnmpOid) entryoids.get(pos);
  557. return (SnmpOid) entryoids[pos];
  558. }
  559. public boolean isNewEntry(int pos) {
  560. if (entryoids == null) return false;
  561. // if (pos == -1 || pos >= entryoids.size() ) return false;
  562. if (pos == -1 || pos >= entrycount ) return false;
  563. // return ((Boolean)isentrynew.get(pos)).booleanValue();
  564. return isentrynew[pos];
  565. }
  566. public SnmpVarBind getRowStatusVarBind(int pos) {
  567. if (entryoids == null) return null;
  568. // if (pos == -1 || pos >= entryoids.size() ) return false;
  569. if (pos == -1 || pos >= entrycount ) return null;
  570. // return ((Boolean)isentrynew.get(pos)).booleanValue();
  571. return rowstatus[pos];
  572. }
  573. public Vector getEntrySubList(int pos) {
  574. if (entrylists == null) return null;
  575. // if (pos == -1 || pos >= entrylists.size() ) return null;
  576. if (pos == -1 || pos >= entrycount ) return null;
  577. // return (Vector) entrylists.get(pos);
  578. return entrylists[pos];
  579. }
  580. public Iterator getEntryOids() {
  581. if (entryoids == null) return null;
  582. // return entryoids.iterator();
  583. return Arrays.asList(entryoids).iterator();
  584. }
  585. public int getEntryCount() {
  586. if (entryoids == null) return 0;
  587. // return entryoids.size();
  588. return entrycount;
  589. }
  590. }
  591. //-------------------------------------------------------------------
  592. //-------------------------------------------------------------------
  593. // Public interface
  594. //-------------------------------------------------------------------
  595. //-------------------------------------------------------------------
  596. //-------------------------------------------------------------------
  597. // Returns the contextual object containing user-data allocated
  598. // through the SnmpUserDataFactory for this request.
  599. //-------------------------------------------------------------------
  600. public Object getUserData() { return request.getUserData(); }
  601. //-------------------------------------------------------------------
  602. // Tells whether creation of new entries is allowed with respect
  603. // to the operation involved (GET=>false/SET=>true)
  604. //-------------------------------------------------------------------
  605. public boolean isCreationAllowed() {
  606. return creationflag;
  607. }
  608. //-------------------------------------------------------------------
  609. // Tells whether we are currently processing a SET request (check/set)
  610. //-------------------------------------------------------------------
  611. public boolean isSetRequest() {
  612. return setreqflag;
  613. }
  614. //-------------------------------------------------------------------
  615. // Returns the protocol version in which the original request is
  616. // evaluated.
  617. //-------------------------------------------------------------------
  618. public int getVersion() {
  619. return version;
  620. }
  621. //-------------------------------------------------------------------
  622. // Returns the actual protocol version of the request PDU.
  623. //-------------------------------------------------------------------
  624. public int getRequestPduVersion() {
  625. return request.getRequestPduVersion();
  626. }
  627. //-------------------------------------------------------------------
  628. // Returns the SnmpMibNode associated with the given handler
  629. //-------------------------------------------------------------------
  630. public SnmpMibNode getMetaNode(Handler handler) {
  631. return handler.meta;
  632. }
  633. //-------------------------------------------------------------------
  634. // Indicates the depth of the arc in the OID that identifies the
  635. // SnmpMibNode associated with the given handler
  636. //-------------------------------------------------------------------
  637. public int getOidDepth(Handler handler) {
  638. return handler.depth;
  639. }
  640. //-------------------------------------------------------------------
  641. // returns an enumeration of the SnmpMibSubRequest's to be invoked on
  642. // the SnmpMibNode associated with a given Handler node.
  643. // If this node is a group, there will be a single subrequest.
  644. // If it is a table, there will be one subrequest per entry involved.
  645. //-------------------------------------------------------------------
  646. public Enumeration getSubRequests(Handler handler) {
  647. return new Enum(this,handler);
  648. }
  649. //-------------------------------------------------------------------
  650. // returns an enumeration of the Handlers stored in the Hashtable.
  651. //-------------------------------------------------------------------
  652. public Enumeration getHandlers() {
  653. return hashtable.elements();
  654. }
  655. //-------------------------------------------------------------------
  656. // adds a varbind to a handler node sublist
  657. //-------------------------------------------------------------------
  658. public void add(SnmpMibNode meta, int depth, SnmpVarBind varbind)
  659. throws SnmpStatusException {
  660. registerNode(meta,depth,null,varbind,false,null);
  661. }
  662. //-------------------------------------------------------------------
  663. // adds an entry varbind to a handler node sublist
  664. //-------------------------------------------------------------------
  665. public void add(SnmpMibNode meta, int depth, SnmpOid entryoid,
  666. SnmpVarBind varbind, boolean isnew)
  667. throws SnmpStatusException {
  668. registerNode(meta,depth,entryoid,varbind,isnew,null);
  669. }
  670. //-------------------------------------------------------------------
  671. // adds an entry varbind to a handler node sublist - specifying the
  672. // varbind which holds the row status
  673. //-------------------------------------------------------------------
  674. public void add(SnmpMibNode meta, int depth, SnmpOid entryoid,
  675. SnmpVarBind varbind, boolean isnew,
  676. SnmpVarBind statusvb)
  677. throws SnmpStatusException {
  678. registerNode(meta,depth,entryoid,varbind,isnew,statusvb);
  679. }
  680. //-------------------------------------------------------------------
  681. //-------------------------------------------------------------------
  682. // Protected interface
  683. //-------------------------------------------------------------------
  684. //-------------------------------------------------------------------
  685. //-------------------------------------------------------------------
  686. // Type of the request (see SnmpDefinitions)
  687. //-------------------------------------------------------------------
  688. void setPduType(int pduType) {
  689. type = pduType;
  690. setreqflag = ((pduType == SnmpDefinitions.pduWalkRequest) ||
  691. (pduType == SnmpDefinitions.pduSetRequestPdu));
  692. }
  693. //-------------------------------------------------------------------
  694. // We deal with a GET-NEXT request
  695. //-------------------------------------------------------------------
  696. void setGetNextFlag() {
  697. getnextflag = true;
  698. }
  699. //-------------------------------------------------------------------
  700. // Tell whether creation is allowed.
  701. //-------------------------------------------------------------------
  702. void switchCreationFlag(boolean flag) {
  703. creationflag = flag;
  704. }
  705. //-------------------------------------------------------------------
  706. // Returns the subrequest handled by the SnmpMibNode itself
  707. // (in principle, only for Groups)
  708. //-------------------------------------------------------------------
  709. SnmpMibSubRequest getSubRequest(Handler handler) {
  710. if (handler == null) return null;
  711. return new SnmpMibSubRequestImpl(request,handler.getSubList(),
  712. null,false,getnextflag,null);
  713. }
  714. //-------------------------------------------------------------------
  715. // Returns the subrequest associated with the entry identified by
  716. // the given entry (only for tables)
  717. //-------------------------------------------------------------------
  718. SnmpMibSubRequest getSubRequest(Handler handler, SnmpOid oid) {
  719. if (handler == null) return null;
  720. final int pos = handler.getEntryPos(oid);
  721. if (pos == -1) return null;
  722. return new SnmpMibSubRequestImpl(request,
  723. handler.getEntrySubList(pos),
  724. handler.getEntryOid(pos),
  725. handler.isNewEntry(pos),
  726. getnextflag,
  727. handler.getRowStatusVarBind(pos));
  728. }
  729. //-------------------------------------------------------------------
  730. // Returns the subrequest associated with the entry identified by
  731. // the given entry (only for tables). The `entry' parameter is an
  732. // index relative to the position of the entry in the handler sublist.
  733. //-------------------------------------------------------------------
  734. SnmpMibSubRequest getSubRequest(Handler handler, int entry) {
  735. if (handler == null) return null;
  736. return new
  737. SnmpMibSubRequestImpl(request,handler.getEntrySubList(entry),
  738. handler.getEntryOid(entry),
  739. handler.isNewEntry(entry),getnextflag,
  740. handler.getRowStatusVarBind(entry));
  741. }
  742. //-------------------------------------------------------------------
  743. //-------------------------------------------------------------------
  744. // Private section
  745. //-------------------------------------------------------------------
  746. //-------------------------------------------------------------------
  747. //-------------------------------------------------------------------
  748. // stores a handler node in the Hashtable
  749. //-------------------------------------------------------------------
  750. private void put(Object key, Handler handler) {
  751. if (handler == null) return;
  752. if (key == null) return;
  753. if (hashtable == null) hashtable = new Hashtable();
  754. hashtable.put(key,handler);
  755. }
  756. //-------------------------------------------------------------------
  757. // finds a handler node in the Hashtable
  758. //-------------------------------------------------------------------
  759. private Handler get(Object key) {
  760. if (key == null) return null;
  761. if (hashtable == null) return null;
  762. return (Handler) hashtable.get(key);
  763. }
  764. //-------------------------------------------------------------------
  765. // Search for the given oid in `oids'. If none is found, returns -1
  766. // otherwise, returns the index at which the oid is located.
  767. //-------------------------------------------------------------------
  768. private static int findOid(SnmpOid[] oids, int count, SnmpOid oid) {
  769. final int size = count;
  770. int low= 0;
  771. int max= size - 1;
  772. int curr= low + (max-low)/2;
  773. //System.out.println("Try to retrieve: " + oid.toString());
  774. while (low <= max) {
  775. final SnmpOid pos = oids[curr];
  776. //System.out.println("Compare with" + pos.toString());
  777. // never know ...we might find something ...
  778. //
  779. final int comp = oid.compareTo(pos);
  780. if (comp == 0)
  781. return curr;
  782. if (oid.equals(pos)) {
  783. return curr;
  784. }
  785. if (comp > 0) {
  786. low = curr + 1;
  787. } else {
  788. max = curr - 1;
  789. }
  790. curr = low + (max-low)/2;
  791. }
  792. return -1;
  793. }
  794. //-------------------------------------------------------------------
  795. // Return the index at which the given oid should be inserted in the
  796. // `oids' array.
  797. //-------------------------------------------------------------------
  798. private static int getInsertionPoint(SnmpOid[] oids, int count,
  799. SnmpOid oid) {
  800. final SnmpOid[] localoids = oids;
  801. final int size = count;
  802. int low= 0;
  803. int max= size - 1;
  804. int curr= low + (max-low)/2;
  805. while (low <= max) {
  806. final SnmpOid pos = localoids[curr];
  807. // never know ...we might find something ...
  808. //
  809. final int comp= oid.compareTo(pos);
  810. // In the calling method we will have to check for this case...
  811. // if (comp == 0)
  812. // return -1;
  813. // Returning curr instead of -1 avoids having to call
  814. // findOid() first and getInsertionPoint() afterwards.
  815. // We can simply call getInsertionPoint() and then checks whether
  816. // there's an OID at the returned position which equals the
  817. // given OID.
  818. if (comp == 0)
  819. return curr;
  820. if (comp>0) {
  821. low= curr +1;
  822. } else {
  823. max= curr -1;
  824. }
  825. curr= low + (max-low)/2;
  826. }
  827. return curr;
  828. }
  829. //-------------------------------------------------------------------
  830. // adds a varbind in a handler node sublist
  831. //-------------------------------------------------------------------
  832. private void registerNode(SnmpMibNode meta, int depth, SnmpOid entryoid,
  833. SnmpVarBind varbind, boolean isnew,
  834. SnmpVarBind statusvb)
  835. throws SnmpStatusException {
  836. if (meta == null) {
  837. if (isDebugOn())
  838. debug("registerNode","meta-node is null!!!");
  839. return;
  840. }
  841. if (varbind == null) {
  842. if (isDebugOn())
  843. debug("registerNode","varbind is null!!!");
  844. return ;
  845. }
  846. final Object key = meta;
  847. // retrieve the handler node associated with the given meta,
  848. // if any
  849. Handler handler = get(key);
  850. // If no handler node was found for that meta, create one.
  851. if (handler == null) {
  852. // if (isDebugOn())
  853. // debug("registerNode", "adding node for " +
  854. // varbind.oid.toString());
  855. handler = new Handler(type);
  856. handler.meta = meta;
  857. handler.depth = depth;
  858. put(key,handler);
  859. }
  860. // else {
  861. // if (isDebugOn())
  862. // debug("registerNode","found node for " +
  863. // varbind.oid.toString());
  864. // }
  865. // Adds the varbind in the handler node's sublist.
  866. if (entryoid == null)
  867. handler.addVarbind(varbind);
  868. else
  869. handler.addVarbind(varbind,entryoid,isnew,statusvb);
  870. return ;
  871. }
  872. private final static boolean isDebugOn() {
  873. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
  874. }
  875. private final static void debug(String func, String info) {
  876. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP,
  877. "SnmpRequestTree", func, info);
  878. }
  879. //-------------------------------------------------------------------
  880. // private variables
  881. //-------------------------------------------------------------------
  882. private Hashtable hashtable = null; // Hashtable of Handler objects
  883. private SnmpMibRequest request = null; // The original list of varbinds
  884. private int version = 0; // The protocol version
  885. private boolean creationflag = false; // Does the operation allow
  886. // creation of entries
  887. private boolean getnextflag = false; // Does the operation allow
  888. // creation of entries
  889. private int type = 0; // Request PDU type as defined
  890. // in SnmpDefinitions
  891. private boolean setreqflag = false; // True if we're processing a
  892. // SET request (check/set).
  893. }