added a compiler for ASN/BER syntax, avoids interpreting it for

every packet we parse.
This commit is contained in:
blackhedd 2006-09-02 16:48:07 +00:00
parent 7fd1089115
commit bc54a9c826
2 changed files with 34 additions and 12 deletions

View file

@ -29,8 +29,6 @@
# #
module Net module Net
module BER module BER
@ -52,6 +50,26 @@ module Net
end end
end end
#--
# This condenses our nicely self-documenting ASN hashes down
# to an array for fast lookups.
# Scoped to be called as a module method, but not intended for
# user code to call.
#
def self.compile_syntax syn
out = [nil] * 256
syn.each {|tclass,tclasses|
tagclass = {:universal=>0, :application=>64, :context_specific=>128, :private=>192} [tclass]
tclasses.each {|codingtype,codings|
encoding = {:primitive=>0, :constructed=>32} [codingtype]
codings.each {|tag,objtype|
out[tagclass + encoding + tag] = objtype
}
}
}
out
end
# This module is for mixing into IO and IO-like objects. # This module is for mixing into IO and IO-like objects.
module BERParser module BERParser
@ -59,7 +77,7 @@ module Net
# Maybe this should have been a hash. # Maybe this should have been a hash.
TagClasses = [:universal, :application, :context_specific, :private] TagClasses = [:universal, :application, :context_specific, :private]
BuiltinSyntax = { BuiltinSyntax = BER.compile_syntax( {
:universal => { :universal => {
:primitive => { :primitive => {
1 => :boolean, 1 => :boolean,
@ -72,7 +90,7 @@ module Net
17 => :array 17 => :array
} }
} }
} })
# #
# read_ber # read_ber
@ -86,10 +104,10 @@ module Net
#return nil if eof? #return nil if eof?
id = getc or return nil # don't trash this value, we'll use it later id = getc or return nil # don't trash this value, we'll use it later
tag = id & 31 #tag = id & 31
tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" ) #tag < 31 or raise BerError.new( "unsupported tag encoding: #{id}" )
tagclass = TagClasses[ id >> 6 ] #tagclass = TagClasses[ id >> 6 ]
encoding = (id & 0x20 != 0) ? :constructed : :primitive #encoding = (id & 0x20 != 0) ? :constructed : :primitive
n = getc n = getc
lengthlength,contentlength = if n <= 127 lengthlength,contentlength = if n <= 127
@ -105,6 +123,7 @@ module Net
newobj = read contentlength newobj = read contentlength
# This exceptionally clever and clear bit of code is verrrry slow. # This exceptionally clever and clear bit of code is verrrry slow.
=begin
objtype = nil objtype = nil
[syntax, BuiltinSyntax].each {|syn| [syntax, BuiltinSyntax].each {|syn|
if syn && (ot = syn[tagclass]) && (ot = ot[encoding]) && ot[tag] if syn && (ot = syn[tagclass]) && (ot = ot[encoding]) && ot[tag]
@ -112,7 +131,9 @@ module Net
break break
end end
} }
=end
objtype = (syntax && syntax[id]) || BuiltinSyntax[id]
=begin =begin
Replaced this case with if/else because Symbol#=== profiled surprisingly hot. Replaced this case with if/else because Symbol#=== profiled surprisingly hot.
obj = case objtype obj = case objtype
@ -164,7 +185,8 @@ module Net
elsif objtype == :boolean elsif objtype == :boolean
newobj != "\000" newobj != "\000"
else else
raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" ) #raise BerError.new( "unsupported object type: class=#{tagclass}, encoding=#{encoding}, tag=#{tag}" )
raise BerError.new( "unsupported object type: id=#{id}" )
end end
# Add the identifier bits into the object if it's a String or an Array. # Add the identifier bits into the object if it's a String or an Array.

View file

@ -271,7 +271,7 @@ module Net
SearchScope_WholeSubtree = 2 SearchScope_WholeSubtree = 2
SearchScopes = [SearchScope_BaseObject, SearchScope_SingleLevel, SearchScope_WholeSubtree] SearchScopes = [SearchScope_BaseObject, SearchScope_SingleLevel, SearchScope_WholeSubtree]
AsnSyntax = { AsnSyntax = BER.compile_syntax({
:application => { :application => {
:constructed => { :constructed => {
0 => :array, # BindRequest 0 => :array, # BindRequest
@ -306,7 +306,7 @@ module Net
3 => :array, # Seach referral 3 => :array, # Seach referral
} }
} }
} })
DefaultHost = "127.0.0.1" DefaultHost = "127.0.0.1"
DefaultPort = 389 DefaultPort = 389