0

The Ruby version I have available is 1.8.7 and can't be upgraded as it is part of standard image that is used on all the companies Linux servers at this time and anything I do needs to be able to run on all of these servers without issue (I'm hoping though this won't be an issue)

The project I am doing is to recreate an application that currently runs on Windows on a Linux server. The application takes a list of multicast groups and interfaces and attempts to join the groups and then listens for any data (doesn't matter what) reporting whether it could join and the data was there. It helps us in our environment prove out network connectivity prior to deployment of actual software on to the server. The data that it will be receiving will be binary encoded financial information from an exchange so I don't need to output (hence the commented out line and the output) I just need to check it is available to the server.

I have read up online and found bits and pieces of code that I have cobbled together into a small version of this where it joins 1 multicast group bound to 1 interface and listens for data for a period of time reporting whether any data was received.

I then wanted to add a second multicast group and this is where my understanding is lacking in how to achieve this. My code is as follows:

#!/usr/bin/ruby

 require 'socket'
 require 'ipaddr'
 require 'timeout'

 MCAST_GROUP_A = 
 {
   :addr => '233.54.12.111',
   :port => 26477,
   :bindaddr => '172.31.230.156'
 }
 MCAST_GROUP_B = 
 {
   :addr => '233.54.12.111',
   :port => 18170,
   :bindaddr => '172.31.230.156'
 }

 ipA = IPAddr.new(MCAST_GROUP_A[:addr]).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
   sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipA
   sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipB
   sockA.bind Socket::INADDR_ANY, MCAST_GROUP_A[:port]
   sockA.bind Socket::INADDR_ANY, MCAST_GROUP_B[:port]

   timeoutSeconds = 10
   Timeout.timeout(timeoutSeconds) do 
     msg, info = sockA.recvfrom(1024)
     #puts "MSG: #{msg} from #{info[2]} (#{info[3]})/#{info[1]} len #{msg.size}"
     puts "MSG: <garbled> from #{info[2]} (#{info[3]})/#{info[1]} len #{msg.size}"
   end
   rescue Timeout::Error
     puts "Nothing received connection timedout\n"
 ensure
   sockA.close
 end

The error I get when I run this is:

[root@dt1d-ddncche21a ~]# ./UDPServer.rb ./UDPServer.rb:35:in `setsockopt': Address already in use (Errno::EADDRINUSE) from ./UDPServer.rb:35

So that's where I am at and could really do with firstly pointers as to what is wrong (hopefully with an update to the code) and then once I this example working the next step will to be add a second interface into the mix to listen to again multiple multicast groups,

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Glen
  • 67
  • 1
  • 8
  • 1
    Having one socket join multiple multicast groups shouldn't be an issue, however a socket can only bind to one port at a time. If you need to read from multiple ports you need a separate socket for each one. – dbush Jul 01 '15 at 12:14
  • Thanks for the response. So how do I bind multiple (and there could be quite a few depending on the requirements of the user) sockets to one interface? Potentially the Port part might be the same but the Group Address could change. – Glen Jul 01 '15 at 12:33
  • 1
    The way I do it is to first bind the socket to the port I want, then call setsockopt with IP_ADD_MEMBERSHIP for each group I want to join on that port. I'm not too familiar with ruby, but that's how it's done via the C API, and it looks like the functions more or less match up. – dbush Jul 01 '15 at 12:44
  • So if I have an input file with multicast groups and ports i should group all the multicast groups that use the same port together... bind a socket to that port and then use the setsockopt IP_ADD_MEMBERSHIP to add the groups. then once i have done that move on to the next port and repeat? – Glen Jul 01 '15 at 13:31
  • Yes, that should do it. – dbush Jul 01 '15 at 13:34
  • ok then i'm going to give that a go and possibly come back with an update... it might lead to more questions which i think will be better dealt with in a new post. – Glen Jul 01 '15 at 13:38

1 Answers1

0

Ok so I followed the advice given to bind to the interface first for each port and then add members for each of the multicast groups I want to listen to and this has resolved this particular issue and moved me on to the next issue I have. The next issue I will raise as a new topic.

Glen
  • 67
  • 1
  • 8