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