Skip to content

Commit eac464b

Browse files
author
blackhedd
committed
added some SNMP app-specific types and cleaned up some BER-encoding problems
with integers.
1 parent e550dc8 commit eac464b

File tree

4 files changed

+92
-23
lines changed

4 files changed

+92
-23
lines changed

lib/net/ber.rb

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -364,31 +364,14 @@ class Fixnum
364364
# to_ber
365365
#
366366
def to_ber
367-
# originally used pack("w") which is WRONG.
368-
#i = [self].pack('w')
369-
370-
# PLEASE optimize this code path. It's awfully ugly and probably slow.
371-
# It also doesn't understand negative numbers yet.
372-
raise Net::BER::BerError.new( "range error in fixnum" ) unless self >= 0
373-
z = [self].pack("N")
374-
zlen = if self < 0x80
375-
1
376-
elsif self < 0x8000
377-
2
378-
elsif self < 0x800000
379-
3
380-
else
381-
4
382-
end
383-
[2, zlen].pack("CC") + z[0-zlen,zlen]
367+
"\002" + to_ber_internal
384368
end
385369

386370
#
387371
# to_ber_enumerated
388372
#
389373
def to_ber_enumerated
390-
i = [self].pack('w')
391-
[10, i.length].pack("CC") + i
374+
"\012" + to_ber_internal
392375
end
393376

394377
#
@@ -403,6 +386,34 @@ def to_ber_length_encoding
403386
end
404387
end
405388

389+
# Generate a BER-encoding for an application-defined INTEGER.
390+
# Example: SNMP's Counter, Gauge, and TimeTick types.
391+
#
392+
def to_ber_application tag
393+
[0x40 + tag].pack("C") + to_ber_internal
394+
end
395+
396+
#--
397+
# Called internally to BER-encode the length and content bytes of a Fixnum.
398+
# The caller will prepend the tag byte.
399+
def to_ber_internal
400+
# PLEASE optimize this code path. It's awfully ugly and probably slow.
401+
# It also doesn't understand negative numbers yet.
402+
raise Net::BER::BerError.new( "range error in fixnum" ) unless self >= 0
403+
z = [self].pack("N")
404+
zlen = if self < 0x80
405+
1
406+
elsif self < 0x8000
407+
2
408+
elsif self < 0x800000
409+
3
410+
else
411+
4
412+
end
413+
[zlen].pack("C") + z[0-zlen,zlen]
414+
end
415+
private :to_ber_internal
416+
406417
end # class Fixnum
407418

408419

@@ -416,6 +427,12 @@ def to_ber
416427
# Ruby represents Bignums as two's-complement numbers so we may actually be
417428
# good as far as representing negatives goes.
418429
# I'm sure this implementation can be improved performance-wise if necessary.
430+
# Ruby's Bignum#size returns the number of bytes in the internal representation
431+
# of the number, but it can and will include leading zero bytes on at least
432+
# some implementations. Evidently Ruby stores these as sets of quadbytes.
433+
# It's not illegal in BER to encode all of the leading zeroes but let's strip
434+
# them out anyway.
435+
#
419436
sz = self.size
420437
out = "\000" * sz
421438
(sz*8).times {|bit|
@@ -424,7 +441,11 @@ def to_ber
424441
end
425442
}
426443

427-
[2, sz].pack("CC") + out.reverse
444+
while out.length > 1 and out[-1] == 0
445+
out.slice!(-1,1)
446+
end
447+
448+
[2, out.length].pack("CC") + out.reverse
428449
end
429450

430451
end

lib/net/snmp.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class SNMP
3636
AsnSyntax = BER.compile_syntax({
3737
:application => {
3838
:primitive => {
39+
1 => :integer, # Counter32, (RFC1155 sec 6)
40+
2 => :integer, # Gauge32, (RFC1155 sec 6)
41+
3 => :integer # TimeTicks32, (RFC1155 sec 6)
3942
},
4043
:constructed => {
4144
}
@@ -51,6 +54,42 @@ class SNMP
5154
}
5255
})
5356

57+
# SNMP 32-bit counter.
58+
# Defined in RFC1155 (Structure of Mangement Information), section 6.
59+
# A 32-bit counter is an ASN.1 application [1] implicit unsigned integer
60+
# with a range from 0 to 2^^32 - 1.
61+
class Counter32
62+
def initialize value
63+
@value = value
64+
end
65+
def to_ber
66+
@value.to_ber_application(1)
67+
end
68+
end
69+
70+
# SNMP 32-bit gauge.
71+
# Defined in RFC1155 (Structure of Mangement Information), section 6.
72+
# A 32-bit counter is an ASN.1 application [2] implicit unsigned integer.
73+
class Gauge32
74+
def initialize value
75+
@value = value
76+
end
77+
def to_ber
78+
@value.to_ber_application(2)
79+
end
80+
end
81+
82+
# SNMP 32-bit timer-ticks.
83+
# Defined in RFC1155 (Structure of Mangement Information), section 6.
84+
# A 32-bit counter is an ASN.1 application [3] implicit unsigned integer.
85+
class TimerTicks32
86+
def initialize value
87+
@value = value
88+
end
89+
def to_ber
90+
@value.to_ber_application(3)
91+
end
92+
end
5493
end
5594

5695
class SnmpPdu

tests/testber.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ def setup
1818
# 5000000000 is a Bignum, which hits different code.
1919
def test_ber_integers
2020
assert_equal( "\002\001\005", 5.to_ber )
21-
assert_equal( "\002\002\203t", 500.to_ber )
22-
assert_equal( "\002\003\203\206P", 50000.to_ber )
23-
assert_equal( "\002\005\222\320\227\344\000", 5000000000.to_ber )
21+
assert_equal( "\002\002\001\364", 500.to_ber )
22+
assert_equal( "\002\003\0\303P", 50000.to_ber )
23+
assert_equal( "\002\005\001*\005\362\000", 5000000000.to_ber )
2424
end
2525

2626
def test_ber_bignums

tests/testsnmp.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ def test_make_bad_response
113113
# Not specifying variables doesn't create an error. (Maybe it should?)
114114
end
115115

116+
def test_snmp_integers
117+
c32 = Net::SNMP::Counter32.new(100)
118+
assert_equal( "A\001d", c32.to_ber )
119+
g32 = Net::SNMP::Gauge32.new(100)
120+
assert_equal( "B\001d", g32.to_ber )
121+
t32 = Net::SNMP::TimerTicks32.new(100)
122+
assert_equal( "C\001d", t32.to_ber )
123+
end
124+
116125
end
117126

118127

0 commit comments

Comments
 (0)