diff --git a/examples/ktcli/ktcli.cpp b/examples/ktcli/ktcli.cpp index 33b47c4..f3e4d97 100644 --- a/examples/ktcli/ktcli.cpp +++ b/examples/ktcli/ktcli.cpp @@ -1,253 +1,253 @@ /*************************************************************************** * Copyright (C) 2010 by Joris Guisson * * joris.guisson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include #include #include #include #include "ktcli.h" #include #include #include #include #include #include #include #include using namespace bt; KTCLI::KTCLI(int argc, char** argv) : QCoreApplication(argc, argv), tc(new TorrentControl()),updates(0) { parser.addPositionalArgument("url", tr("Torrent to open")); parser.addOption(QCommandLineOption("port", tr("Port to use"), "", "6881")); parser.addOption(QCommandLineOption("tmpdir", tr("Port to use"), "", QDir::tempPath())); parser.addOption(QCommandLineOption("encryption", tr("Whether or not to enable encryption"))); parser.addOption(QCommandLineOption("pex", tr("Whether or not to enable peer exchange"))); parser.addOption(QCommandLineOption("utp", tr("Whether or not to use utp"))); parser.process(*this); qsrand(time(0)); bt::SetClientInfo("ktcli",bt::MAJOR,bt::MINOR,bt::RELEASE,bt::NORMAL,"KT"); bt::InitLog("ktcli.log",false,true,false); connect(tc.get(),SIGNAL(finished(bt::TorrentInterface*)),this,SLOT(finished(bt::TorrentInterface*))); connect(this,SIGNAL(aboutToQuit()),this,SLOT(shutdown())); } KTCLI::~KTCLI() { } bool KTCLI::start() { bool ok = false; quint16 port = parser.value("port").toInt(&ok); if (!ok) port = qrand(); if (parser.isSet("encryption")) { Out(SYS_GEN|LOG_NOTICE) << "Enabled encryption" << endl; ServerInterface::enableEncryption(false); } if (parser.isSet("pex")) { Out(SYS_GEN|LOG_NOTICE) << "Enabled PEX" << endl; UTPex::setEnabled(true); } if (parser.isSet("utp")) { Out(SYS_GEN|LOG_NOTICE) << "Enabled UTP" << endl; if (!bt::Globals::instance().initUTPServer(port)) { Out(SYS_GEN|LOG_NOTICE) << "Failed to listen on port " << port << endl; return false; } ServerInterface::setPort(port); ServerInterface::setUtpEnabled(true,true); ServerInterface::setPrimaryTransportProtocol(UTP); } else { if (!bt::Globals::instance().initTCPServer(port)) { Out(SYS_GEN|LOG_NOTICE) << "Failed to listen on port " << port << endl; return false; } } if (parser.positionalArguments().isEmpty()) return false; return load(QUrl::fromLocalFile(parser.positionalArguments().at(0))); } bool KTCLI::load(const QUrl &url) { QDir dir(url.toLocalFile()); if (dir.exists() && dir.exists("torrent") && dir.exists("stats")) { // Load existing torrent if (loadFromDir(dir.absolutePath())) { tc->start(); connect(&timer,SIGNAL(timeout()),this,SLOT(update())); timer.start(250); return true; } } else if (url.isLocalFile()) { QString path = url.toLocalFile(); if (loadFromFile(path)) { tc->start(); connect(&timer,SIGNAL(timeout()),this,SLOT(update())); timer.start(250); return true; } } else { Out(SYS_GEN|LOG_IMPORTANT) << "Non local files not supported" << endl; } return false; } QString KTCLI::tempDir() { QDir tmpdir = QDir(parser.value("tmpdir")); int i = 0; while (tmpdir.exists(QString("tor%1").arg(i))) i++; QString sd = QString("tor%1").arg(i); if (!tmpdir.mkdir(sd)) throw bt::Error(QString("Failed to create temporary directory %1").arg(sd)); tmpdir.cd(sd); return tmpdir.absolutePath(); } bool KTCLI::loadFromFile(const QString & path) { try { tc->init(this, bt::LoadFile(path), tempDir(), QDir::currentPath()); tc->setLoadUrl(QUrl(path)); tc->createFiles(); return true; } catch (bt::Error & err) { Out(SYS_GEN|LOG_IMPORTANT) << err.toString() << endl; return false; } } bool KTCLI::loadFromDir(const QString& path) { try { - tc->init(this, bt::LoadFile(path + "/torrent"), path, QString::null); + tc->init(this, bt::LoadFile(path + "/torrent"), path, QString()); tc->createFiles(); return true; } catch (bt::Error & err) { Out(SYS_GEN|LOG_IMPORTANT) << err.toString() << endl; return false; } } bool KTCLI::notify(QObject* obj, QEvent* ev) { try { return QCoreApplication::notify(obj,ev); } catch (bt::Error & err) { Out(SYS_GEN|LOG_DEBUG) << "Error: " << err.toString() << endl; } catch (std::exception & err) { Out(SYS_GEN|LOG_DEBUG) << "Error: " << err.what() << endl; } return true; } bool KTCLI::alreadyLoaded(const bt::SHA1Hash& ih) const { Q_UNUSED(ih); return false; } void KTCLI::mergeAnnounceList(const bt::SHA1Hash& ih, const bt::TrackerTier* trk) { Q_UNUSED(ih); Q_UNUSED(trk); } void KTCLI::update() { bt::UpdateCurrentTime(); AuthenticationMonitor::instance().update(); tc->update(); updates++; if (updates % 20 == 0) { Out(SYS_GEN|LOG_DEBUG) << "Speed down " << bt::BytesPerSecToString(tc->getStats().download_rate) << endl; Out(SYS_GEN|LOG_DEBUG) << "Speed up " << bt::BytesPerSecToString(tc->getStats().upload_rate) << endl; } } void KTCLI::finished(bt::TorrentInterface* tor) { Q_UNUSED(tor); Out(SYS_GEN|LOG_NOTICE) << "Torrent fully downloaded" << endl; QTimer::singleShot(0,this,SLOT(shutdown())); } void KTCLI::shutdown() { AuthenticationMonitor::instance().shutdown(); WaitJob* j = new WaitJob(2000); tc->stop(j); if (j->needToWait()) j->exec(); j->deleteLater(); Globals::instance().shutdownTCPServer(); Globals::instance().shutdownUTPServer(); quit(); } diff --git a/src/dht/kbucket.cpp b/src/dht/kbucket.cpp index df10274..c33396d 100644 --- a/src/dht/kbucket.cpp +++ b/src/dht/kbucket.cpp @@ -1,377 +1,377 @@ /*************************************************************************** * Copyright (C) 2005 by Joris Guisson * * joris.guisson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "kbucket.h" #include #include #include #include #include #include #include #include #include "kclosestnodessearch.h" #include "rpcserverinterface.h" #include "task.h" #include "pingreq.h" using namespace bt; namespace dht { KBucket::KBucket(RPCServerInterface* srv, const dht::Key& our_id) : RPCCallListener(0), min_key(Key::min()), max_key(Key::max()), srv(srv), our_id(our_id), last_modified(bt::CurrentTime()), refresh_task(0) { } KBucket::KBucket(const dht::Key & min_key, const dht::Key & max_key, dht::RPCServerInterface* srv, const dht::Key& our_id) : RPCCallListener(0), min_key(min_key), max_key(max_key), srv(srv), our_id(our_id), last_modified(bt::CurrentTime()), refresh_task(0) { } KBucket::~KBucket() {} bool KBucket::keyInRange(const dht::Key& k) const { return min_key <= k && k <= max_key; } bool KBucket::splitAllowed() const { if(!keyInRange(our_id)) return false; if(min_key + dht::K >= max_key) return false; return true; } std::pair KBucket::split() throw (KBucket::UnableToSplit) { dht::Key m = dht::Key::mid(min_key, max_key); if(m == min_key || m + 1 == max_key) throw UnableToSplit(); KBucket::Ptr left(new KBucket(min_key, m, srv, our_id)); KBucket::Ptr right(new KBucket(m + 1, max_key, srv, our_id)); QList::iterator i; for (i = entries.begin();i != entries.end();++i) { KBucketEntry & e = *i; if (left->keyInRange(e.getID())) left->insert(e); else right->insert(e); } return std::make_pair(left, right); } bool KBucket::insert(const KBucketEntry & entry) { - QList::iterator i = qFind(entries.begin(), entries.end(), entry); + QList::iterator i = std::find(entries.begin(), entries.end(), entry); // If in the list, move it to the end if (i != entries.end()) { KBucketEntry & e = *i; e.hasResponded(); last_modified = bt::CurrentTime(); entries.erase(i); entries.append(entry); return false; } // insert if not already in the list and we still have room if (i == entries.end() && entries.count() < (int) dht::K) { entries.append(entry); last_modified = bt::CurrentTime(); } else if (!replaceBadEntry(entry)) { if (entries.count() == (int) dht::K && splitAllowed()) { // We can split return true; } else { // ping questionable nodes when replacing a bad one fails pingQuestionable(entry); } } return false; } void KBucket::onResponse(RPCCall* c, RPCMsg::Ptr rsp) { Q_UNUSED(rsp); last_modified = bt::CurrentTime(); if (!pending_entries_busy_pinging.contains(c)) return; KBucketEntry entry = pending_entries_busy_pinging[c]; pending_entries_busy_pinging.remove(c); // call is done so erase it // we have a response so try to find the next bad or questionable node // if we do not have room see if we can get rid of some bad peers if (!replaceBadEntry(entry)) // if no bad peers ping a questionable one pingQuestionable(entry); } void KBucket::onTimeout(RPCCall* c) { if (!pending_entries_busy_pinging.contains(c)) return; KBucketEntry entry = pending_entries_busy_pinging[c]; // replace the entry which timed out QList::iterator i; for (i = entries.begin();i != entries.end();++i) { KBucketEntry & e = *i; if (e.getAddress() == c->getRequest()->getOrigin()) { last_modified = bt::CurrentTime(); entries.erase(i); entries.append(entry); break; } } pending_entries_busy_pinging.remove(c); // call is done so erase it // see if we can do another pending entry if (pending_entries_busy_pinging.count() < 2 && pending_entries.count() > 0) { KBucketEntry pe = pending_entries.front(); pending_entries.pop_front(); if (!replaceBadEntry(pe)) // if no bad peers ping a questionable one pingQuestionable(pe); } } void KBucket::pingQuestionable(const KBucketEntry & replacement_entry) { if (pending_entries_busy_pinging.count() >= 2) { pending_entries.append(replacement_entry); // lets not have to many pending_entries calls going on return; } QList::iterator i; // we haven't found any bad ones so try the questionable ones for (i = entries.begin();i != entries.end();++i) { KBucketEntry & e = *i; if (e.isQuestionable()) { Out(SYS_DHT | LOG_DEBUG) << "Pinging questionable node : " << e.getAddress().toString() << endl; RPCMsg::Ptr p(new PingReq(our_id)); p->setDestination(e.getAddress()); RPCCall* c = srv->doCall(p); if (c) { e.onPingQuestionable(); c->addListener(this); // add the pending entry pending_entries_busy_pinging.insert(c, replacement_entry); return; } } } } bool KBucket::replaceBadEntry(const KBucketEntry & entry) { QList::iterator i; for (i = entries.begin();i != entries.end();++i) { KBucketEntry & e = *i; if (e.isBad()) { // bad one get rid of it last_modified = bt::CurrentTime(); entries.erase(i); entries.append(entry); return true; } } return false; } bool KBucket::contains(const KBucketEntry & entry) const { return entries.contains(entry); } void KBucket::findKClosestNodes(KClosestNodesSearch & kns) { QList::iterator i = entries.begin(); while (i != entries.end()) { kns.tryInsert(*i); ++i; } } bool KBucket::onTimeout(const net::Address & addr) { QList::iterator i; for (i = entries.begin();i != entries.end();++i) { KBucketEntry & e = *i; if (e.getAddress() == addr) { e.requestTimeout(); return true; } } return false; } bool KBucket::needsToBeRefreshed() const { bt::TimeStamp now = bt::CurrentTime(); if (last_modified > now) { last_modified = now; return false; } return !refresh_task && entries.count() > 0 && (now - last_modified > BUCKET_REFRESH_INTERVAL); } void KBucket::updateRefreshTimer() { last_modified = bt::CurrentTime(); } void KBucket::save(bt::BEncoder & enc) { enc.beginDict(); enc.write(QByteArrayLiteral("min"), min_key.toByteArray()); enc.write(QByteArrayLiteral("max"), max_key.toByteArray()); enc.write(QByteArrayLiteral("entries")); enc.beginList(); QList::iterator i; for (i = entries.begin();i != entries.end();++i) { enc.beginDict(); KBucketEntry & e = *i; enc.write(QByteArrayLiteral("id"), e.getID().toByteArray()); enc.write(QByteArrayLiteral("address")); if (e.getAddress().ipVersion() == 4) { Uint8 tmp[6]; bt::WriteUint32(tmp, 0, e.getAddress().toIPv4Address()); bt::WriteUint16(tmp, 4, e.getAddress().port()); enc.write(tmp, 6); } else { Uint8 tmp[18]; memcpy(tmp, e.getAddress().toIPv6Address().c, 16); bt::WriteUint16(tmp, 16, e.getAddress().port()); enc.write(tmp, 18); } enc.end(); } enc.end(); enc.end(); } void KBucket::load(bt::BDictNode* dict) { min_key = dht::Key(dict->getByteArray("min")); max_key = dht::Key(dict->getByteArray("max")); BListNode* entry_list = dict->getList("entries"); if (!entry_list || entry_list->getNumChildren() == 0) return; for (Uint32 i = 0;i < entry_list->getNumChildren(); i++) { BDictNode* entry = entry_list->getDict(i); if (!entry) continue; Key id = Key(entry->getByteArray("id")); QByteArray addr = entry->getByteArray("address"); if (addr.size() == 6) { entries.append(KBucketEntry(net::Address(bt::ReadUint32((const Uint8*)addr.data(), 0), bt::ReadUint16((const Uint8*)addr.data(), 4)), id)); } else { Q_IPV6ADDR ip; memcpy(ip.c, addr.data(), 16); entries.append(KBucketEntry(net::Address(ip, bt::ReadUint16((const Uint8*)addr.data(), 16)), id)); } } } void KBucket::onFinished(Task* t) { if (t == refresh_task) refresh_task = 0; } void KBucket::setRefreshTask(Task* t) { refresh_task = t; if (refresh_task) { connect(refresh_task, &Task::finished, this, &KBucket::onFinished); } } } diff --git a/src/net/portlist.cpp b/src/net/portlist.cpp index 9587039..af37ec3 100644 --- a/src/net/portlist.cpp +++ b/src/net/portlist.cpp @@ -1,74 +1,74 @@ /*************************************************************************** * Copyright (C) 2005 by Joris Guisson * * joris.guisson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "portlist.h" #include namespace net { Port::Port() : number(0),proto(TCP),forward(false) { } Port::Port(bt::Uint16 number,Protocol proto,bool forward) : number(number),proto(proto),forward(forward) { } Port::Port(const Port & p) : number(p.number),proto(p.proto),forward(p.forward) { } bool Port::operator == (const Port & p) const { return number == p.number && proto == p.proto; } PortList::PortList() : lst(0) {} PortList::~PortList() {} void PortList::addNewPort(bt::Uint16 number,Protocol proto,bool forward) { Port p = Port(number,proto,forward); append(p); if (lst) lst->portAdded(p); } void PortList::removePort(bt::Uint16 number,Protocol proto) { - PortList::iterator itr = qFind(begin(),end(),Port(number,proto,false)); + PortList::iterator itr = std::find(begin(),end(),Port(number,proto,false)); if (itr == end()) return; if (lst) lst->portRemoved(*itr); erase(itr); } }