Project

General

Profile

Bug #8159 » 0002-Fix-multicast-of-rinda.patch

h.shirosaki (Hiroshi Shirosaki), 04/09/2013 06:26 PM

View differences:

lib/rinda/ring.rb
# +addresses+ can contain multiple addresses. If a multicast address is
# given in +addresses+ then the RingServer will listen for multicast
# queries.
#
# If you use IPv4 multicast you may need to set an address of the inbound
# interface which joins a multicast group.
#
# ts = Rinda::TupleSpace.new
# rs = Rinda::RingServer.new(ts, [['239.0.0.1', '9.5.1.1']])
#
# You can set addresses as an Array Object. The first element of the
# Array is a multicast address and the second is an inbound interface
# address. If the second is omitted then '0.0.0.0' is used.
#
# If you use IPv6 multicast you may need to set both the local interface
# address and the inbound interface index:
#
# rs = Rinda::RingServer.new(ts, [['ff02::1', '::1', 1]])
#
# The first element is a multicast address and the second is an inbound
# interface address. The third is an inbound interface index.
#
# At this time there is no easy way to get an interface index by name.
#
# If the second is omitted then '::1' is used.
# If the third is omitted then 0 (default interface) is used.
def initialize(ts, addresses=[Socket::INADDR_ANY], port=Ring_PORT)
@port = port
......
@renewer = Renewer.new
@ts = ts
@sockets = addresses.map do |address|
make_socket(address)
@sockets = []
addresses.each do |address|
if Array === address
make_socket(*address)
else
make_socket(address)
end
end
@w_services = write_services
......
##
# Creates a socket at +address+
#
# If +address+ is multicast address then +interface_address+ and
# +multicast_interface+ can be set as optional.
#
# A created socket is bound to +interface_address+. If you use IPv4
# multicast then the interface of +interface_address+ is used as the
# inbound interface.
#
# If you use IPv6 multicast then +multicast_interface+ is used as the
# inbound interface. +multicast_interface+ is a network interface index.
def make_socket(address)
def make_socket(address, interface_address=nil, multicast_interface=0)
addrinfo = Addrinfo.udp(address, @port)
socket = Socket.new(addrinfo.pfamily, addrinfo.socktype,
......
end
if addrinfo.ipv4_multicast? then
interface_address = '0.0.0.0' if interface_address.nil?
socket.bind(Addrinfo.udp(interface_address, @port))
mreq = IPAddr.new(addrinfo.ip_address).hton +
IPAddr.new('0.0.0.0').hton
IPAddr.new(interface_address).hton
socket.setsockopt(:IPPROTO_IP, :IP_ADD_MEMBERSHIP, mreq)
else
mreq = IPAddr.new(addrinfo.ip_address).hton + [0].pack('I')
interface_address = '::1' if interface_address.nil?
socket.bind(Addrinfo.udp(interface_address, @port))
mreq = IPAddr.new(addrinfo.ip_address).hton +
[multicast_interface].pack('I')
socket.setsockopt(:IPPROTO_IPV6, :IPV6_JOIN_GROUP, mreq)
end
else
socket.bind(addrinfo)
end
socket.bind(addrinfo)
@sockets << socket
socket
end
test/rinda/test_rinda.rb
assert(v4mc.getsockopt(:SOCKET, :SO_REUSEADDR).bool)
end
assert_equal('239.0.0.1', v4mc.local_address.ip_address)
assert_equal(@port, v4mc.local_address.ip_port)
assert_equal('0.0.0.0', v4mc.local_address.ip_address)
assert_equal(@port, v4mc.local_address.ip_port)
end
def test_make_socket_ipv6_multicast
......
assert v6mc.getsockopt(:SOCKET, :SO_REUSEADDR).bool
end
assert_equal('ff02::1', v6mc.local_address.ip_address)
assert_equal('::1', v6mc.local_address.ip_address)
assert_equal(@port, v6mc.local_address.ip_port)
end
def test_ring_server_ipv4_multicast
@rs = Rinda::RingServer.new(@ts, [['239.0.0.1', '0.0.0.0']], @port)
v4mc = @rs.instance_variable_get('@sockets').first
if Socket.const_defined?(:SO_REUSEPORT) then
assert(v4mc.getsockopt(:SOCKET, :SO_REUSEPORT).bool)
else
assert(v4mc.getsockopt(:SOCKET, :SO_REUSEADDR).bool)
end
assert_equal('0.0.0.0', v4mc.local_address.ip_address)
assert_equal(@port, v4mc.local_address.ip_port)
end
def test_ring_server_ipv6_multicast
skip 'IPv6 not available' unless
Socket.ip_address_list.any? { |addrinfo| addrinfo.ipv6? }
begin
@rs = Rinda::RingServer.new(@ts, [['ff02::1', '::1', 0]], @port)
rescue Errno::EADDRNOTAVAIL
return # IPv6 address for multicast not available
end
v6mc = @rs.instance_variable_get('@sockets').first
if Socket.const_defined?(:SO_REUSEPORT) then
assert v6mc.getsockopt(:SOCKET, :SO_REUSEPORT).bool
else
assert v6mc.getsockopt(:SOCKET, :SO_REUSEADDR).bool
end
assert_equal('::1', v6mc.local_address.ip_address)
assert_equal(@port, v6mc.local_address.ip_port)
end
(2-2/2)