Sometime we need to call some funtion from C library, etc. libpcap, libnids. But these C library is base on callback mechanism, how to let it work with qt signal-slot mechanism?

After some search, I found a way to wrap a callback-base C library using QThread and C++ singleton class. ()

for example, wrap libnids. is an implementation of an E-component of Network Intrusion Detection System. It use callback to pass network packet info.

To wrap this library using Qt signal, there are some points:

1. Include C head file

When include a C head file in a C++ source, must extern it to “C”

File: nidsthread.cpp

3
4
5
extern "C"{
#include "nids.h"
}

2. Call C funtion in a new thread

If don’t call funtion from libnids in a new thread, it will block the main thread.

Qt provide thread by QThread, so I create a class named NidsThread inherit QThread.

File: nidsthread.h

7
8
9
10
11
12
13
14
15
16
17
18
19
class NidsThread : public QThread
{
    Q_OBJECT
public:
    NidsThread();
    // init libnids in run(), it will execute in a new thread
    void run();
 
private:
    proxy pro;
    // callback funtion must be static
    static void callback(struct tcp_stream *a_tcp, void ** this_time_not_needed);
};

As if all nids funtion must be call in static class funtion, etc. init(), the callback funtion, exit(). (Actually I don’t know why, I hope someone tell me. : P)

Then call nids_init() in NidsThread::run, and register callback funtion.

File: nidsthread.cpp

7
8
9
10
11
12
13
14
15
16
17
18
19
20
void NidsThread::run()
{
    if (!nids_init()) {
        qDebug(nids_errbuf);
    }
    nids_register_tcp((void*)(callback));
    nids_run();
}
 
void NidsThread::callback(struct tcp_stream *a_tcp, void ** this_time_not_needed)
{
    // use Proxy to emit a signal for this callback funtion
    Proxy::singleton()->callback();
}

The proxy class will be create later.

3. Create a Proxy class to emit signals

We can call nids funtion in a new Thread now, but qt can’t emit a signal without a object. So we need to create a proxy to emit signal.

At this example, I define a tcpCallback signal in the Proxy class, and a callback funtion to emit it.

10
11
12
13
14
15
16
17
18
19
20
21
22
class proxy : public QThread
{
    Q_OBJECT
public:
    Proxy();
    // just use to emit a signal
    void callback(struct tcp_stream *a_tcp){ emit tcpCallback(a_tcp);}
    static Proxy* singleton();
signals:
    void tcpCallback(struct tcp_stream *a_tcp);
private:
    static Proxy *m_singleton;
};

And make it singleton

1
2
3
4
5
6
7
8
9
10
11
12
#include "proxy.h"
 
Proxy * Proxy::m_singleton = new Proxy();
 
Proxy::Proxy()
{
}
 
Proxy* Proxy::singleton()
{
    return m_singleton;
}

Now we can get the proxy singleton by calling Proxy::singleton(), and connect it’s signal, witch will emit in NidsThread callback funtion.

Let the proxy singleton will reduce some code for pass object between two thread. (If know a better method, tell me)

4. Connect signal

15
16
17
18
19
    MainWindow w;
 
    NidsThread nid;
    QObject::connect(Proxy::singleton(), SIGNAL(ipCallback()), &w, SLOT(parseCallback()));
    nid.start();

At this example I didn’t pass the struct tcp_stream through signal. As if signal can only deliver Type registered in QMetaType. registered struct tcp_stream or pick-up the useful data from the struct and change to QMetaType … I don’t keep on. : P

a exmaple source. dependent Libnids

 

文件: nidsproject.tar.gz
大小: 1KB
下载: 下载