Я пытаюсь реализовать очень простой контроллер upnp на linux, чтобы я мог управлять устройством, которое в противном случае требует проприетарного программного обеспечения.Прослушивание одноадресного ответа UDP на сообщение многоадресной рассылки UDP
Документы говорят, что мне нужно отправить запрос многоадресной рассылки UDP определенной формы (см. Строку «М-ПОИСК» в приведенном ниже коде) на конкретный адрес и порт, и что устройства будут отвечать UDP unicast по адресу и порту, который я отправил.
Я не могу выполнить эту работу. tcpdump показывает, что запрос многоадресной рассылки UDP подходит к правильному адресу и порту, и формат отображается правильно, но я не вижу ответа.
Отправляю и слушаю интерфейс loopback (устройство находится на одной машине).
Другой контроллер upnp (т. Е. Не мой) работает правильно на интерфейсе петлевой петли.
Может кто-нибудь предложить, что я делаю неправильно?
Вот код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <unistd.h>
#include <fcntl.h>
#define MAXBUFSIZE 65536
int main(int argc, char ** argv) {
unsigned char loop;
loop = 0;
unsigned char ttl;
ttl = 4;
int bcast;
bcast = 1;
int sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
struct sockaddr_in destadd;
memset(&destadd, 0, sizeof(destadd));
destadd.sin_family = AF_INET;
destadd.sin_port = htons((uint16_t)1900);
if (inet_pton(AF_INET, "239.255.255.250", &destadd.sin_addr) < 1) {
perror("inet_pton dest");
exit(EXIT_FAILURE);
}
struct sockaddr_in interface_addr;
memset(&interface_addr, 0, sizeof(interface_addr));
interface_addr.sin_family = AF_INET;
interface_addr.sin_port = htons(0);
if (inet_pton(AF_INET, "127.0.0.1", &interface_addr.sin_addr) < 1) {
perror("inet_pton interface");
exit(EXIT_FAILURE);
}
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0){
perror("setsockopt loop");
exit(EXIT_FAILURE);
}
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0){
perror("setsockopt ttl");
exit(EXIT_FAILURE);
}
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
(struct in_addr *)&interface_addr.sin_addr,
sizeof(interface_addr.sin_addr)) < 0) {
perror("setsockopt if");
exit(EXIT_FAILURE);
}
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bcast, sizeof(bcast)) < 0) {
perror("setsockopt bcast");
exit(EXIT_FAILURE);
}
struct ip_mreqn imr;
memset(&imr, 0, sizeof(imr));
if (inet_pton(AF_INET, "239.255.255.250", &imr.imr_multiaddr.s_addr) < 1) {
perror("inet_pton");
exit(EXIT_FAILURE);
}
inet_pton(AF_INET, "127.0.0.1", (struct in_addr *)&imr.imr_address);
imr.imr_ifindex = 0;
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(void *)&imr, sizeof(imr)) < 0) {
perror("setsockopt addmem");
exit(EXIT_FAILURE);
}
if (bind(sock, (struct sockaddr *)&interface_addr,
sizeof(struct sockaddr_in)) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
char buffer[1024];
strcpy(buffer, "M-SEARCH * HTTP/1.1\r\n"
"Host: 239.255.255.250:1900\r\n"
"Man: \"ssdp:discover\"\r\n"
"ST: upnp:rootdevice\r\n"
"MX: 3\r\n"
"User-Agent: Test/1.0\r\n"
"\r\n");
if (sendto(sock, buffer, strlen(buffer), 0, (struct sockaddr*)&destadd,
sizeof(destadd)) < 0) {
perror("sendto");
exit(EXIT_FAILURE);
}
if (recvfrom(sock, &buffer, sizeof(buffer)-1, 0, NULL, NULL) < 0) {
perror("recvfrom");
exit(EXIT_FAILURE);
}
if (close(sock) < 0) {
perror("close");
exit(EXIT_FAILURE);
}
}
Устройство находится на локальном хосте? Как? Попробуйте удалить шаг 'bind()' и шаг 'IP_MULTICAST_IF'. – EJP
Чтобы избежать проблем с брандмауэром, я начинаю с устройства DLNA, которое находится в программном обеспечении (minidlna) и работает в локальной системе. Как только я получу эту работу, я попытаюсь использовать реальное устройство в локальной сети. minidlna отвечает от localhost на другие контроллеры DLNA. Спасибо за предложенные средства. К сожалению, если я удалю шаг IP_MULTICAST_IF, трафик из моей программы выходит на eth0.Удаление связывания в одиночку или как bind, так и IP_MULTICAST_IF, похоже, не решает проблему. – Tony
Каков результат маршрута -n на вашем компьютере? – wick