Недопустимый аргумент в 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