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.
341 342 343 344 345 346 347 348 349 |
# File 'lib/rinda/ring.rb', line 341 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.
310 311 312 |
# File 'lib/rinda/ring.rb', line 310 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).
317 318 319 |
# File 'lib/rinda/ring.rb', line 317 def multicast_hops @multicast_hops end |
#multicast_interface ⇒ Object
The interface index to send IPv6 multicast packets from.
322 323 324 |
# File 'lib/rinda/ring.rb', line 322 def multicast_interface @multicast_interface end |
#port ⇒ Object
The port that RingFinger will send query packets to.
327 328 329 |
# File 'lib/rinda/ring.rb', line 327 def port @port end |
#primary ⇒ Object
Contain the first advertised TupleSpace after lookup_ring_any is called.
332 333 334 |
# File 'lib/rinda/ring.rb', line 332 def primary @primary end |
Class Method Details
.finger ⇒ Object
Creates a singleton RingFinger and looks for a RingServer. Returns the created RingFinger.
285 286 287 288 289 290 291 |
# File 'lib/rinda/ring.rb', line 285 def self.finger unless @@finger @@finger = self.new @@finger.lookup_ring_any end @@finger end |
.primary ⇒ Object
Returns the first advertised TupleSpace.
296 297 298 |
# File 'lib/rinda/ring.rb', line 296 def self.primary finger.primary end |
.to_a ⇒ Object
Contains all discovered TupleSpaces except for the primary.
303 304 305 |
# File 'lib/rinda/ring.rb', line 303 def self.to_a finger.to_a end |
Instance Method Details
#each {|@primary| ... } ⇒ Object
Iterates over all discovered TupleSpaces starting with the primary.
361 362 363 364 365 366 |
# File 'lib/rinda/ring.rb', line 361 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.
373 374 375 376 377 378 379 380 381 |
# File 'lib/rinda/ring.rb', line 373 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
.
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
# File 'lib/rinda/ring.rb', line 387 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.
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 438 |
# File 'lib/rinda/ring.rb', line 413 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:
440 441 442 443 444 445 446 447 448 |
# File 'lib/rinda/ring.rb', line 440 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.
354 355 356 |
# File 'lib/rinda/ring.rb', line 354 def to_a @rings end |