1. /*
  2. * @(#)file SnmpSubRequestHandler.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 4.37
  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. */
  11. package com.sun.jmx.snmp.daemon;
  12. // java import
  13. //
  14. import java.util.Vector;
  15. // jmx imports
  16. //
  17. import com.sun.jmx.snmp.SnmpPdu;
  18. import com.sun.jmx.snmp.SnmpVarBind;
  19. import com.sun.jmx.snmp.SnmpDefinitions;
  20. import com.sun.jmx.snmp.SnmpStatusException;
  21. import com.sun.jmx.snmp.SnmpEngine;
  22. // RI imports
  23. //
  24. import com.sun.jmx.trace.Trace;
  25. // SNMP Runtime import
  26. //
  27. import com.sun.jmx.snmp.agent.SnmpMibAgent;
  28. import com.sun.jmx.snmp.agent.SnmpMibRequest;
  29. import com.sun.jmx.snmp.ThreadContext;
  30. import com.sun.jmx.snmp.internal.SnmpIncomingRequest;
  31. class SnmpSubRequestHandler implements SnmpDefinitions, Runnable {
  32. protected SnmpIncomingRequest incRequest = null;
  33. protected SnmpEngine engine = null;
  34. /**
  35. * V3 enabled Adaptor. Each Oid is added using updateRequest method.
  36. */
  37. protected SnmpSubRequestHandler(SnmpEngine engine,
  38. SnmpIncomingRequest incRequest,
  39. SnmpMibAgent agent,
  40. SnmpPdu req) {
  41. this(agent, req);
  42. init(engine, incRequest);
  43. }
  44. /**
  45. * V3 enabled Adaptor.
  46. */
  47. protected SnmpSubRequestHandler(SnmpEngine engine,
  48. SnmpIncomingRequest incRequest,
  49. SnmpMibAgent agent,
  50. SnmpPdu req,
  51. boolean nouse) {
  52. this(agent, req, nouse);
  53. init(engine, incRequest);
  54. }
  55. /**
  56. * SNMP V1/V2 . To be called with updateRequest.
  57. */
  58. protected SnmpSubRequestHandler(SnmpMibAgent agent, SnmpPdu req) {
  59. dbgTag = makeDebugTag();
  60. if (isTraceOn()) {
  61. trace("constructor", "creating instance for request " + String.valueOf(req.requestId));
  62. }
  63. version= req.version;
  64. type= req.type;
  65. this.agent= agent;
  66. // We get a ref on the pdu in order to pass it to SnmpMibRequest.
  67. reqPdu = req;
  68. //Pre-allocate room for storing varbindlist and translation table.
  69. //
  70. int length= req.varBindList.length;
  71. translation= new int[length];
  72. varBind= new NonSyncVector(length);
  73. }
  74. /**
  75. * SNMP V1/V2 The constuctor initialize the subrequest with the whole varbind list contained
  76. * in the original request.
  77. */
  78. protected SnmpSubRequestHandler(SnmpMibAgent agent,
  79. SnmpPdu req,
  80. boolean nouse) {
  81. this(agent,req);
  82. // The translation table is easy in this case ...
  83. //
  84. int max= translation.length;
  85. SnmpVarBind[] list= req.varBindList;
  86. for(int i=0; i < max; i++) {
  87. translation[i]= i;
  88. ((NonSyncVector)varBind).addNonSyncElement(list[i]);
  89. }
  90. }
  91. SnmpMibRequest createMibRequest(Vector vblist,
  92. int protocolVersion,
  93. Object userData) {
  94. // This is an optimization:
  95. // The SnmpMibRequest created in the check() phase is
  96. // reused in the set() phase.
  97. //
  98. if (type == pduSetRequestPdu && mibRequest != null)
  99. return mibRequest;
  100. //This is a request comming from an SnmpV3AdaptorServer.
  101. //Full power.
  102. SnmpMibRequest result = null;
  103. if(incRequest != null) {
  104. result = SnmpMibAgent.newMibRequest(engine,
  105. reqPdu,
  106. vblist,
  107. protocolVersion,
  108. userData,
  109. incRequest.getPrincipal(),
  110. incRequest.getSecurityLevel(),
  111. incRequest.getSecurityModel(),
  112. incRequest.getContextName(),
  113. incRequest.getAccessContext());
  114. } else {
  115. result = SnmpMibAgent.newMibRequest(reqPdu,
  116. vblist,
  117. protocolVersion,
  118. userData);
  119. }
  120. // If we're doing the check() phase, we store the SnmpMibRequest
  121. // so that we can reuse it in the set() phase.
  122. //
  123. if (type == pduWalkRequest)
  124. mibRequest = result;
  125. return result;
  126. }
  127. void setUserData(Object userData) {
  128. data = userData;
  129. }
  130. public void run() {
  131. try {
  132. final ThreadContext oldContext =
  133. ThreadContext.push("SnmpUserData",data);
  134. try {
  135. switch(type) {
  136. case pduGetRequestPdu:
  137. // Invoke a get operation
  138. //
  139. if (isTraceOn()) {
  140. trace("run", "[" + Thread.currentThread() +
  141. "]:get operation on " + agent.getMibName());
  142. }
  143. agent.get(createMibRequest(varBind,version,data));
  144. break;
  145. case pduGetNextRequestPdu:
  146. if (isTraceOn()) {
  147. trace("run", "[" + Thread.currentThread() +
  148. "]:getNext operation on " + agent.getMibName());
  149. }
  150. //#ifdef DEBUG
  151. agent.getNext(createMibRequest(varBind,version,data));
  152. break;
  153. case pduSetRequestPdu:
  154. if (isTraceOn()) {
  155. trace("run", "[" + Thread.currentThread() +
  156. "]:set operation on " + agent.getMibName());
  157. }
  158. agent.set(createMibRequest(varBind,version,data));
  159. break;
  160. case pduWalkRequest:
  161. if (isTraceOn()) {
  162. trace("run", "[" + Thread.currentThread() +
  163. "]:check operation on " + agent.getMibName());
  164. }
  165. agent.check(createMibRequest(varBind,version,data));
  166. break;
  167. default:
  168. if (isDebugOn()) {
  169. debug("run", "[" + Thread.currentThread() +
  170. "]:unknown operation (" + type + ") on " +
  171. agent.getMibName());
  172. }
  173. errorStatus= snmpRspGenErr;
  174. errorIndex= 1;
  175. break;
  176. }// end of switch
  177. } finally {
  178. ThreadContext.restore(oldContext);
  179. }
  180. } catch(SnmpStatusException x) {
  181. errorStatus = x.getStatus() ;
  182. errorIndex= x.getErrorIndex();
  183. if (isDebugOn()) {
  184. debug("run", "[" + Thread.currentThread() +
  185. "]:an Snmp error occured during the operation");
  186. debug("run", x);
  187. }
  188. }
  189. catch(Exception x) {
  190. errorStatus = SnmpDefinitions.snmpRspGenErr ;
  191. if (isTraceOn()) {
  192. trace("run", "[" + Thread.currentThread() +
  193. "]:a generic error occured during the operation");
  194. }
  195. if (isDebugOn()) {
  196. debug("run", "Error is: " + x);
  197. debug("run", x);
  198. }
  199. }
  200. if (isTraceOn()) {
  201. trace("run", "[" + Thread.currentThread() +
  202. "]:operation completed");
  203. }
  204. }
  205. // -------------------------------------------------------------
  206. //
  207. // This function does a best-effort to map global error status
  208. // to SNMP v1 valid global error status.
  209. //
  210. // An SnmpStatusException can contain either:
  211. // <li> v2 local error codes (that should be stored in the varbind)</li>
  212. // <li> v2 global error codes </li>
  213. // <li> v1 global error codes </li>
  214. //
  215. // v2 local error codes (noSuchInstance, noSuchObject) are
  216. // transformed in a global v1 snmpRspNoSuchName error.
  217. //
  218. // v2 global error codes are transformed in the following way:
  219. //
  220. // If the request was a GET/GETNEXT then either
  221. // snmpRspNoSuchName or snmpRspGenErr is returned.
  222. //
  223. // Otherwise:
  224. // snmpRspNoAccess, snmpRspInconsistentName
  225. // => snmpRspNoSuchName
  226. // snmpRspAuthorizationError, snmpRspNotWritable, snmpRspNoCreation
  227. // => snmpRspReadOnly (snmpRspNoSuchName for GET/GETNEXT)
  228. // snmpRspWrong*
  229. // => snmpRspBadValue (snmpRspNoSuchName for GET/GETNEXT)
  230. // snmpRspResourceUnavailable, snmpRspRspCommitFailed,
  231. // snmpRspUndoFailed
  232. // => snmpRspGenErr
  233. //
  234. // -------------------------------------------------------------
  235. //
  236. static final int mapErrorStatusToV1(int errorStatus, int reqPduType) {
  237. // Map v2 codes onto v1 codes
  238. //
  239. if (errorStatus == SnmpDefinitions.snmpRspNoError)
  240. return SnmpDefinitions.snmpRspNoError;
  241. if (errorStatus == SnmpDefinitions.snmpRspGenErr)
  242. return SnmpDefinitions.snmpRspGenErr;
  243. if (errorStatus == SnmpDefinitions.snmpRspNoSuchName)
  244. return SnmpDefinitions.snmpRspNoSuchName;
  245. if ((errorStatus == SnmpStatusException.noSuchInstance) ||
  246. (errorStatus == SnmpStatusException.noSuchObject) ||
  247. (errorStatus == SnmpDefinitions.snmpRspNoAccess) ||
  248. (errorStatus == SnmpDefinitions.snmpRspInconsistentName) ||
  249. (errorStatus == SnmpDefinitions.snmpRspAuthorizationError)){
  250. return SnmpDefinitions.snmpRspNoSuchName;
  251. } else if ((errorStatus ==
  252. SnmpDefinitions.snmpRspAuthorizationError) ||
  253. (errorStatus == SnmpDefinitions.snmpRspNotWritable)) {
  254. if (reqPduType == SnmpDefinitions.pduWalkRequest)
  255. return SnmpDefinitions.snmpRspReadOnly;
  256. else
  257. return SnmpDefinitions.snmpRspNoSuchName;
  258. } else if ((errorStatus == SnmpDefinitions.snmpRspNoCreation)) {
  259. return SnmpDefinitions.snmpRspNoSuchName;
  260. } else if ((errorStatus == SnmpDefinitions.snmpRspWrongType) ||
  261. (errorStatus == SnmpDefinitions.snmpRspWrongLength) ||
  262. (errorStatus == SnmpDefinitions.snmpRspWrongEncoding) ||
  263. (errorStatus == SnmpDefinitions.snmpRspWrongValue) ||
  264. (errorStatus == SnmpDefinitions.snmpRspWrongLength) ||
  265. (errorStatus ==
  266. SnmpDefinitions.snmpRspInconsistentValue)) {
  267. if ((reqPduType == SnmpDefinitions.pduSetRequestPdu) ||
  268. (reqPduType == SnmpDefinitions.pduWalkRequest))
  269. return SnmpDefinitions.snmpRspBadValue;
  270. else
  271. return SnmpDefinitions.snmpRspNoSuchName;
  272. } else if ((errorStatus ==
  273. SnmpDefinitions.snmpRspResourceUnavailable) ||
  274. (errorStatus ==
  275. SnmpDefinitions.snmpRspCommitFailed) ||
  276. (errorStatus == SnmpDefinitions.snmpRspUndoFailed)) {
  277. return SnmpDefinitions.snmpRspGenErr;
  278. }
  279. // At this point we should have a V1 error code
  280. //
  281. if (errorStatus == SnmpDefinitions.snmpRspTooBig)
  282. return SnmpDefinitions.snmpRspTooBig;
  283. if( (errorStatus == SnmpDefinitions.snmpRspBadValue) ||
  284. (errorStatus == SnmpDefinitions.snmpRspReadOnly)) {
  285. if ((reqPduType == SnmpDefinitions.pduSetRequestPdu) ||
  286. (reqPduType == SnmpDefinitions.pduWalkRequest))
  287. return errorStatus;
  288. else
  289. return SnmpDefinitions.snmpRspNoSuchName;
  290. }
  291. // We have a snmpRspGenErr, or something which is not defined
  292. // in RFC1905 => return a snmpRspGenErr
  293. //
  294. return SnmpDefinitions.snmpRspGenErr;
  295. }
  296. // -------------------------------------------------------------
  297. //
  298. // This function does a best-effort to map global error status
  299. // to SNMP v2 valid global error status.
  300. //
  301. // An SnmpStatusException can contain either:
  302. // <li> v2 local error codes (that should be stored in the varbind)</li>
  303. // <li> v2 global error codes </li>
  304. // <li> v1 global error codes </li>
  305. //
  306. // v2 local error codes (noSuchInstance, noSuchObject)
  307. // should not raise this level: they should have been stored in the
  308. // varbind earlier. If they, do there is nothing much we can do except
  309. // to transform them into:
  310. // <li> a global snmpRspGenErr (if the request is a GET/GETNEXT) </li>
  311. // <li> a global snmpRspNoSuchName otherwise. </li>
  312. //
  313. // v2 global error codes are transformed in the following way:
  314. //
  315. // If the request was a GET/GETNEXT then snmpRspGenErr is returned.
  316. // (snmpRspGenErr is the only global error that is expected to be
  317. // raised by a GET/GETNEXT request).
  318. //
  319. // Otherwise the v2 code itself is returned
  320. //
  321. // v1 global error codes are transformed in the following way:
  322. //
  323. // snmpRspNoSuchName
  324. // => snmpRspNoAccess (snmpRspGenErr for GET/GETNEXT)
  325. // snmpRspReadOnly
  326. // => snmpRspNotWritable (snmpRspGenErr for GET/GETNEXT)
  327. // snmpRspBadValue
  328. // => snmpRspWrongValue (snmpRspGenErr for GET/GETNEXT)
  329. //
  330. // -------------------------------------------------------------
  331. //
  332. static final int mapErrorStatusToV2(int errorStatus, int reqPduType) {
  333. // Map v1 codes onto v2 codes
  334. //
  335. if (errorStatus == SnmpDefinitions.snmpRspNoError)
  336. return SnmpDefinitions.snmpRspNoError;
  337. if (errorStatus == SnmpDefinitions.snmpRspGenErr)
  338. return SnmpDefinitions.snmpRspGenErr;
  339. if (errorStatus == SnmpDefinitions.snmpRspTooBig)
  340. return SnmpDefinitions.snmpRspTooBig;
  341. // For get / getNext / getBulk the only global error
  342. // (PDU-level) possible is genErr.
  343. //
  344. if ((reqPduType != SnmpDefinitions.pduSetRequestPdu) &&
  345. (reqPduType != SnmpDefinitions.pduWalkRequest)) {
  346. if(errorStatus == SnmpDefinitions.snmpRspAuthorizationError)
  347. return errorStatus;
  348. else
  349. return SnmpDefinitions.snmpRspGenErr;
  350. }
  351. // Map to noSuchName
  352. // if ((errorStatus == SnmpDefinitions.snmpRspNoSuchName) ||
  353. // (errorStatus == SnmpStatusException.noSuchInstance) ||
  354. // (errorStatus == SnmpStatusException.noSuchObject))
  355. // return SnmpDefinitions.snmpRspNoSuchName;
  356. // SnmpStatusException.noSuchInstance and
  357. // SnmpStatusException.noSuchObject can't happen...
  358. if (errorStatus == SnmpDefinitions.snmpRspNoSuchName)
  359. return SnmpDefinitions.snmpRspNoAccess;
  360. // Map to notWritable
  361. if (errorStatus == SnmpDefinitions.snmpRspReadOnly)
  362. return SnmpDefinitions.snmpRspNotWritable;
  363. // Map to wrongValue
  364. if (errorStatus == SnmpDefinitions.snmpRspBadValue)
  365. return SnmpDefinitions.snmpRspWrongValue;
  366. // Other valid V2 codes
  367. if ((errorStatus == SnmpDefinitions.snmpRspNoAccess) ||
  368. (errorStatus == SnmpDefinitions.snmpRspInconsistentName) ||
  369. (errorStatus == SnmpDefinitions.snmpRspAuthorizationError) ||
  370. (errorStatus == SnmpDefinitions.snmpRspNotWritable) ||
  371. (errorStatus == SnmpDefinitions.snmpRspNoCreation) ||
  372. (errorStatus == SnmpDefinitions.snmpRspWrongType) ||
  373. (errorStatus == SnmpDefinitions.snmpRspWrongLength) ||
  374. (errorStatus == SnmpDefinitions.snmpRspWrongEncoding) ||
  375. (errorStatus == SnmpDefinitions.snmpRspWrongValue) ||
  376. (errorStatus == SnmpDefinitions.snmpRspWrongLength) ||
  377. (errorStatus == SnmpDefinitions.snmpRspInconsistentValue) ||
  378. (errorStatus == SnmpDefinitions.snmpRspResourceUnavailable) ||
  379. (errorStatus == SnmpDefinitions.snmpRspCommitFailed) ||
  380. (errorStatus == SnmpDefinitions.snmpRspUndoFailed))
  381. return errorStatus;
  382. // Ivalid V2 code => genErr
  383. return SnmpDefinitions.snmpRspGenErr;
  384. }
  385. static final int mapErrorStatus(int errorStatus,
  386. int protocolVersion,
  387. int reqPduType) {
  388. if (errorStatus == SnmpDefinitions.snmpRspNoError)
  389. return SnmpDefinitions.snmpRspNoError;
  390. // Too bad, an error occurs ... we need to translate it ...
  391. //
  392. if (protocolVersion == SnmpDefinitions.snmpVersionOne)
  393. return mapErrorStatusToV1(errorStatus,reqPduType);
  394. if (protocolVersion == SnmpDefinitions.snmpVersionTwo ||
  395. protocolVersion == SnmpDefinitions.snmpVersionThree)
  396. return mapErrorStatusToV2(errorStatus,reqPduType);
  397. return SnmpDefinitions.snmpRspGenErr;
  398. }
  399. /**
  400. * The method returns the error status of the operation.
  401. * The method takes into account the protocol version.
  402. */
  403. protected int getErrorStatus() {
  404. if (errorStatus == snmpRspNoError)
  405. return snmpRspNoError;
  406. return mapErrorStatus(errorStatus,version,type);
  407. }
  408. /**
  409. * The method returns the error index as a position in the var bind list.
  410. * The value returned by the method corresponds to the index in the original
  411. * var bind list as received by the SNMP protocol adaptor.
  412. */
  413. protected int getErrorIndex() {
  414. if (errorStatus == snmpRspNoError)
  415. return -1;
  416. // An error occurs. We need to be carefull because the index
  417. // we are getting is a valid SNMP index (so range starts at 1).
  418. // FIX ME: Shall we double-check the range here ?
  419. // The response is : YES :
  420. if ((errorIndex == 0) || (errorIndex == -1))
  421. errorIndex = 1;
  422. return translation[errorIndex -1];
  423. }
  424. /**
  425. * The method updates the varbind list of the subrequest.
  426. */
  427. protected void updateRequest(SnmpVarBind var, int pos) {
  428. int size= varBind.size();
  429. translation[size]= pos;
  430. varBind.addElement(var);
  431. }
  432. /**
  433. * The method updates a given var bind list with the result of a
  434. * previsouly invoked operation.
  435. * Prior to calling the method, one must make sure that the operation was
  436. * successful. As such the method getErrorIndex or getErrorStatus should be
  437. * called.
  438. */
  439. protected void updateResult(SnmpVarBind[] result) {
  440. if (result == null) return;
  441. final int max=varBind.size();
  442. final int len=result.length;
  443. for(int i= 0; i< max ; i++) {
  444. // bugId 4641694: must check position in order to avoid
  445. // ArrayIndexOutOfBoundException
  446. final int pos=translation[i];
  447. if (pos < len) {
  448. result[pos] =
  449. (SnmpVarBind)((NonSyncVector)varBind).elementAtNonSync(i);
  450. } else {
  451. debug("updateResult","Position `"+pos+"' is out of bound...");
  452. }
  453. }
  454. }
  455. private void init(SnmpEngine engine,
  456. SnmpIncomingRequest incRequest) {
  457. this.incRequest = incRequest;
  458. this.engine = engine;
  459. }
  460. protected boolean isTraceOn() {
  461. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP);
  462. }
  463. protected void trace(String clz, String func, String info) {
  464. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
  465. }
  466. protected void trace(String func, String info) {
  467. trace(dbgTag, func, info);
  468. }
  469. protected boolean isDebugOn() {
  470. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
  471. }
  472. protected void debug(String clz, String func, String info) {
  473. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, clz, func, info);
  474. }
  475. protected void debug(String func, Throwable t) {
  476. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP, dbgTag, func, t);
  477. }
  478. protected void debug(String func, String info) {
  479. debug(dbgTag, func, info);
  480. }
  481. protected String makeDebugTag() {
  482. return "SnmpSubRequestHandler";
  483. }
  484. // PRIVATE VARIABLES
  485. //------------------
  486. protected String dbgTag = null;
  487. /**
  488. * Store the protocol version to handle
  489. */
  490. protected int version= snmpVersionOne;
  491. /**
  492. * Store the operation type. Remember if the type is Walk, it means
  493. * that we have to invoke the check method ...
  494. */
  495. protected int type= 0;
  496. /**
  497. * Agent directly handled by the sub-request handler.
  498. */
  499. protected SnmpMibAgent agent;
  500. /**
  501. * Error status.
  502. */
  503. protected int errorStatus= snmpRspNoError;
  504. /**
  505. * Index of error.
  506. * A value of -1 means no error.
  507. */
  508. protected int errorIndex= -1;
  509. /**
  510. * The varbind list specific to the current sub request.
  511. * The vector must contain object of type SnmpVarBind.
  512. */
  513. protected Vector varBind;
  514. /**
  515. * The array giving the index translation between the content of
  516. * <VAR>varBind</VAR> and the varbind list as specified in the request.
  517. */
  518. protected int[] translation;
  519. /**
  520. * Contextual object allocated by the SnmpUserDataFactory.
  521. **/
  522. protected Object data;
  523. /**
  524. * The SnmpMibRequest that will be passed to the agent.
  525. *
  526. **/
  527. private SnmpMibRequest mibRequest = null;
  528. /**
  529. * The SnmpPdu that will be passed to the request.
  530. *
  531. **/
  532. private SnmpPdu reqPdu = null;
  533. // All the methods of the Vector class are synchronized.
  534. // Synchronization is a very expensive operation. In our case it is not always
  535. // required...
  536. //
  537. class NonSyncVector extends Vector {
  538. public NonSyncVector(int size) {
  539. super(size);
  540. }
  541. final void addNonSyncElement(Object obj) {
  542. ensureCapacity(elementCount + 1);
  543. elementData[elementCount++] = obj;
  544. }
  545. final Object elementAtNonSync(int index) {
  546. return elementData[index];
  547. }
  548. };
  549. }