Archive

Archive for the ‘UPnP’ Category

Qt And Custom Networking Protocols, Or: The Holy Grail Of The Internet

September 27, 2011 5 comments

In the previous installment I talked about combining UPnP’s IGD features with Qt. This culminated for me in a few days of programming and debugging in order to get a functional program working.

Let’s be short about one thing: if you intend to use Qt with custom networking protocols, meaning something other than the standard HTTP, FTP and other such generic protocols, be aware that you shouldn’t use anything more of Qt than QTcpSocket and QTcpServer. QNetworkAccessManager doesn’t work unless you want to extend its range of protocols, while it’s easier to implement the protocol outside it. Avoid QByteArrays for received data and go as low-level as possible. Unsigned integers in Qt, such as quint8 are excellent to use with a standard C/C++ array. It makes data conversion so much easier, assuming you’re using a binary protocol, like I was.

Also brush up on your bitwise operators. You’ll need to know your way with the & AND operator for masking and the << and >> bitwise shifts, such as when converting an integer to bytes for adding them to an array:

QByteArray output;
for (quint32 i = sizeof(ourInt); i > 0; --i) {
    output.append((ourInt >> ((i - 1) * 8)) & 0xFF);
}

Earlier today I finished the first alpha build of the application. It was inspired by a recent XKCD comic:

File transfers

Why not have a basic application which allows one to just transfer files without any accounts, messing with NAT router forwardings, firewalls, setting up servers and other unpleasantness? With all of the raw power available, why can’t we just give someone a link (URI/URL) which allows that person to download a file straight from our own PC? It was the original concept behind the World Wide Web after all.

May I present to you, as the first stage in making this dream a reality, the Universal Data Share (UDS) application:

UDS

For those who want to give it a try, it’s available from here, as a Windows .exe: http://www.mayaposch.com/downloads/Universal_Data_Share.exe. It’s statically compiled against the Qt libraries, so no DLLs are required. UPX was used to compress the EXE (10 MB down to 3.25 MB).

Quick usage tutorial: after starting, go to Shares -> Go Online. This initiates the UPnP IGD discovery and port mapping. Port 11310 is hard-coded in this version. Under File you can add files to the local list. Under Remote you can copy the global (external) IP to the clipboard, which will then allow another person also running UDS to connect to you and obtain a list of your shares. These can then be downloaded via a menu option as well.

In the future I’d like to add URL-based downloads, maybe even add HTTP support so that it can act like a web server, allowing anyone with a browser to connect to it. Anyway, give it a whirl and let me know how it works for you. Feature requests are also quite welcome.

For the usual disclaimer, I’ll just say that this Alpha-level software. I have tested it for the past two days on my Windows 7 Enterprise system via the loopback network. The port mapping was not directly tested and may have issues with some NAT routers. I can not take responsibility for any damage which may be caused to routers, computers, files or other hardware or software. Use of this experimental software is completely at your own risk.

Now go have fun 🙂

Maya

Advertisements
Categories: programming, Qt, Software, UPnP

Setting Up MiniUPnPc With Qt

September 18, 2011 7 comments

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/

Categories: MiniUPnP, programming, Qt, UPnP