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.
344 345 346 347 348 349 350 351 352 |
# File 'lib/rinda/ring.rb', line 344 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.
313 314 315 |
# File 'lib/rinda/ring.rb', line 313 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).
320 321 322 |
# File 'lib/rinda/ring.rb', line 320 def multicast_hops @multicast_hops end |
#multicast_interface ⇒ Object
The interface index to send IPv6 multicast packets from.
325 326 327 |
# File 'lib/rinda/ring.rb', line 325 def multicast_interface @multicast_interface end |
#port ⇒ Object
The port that RingFinger will send query packets to.
330 331 332 |
# File 'lib/rinda/ring.rb', line 330 def port @port end |
#primary ⇒ Object
Contain the first advertised TupleSpace after lookup_ring_any is called.
335 336 337 |
# File 'lib/rinda/ring.rb', line 335 def primary @primary end |
Class Method Details
.finger ⇒ Object
Creates a singleton RingFinger and looks for a RingServer. Returns the created RingFinger.
288 289 290 291 292 293 294 |
# File 'lib/rinda/ring.rb', line 288 def self.finger unless @@finger @@finger = self.new @@finger.lookup_ring_any end @@finger end |
.primary ⇒ Object
Returns the first advertised TupleSpace.
299 300 301 |
# File 'lib/rinda/ring.rb', line 299 def self.primary finger.primary end |
.to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
306 307 308 |
# File 'lib/rinda/ring.rb', line 306 def self.to_a finger.to_a end |
Instance Method Details
#each {|@primary| ... } ⇒ Object
Iterates over all discovered TupleSpaces starting with the primary.
364 365 366 367 368 369 |
# File 'lib/rinda/ring.rb', line 364 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.
376 377 378 379 380 381 382 383 384 |
# File 'lib/rinda/ring.rb', line 376 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
.
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'lib/rinda/ring.rb', line 390 def lookup_ring_any(timeout=5) queue = Thread::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.
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/rinda/ring.rb', line 416 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:
443 444 445 446 447 448 449 450 451 |
# File 'lib/rinda/ring.rb', line 443 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.
357 358 359 |
# File 'lib/rinda/ring.rb', line 357 def to_a @rings end |