From 844bd52c6769f8644763859aebbea82dafbf95b3 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sat, 22 Jan 2011 18:55:54 +0000 Subject: [PATCH] Improved hostname resolution code --- src/properties/peerlistwidget.cpp | 14 +-- src/properties/peerlistwidget.h | 2 +- src/reverseresolution.h | 155 ++++++------------------------ 3 files changed, 36 insertions(+), 135 deletions(-) diff --git a/src/properties/peerlistwidget.cpp b/src/properties/peerlistwidget.cpp index d03b5ee3d..ac0a0bb86 100644 --- a/src/properties/peerlistwidget.cpp +++ b/src/properties/peerlistwidget.cpp @@ -100,12 +100,12 @@ void PeerListWidget::updatePeerHostNameResolutionState() { if(!resolver) { resolver = new ReverseResolution(this); connect(resolver, SIGNAL(ip_resolved(QString,QString)), this, SLOT(handleResolved(QString,QString))); - resolver->start(); loadPeers(properties->getCurrentTorrent(), true); } } else { - if(resolver) - resolver->asyncDelete(); + if(resolver) { + delete resolver; + } } } @@ -315,7 +315,7 @@ void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_reso old_peers_set.remove(peer_ip); if(force_hostname_resolution) { if(resolver) { - QString host = resolver->getHostFromCache(peer.ip); + const QString host = resolver->getHostFromCache(peer.ip); if(host.isNull()) { resolver->resolve(peer.ip); } else { @@ -396,12 +396,12 @@ void PeerListWidget::updatePeer(QString ip, peer_info peer) { listModel->setData(listModel->index(row, TOT_UP), (qulonglong)peer.total_upload); } -void PeerListWidget::handleResolved(QString ip, QString hostname) { +void PeerListWidget::handleResolved(const QString &ip, const QString &hostname) { QStandardItem *item = peerItems.value(ip, 0); if(item) { qDebug("Resolved %s -> %s", qPrintable(ip), qPrintable(hostname)); - item->setData(hostname); - //listModel->setData(listModel->index(item->row(), IP), hostname); + item->setData(hostname, Qt::DisplayRole); + //listModel->setData(listModel->index(item->row(), IP), hostname, Qt::DisplayRole); } } diff --git a/src/properties/peerlistwidget.h b/src/properties/peerlistwidget.h index 8402ff0ba..554dd5e4e 100644 --- a/src/properties/peerlistwidget.h +++ b/src/properties/peerlistwidget.h @@ -65,7 +65,7 @@ public slots: void loadPeers(const QTorrentHandle &h, bool force_hostname_resolution=false); QStandardItem* addPeer(QString ip, libtorrent::peer_info peer); void updatePeer(QString ip, libtorrent::peer_info peer); - void handleResolved(QString ip, QString hostname); + void handleResolved(const QString &ip, const QString &hostname); void updatePeerHostNameResolutionState(); void updatePeerCountryResolutionState(); void clear(); diff --git a/src/reverseresolution.h b/src/reverseresolution.h index 0c5b0fad4..e0f2e57e9 100644 --- a/src/reverseresolution.h +++ b/src/reverseresolution.h @@ -31,12 +31,10 @@ #ifndef REVERSERESOLUTION_H #define REVERSERESOLUTION_H -#include -#include -#include -#include #include #include +#include +#include #include "misc.h" #include @@ -46,160 +44,63 @@ #include #endif -const int MAX_THREADS = 20; const int CACHE_SIZE = 500; -class ReverseResolutionST: public QThread { - Q_OBJECT - -private: - libtorrent::asio::ip::tcp::endpoint ip; - libtorrent::asio::ip::tcp::resolver resolver; - bool stopped; - -public: - ReverseResolutionST(libtorrent::asio::io_service &ios, QObject *parent=0): - QThread(parent), resolver(ios), stopped(false) { - - } - - ~ReverseResolutionST() { - stopped = true; - if(isRunning()) { - resolver.cancel(); - wait(); - } - } - - void setIP(libtorrent::asio::ip::tcp::endpoint &_ip) { - ip = _ip; - } - -signals: - void ip_resolved(QString ip, QString hostname); - -protected: - void run() { - try { - boost::system::error_code ec; - libtorrent::asio::ip::tcp::resolver::iterator it = resolver.resolve(ip, ec); - if(ec || stopped) return; - const std::string ip_str = ip.address().to_string(ec); - if(ec) return; - const QString host_name = misc::toQString(it->host_name()); - const QString ip_qstr = misc::toQString(ip_str); - if(host_name != ip_qstr) { - emit ip_resolved(ip_qstr, host_name); - } - } catch(std::exception/* &e*/) { - /*std::cerr << "Hostname resolution failed, reason: " << e.what() << std::endl;*/ - std::cerr << "Hostname resolution error." << std::endl; - } - } -}; - -class ReverseResolution: public QThread { +class ReverseResolution: public QObject { Q_OBJECT Q_DISABLE_COPY(ReverseResolution) public: - explicit ReverseResolution(QObject* parent): QThread(parent), stopped(false) { - cache = new QCache(CACHE_SIZE); + explicit ReverseResolution(QObject* parent): QObject(parent) { + m_cache.setMaxCost(CACHE_SIZE); } ~ReverseResolution() { qDebug("Deleting host name resolver..."); - if(!stopped) { - stopped = true; - cond.wakeOne(); - } - delete cache; - wait(); - qDebug("Host name resolver was deleted"); } - void asyncDelete() { - connect(this, SIGNAL(finished()), this, SLOT(deleteLater())); - qDebug("Deleting async host name resolver..."); - stopped = true; - cond.wakeOne(); - } - - QString getHostFromCache(libtorrent::asio::ip::tcp::endpoint ip) { - mut.lock(); - QString ip_str = misc::toQString(ip.address().to_string()); + QString getHostFromCache(const libtorrent::asio::ip::tcp::endpoint &ip) { + const QString ip_str = misc::toQString(ip.address().to_string()); QString ret; - if(cache->contains(ip_str)) { + if(m_cache.contains(ip_str)) { qDebug("Got host name from cache"); - ret = *cache->object(ip_str); + ret = *m_cache.object(ip_str); } else { ret = QString::null; } - mut.unlock(); return ret; } - void resolve(libtorrent::asio::ip::tcp::endpoint ip) { - mut.lock(); - QString ip_str = misc::toQString(ip.address().to_string()); - if(cache->contains(ip_str)) { + void resolve(const libtorrent::asio::ip::tcp::endpoint &ip) { + const QString ip_str = misc::toQString(ip.address().to_string()); + if(m_cache.contains(ip_str)) { qDebug("Resolved host name using cache"); - emit ip_resolved(ip_str, *cache->object(ip_str)); - mut.unlock(); + emit ip_resolved(ip_str, *m_cache.object(ip_str)); return; } - ips.enqueue(ip); - if(subThreads.size() < MAX_THREADS) - cond.wakeOne(); - mut.unlock(); + // Actually resolve the ip + QHostInfo::lookupHost(ip_str, this, SLOT(hostResolved(QHostInfo))); } signals: - void ip_resolved(QString ip, QString hostname); + void ip_resolved(const QString &ip, const QString &hostname); -protected slots: - void forwardSignal(QString ip, QString hostname) { - emit ip_resolved(ip, hostname); - mut.lock(); - cache->insert(ip, new QString(hostname)); - subThreads.removeOne(static_cast(sender())); - if(!ips.empty()) - cond.wakeOne(); - mut.unlock(); - delete sender(); - //sender()->deleteLater(); - } - -protected: - void run() { - do { - mut.lock(); - cond.wait(&mut); - if(stopped) { - mut.unlock(); - break; +private slots: + void hostResolved(const QHostInfo& host) { + if (host.error() == QHostInfo::NoError) { + const QString hostname = host.hostName(); + if(host.addresses().isEmpty() || hostname.isEmpty()) return; + const QString ip = host.addresses().first().toString(); + if(hostname != ip) { + //qDebug() << Q_FUNC_INFO << ip << QString("->") << hostname; + m_cache.insert(ip, new QString(hostname)); + emit ip_resolved(ip, hostname); } - libtorrent::asio::ip::tcp::endpoint ip = ips.dequeue(); - ReverseResolutionST *st = new ReverseResolutionST(ios); - subThreads.append(st); - mut.unlock(); - connect(st, SIGNAL(ip_resolved(QString,QString)), this, SLOT(forwardSignal(QString,QString))); - st->setIP(ip); - st->start(); - }while(!stopped); - mut.lock(); - qDeleteAll(subThreads); - mut.unlock(); + } } private: - QQueue ips; - QMutex mut; - QWaitCondition cond; - bool stopped; - libtorrent::asio::io_service ios; - QCache *cache; - QList subThreads; + QCache m_cache; };