Erreur « Aucun tel dispositif » dans setsockopt d'appel lors de l'adhésion groupe de multidiffusion
-
02-10-2019 - |
Question
J'ai un code dans lequel envoyer datagrammes multicast. Un élément essentiel de 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");
}
...
Parfois, programme exécute avec succès (en ce moment j'ai IP - 192.168.80.122
). Je peux capturer mon datagrammes multicast par Wireshark. C'est tout OK.
Mais si je change mon adresse IP à 192.168.1.2
, je reçois l'erreur quand on appelle
int optres =
setsockopt( sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req,
sizeof( req ));
Et je ne peux même pas capturer mon paquet de multidiffusion. Rien n'est envoyé. Le bug Où?
La solution
Si cela fonctionne pour une IP, mais pas pour une autre, peut-être cette aide peut.
Qu'est-ce? "IP_ADD_MEMBERSHIP: Aucun dispositif" moyenne
Cela signifie que l'outil tente d'utiliser la multidiffusion, mais l'interface réseau ne supporte pas Il y a deux causes possibles:
La machine ne supporte pas la multidiffusion. Par exemple, sous Linux et FreeBSD, il est possible de compiler un noyau qui ne prend pas en charge la multidiffusion.
Vous ne disposez pas d'un itinéraire pour le trafic de multidiffusion. Certains systèmes n'ajoutent pas par défaut, et vous devez exécuter.
route add -net 224.0.0.0 netmask 224.0.0.0 eth0
(ou similaire). Si vous souhaitez utiliser RAT en mode unicast seulement, il est possible d'ajouter la route de multidiffusion sur l'interface loopback.
Autres conseils
IP_ADD_MEMBERSHIP
et bind()
ne sont nécessaires pour recevoir la multidiffusion, l'utilisation IP_MULTICAST_IF
plutôt pour efficacement une « adhésion d'envoi uniquement » d'un groupe de multidiffusion.
IP_MULTICAST_IF
définit le noyau d'envoyer des paquets de multidiffusion pour un groupe donné sur une interface donnée, il est efficace « envoyer uniquement » que vous ne serez pas en mesure de recevoir le trafic sur ce groupe après réglage. Cela varie selon la plate-forme. Plates-formes Posix fonctionnent généralement de cette façon comme une optimisation, tandis que Win32 interprétera niveau du logiciel de routage pour propager les paquets générés localement