added some SNMP app-specific types and cleaned up some BER-encoding problems
with integers.
This commit is contained in:
parent
e550dc80ab
commit
eac464bcb9
|
@ -364,31 +364,14 @@ class Fixnum
|
||||||
# to_ber
|
# to_ber
|
||||||
#
|
#
|
||||||
def to_ber
|
def to_ber
|
||||||
# originally used pack("w") which is WRONG.
|
"\002" + to_ber_internal
|
||||||
#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]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# to_ber_enumerated
|
# to_ber_enumerated
|
||||||
#
|
#
|
||||||
def to_ber_enumerated
|
def to_ber_enumerated
|
||||||
i = [self].pack('w')
|
"\012" + to_ber_internal
|
||||||
[10, i.length].pack("CC") + i
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -403,6 +386,34 @@ class Fixnum
|
||||||
end
|
end
|
||||||
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
|
end # class Fixnum
|
||||||
|
|
||||||
|
|
||||||
|
@ -416,6 +427,12 @@ class Bignum
|
||||||
# Ruby represents Bignums as two's-complement numbers so we may actually be
|
# Ruby represents Bignums as two's-complement numbers so we may actually be
|
||||||
# good as far as representing negatives goes.
|
# good as far as representing negatives goes.
|
||||||
# I'm sure this implementation can be improved performance-wise if necessary.
|
# 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
|
sz = self.size
|
||||||
out = "\000" * sz
|
out = "\000" * sz
|
||||||
(sz*8).times {|bit|
|
(sz*8).times {|bit|
|
||||||
|
@ -424,7 +441,11 @@ class Bignum
|
||||||
end
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,6 +36,9 @@ module Net
|
||||||
AsnSyntax = BER.compile_syntax({
|
AsnSyntax = BER.compile_syntax({
|
||||||
:application => {
|
:application => {
|
||||||
:primitive => {
|
:primitive => {
|
||||||
|
1 => :integer, # Counter32, (RFC1155 sec 6)
|
||||||
|
2 => :integer, # Gauge32, (RFC1155 sec 6)
|
||||||
|
3 => :integer # TimeTicks32, (RFC1155 sec 6)
|
||||||
},
|
},
|
||||||
:constructed => {
|
: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
|
end
|
||||||
|
|
||||||
class SnmpPdu
|
class SnmpPdu
|
||||||
|
|
|
@ -18,9 +18,9 @@ class TestBer < Test::Unit::TestCase
|
||||||
# 5000000000 is a Bignum, which hits different code.
|
# 5000000000 is a Bignum, which hits different code.
|
||||||
def test_ber_integers
|
def test_ber_integers
|
||||||
assert_equal( "\002\001\005", 5.to_ber )
|
assert_equal( "\002\001\005", 5.to_ber )
|
||||||
assert_equal( "\002\002\203t", 500.to_ber )
|
assert_equal( "\002\002\001\364", 500.to_ber )
|
||||||
assert_equal( "\002\003\203\206P", 50000.to_ber )
|
assert_equal( "\002\003\0\303P", 50000.to_ber )
|
||||||
assert_equal( "\002\005\222\320\227\344\000", 5000000000.to_ber )
|
assert_equal( "\002\005\001*\005\362\000", 5000000000.to_ber )
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_ber_bignums
|
def test_ber_bignums
|
||||||
|
|
|
@ -113,6 +113,15 @@ class TestSnmp < Test::Unit::TestCase
|
||||||
# Not specifying variables doesn't create an error. (Maybe it should?)
|
# Not specifying variables doesn't create an error. (Maybe it should?)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue