lookuphost.cpp
1 //------------------------------------------------------------------------------
2 // lookuphost.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301, USA.
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2015 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "lookuphost.h"
24 
25 #include <QHostInfo>
26 #include <QMutex>
27 #include <QMutexLocker>
28 #include <QTimer>
29 #include "log.h"
30 
31 LookupHost *LookupHost::inst = NULL;
32 
33 DClass<LookupHost>
34 {
35 public:
40  static const int MAX_LOOKUPS = 20;
41 
42  QAtomicInt workCounter;
43  int runningLookups;
45  QMutex lock;
46  bool accepting;
47 
48  int workCount() const
49  {
50 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) && (QT_VERSION < QT_VERSION_CHECK(5, 3, 0))
51  // I have no idea why primitive cast operator was removed from
52  // QAtomicInt between versions Qt 5.0 and Qt 5.3. Qt 4.x had
53  // it. Qt >=5.3 has it.
54  return workCounter.load();
55 #else
56  return workCounter;
57 #endif
58  }
59 };
60 
61 DPointeredNoCopy(LookupHost)
62 
64 {
65  d->accepting = true;
66  d->runningLookups = 0;
67 }
68 
69 LookupHost::~LookupHost()
70 {
71 }
72 
73 void LookupHost::lookupHost(const QString &name, QObject *receiver, const char *receiverSlot)
74 {
75  instance()->lookupHost_(name, receiver, receiverSlot);
76 }
77 
78 void LookupHost::lookupHost_(const QString &name, QObject *receiver, const char *receiverSlot)
79 {
80  QMutexLocker locker(&d->lock);
81  if (!d->accepting)
82  {
83  return;
84  }
85  d->workCounter.ref();
86 
87  QTimer *timer = new QTimer();
88  LookupHostWorker *worker = new LookupHostWorker(name);
89 
90  QObject::connect(worker, SIGNAL(hostFound(QHostInfo)), receiver, receiverSlot);
91  worker->connect(timer, SIGNAL(timeout()), SLOT(work()));
92  timer->connect(timer, SIGNAL(timeout()), SLOT(deleteLater()));
93 
94  timer->start(0);
95 
96  worker->moveToThread(&d->thread);
97  timer->moveToThread(&d->thread);
98 }
99 
100 void LookupHost::finalizeAndJoin()
101 {
102  if (inst != NULL)
103  {
104  gLog << tr("Finalizing LookupHost thread");
105  instance()->finalizeAndJoin_();
106  gLog << tr("Finalized LookupHost thread");
107  }
108 }
109 
110 void LookupHost::finalizeAndJoin_()
111 {
112  {
113  QMutexLocker locker(&d->lock);
114  d->accepting = false;
115  }
116  while (d->workCount() > 0)
117  {
118  d->thread.wait(1000);
119  }
120  d->thread.quit();
121 }
122 
123 void LookupHost::derefWorkCounter()
124 {
125  d->workCounter.deref();
126 }
127 
128 LookupHost *LookupHost::instance()
129 {
130  if (inst == NULL)
131  {
132  inst = new LookupHost();
133  inst->d->thread.start();
134  }
135  return inst;
136 }
138 LookupHostWorker::LookupHostWorker(const QString &hostName)
139 {
140  this->hostName = hostName;
141 }
142 
143 void LookupHostWorker::work()
144 {
145  QMutexLocker locker(&LookupHost::instance()->d->lock);
146  if (LookupHost::instance()->d->accepting)
147  {
148  if (LookupHost::instance()->d->runningLookups < PrivData<LookupHost>::MAX_LOOKUPS)
149  {
150  ++LookupHost::instance()->d->runningLookups;
151  QHostInfo::lookupHost(hostName, this, SLOT(hostFoundReceived(QHostInfo)));
152  }
153  else
154  {
155  // Wait a while and try again.
156  QTimer::singleShot(1000, this, SLOT(work()));
157  }
158  }
159  else
160  {
161  LookupHost::instance()->derefWorkCounter();
162  deleteLater();
163  }
164 }
165 
166 void LookupHostWorker::hostFoundReceived(const QHostInfo &hostInfo)
167 {
168  QMutexLocker locker(&LookupHost::instance()->d->lock);
169  --LookupHost::instance()->d->runningLookups;
170  LookupHost::instance()->derefWorkCounter();
171  emit hostFound(hostInfo);
172  deleteLater();
173 }
175 void LookupHostConsumerThread::run()
176 {
177  qDebug() << "LookupHostConsumerThread:" << QThread::currentThreadId();
178  exec();
179 }
Definition: dptr.h:31