Question

I am trying to implement UpNP in C++, I found a few sources on google but none worked. I found this one working (http://www.codeproject.com/KB/IP/upnplib.aspx) but it's for .NET, so I decided to sniff the network to see what the code was doing and then do the same with sockets.

Here are the results (full size: http://i.stack.imgur.com/eLoHK.jpg): enter image description here

That shows me that the packet doesn't look bad, everything seems to be the same, everything but the source address of my code, which I don't know how to control (both my code and finder.net.exe are being tested on the same computer connected to the same network).

Here's my code:

#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;
}

I removed all the WSAGetLastError() error checking to make the code easier to read, everything goes fine until recvfrom, that always returns -1 and strerror(WSAGetLastError()) prints "Unknown error".

I hope someone could guide me in the right direction, I've been the last two days trying to make this work.

Was it helpful?

Solution

EDIT:

As hasturkun pointed out, my initial answer was wrong. Also, slemdx correctly diagnosed the problem: the uPnP request is going out from the wrong interface. The problem is, I am not sure how you can determine the right interface. One possibility is to use the interface containing the default gateway on the routing table, but I don't think that would be the right choice. There may be uPnP devices hooked to other interfaces.

One option is to send the initial search packet on all available interfaces. Maybe the answers to this question can help. There is also another link on the last answer that you should check out.

OTHER TIPS

Why broadcast? UPnP uses multicast, so as far as I remember (Unix) you should use setsockopt() to request that the kernel join a multicast group. I am not sure about Windows, it could be the same call. Something like:

 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))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top