Class: BinProxy::Parser

Inherits:
Object
  • Object
show all
Includes:
Logger
Defined in:
lib/binproxy/parser.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logger

log

Constructor Details

#initializeParser

Returns a new instance of Parser.



24
25
26
27
28
29
30
31
32
33
# File 'lib/binproxy/parser.rb', line 24

def initialize
  @protocol_state = message_class.initial_state
rescue => e
  log.warn "Exception while getting initial state for #{message_class}: e"
  if e.message.match /undefined method `initial_state'/ then
    log.warn "This is possibly not a subclass of BinData::Base"
  end
  # try to proceed with a default value
  BinData::Base.initial_state
end

Class Attribute Details

.message_classObject

Returns the value of attribute message_class.



8
9
10
# File 'lib/binproxy/parser.rb', line 8

def message_class
  @message_class
end

.proxyObject

Returns the value of attribute proxy.



8
9
10
# File 'lib/binproxy/parser.rb', line 8

def proxy
  @proxy
end

.validateObject

Returns the value of attribute validate.



8
9
10
# File 'lib/binproxy/parser.rb', line 8

def validate
  @validate
end

Class Method Details

.subclass(proxy, mc) ⇒ Object



13
14
15
16
17
18
19
20
21
22
# File 'lib/binproxy/parser.rb', line 13

def self.subclass(proxy, mc)
  unless mc.class == Class
    BinProxy::Logger::log.fatal "#{mc} is a #{mc.class}, not a Class."
    exit!
  end
  c = Class.new(self) do
    @proxy = proxy #XXX I don't love the tight coupling here; need a better way to pass messages up the chain
    @message_class = mc
  end
end

Instance Method Details

#message_classObject



10
# File 'lib/binproxy/parser.rb', line 10

def message_class; self.class.message_class; end

#parse(raw_buffer, peer) ⇒ Object

Try to parse one or more messages from the buffer, and yield them



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/binproxy/parser.rb', line 36

def parse(raw_buffer, peer)
  start_pos = nil
  loop do
    break if raw_buffer.eof?

    start_pos = raw_buffer.pos

    log.debug "at #{start_pos} of #{raw_buffer.length} in buffer"

    read_fn = lambda { message_class.new(src: peer.to_s, protocol_state: @protocol_state).read(raw_buffer) }

    message = if log.debug?
      BinData::trace_reading &read_fn
    else
      read_fn.call
    end

    bytes_read = raw_buffer.pos - start_pos
    log.debug "read #{bytes_read} bytes"

    # Go back and grab raw bytes for validation of serialization
    raw_buffer.pos = start_pos
    raw_m = raw_buffer.read bytes_read

    @protocol_state = message.update_state
    log.debug "protocol state is now #{@protocol_state.inspect}"

    pm = ProxyMessage.new(raw_m, message)
    pm.src = peer
    yield pm
  end
rescue EOFError, IOError
  log.info "Hit end of buffer while parsing.  Consumed #{raw_buffer.pos - start_pos} bytes."
  raw_buffer.pos = start_pos #rewind partial read
  #todo, warn to client if validate flag set?
rescue Exception => e
  log.err_trace(e, 'parsing message (probably an issue with user BinData class)', ::Logger::WARN)
  self.class.proxy.on_bindata_error('parsing', e)
end

#validateObject



11
# File 'lib/binproxy/parser.rb', line 11

def validate; self.class.validate; end