16

I wish to send UDP multicast packets to loopback address and receive the same in other application. All tests done on fedora core 17 Linux.

The idea is to receive a video stream via RTSP/HTTP or any other network protocol and multicast it on the loopback address so that I can use VLC to play the stream using multicast address. Leaving aside other bitrate and controlled multicast issues, I tried to read one video file and multicast on loopback device. But when tried to play the same on vlc it didn't worked. I'm able to see packet getting transmitted in wireshark but the src ip is taken from my default network interface (i.e interface which is my default gateway)

I have already tried following commands

sudo ifconfig lo multicast
sudo ip route add 239.252.10.10 dev lo

Any suggestion in this regard would be very helpful.

Test program code pasted below

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


    #define MULTICAST_ADDRESS "239.252.10.10"
    #define UDP_PORT 1234
    #define INTERFACE_IP    "127.0.0.1"
    #define MTU 1474
    #define DATA_BUFFER_SIZE  (1024*1024)

    static int  socket_init(char *intf_ip) {
    int sd;
    struct in_addr localInterface;

      sd = socket (AF_INET, SOCK_DGRAM, 0);
      if (sd < 0) {
          perror ("Opening datagram socket error");
          return -1;
      }
      else
        printf ("Opening the datagram socket...OK.\n");

      localInterface.s_addr = inet_addr (intf_ip);

      if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &localInterface,sizeof (localInterface)) < 0){
          perror ("Setting local interface error");
          close(sd);
          return -1;
      }
      else
        printf ("Setting the local interface...OK\n");
    #if 1
        char loopch = 1;

        if(setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0){
        perror("Setting IP_MULTICAST_LOOP error");
        close(sd);
        return -1;
        }
        else
        printf("Enabling the loopback...OK.\n");
    #endif
      return sd;

    }


    static int transmit_packet(int sd, char *databuf, int size,char *ip, unsigned short port){

    struct sockaddr_in groupSock;
    int len,datalen,rc;

      memset ((char *) &groupSock, 0, sizeof (groupSock));

      groupSock.sin_family = AF_INET;

      groupSock.sin_addr.s_addr = inet_addr (ip);

      groupSock.sin_port = htons (port);

      len=0;
      datalen = MTU;
      if(size < MTU)
        datalen = size;

      while(len < size){
        rc = sendto(sd, databuf, datalen, 0, (struct sockaddr *) &groupSock,sizeof (groupSock));
        if(rc <0){
          perror ("Sending datagram message error");
          return -1;
        }
        usleep(10000);
        len += rc;
      }
      return len;
    }

    static int transmit_file(char *filepath, char *dstip, char *srcip,unsigned short port) {
    FILE *fp;
    int sd,rc;
    char *databuf;


        fp = fopen(filepath, "r");
        if(!fp) {
        printf("transmit_file : no such file or directory %s \n",filepath);
        return -1;
        }
        sd = socket_init(srcip);
        if(sd < 0) {
        printf("Socket initialization failed \n");
        fclose(fp);
        return -1;
        }
        databuf = (char*) malloc(sizeof(char)*DATA_BUFFER_SIZE);
        if(!databuf) {
        printf("Unable to allocate databuf\n");
        close(sd);fclose(fp);
        return -1;
        }
        while(!feof(fp)){
        rc = fread(databuf,1,DATA_BUFFER_SIZE,fp);
        if(rc<= 0) {
            printf("read failed or EOF reached\n");
            break;
        }           
        if(transmit_packet(sd,databuf,rc,dstip,port) <0)
            printf("Transmit failed\n");    
        }
        close(sd);fclose(fp);
        free(databuf);
        return 0;
    }

    int main(int argc, char *argv[]){

       if(argc != 3){
        printf("%s <filename> <ip>\n",argv[0]);
        return -1;
       }
       transmit_file(argv[1],argv[2],INTERFACE_IP,UDP_PORT);
       return 0;
    }
nbro
  • 15,395
  • 32
  • 113
  • 196
Akhilesh Soni
  • 169
  • 1
  • 1
  • 3

3 Answers3

23

You can use multicast on loopback but you have to add a new route because your OS using default external interface by default for multicast. Also multicast can be disabled by default on loopback. On linux you can change this with this command :

route add -net 224.0.0.0 netmask 240.0.0.0 dev lo
ifconfig lo multicast
Azwaw
  • 548
  • 3
  • 12
  • 2
    It also works for ROS2 users. Try out following commands after setting above commands. Terminal 1: `ros2 run demo_nodes_cpp listener`, Terminal 2: `ros2 run demo_nodes_cpp talker` – Kevin Patel Jun 15 '19 at 14:27
4

Binding or routing to the loopback device is necessary if you do not want IP multicast traffic (such as IGMP messages) to be sent across the network. However, this is typically only necessary if there are other computers on the network that may interfere by using the same multicast group.

The real problem is having programs on the same host receive multicast data sent by each other (or, equivalently, having sockets within a single program receive multicast data sent by each other), when they're both configured to use the same multicast group.

This is quite a common question with many StackOverflow questions on it, but they are often misunderstood or poorly worded. It is difficult to search for this problem specifically with regards to operating system behavior or standardization.

On the hardware level, multicast traffic is treated like broadcast traffic in that it is not routed back to the physical port it was sent from in order to prevent link level loops. This means that the operating system is responsible for forwarding traffic to other programs or sockets on the same host that joined a multicast group, since it won't be read from the interface.

This is configured by the standard IP_MULTICAST_LOOP option, which is best summarized by the IP Multicast MSDN article (archived):

Currently, most IP multicast implementations use a set of socket options proposed by Steve Deering to the Internet Engineering Task Force (IETF). Five operations are thus made available:

[...]

  • IP_MULTICAST_LOOP—Controls loopback of multicast traffic.

[...]

The Winsock version of the IP_MULTICAST_LOOP option is semantically different than the UNIX version of the IP_MULTICAST_LOOP option:

  • In Winsock, the IP_MULTICAST_LOOP option applies only to the receive path.
  • In the UNIX version, the IP_MULTICAST_LOOP option applies to the send path.

For example, applications ON and OFF (which are easier to [keep track of] than X and Y) join the same group on the same interface; application ON sets the IP_MULTICAST_LOOP option on, application OFF sets the IP_MULTICAST_LOOP option off. If ON and OFF are Winsock applications, OFF can send to ON, but ON cannot sent to OFF. In contrast, if ON and OFF are UNIX applications, ON can send to OFF, but OFF cannot send to ON.

From what I have read this is setting may be disabled by default on Windows and enabled by default on Linux, but I haven't tested it myself.

As an important side note, the IP_MULTICAST_LOOP option is entirely different from the IPV6_MULTICAST_LOOP option, referring to the Linux ip(7) and ipv6(7) man pages:

IP_MULTICAST_LOOP (since Linux 1.2) Set or read a boolean integer argument that determines whether sent multicast packets should be looped back to the local sockets.

IPV6_MULTICAST_LOOP Control whether the socket sees multicast packets that it has [sent] itself. Argument is a pointer to boolean.

IP_MULTICAST_LOOP allows IP multicast traffic to be received on different sockets on the same host it was sent. IPV6_MULTICAST_LOOP allows IPv6 multicast traffic to be received on the same socket it was sent -- something which is not typically possible with IPv4.

If anyone has references to official standards about the intended behavior of implementations (RFCs, IEEE POSIX standards, etc.), please post them in the comments or edit this answer.

-6

I wish to send UDP multicast packets to loopback address

Stop right there. You can't do that. It's impossible. You can only send multicasts to multicast addresses. Your code doesn't do any multicasting, just sending to 127.0.0.1.

If you're only sending to the localhost, why are you using multicast at all? Do you have multiple listening processes?

the src ip is taken from my default network interface(i.e interface which is my default gateway)

Very likely, as you haven't bound your socket. What did you expect?

user207421
  • 305,947
  • 44
  • 307
  • 483
  • The multicast address can be given from command line which is taken as destination ip. Basically i want to transmit whatever i receive to loopback interface in a multicast way so that one application can receive it to record in a file while another application plays it and so on. That's why multicast destination is set for the udp packet's destination ip. – Akhilesh Soni Apr 16 '13 at 06:32
  • For interface src ip even if I bind the socket to 127.0.0.1 still it doesn't take that in outgoing packets. – Akhilesh Soni Apr 16 '13 at 06:34
  • 3
    @EJP What if I want to have multiple processes read from one stream in a sub/pub kind of way? Live video for instance. – Aron Nov 16 '15 at 08:11
  • This answer isn't any helpful with regard to what the OP already explains, as well as factually wrong. – Tchakabam Oct 08 '20 at 01:08