added some SNMP app-specific types and cleaned up some BER-encoding problems

with integers.
This commit is contained in:
blackhedd 2006-12-17 19:04:41 +00:00
parent e550dc80ab
commit eac464bcb9
4 changed files with 92 additions and 23 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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