1

我正在尝试在 C++ 中实现 UpNP,我在 google 上找到了一些资源,但没有一个有效。我发现这个工作(http://www.codeproject.com/KB/IP/upnplib.aspx)但它适用于.NET,所以我决定嗅探网络以查看代码在做什么,然后做同样的事情插座。

以下是结果(全尺寸:http: //i.stack.imgur.com/eLoHK.jpg): 在此处输入图像描述

这表明我的数据包看起来不错,一切似乎都一样,除了源地址之外的一切,我不知道如何控制(我的代码和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()) 打印“未知错误”。

我希望有人能引导我朝着正确的方向前进,我最近两天一直在努力完成这项工作。

4

2 回答 2

2

为什么要广播?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))
于 2011-05-19T08:02:59.697 回答
1

编辑:

正如 hasturkun 指出的那样,我最初的回答是错误的。此外,slemdx 正确诊断出问题:uPnP 请求从错误的接口发出。问题是,我不确定如何确定正确的界面。一种可能性是在路由表上使用包含默认网关的接口,但我认为这不是正确的选择。可能有连接到其他接口的 uPnP 设备。

一种选择是在所有可用接口上发送初始搜索包。也许这个问题的答案可以提供帮助。最后一个答案还有另一个链接,您应该查看。

于 2011-05-18T21:55:53.423 回答