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-fA-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
23
# File 'lib/presence/scanner.rb', line 14

def initialize(options = nil)
  options ||= {}
  self.options = {
    retries:      1,
    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



88
89
90
91
92
93
94
95
96
# File 'lib/presence/scanner.rb', line 88

def check_env
  commands = Commands.new
  required_commands = %w{ifconfig arping}
  required_commands.each do |cmd|
    if commands.run("which #{cmd}").size == 0
      raise Presence::InvalidEnvironment.new("Unsupported platform: #{cmd} not found.")
    end
  end
end

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

Yields:

  • (scanner)


98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/presence/scanner.rb', line 98

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



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

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

#ip_prefixObject



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

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

#localhost_ipObject



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

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

#octet_rangeObject



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

def octet_range
  options[:octet_range]
end

#process_scan_result(ip, cmd, result) ⇒ Object



67
68
69
70
71
72
73
74
75
# File 'lib/presence/scanner.rb', line 67

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



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

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

#retriesObject



49
50
51
# File 'lib/presence/scanner.rb', line 49

def retries
  options[:retries]
end

#scanObject



53
54
55
56
57
58
59
# File 'lib/presence/scanner.rb', line 53

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



61
62
63
64
65
# File 'lib/presence/scanner.rb', line 61

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

#to_sObject



83
84
85
# File 'lib/presence/scanner.rb', line 83

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