Browse Source

Improved hostname resolution code

adaptive-webui-19844
Christophe Dumez 14 years ago
parent
commit
844bd52c67
  1. 14
      src/properties/peerlistwidget.cpp
  2. 2
      src/properties/peerlistwidget.h
  3. 153
      src/reverseresolution.h

14
src/properties/peerlistwidget.cpp

@ -100,12 +100,12 @@ void PeerListWidget::updatePeerHostNameResolutionState() {
if(!resolver) { if(!resolver) {
resolver = new ReverseResolution(this); resolver = new ReverseResolution(this);
connect(resolver, SIGNAL(ip_resolved(QString,QString)), this, SLOT(handleResolved(QString,QString))); connect(resolver, SIGNAL(ip_resolved(QString,QString)), this, SLOT(handleResolved(QString,QString)));
resolver->start();
loadPeers(properties->getCurrentTorrent(), true); loadPeers(properties->getCurrentTorrent(), true);
} }
} else { } else {
if(resolver) if(resolver) {
resolver->asyncDelete(); delete resolver;
}
} }
} }
@ -315,7 +315,7 @@ void PeerListWidget::loadPeers(const QTorrentHandle &h, bool force_hostname_reso
old_peers_set.remove(peer_ip); old_peers_set.remove(peer_ip);
if(force_hostname_resolution) { if(force_hostname_resolution) {
if(resolver) { if(resolver) {
QString host = resolver->getHostFromCache(peer.ip); const QString host = resolver->getHostFromCache(peer.ip);
if(host.isNull()) { if(host.isNull()) {
resolver->resolve(peer.ip); resolver->resolve(peer.ip);
} else { } else {
@ -396,12 +396,12 @@ void PeerListWidget::updatePeer(QString ip, peer_info peer) {
listModel->setData(listModel->index(row, TOT_UP), (qulonglong)peer.total_upload); 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); QStandardItem *item = peerItems.value(ip, 0);
if(item) { if(item) {
qDebug("Resolved %s -> %s", qPrintable(ip), qPrintable(hostname)); qDebug("Resolved %s -> %s", qPrintable(ip), qPrintable(hostname));
item->setData(hostname); item->setData(hostname, Qt::DisplayRole);
//listModel->setData(listModel->index(item->row(), IP), hostname); //listModel->setData(listModel->index(item->row(), IP), hostname, Qt::DisplayRole);
} }
} }

2
src/properties/peerlistwidget.h

@ -65,7 +65,7 @@ public slots:
void loadPeers(const QTorrentHandle &h, bool force_hostname_resolution=false); void loadPeers(const QTorrentHandle &h, bool force_hostname_resolution=false);
QStandardItem* addPeer(QString ip, libtorrent::peer_info peer); QStandardItem* addPeer(QString ip, libtorrent::peer_info peer);
void updatePeer(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 updatePeerHostNameResolutionState();
void updatePeerCountryResolutionState(); void updatePeerCountryResolutionState();
void clear(); void clear();

153
src/reverseresolution.h

@ -31,12 +31,10 @@
#ifndef REVERSERESOLUTION_H #ifndef REVERSERESOLUTION_H
#define REVERSERESOLUTION_H #define REVERSERESOLUTION_H
#include <QQueue>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QList> #include <QList>
#include <QCache> #include <QCache>
#include <QDebug>
#include <QHostInfo>
#include "misc.h" #include "misc.h"
#include <boost/version.hpp> #include <boost/version.hpp>
@ -46,160 +44,63 @@
#include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/tcp.hpp>
#endif #endif
const int MAX_THREADS = 20;
const int CACHE_SIZE = 500; const int CACHE_SIZE = 500;
class ReverseResolutionST: public QThread { class ReverseResolution: public QObject {
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 {
Q_OBJECT Q_OBJECT
Q_DISABLE_COPY(ReverseResolution) Q_DISABLE_COPY(ReverseResolution)
public: public:
explicit ReverseResolution(QObject* parent): QThread(parent), stopped(false) { explicit ReverseResolution(QObject* parent): QObject(parent) {
cache = new QCache<QString, QString>(CACHE_SIZE); m_cache.setMaxCost(CACHE_SIZE);
} }
~ReverseResolution() { ~ReverseResolution() {
qDebug("Deleting host name resolver..."); 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) { QString getHostFromCache(const libtorrent::asio::ip::tcp::endpoint &ip) {
mut.lock(); const QString ip_str = misc::toQString(ip.address().to_string());
QString ip_str = misc::toQString(ip.address().to_string());
QString ret; QString ret;
if(cache->contains(ip_str)) { if(m_cache.contains(ip_str)) {
qDebug("Got host name from cache"); qDebug("Got host name from cache");
ret = *cache->object(ip_str); ret = *m_cache.object(ip_str);
} else { } else {
ret = QString::null; ret = QString::null;
} }
mut.unlock();
return ret; return ret;
} }
void resolve(libtorrent::asio::ip::tcp::endpoint ip) { void resolve(const libtorrent::asio::ip::tcp::endpoint &ip) {
mut.lock(); const QString ip_str = misc::toQString(ip.address().to_string());
QString ip_str = misc::toQString(ip.address().to_string()); if(m_cache.contains(ip_str)) {
if(cache->contains(ip_str)) {
qDebug("Resolved host name using cache"); qDebug("Resolved host name using cache");
emit ip_resolved(ip_str, *cache->object(ip_str)); emit ip_resolved(ip_str, *m_cache.object(ip_str));
mut.unlock();
return; return;
} }
ips.enqueue(ip); // Actually resolve the ip
if(subThreads.size() < MAX_THREADS) QHostInfo::lookupHost(ip_str, this, SLOT(hostResolved(QHostInfo)));
cond.wakeOne();
mut.unlock();
} }
signals: signals:
void ip_resolved(QString ip, QString hostname); void ip_resolved(const QString &ip, const QString &hostname);
protected slots: private slots:
void forwardSignal(QString ip, QString hostname) { 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); emit ip_resolved(ip, hostname);
mut.lock();
cache->insert(ip, new QString(hostname));
subThreads.removeOne(static_cast<ReverseResolutionST*>(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;
} }
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: private:
QQueue<libtorrent::asio::ip::tcp::endpoint> ips; QCache<QString, QString> m_cache;
QMutex mut;
QWaitCondition cond;
bool stopped;
libtorrent::asio::io_service ios;
QCache<QString, QString> *cache;
QList<ReverseResolutionST*> subThreads;
}; };

Loading…
Cancel
Save