Class: Presence::Scanner

Inherits:
Object
  • Object
show all
Defined in:
lib/presence/scanner.rb

Overview

Scans a network for connected clients, captures the MAC address, and dispatches related events to any registered listeners.

Constant Summary collapse

PAIR =
'[0-9a-f]{2}'
SEP =
'\:'
MAC_REGEXP =
Regexp.new("(#{6.times.map {PAIR}.join(SEP)})")

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = nil) ⇒ Scanner

Returns a new instance of Scanner.



14
15
16
17
18
19
20
21
22
# File 'lib/presence/scanner.rb', line 14

def initialize(options = nil)
  options ||= {}
  self.options = {
    ip_prefix:    nil,
    octet_range: (1..255)
  }.merge(options)
  self.listeners = []
  @commands = Presence::Commands.new
end

Instance Attribute Details

#listenersObject

Returns the value of attribute listeners.



12
13
14
# File 'lib/presence/scanner.rb', line 12

def listeners
  @listeners
end

#optionsObject

Returns the value of attribute options.



12
13
14
# File 'lib/presence/scanner.rb', line 12

def options
  @options
end

Class Method Details

.check_envObject



83
84
85
86
87
88
89
90
91
92
# File 'lib/presence/scanner.rb', line 83

def check_env
  commands = Commands.new
  if commands.run('which ifconfig').size == 0
    raise Presence::InvalidEnvironment.new("Unsupported platform: ifconfig not found.")
  end
  if commands.run('which arping').size == 0
    raise Presence::InvalidEnvironment.new("Unsupported platform: arping not found.")
    raise Presence::InvalidEnvironment.new("Install arping first: brew install arping")
  end
end

.scan_loop {|scanner| ... } ⇒ Object

Yields:

  • (scanner)


94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/presence/scanner.rb', line 94

def scan_loop(&block)
  scanner = self.new
  yield(scanner) if block_given?

  while(true)
    begin
      scanner.scan
    rescue Interrupt
      break
    end
  end
end

Instance Method Details

#dispatch(event, *args) ⇒ Object



72
73
74
75
76
# File 'lib/presence/scanner.rb', line 72

def dispatch(event, *args)
  listeners.each do |l|
    l.send(event, *args) if l.respond_to?(event)
  end
end

#ip_prefixObject



37
38
39
40
41
42
# File 'lib/presence/scanner.rb', line 37

def ip_prefix
  unless options[:ip_prefix]
    options[:ip_prefix] = localhost_ip.split('.')[0,3].join('.')
  end
  options[:ip_prefix]
end

#localhost_ipObject



30
31
32
33
34
35
# File 'lib/presence/scanner.rb', line 30

def localhost_ip
  unless @localhost_ip
    @localhost_ip = @commands.local_ip
  end
  @localhost_ip
end

#octet_rangeObject



44
45
46
# File 'lib/presence/scanner.rb', line 44

def octet_range
  options[:octet_range]
end

#process_scan_result(ip, cmd, result) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/presence/scanner.rb', line 62

def process_scan_result(ip, cmd, result)
  if result =~ MAC_REGEXP
    mac = $1
    dispatch(:localhost_found, ip, mac) if ip == localhost_ip
    dispatch(:mac_found, ip, mac)
  else
    dispatch(:mac_not_found, ip)
  end
end

#register_listener(l) ⇒ Object



24
25
26
27
28
# File 'lib/presence/scanner.rb', line 24

def register_listener(l)
  raise Presence::InvalidListener.new("Listener cannot be nil") if l.nil?
  listeners << l
  dispatch(:listener_registered, l, self)
end

#scanObject



48
49
50
51
52
53
54
# File 'lib/presence/scanner.rb', line 48

def scan
  dispatch(:scan_started, ip_prefix, octet_range)
  octet_range.each do |i|
    scan_ip("#{ip_prefix}.#{i}")
  end
  dispatch(:scan_finished, ip_prefix, octet_range)
end

#scan_ip(ip) ⇒ Object



56
57
58
59
60
# File 'lib/presence/scanner.rb', line 56

def scan_ip(ip)
  cmd, result = @commands.arping(ip)
  dispatch(:ip_scanned, ip, cmd, result)
  process_scan_result(ip, cmd, result)
end

#to_sObject



78
79
80
# File 'lib/presence/scanner.rb', line 78

def to_s
  "<#{self.class} ip_prefix: '#{self.ip_prefix}' octet_range: (#{self.octet_range})>"
end