15

I have a code in which send multicast datagrams. A critical piece of code:

uint32_t port;
int sockfd, err_ip;
const uint32_t sizebuff = 65535 - (20 + 8);
unsigned char *buff = (unsigned char *) malloc(sizebuff);
struct sockaddr_in servaddr, cliaddr;
struct in_addr serv_in_addr;
struct ip_mreq req;

port = str2uint16(cmdsrv->ipport);
bzero(buff, (size_t)sizebuff);
bzero(&servaddr, sizeof(servaddr));
bzero(&serv_in_addr, sizeof(serv_in_addr));
err_ip = inet_aton(cmdsrv->ipaddr, &serv_in_addr);

if(( err_ip != 0 ) && ( port != 0 )) {
   servaddr.sin_family = AF_INET;
   servaddr.sin_addr = serv_in_addr;
   servaddr.sin_port = htons(port);
   memcpy(&req.imr_multiaddr,&serv_in_addr,sizeof(req.imr_multiaddr));
   req.imr_interface.s_addr = INADDR_ANY;
   sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

   if( sockfd == -1 ) {
      int outerror = errno;
      char *retstr = "Couldn't open socket\n";
      pthread_exit(retstr);
   }
   else {
      struct in_addr ifaddr;
      ifaddr.s_addr = INADDR_ANY;
      int optres3 =
         setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
                     sizeof( ifaddr ));
      if( optres3 == -1 ) {
         int perrno = errno;
         char *retstr = "Can't set IP_MULTICAST_IF for socket\n";
         printf( "Error setsockopt: ERRNO = %s\n", strerror( perrno ));
         printf( "%s",retstr );
         pthread_exit(retstr);
      }

      unsigned char ttl = 32;
      int optres2 =
         setsockopt( sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl,
                     sizeof( ttl ));
      if( optres2 == -1 ) {
         int perrno = errno;
         char *retstr = "Can't set IP_MULTICAST_TTL for socket\n";
         printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
         printf("%s",retstr);
         pthread_exit(retstr);
      }

      int optres =
         setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
                     sizeof( req ));
      if( optres == -1 ) {
         int perrno = errno;
         char *retstr = "Can't join to multicast-group\n";
         printf("Error setsockopt: ERRNO = %s\n",strerror(perrno));
         printf("%s",retstr);
         pthread_exit(retstr);
      }

      // Bind port with socket
      uint16_t cliport;
      cliaddr.sin_family = AF_INET;
      cliaddr.sin_addr.s_addr = INADDR_ANY;

      if( strcmp( cmdsrv->ipport, "16011" ) == 0 ) {
         cliport = str2uint16("16003");
         cliaddr.sin_port = htons(cliport);
      }
      else if( strcmp( cmdsrv->ipport, "16012" ) == 0 ) {
         cliport = str2uint16("16004");
         cliaddr.sin_port = htons(cliport);                     
      }
      else {
         printf("Device hasn't such port");
         pthread_exit(NULL);
      }

      int bindres =
         bind( sockfd, (struct sockaddr*)&cliaddr, sizeof( cliaddr ));
      if( bindres == -1 ) {
         int perrno = errno;
         perror("Error in bind\n");
      }
      // ADD 1 BYTE
      data rawdata;
      rawdata.desc = 23;
      printf( "SIZEOF = %d\n", sizeof( *( cmdsrv->cmd )));
      memcpy( &rawdata.cmd, cmdsrv->cmd, sizeof( *( cmdsrv->cmd )));
      printf( "RAWDATA: desc = %d, cmd = %d\n", rawdata.desc, rawdata.cmd );

      int outerror = 0;
      printf( "Send command to IP:\n addr = %s, port = %d\n",
         inet_ntoa( servaddr.sin_addr ), ntohs( servaddr.sin_port ));
      int size = sendto( sockfd, &rawdata, sizeof( rawdata ), 0,
         (struct sockaddr*)&servaddr, sizeof( servaddr ));
      if( size == -1 ) {
         perror("Can't send command to socket");
      }
      ...

Sometimes program executes successfully (at this moment I have IP - 192.168.80.122). I can capture my multicast datagram by wireshark. That's all OK.

But if I change my IP to 192.168.1.2, I get error when is called

int optres =
   setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
               sizeof( req ));

And I can't even capture my multicast packet. Nothing is sent. Where's bug?

pynexj
  • 19,215
  • 5
  • 38
  • 56
Mephi_stofel
  • 355
  • 2
  • 6
  • 15

4 Answers4

28

If it works for one IP but not for another, maybe this can help.

What does "IP_ADD_MEMBERSHIP: No such device" mean?

It means that the tool is trying to use multicast but the network interface doesn't support it There are two likely causes:

  • Your machine doesn't have multicast support enabled. For example, on Linux and FreeBSD it is possible to compile a kernel which doesn't support multicast.

  • You don't have a route for multicast traffic. Some systems don't add this by default, and you need to run. route add -net 224.0.0.0 netmask 224.0.0.0 eth0 (or similar). If you wish to use RAT in unicast mode only, it is possible to add the multicast route on the loopback interface.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
Aditya Sehgal
  • 2,867
  • 3
  • 27
  • 37
  • Thank's! But if I did everything right, I did what was written in that post and that doesn't work! But now that works! Nevertheless I still can't understand behaviour my program. Because in that article nobody said about different behaviour because of various IP-addresses. – Mephi_stofel Jul 07 '10 at 14:25
  • Would like to add that my ubuntu14.04 machines sometime need the route added "route add -net 224.0.0.0 netmask 224.0.0.0 eth0" or they'll have this error too. And sometimes not. Seems to need it more often on machines with WiFi and hardwired Ethernet. So, even in 2016, this is still a problem. – david1024 Oct 19 '16 at 13:04
  • 1
    how do you decide netmask as 224.0.0.0 ? I used netmask 240.0.0.0 and it worked . So which is appropriate ? – user1371666 Jul 25 '22 at 11:24
2

IP_ADD_MEMBERSHIP and bind() are only required for receiving multicast, use IP_MULTICAST_IF instead for effectively a "send-only membership" of a multicast group.

IP_MULTICAST_IF sets the kernel to send multicast packets for a given group on a given interface, it is effectively "send-only" as you will not be able to receive traffic on that group after setting. This varies by platform: Posix platforms generally function this way as an optimisation, whilst Win32 will perform software level routing to propagate locally generated packets.

Steve-o
  • 12,678
  • 2
  • 41
  • 60
  • Yes, I join to multicast group for receiving packetes, which will send hardware after reception my packet. – Mephi_stofel Jul 07 '10 at 14:30
  • There is no such thing as 'send-only membership of a multicast group'. You don't need to join the group to send to it. – user207421 Aug 28 '19 at 04:00
  • @user207421 hence why it is mentioned in quotes, you still have to enact an operation to send only on one interface, also is not just a generic option like `SO_BINDTODEVICE`. – Steve-o Sep 14 '19 at 04:46
0

You might not use the interface address as INADDR_ANY.

req.imr_interface.s_addr = INADDR_ANY;

check where the loopback is running using ifconfig.

lo    Link encap:Local Loopback
      inet addr:127.0.0.1  Mask:255.0.0.0
      inet6 addr: ::1/128 Scope:Host
      UP LOOPBACK RUNNING  MTU:65536  Metric:1

You need to use interface address as inet addr i.e. 127.0.0.1

Check your loopback interface address and use that address only.

sachinsaini
  • 53
  • 1
  • 10
0

please recheck the netmask, ip and gateway need to in the same network.

  • 1
    This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/34012258) – user16217248 Mar 17 '23 at 03:08
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 17 '23 at 06:09