Сокет передает данные, но не может получить ответ

Я пытаюсь реализовать UpNP на C ++, я нашел несколько источников в Google, но ни один из них не работал. Я нашел этот рабочий (http://www.codeproject.com/KB/IP/upnplib.aspx), но он для .NET, поэтому я решил обнюхать сеть, чтобы увидеть, что делает код, а затем проделать то же самое с сокетами.

Вот результаты (полный размер: https://i.stack.imgur.com/eLoHK.jpg): введите описание изображения здесь

Это показывает мне, что пакет выглядит неплохо, все кажется одинаковым, все, кроме исходного адреса моего кода, который я не знаю, как контролировать (и мой код, и средство поиска .net.exe тестируются на том же компьютере, подключенном к той же сети).

Вот мой код:

#define upnp_broadcast_ip   "239.255.255.250"
#define upnp_broadcast_port 1900
#define upnp_search_request "M-SEARCH * HTTP/1.1\r\n"       \
                            "Host:239.255.255.250:1900\r\n" \
                            "ST:upnp:rootdevice\r\n"        \
                            "Man:\"ssdp:discover\"\r\n"     \
                            "MX:3\r\n"                      \
                            "\r\n"

WSAStartup(MAKEWORD(2, 2), &WsaData);

BOOL discover( )
{
    SOCKET              ConnectSocket;
    struct sockaddr_in  Addr;
    char                Buffer[1450];
    int                 t       = 0,
                        iResult = 0,
                        TrueLen = sizeof(bool);
    bool                True    = true;
    ulong               One     = 1;

    // Open datagram socket
    ConnectSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );

    // Clear out struct
    memset( &Addr, 0, sizeof(Addr) );

    // Specify the address family, IP address, and port
    Addr.sin_family      = AF_INET;
    Addr.sin_port        = htons( upnp_broadcast_port );
    Addr.sin_addr.s_addr = inet_addr( upnp_broadcast_ip );

    iResult = setsockopt( ConnectSocket, SOL_SOCKET, SO_BROADCAST, (char*)&True, TrueLen ); // Not sure what is this for

    // Transmit data
    int sent = sendto( ConnectSocket, upnp_search_request, strlen(upnp_search_request), 0, (struct sockaddr*)&Addr, sizeof(Addr) );

    // Try to receive data 10 times
    for( t = 0; t < 10; t++ )
    {
        ioctlsocket( ConnectSocket, FIONBIO, &One );

        // Clear out buffer
        memset( &Buffer, 0, sizeof(Buffer) );
        int length = sizeof(Addr);

        // Receive data
        iResult = recvfrom( ConnectSocket, Buffer, (sizeof(Buffer) - 1), 0, (struct sockaddr*)&Addr, &length );
        if( iResult == SOCKET_ERROR)
        {
            Sleep( 1000 );
            continue;
        } else {
            // Do stuff with received data
        }
    }

    closesocket( ConnectSocket );
    return FALSE;
}

Я удалил все проверки ошибок WSAGetLastError (), чтобы код было легче читать, все идет нормально, пока recvfrom, который всегда возвращает -1, а strerror (WSAGetLastError ()) печатает «Неизвестная ошибка».

Я надеюсь, что кто-то сможет направить меня в правильном направлении, последние два дня я пытался заставить эту работу работать.


person slemdx    schedule 18.05.2011    source источник
comment
IMHO, вы не должны менять вопрос так радикально: вы можете создать новый вопрос о способе получения IP-адреса, который вы ищете, но прямо сейчас заголовок вводит в заблуждение, и вы получили ответ на исходный вопрос. ..   -  person rlc    schedule 19.05.2011


Ответы (2)


РЕДАКТИРОВАТЬ:

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

Один из вариантов - отправить начальный поисковый пакет на все доступные интерфейсы. Возможно, ответы на этот вопрос помогут. Есть еще одна ссылка на последний ответ, которую вам следует проверить.

person vhallac    schedule 18.05.2011
comment
Я попытался заменить recvfrom на recv, и ничего не изменилось, я подозреваю, что моя проблема - это адрес источника первого пакета M-SEARCH, как вы можете видеть на изображении адрес источника, используемый в finder.net.exe (программное обеспечение, которое работает ) использует 192.168.1.103, который отличается от того, который использовался в моем коде (192.168.1.1), но я не знаю, как установить этот адрес (без использования более сложных кодов, которых я еще не понимаю). - person slemdx; 19.05.2011
comment
Изображение, показывающее трассировку пакетов, указывает на то, что ответный пакет просто не возвращается (при условии, что трассировка завершена). Но +1 в любом случае, потому что мне это кажется верным аргументом. - person Mark Wilkins; 19.05.2011
comment
-1, recvfrom возвращает адрес источника, в противном случае он эквивалентен простому recv - person Hasturkun; 19.05.2011

Зачем транслировать? UPnP использует многоадресную рассылку, поэтому, насколько я помню (Unix), вы должны использовать setsockopt (), чтобы запросить, чтобы ядро ​​присоединилось к группе многоадресной рассылки. Я не уверен насчет Windows, это может быть тот же вызов. Что-то типа:

 struct ip_mreq mreq;
 ....
 mreq.imr_multiaddr.s_addr=inet_addr(GROUP_IP);
 mreq.imr_interface.s_addr=htonl(INADDR_ANY);

 setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))
person tvn    schedule 19.05.2011