1 22 23 package org.snmp4j.agent.agentx; 24 25 import java.net.*; 26 import java.nio.*; 27 import java.util.*; 28 29 import org.snmp4j.agent.*; 30 import org.snmp4j.smi.*; 31 import org.snmp4j.transport.MessageLengthDecoder; 32 import org.snmp4j.transport.MessageLength; 33 import java.io.IOException ; 34 import org.snmp4j.log.LogAdapter; 35 import org.snmp4j.log.LogFactory; 36 37 public class AgentXProtocol implements MessageLengthDecoder { 38 39 private static final LogAdapter logger = 40 LogFactory.getLogger(AgentXProtocol.class); 41 42 public static final byte VERSION_1_0 = 1; 43 44 public static final byte REASON_OTHER = 1; 45 public static final byte REASON_PARSE_ERROR = 2; 46 public static final byte REASON_PROTOCOL_ERROR = 3; 47 public static final byte REASON_TIMEOUTS = 4; 48 public static final byte REASON_SHUTDOWN = 5; 49 public static final byte REASON_BY_MANAGER = 6; 50 51 public static final int AGENTX_OPEN_FAILED = 256; 52 public static final int AGENTX_NOT_OPEN = 257; 53 public static final int AGENTX_INDEX_WRONG_TYPE = 258; 54 public static final int AGENTX_INDEX_ALREADY_ALLOCATED= 259; 55 public static final int AGENTX_INDEX_NONE_AVAILABLE = 260; 56 public static final int AGENTX_INDEX_NOT_ALLOCATED = 261; 57 public static final int AGENTX_UNSUPPORTED_CONTEXT = 262; 58 public static final int AGENTX_DUPLICATE_REGISTRATION = 263; 59 public static final int AGENTX_UNKNOWN_REGISTRATION = 264; 60 public static final int AGENTX_UNKNOWN_AGENTCAPS = 265; 61 public static final int AGENTX_PARSE_ERROR = 266; 62 public static final int AGENTX_REQUEST_DENIED = 267; 63 public static final int AGENTX_PROCESSING_ERROR = 268; 64 65 66 67 public static final int AGENTX_SUCCESS = 0; 68 public static final int AGENTX_ERROR = -1; 69 public static final int AGENTX_DISCONNECT = -5; 70 public static final int AGENTX_BADVER =-10; 71 public static final int AGENTX_TIMEOUT =-11; 72 73 74 public static final int AGENTX_NOREG = -40; 75 public static final int AGENTX_DUPMAP = -41; 76 77 public static final byte FLAG_INSTANCE_REGISTRATION = 0x01; 78 public static final byte FLAG_NEW_INDEX = 0x02; 79 public static final byte FLAG_ANY_INDEX = 0x04; 80 public static final byte FLAG_NON_DEFAULT_CONTEXT = 0x08; 81 public static final byte FLAG_NETWORK_BYTE_ORDER = 0x10; 82 83 private static final OID INTERNET = new OID(new int[]{ 1,3,6,1 }); 84 85 private static final int IPADDRESS_OCTETS = 4; 86 87 protected static final int AGENTX_INT_SIZE = 4; 88 89 public static final int HEADER_LENGTH = 5 * AGENTX_INT_SIZE; 90 91 public static final int DEFAULT_TIMEOUT_SECONDS = 5; 92 public static final int DEFAULT_MAX_CONSECUTIVE_TIMEOUTS = 3; 93 public static final int DEFAULT_MAX_PARSE_ERRORS = -1; 94 public static final int MAX_TIMEOUT_SECONDS = 255; 95 96 97 private static boolean nonDefaultContextEnabled = true; 98 99 100 public static void encodeOID(ByteBuffer buf, 101 OID oid, 102 boolean include) { 103 if (oid == null) { 104 buf.put(new byte[] { 0,0,0,0 }); 105 } 106 else { 107 int startPos = 0; 108 if ((oid.size() > INTERNET.size()) && (oid.startsWith(INTERNET))) { 109 buf.put((byte) (oid.size() - (INTERNET.size() + 1))); 110 buf.put((byte) oid.get(INTERNET.size())); 111 startPos = INTERNET.size() + 1; 112 } 113 else { 114 buf.put((byte) oid.size()); 115 buf.put((byte) 0); 116 } 117 if ((include) && (oid.size() > 0)) { 118 buf.put((byte) 1); 119 buf.put((byte) 0); 120 } 121 else { 122 buf.put(new byte[] {0, 0}); 123 } 124 for (int i = startPos; i < oid.size(); i++) { 125 buf.putInt(oid.get(i)); 126 } 127 } 128 } 129 130 public static int getOIDLength(OID oid) { 131 if (oid == null) { 132 return AGENTX_INT_SIZE; 133 } 134 int startPos = 0; 135 if ((oid.size() > INTERNET.size()) && (oid.startsWith(INTERNET))) { 136 startPos = INTERNET.size()+1; 137 } 138 return AGENTX_INT_SIZE + (AGENTX_INT_SIZE * (oid.size() - startPos)); 139 } 140 141 public static boolean decodeOID(ByteBuffer buf, OID oid) { 142 int size = buf.get(); 143 int first = buf.get(); 144 int[] value = new int[size+((first != 0) ? INTERNET.size()+1 : 0)]; 145 int startPos = 0; 146 if (first != 0) { 147 System.arraycopy(INTERNET.getValue(), 0, value, 0, INTERNET.size()); 148 value[INTERNET.size()] = first; 149 startPos = INTERNET.size()+1; 150 } 151 boolean include = (buf.get() != 0); 152 buf.get(); for (int i=0; i<size; i++) { 154 value[startPos+i] = buf.getInt(); 155 } 156 oid.setValue(value); 157 return include; 158 } 159 160 public static void encodeVariableData(ByteBuffer buf, Variable v) { 161 if (v == null) { 162 return; 163 } 164 switch (v.getSyntax()) { 165 case SMIConstants.SYNTAX_GAUGE32: 167 case SMIConstants.SYNTAX_TIMETICKS: 168 case SMIConstants.SYNTAX_COUNTER32: { 169 buf.putInt((int)(((UnsignedInteger32)v).getValue() & 0xFFFFFFFFL)); 170 break; 171 } 172 case SMIConstants.SYNTAX_INTEGER32: { 173 buf.putInt(((Integer32)v).getValue()); 174 break; 175 } 176 case SMIConstants.SYNTAX_COUNTER64: { 177 buf.putLong(((Counter64)v).getValue()); 178 break; 179 } 180 case SMIConstants.SYNTAX_OCTET_STRING: 181 case SMIConstants.SYNTAX_OPAQUE: { 182 encodeOctetString(buf, (OctetString)v); 183 break; 184 } 185 case SMIConstants.SYNTAX_IPADDRESS: { 186 encodeOctetString(buf, 187 new OctetString(((IpAddress)v).getInetAddress().getAddress())); 188 break; 190 } 191 case SMIConstants.SYNTAX_OBJECT_IDENTIFIER: { 192 encodeOID(buf, (OID)v, false); 193 break; 194 } 195 default: 196 break; 197 } 198 } 199 200 public static int getVariableDataLength(Variable v) { 201 if (v == null) { 202 return 0; 203 } 204 switch (v.getSyntax()) { 205 case SMIConstants.SYNTAX_GAUGE32: 207 case SMIConstants.SYNTAX_TIMETICKS: 208 case SMIConstants.SYNTAX_COUNTER32: 209 case SMIConstants.SYNTAX_INTEGER32: { 210 return AGENTX_INT_SIZE; 211 } 212 case SMIConstants.SYNTAX_COUNTER64: { 213 return 2 * AGENTX_INT_SIZE; 214 } 215 case SMIConstants.SYNTAX_OCTET_STRING: 216 case SMIConstants.SYNTAX_OPAQUE: { 217 return getOctetStringLength((OctetString)v); 218 } 219 case SMIConstants.SYNTAX_IPADDRESS: { 220 return 2 * AGENTX_INT_SIZE; 221 } 222 case SMIConstants.SYNTAX_OBJECT_IDENTIFIER: { 223 return getOIDLength((OID)v); 224 } 225 default: 226 break; 227 } 228 return 0; 229 } 230 231 public static Variable decodeVariableData(ByteBuffer buf, int syntax) { 232 switch (syntax) { 233 case SMIConstants.SYNTAX_GAUGE32: 235 return new Gauge32((buf.getInt() & 0xFFFFFFFFL)); 236 case SMIConstants.SYNTAX_TIMETICKS: 237 return new TimeTicks((buf.getInt() & 0xFFFFFFFFL)); 238 case SMIConstants.SYNTAX_COUNTER32: 239 return new Counter32((buf.getInt() & 0xFFFFFFFFL)); 240 case SMIConstants.SYNTAX_INTEGER32: 241 return new Integer32(buf.getInt()); 242 case SMIConstants.SYNTAX_COUNTER64: 243 return new Counter64(buf.getLong()); 244 case SMIConstants.SYNTAX_OCTET_STRING: 245 return decodeOctetString(buf); 246 case SMIConstants.SYNTAX_OPAQUE: 247 return new Opaque(decodeOctetString(buf).getValue()); 248 case SMIConstants.SYNTAX_IPADDRESS: { 249 byte[] addrBytes = decodeOctetString(buf).getValue(); 250 if (addrBytes.length > IPADDRESS_OCTETS) { 253 logger.warn("Subagent returned IpAddress with length "+ 254 addrBytes.length+ 255 " > "+IPADDRESS_OCTETS+ 256 " which violates AgentX protocol specification"); 257 byte[] fourBytes = new byte[IPADDRESS_OCTETS]; 258 System.arraycopy(addrBytes, 0, fourBytes, 0, IPADDRESS_OCTETS); 259 addrBytes = fourBytes; 260 } 261 InetAddress addr = null; 262 try { 263 addr = InetAddress.getByAddress(addrBytes); 264 } 265 catch (UnknownHostException ex) { 266 logger.error("Failed to create IpAddress from address bytes "+ 267 " with length "+addrBytes.length+ 268 ", using default IpAddress instead", ex); 269 return new IpAddress(); 270 } 271 return new IpAddress(addr); 272 } 273 case SMIConstants.SYNTAX_OBJECT_IDENTIFIER: { 274 OID oid = new OID(); 275 decodeOID(buf, oid); 276 return oid; 277 } 278 case SMIConstants.EXCEPTION_END_OF_MIB_VIEW: 279 case SMIConstants.EXCEPTION_NO_SUCH_INSTANCE: 280 case SMIConstants.EXCEPTION_NO_SUCH_OBJECT: { 281 return new Null(syntax); 282 } 283 case SMIConstants.SYNTAX_NULL: { 284 return new Null(); 285 } 286 default: { 287 logger.error("Unknown AgentX variable syntax '"+syntax+ 288 "', using Null instead"); 289 return new Null(); 290 } 291 } 292 } 293 294 public static VariableBinding[] decodeVariableBindings(ByteBuffer buf) { 295 ArrayList vbs = new ArrayList(); 296 while (buf.remaining() > 0) { 297 int type = buf.getShort() & 0xFFFF; 298 buf.getShort(); 299 OID oid = new OID(); 300 decodeOID(buf, oid); 301 Variable v = decodeVariableData(buf, type); 302 vbs.add(new VariableBinding(oid, v)); 303 } 304 return (VariableBinding[]) vbs.toArray(new VariableBinding[vbs.size()]); 305 } 306 307 public static void encodeVaribleBindings(ByteBuffer buf, VariableBinding[] vbs) { 308 for (int i=0; i<vbs.length; i++) { 309 buf.putShort((short)vbs[i].getSyntax()); 310 buf.put(new byte[] { 0,0 }); encodeOID(buf, vbs[i].getOid(), false); 312 encodeVariableData(buf, vbs[i].getVariable()); 313 } 314 } 315 316 public static void encodeRanges(ByteBuffer buf, MOScope[] searchRanges) { 317 for (int i=0; i<searchRanges.length; i++) { 318 encodeOID(buf, searchRanges[i].getLowerBound(), 319 searchRanges[i].isLowerIncluded()); 320 if (searchRanges[i].isUpperIncluded()) { 321 encodeOID(buf, searchRanges[i].getUpperBound().successor(), false); 322 } 323 else { 324 encodeOID(buf, searchRanges[i].getUpperBound(), false); 325 } 326 } 327 } 328 329 public static int getOctetStringLength(OctetString os) { 330 int padding = 0; 331 if ((os.length() % AGENTX_INT_SIZE) > 0) { 332 padding = AGENTX_INT_SIZE - (os.length() % AGENTX_INT_SIZE); 333 } 334 return AGENTX_INT_SIZE + os.length() + padding; 335 } 336 337 public static void encodeOctetString(ByteBuffer buf, OctetString os) { 338 buf.putInt(os.length()); 339 buf.put(os.getValue()); 340 if ((os.length() % AGENTX_INT_SIZE) > 0) { 341 for (int i=0; i < AGENTX_INT_SIZE - (os.length() % AGENTX_INT_SIZE); i++) { 342 buf.put((byte)0); 343 } 344 } 345 } 346 347 public static OctetString decodeOctetString(ByteBuffer buf) { 348 int size = buf.getInt(); 349 byte[] value = new byte[size]; 350 buf.get(value); 351 if ((size % AGENTX_INT_SIZE) > 0) { 352 for (int i=0; i < AGENTX_INT_SIZE - (size % AGENTX_INT_SIZE); i++) { 353 buf.get(); } 355 } 356 return new OctetString(value); 357 } 358 359 public static MOScope[] decodeRanges(ByteBuffer buf) { 360 return decodeRanges(buf, false); 361 } 362 363 public static MOScope[] decodeRanges(ByteBuffer buf, 364 boolean lowerAlwaysIncluded) { 365 ArrayList ranges = new ArrayList(); 366 while (buf.hasRemaining()) { 367 OID lowerBound = new OID(); 368 boolean isLowerIncluded= lowerAlwaysIncluded | decodeOID(buf, lowerBound); 369 OID upperBound = new OID(); 370 decodeOID(buf, upperBound); 371 if (upperBound.size() == 0) { 372 upperBound = null; 373 } 374 ranges.add(new DefaultMOScope(lowerBound, isLowerIncluded, 375 upperBound, false)); 376 } 377 return (MOScope[]) ranges.toArray(new MOScope[ranges.size()]); 378 } 379 380 public static int getRangesLength(MOScope[] ranges) { 381 int length = 0; 382 for (int i=0; i<ranges.length; i++) { 383 length += AgentXProtocol.getOIDLength(ranges[i].getLowerBound()); 384 if (ranges[i].isUpperIncluded()) { 385 length += 386 AgentXProtocol.getOIDLength(ranges[i].getUpperBound().successor()); 387 } 388 else { 389 length += AgentXProtocol.getOIDLength(ranges[i].getUpperBound()); 390 } 391 } 392 return length; 393 } 394 395 public static int getVariableBindingsLength(VariableBinding[] vbs) { 396 int length = 0; 397 for (int i=0; i<vbs.length; i++) { 398 length += AGENTX_INT_SIZE + getOIDLength(vbs[i].getOid()) + 399 getVariableDataLength(vbs[i].getVariable()); 400 } 401 return length; 402 } 403 404 public int getMinHeaderLength() { 405 return HEADER_LENGTH; 406 } 407 408 public MessageLength getMessageLength(ByteBuffer buf) throws IOException { 409 return decodeHeader(buf); 410 } 411 412 public static final AgentXMessageHeader decodeHeader(ByteBuffer buf) 413 throws IOException 414 { 415 byte version = buf.get(); 416 if (version != AgentXProtocol.VERSION_1_0) { 417 throw new IOException ("Unknown AgentX version: "+version); 418 } 419 byte type = buf.get(); 420 byte flags = buf.get(); 421 buf.get(); 422 ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN; 423 if ((flags & AgentXProtocol.FLAG_NETWORK_BYTE_ORDER) != 0) { 424 byteOrder = ByteOrder.BIG_ENDIAN; 425 } 426 buf.order(byteOrder); 427 int sessionID = buf.getInt(); 428 int transactionID = buf.getInt(); 429 int packetID = buf.getInt(); 430 int length = buf.getInt(); 431 return new AgentXMessageHeader(type, flags, sessionID, transactionID, 432 packetID, length); 433 } 434 435 public static void setNonDefaultContextsEnabled(boolean enabled) { 436 nonDefaultContextEnabled = enabled; 437 } 438 439 public static boolean isNonDefaultContextsEnabled() { 440 return nonDefaultContextEnabled; 441 } 442 443 public static final byte DEFAULT_PRIORITY = 127; 444 public static final int FLAG_ALLOCATE_INDEX = 0; 445 } 446 | Popular Tags |