Ошибка Нет такого устройства в вызове setsockopt при присоединении к группе многоадресной рассылки

У меня есть код, в котором отправляются многоадресные дейтаграммы. Важный фрагмент кода:

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

Иногда программа выполняется успешно (на данный момент у меня IP - 192.168.80.122). Я могу захватить свою многоадресную дейтаграмму с помощью wireshark. Все в порядке.

Но если я изменю свой IP на 192.168.1.2, я получаю сообщение об ошибке при вызове

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

И я даже не могу захватить свой многоадресный пакет. Ничего не отправляется. Где ошибка?


person Mephi_stofel    schedule 06.07.2010    source источник


Ответы (2)


Если это работает для одного IP-адреса, но не для другого, возможно, это может помочь.

Что означает «IP_ADD_MEMBERSHIP: нет такого устройства»?

Это означает, что инструмент пытается использовать многоадресную рассылку, но сетевой интерфейс ее не поддерживает. Возможны две причины:

  • На вашем компьютере не включена поддержка многоадресной рассылки. Например, в Linux и FreeBSD можно скомпилировать ядро, не поддерживающее многоадресную рассылку.

  • У вас нет маршрута для многоадресного трафика. Некоторые системы не добавляют это по умолчанию, и вам нужно запустить. route add -net 224.0.0.0 netmask 224.0.0.0 eth0 (или аналогичный). Если вы хотите использовать RAT только в одноадресном режиме, можно добавить многоадресный маршрут на петлевом интерфейсе.

person Aditya Sehgal    schedule 06.07.2010
comment
Спасибо! Но если я сделал все правильно, я сделал то, что написано в том посте, и это не работает! Но теперь это работает! Тем не менее я до сих пор не могу понять поведение моей программы. Потому что в той статье никто не говорил о разном поведении из-за разных IP-адресов. - person Mephi_stofel; 07.07.2010
comment
Хотел бы добавить, что моим машинам с Ubuntu14.04 иногда требуется маршрут, добавленный маршрутом, добавить -net 224.0.0.0 netmask 224.0.0.0 eth0, иначе у них тоже будет эта ошибка. А иногда и нет. Кажется, это нужно чаще на машинах с WiFi и проводным Ethernet. Так что даже в 2016 году это все еще проблема. - person david1024; 19.10.2016

IP_ADD_MEMBERSHIP и bind() требуются только для получения многоадресной рассылки, вместо этого используйте IP_MULTICAST_IF для эффективного «членства только для отправки» в группе многоадресной рассылки.

IP_MULTICAST_IF устанавливает ядро ​​​​для отправки многоадресных пакетов для данной группы на заданном интерфейсе, это фактически «только для отправки», поскольку после настройки вы не сможете получать трафик в этой группе. Это зависит от платформы: платформы Posix обычно функционируют таким образом как оптимизация, в то время как Win32 будет выполнять маршрутизацию на уровне программного обеспечения для распространения локально сгенерированных пакетов.

person Steve-o    schedule 07.07.2010
comment
Да, я присоединяюсь к группе многоадресной рассылки для получения пакетов, которая будет отправлять оборудование после получения моего пакета. - person Mephi_stofel; 07.07.2010
comment
Не существует такого понятия, как «членство в группе многоадресной рассылки только для отправки». Вам не нужно присоединяться к группе, чтобы отправить в нее. - person user207421; 28.08.2019
comment
@user207421 user207421 поэтому, почему он упоминается в кавычках, вам все равно нужно выполнить операцию для отправки только на один интерфейс, а также это не просто общий параметр, такой как SO_BINDTODEVICE. - person Steve-o; 14.09.2019