added some SNMP app-specific types and cleaned up some BER-encoding problems
with integers.
This commit is contained in:
parent
e550dc80ab
commit
eac464bcb9
4 changed files with 92 additions and 23 deletions
|
@ -364,31 +364,14 @@ class Fixnum
|
|||
# to_ber
|
||||
#
|
||||
def to_ber
|
||||
# originally used pack("w") which is WRONG.
|
||||
#i = [self].pack('w')
|
||||
|
||||
# PLEASE optimize this code path. It's awfully ugly and probably slow.
|
||||
# It also doesn't understand negative numbers yet.
|
||||
raise Net::BER::BerError.new( "range error in fixnum" ) unless self >= 0
|
||||
z = [self].pack("N")
|
||||
zlen = if self < 0x80
|
||||
1
|
||||
elsif self < 0x8000
|
||||
2
|
||||
elsif self < 0x800000
|
||||
3
|
||||
else
|
||||
4
|
||||
end
|
||||
[2, zlen].pack("CC") + z[0-zlen,zlen]
|
||||
"\002" + to_ber_internal
|
||||
end
|
||||
|
||||
#
|
||||
# to_ber_enumerated
|
||||
#
|
||||
def to_ber_enumerated
|
||||
i = [self].pack('w')
|
||||
[10, i.length].pack("CC") + i
|
||||
"\012" + to_ber_internal
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -403,6 +386,34 @@ class Fixnum
|
|||
end
|
||||
end
|
||||
|
||||
# Generate a BER-encoding for an application-defined INTEGER.
|
||||
# Example: SNMP's Counter, Gauge, and TimeTick types.
|
||||
#
|
||||
def to_ber_application tag
|
||||
[0x40 + tag].pack("C") + to_ber_internal
|
||||
end
|
||||
|
||||
#--
|
||||
# Called internally to BER-encode the length and content bytes of a Fixnum.
|
||||
# The caller will prepend the tag byte.
|
||||
def to_ber_internal
|
||||
# PLEASE optimize this code path. It's awfully ugly and probably slow.
|
||||
# It also doesn't understand negative numbers yet.
|
||||
raise Net::BER::BerError.new( "range error in fixnum" ) unless self >= 0
|
||||
z = [self].pack("N")
|
||||
zlen = if self < 0x80
|
||||
1
|
||||
elsif self < 0x8000
|
||||
2
|
||||
elsif self < 0x800000
|
||||
3
|
||||
else
|
||||
4
|
||||
end
|
||||
[zlen].pack("C") + z[0-zlen,zlen]
|
||||
end
|
||||
private :to_ber_internal
|
||||
|
||||
end # class Fixnum
|
||||
|
||||
|
||||
|
@ -416,6 +427,12 @@ class Bignum
|
|||
# Ruby represents Bignums as two's-complement numbers so we may actually be
|
||||
# good as far as representing negatives goes.
|
||||
# I'm sure this implementation can be improved performance-wise if necessary.
|
||||
# Ruby's Bignum#size returns the number of bytes in the internal representation
|
||||
# of the number, but it can and will include leading zero bytes on at least
|
||||
# some implementations. Evidently Ruby stores these as sets of quadbytes.
|
||||
# It's not illegal in BER to encode all of the leading zeroes but let's strip
|
||||
# them out anyway.
|
||||
#
|
||||
sz = self.size
|
||||
out = "\000" * sz
|
||||
(sz*8).times {|bit|
|
||||
|
@ -424,7 +441,11 @@ class Bignum
|
|||
end
|
||||
}
|
||||
|
||||
[2, sz].pack("CC") + out.reverse
|
||||
while out.length > 1 and out[-1] == 0
|
||||
out.slice!(-1,1)
|
||||
end
|
||||
|
||||
[2, out.length].pack("CC") + out.reverse
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -36,6 +36,9 @@ module Net
|
|||
AsnSyntax = BER.compile_syntax({
|
||||
:application => {
|
||||
:primitive => {
|
||||
1 => :integer, # Counter32, (RFC1155 sec 6)
|
||||
2 => :integer, # Gauge32, (RFC1155 sec 6)
|
||||
3 => :integer # TimeTicks32, (RFC1155 sec 6)
|
||||
},
|
||||
:constructed => {
|
||||
}
|
||||
|
@ -51,6 +54,42 @@ module Net
|
|||
}
|
||||
})
|
||||
|
||||
# SNMP 32-bit counter.
|
||||
# Defined in RFC1155 (Structure of Mangement Information), section 6.
|
||||
# A 32-bit counter is an ASN.1 application [1] implicit unsigned integer
|
||||
# with a range from 0 to 2^^32 - 1.
|
||||
class Counter32
|
||||
def initialize value
|
||||
@value = value
|
||||
end
|
||||
def to_ber
|
||||
@value.to_ber_application(1)
|
||||
end
|
||||
end
|
||||
|
||||
# SNMP 32-bit gauge.
|
||||
# Defined in RFC1155 (Structure of Mangement Information), section 6.
|
||||
# A 32-bit counter is an ASN.1 application [2] implicit unsigned integer.
|
||||
class Gauge32
|
||||
def initialize value
|
||||
@value = value
|
||||
end
|
||||
def to_ber
|
||||
@value.to_ber_application(2)
|
||||
end
|
||||
end
|
||||
|
||||
# SNMP 32-bit timer-ticks.
|
||||
# Defined in RFC1155 (Structure of Mangement Information), section 6.
|
||||
# A 32-bit counter is an ASN.1 application [3] implicit unsigned integer.
|
||||
class TimerTicks32
|
||||
def initialize value
|
||||
@value = value
|
||||
end
|
||||
def to_ber
|
||||
@value.to_ber_application(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class SnmpPdu
|
||||
|
|
|
@ -18,9 +18,9 @@ class TestBer < Test::Unit::TestCase
|
|||
# 5000000000 is a Bignum, which hits different code.
|
||||
def test_ber_integers
|
||||
assert_equal( "\002\001\005", 5.to_ber )
|
||||
assert_equal( "\002\002\203t", 500.to_ber )
|
||||
assert_equal( "\002\003\203\206P", 50000.to_ber )
|
||||
assert_equal( "\002\005\222\320\227\344\000", 5000000000.to_ber )
|
||||
assert_equal( "\002\002\001\364", 500.to_ber )
|
||||
assert_equal( "\002\003\0\303P", 50000.to_ber )
|
||||
assert_equal( "\002\005\001*\005\362\000", 5000000000.to_ber )
|
||||
end
|
||||
|
||||
def test_ber_bignums
|
||||
|
|
|
@ -113,6 +113,15 @@ class TestSnmp < Test::Unit::TestCase
|
|||
# Not specifying variables doesn't create an error. (Maybe it should?)
|
||||
end
|
||||
|
||||
def test_snmp_integers
|
||||
c32 = Net::SNMP::Counter32.new(100)
|
||||
assert_equal( "A\001d", c32.to_ber )
|
||||
g32 = Net::SNMP::Gauge32.new(100)
|
||||
assert_equal( "B\001d", g32.to_ber )
|
||||
t32 = Net::SNMP::TimerTicks32.new(100)
|
||||
assert_equal( "C\001d", t32.to_ber )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue