summaryrefslogtreecommitdiffstats
path: root/libktorrent/torrent/chunkdownload.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libktorrent/torrent/chunkdownload.cpp')
-rw-r--r--libktorrent/torrent/chunkdownload.cpp484
1 files changed, 0 insertions, 484 deletions
diff --git a/libktorrent/torrent/chunkdownload.cpp b/libktorrent/torrent/chunkdownload.cpp
deleted file mode 100644
index 76638ce..0000000
--- a/libktorrent/torrent/chunkdownload.cpp
+++ /dev/null
@@ -1,484 +0,0 @@
-/***************************************************************************
- * 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 <algorithm>
-#include <util/file.h>
-#include <util/log.h>
-#include <util/array.h>
-#include "chunkdownload.h"
-#include "downloader.h"
-#include "chunk.h"
-#include "peer.h"
-#include "peermanager.h"
-#include "piece.h"
-#include "peerdownloader.h"
-
-#include <tdelocale.h>
-
-namespace bt
-{
-
- class DownloadStatus : public std::set<Uint32>
- {
- public:
- // typedef std::set<Uint32>::iterator iterator;
-
- DownloadStatus()
- {
-
- }
-
- ~DownloadStatus()
- {
- }
-
- void add(Uint32 p)
- {
- insert(p);
- }
-
- void remove(Uint32 p)
- {
- erase(p);
- }
-
- bool contains(Uint32 p)
- {
- return count(p) > 0;
- }
- };
-
- ChunkDownload::ChunkDownload(Chunk* chunk) : chunk(chunk)
- {
- num = num_downloaded = 0;
-
- num = chunk->getSize() / MAX_PIECE_LEN;
-
- if (chunk->getSize() % MAX_PIECE_LEN != 0)
- {
- last_size = chunk->getSize() % MAX_PIECE_LEN;
- num++;
- }
- else
- {
- last_size = MAX_PIECE_LEN;
- }
-
- pieces = BitSet(num);
- pieces.clear();
-
- for (Uint32 i = 0;i < num;i++)
- piece_queue.append(i);
-
- dstatus.setAutoDelete(true);
- chunk->ref();
-
- num_pieces_in_hash = 0;
- if (usingContinuousHashing())
- hash_gen.start();
-
- }
-
- ChunkDownload::~ChunkDownload()
- {
- chunk->unref();
- }
-
- bool ChunkDownload::piece(const Piece & p,bool & ok)
- {
- ok = false;
- timer.update();
-
- Uint32 pp = p.getOffset() / MAX_PIECE_LEN;
- if (pieces.get(pp))
- return false;
-
-
- DownloadStatus* ds = dstatus.find(p.getPeer());
- if (ds)
- ds->remove(pp);
-
- Uint8* buf = chunk->getData();
- if (buf)
- {
- ok = true;
- memcpy(buf + p.getOffset(),p.getData(),p.getLength());
- pieces.set(pp,true);
- piece_queue.remove(pp);
- piece_providers.insert(p.getPeer());
- num_downloaded++;
- if (pdown.count() > 1)
- {
- endgameCancel(p);
- }
-
- if (usingContinuousHashing())
- updateHash();
-
- if (num_downloaded >= num)
- {
- // finalize hash
- if (usingContinuousHashing())
- hash_gen.end();
-
- releaseAllPDs();
- return true;
- }
- }
-
- for (TQPtrList<PeerDownloader>::iterator i = pdown.begin();i != pdown.end();++i)
- sendRequests(*i);
-
- return false;
- }
-
- void ChunkDownload::releaseAllPDs()
- {
- for (Uint32 i = 0;i < pdown.count();i++)
- {
- PeerDownloader* pd = pdown.at(i);
- pd->release();
- disconnect(pd,TQT_SIGNAL(timedout(const Request& )),this,TQT_SLOT(onTimeout(const Request& )));
- disconnect(pd,TQT_SIGNAL(rejected( const Request& )),this,TQT_SLOT(onRejected( const Request& )));
- }
- dstatus.clear();
- pdown.clear();
- }
-
- bool ChunkDownload::assignPeer(PeerDownloader* pd)
- {
- if (!pd || pdown.contains(pd))
- return false;
-
- pd->grab();
- pdown.append(pd);
- dstatus.insert(pd->getPeer()->getID(),new DownloadStatus());
- sendRequests(pd);
- connect(pd,TQT_SIGNAL(timedout(const Request& )),this,TQT_SLOT(onTimeout(const Request& )));
- connect(pd,TQT_SIGNAL(rejected( const Request& )),this,TQT_SLOT(onRejected( const Request& )));
- return true;
- }
-
- void ChunkDownload::notDownloaded(const Request & r,bool reject)
- {
- // find the peer
- DownloadStatus* ds = dstatus.find(r.getPeer());
- if (ds)
- {
- // Out() << "ds != 0" << endl;
- Uint32 p = r.getOffset() / MAX_PIECE_LEN;
- ds->remove(p);
- }
-
- // go over all PD's and do requets again
- for (TQPtrList<PeerDownloader>::iterator i = pdown.begin();i != pdown.end();++i)
- sendRequests(*i);
- }
-
- void ChunkDownload::onRejected(const Request & r)
- {
- if (chunk->getIndex() == r.getIndex())
- {
-// Out(SYS_CON|LOG_DEBUG) << TQString("Request rejected %1 %2 %3 %4").arg(r.getIndex()).arg(r.getOffset()).arg(r.getLength()).arg(r.getPeer()) << endl;
-
- notDownloaded(r,true);
- }
- }
-
- void ChunkDownload::onTimeout(const Request & r)
- {
- // see if we are dealing with a piece of ours
- if (chunk->getIndex() == r.getIndex())
- {
- Out(SYS_CON|LOG_DEBUG) << TQString("Request timed out %1 %2 %3 %4").arg(r.getIndex()).arg(r.getOffset()).arg(r.getLength()).arg(r.getPeer()) << endl;
-
- notDownloaded(r,false);
- }
- }
-
- void ChunkDownload::sendRequests(PeerDownloader* pd)
- {
- timer.update();
- DownloadStatus* ds = dstatus.find(pd->getPeer()->getID());
- if (!ds)
- return;
-
- // if the peer is choked and we are not downloading an allowed fast chunk
- if (pd->isChoked())
- return;
-
- Uint32 num_visited = 0;
- while (num_visited < piece_queue.count() && pd->canAddRequest())
- {
- // get the first one in the queue
- Uint32 i = piece_queue.first();
- if (!ds->contains(i))
- {
- // send request
- pd->download(
- Request(
- chunk->getIndex(),
- i*MAX_PIECE_LEN,
- i+1<num ? MAX_PIECE_LEN : last_size,
- pd->getPeer()->getID()));
- ds->add(i);
- }
- // move to the back so that it will take a while before it's turn is up
- piece_queue.pop_front();
- piece_queue.append(i);
- num_visited++;
- }
-
- if (piece_queue.count() < 2 && piece_queue.count() > 0)
- pd->setNearlyDone(true);
- }
-
-
-
- void ChunkDownload::update()
- {
- // go over all PD's and do requets again
- for (TQPtrList<PeerDownloader>::iterator i = pdown.begin();i != pdown.end();++i)
- sendRequests(*i);
- }
-
-
- void ChunkDownload::sendCancels(PeerDownloader* pd)
- {
- DownloadStatus* ds = dstatus.find(pd->getPeer()->getID());
- if (!ds)
- return;
-
- DownloadStatus::iterator itr = ds->begin();
- while (itr != ds->end())
- {
- Uint32 i = *itr;
- pd->cancel(
- Request(
- chunk->getIndex(),
- i*MAX_PIECE_LEN,
- i+1<num ? MAX_PIECE_LEN : last_size,0));
- itr++;
- }
- ds->clear();
- timer.update();
- }
-
- void ChunkDownload::endgameCancel(const Piece & p)
- {
- TQPtrList<PeerDownloader>::iterator i = pdown.begin();
- while (i != pdown.end())
- {
- PeerDownloader* pd = *i;
- DownloadStatus* ds = dstatus.find(pd->getPeer()->getID());
- Uint32 pp = p.getOffset() / MAX_PIECE_LEN;
- if (ds && ds->contains(pp))
- {
- pd->cancel(Request(p));
- ds->remove(pp);
- }
- i++;
- }
- }
-
- void ChunkDownload::peerKilled(PeerDownloader* pd)
- {
- if (!pdown.contains(pd))
- return;
-
- dstatus.erase(pd->getPeer()->getID());
- pdown.remove(pd);
- disconnect(pd,TQT_SIGNAL(timedout(const Request& )),this,TQT_SLOT(onTimeout(const Request& )));
- disconnect(pd,TQT_SIGNAL(rejected( const Request& )),this,TQT_SLOT(onRejected( const Request& )));
- }
-
-
- const Peer* ChunkDownload::getCurrentPeer() const
- {
- if (pdown.count() == 0)
- return 0;
- else
- return pdown.getFirst()->getPeer();
- }
-
- Uint32 ChunkDownload::getChunkIndex() const
- {
- return chunk->getIndex();
- }
-
- TQString ChunkDownload::getCurrentPeerID() const
- {
- if (pdown.count() == 0)
- {
- return TQString();
- }
- else if (pdown.count() == 1)
- {
- const Peer* p = pdown.getFirst()->getPeer();
- return p->getPeerID().identifyClient();
- }
- else
- {
- return i18n("1 peer","%n peers",pdown.count());
- }
- }
-
- Uint32 ChunkDownload::getDownloadSpeed() const
- {
- Uint32 r = 0;
- TQPtrList<PeerDownloader>::const_iterator i = pdown.begin();
- while (i != pdown.end())
- {
- const PeerDownloader* pd = *i;
- r += pd->getPeer()->getDownloadRate();
- i++;
- }
- return r;
- }
-
-
-
- void ChunkDownload::save(File & file)
- {
- ChunkDownloadHeader hdr;
- hdr.index = chunk->getIndex();
- hdr.num_bits = pieces.getNumBits();
- hdr.buffered = chunk->getStatus() == Chunk::BUFFERED ? 1 : 0;
- // save the chunk header
- file.write(&hdr,sizeof(ChunkDownloadHeader));
- // save the bitset
- file.write(pieces.getData(),pieces.getNumBytes());
- if (hdr.buffered)
- {
- // if it's a buffered chunk, save the contents to
- file.write(chunk->getData(),chunk->getSize());
- chunk->clear();
- chunk->setStatus(Chunk::ON_DISK);
- }
- }
-
- bool ChunkDownload::load(File & file,ChunkDownloadHeader & hdr)
- {
- // read pieces
- if (hdr.num_bits != num)
- return false;
-
- pieces = BitSet(hdr.num_bits);
- Array<Uint8> data(pieces.getNumBytes());
- file.read(data,pieces.getNumBytes());
- pieces = BitSet(data,hdr.num_bits);
- num_downloaded = pieces.numOnBits();
- if (hdr.buffered)
- {
- // if it's a buffered chunk, load the data to
- if (file.read(chunk->getData(),chunk->getSize()) != chunk->getSize())
- return false;
- }
-
- for (Uint32 i = 0;i < pieces.getNumBits();i++)
- if (pieces.get(i))
- piece_queue.remove(i);
-
- updateHash();
- return true;
- }
-
- Uint32 ChunkDownload::bytesDownloaded() const
- {
- Uint32 num_bytes = 0;
- for (Uint32 i = 0;i < num;i++)
- {
- if (pieces.get(i))
- {
- num_bytes += i == num-1 ? last_size : MAX_PIECE_LEN;
- }
- }
- return num_bytes;
- }
-
- void ChunkDownload::cancelAll()
- {
- TQPtrList<PeerDownloader>::iterator i = pdown.begin();
- while (i != pdown.end())
- {
- sendCancels(*i);
- i++;
- }
- }
-
- bool ChunkDownload::getOnlyDownloader(Uint32 & pid)
- {
- if (piece_providers.size() == 1)
- {
- pid = *piece_providers.begin();
- return true;
- }
- else
- {
- return false;
- }
- }
-
- void ChunkDownload::getStats(Stats & s)
- {
- s.chunk_index = chunk->getIndex();
- s.current_peer_id = getCurrentPeerID();
- s.download_speed = getDownloadSpeed();
- s.num_downloaders = getNumDownloaders();
- s.pieces_downloaded = num_downloaded;
- s.total_pieces = num;
- }
-
- bool ChunkDownload::isChoked() const
- {
- TQPtrList<PeerDownloader>::const_iterator i = pdown.begin();
- while (i != pdown.end())
- {
- const PeerDownloader* pd = *i;
- // if there is one which isn't choked
- if (!pd->isChoked())
- return false;
- i++;
- }
- return true;
- }
-
- void ChunkDownload::updateHash()
- {
- // update the hash until where we can
- Uint32 nn = num_pieces_in_hash;
- while (pieces.get(nn) && nn < num)
- nn++;
-
- for (Uint32 i = num_pieces_in_hash;i < nn;i++)
- {
- const Uint8* data = chunk->getData() + i * MAX_PIECE_LEN;
- hash_gen.update(data,i == num - 1 ? last_size : MAX_PIECE_LEN);
- }
- num_pieces_in_hash = nn;
- }
-
- bool ChunkDownload::usingContinuousHashing() const
- {
- // if the pieces are larger then 1 MB we will be using the continuous hashing feature
- return pieces.getNumBits() > 64;
- }
-}
-#include "chunkdownload.moc"