I have tried to do a multicast on a local network in C. My main problem is that:- When I am trying to execute multiple instance listening to the broadcaster, only one client receives the message and all of the others are not receiving anything.
Multicaster Code(the one who send the create the multicast group):
int create_multidiffusion(int port, struct sockaddr_in6 *adr6)
{
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0)
{
perror("Socket creation error");
return -1;
}
memset(adr6, 0, sizeof(*adr6));
(*(adr6)).sin6_family = AF_INET6;
(*(adr6)).sin6_port = htons(port);
(*(adr6)).sin6_addr = in6addr_any;
int index = 0;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0)
{ // For multidiffusion
perror("Erreur initialisation interface locale");
close(sock);
return -1;
}
index = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &index, sizeof(index)) < 0)
{
perror("Error Reussadr");
close(sock);
return -1;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &index, sizeof(index)) < 0)
{
perror("Error Reussadr");
close(sock);
return -1;
}
if (bind(sock, (struct sockaddr *)adr6, sizeof(*adr6)) < 0)
{ // Bind
perror("Error bind");
close(sock);
return -1;
}
struct ipv6_mreq group;
inet_pton(AF_INET6, adresse, &group.ipv6mr_multiaddr);
group.ipv6mr_interface = ifindex;
if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &group, sizeof(group)) < 0)
{
perror("erroi joining multicast group");
close(sock);
return -1;
}
if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &index, sizeof(index)) < 0)
{
perror("Error activation multicast loop");
close(sock);
return -1;
}
while(1){
char *buf = readline(NULL);
size_t s = sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)adr6, sizeof(*adr6));
printf("I have send %ld data \n", s);
free(buf);
}
exit(1);
// return sock;
}
Client Code:
int join_multidiffusion(char *adresse_multidiffusion, int port, struct sockaddr_in6 *adr6)
{
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0)
{
perror("Erreur creation socket");
return -1;
}
memset(adr6, 0, sizeof(*adr6));
(*(adr6)).sin6_family = AF_INET6;
(*(adr6)).sin6_addr = in6addr_any;
(*(adr6)).sin6_port = htons(port);
int index = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &index, sizeof(index)) < 0)
{
perror("Error Reussadr");
close(sock);
return -1;
}
index = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &index, sizeof(index)) < 0)
{
perror("Error Reussport");
close(sock);
return -1;
}
if (bind(sock, (struct sockaddr *)adr6, sizeof(*adr6)) < 0)
{
perror("Bind error");
close(sock);
return -1;
}
struct ipv6_mreq group;
group.ipv6mr_interface = ifindex;
if (inet_pton(AF_INET6, adresse_multidiffusion, &group.ipv6mr_multiaddr) <= 0)
{
perror("Error inet");
close(sock);
return -1;
}
if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &group, sizeof(group)) < 0)
{ // Join the multicast group
perror("error joining multicast group");
close(sock);
return -1;
}
char buf[1000];
memset(buf,'\0',1000);
while(1){
recv(sock, buf, 1000, 0);
printf("I have received : %s\n", buf);
}
exit(0);
My goal is to make it work, on my PC first, then on LAN. I first tried using the same IP address for both the subscriber and the broadcaster, but with different port numbers — that didn’t work. Then I tried using the same IP address and the same port number, which worked at first. However, when I sent a message from the broadcaster, only one subscriber in the multicast group received it, while the others got nothing. My goal is for all subscribers in the multicast group to receive the message.
The input I have tried for the ipv6 address ff12::1234
, ff12::1:2:3
, the port : 5555
,7777
and the value of ifindex
was either 0
for the automatic interfaces or 2
which was corresponding to the interfaces of my PC wlo1
. My OS is UBUNTU, if that makes any difference.
The problem here is you're not sending where you think you're sending to.
You first set adr6
to address/port [::]:1234
which you bind to. You then pass adr6
to sendto
as the destination.
This does two things. First, it means you only ever send to the same port you're bound to, so the receiver port has to match the sender port. Second, you're sending to IP [::]
which defaults to the unicast address of the first adapter. And because you're sending to a unicast address instead of a multicast address, only one of the receivers bound to that port will receive the packet.
You need to populate a separate instance of a sockaddr_in6
for the destination, and pass that to sendto
.
struct sockaddr_in6 dest;
dest.sin6_family = AF_INET6;
dest.sin6_port = htons(destport);
inet_pton(AF_INET6, adresse, &dest.sin6_addr);
while(1){
char buf[100];
fgets(buf, sizeof buf, stdin);
size_t s = sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&dest, sizeof(dest));
printf("I have send %ld data \n", s);
}
Once you do this, all receivers will receive the packet, and the sender doesn't need to use the same port as the receivers (unless it also wants to receive the same data) nor does it need to join the multicast group.
Also, not that using SO_REUSEADDR
and SO_REUSEPORT
won't be necessary if you only run one instance of the receiver on a given host. It only matters now while you're testing multiple clients on one host.