Hello,

I'm trying to get a simple multicasting example to work on Linux (I've
tried both RHEL 4 2.6.9 and Ubuntu 8.04 2.6.24). The general idea is
that I would like the server to bind to a unicast address and then add
itself to the group ff02::1. I would then like it to receive
multicasts sent to ff02::1. The code below works on Mac OS X 10.5 (in
fact, a server running on OS X gets multicasts sent from Linux
clients), but I can't get the Linux server side to work. It doesn't
get any multicasts. If I change the code to bind to :: (INADDR_ANY)
rather than a unicast address (I've tried both link-local and global
addresses), it does get the multicasts. I was wondering if someone
could point out what I'm doing wrong.

server:

memset( &hint, 0, sizeof( hint ) );

hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_DGRAM;

// argv[1] is either a link-local or a global address
err = getaddrinfo( argv[1], NULL, &hint, &info );

if( err != 0 ) {
perror( "getaddrinfo" );
exit( 1 );
}

struct sockaddr_in6 * addr = (struct sockaddr_in6*)info->ai_addr;
//addr->sin6_addr = in6addr_any; // if this is uncommented,
multicasts are received
addr->sin6_port = htons( 7890 );
s = socket( AF_INET6, SOCK_DGRAM, 0 );

if( bind( s, (struct sockaddr*) addr, info->ai_addrlen ) != 0 ) {
close( s );
perror( "bind" );
exit( 1 );
}

if( getaddrinfo( "ff02::1", NULL, &hint, &multi ) != 0 ) {
close( s );
perror( "getaddrinfo" );
exit( 1 );
}

struct ipv6_mreq mreq;
memset( &mreq, 0, sizeof(mreq) );
memcpy( &mreq.ipv6mr_multiaddr,
&((struct sockaddr_in6 *) multi->ai_addr)->sin6_addr,
sizeof(mreq.ipv6mr_multiaddr) );
mreq.ipv6mr_interface = 2; // 2 happens to be the interface ID;
I've tried other values here
freeaddrinfo( multi );

if( setsockopt( s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
sizeof(mreq) ) != 0 ) {
close( s );
perror( "IPV6_JOIN_GROUP" );
exit( 1 );
}

for( ; ; ) {
char data[6];
size_t len;

len = recvfrom( s, data, 5, 0, NULL, NULL );
data[5] = '\0';

printf( "Received %s\n", data );

if( strcmp( data, "exitt" ) == 0 ) {
break;
}
}

The client code is as follows:

memset( &hint, 0, sizeof( hint ) );

hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_DGRAM;
hint.ai_protocol = 0;

err = getaddrinfo( "ff02::1", NULL, &hint, &info );

if( err != 0 ) {
perror( "getaddrinfo" );
return 0;
}

struct sockaddr_in6 * addr = (struct sockaddr_in6*)info->ai_addr;
addr->sin6_port = htons( 7890 );
addr->sin6_scope_id = 2; // 2 happens to be the interface ID
s = socket( AF_INET6, SOCK_DGRAM, 0 );

for( ; ; ) {
char data[6];
size_t len;

scanf( "%5s", data );
data[5] = '\0';
printf( "Sending %s\n", data );
if( sendto( s, data, 5, 0, info->ai_addr, info->ai_addrlen ) !
= 5 ) {
printf( "Error sending\n" );
}

if( strcmp( data, "exitt" ) == 0 ) {
break;
}
}

close( s );