|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtNetwork module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qhostinfo.h" |
|
43 #include "qhostinfo_p.h" |
|
44 |
|
45 #include "QtCore/qscopedpointer.h" |
|
46 #include <qabstracteventdispatcher.h> |
|
47 #include <private/qunicodetables_p.h> |
|
48 #include <qcoreapplication.h> |
|
49 #include <qmetaobject.h> |
|
50 #include <qregexp.h> |
|
51 #include <private/qnativesocketengine_p.h> |
|
52 #include <qstringlist.h> |
|
53 #include <qthread.h> |
|
54 #include <qtimer.h> |
|
55 #include <qurl.h> |
|
56 |
|
57 #ifdef Q_OS_UNIX |
|
58 # include <unistd.h> |
|
59 #endif |
|
60 |
|
61 QT_BEGIN_NAMESPACE |
|
62 |
|
63 #ifndef QT_NO_THREAD |
|
64 Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager) |
|
65 #endif |
|
66 |
|
67 //#define QHOSTINFO_DEBUG |
|
68 |
|
69 /*! |
|
70 \class QHostInfo |
|
71 \brief The QHostInfo class provides static functions for host name lookups. |
|
72 |
|
73 \reentrant |
|
74 \inmodule QtNetwork |
|
75 \ingroup network |
|
76 |
|
77 QHostInfo uses the lookup mechanisms provided by the operating |
|
78 system to find the IP address(es) associated with a host name, |
|
79 or the host name associated with an IP address. |
|
80 The class provides two static convenience functions: one that |
|
81 works asynchronously and emits a signal once the host is found, |
|
82 and one that blocks and returns a QHostInfo object. |
|
83 |
|
84 To look up a host's IP addresses asynchronously, call lookupHost(), |
|
85 which takes the host name or IP address, a receiver object, and a slot |
|
86 signature as arguments and returns an ID. You can abort the |
|
87 lookup by calling abortHostLookup() with the lookup ID. |
|
88 |
|
89 Example: |
|
90 |
|
91 \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 0 |
|
92 |
|
93 |
|
94 The slot is invoked when the results are ready. (If you use |
|
95 Qt for Embedded Linux and disabled multithreading support by defining |
|
96 \c QT_NO_THREAD, lookupHost() will block until the lookup has |
|
97 finished.) The results are stored in a QHostInfo object. Call |
|
98 addresses() to get the list of IP addresses for the host, and |
|
99 hostName() to get the host name that was looked up. |
|
100 |
|
101 If the lookup failed, error() returns the type of error that |
|
102 occurred. errorString() gives a human-readable description of the |
|
103 lookup error. |
|
104 |
|
105 If you want a blocking lookup, use the QHostInfo::fromName() function: |
|
106 |
|
107 \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 1 |
|
108 |
|
109 QHostInfo supports Internationalized Domain Names (IDNs) through the |
|
110 IDNA and Punycode standards. |
|
111 |
|
112 To retrieve the name of the local host, use the static |
|
113 QHostInfo::localHostName() function. |
|
114 |
|
115 \note Since Qt 4.6.1 QHostInfo is using multiple threads for DNS lookup |
|
116 instead of one dedicated DNS thread. This improves performance, |
|
117 but also changes the order of signal emissions when using lookupHost() |
|
118 compared to previous versions of Qt. |
|
119 \note Since Qt 4.6.3 QHostInfo is using a small internal 60 second DNS cache |
|
120 for performance improvements. |
|
121 |
|
122 \sa QAbstractSocket, {http://www.rfc-editor.org/rfc/rfc3492.txt}{RFC 3492} |
|
123 */ |
|
124 |
|
125 static QBasicAtomicInt theIdCounter = Q_BASIC_ATOMIC_INITIALIZER(1); |
|
126 |
|
127 /*! |
|
128 Looks up the IP address(es) associated with host name \a name, and |
|
129 returns an ID for the lookup. When the result of the lookup is |
|
130 ready, the slot or signal \a member in \a receiver is called with |
|
131 a QHostInfo argument. The QHostInfo object can then be inspected |
|
132 to get the results of the lookup. |
|
133 |
|
134 The lookup is performed by a single function call, for example: |
|
135 |
|
136 \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 2 |
|
137 |
|
138 The implementation of the slot prints basic information about the |
|
139 addresses returned by the lookup, or reports an error if it failed: |
|
140 |
|
141 \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 3 |
|
142 |
|
143 If you pass a literal IP address to \a name instead of a host name, |
|
144 QHostInfo will search for the domain name for the IP (i.e., QHostInfo will |
|
145 perform a \e reverse lookup). On success, the resulting QHostInfo will |
|
146 contain both the resolved domain name and IP addresses for the host |
|
147 name. Example: |
|
148 |
|
149 \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 4 |
|
150 |
|
151 \note There is no guarantee on the order the signals will be emitted |
|
152 if you start multiple requests with lookupHost(). |
|
153 |
|
154 \sa abortHostLookup(), addresses(), error(), fromName() |
|
155 */ |
|
156 int QHostInfo::lookupHost(const QString &name, QObject *receiver, |
|
157 const char *member) |
|
158 { |
|
159 #if defined QHOSTINFO_DEBUG |
|
160 qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)", |
|
161 name.toLatin1().constData(), receiver, member ? member + 1 : 0); |
|
162 #endif |
|
163 if (!QAbstractEventDispatcher::instance(QThread::currentThread())) { |
|
164 qWarning("QHostInfo::lookupHost() called with no event dispatcher"); |
|
165 return -1; |
|
166 } |
|
167 |
|
168 qRegisterMetaType<QHostInfo>("QHostInfo"); |
|
169 |
|
170 int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID |
|
171 |
|
172 if (name.isEmpty()) { |
|
173 QHostInfo hostInfo(id); |
|
174 hostInfo.setError(QHostInfo::HostNotFound); |
|
175 hostInfo.setErrorString(QObject::tr("No host name given")); |
|
176 QScopedPointer<QHostInfoResult> result(new QHostInfoResult); |
|
177 QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)), |
|
178 receiver, member, Qt::QueuedConnection); |
|
179 result.data()->emitResultsReady(hostInfo); |
|
180 return id; |
|
181 } |
|
182 |
|
183 #ifdef QT_NO_THREAD |
|
184 QHostInfo hostInfo = QHostInfoAgent::fromName(name); |
|
185 hostInfo.setLookupId(id); |
|
186 QScopedPointer<QHostInfoResult> result(new QHostInfoResult); |
|
187 QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)), |
|
188 receiver, member, Qt::QueuedConnection); |
|
189 result.data()->emitResultsReady(hostInfo); |
|
190 #else |
|
191 QHostInfoLookupManager *manager = theHostInfoLookupManager(); |
|
192 if (manager) { |
|
193 // the application is still alive |
|
194 if (manager->cache.isEnabled()) { |
|
195 // check cache first |
|
196 bool valid = false; |
|
197 QHostInfo info = manager->cache.get(name, &valid); |
|
198 if (valid) { |
|
199 info.setLookupId(id); |
|
200 QHostInfoResult result; |
|
201 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); |
|
202 result.emitResultsReady(info); |
|
203 return id; |
|
204 } |
|
205 } |
|
206 // cache is not enabled or it was not in the cache, do normal lookup |
|
207 QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id); |
|
208 QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); |
|
209 manager->scheduleLookup(runnable); |
|
210 } |
|
211 #endif |
|
212 |
|
213 return id; |
|
214 } |
|
215 |
|
216 /*! |
|
217 Aborts the host lookup with the ID \a id, as returned by lookupHost(). |
|
218 |
|
219 \sa lookupHost(), lookupId() |
|
220 */ |
|
221 void QHostInfo::abortHostLookup(int id) |
|
222 { |
|
223 #ifndef QT_NO_THREAD |
|
224 theHostInfoLookupManager()->abortLookup(id); |
|
225 #else |
|
226 // we cannot abort if it was non threaded.. the result signal has already been posted |
|
227 Q_UNUSED(id); |
|
228 #endif |
|
229 } |
|
230 |
|
231 /*! |
|
232 Looks up the IP address(es) for the given host \a name. The |
|
233 function blocks during the lookup which means that execution of |
|
234 the program is suspended until the results of the lookup are |
|
235 ready. Returns the result of the lookup in a QHostInfo object. |
|
236 |
|
237 If you pass a literal IP address to \a name instead of a host name, |
|
238 QHostInfo will search for the domain name for the IP (i.e., QHostInfo will |
|
239 perform a \e reverse lookup). On success, the returned QHostInfo will |
|
240 contain both the resolved domain name and IP addresses for the host name. |
|
241 |
|
242 \sa lookupHost() |
|
243 */ |
|
244 QHostInfo QHostInfo::fromName(const QString &name) |
|
245 { |
|
246 #if defined QHOSTINFO_DEBUG |
|
247 qDebug("QHostInfo::fromName(\"%s\")",name.toLatin1().constData()); |
|
248 #endif |
|
249 |
|
250 return QHostInfoAgent::fromName(name); |
|
251 } |
|
252 |
|
253 /*! |
|
254 \enum QHostInfo::HostInfoError |
|
255 |
|
256 This enum describes the various errors that can occur when trying |
|
257 to resolve a host name. |
|
258 |
|
259 \value NoError The lookup was successful. |
|
260 \value HostNotFound No IP addresses were found for the host. |
|
261 \value UnknownError An unknown error occurred. |
|
262 |
|
263 \sa error(), setError() |
|
264 */ |
|
265 |
|
266 /*! |
|
267 Constructs an empty host info object with lookup ID \a id. |
|
268 |
|
269 \sa lookupId() |
|
270 */ |
|
271 QHostInfo::QHostInfo(int id) |
|
272 : d(new QHostInfoPrivate) |
|
273 { |
|
274 d->lookupId = id; |
|
275 } |
|
276 |
|
277 /*! |
|
278 Constructs a copy of \a other. |
|
279 */ |
|
280 QHostInfo::QHostInfo(const QHostInfo &other) |
|
281 : d(new QHostInfoPrivate(*other.d.data())) |
|
282 { |
|
283 } |
|
284 |
|
285 /*! |
|
286 Assigns the data of the \a other object to this host info object, |
|
287 and returns a reference to it. |
|
288 */ |
|
289 QHostInfo &QHostInfo::operator=(const QHostInfo &other) |
|
290 { |
|
291 *d.data() = *other.d.data(); |
|
292 return *this; |
|
293 } |
|
294 |
|
295 /*! |
|
296 Destroys the host info object. |
|
297 */ |
|
298 QHostInfo::~QHostInfo() |
|
299 { |
|
300 } |
|
301 |
|
302 /*! |
|
303 Returns the list of IP addresses associated with hostName(). This |
|
304 list may be empty. |
|
305 |
|
306 Example: |
|
307 |
|
308 \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 5 |
|
309 |
|
310 \sa hostName(), error() |
|
311 */ |
|
312 QList<QHostAddress> QHostInfo::addresses() const |
|
313 { |
|
314 return d->addrs; |
|
315 } |
|
316 |
|
317 /*! |
|
318 Sets the list of addresses in this QHostInfo to \a addresses. |
|
319 |
|
320 \sa addresses() |
|
321 */ |
|
322 void QHostInfo::setAddresses(const QList<QHostAddress> &addresses) |
|
323 { |
|
324 d->addrs = addresses; |
|
325 } |
|
326 |
|
327 /*! |
|
328 Returns the name of the host whose IP addresses were looked up. |
|
329 |
|
330 \sa localHostName() |
|
331 */ |
|
332 QString QHostInfo::hostName() const |
|
333 { |
|
334 return d->hostName; |
|
335 } |
|
336 |
|
337 /*! |
|
338 Sets the host name of this QHostInfo to \a hostName. |
|
339 |
|
340 \sa hostName() |
|
341 */ |
|
342 void QHostInfo::setHostName(const QString &hostName) |
|
343 { |
|
344 d->hostName = hostName; |
|
345 } |
|
346 |
|
347 /*! |
|
348 Returns the type of error that occurred if the host name lookup |
|
349 failed; otherwise returns NoError. |
|
350 |
|
351 \sa setError(), errorString() |
|
352 */ |
|
353 QHostInfo::HostInfoError QHostInfo::error() const |
|
354 { |
|
355 return d->err; |
|
356 } |
|
357 |
|
358 /*! |
|
359 Sets the error type of this QHostInfo to \a error. |
|
360 |
|
361 \sa error(), errorString() |
|
362 */ |
|
363 void QHostInfo::setError(HostInfoError error) |
|
364 { |
|
365 d->err = error; |
|
366 } |
|
367 |
|
368 /*! |
|
369 Returns the ID of this lookup. |
|
370 |
|
371 \sa setLookupId(), abortHostLookup(), hostName() |
|
372 */ |
|
373 int QHostInfo::lookupId() const |
|
374 { |
|
375 return d->lookupId; |
|
376 } |
|
377 |
|
378 /*! |
|
379 Sets the ID of this lookup to \a id. |
|
380 |
|
381 \sa lookupId(), lookupHost() |
|
382 */ |
|
383 void QHostInfo::setLookupId(int id) |
|
384 { |
|
385 d->lookupId = id; |
|
386 } |
|
387 |
|
388 /*! |
|
389 If the lookup failed, this function returns a human readable |
|
390 description of the error; otherwise "Unknown error" is returned. |
|
391 |
|
392 \sa setErrorString(), error() |
|
393 */ |
|
394 QString QHostInfo::errorString() const |
|
395 { |
|
396 return d->errorStr; |
|
397 } |
|
398 |
|
399 /*! |
|
400 Sets the human readable description of the error that occurred to \a str |
|
401 if the lookup failed. |
|
402 |
|
403 \sa errorString(), setError() |
|
404 */ |
|
405 void QHostInfo::setErrorString(const QString &str) |
|
406 { |
|
407 d->errorStr = str; |
|
408 } |
|
409 |
|
410 /*! |
|
411 \fn QString QHostInfo::localHostName() |
|
412 |
|
413 Returns the host name of this machine. |
|
414 |
|
415 \sa hostName() |
|
416 */ |
|
417 |
|
418 /*! |
|
419 \fn QString QHostInfo::localDomainName() |
|
420 |
|
421 Returns the DNS domain of this machine. |
|
422 |
|
423 Note: DNS domains are not related to domain names found in |
|
424 Windows networks. |
|
425 |
|
426 \sa hostName() |
|
427 */ |
|
428 |
|
429 #ifndef QT_NO_THREAD |
|
430 QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i) |
|
431 { |
|
432 setAutoDelete(true); |
|
433 } |
|
434 |
|
435 // the QHostInfoLookupManager will at some point call this via a QThreadPool |
|
436 void QHostInfoRunnable::run() |
|
437 { |
|
438 QHostInfoLookupManager *manager = theHostInfoLookupManager(); |
|
439 // check aborted |
|
440 if (manager->wasAborted(id)) { |
|
441 manager->lookupFinished(this); |
|
442 return; |
|
443 } |
|
444 |
|
445 QHostInfo hostInfo; |
|
446 |
|
447 // QHostInfo::lookupHost already checks the cache. However we need to check |
|
448 // it here too because it might have been cache saved by another QHostInfoRunnable |
|
449 // in the meanwhile while this QHostInfoRunnable was scheduled but not running |
|
450 if (manager->cache.isEnabled()) { |
|
451 // check the cache first |
|
452 bool valid = false; |
|
453 hostInfo = manager->cache.get(toBeLookedUp, &valid); |
|
454 if (!valid) { |
|
455 // not in cache, we need to do the lookup and store the result in the cache |
|
456 hostInfo = QHostInfoAgent::fromName(toBeLookedUp); |
|
457 manager->cache.put(toBeLookedUp, hostInfo); |
|
458 } |
|
459 } else { |
|
460 // cache is not enabled, just do the lookup and continue |
|
461 hostInfo = QHostInfoAgent::fromName(toBeLookedUp); |
|
462 } |
|
463 |
|
464 // check aborted again |
|
465 if (manager->wasAborted(id)) { |
|
466 manager->lookupFinished(this); |
|
467 return; |
|
468 } |
|
469 |
|
470 // signal emission |
|
471 hostInfo.setLookupId(id); |
|
472 resultEmitter.emitResultsReady(hostInfo); |
|
473 |
|
474 manager->lookupFinished(this); |
|
475 |
|
476 // thread goes back to QThreadPool |
|
477 } |
|
478 |
|
479 QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false) |
|
480 { |
|
481 moveToThread(QCoreApplicationPrivate::mainThread()); |
|
482 connect(QCoreApplication::instance(), SIGNAL(destroyed()), SLOT(waitForThreadPoolDone()), Qt::DirectConnection); |
|
483 threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel |
|
484 } |
|
485 |
|
486 QHostInfoLookupManager::~QHostInfoLookupManager() |
|
487 { |
|
488 wasDeleted = true; |
|
489 |
|
490 // don't qDeleteAll currentLookups, the QThreadPool has ownership |
|
491 qDeleteAll(postponedLookups); |
|
492 qDeleteAll(scheduledLookups); |
|
493 qDeleteAll(finishedLookups); |
|
494 } |
|
495 |
|
496 void QHostInfoLookupManager::work() |
|
497 { |
|
498 if (wasDeleted) |
|
499 return; |
|
500 |
|
501 // goals of this function: |
|
502 // - launch new lookups via the thread pool |
|
503 // - make sure only one lookup per host/IP is in progress |
|
504 |
|
505 QMutexLocker locker(&mutex); |
|
506 |
|
507 if (!finishedLookups.isEmpty()) { |
|
508 // remove ID from aborted if it is in there |
|
509 for (int i = 0; i < finishedLookups.length(); i++) { |
|
510 abortedLookups.removeAll(finishedLookups.at(i)->id); |
|
511 } |
|
512 |
|
513 finishedLookups.clear(); |
|
514 } |
|
515 |
|
516 if (!postponedLookups.isEmpty()) { |
|
517 // try to start the postponed ones |
|
518 |
|
519 QMutableListIterator<QHostInfoRunnable*> iterator(postponedLookups); |
|
520 while (iterator.hasNext()) { |
|
521 QHostInfoRunnable* postponed = iterator.next(); |
|
522 |
|
523 // check if none of the postponed hostnames is currently running |
|
524 bool alreadyRunning = false; |
|
525 for (int i = 0; i < currentLookups.length(); i++) { |
|
526 if (currentLookups.at(i)->toBeLookedUp == postponed->toBeLookedUp) { |
|
527 alreadyRunning = true; |
|
528 break; |
|
529 } |
|
530 } |
|
531 if (!alreadyRunning) { |
|
532 iterator.remove(); |
|
533 scheduledLookups.prepend(postponed); // prepend! we want to finish it ASAP |
|
534 } |
|
535 } |
|
536 } |
|
537 |
|
538 if (!scheduledLookups.isEmpty()) { |
|
539 // try to start the new ones |
|
540 QMutableListIterator<QHostInfoRunnable*> iterator(scheduledLookups); |
|
541 while (iterator.hasNext()) { |
|
542 QHostInfoRunnable *scheduled = iterator.next(); |
|
543 |
|
544 // check if a lookup for this host is already running, then postpone |
|
545 for (int i = 0; i < currentLookups.size(); i++) { |
|
546 if (currentLookups.at(i)->toBeLookedUp == scheduled->toBeLookedUp) { |
|
547 iterator.remove(); |
|
548 postponedLookups.append(scheduled); |
|
549 scheduled = 0; |
|
550 break; |
|
551 } |
|
552 } |
|
553 |
|
554 if (scheduled && threadPool.tryStart(scheduled)) { |
|
555 // runnable now running in new thread, track this in currentLookups |
|
556 iterator.remove(); |
|
557 currentLookups.append(scheduled); |
|
558 } else if (scheduled) { |
|
559 // wanted to start, but could not because thread pool is busy |
|
560 break; |
|
561 } else { |
|
562 // was postponed, continue iterating |
|
563 continue; |
|
564 } |
|
565 }; |
|
566 } |
|
567 } |
|
568 |
|
569 // called by QHostInfo |
|
570 void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r) |
|
571 { |
|
572 if (wasDeleted) |
|
573 return; |
|
574 |
|
575 QMutexLocker locker(&this->mutex); |
|
576 scheduledLookups.enqueue(r); |
|
577 work(); |
|
578 } |
|
579 |
|
580 // called by QHostInfo |
|
581 void QHostInfoLookupManager::abortLookup(int id) |
|
582 { |
|
583 if (wasDeleted) |
|
584 return; |
|
585 |
|
586 QMutexLocker locker(&this->mutex); |
|
587 if (!abortedLookups.contains(id)) |
|
588 abortedLookups.append(id); |
|
589 } |
|
590 |
|
591 // called from QHostInfoRunnable |
|
592 bool QHostInfoLookupManager::wasAborted(int id) |
|
593 { |
|
594 if (wasDeleted) |
|
595 return true; |
|
596 |
|
597 QMutexLocker locker(&this->mutex); |
|
598 return abortedLookups.contains(id); |
|
599 } |
|
600 |
|
601 // called from QHostInfoRunnable |
|
602 void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r) |
|
603 { |
|
604 if (wasDeleted) |
|
605 return; |
|
606 |
|
607 QMutexLocker locker(&this->mutex); |
|
608 currentLookups.removeOne(r); |
|
609 finishedLookups.append(r); |
|
610 work(); |
|
611 } |
|
612 |
|
613 // This function returns immediatly when we had a result in the cache, else it will later emit a signal |
|
614 QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id) |
|
615 { |
|
616 *valid = false; |
|
617 *id = -1; |
|
618 |
|
619 // check cache |
|
620 QHostInfoLookupManager* manager = theHostInfoLookupManager(); |
|
621 if (manager && manager->cache.isEnabled()) { |
|
622 QHostInfo info = manager->cache.get(name, valid); |
|
623 if (*valid) { |
|
624 return info; |
|
625 } |
|
626 } |
|
627 |
|
628 // was not in cache, trigger lookup |
|
629 *id = QHostInfo::lookupHost(name, receiver, member); |
|
630 |
|
631 // return empty response, valid==false |
|
632 return QHostInfo(); |
|
633 } |
|
634 |
|
635 void qt_qhostinfo_clear_cache() |
|
636 { |
|
637 QHostInfoLookupManager* manager = theHostInfoLookupManager(); |
|
638 if (manager) { |
|
639 manager->cache.clear(); |
|
640 } |
|
641 } |
|
642 |
|
643 void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e) |
|
644 { |
|
645 QHostInfoLookupManager* manager = theHostInfoLookupManager(); |
|
646 if (manager) { |
|
647 manager->cache.setEnabled(e); |
|
648 } |
|
649 } |
|
650 |
|
651 // cache for 60 seconds |
|
652 // cache 64 items |
|
653 QHostInfoCache::QHostInfoCache() : max_age(60), enabled(true), cache(64) |
|
654 { |
|
655 #ifdef QT_QHOSTINFO_CACHE_DISABLED_BY_DEFAULT |
|
656 enabled = false; |
|
657 #endif |
|
658 } |
|
659 |
|
660 bool QHostInfoCache::isEnabled() |
|
661 { |
|
662 return enabled; |
|
663 } |
|
664 |
|
665 // this function is currently only used for the auto tests |
|
666 // and not usable by public API |
|
667 void QHostInfoCache::setEnabled(bool e) |
|
668 { |
|
669 enabled = e; |
|
670 } |
|
671 |
|
672 |
|
673 QHostInfo QHostInfoCache::get(const QString &name, bool *valid) |
|
674 { |
|
675 QMutexLocker locker(&this->mutex); |
|
676 |
|
677 *valid = false; |
|
678 if (cache.contains(name)) { |
|
679 QHostInfoCacheElement *element = cache.object(name); |
|
680 if (element->age.elapsed() < max_age*1000) |
|
681 *valid = true; |
|
682 return element->info; |
|
683 |
|
684 // FIXME idea: |
|
685 // if too old but not expired, trigger a new lookup |
|
686 // to freshen our cache |
|
687 } |
|
688 |
|
689 return QHostInfo(); |
|
690 } |
|
691 |
|
692 void QHostInfoCache::put(const QString &name, const QHostInfo &info) |
|
693 { |
|
694 // if the lookup failed, don't cache |
|
695 if (info.error() != QHostInfo::NoError) |
|
696 return; |
|
697 |
|
698 QHostInfoCacheElement* element = new QHostInfoCacheElement(); |
|
699 element->info = info; |
|
700 element->age = QTime(); |
|
701 element->age.start(); |
|
702 |
|
703 QMutexLocker locker(&this->mutex); |
|
704 cache.insert(name, element); // cache will take ownership |
|
705 } |
|
706 |
|
707 void QHostInfoCache::clear() |
|
708 { |
|
709 QMutexLocker locker(&this->mutex); |
|
710 cache.clear(); |
|
711 } |
|
712 |
|
713 #endif // QT_NO_THREAD |
|
714 |
|
715 QT_END_NAMESPACE |