I am currently using Ruby 1.8.7 to develop a Linux version of a Windows tool that checks for multicast data on up to 2 interfaces based on user configured multicast groups and ports.
I had a previous issue where I wasn't sure how to listen to multiple multicast channels but that has been resolved from a previous question.
This has led to the next problem. I need to listen to multiple multicast groups and:
Determine if any data was received on each of the specficic groups and report back which ones have data and which don't
Listen for data for a user configurable timeout period on all channels at the same time
I am trying to get this working in a separate piece of code where the multicast groups, ports and interfaces are all hard coded, once I get this sorted out and understood I will migrate it to my main program where user input and validation is already complete. I have updated my simple program code so now it looks like:
#!/usr/bin/ruby
require 'socket'
require 'ipaddr'
require 'timeout'
MCAST_GROUP_A
{
:addr1 => '233.54.12.111',
:addr2 => '233.86.230.111',
:port => 26477,
:bindaddr => '172.31.230.156'
}
MCAST_GROUP_B =
{
:addr => '233.54.12.111',
:port => 18170,
:bindaddr => '172.31.230.156'
}
ipA1 = IPAddr.new(MCAST_GROUP_A[:addr1]).hton + IPAddr.new(MCAST_GROUP_A[:bindaddr]).hton
ipA2 = IPAddr.new(MCAST_GROUP_A[:addr2]).hton + IPAddr.new(MCAST_GROUP_A[:bindaddr]).hton
ipB = IPAddr.new(MCAST_GROUP_B[:addr]).hton + IPAddr.new(MCAST_GROUP_B[:bindaddr]).hton
begin
sockA = UDPSocket.open
sockB = UDPSocket.open
sockA.bind Socket::INADDR_ANY, MCAST_GROUP_A[:port]
sockB.bind Socket::INADDR_ANY, MCAST_GROUP_B[:port]
sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipA1
sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipA2
sockB.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipB
timeoutSeconds = 10
Timeout.timeout(timeoutSeconds) do
msg1, info1 = sockA.recvfrom(1024)
msg2, info2 = sockB.recvfrom(1024)
#puts "MSG: #{msg} from #{info[2]} (#{info[3]})/#{info[1]} len #{msg.size}"
puts "MSG: <garbled> from #{info1[2]} (#{info1[3]})/#{info1[1]} len #{msg1.size}"
puts "MSG: <garbled> from #{info2[2]} (#{info2[3]})/#{info2[1]} len #{msg2.size}"
end
rescue Timeout::Error
puts "Nothing received connection timedout\n"
ensure
sockA.close
sockB.close
end
But this has produced the problem in that it reports nothing is received because data on the B socket is not present.
I understand the reason for this is that the second recvfrom times out and we end up in the rescue part of the code because of that. But as this is my first Ruby program and I'm still learning about it I'm not sure what to do to resolve it.
In short I need to understand:
How to determine which channel data was received on for sockA as there are 2 multicast groups on that socket
How to monitor a configurable number of multicast groups for data at the same time and not have one failure to receive data cause an incorrect error to be output