Прослушивание многоадресных рассылок IPv6 в Linux - PullRequest
3 голосов
/ 03 октября 2010

Я пытаюсь получить простой пример многоадресной рассылки для работы в Linux пробовал оба RHEL 4 2.6.9 и Ubuntu 8.04 2.6.24). Общая идея что я хотел бы, чтобы сервер связался с одноадресным адресом, а затем добавил сама к группе ff02 :: 1. Я бы тогда хотел это получить многоадресная рассылка отправлена ​​на ff02 :: 1. Код ниже работает на Mac OS X 10.5 (в Фактически, сервер, работающий на OS X, получает многоадресные рассылки, отправленные из Linux клиенты), но я не могу заставить работать сервер Linux. Это не получить многоадресную рассылку. Если я изменю код для привязки к :: (INADDR6_ANY) а не одноадресный адрес (я пробовал как локальные, так и глобальные ссылки адреса), он получает многоадресную рассылку. Мне было интересно, если кто-то могу указать, что я делаю не так.

Сервер:

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;
    }
}

Код клиента выглядит следующим образом:

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 );

1 Ответ

3 голосов
/ 04 октября 2010

Привязка фильтрует входящие адреса, поэтому, если вы привязываетесь к адресу адаптера, вы получаете только пакеты с совпадающим адресом назначения: то есть одноадресные пакеты, если вы привязываетесь к многоадресному адресу, вы будете получать только многоадресные пакеты;чтобы получить многоадресные и одноадресные пакеты, вы должны связать их с INADDR_ANY или IN6ADDR_ANY.

...