Class: Rinda::RingFinger
- Inherits:
-
Object
- Object
- Rinda::RingFinger
- Defined in:
- lib/rinda/ring.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 {|@primary| ... } ⇒ 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) ⇒ 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.
340 341 342 343 344 345 346 347 348 |
# File 'lib/rinda/ring.rb', line 340 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.
309 310 311 |
# File 'lib/rinda/ring.rb', line 309 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).
316 317 318 |
# File 'lib/rinda/ring.rb', line 316 def multicast_hops @multicast_hops end |
#multicast_interface ⇒ Object
The interface index to send IPv6 multicast packets from.
321 322 323 |
# File 'lib/rinda/ring.rb', line 321 def multicast_interface @multicast_interface end |
#port ⇒ Object
The port that RingFinger will send query packets to.
326 327 328 |
# File 'lib/rinda/ring.rb', line 326 def port @port end |
#primary ⇒ Object
Contain the first advertised TupleSpace after lookup_ring_any is called.
331 332 333 |
# File 'lib/rinda/ring.rb', line 331 def primary @primary end |
Class Method Details
.finger ⇒ Object
Creates a singleton RingFinger and looks for a RingServer. Returns the created RingFinger.
284 285 286 287 288 289 290 |
# File 'lib/rinda/ring.rb', line 284 def self.finger unless @@finger @@finger = self.new @@finger.lookup_ring_any end @@finger end |
.primary ⇒ Object
Returns the first advertised TupleSpace.
295 296 297 |
# File 'lib/rinda/ring.rb', line 295 def self.primary finger.primary end |
.to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
302 303 304 |
# File 'lib/rinda/ring.rb', line 302 def self.to_a finger.to_a end |
Instance Method Details
#each {|@primary| ... } ⇒ Object
Iterates over all discovered TupleSpaces starting with the primary.
360 361 362 363 364 365 |
# File 'lib/rinda/ring.rb', line 360 def each lookup_ring_any unless @primary return unless @primary yield(@primary) @rings.each { |x| yield(x) } 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.
372 373 374 375 376 377 378 379 380 |
# File 'lib/rinda/ring.rb', line 372 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
.
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 |
# File 'lib/rinda/ring.rb', line 386 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) ⇒ Object
Creates a socket for address
with the appropriate multicast options for multicast addresses.
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 |
# File 'lib/rinda/ring.rb', line 412 def make_socket(address) # :nodoc: addrinfo = Addrinfo.udp(address, @port) soc = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol) begin if addrinfo.ipv4_multicast? then soc.setsockopt(Socket::Option.ipv4_multicast_loop(1)) soc.setsockopt(Socket::Option.ipv4_multicast_ttl(@multicast_hops)) 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:
439 440 441 442 443 444 445 446 447 |
# File 'lib/rinda/ring.rb', line 439 def (address, ) # :nodoc: soc = make_socket(address) soc.send(, 0) rescue nil ensure soc.close if soc end |
#to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
353 354 355 |
# File 'lib/rinda/ring.rb', line 353 def to_a @rings end |