downloadlist.cpp

Go to the documentation of this file.
00001 /**
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** \file downloadlist.cpp
00020  *  Implementation of Download and DownloadList classes
00021  */
00022 
00023 #include <hn/hnprec.h>
00024 #include "downloadlist.h"
00025 #include "clients.h"
00026 #include "clientext.h"
00027 #include <hn/fileslist.h>
00028 #include <hn/sharedfile.h>
00029 #include <hn/metadata.h>
00030 #include <hn/partdata.h>
00031 #include <boost/lambda/bind.hpp>
00032 #include <boost/multi_index_container.hpp>
00033 #include <boost/multi_index/key_extractors.hpp>
00034 #include <boost/multi_index/ordered_index.hpp>
00035 
00036 const std::string TRACE_SRCEXCH("SourceExchange");
00037 
00038 // Download class
00039 // --------------
00040 Download::Download(PartData *pd, const Hash<ED2KHash> &hash) : m_partData(pd),
00041 m_hash(hash), m_lastSrcExch(), m_sourceLimit(), m_lastUdpQuery() {}
00042 
00043 Download::~Download() {}
00044 
00045 bool Download::isSourceReqAllowed(Client *c) const {
00046         if (c->getSrcExchVer() < 1) {
00047                 return false; // no source-exchange support
00048         }
00049         if (m_sourceLimit && m_sources.size() >= m_sourceLimit) {
00050                 return false; // got enough sources already
00051         }
00052         uint64_t curTick = Utils::getTick();
00053         Detail::SourceInfoPtr src = c->getSourceInfo();
00054 
00055         // too early for this client
00056         if (src->getLastSrcExch() + SRCEXCH_CTIME > curTick) {
00057                 return false;
00058         }
00059 
00060         // very rare file is asked from each client, once per 40 min
00061         if (getSourceCount() < 10) {
00062                 return true;
00063         }
00064 
00065         // rare file asked once per 5 minutes
00066         if (m_lastSrcExch + SRCEXCH_FTIME > curTick) {
00067                 return false;
00068         }
00069 
00070         // rare files asked once per 5 minutes from one client
00071         if (getSourceCount() < 50) {
00072                 return true;
00073         }
00074 
00075         // not rare file - one query per 20 minutes per file
00076         if (m_lastSrcExch + SRCEXCH_FTIME * 4 > curTick) {
00077                 return false;
00078         } else {
00079                 return true;
00080         }
00081 
00082         return false;
00083 }
00084 
00085 std::vector<Download::Source> Download::getSources() const {
00086         std::vector<Source> tmp;
00087         for (CIter i = m_sources.begin(); i != m_sources.end(); ++i) {
00088                 Source src(
00089                         (*i)->getId(), (*i)->getTcpPort(),
00090                         (*i)->getServerAddr().getIp(),
00091                         (*i)->getServerAddr().getPort()
00092                 );
00093                 tmp.push_back(src);
00094         }
00095         return tmp;
00096 }
00097 
00098 uint32_t Download::getSize() const { return m_partData->getSize(); }
00099 
00100 void Download::destroy() {
00101         CIter i = m_sources.begin();
00102         while (i != m_sources.end()) {
00103                 CIter tmp(i++);
00104                 (*tmp)->remOffered(this, false);
00105         }
00106 }
00107 
00108 // DownloadList class
00109 // ------------------
00110 
00111 namespace Detail {
00112         struct MIDownloadList : boost::multi_index_container<
00113                 Download*,
00114                 boost::multi_index::indexed_by<
00115                         boost::multi_index::ordered_unique<
00116                                 boost::multi_index::const_mem_fun<
00117                                         Download, PartData*,
00118                                         &Download::getPartData
00119                                 >
00120                         >,
00121                         boost::multi_index::ordered_unique<
00122                                 boost::multi_index::identity<
00123                                         Download*
00124                                 >
00125                         >,
00126                         boost::multi_index::ordered_unique<
00127                                 boost::multi_index::const_mem_fun<
00128                                         Download, Hash<ED2KHash>,
00129                                         &Download::getHash
00130                                 >
00131                         >,
00132                         boost::multi_index::ordered_non_unique<
00133                                 boost::multi_index::const_mem_fun<
00134                                         Download, uint32_t,
00135                                         &Download::getSourceCount
00136                                 >
00137                         >,
00138                         boost::multi_index::ordered_non_unique<
00139                                 boost::multi_index::const_mem_fun<
00140                                         Download, uint64_t,
00141                                         &Download::getLastUdpQuery
00142                                 >
00143                         >
00144                 >
00145         > {};
00146         enum { ID_PD, ID_Download, ID_Hash, ID_SrcCnt, ID_UdpQTime };
00147         typedef MIDownloadList::nth_index<ID_PD>::type::iterator Iter;
00148         typedef MIDownloadList::nth_index<ID_Download>::type::iterator DIter;
00149         typedef MIDownloadList::nth_index<ID_Hash>::type::iterator HashIter;
00150         typedef MIDownloadList::nth_index<ID_SrcCnt>::type::iterator SrcCIter;
00151         typedef MIDownloadList::nth_index<ID_UdpQTime>::type::iterator QTIter;
00152         struct MIDownloadListIterator : public Iter {
00153                 template<typename T>
00154                 MIDownloadListIterator(T t) : Iter(t) {}
00155         };
00156 }
00157 
00158 DownloadList::Iter::Iter(Impl impl) : m_impl(impl) {}
00159 Download& DownloadList::Iter::operator*() { return *(*(*m_impl)); }
00160 Download& DownloadList::Iter::operator->() { return *(*(*m_impl)); }
00161 void DownloadList::Iter::operator++() { ++*m_impl; }
00162 void DownloadList::Iter::operator--() { --*m_impl; }
00163 bool DownloadList::Iter::operator==(const DownloadList::Iter& x) const {
00164         return *m_impl == *x.m_impl;
00165 }
00166 bool DownloadList::Iter::operator!=(const DownloadList::Iter& x) const {
00167         return *m_impl != *x.m_impl;
00168 }
00169 
00170 DownloadList *s_downloadList = 0;
00171 DownloadList::DownloadList() : m_list(new Detail::MIDownloadList) {}
00172 DownloadList::~DownloadList() { s_downloadList = 0; }
00173 DownloadList::Iter DownloadList::begin() {
00174         Iter::Impl tmp(new Detail::MIDownloadListIterator(m_list->begin()));
00175         return Iter(tmp);
00176 }
00177 DownloadList::Iter DownloadList::end() {
00178         Iter::Impl tmp(new Detail::MIDownloadListIterator(m_list->end()));
00179         return Iter(tmp);
00180 }
00181 
00182 DownloadList& DownloadList::instance() {
00183         if (!s_downloadList) {
00184                 s_downloadList = new DownloadList;
00185         }
00186         return *s_downloadList;
00187 }
00188 
00189 void DownloadList::init() {
00190         FilesList::SFIter it = FilesList::instance().begin();
00191         for (; it != FilesList::instance().end(); ++it) {
00192                 tryAddFile(*it);
00193         }
00194         PartData::getEventTable().addHandler(0, this, &DownloadList::onPDEvent);
00195         SharedFile::getEventTable().addHandler(
00196                 0, this, &DownloadList::onSFEvent
00197         );
00198 
00199         Log::instance().enableTraceMask(TRACE_SRCEXCH);
00200         logDebug(
00201                 boost::format(
00202                         "DownloadList initialized, %d downloads are known."
00203                 ) % m_list->size()
00204         );
00205 }
00206 
00207 void DownloadList::exit() {
00208         for (Detail::Iter it = m_list->begin(); it != m_list->end(); ++it) {
00209                 delete *it;
00210         }
00211 }
00212 
00213 void DownloadList::tryAddFile(SharedFile *sf) {
00214         if (!sf->isPartial()) {
00215                 return;
00216         }
00217         if (!sf->getMetaData()) {
00218                 return;
00219         }
00220         MetaData *md = sf->getMetaData();
00221         if (md->getFileSize() > std::numeric_limits<uint32_t>::max()) {
00222                 return;
00223         }
00224         for (uint32_t j = 0; j < md->getHashSetCount(); ++j) {
00225                 HashSetBase *hs = md->getHashSet(j);
00226                 if (hs->getFileHashTypeId() != CGComm::OP_HT_ED2K) {
00227                         continue;
00228                 }
00229                 const Hash<ED2KHash> &h(
00230                         dynamic_cast<const Hash<ED2KHash>&>(hs->getFileHash())
00231                 );
00232                 Download *d = new Download(sf->getPartData(), h);
00233                 m_list->insert(d);
00234                 onAdded(*d);
00235         }
00236 }
00237 
00238 void DownloadList::onPDEvent(PartData *pd, int evt) {
00239         if (evt != PD_DESTROY) {
00240                 return;
00241         }
00242         Detail::Iter it = m_list->find(pd);
00243         if (it == m_list->end()) {
00244                 return;
00245         }
00246         onRemoved(*(*it));
00247         (*it)->destroy();
00248         delete *it;
00249         m_list->erase(it);
00250 }
00251 
00252 void DownloadList::onSFEvent(SharedFile *sf, int evt) {
00253         if (evt == SF_ADDED && sf->isPartial()) {
00254                 tryAddFile(sf);
00255         }
00256 }
00257 
00258 Download* DownloadList::getNextForUdpQuery() {
00259         uint64_t curTick = Utils::getTick();
00260         Detail::QTIter it = m_list->get<Detail::ID_UdpQTime>().lower_bound(0);
00261 
00262         if (it != m_list->get<Detail::ID_UdpQTime>().end()) {
00263                 m_list->get<Detail::ID_UdpQTime>().modify(
00264                         it, bind(&Download::m_lastUdpQuery, __1(__1)) = curTick
00265                 );
00266                 return *it;
00267         } else {
00268                 return 0;
00269         }
00270 }
00271 
00272 Download* DownloadList::find(const Hash<ED2KHash> &hash) const {
00273         Detail::HashIter it = m_list->get<Detail::ID_Hash>().find(hash);
00274         return it == m_list->get<Detail::ID_Hash>().end() ? 0 : *it;
00275 }
00276 
00277 bool DownloadList::valid(Download *ptr) const {
00278         Detail::DIter it = m_list->get<Detail::ID_Download>().find(ptr);
00279         return it != m_list->get<Detail::ID_Download>().end();
00280 }