Home > MiniUPnP, programming, Qt, UPnP > Setting Up MiniUPnPc With Qt

Setting Up MiniUPnPc With Qt

Recently I decided to give a feature of Universal Plug ‘n’ Play (UPnP) a whirl: Internet Gateway Device protocol (IGD) [1]. This is a feature which has become commonplace in network devices, specifically routers. Previously one would have to manually set port forwardings in the router’s administration panel in order to allow programs outside the LAN to talk to programs inside it. With UPnP’s IGD functionality the LAN-based program can now take care of those port mappings/forwardings itself. Many games, chat and other programs already use it. One could say that it is now an essential skill for anyone doing serious network programming.

If you need more than just IGD, you can go with one of the more expansive SDKs [2], but otherwise you should be perfectly happy with the extremely light-weight and easy to use MiniUPnPc library [3] which implements the IGD client functionality in ANSI C. This allows it to be used with a variety of languages, in this particular case C++.

The popular C++-based framework Qt doesn’t have native support for UPnP, thus one has to use an external library to add such support. I am currently using MiniUPnPc 1.6 with the Qt 4.7.4 libraries using the MinGW compiler.

Compiling MiniUPnPC is a quick and painless process. On Windows it’s as easy as executing the provided BAT file with MinGW in the PATH and within ten seconds you are left with an .a and .lib library. There’s also MSVC project support if you want to use MSVC, although I haven’t tested it yet.

At this point we can add the first bits of IGD support to our application. Most crucial is adding these parts to the top of the source file:

#define STATICLIB
#include <miniupnpc.h>

Next we have to initialize the network socket library, in this case Winsock2:

WSADATA wsaData;
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(nResult != NO_ERROR) {
    QMessageBox::critical(this, "Error", "WSAStartup() failed.");
    return;
}

With that out of the way, we can verify that all is working using the simple demo code below:

UPNPDev* devlist;
UPNPUrls urls;
IGDdatas data;
char lanaddr[64]; // IP address on the LAN
const char* multicastif = 0;
const char* minissdpdpath = 0;
int error;
devlist = upnpDiscover(1000, multicastif, minissdpdpath, 0, 0, &error);
if (error > 0) {
    QMessageBox::critical(this, "Error", "UPnP discovery failed: " + QString::number(error));
}
else {
    error = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr));
    freeUPNPDevlist(devlist);
    if (error == 0) {
        QMessageBox::critical(this, tr("Devices"), tr("No IGD found."));
    }
    else if (error == 1) {
        QMessageBox::critical(this, tr("Devices"), tr("A valid connected IGD has been found."));
    }
    else if (error == 2) {
        QMessageBox::critical(this, tr("Devices"), tr("A valid IGD has been found, but it reported as not connected."));
    }
    else if (error == 3) {
        QMessageBox::critical(this, tr("Devices"), tr("An UPnP device was found, but wasn't recognized as an IGD."));
    }
}

As defined in the source code, the error codes for the upnpDiscover() function are as follows:

#define UPNPDISCOVER_SUCCESS (0)
#define UPNPDISCOVER_UNKNOWN_ERROR (-1)
#define UPNPDISCOVER_SOCKET_ERROR (-101)
#define UPNPDISCOVER_MEMORY_ERROR (-102)

Now, to get it all to compile so that we can test it. In our Qt project we need to add a few items to the Pro file. First, depending on whether the library file we intend to use is already in a known location (MinGW lib folder or Qt SDK’s lib folder) we may have to add its location using

LIBS += D:/dev/miniupnpc/miniupnpc.a

Personally I prefer to put the library files I use a lot in projects directly into the compiler’s lib folder. This means I only have to add the following to the Pro file for it:

LIBS += -lminiupnpc -liphlpapi

Note hereby that the library itself is called ‘libminiupnpc.a’, but we prefix with -l and omit the ‘lib’ and extension. Finally we must include the libiphlpapi.a library as it contains a number of functions used by MiniUPnPc’s network functionality.

At this point we should be able to compile the project and have it run successfully. If there’s a device on the network (router) with IGD (UPnP) enabled, it will respond to the discovery broadcast and be identified. You can verify the output using the commandline test application provided with MiniUPnPc ‘upnpc-static.exe’. Detailed sample code can be found in upnpc.c, which is the source for the test application. There isn’t much available in terms of documentation, but with some puzzling and liberal use of said sample source code, it shouldn’t be too hard to figure out how to do something.

Until next time,

Maya

[1] http://en.wikipedia.org/wiki/Internet_Gateway_Device_Protocol
[2] http://upnp.org/sdcps-and-certification/resources/sdks/
[3] http://miniupnp.free.fr/

Advertisements
Categories: MiniUPnP, programming, Qt, UPnP
  1. October 10, 2011 at 11:22 AM

    Hi Maya,

    I am trying to compile miniupnp using mingw make batch file.

    I get below error

    mkdir dll
    A subdirectory or file dll already exists.
    mingw32-make: *** [init] Error 1

    I checked for DLL directory in all the source but didnt find any directory with such a name

    I see that in mingw make file it expects an argument since it has %1

    please let me knw wht ‘m i doing wrong, any help is much appreciated

    • October 10, 2011 at 12:23 PM

      Hi veenra, what the error message seems to indicate is that there is already a dll folder in the directory containing the makefile. If there is no such folder, then I’m not sure what to suggest, except maybe creating the dll folder yourself and commenting out the mkdir command in the makefile.

      • October 10, 2011 at 12:59 PM

        thanks very much for the quick reply…it helped n it needed 1 more change to copy upnpc.o to dll directory…thanks again

  2. March 25, 2012 at 11:56 PM

    Hi, I found this blog while trying to find info on UPnP. It seems that you are defining lanaddr twice, where the second definition shadows the first and is probably incorrect, as you are passing a null pointer to UPNP_GetValidIGD.

    • March 26, 2012 at 12:05 AM

      Thank you for that comment, josiahmanson. The error you point out has been corrected in the UDS source code for a while. For some reason I didn’t correct it in the article yet. Thanks for pointing it out.

      Maya

  3. jensenr30
    July 26, 2013 at 5:38 AM

    Wow! Thanks a lot. I’ve been trying to find some documentation for this library so I can get to work writing some p2p networking software, but I couldn’t find any. It is really nice to see someone who is more familiar with building/using software development kits than I am getting things working.
    Thanks for writing this article!

    • July 26, 2013 at 5:58 PM

      You’re very welcome 🙂 I found that the provided sample code was quite informative, but it still took me a while to figure out the details.

  1. No trackbacks yet.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: