Сокет передает данные, но не может получить ответ - PullRequest
1 голос
/ 19 мая 2011

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

Вот результаты(полный размер: http://i.stack.imgur.com/eLoHK.jpg): enter image description here

Это показывает, что пакет выглядит не плохо, все выглядит одинаково, все, кроме адреса источника измой код, который я не знаю, как контролировать (мой код и finder.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 ()) выводит «Unknown error».

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

Ответы [ 2 ]

2 голосов
/ 19 мая 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))
1 голос
/ 19 мая 2011

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

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

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

...