Class: Frisky::SSDP::MulticastConnection

Inherits:
EventMachine::Connection
  • Object
show all
Includes:
NetworkConstants, LogSwitch
Defined in:
lib/frisky/ssdp/multicast_connection.rb

Direct Known Subclasses

Listener, Notifier, Searcher

Constant Summary

Constants included from NetworkConstants

NetworkConstants::BROADCAST_IP, NetworkConstants::MULTICAST_IP, NetworkConstants::MULTICAST_PORT, NetworkConstants::TTL

Instance Method Summary collapse

Constructor Details

#initialize(ttl = TTL) ⇒ MulticastConnection

Returns a new instance of MulticastConnection.

Parameters:

  • ttl (Fixnum) (defaults to: TTL)

    The TTL value to use when opening the UDP socket required for SSDP actions.



19
20
21
22
23
24
25
26
27
# File 'lib/frisky/ssdp/multicast_connection.rb', line 19

def initialize(ttl=TTL)
  @ttl = ttl

  @discovery_responses = EM::Channel.new
  @alive_notifications = EM::Channel.new
  @byebye_notifications = EM::Channel.new

  setup_multicast_socket
end

Instance Method Details

#parse(data) ⇒ Hash

Converts the headers to a set of key-value pairs.

Parameters:

  • data (String)

    The data to convert.

Returns:

  • (Hash)

    The converted data. Returns an empty Hash if it didn’t know how to parse.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/frisky/ssdp/multicast_connection.rb', line 45

def parse(data)
  new_data = {}

  unless data =~ /\n/
    log 'Received response as a single-line String.  Discarding.'
    log "Bad response looked like:\n#{data}"
    return new_data
  end

  data.each_line do |line|
    line =~ /(\S+):(.*)/

    unless $1.nil?
      key = $1
      value = $2
      key = key.gsub('-', '_').downcase.to_sym
      new_data[key] = value.strip
    end
  end

  new_data
end

#peer_infoArray<String,Fixnum>

Gets the IP and port from the peer that just sent data.

Returns:

  • (Array<String,Fixnum>)

    The IP and port.



32
33
34
35
36
37
38
# File 'lib/frisky/ssdp/multicast_connection.rb', line 32

def peer_info
  peer_bytes = get_peername[2, 6].unpack('nC4')
  port = peer_bytes.first.to_i
  ip = peer_bytes[1, 4].join('.')

  [ip, port]
end

#set_membership(membership) ⇒ Object

Parameters:

  • membership (String)

    The network byte ordered String that represents the IP(s) that should join the membership group.



83
84
85
# File 'lib/frisky/ssdp/multicast_connection.rb', line 83

def set_membership(membership)
  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, membership)
end

#set_multicast_ttl(ttl) ⇒ Object

Parameters:

  • ttl (Fixnum)

    TTL to set IP_MULTICAST_TTL to.



88
89
90
91
# File 'lib/frisky/ssdp/multicast_connection.rb', line 88

def set_multicast_ttl(ttl)
  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL,
    [ttl].pack('i'))
end

#set_ttl(ttl) ⇒ Object

Parameters:

  • ttl (Fixnum)

    TTL to set IP_TTL to.



94
95
96
# File 'lib/frisky/ssdp/multicast_connection.rb', line 94

def set_ttl(ttl)
  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_TTL, [ttl].pack('i'))
end

#setup_multicast_socketObject

Sets Socket options to allow for multicasting. If ENV is equal to “testing”, then it doesn’t turn off multicast looping.



70
71
72
73
74
75
76
77
78
79
# File 'lib/frisky/ssdp/multicast_connection.rb', line 70

def setup_multicast_socket
  set_membership(IPAddr.new(MULTICAST_IP).hton +
    IPAddr.new('0.0.0.0').hton)
  set_multicast_ttl(@ttl)
  set_ttl(@ttl)

  unless ENV['RUBY_UPNP_ENV'] == 'testing'
    switch_multicast_loop :off
  end
end

#switch_multicast_loop(on_off) ⇒ Object

Parameters:

  • on_off (Symbol)

    Turn on/off multicast looping. Supply :on or :off.



99
100
101
102
103
104
105
106
107
108
109
# File 'lib/frisky/ssdp/multicast_connection.rb', line 99

def switch_multicast_loop(on_off)
  hex_value = case on_off
  when :on then "\001"
  when "\001" then "\001"
  when :off then "\000"
  when "\000" then "\000"
  else raise SSDP::Error, "Can't switch IP_MULTICAST_LOOP to '#{on_off}'"
  end

  set_sock_opt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_LOOP, hex_value)
end