Недопустимый аргумент в sendto при использовании имени интерфейса для установки IP_MULTICAST_IF

Я пишу небольшую программу, которая отправляет и получает многоадресные пакеты. Мне нужно установить исходящий интерфейс с его именем (например, eth0), а не его адрес. Поэтому я должен использовать struct ip_mreqn (а не struct in_addr), чтобы я мог использовать его поле imr_ifindex для установки индекса интерфейса (который я могу получить, используя имя интерфейса).

Однако по какой-то причине это не работает. Вызов setsockopt() работает нормально, но следующий вызов sendto() возвращает ошибку "Недопустимый аргумент". Конечно, ошибка исчезает, если я заменю ip_mreqn на in_addr и вместо этого использую адрес интерфейса.

Ниже приведен мой код:

sd = socket(AF_INET, SOCK_DGRAM, 0);

struct ip_mreqn addr;
addr.imr_ifindex = if_nametoindex("eth0");
setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr);

struct sockaddr_in sock_addr;
memset((char *) &sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = destination_port;
sock_addr.sin_addr.s_addr = destination_address;

char msg[] = "abc";

while (sendto(sd, msg, sizeof(msg), 0, reinterpret_cast<const sockaddr*>(&sock_addr),
  sizeof(sock_addr)) < 0)
    throw std::runtime_error(strerror(errno));

Есть ли проблема в использовании struct ip_mreqn при установке IP_MULTICAST_IF? У кого-нибудь есть идеи? Очень ценю помощь. Благодарю.

Обратите внимание, что порт и адрес назначения уже находятся в сетевом порядке байтов.

2 ответа

Решение

Из многоадресного руководства по tldp:

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

struct in_addr interface_addr;
setsockopt (socket, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr));

По их словам, недостаточно указателя на интерфейс.

Редактировать:
Вы, возможно, путаете IP_MULTICAST_IF с IPV6_MULTICAST_IF последний принимает целое число без знака для обозначения номера интерфейса (см. man 7 ipv6).

Редактировать:
Как оказалось, приведенный пример работает, как и ожидалось. Вот мой полный тестовый пример:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/socket.h>


int main()
{
    int sd = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in sa = {0};
    struct ip_mreqn addr = {{0}};
    char msg[] = "abc";

    addr.imr_ifindex = if_nametoindex("eth0");
    setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &addr, sizeof(addr));

    sa.sin_family = AF_INET;
    sa.sin_port = 8653;

    inet_pton(AF_INET, "224.255.255.5", &sa.sin_addr);
    if (sendto(sd, msg, sizeof(msg), 0, (void*)&sa, sizeof(sa)) < 0) {
        perror("bugger");
        return 1;
    }
    return 0;
}

В примере кода ответа не забудьте htons() порт назначения в.sin_port

Другие вопросы по тегам