Changeset 561 for trunk/src/network/kernel/qhostinfo.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/network/kernel/qhostinfo.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtNetwork module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 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 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 43 43 #include "qhostinfo_p.h" 44 44 45 #include "QtCore/qscopedpointer.h" 45 46 #include <qabstracteventdispatcher.h> 46 47 #include <private/qunicodetables_p.h> … … 60 61 QT_BEGIN_NAMESPACE 61 62 62 Q_GLOBAL_STATIC(QHostInfoAgent, theAgent) 63 void QHostInfoAgent::staticCleanup() 64 { 65 theAgent()->cleanup(); 66 } 63 #ifndef QT_NO_THREAD 64 Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager) 65 #endif 67 66 68 67 //#define QHOSTINFO_DEBUG … … 74 73 \reentrant 75 74 \inmodule QtNetwork 76 \ingroup io75 \ingroup network 77 76 78 77 QHostInfo uses the lookup mechanisms provided by the operating … … 142 141 143 142 \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 4 143 144 \note There is no guarantee on the order the signals will be emitted 145 if you start multiple requests with lookupHost(). 144 146 145 147 \sa abortHostLookup(), addresses(), error(), fromName() … … 159 161 qRegisterMetaType<QHostInfo>("QHostInfo"); 160 162 161 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) 162 QWindowsSockInit bust; // makes sure WSAStartup was callled 163 int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID 164 165 if (name.isEmpty()) { 166 QHostInfo hostInfo(id); 167 hostInfo.setError(QHostInfo::HostNotFound); 168 hostInfo.setErrorString(QObject::tr("No host name given")); 169 QScopedPointer<QHostInfoResult> result(new QHostInfoResult); 170 QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)), 171 receiver, member, Qt::QueuedConnection); 172 result.data()->emitResultsReady(hostInfo); 173 return id; 174 } 175 176 #ifdef QT_NO_THREAD 177 QHostInfo hostInfo = QHostInfoAgent::fromName(name); 178 hostInfo.setLookupId(id); 179 QScopedPointer<QHostInfoResult> result(new QHostInfoResult); 180 QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)), 181 receiver, member, Qt::QueuedConnection); 182 result.data()->emitResultsReady(hostInfo); 183 #else 184 QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id); 185 QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); 186 theHostInfoLookupManager()->scheduleLookup(runnable); 163 187 #endif 164 188 165 // Support for IDNA 166 QString lookup = QString::fromLatin1(QUrl::toAce(name)); 167 168 QHostInfoResult *result = new QHostInfoResult; 169 result->autoDelete = false; 170 QObject::connect(result, SIGNAL(resultsReady(QHostInfo)), 171 receiver, member); 172 int id = result->lookupId = theIdCounter.fetchAndAddRelaxed(1); 173 174 if (lookup.isEmpty()) { 175 QHostInfo info(id); 176 info.setError(QHostInfo::HostNotFound); 177 info.setErrorString(QObject::tr("No host name given")); 178 QMetaObject::invokeMethod(result, "emitResultsReady", Qt::QueuedConnection, 179 Q_ARG(QHostInfo, info)); 180 result->autoDelete = true; 181 return id; 182 } 183 184 QHostInfoAgent *agent = theAgent(); 185 agent->addHostName(lookup, result); 186 187 #if !defined QT_NO_THREAD 188 if (!agent->isRunning()) 189 agent->start(); 189 return id; 190 } 191 192 /*! 193 Aborts the host lookup with the ID \a id, as returned by lookupHost(). 194 195 \sa lookupHost(), lookupId() 196 */ 197 void QHostInfo::abortHostLookup(int id) 198 { 199 #ifndef QT_NO_THREAD 200 theHostInfoLookupManager()->abortLookup(id); 190 201 #else 191 // if (!agent->isRunning()) 192 agent->run(); 193 // else 194 // agent->wakeOne(); 202 // we cannot abort if it was non threaded.. the result signal has already been posted 203 Q_UNUSED(id); 195 204 #endif 196 return id;197 }198 199 /*!200 Aborts the host lookup with the ID \a id, as returned by lookupHost().201 202 \sa lookupHost(), lookupId()203 */204 void QHostInfo::abortHostLookup(int id)205 {206 QHostInfoAgent *agent = theAgent();207 agent->abortLookup(id);208 205 } 209 206 … … 227 224 #endif 228 225 229 if (!name.isEmpty()) 230 return QHostInfoAgent::fromName(QLatin1String(QUrl::toAce(name))); 231 232 QHostInfo retval; 233 retval.d->err = HostNotFound; 234 retval.d->errorStr = QObject::tr("No host name given"); 235 return retval; 236 } 237 238 /*! 239 \internal 240 Pops a query off the queries list, performs a blocking call to 241 QHostInfoAgent::lookupHost(), and emits the resultsReady() 242 signal. This process repeats until the queries list is empty. 243 */ 244 void QHostInfoAgent::run() 245 { 246 #ifndef QT_NO_THREAD 247 // Dont' allow thread termination during event delivery, but allow it 248 // during the actual blocking host lookup stage. 249 setTerminationEnabled(false); 250 forever 251 #endif 252 { 253 QHostInfoQuery *query; 254 { 255 #ifndef QT_NO_THREAD 256 // the queries list is shared between threads. lock all 257 // access to it. 258 QMutexLocker locker(&mutex); 259 if (!quit && queries.isEmpty()) 260 cond.wait(&mutex); 261 if (quit) { 262 // Reset the quit variable in case QCoreApplication is 263 // destroyed and recreated. 264 quit = false; 265 break; 266 } 267 if (queries.isEmpty()) 268 continue; 269 #else 270 if (queries.isEmpty()) 271 return; 272 #endif 273 query = queries.takeFirst(); 274 pendingQueryId = query->object->lookupId; 275 } 276 277 #if defined(QHOSTINFO_DEBUG) 278 qDebug("QHostInfoAgent::run(%p): looking up \"%s\"", this, 279 query->hostName.toLatin1().constData()); 280 #endif 281 282 #ifndef QT_NO_THREAD 283 // Start query - allow termination at this point, but not outside. We 284 // don't want to all termination during event delivery, but we don't 285 // want the lookup to prevent the app from quitting (the agent 286 // destructor terminates the thread). 287 setTerminationEnabled(true); 288 #endif 289 QHostInfo info = fromName(query->hostName); 290 #ifndef QT_NO_THREAD 291 setTerminationEnabled(false); 292 #endif 293 294 int id = query->object->lookupId; 295 info.setLookupId(id); 296 if (pendingQueryId == id) 297 query->object->emitResultsReady(info); 298 delete query; 299 } 226 return QHostInfoAgent::fromName(name); 300 227 } 301 228 … … 328 255 */ 329 256 QHostInfo::QHostInfo(const QHostInfo &other) 330 : d(new QHostInfoPrivate(*other.d ))257 : d(new QHostInfoPrivate(*other.d.data())) 331 258 { 332 259 } … … 338 265 QHostInfo &QHostInfo::operator=(const QHostInfo &other) 339 266 { 340 *d = *other.d;267 *d.data() = *other.d.data(); 341 268 return *this; 342 269 } … … 347 274 QHostInfo::~QHostInfo() 348 275 { 349 delete d;350 276 } 351 277 … … 477 403 */ 478 404 405 #ifndef QT_NO_THREAD 406 QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i) 407 { 408 setAutoDelete(true); 409 } 410 411 // the QHostInfoLookupManager will at some point call this via a QThreadPool 412 void QHostInfoRunnable::run() 413 { 414 QHostInfoLookupManager *manager = theHostInfoLookupManager(); 415 // check aborted 416 if (manager->wasAborted(id)) { 417 manager->lookupFinished(this); 418 return; 419 } 420 421 // check cache 422 // FIXME 423 424 // if not in cache: OS lookup 425 QHostInfo hostInfo = QHostInfoAgent::fromName(toBeLookedUp); 426 427 // save to cache 428 // FIXME 429 430 // check aborted again 431 if (manager->wasAborted(id)) { 432 manager->lookupFinished(this); 433 return; 434 } 435 436 // signal emission 437 hostInfo.setLookupId(id); 438 resultEmitter.emitResultsReady(hostInfo); 439 440 manager->lookupFinished(this); 441 442 // thread goes back to QThreadPool 443 } 444 445 QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false) 446 { 447 moveToThread(QCoreApplicationPrivate::mainThread()); 448 threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel 449 } 450 451 QHostInfoLookupManager::~QHostInfoLookupManager() 452 { 453 wasDeleted = true; 454 } 455 456 void QHostInfoLookupManager::work() 457 { 458 if (wasDeleted) 459 return; 460 461 // goals of this function: 462 // - launch new lookups via the thread pool 463 // - make sure only one lookup per host/IP is in progress 464 465 QMutexLocker locker(&mutex); 466 467 if (!finishedLookups.isEmpty()) { 468 // remove ID from aborted if it is in there 469 for (int i = 0; i < finishedLookups.length(); i++) { 470 abortedLookups.removeAll(finishedLookups.at(i)->id); 471 } 472 473 finishedLookups.clear(); 474 } 475 476 if (!postponedLookups.isEmpty()) { 477 // try to start the postponed ones 478 479 QMutableListIterator<QHostInfoRunnable*> iterator(postponedLookups); 480 while (iterator.hasNext()) { 481 QHostInfoRunnable* postponed = iterator.next(); 482 483 // check if none of the postponed hostnames is currently running 484 bool alreadyRunning = false; 485 for (int i = 0; i < currentLookups.length(); i++) { 486 if (currentLookups.at(i)->toBeLookedUp == postponed->toBeLookedUp) { 487 alreadyRunning = true; 488 break; 489 } 490 } 491 if (!alreadyRunning) { 492 iterator.remove(); 493 scheduledLookups.prepend(postponed); // prepend! we want to finish it ASAP 494 } 495 } 496 } 497 498 if (!scheduledLookups.isEmpty()) { 499 // try to start the new ones 500 QMutableListIterator<QHostInfoRunnable*> iterator(scheduledLookups); 501 while (iterator.hasNext()) { 502 QHostInfoRunnable *scheduled = iterator.next(); 503 504 // check if a lookup for this host is already running, then postpone 505 for (int i = 0; i < currentLookups.size(); i++) { 506 if (currentLookups.at(i)->toBeLookedUp == scheduled->toBeLookedUp) { 507 iterator.remove(); 508 postponedLookups.append(scheduled); 509 scheduled = 0; 510 break; 511 } 512 } 513 514 if (scheduled && threadPool.tryStart(scheduled)) { 515 // runnable now running in new thread, track this in currentLookups 516 iterator.remove(); 517 currentLookups.append(scheduled); 518 } else if (scheduled) { 519 // wanted to start, but could not because thread pool is busy 520 break; 521 } else { 522 // was postponed, continue iterating 523 continue; 524 } 525 }; 526 } 527 } 528 529 // called by QHostInfo 530 void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r) 531 { 532 if (wasDeleted) 533 return; 534 535 QMutexLocker locker(&this->mutex); 536 scheduledLookups.enqueue(r); 537 work(); 538 } 539 540 // called by QHostInfo 541 void QHostInfoLookupManager::abortLookup(int id) 542 { 543 if (wasDeleted) 544 return; 545 546 QMutexLocker locker(&this->mutex); 547 if (!abortedLookups.contains(id)) 548 abortedLookups.append(id); 549 } 550 551 // called from QHostInfoRunnable 552 bool QHostInfoLookupManager::wasAborted(int id) 553 { 554 if (wasDeleted) 555 return true; 556 557 QMutexLocker locker(&this->mutex); 558 return abortedLookups.contains(id); 559 } 560 561 // called from QHostInfoRunnable 562 void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r) 563 { 564 if (wasDeleted) 565 return; 566 567 QMutexLocker locker(&this->mutex); 568 currentLookups.removeOne(r); 569 finishedLookups.append(r); 570 work(); 571 } 572 573 #endif // QT_NO_THREAD 574 479 575 QT_END_NAMESPACE
Note:
See TracChangeset
for help on using the changeset viewer.