Error “No existe el dispositivo” en setsockopt llamada cuando unirse al grupo de multidifusión

StackOverflow https://stackoverflow.com/questions/3187919

Pregunta

Tengo un código en el que envía los datagramas de multidifusión. Una parte crítica de código:

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");
      }
      ...

A veces se ejecuta con éxito del programa (en este momento no tienen IP - 192.168.80.122). Puedo captar mi datagramas de multidifusión por Wireshark. Eso es todo OK.

Pero si cambio de IP para 192.168.1.2, me sale error cuando se llama

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

Y ni siquiera puedo capturar mi paquete de multidifusión. No se envía nada. de donde bug?

¿Fue útil?

Solución

Si funciona para un IP pero no para otro, tal vez esta ayuda lata.

¿Qué hace? "IP_ADD_MEMBERSHIP: No existe el dispositivo" media

Esto significa que la herramienta está tratando de usar multidifusión, pero la interfaz de red no lo soporta Hay dos causas probables:

  • La máquina no tiene soporte multicast habilitado. Por ejemplo, en Linux y FreeBSD es posible compilar un kernel que no soporta multidifusión.

  • Usted no tiene una ruta para el tráfico de multidifusión. Algunos sistemas no añaden esto por defecto, y lo que necesita para funcionar. route add -net 224.0.0.0 netmask 224.0.0.0 eth0 (o similar). Si desea utilizar rata en modo unicast, es posible añadir la ruta de multidifusión en la interfaz de bucle de retorno.

Otros consejos

IP_ADD_MEMBERSHIP y bind() sólo son necesarios para la recepción de multidifusión, IP_MULTICAST_IF uso en lugar de una manera efectiva "pertenencia envío de sólo" de un grupo de multidifusión.

IP_MULTICAST_IF establece el kernel para enviar paquetes de multidifusión para un grupo dado en una interfaz determinada, es efectivamente "send-only", ya que no será capaz de recibir tráfico en ese grupo después de ajuste. Esto varía según la plataforma:. Plataformas Posix generalmente funcionan de esta manera como una optimización, mientras Win32 llevará a cabo a nivel de software de enrutamiento para propagar los paquetes generados localmente

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top