Class: Rinda::RingFinger
- Inherits:
-
Object
- Object
- Rinda::RingFinger
- Defined in:
- lib/rinda2/ring/finger.rb
Overview
RingFinger is used by RingServer clients to discover the RingServer’s TupleSpace. Typically, all a client needs to do is call RingFinger.primary to retrieve the remote TupleSpace, which it can then begin using.
To find the first available remote TupleSpace:
Rinda::RingFinger.primary
To create a RingFinger that broadcasts to a custom list:
rf = Rinda::RingFinger.new ['localhost', '192.0.2.1']
rf.primary
Rinda::RingFinger also understands multicast addresses and sets them up properly. This allows you to run multiple RingServers on the same host:
rf = Rinda::RingFinger.new ['239.0.0.1']
rf.primary
You can set the hop count (or TTL) for multicast searches using #multicast_hops.
If you use IPv6 multicast you may need to set both an address and the outbound interface index:
rf = Rinda::RingFinger.new ['ff02::1']
rf.multicast_interface = 1
rf.primary
At this time there is no easy way to get an interface index by name.
Constant Summary collapse
- @@broadcast_list =
['<broadcast>', 'localhost']
- @@finger =
nil
Instance Attribute Summary collapse
-
#broadcast_list ⇒ Object
The list of addresses where RingFinger will send query packets.
-
#multicast_hops ⇒ Object
Maximum number of hops for sent multicast packets (if using a multicast address in the broadcast list).
-
#multicast_interface ⇒ Object
The interface index to send IPv6 multicast packets from.
-
#port ⇒ Object
The port that RingFinger will send query packets to.
-
#primary ⇒ Object
Contain the first advertised TupleSpace after lookup_ring_any is called.
Class Method Summary collapse
-
.finger ⇒ Object
Creates a singleton RingFinger and looks for a RingServer.
-
.primary ⇒ Object
Returns the first advertised TupleSpace.
-
.to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
Instance Method Summary collapse
-
#each ⇒ Object
Iterates over all discovered TupleSpaces starting with the primary.
-
#initialize(broadcast_list = @@broadcast_list, port = Ring_PORT) ⇒ RingFinger
constructor
Creates a new RingFinger that will look for RingServers at
port
on the addresses inbroadcast_list
. -
#lookup_ring(timeout = 5, &block) ⇒ Object
Looks up RingServers waiting
timeout
seconds. -
#lookup_ring_any(timeout = 5) ⇒ Object
Returns the first found remote TupleSpace.
-
#make_socket(address, interface_address = nil) ⇒ Object
Creates a socket for
address
with the appropriate multicast options for multicast addresses. -
#send_message(address, message) ⇒ Object
:nodoc:.
-
#to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
Constructor Details
#initialize(broadcast_list = @@broadcast_list, port = Ring_PORT) ⇒ RingFinger
Creates a new RingFinger that will look for RingServers at port
on the addresses in broadcast_list
.
If broadcast_list
contains a multicast address then multicast queries will be made using the given multicast_hops and multicast_interface.
102 103 104 105 106 107 108 109 110 |
# File 'lib/rinda2/ring/finger.rb', line 102 def initialize(broadcast_list=@@broadcast_list, port=Ring_PORT) @broadcast_list = broadcast_list || ['localhost'] @port = port @primary = nil @rings = [] @multicast_hops = 1 @multicast_interface = 0 end |
Instance Attribute Details
#broadcast_list ⇒ Object
The list of addresses where RingFinger will send query packets.
71 72 73 |
# File 'lib/rinda2/ring/finger.rb', line 71 def broadcast_list @broadcast_list end |
#multicast_hops ⇒ Object
Maximum number of hops for sent multicast packets (if using a multicast address in the broadcast list). The default is 1 (same as UDP broadcast).
78 79 80 |
# File 'lib/rinda2/ring/finger.rb', line 78 def multicast_hops @multicast_hops end |
#multicast_interface ⇒ Object
The interface index to send IPv6 multicast packets from.
83 84 85 |
# File 'lib/rinda2/ring/finger.rb', line 83 def multicast_interface @multicast_interface end |
#port ⇒ Object
The port that RingFinger will send query packets to.
88 89 90 |
# File 'lib/rinda2/ring/finger.rb', line 88 def port @port end |
#primary ⇒ Object
Contain the first advertised TupleSpace after lookup_ring_any is called.
93 94 95 |
# File 'lib/rinda2/ring/finger.rb', line 93 def primary @primary end |
Class Method Details
.finger ⇒ Object
Creates a singleton RingFinger and looks for a RingServer. Returns the created RingFinger.
46 47 48 49 50 51 52 |
# File 'lib/rinda2/ring/finger.rb', line 46 def self.finger unless @@finger @@finger = self.new @@finger.lookup_ring_any end @@finger end |
.primary ⇒ Object
Returns the first advertised TupleSpace.
57 58 59 |
# File 'lib/rinda2/ring/finger.rb', line 57 def self.primary finger.primary end |
.to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
64 65 66 |
# File 'lib/rinda2/ring/finger.rb', line 64 def self.to_a finger.to_a end |
Instance Method Details
#each ⇒ Object
Iterates over all discovered TupleSpaces starting with the primary.
122 123 124 125 126 127 128 129 |
# File 'lib/rinda2/ring/finger.rb', line 122 def each Enumerator.new do |y| lookup_ring_any unless @primary return unless @primary y << @primary @rings.each { |x| y << x } end end |
#lookup_ring(timeout = 5, &block) ⇒ Object
Looks up RingServers waiting timeout
seconds. RingServers will be given block
as a callback, which will be called with the remote TupleSpace.
136 137 138 139 140 141 142 143 144 |
# File 'lib/rinda2/ring/finger.rb', line 136 def lookup_ring(timeout=5, &block) return lookup_ring_any(timeout) unless block_given? msg = Marshal.dump([[:lookup_ring, DRbObject.new(block)], timeout]) @broadcast_list.each do |it| (it, msg) end sleep(timeout) end |
#lookup_ring_any(timeout = 5) ⇒ Object
Returns the first found remote TupleSpace. Any further recovered TupleSpaces can be found by calling to_a
.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/rinda2/ring/finger.rb', line 150 def lookup_ring_any(timeout=5) queue = Queue.new Thread.new do self.lookup_ring(timeout) do |ts| queue.push(ts) end queue.push(nil) end @primary = queue.pop raise('RingNotFound') if @primary.nil? Thread.new do while it = queue.pop @rings.push(it) end end @primary end |
#make_socket(address, interface_address = nil) ⇒ Object
Creates a socket for address
with the appropriate multicast options for multicast addresses.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/rinda2/ring/finger.rb', line 176 def make_socket(address, interface_address = nil) # :nodoc: addrinfo = Addrinfo.udp(address, @port) soc = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) begin if addrinfo.ipv4_multicast? then interface_address ||= '0.0.0.0' soc.setsockopt(Socket::Option.ipv4_multicast_loop(1)) soc.setsockopt(Socket::Option.ipv4_multicast_ttl(@multicast_hops)) ifreq = IPAddr.new(interface_address).hton soc.setsockopt(:IPPROTO_IP, :IP_MULTICAST_IF, ifreq) elsif addrinfo.ipv6_multicast? then soc.setsockopt(:IPPROTO_IPV6, :IPV6_MULTICAST_LOOP, true) soc.setsockopt(:IPPROTO_IPV6, :IPV6_MULTICAST_HOPS, [@multicast_hops].pack('I')) soc.setsockopt(:IPPROTO_IPV6, :IPV6_MULTICAST_IF, [@multicast_interface].pack('I')) else soc.setsockopt(:SOL_SOCKET, :SO_BROADCAST, true) end soc.connect(addrinfo) rescue Exception soc.close raise end soc end |
#send_message(address, message) ⇒ Object
:nodoc:
206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/rinda2/ring/finger.rb', line 206 def (address, ) # :nodoc: soc = if Array === address make_socket(*address) else make_socket(address) end soc.send(, 0) rescue nil ensure soc.close if soc end |
#to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
115 116 117 |
# File 'lib/rinda2/ring/finger.rb', line 115 def to_a @rings end |