2
* Copyright (C) 2006 Justin Karneges
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
#include "netinterface.h"
23
#include "irisnetplugin.h"
24
#include "irisnetglobal_p.h"
26
#include <QWaitCondition>
32
//----------------------------------------------------------------------------
34
//----------------------------------------------------------------------------
35
class NetTracker : public QObject {
38
QList<NetInterfaceProvider::Info> getInterfaces() {
39
QMutexLocker locker(&m);
45
QList<IrisNetProvider*> list = irisNetProviders();
48
foreach(IrisNetProvider* p, list) {
49
c = p->createNetInterfaceProvider();
52
Q_ASSERT(c); // we have built-in support, so this should never fail
53
connect(c, SIGNAL(updated()), SLOT(c_updated()));
56
info = filterList(c->interfaces());
60
QMutexLocker locker(&m);
70
static QList<NetInterfaceProvider::Info> filterList(const QList<NetInterfaceProvider::Info> &in) {
71
QList<NetInterfaceProvider::Info> out;
72
for(int n = 0; n < in.count(); ++n)
74
if(!in[n].isLoopback) out += in[n];
82
QMutexLocker locker(&m);
83
info = filterList(c->interfaces());
90
// this are all protected by m
91
NetInterfaceProvider *c;
93
QList<NetInterfaceProvider::Info> info;
98
// Global because static getRef needs this too.
99
Q_GLOBAL_STATIC(QMutex, nettracker_mutex)
101
class NetTrackerThread : public QThread {
104
/** Get a reference to the NetTracker singleton.
105
Calls to getInterfaces will immediately give valid results
107
static NetTrackerThread* getRef() {
108
QMutexLocker locker(nettracker_mutex());
111
self = new NetTrackerThread();
117
/** Release reference.
120
QMutexLocker locker(nettracker_mutex());
132
QList<NetInterfaceProvider::Info> getInterfaces() {
133
return nettracker->getInterfaces();
137
~NetTrackerThread() {
138
// locked from caller
146
// locked from caller
148
moveToThread(QCoreApplication::instance()->thread());
149
startMutex = new QMutex();
151
QMutexLocker startLocker(startMutex);
153
startCond.wait(startMutex); // wait for thread startup finished
161
QMutexLocker locker(startMutex);
163
nettracker = new NetTracker();
164
connect(nettracker, SIGNAL(updated()), SIGNAL(updated()), Qt::DirectConnection);
166
startCond.wakeOne(); // we're ready to serve.
174
QWaitCondition startCond;
176
// these are all protected by global nettracker_mutex.
178
static NetTrackerThread *self;
179
NetTracker *nettracker;
182
NetTrackerThread *NetTrackerThread::self = 0;
185
//----------------------------------------------------------------------------
187
//----------------------------------------------------------------------------
188
class NetInterfacePrivate : public QObject
192
friend class NetInterfaceManagerPrivate;
196
QPointer<NetInterfaceManager> man;
199
QList<QHostAddress> addrs;
202
NetInterfacePrivate(NetInterface *_q) : QObject(_q), q(_q)
211
if (man.isNull()) return;
213
emit q->unavailable();
217
NetInterface::NetInterface(const QString &id, NetInterfaceManager *manager)
220
d = new NetInterfacePrivate(this);
223
NetInterfaceProvider::Info *info = (NetInterfaceProvider::Info *)d->man->reg(id, this);
227
d->name = info->name;
228
d->addrs = info->addresses;
229
d->gw = info->gateway;
234
NetInterface::~NetInterface()
236
if (d->valid && !d->man.isNull()) d->man->unreg(this);
240
bool NetInterface::isValid() const
242
return d->valid && !d->man.isNull();
245
QString NetInterface::id() const
250
QString NetInterface::name() const
255
QList<QHostAddress> NetInterface::addresses() const
260
QHostAddress NetInterface::gateway() const
265
//----------------------------------------------------------------------------
266
// NetInterfaceManager
267
//----------------------------------------------------------------------------
268
class NetInterfaceManagerPrivate : public QObject
272
NetInterfaceManager *q;
274
QList<NetInterfaceProvider::Info> info;
275
QList<NetInterface*> listeners;
276
NetTrackerThread *tracker;
280
NetInterfaceManagerPrivate(NetInterfaceManager *_q) : QObject(_q), q(_q)
282
tracker = NetTrackerThread::getRef();
284
connect(tracker, SIGNAL(updated()), SLOT(tracker_updated()));
287
~NetInterfaceManagerPrivate() {
288
tracker->releaseRef();
292
static int lookup(const QList<NetInterfaceProvider::Info> &list, const QString &id)
294
for(int n = 0; n < list.count(); ++n) {
295
if(list[n].id == id) return n;
300
static bool sameContent(const NetInterfaceProvider::Info &a, const NetInterfaceProvider::Info &b)
302
// assume ids are the same already
303
return (a.name == b.name && a.isLoopback == b.isLoopback && a.addresses == b.addresses && a.gateway == b.gateway);
308
// grab the latest info
309
QList<NetInterfaceProvider::Info> newinfo = tracker->getInterfaces();
311
QStringList here_ids, gone_ids;
314
for(int n = 0; n < info.count(); ++n)
316
int i = lookup(newinfo, info[n].id);
320
if(!sameContent(info[n], newinfo[i])) {
321
gone_ids += info[n].id;
322
here_ids += info[n].id;
324
} else { // id is gone
325
gone_ids += info[n].id;
330
for(int n = 0; n < newinfo.count(); ++n) {
331
int i = lookup(info, newinfo[n].id);
333
here_ids += newinfo[n].id;
338
for(int n = 0; n < gone_ids.count(); ++n) {
339
// work on a copy, just in case the list changes.
340
// it is important to make the copy here, and not
341
// outside the outer loop, in case the items
343
QList<NetInterface*> list = listeners;
344
for(int i = 0; i < list.count(); ++i) {
345
if(list[i]->d->id == gone_ids[n]) {
346
list[i]->d->doUnavailable();
352
for(int n = 0; n < here_ids.count(); ++n)
353
emit q->interfaceAvailable(here_ids[n]);
357
void tracker_updated()
359
// collapse multiple updates by queuing up an update if there isn't any queued yet.
361
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
373
NetInterfaceManager::NetInterfaceManager(QObject *parent)
376
d = new NetInterfaceManagerPrivate(this);
379
NetInterfaceManager::~NetInterfaceManager()
384
QStringList NetInterfaceManager::interfaces() const
386
d->info = d->tracker->getInterfaces();
388
for(int n = 0; n < d->info.count(); ++n) {
389
out += d->info[n].id;
394
QString NetInterfaceManager::interfaceForAddress(const QHostAddress &a)
396
NetInterfaceManager netman;
397
QStringList list = netman.interfaces();
398
for(int n = 0; n < list.count(); ++n) {
399
NetInterface iface(list[n], &netman);
400
if(iface.addresses().contains(a)) return list[n];
405
void *NetInterfaceManager::reg(const QString &id, NetInterface *i)
407
for(int n = 0; n < d->info.count(); ++n) {
408
if(d->info[n].id == id) {
410
return new NetInterfaceProvider::Info(d->info[n]);
416
void NetInterfaceManager::unreg(NetInterface *i)
418
d->listeners.removeAll(i);
423
#include "netinterface.moc"