Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1070
  • Last Modified:

Multicast - multiple interfaces

Hello experts,

I have multiple NICs on my Linux box. Their IPs are eth0 172.22.1.10 and eth1 192.168.1.1.

I want to join a multicast group 224.3.0.15 : 55150. This multicast group is tied to 192.168.1.1.

The code to join this multicast group is:

int join_multicast_group(ip_multicast_address obj)
{
      int sd;
      struct sockaddr_in cliAddr;
      
      /* create socket */
      sd = socket(AF_INET, SOCK_DGRAM, 0);
      if (sd < 0)
      {
            printf("Cannot open socket\n");
            return -1;
      }

      struct hostent *h;
      h = gethostbyname("192.168.1.1");
      struct sockaddr_in localAddr;

      memcpy((char *) &localAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);

      /* bind any port number */
      cliAddr.sin_family = AF_INET;
      cliAddr.sin_addr.s_addr = INADDR_ANY;
      cliAddr.sin_port =  htons(obj.port);
      
      if (bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr)) < 0)
      {
            printf("Cannot bind to port: %d\n", obj.port);
            return -1;
      }

      struct sockaddr_in remoteServAddr;
      struct ip_mreq mreq;
      
      //Check ip address
      h = gethostbyname(obj.ipaddress);      
      if (h == NULL)
      {
            printf("Unknown host '%s'\n", obj.ipaddress);
            return -1;
      }
      
      memcpy((char *) &remoteServAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
      
      mreq.imr_multiaddr.s_addr = remoteServAddr.sin_addr.s_addr;

      mreq.imr_interface.s_addr = localAddr.sin_addr.s_addr;

      //Join 1 multicast group
      if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *) &mreq, sizeof(mreq)) < 0)
      {
            printf("Cannot join multicast group '%s'\n", inet_ntoa(remoteServAddr.sin_addr));
            return -1;
      }
      else
      {
            printf("join successfully to multicast group '%s'\n", inet_ntoa(remoteServAddr.sin_addr));
      }

      return sd;
}

I bind using INADDR_ANY, and I join to the specific mr_interface which is 192.168.1.1.

The code works well, I can create the socket, I can bind, I can join the multicast group with appropriate parameters.

I use /sbin/ifconfig to check it and right after the join, I see that data is coming (RX bytes is updated).

NOW my problem is that the recvfrom function blocks there awaiting for data to come. It does not return.

Please shed some lights for me. If you need any more detail, please let me know.

Grade A and 500 points are my thanks.

Best regards,
Nhuan
0
nhuanvn
Asked:
nhuanvn
  • 20
  • 19
1 Solution
 
NopiusCommented:
I have two suggestions:

1) do setsockopt() BEFORE bind.


2) Try to bind directly to multicast address.
// 224.3.0.15 = FE03000D
cliAddr.sin_addr.s_addr = htons(0xFE03000D);

0
 
nhuanvnAuthor Commented:
Hello Nopius,

224.3.0.15 = 0xE003000D, not 0xFE03000D (0xFE03000D = 254.3.0.15). I will try your second suggestions first and will let you know. Could you please explain a little bit more about parameters for setsockopt()?

Thank you for your help,

Nhuan
0
 
NopiusCommented:
My second suggestion will hardly help you, chanking setsockopt and bind order is more significant.
man setsockopt
this link may also be useful: http://www.cs.unc.edu/~jeffay/dirt/FAQ/comp249-001-F99/mcast-socket.html
0
Free Backup Tool for VMware and Hyper-V

Restore full virtual machine or individual guest files from 19 common file systems directly from the backup file. Schedule VM backups with PowerShell scripts. Set desired time, lean back and let the script to notify you via email upon completion.  

 
nhuanvnAuthor Commented:
I have tried EITHER and then BOTH suggestions. Unfortunately it does not help.

Then, I found out that /sbin/route shows me something like

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.22.72.254   0.0.0.0         UG    0      0        0 eth1

This route will capture activities on 224.x.x.x. So, I add one more route to the kernel IP routing table so that I have

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
224.0.0.0       *               240.0.0.0       U     0      0        0 eth0

After this addition, when I run the code, I can see

ping 224.3.0.15
PING 224.3.0.15 (224.3.0.15) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.020 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.013 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.009 ms

Which mean I can JOIN successfully.
However, my problem still exists, I ***DO NOT*** see the recvfrom to return.

Please please help me, experts!!!
Nhuan
0
 
nhuanvnAuthor Commented:
The following shows some multicast over TCP/IP HOW TO.

http://www.tldp.org/HOWTO/Multicast-HOWTO.html

It helps me with my above findings. My problem is still there, though.
0
 
NopiusCommented:
Have you changed order of setsockopt() and bind()?
0
 
nhuanvnAuthor Commented:
Hello Nopius,

YES, and it has not helped.

I also noticed something: tcpdump showed me packets from 224.3.0.15. So data is absolutely there.

I tried its open source code and deal with libpcap. I was able to write some code, using this library to get packets from 224.3.0.15 !!! The following link is very useful for me to write my code to get packets from 224.3.0.15, utilizing libpcap:

http://www.cet.nau.edu/~mc8/Socket/Tutorials/section1.html

The problem with using libpcap is that I have to run with root privillege, and of course it is not good to do so. Another thing is that with libpcap, I have to deal with packets with Ethernet, then IP, then UDP headers before getting the payload.

I will keep using the libpcap to get data from 224.3.0.18 and will fight to use the usual recvfrom. It is irritated but it is also a good chance to study deeply into libpcap and tcpdump, and the like :-))

Any help is much appreciated. I wonder where all other experts are. Only Nopius has been trying to help me.
0
 
NopiusCommented:
You may look to sources of 'spread' library code (it's multicast communication library) http://www.spread.org/
There are soruces available for download.
in file 'data_link.c' you will find binding to multicast interface and recvfrom() on that interface.

0
 
nhuanvnAuthor Commented:
I still do not have the answer for my question. :-(
I suggest a refund.

Nopius, what do you think?
Nhuan
0
 
NopiusCommented:
nhuanvn, did you have a look inside suggested 'spread' library file?
0
 
nhuanvnAuthor Commented:
Hello Nopius,

I did take a look inside data_link.c.
You mean functions DL_init_channel and DL_recv, right? I did not see anything special to solve my problem, so I stopped.

libpcap works, and the irritation that it brings is the need to use 'root' privillege so as to run the application. I am exhausted with this issue.

Let me know what should I do with this question.

Where are other experts, Venabili?
Nhuan
0
 
NopiusCommented:
BTW what is your kernel version and compilation parameters regarding to multicast?
0
 
nhuanvnAuthor Commented:
Hello Nopius,

The kernel version is 2.4.27-2-686-smp. Compilation parameters should not cause a
problem for me, or else tcpdump cannot work.

Nhuan
0
 
NopiusCommented:
tcpdump works on raw devices, so it works always (even if you have no IP configured in your kernel).
I'll check version 2.4.27 for multicast bugs later.
0
 
nhuanvnAuthor Commented:
Hello Nopius,

I have this on my .config file:

CONFIG_IP_MULTICAST=y

There are many other kernel compilation parameters that I do not know if they relate to multicast or not. Please let me know if you need to know the setting for any dedicated compilation parameter.

Nhuan
0
 
NopiusCommented:
I recommend you to update to 2.4.32. At least in 2.4.30 there is a fix:
[NETLINK]: Fix multicast bind/autobind race

Also please post 'ifconfig eth0'. Is 'MULTICAST' there?
0
 
NopiusCommented:
After your application binds to multicast group, execute:
netstat -gn
0
 
nhuanvnAuthor Commented:
/sbin/ifconfig eth0 shows (in part):

inet addr:192.168.1.1  Bcast:192.168.1.255  Mask:255.255.255.0
inet6 addr: fe80::211:43ff:fefd:4881/64 Scope:Link
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
0
 
nhuanvnAuthor Commented:
After my application binds to multicast group, netstat -gn shows:

IPv6/IPv4 Group Memberships
Interface       RefCnt Group
--------------- ------ ---------------------
lo                1      224.0.0.1
eth0            1      224.3.0.15
eth0            1      224.0.0.1
eth1            1      224.0.0.1
lo                1      ff02::1
eth0            1      ff02::1:fffd:4881
eth0            1      ff02::1
eth1            1      ff02::1:fff6:9506
eth1            1      ff02::1
0
 
NopiusCommented:
I just compiled and tested some example code from here: http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/
there where two listeners: on Solaris (10/SPARC) and on Linux (2.6.16/i386) and everything works fine for me.

I cannot figure out what is wrong with your code, because I don't see enture picture. You provided just a code snippet without content of it's usage.
I recommend you to try this simple examples first (sender and listener). But please fix some errors in that code:

http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html#sender
change:
sizeof(message)
to
strlen(message)
in line "if (sendto(fd,message,sizeof(message),0,(struct sockaddr *) &addr,"

http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html#listener
change:
puts(message);
to:
puts(msgbuf);
in very last line, also add
bzero(msgbuf, MSGBUFSIZE)
before line "if ((nbytes=recvfrom(fd,msgbuf,MSGBUFSIZE,0,"

when you compile and run this code we may decide is it an error in your code or something wrong in the kernel.


0
 
nhuanvnAuthor Commented:
Nopius,

I think you FORGET about the problem that I am having.
On the multipcast example that you gave me the link, I saw the following lines on the listener:

mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP);
mreq.imr_interface.s_addr=htonl(INADDR_ANY);

These lines will NOT BE SUITABLE for my usage, because I have MULTIPLE INTERFACES. So "everything works fine for you" does not mean anything to my case.

I am sorry for the irritation that my problem is causing.
Nhuan
0
 
NopiusCommented:
You say, your program works with: mreq.imr_interface.s_addr=htonl(INADDR_ANY); ?
0
 
nhuanvnAuthor Commented:
Nopius,

I want to join the multicast group on the particular interface (eth1), which is not the default interface. So

mreq.imr_interface.s_addr = htonl(INADDR_ANY);

should not be applied.
0
 
NopiusCommented:
I'm sorry for my stupidity.

Probably you need to bind to socket on specific address, then to join on that socket to the multicast group:

/* before bind to 192.168.1.1 */
cliAddr.sin_addr.s_addr = htonl(0xC0A80101);
cliAddr.sin_port =  htons(obj.port);
...

/* before join to 224.3.0.15 */
mreq.imr_multiaddr.s_addr = htonl(0xE003000D);
mreq.imr_interface.s_addr = htonl(0xC0A80101);
...
0
 
nhuanvnAuthor Commented:
I tried to bind to socket on specific address, and I found out that it leads to the same result. Before joining to 224.3.0.15, I tried similar lines as you suggested:

mreq.imr_multiaddr.s_addr = htonl(0xE003000D);
mreq.imr_interface.s_addr = htonl(0xC0A80101);

If you look at my original post at the top of the page, you will see these lines:

mreq.imr_multiaddr.s_addr = remoteServAddr.sin_addr.s_addr;
mreq.imr_interface.s_addr = localAddr.sin_addr.s_addr;

0
 
NopiusCommented:
I just checked binding to specific IP address. Your code is absolutely correct.

Probably you have a routing problem in your sending side or you have very restrictive firewall.
I tested similar scenario. I have no eth1, so I binded to lo0 and recvfrom also was blocked.

My sender program (on the same host where lister) also didn't work until I fixed sending flag:

sendto(fd,message,strlen(message), MSG_DONTROUTE, (struct sockaddr *) &addr,  sizeof(addr))



0
 
NopiusCommented:
Or the same result after addition of the second route to multicast address.

Routing Table: IPv4
  Destination           Gateway           Flags  Ref   Use   Interface
-------------------- -------------------- ----- ----- ------ ---------
224.0.0.0            127.0.0.1            U         1      0  lo0
224.0.0.0            10.100.12.110        U         1      0  bge0


may be it's better to use specific gateway IP address instead of *?
0
 
nhuanvnAuthor Commented:
Nopius,

I think this is a good clue. The problem with me is that in my usage scenario, the SENDER is from an external source, it's not MY SOFTWARE. I only develop the client to recvfrom from the multicast group.

How can we check if the SENDER is in trouble (with the sending flag) or not? Also, please remember that plibcap works.

Thanks,
Nhuan



0
 
NopiusCommented:
Second route is a bad Idea, there should be only one route, since second is for redundancy only.
For me ping of multicast address works always, even if sender uses incorrect interface, but changing routing tables might help.
If nothing will work, try to add 224.3.0.15 as a host route to 192.168.1.1 as a default gateway.
0
 
nhuanvnAuthor Commented:
Please check my comment on 04/24/2006 09:07AM PDT about the gateway and routes.

Thanks,
Nhuan
0
 
NopiusCommented:
I used very simple sender,  it may be useful for testing of your listener (corrected to fit your IPs and port numbers).
Use it for testing _from_the_same_host_ as listener (at least recvfrom should unblock now, even if message format is obviously incorrect for you)

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>

/* !!!! FIX PORT NUMBER HERE !!!! */
#define HELLO_PORT
#define HELLO_GROUP "224.3.0.15"

main(int argc, char *argv[])
{
     struct sockaddr_in addr;
     int fd, cnt;
     struct ip_mreq mreq;
     char *message="Hello, World!";

     /* create what looks like an ordinary UDP socket */
     if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) {
          perror("socket");
          exit(1);
     }

     /* set up destination address */
     memset(&addr,0,sizeof(addr));
     addr.sin_family=AF_INET;
     addr.sin_addr.s_addr=inet_addr(HELLO_GROUP);
     addr.sin_port=htons(HELLO_PORT);

     /* now just sendto() our destination! */
     while (1) {
          if (sendto(fd,message,strlen(message), MSG_DONTROUTE,(struct sockaddr *) &addr,
                     sizeof(addr)) < 0) {
               perror("sendto");
               exit(1);
          }
          sleep(1);
     }
}

0
 
NopiusCommented:
Do you run sender on the same host as listener?

How can we check if the SENDER is in trouble (with the sending flag) or not? Also, please remember that plibcap works.

For testing, run this commands in two separate screens:
tcpdump -i eth0 -n multicast
tcpdump -i eth1 -n multicast

then run SENDER
then see IP source address of the packet and interface where the packet really arrives.

Probably SENDER uses system default IP address (on eth0) and then multicasts to eth0 segment, while listener listens on another network card.
0
 
nhuanvnAuthor Commented:
Nopius,

With your code above (and add the port number in, of course), I can sendto/recvfrom on the same host on the correct interface.

It shows that the CLIENT that I developed does not cause trouble. Something is with the SENDER and/or with the routing/firewall.

We come close to a solution, Nopius.

Please investigate a little bit more with me.
Thanks,
Nhuan
0
 
nhuanvnAuthor Commented:
From nhuanvn's 05/21/2006 08:46PM PDT comment:

"The problem with me is that in my usage scenario, the SENDER is from an external source, it's not MY SOFTWARE. I only develop the client to recvfrom from the multicast group"
0
 
nhuanvnAuthor Commented:
Nopius,

You wrote: Probably SENDER uses system default IP address (on eth0) and then multicasts to eth0 segment, while listener listens on another network card.

For sure the SENDER cannot multicasts to eth0 segment, because eth0 connects to a different line. The SENDDER MUST be sending data to eth1 because it connects to the correct line.
0
 
NopiusCommented:
What is your local time? 15:35 is mine.

to be shure that sender sends on correct interface run these commands:

tcpdump -i eth0 -n multicast

then

tcpdump -i eth1 -n multicast

while running sender and paste the output here
0
 
nhuanvnAuthor Commented:
My local time is 11:50 AM now.

Right now the remote SENDER does not work. It will start data transfering around 20:00 my time.

I will check it and let you know later.

Thanks,
Nhuan
0
 
VenabiliCommented:
Any update here?
0
 
NopiusCommented:
Venabili, problem was found, as I can see. But the reason is not under control of nhuanvn.
0
 
nhuanvnAuthor Commented:
Hello Nopius,

Thank you very much for your help. Up to this point what I can think of is that we have a problem with the SENDER or the routing/firewall.

I decided to close the topic because in a production point of view, I cannot survive after such a long time without answering WHY it is the case. Luckily, plibcap works and I am happy with it at the moment.

I appreciate your effort much :-))))

Happy working,
nhuanvn
0

Featured Post

Veeam and MySQL: How to Perform Backup & Recovery

MySQL and the MariaDB variant are among the most used databases in Linux environments, and many critical applications support their data on them. Watch this recorded webinar to find out how Veeam Backup & Replication allows you to get consistent backups of MySQL databases.

  • 20
  • 19
Tackle projects and never again get stuck behind a technical roadblock.
Join Now