1. /*
  2. * @(#)file SnmpMessage.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 4.31
  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;
  12. // "@(#)SnmpMessage.java 1.1 98/07/23 SMI"
  13. // java imports
  14. //
  15. import java.util.Vector;
  16. import java.net.InetAddress;
  17. // import debug stuff
  18. //
  19. import com.sun.jmx.trace.Trace;
  20. /**
  21. * Is a partially decoded representation of an SNMP packet.
  22. * <P>
  23. * You will not normally need to use this class unless you decide to
  24. * implement your own {@link com.sun.jmx.snmp.SnmpPduFactory SnmpPduFactory} object.
  25. * <P>
  26. * The <CODE>SnmpMessage</CODE> class is directly mapped onto the
  27. * <CODE>Message</CODE> syntax defined in RFC1157 and RFC1902.
  28. * <BLOCKQUOTE>
  29. * <PRE>
  30. * Message ::= SEQUENCE {
  31. * version INTEGER { version(1) }, -- for SNMPv2
  32. * community OCTET STRING, -- community name
  33. * data ANY -- an SNMPv2 PDU
  34. * }
  35. * </PRE>
  36. * </BLOCKQUOTE>
  37. *
  38. * <p><b>This API is a Sun Microsystems internal API and is subject
  39. * to change without notice.</b></p>
  40. * @see SnmpPduFactory
  41. * @see SnmpPduPacket
  42. *
  43. * @version 1.1 07/23/98
  44. * @author Sun Microsystems, Inc
  45. */
  46. public class SnmpMessage extends SnmpMsg implements SnmpDefinitions {
  47. /**
  48. * Community name.
  49. */
  50. public byte[] community ;
  51. /**
  52. * Encodes this message and puts the result in the specified byte array.
  53. * For internal use only.
  54. *
  55. * @param outputBytes An array to receive the resulting encoding.
  56. *
  57. * @exception ArrayIndexOutOfBoundsException If the result does not fit
  58. * into the specified array.
  59. */
  60. public int encodeMessage(byte[] outputBytes) throws SnmpTooBigException {
  61. int encodingLength = 0 ;
  62. if (data == null)
  63. throw new IllegalArgumentException("Data field is null") ;
  64. //
  65. // Reminder: BerEncoder does backward encoding !
  66. //
  67. try {
  68. BerEncoder benc = new BerEncoder(outputBytes) ;
  69. benc.openSequence() ;
  70. benc.putAny(data, dataLength) ;
  71. benc.putOctetString((community != null) ? community : new byte[0]) ;
  72. benc.putInteger(version) ;
  73. benc.closeSequence() ;
  74. encodingLength = benc.trim() ;
  75. }
  76. catch(ArrayIndexOutOfBoundsException x) {
  77. throw new SnmpTooBigException() ;
  78. }
  79. return encodingLength ;
  80. }
  81. /**
  82. * Returns the associated request ID.
  83. * @param inputBytes The flat message.
  84. * @return The request ID.
  85. *
  86. * @since 1.5
  87. */
  88. public int getRequestId(byte[] inputBytes) throws SnmpStatusException {
  89. int requestId = 0;
  90. BerDecoder bdec = null;
  91. BerDecoder bdec2 = null;
  92. byte[] any = null;
  93. try {
  94. bdec = new BerDecoder(inputBytes);
  95. bdec.openSequence();
  96. bdec.fetchInteger();
  97. bdec.fetchOctetString();
  98. any = bdec.fetchAny();
  99. bdec2 = new BerDecoder(any);
  100. int type = bdec2.getTag();
  101. bdec2.openSequence(type);
  102. requestId = bdec2.fetchInteger();
  103. }
  104. catch(BerException x) {
  105. throw new SnmpStatusException("Invalid encoding") ;
  106. }
  107. try {
  108. bdec.closeSequence();
  109. }
  110. catch(BerException x) {
  111. }
  112. try {
  113. bdec2.closeSequence();
  114. }
  115. catch(BerException x) {
  116. }
  117. return requestId;
  118. }
  119. /**
  120. * Decodes the specified bytes and initializes this message.
  121. * For internal use only.
  122. *
  123. * @param inputBytes The bytes to be decoded.
  124. *
  125. * @exception SnmpStatusException If the specified bytes are not a valid encoding.
  126. */
  127. public void decodeMessage(byte[] inputBytes, int byteCount)
  128. throws SnmpStatusException {
  129. try {
  130. BerDecoder bdec = new BerDecoder(inputBytes/*, byteCount */) ; // FIXME
  131. bdec.openSequence() ;
  132. version = bdec.fetchInteger() ;
  133. community = bdec.fetchOctetString() ;
  134. data = bdec.fetchAny() ;
  135. dataLength = data.length ;
  136. bdec.closeSequence() ;
  137. }
  138. catch(BerException x) {
  139. throw new SnmpStatusException("Invalid encoding") ;
  140. }
  141. }
  142. /**
  143. * Initializes this message with the specified <CODE>pdu</CODE>.
  144. * <P>
  145. * This method initializes the data field with an array of
  146. * <CODE>maxDataLength</CODE> bytes. It encodes the <CODE>pdu</CODE>.
  147. * The resulting encoding is stored in the data field
  148. * and the length of the encoding is stored in <CODE>dataLength</CODE>.
  149. * <p>
  150. * If the encoding length exceeds <CODE>maxDataLength</CODE>,
  151. * the method throws an exception.
  152. *
  153. * @param pdu The PDU to be encoded.
  154. * @param maxDataLength The maximum length permitted for the data field.
  155. *
  156. * @exception SnmpStatusException If the specified <CODE>pdu</CODE> is not valid.
  157. * @exception SnmpTooBigException If the resulting encoding does not fit
  158. * into <CODE>maxDataLength</CODE> bytes.
  159. * @exception ArrayIndexOutOfBoundsException If the encoding exceeds <CODE>maxDataLength</CODE>.
  160. *
  161. * @since 1.5
  162. */
  163. public void encodeSnmpPdu(SnmpPdu pdu, int maxDataLength)
  164. throws SnmpStatusException, SnmpTooBigException {
  165. //
  166. // The easy work
  167. //
  168. SnmpPduPacket pdupacket = (SnmpPduPacket) pdu;
  169. version = pdupacket.version ;
  170. community = pdupacket.community ;
  171. address = pdupacket.address ;
  172. port = pdupacket.port ;
  173. //
  174. // Allocate the array to receive the encoding.
  175. //
  176. data = new byte[maxDataLength] ;
  177. //
  178. // Encode the pdupacket
  179. // Reminder: BerEncoder does backward encoding !
  180. //
  181. try {
  182. BerEncoder benc = new BerEncoder(data) ;
  183. benc.openSequence() ;
  184. encodeVarBindList(benc, pdupacket.varBindList) ;
  185. switch(pdupacket.type) {
  186. case pduGetRequestPdu :
  187. case pduGetNextRequestPdu :
  188. case pduInformRequestPdu :
  189. case pduGetResponsePdu :
  190. case pduSetRequestPdu :
  191. case pduV2TrapPdu :
  192. case pduReportPdu :
  193. SnmpPduRequest reqPdu = (SnmpPduRequest)pdupacket ;
  194. benc.putInteger(reqPdu.errorIndex) ;
  195. benc.putInteger(reqPdu.errorStatus) ;
  196. benc.putInteger(reqPdu.requestId) ;
  197. break ;
  198. case pduGetBulkRequestPdu :
  199. SnmpPduBulk bulkPdu = (SnmpPduBulk)pdupacket ;
  200. benc.putInteger(bulkPdu.maxRepetitions) ;
  201. benc.putInteger(bulkPdu.nonRepeaters) ;
  202. benc.putInteger(bulkPdu.requestId) ;
  203. break ;
  204. case pduV1TrapPdu :
  205. SnmpPduTrap trapPdu = (SnmpPduTrap)pdupacket ;
  206. benc.putInteger(trapPdu.timeStamp, SnmpValue.TimeticksTag) ;
  207. benc.putInteger(trapPdu.specificTrap) ;
  208. benc.putInteger(trapPdu.genericTrap) ;
  209. if(trapPdu.agentAddr != null)
  210. benc.putOctetString(trapPdu.agentAddr.byteValue(), SnmpValue.IpAddressTag) ;
  211. else
  212. benc.putOctetString(new byte[0], SnmpValue.IpAddressTag);
  213. benc.putOid(trapPdu.enterprise.longValue()) ;
  214. break ;
  215. default:
  216. throw new SnmpStatusException("Invalid pdu type " + String.valueOf(pdupacket.type)) ;
  217. }
  218. benc.closeSequence(pdupacket.type) ;
  219. dataLength = benc.trim() ;
  220. }
  221. catch(ArrayIndexOutOfBoundsException x) {
  222. throw new SnmpTooBigException() ;
  223. }
  224. }
  225. /**
  226. * Gets the PDU encoded in this message.
  227. * <P>
  228. * This method decodes the data field and returns the resulting PDU.
  229. *
  230. * @return The resulting PDU.
  231. * @exception SnmpStatusException If the encoding is not valid.
  232. *
  233. * @since 1.5
  234. */
  235. public SnmpPdu decodeSnmpPdu()
  236. throws SnmpStatusException {
  237. //
  238. // Decode the pdu
  239. //
  240. SnmpPduPacket pdu = null ;
  241. BerDecoder bdec = new BerDecoder(data) ;
  242. try {
  243. int type = bdec.getTag() ;
  244. bdec.openSequence(type) ;
  245. switch(type) {
  246. case pduGetRequestPdu :
  247. case pduGetNextRequestPdu :
  248. case pduInformRequestPdu :
  249. case pduGetResponsePdu :
  250. case pduSetRequestPdu :
  251. case pduV2TrapPdu :
  252. case pduReportPdu :
  253. SnmpPduRequest reqPdu = new SnmpPduRequest() ;
  254. reqPdu.requestId = bdec.fetchInteger() ;
  255. reqPdu.errorStatus = bdec.fetchInteger() ;
  256. reqPdu.errorIndex = bdec.fetchInteger() ;
  257. pdu = reqPdu ;
  258. break ;
  259. case pduGetBulkRequestPdu :
  260. SnmpPduBulk bulkPdu = new SnmpPduBulk() ;
  261. bulkPdu.requestId = bdec.fetchInteger() ;
  262. bulkPdu.nonRepeaters = bdec.fetchInteger() ;
  263. bulkPdu.maxRepetitions = bdec.fetchInteger() ;
  264. pdu = bulkPdu ;
  265. break ;
  266. case pduV1TrapPdu :
  267. SnmpPduTrap trapPdu = new SnmpPduTrap() ;
  268. trapPdu.enterprise = new SnmpOid(bdec.fetchOid()) ;
  269. byte []b = bdec.fetchOctetString(SnmpValue.IpAddressTag);
  270. if(b.length != 0)
  271. trapPdu.agentAddr = new SnmpIpAddress(b) ;
  272. else
  273. trapPdu.agentAddr = null;
  274. trapPdu.genericTrap = bdec.fetchInteger() ;
  275. trapPdu.specificTrap = bdec.fetchInteger() ;
  276. trapPdu.timeStamp = bdec.fetchInteger(SnmpValue.TimeticksTag) ;
  277. pdu = trapPdu ;
  278. break ;
  279. default:
  280. throw new SnmpStatusException(snmpRspWrongEncoding) ;
  281. }
  282. pdu.type = type ;
  283. pdu.varBindList = decodeVarBindList(bdec) ;
  284. bdec.closeSequence() ;
  285. } catch(BerException e) {
  286. if (isDebugOn()) {
  287. debug("decodeSnmpPdu", e);
  288. }
  289. throw new SnmpStatusException(snmpRspWrongEncoding);
  290. } catch(IllegalArgumentException e) {
  291. // bug id 4654066
  292. if (isDebugOn()) {
  293. debug("decodeSnmpPdu", e);
  294. }
  295. throw new SnmpStatusException(snmpRspWrongEncoding);
  296. }
  297. //
  298. // The easy work
  299. //
  300. pdu.version = version ;
  301. pdu.community = community ;
  302. pdu.address = address ;
  303. pdu.port = port ;
  304. return pdu;
  305. }
  306. /**
  307. * Dumps this message in a string.
  308. *
  309. * @return The string containing the dump.
  310. */
  311. public String printMessage() {
  312. StringBuffer sb = new StringBuffer();
  313. if (community == null) {
  314. sb.append("Community: null") ;
  315. }
  316. else {
  317. sb.append("Community: {\n") ;
  318. sb.append(dumpHexBuffer(community, 0, community.length)) ;
  319. sb.append("\n}\n") ;
  320. }
  321. return sb.append(super.printMessage()).toString();
  322. }
  323. // TRACES & DEBUG
  324. //---------------
  325. boolean isTraceOn() {
  326. return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_SNMP);
  327. }
  328. void trace(String clz, String func, String info) {
  329. Trace.send(Trace.LEVEL_TRACE, Trace.INFO_SNMP, clz, func, info);
  330. }
  331. void trace(String func, String info) {
  332. trace(dbgTag, func, info);
  333. }
  334. boolean isDebugOn() {
  335. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_SNMP);
  336. }
  337. void debug(String clz, String func, String info) {
  338. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_SNMP, clz, func, info);
  339. }
  340. void debug(String clz, String func, Throwable exception) {
  341. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_SNMP, clz, func, exception);
  342. }
  343. void debug(String func, String info) {
  344. debug(dbgTag, func, info);
  345. }
  346. void debug(String func, Throwable exception) {
  347. debug(dbgTag, func, exception);
  348. }
  349. String dbgTag = "SnmpMessage";
  350. }