mirror of https://github.com/aria2/aria2
pull/1/head
parent
ec642ad294
commit
45463f935f
|
@ -3,6 +3,8 @@
|
|||
To divide TorrentMan into 6 classes: BtContext, BtRuntime,
|
||||
PeerStorage, PieceStorage, BtAnnounce and BtProgressInfoFile
|
||||
|
||||
* src/TorrentMan.h: Removed.
|
||||
* src/TorrentMan.cc: Removed.
|
||||
* src/TrackerWatcherComand.h: Made subclass of BtContextAwareCommand.
|
||||
* src/SeedCheckCommand.cc: Use pieceStorage, btRuntime
|
||||
* src/PeerAbstractCommand.h: Made subclass of BtContextAwareCommand.
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
../src/TorrentMan.cc \
|
||||
../src/RequestInfo.h \
|
||||
../src/message.h \
|
||||
../src/DownloadEngineFactory.cc \
|
||||
../src/TorrentRequestInfo.cc \
|
||||
../src/UrlRequestInfo.cc \
|
||||
../src/main.cc
|
||||
../src/main.cc \
|
||||
../src/DefaultPieceStorage.cc \
|
||||
../src/DefaultBtAnnounce.cc \
|
||||
../src/DefaultBtProgressInfoFile.cc
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
src/TorrentMan.cc
|
||||
src/RequestInfo.h
|
||||
src/message.h
|
||||
src/DownloadEngineFactory.cc
|
||||
src/TorrentRequestInfo.cc
|
||||
src/UrlRequestInfo.cc
|
||||
src/main.cc
|
||||
src/DefaultPieceStorage.cc
|
||||
src/DefaultBtAnnounce.cc
|
||||
src/DefaultBtProgressInfoFile.cc
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
|
||||
"POT-Creation-Date: 2006-10-18 23:54+0900\n"
|
||||
"POT-Creation-Date: 2006-11-06 00:12+0900\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@ -16,14 +16,6 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: src/TorrentMan.cc:685
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr ""
|
||||
|
||||
#: src/TorrentMan.cc:688
|
||||
msgid "The download was complete."
|
||||
msgstr ""
|
||||
|
||||
#: src/RequestInfo.h:97
|
||||
#, c-format
|
||||
msgid ""
|
||||
|
@ -352,12 +344,12 @@ msgstr ""
|
|||
msgid "Failed to peek data, cause: %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/DownloadEngineFactory.cc:110
|
||||
#: src/DownloadEngineFactory.cc:139
|
||||
#, c-format
|
||||
msgid "Errors occurred while binding port.\n"
|
||||
msgstr ""
|
||||
|
||||
#: src/TorrentRequestInfo.cc:90
|
||||
#: src/TorrentRequestInfo.cc:91
|
||||
msgid "Files:"
|
||||
msgstr ""
|
||||
|
||||
|
@ -850,3 +842,11 @@ msgstr ""
|
|||
#: src/main.cc:773
|
||||
msgid "checksum ERROR."
|
||||
msgstr ""
|
||||
|
||||
#: src/DefaultPieceStorage.cc:219
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr ""
|
||||
|
||||
#: src/DefaultPieceStorage.cc:222
|
||||
msgid "The download was complete."
|
||||
msgstr ""
|
||||
|
|
30
po/de.po
30
po/de.po
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: de\n"
|
||||
"Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
|
||||
"POT-Creation-Date: 2006-10-18 23:54+0900\n"
|
||||
"POT-Creation-Date: 2006-11-06 00:12+0900\n"
|
||||
"PO-Revision-Date: 2006-05-05 19:44+0900\n"
|
||||
"Last-Translator: Hermann J. Beckers <hj.beckers@onlinehome.de>\n"
|
||||
"Language-Team: deutsch <de@li.org>\n"
|
||||
|
@ -16,18 +16,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: KBabel 1.3\n"
|
||||
|
||||
#: src/TorrentMan.cc:685
|
||||
#, fuzzy
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr " Nur ausgewählte Dateien abrufen:"
|
||||
|
||||
#: src/TorrentMan.cc:688
|
||||
#, fuzzy
|
||||
msgid "The download was complete."
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Abruf ist vollständig. <%s>\n"
|
||||
|
||||
#: src/RequestInfo.h:97
|
||||
#, c-format
|
||||
msgid ""
|
||||
|
@ -369,12 +357,12 @@ msgstr "Konnte Daten nicht erhalten, Ursache: %s"
|
|||
msgid "Failed to peek data, cause: %s"
|
||||
msgstr "Datenermittelung fehlgeschlagen, Ursache: %s"
|
||||
|
||||
#: src/DownloadEngineFactory.cc:110
|
||||
#: src/DownloadEngineFactory.cc:139
|
||||
#, c-format
|
||||
msgid "Errors occurred while binding port.\n"
|
||||
msgstr "Fehler beim Binden an Port aufgetreten.\n"
|
||||
|
||||
#: src/TorrentRequestInfo.cc:90
|
||||
#: src/TorrentRequestInfo.cc:91
|
||||
msgid "Files:"
|
||||
msgstr "Dateien:"
|
||||
|
||||
|
@ -1014,6 +1002,18 @@ msgstr ""
|
|||
msgid "checksum ERROR."
|
||||
msgstr ""
|
||||
|
||||
#: src/DefaultPieceStorage.cc:219
|
||||
#, fuzzy
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr " Nur ausgewählte Dateien abrufen:"
|
||||
|
||||
#: src/DefaultPieceStorage.cc:222
|
||||
#, fuzzy
|
||||
msgid "The download was complete."
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Abruf ist vollständig. <%s>\n"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid ""
|
||||
#~ " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
|
||||
|
|
22
po/ja.po
22
po/ja.po
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: aria2c 0.2.1\n"
|
||||
"Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
|
||||
"POT-Creation-Date: 2006-10-18 23:54+0900\n"
|
||||
"POT-Creation-Date: 2006-11-06 00:12+0900\n"
|
||||
"PO-Revision-Date: 2006-10-01 22:31+0900\n"
|
||||
"Last-Translator: Tatsuhiro Tsujikawa <tujikawa@rednoah.com>\n"
|
||||
"Language-Team: Japanese <ja@li.org>\n"
|
||||
|
@ -16,14 +16,6 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/TorrentMan.cc:685
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr "ご指定のファイルのダウンロードが完了."
|
||||
|
||||
#: src/TorrentMan.cc:688
|
||||
msgid "The download was complete."
|
||||
msgstr "ダウンロードが完了."
|
||||
|
||||
#: src/RequestInfo.h:97
|
||||
#, c-format
|
||||
msgid ""
|
||||
|
@ -369,12 +361,12 @@ msgstr "
|
|||
msgid "Failed to peek data, cause: %s"
|
||||
msgstr "データの peek に失敗しました. 原因: %s"
|
||||
|
||||
#: src/DownloadEngineFactory.cc:110
|
||||
#: src/DownloadEngineFactory.cc:139
|
||||
#, c-format
|
||||
msgid "Errors occurred while binding port.\n"
|
||||
msgstr "ポートをバインド中にエラーが発生しました.\n"
|
||||
|
||||
#: src/TorrentRequestInfo.cc:90
|
||||
#: src/TorrentRequestInfo.cc:91
|
||||
msgid "Files:"
|
||||
msgstr "ファイル:"
|
||||
|
||||
|
@ -1035,6 +1027,14 @@ msgstr "
|
|||
msgid "checksum ERROR."
|
||||
msgstr "チェックサム エラー."
|
||||
|
||||
#: src/DefaultPieceStorage.cc:219
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr "ご指定のファイルのダウンロードが完了."
|
||||
|
||||
#: src/DefaultPieceStorage.cc:222
|
||||
msgid "The download was complete."
|
||||
msgstr "ダウンロードが完了."
|
||||
|
||||
#~ msgid ""
|
||||
#~ " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
|
||||
#~ " K or M(1K = 1024, 1M = 1024K). This\n"
|
||||
|
|
30
po/ru.po
30
po/ru.po
|
@ -10,7 +10,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: ru\n"
|
||||
"Report-Msgid-Bugs-To: http://aria2.sourceforge.net/\n"
|
||||
"POT-Creation-Date: 2006-10-18 23:54+0900\n"
|
||||
"POT-Creation-Date: 2006-11-06 00:12+0900\n"
|
||||
"PO-Revision-Date: 2006-07-28 18:04+0600\n"
|
||||
"Last-Translator: Azamat H. Hackimov <azamat.hackimov@gmail.com>\n"
|
||||
"Language-Team: <ru@li.org>\n"
|
||||
|
@ -21,18 +21,6 @@ msgstr ""
|
|||
"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: KBabel 1.11.2\n"
|
||||
|
||||
#: src/TorrentMan.cc:685
|
||||
#, fuzzy
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr " Скачать только выбранные файлы:"
|
||||
|
||||
#: src/TorrentMan.cc:688
|
||||
#, fuzzy
|
||||
msgid "The download was complete."
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Скачивание завершено. <%s>\n"
|
||||
|
||||
#: src/RequestInfo.h:97
|
||||
#, c-format
|
||||
msgid ""
|
||||
|
@ -371,12 +359,12 @@ msgstr "Ошибка получения данных: %s"
|
|||
msgid "Failed to peek data, cause: %s"
|
||||
msgstr "Ошибка запроса данных: %s"
|
||||
|
||||
#: src/DownloadEngineFactory.cc:110
|
||||
#: src/DownloadEngineFactory.cc:139
|
||||
#, c-format
|
||||
msgid "Errors occurred while binding port.\n"
|
||||
msgstr "Ошибка при открытии порта.\n"
|
||||
|
||||
#: src/TorrentRequestInfo.cc:90
|
||||
#: src/TorrentRequestInfo.cc:91
|
||||
msgid "Files:"
|
||||
msgstr "Файлы:"
|
||||
|
||||
|
@ -994,6 +982,18 @@ msgstr ""
|
|||
msgid "checksum ERROR."
|
||||
msgstr ""
|
||||
|
||||
#: src/DefaultPieceStorage.cc:219
|
||||
#, fuzzy
|
||||
msgid "Download of selected files was complete."
|
||||
msgstr " Скачать только выбранные файлы:"
|
||||
|
||||
#: src/DefaultPieceStorage.cc:222
|
||||
#, fuzzy
|
||||
msgid "The download was complete."
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Скачивание завершено. <%s>\n"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid ""
|
||||
#~ " --min-segment-size=SIZE[K|M] Set minimum segment size. You can append\n"
|
||||
|
|
|
@ -1,911 +0,0 @@
|
|||
/* <!-- copyright */
|
||||
/*
|
||||
* aria2 - The high speed download utility
|
||||
*
|
||||
* Copyright (C) 2006 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the
|
||||
* OpenSSL library under certain conditions as described in each
|
||||
* individual source file, and distribute linked combinations
|
||||
* including the two.
|
||||
* You must obey the GNU General Public License in all respects
|
||||
* for all of the code used other than OpenSSL. If you modify
|
||||
* file(s) with this exception, you may extend this exception to your
|
||||
* version of the file(s), but you are not obligated to do so. If you
|
||||
* do not wish to do so, delete this exception statement from your
|
||||
* version. If you delete this exception statement from all source
|
||||
* files in the program, then also delete it here.
|
||||
*/
|
||||
/* copyright --> */
|
||||
#include "TorrentMan.h"
|
||||
#include "Dictionary.h"
|
||||
#include "List.h"
|
||||
#include "ShaVisitor.h"
|
||||
#include "Util.h"
|
||||
#include "MetaFileUtil.h"
|
||||
#include "DlAbortEx.h"
|
||||
#include "File.h"
|
||||
#include "message.h"
|
||||
#include "PreAllocationDiskWriter.h"
|
||||
#include "DefaultDiskWriter.h"
|
||||
#include "MultiDiskWriter.h"
|
||||
#include "prefs.h"
|
||||
#include "CopyDiskAdaptor.h"
|
||||
#include "DirectDiskAdaptor.h"
|
||||
#include "MultiDiskAdaptor.h"
|
||||
#include "LogFactory.h"
|
||||
#include "DelegatingPeerListProcessor.h"
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
extern PeerHandle nullPeer;
|
||||
|
||||
TorrentMan::TorrentMan():bitfield(0),
|
||||
peerEntryIdCounter(0),
|
||||
cuidCounter(0),
|
||||
downloadLength(0),
|
||||
uploadLength(0),
|
||||
preDownloadLength(0),
|
||||
preUploadLength(0),
|
||||
storeDir("."),
|
||||
setupComplete(false),
|
||||
halt(false),
|
||||
interval(DEFAULT_ANNOUNCE_INTERVAL),
|
||||
minInterval(DEFAULT_ANNOUNCE_MIN_INTERVAL),
|
||||
complete(0),
|
||||
incomplete(0),
|
||||
connections(0),
|
||||
trackers(0),
|
||||
trackerNumTry(0),
|
||||
diskAdaptor(0)
|
||||
{
|
||||
logger = LogFactory::getInstance();
|
||||
// to force requesting to a tracker first time.
|
||||
announceInterval.setTimeInSec(0);
|
||||
}
|
||||
|
||||
TorrentMan::~TorrentMan() {
|
||||
delete bitfield;
|
||||
delete diskAdaptor;
|
||||
}
|
||||
|
||||
// TODO do not use this method in application code
|
||||
void TorrentMan::updatePeers(const Peers& peers) {
|
||||
this->peers = peers;
|
||||
}
|
||||
|
||||
void TorrentMan::addPeer(const Peers& peers) {
|
||||
for(Peers::const_iterator itr = peers.begin();
|
||||
itr != peers.end(); itr++) {
|
||||
const PeerHandle& peer = *itr;
|
||||
if(addPeer(peer)) {
|
||||
logger->debug("Adding peer %s:%d",
|
||||
peer->ipaddr.c_str(), peer->port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TorrentMan::addPeer(const PeerHandle& peer) {
|
||||
Peers::iterator itr = find(peers.begin(), peers.end(), peer);
|
||||
if(itr == peers.end()) {
|
||||
if(peers.size() > MAX_PEER_LIST_SIZE) {
|
||||
deleteUnusedPeer(peers.size()-MAX_PEER_LIST_SIZE+1);
|
||||
}
|
||||
++peerEntryIdCounter;
|
||||
peer->entryId = peerEntryIdCounter;
|
||||
peers.push_back(peer);
|
||||
return true;
|
||||
} else {
|
||||
const PeerHandle& peer = *itr;
|
||||
if(peer->error >= MAX_PEER_ERROR || peer->cuid != 0) {
|
||||
return false;
|
||||
} else {
|
||||
*itr = peer;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void TorrentMan::updatePeer(const Peer& peer) {
|
||||
for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
|
||||
Peer& p = *itr;
|
||||
if(p.eid == peer.eid) {
|
||||
p = peer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool TorrentMan::isPeerAvailable() const {
|
||||
return getPeer() != nullPeer;
|
||||
}
|
||||
|
||||
void TorrentMan::deleteUnusedPeer(int delSize) {
|
||||
for(Peers::iterator itr = peers.begin();
|
||||
itr != peers.end() && delSize > 0;) {
|
||||
const PeerHandle& p = *itr;
|
||||
if(p->cuid == 0) {
|
||||
itr = peers.erase(itr);
|
||||
delSize--;
|
||||
} else {
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PeerHandle TorrentMan::getPeer() const {
|
||||
if(connections > MIN_PEERS) {
|
||||
return nullPeer;
|
||||
}
|
||||
for(Peers::const_iterator itr = peers.begin(); itr != peers.end(); itr++) {
|
||||
const PeerHandle& p = *itr;
|
||||
if(p->cuid == 0 && p->error < MAX_PEER_ERROR) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return nullPeer;
|
||||
}
|
||||
|
||||
bool TorrentMan::isEndGame() const {
|
||||
return bitfield->countMissingBlock() <= END_GAME_PIECE_NUM;
|
||||
}
|
||||
|
||||
bool TorrentMan::hasMissingPiece(const PeerHandle& peer) const {
|
||||
return bitfield->hasMissingPiece(peer->getBitfield(),
|
||||
peer->getBitfieldLength());
|
||||
}
|
||||
|
||||
int TorrentMan::getMissingPieceIndex(const PeerHandle& peer) const {
|
||||
int index = -1;
|
||||
if(isEndGame()) {
|
||||
index = bitfield->getMissingIndex(peer->getBitfield(),
|
||||
peer->getBitfieldLength());
|
||||
} else {
|
||||
index = bitfield->getMissingUnusedIndex(peer->getBitfield(),
|
||||
peer->getBitfieldLength());
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int TorrentMan::getMissingFastPieceIndex(const PeerHandle& peer) const {
|
||||
int index = -1;
|
||||
if(peer->isFastExtensionEnabled() && peer->countFastSet() > 0) {
|
||||
BitfieldMan tempBitfield(pieceLength, totalLength);
|
||||
for(Integers::const_iterator itr = peer->getFastSet().begin();
|
||||
itr != peer->getFastSet().end(); itr++) {
|
||||
if(!hasPiece(*itr) && peer->hasPiece(*itr)) {
|
||||
tempBitfield.setBit(*itr);
|
||||
}
|
||||
}
|
||||
if(isEndGame()) {
|
||||
index = bitfield->getMissingIndex(tempBitfield.getBitfield(),
|
||||
tempBitfield.getBitfieldLength());
|
||||
} else {
|
||||
index = bitfield->getMissingUnusedIndex(tempBitfield.getBitfield(),
|
||||
tempBitfield.getBitfieldLength());
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
Piece TorrentMan::getMissingFastPiece(const PeerHandle& peer) {
|
||||
int index = getMissingFastPieceIndex(peer);
|
||||
return checkOutPiece(index);
|
||||
}
|
||||
|
||||
Piece TorrentMan::getMissingPiece(const PeerHandle& peer) {
|
||||
int index = getMissingPieceIndex(peer);
|
||||
return checkOutPiece(index);
|
||||
}
|
||||
|
||||
Piece TorrentMan::checkOutPiece(int index) {
|
||||
if(index == -1) {
|
||||
return Piece::nullPiece;
|
||||
}
|
||||
bitfield->setUseBit(index);
|
||||
|
||||
Piece piece = findUsedPiece(index);
|
||||
if(Piece::isNull(piece)) {
|
||||
Piece piece(index, bitfield->getBlockLength(index));
|
||||
addUsedPiece(piece);
|
||||
return piece;
|
||||
} else {
|
||||
return piece;
|
||||
}
|
||||
}
|
||||
|
||||
int TorrentMan::deleteUsedPiecesByFillRate(int fillRate, int toDelete) {
|
||||
int deleted = 0;
|
||||
for(Pieces::iterator itr = usedPieces.begin();
|
||||
itr != usedPieces.end() && deleted < toDelete;) {
|
||||
Piece& piece = *itr;
|
||||
if(!bitfield->isUseBitSet(piece.getIndex()) &&
|
||||
piece.countCompleteBlock() <= piece.countBlock()*(fillRate/100.0)) {
|
||||
logger->debug("Deleting used piece index=%d, fillRate(%%)=%d<=%d",
|
||||
piece.getIndex(),
|
||||
(piece.countCompleteBlock()*100)/piece.countBlock(),
|
||||
fillRate);
|
||||
itr = usedPieces.erase(itr);
|
||||
deleted++;
|
||||
} else {
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
return deleted;
|
||||
}
|
||||
|
||||
void TorrentMan::reduceUsedPieces(int max) {
|
||||
int toDelete = usedPieces.size()-max;
|
||||
if(toDelete <= 0) {
|
||||
return;
|
||||
}
|
||||
int fillRate = 10;
|
||||
while(fillRate < 50) {
|
||||
int deleted = deleteUsedPiecesByFillRate(fillRate, toDelete);
|
||||
if(deleted == 0) {
|
||||
break;
|
||||
}
|
||||
toDelete -= deleted;
|
||||
fillRate += 10;
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::addUsedPiece(const Piece& piece) {
|
||||
// TODO ? if nullPiece
|
||||
usedPieces.push_back(piece);
|
||||
}
|
||||
|
||||
Piece TorrentMan::findUsedPiece(int index) const {
|
||||
for(Pieces::const_iterator itr = usedPieces.begin(); itr != usedPieces.end(); itr++) {
|
||||
const Piece& piece = *itr;
|
||||
if(piece.getIndex() == index) {
|
||||
return piece;
|
||||
}
|
||||
}
|
||||
return Piece::nullPiece;
|
||||
}
|
||||
|
||||
void TorrentMan::deleteUsedPiece(const Piece& piece) {
|
||||
if(Piece::isNull(piece)) {
|
||||
return;
|
||||
}
|
||||
Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), piece);
|
||||
if(itr != usedPieces.end()) {
|
||||
usedPieces.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::completePiece(const Piece& piece) {
|
||||
if(Piece::isNull(piece)) {
|
||||
return;
|
||||
}
|
||||
if(!hasPiece(piece.getIndex())) {
|
||||
addDownloadLength(piece.getLength());
|
||||
}
|
||||
deleteUsedPiece(piece);
|
||||
if(!isEndGame()) {
|
||||
reduceUsedPieces(100);
|
||||
}
|
||||
if(downloadComplete()) {
|
||||
return;
|
||||
}
|
||||
bitfield->setBit(piece.getIndex());
|
||||
bitfield->unsetUseBit(piece.getIndex());
|
||||
if(downloadComplete()) {
|
||||
onDownloadComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::cancelPiece(const Piece& piece) {
|
||||
if(Piece::isNull(piece)) {
|
||||
return;
|
||||
}
|
||||
updatePiece(piece);
|
||||
bitfield->unsetUseBit(piece.getIndex());
|
||||
if(!isEndGame()) {
|
||||
if(piece.countCompleteBlock() == 0) {
|
||||
deleteUsedPiece(piece);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::updatePiece(const Piece& piece) {
|
||||
if(Piece::isNull(piece)) {
|
||||
return;
|
||||
}
|
||||
Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(),
|
||||
piece);
|
||||
if(itr != usedPieces.end()) {
|
||||
*itr = piece;
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::syncPiece(Piece& piece) {
|
||||
if(Piece::isNull(piece)) {
|
||||
return;
|
||||
}
|
||||
Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(),
|
||||
piece);
|
||||
if(itr != usedPieces.end()) {
|
||||
piece = *itr;
|
||||
return;
|
||||
} else {
|
||||
// hasPiece(piece.getIndex()) is true, then set all bit of
|
||||
// piece.bitfield to 1
|
||||
if(hasPiece(piece.getIndex())) {
|
||||
piece.setAllBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::initBitfield() {
|
||||
if(bitfield != NULL) {
|
||||
delete bitfield;
|
||||
}
|
||||
bitfield = new BitfieldMan(pieceLength, totalLength);
|
||||
}
|
||||
|
||||
void TorrentMan::setBitfield(unsigned char* bitfield, int bitfieldLength) {
|
||||
if(this->bitfield == NULL) {
|
||||
initBitfield();
|
||||
}
|
||||
this->bitfield->setBitfield(bitfield, bitfieldLength);
|
||||
}
|
||||
|
||||
bool TorrentMan::downloadComplete() const {
|
||||
return bitfield->isAllBitSet();
|
||||
}
|
||||
|
||||
bool TorrentMan::hasAllPieces() const {
|
||||
return bitfield->getTotalLength() == downloadLength;
|
||||
}
|
||||
|
||||
void TorrentMan::readFileEntry(FileEntries& fileEntries, Directory** pTopDir, const Dictionary* infoDic, const string& defaultName) {
|
||||
Data* topName = (Data*)infoDic->get("name");
|
||||
if(topName != NULL) {
|
||||
name = topName->toString();
|
||||
} else {
|
||||
char* basec = strdup(defaultName.c_str());
|
||||
name = string(basename(basec))+".file";
|
||||
free(basec);
|
||||
}
|
||||
List* files = (List*)infoDic->get("files");
|
||||
if(files == NULL) {
|
||||
// single-file mode;
|
||||
setFileMode(SINGLE);
|
||||
Data* length = (Data*)infoDic->get("length");
|
||||
totalLength = length->toLLInt();
|
||||
FileEntry fileEntry(name, totalLength, 0);
|
||||
fileEntries.push_back(fileEntry);
|
||||
} else {
|
||||
long long int length = 0;
|
||||
long long int offset = 0;
|
||||
// multi-file mode
|
||||
setFileMode(MULTI);
|
||||
*pTopDir = new Directory(name);
|
||||
const MetaList& metaList = files->getList();
|
||||
for(MetaList::const_iterator itr = metaList.begin(); itr != metaList.end();
|
||||
itr++) {
|
||||
Dictionary* fileDic = (Dictionary*)(*itr);
|
||||
Data* lengthData = (Data*)fileDic->get("length");
|
||||
length += lengthData->toLLInt();
|
||||
List* path = (List*)fileDic->get("path");
|
||||
const MetaList& paths = path->getList();
|
||||
Directory* parentDir = *pTopDir;
|
||||
string filePath = name;
|
||||
for(int i = 0; i < (int)paths.size()-1; i++) {
|
||||
Data* subpath = (Data*)paths.at(i);
|
||||
Directory* dir = new Directory(subpath->toString());
|
||||
parentDir->addFile(dir);
|
||||
parentDir = dir;
|
||||
filePath.append("/").append(subpath->toString());
|
||||
}
|
||||
Data* lastpath = (Data*)paths.back();
|
||||
filePath.append("/").append(lastpath->toString());
|
||||
FileEntry fileEntry(filePath, lengthData->toLLInt(), offset);
|
||||
fileEntries.push_back(fileEntry);
|
||||
offset += fileEntry.length;
|
||||
}
|
||||
totalLength = length;
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::setupInternal1(const string& metaInfoFile) {
|
||||
peerId = "-aria2-";
|
||||
peerId += Util::randomAlpha(20-peerId.size());
|
||||
key = Util::randomAlpha(8);
|
||||
|
||||
uploadLength = 0;
|
||||
downloadLength = 0;
|
||||
Dictionary* topDic = (Dictionary*)MetaFileUtil::parseMetaFile(metaInfoFile);
|
||||
const Dictionary* infoDic = (const Dictionary*)topDic->get("info");
|
||||
ShaVisitor v;
|
||||
infoDic->accept(&v);
|
||||
unsigned char md[20];
|
||||
int len;
|
||||
v.getHash(md, len);
|
||||
setInfoHash(md);
|
||||
|
||||
FileEntries fileEntries;
|
||||
Directory* topDir = NULL;
|
||||
readFileEntry(fileEntries, &topDir, infoDic, metaInfoFile);
|
||||
|
||||
string announce = ((Data*)topDic->get("announce"))->toString();
|
||||
const MetaEntry* announces = topDic->get("announce-list");
|
||||
if(announces) {
|
||||
announceList.reconfigure(announces);
|
||||
announceList.shuffle();
|
||||
}
|
||||
if(!announceList.countTier()) {
|
||||
announceList.reconfigure(announce);
|
||||
}
|
||||
pieceLength = ((Data*)infoDic->get("piece length"))->toInt();
|
||||
pieces = totalLength/pieceLength+(totalLength%pieceLength ? 1 : 0);
|
||||
Data* piecesHashData = (Data*)infoDic->get("pieces");
|
||||
if(piecesHashData->getLen() != pieces*20) {
|
||||
throw new DlAbortEx("The number of pieces is wrong.");
|
||||
}
|
||||
for(int index = 0; index < pieces; index++) {
|
||||
string hex = Util::toHex((unsigned char*)&piecesHashData->getData()[index*20], 20);
|
||||
pieceHashes.push_back(hex);
|
||||
logger->debug("piece #%d, hash:%s", index, hex.c_str());
|
||||
}
|
||||
|
||||
initBitfield();
|
||||
delete topDic;
|
||||
|
||||
if(option->get(PREF_DIRECT_FILE_MAPPING) == V_TRUE) {
|
||||
if(fileMode == SINGLE) {
|
||||
diskAdaptor = new DirectDiskAdaptor(new DefaultDiskWriter(totalLength));
|
||||
} else {
|
||||
diskAdaptor = new MultiDiskAdaptor(new MultiDiskWriter(pieceLength));
|
||||
}
|
||||
} else {
|
||||
diskAdaptor = new CopyDiskAdaptor(new PreAllocationDiskWriter(totalLength));
|
||||
((CopyDiskAdaptor*)diskAdaptor)->setTempFilename(name+".a2tmp");
|
||||
}
|
||||
diskAdaptor->setStoreDir(storeDir);
|
||||
diskAdaptor->setTopDir(topDir);
|
||||
diskAdaptor->setFileEntries(fileEntries);
|
||||
}
|
||||
|
||||
void TorrentMan::setupInternal2() {
|
||||
if(segmentFileExists()) {
|
||||
load();
|
||||
diskAdaptor->openExistingFile();
|
||||
} else {
|
||||
diskAdaptor->initAndOpenFile();
|
||||
}
|
||||
setupComplete = true;
|
||||
}
|
||||
|
||||
void TorrentMan::setup(const string& metaInfoFile, const Integers& targetFileIndexes) {
|
||||
setupInternal1(metaInfoFile);
|
||||
Strings targetFilePaths;
|
||||
const FileEntries& entries = diskAdaptor->getFileEntries();
|
||||
for(int i = 0; i < (int)entries.size(); i++) {
|
||||
if(find(targetFileIndexes.begin(), targetFileIndexes.end(), i+1) != targetFileIndexes.end()) {
|
||||
logger->debug("index=%d is %s", i+1, entries.at(i).path.c_str());
|
||||
targetFilePaths.push_back(entries.at(i).path);
|
||||
}
|
||||
}
|
||||
setFileFilter(targetFilePaths);
|
||||
setupInternal2();
|
||||
}
|
||||
|
||||
void TorrentMan::setup(const string& metaInfoFile, const Strings& targetFilePaths) {
|
||||
setupInternal1(metaInfoFile);
|
||||
setFileFilter(targetFilePaths);
|
||||
setupInternal2();
|
||||
}
|
||||
|
||||
void TorrentMan::setFileFilter(const Strings& filePaths) {
|
||||
if(fileMode != MULTI || filePaths.empty()) {
|
||||
return;
|
||||
}
|
||||
diskAdaptor->removeAllDownloadEntry();
|
||||
for(Strings::const_iterator pitr = filePaths.begin();
|
||||
pitr != filePaths.end(); pitr++) {
|
||||
if(!diskAdaptor->addDownloadEntry(*pitr)) {
|
||||
throw new DlAbortEx("No such file entry %s", (*pitr).c_str());
|
||||
}
|
||||
FileEntry fileEntry = diskAdaptor->getFileEntryFromPath(*pitr);
|
||||
bitfield->addFilter(fileEntry.offset, fileEntry.length);
|
||||
}
|
||||
bitfield->enableFilter();
|
||||
}
|
||||
|
||||
FileEntries TorrentMan::readFileEntryFromMetaInfoFile(const string& metaInfoFile) {
|
||||
Dictionary* topDic = (Dictionary*)MetaFileUtil::parseMetaFile(metaInfoFile);
|
||||
const Dictionary* infoDic = (const Dictionary*)topDic->get("info");
|
||||
FileEntries fileEntries;
|
||||
Directory* topDir = NULL;
|
||||
readFileEntry(fileEntries, &topDir, infoDic, metaInfoFile);
|
||||
if(topDir != NULL) {
|
||||
delete topDir;
|
||||
}
|
||||
return fileEntries;
|
||||
}
|
||||
|
||||
string TorrentMan::getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
bool TorrentMan::hasPiece(int index) const {
|
||||
return bitfield->isBitSet(index);
|
||||
}
|
||||
|
||||
string TorrentMan::getPieceHash(int index) const {
|
||||
return pieceHashes.at(index);
|
||||
}
|
||||
|
||||
string TorrentMan::getSegmentFilePath() const {
|
||||
return storeDir+"/"+name+".aria2";
|
||||
}
|
||||
|
||||
bool TorrentMan::segmentFileExists() const {
|
||||
string segFilename = getSegmentFilePath();
|
||||
File f(segFilename);
|
||||
if(f.isFile()) {
|
||||
logger->info(MSG_SEGMENT_FILE_EXISTS, segFilename.c_str());
|
||||
return true;
|
||||
} else {
|
||||
logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, segFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FILE* TorrentMan::openSegFile(const string& segFilename, const string& mode) const {
|
||||
FILE* segFile = fopen(segFilename.c_str(), mode.c_str());
|
||||
if(segFile == NULL) {
|
||||
throw new DlAbortEx(EX_SEGMENT_FILE_OPEN,
|
||||
segFilename.c_str(), strerror(errno));
|
||||
}
|
||||
return segFile;
|
||||
}
|
||||
|
||||
void TorrentMan::load() {
|
||||
string segFilename = getSegmentFilePath();
|
||||
logger->info(MSG_LOADING_SEGMENT_FILE, segFilename.c_str());
|
||||
FILE* segFile = openSegFile(segFilename, "r+");
|
||||
try {
|
||||
read(segFile);
|
||||
fclose(segFile);
|
||||
} catch(string ex) {
|
||||
fclose(segFile);
|
||||
throw new DlAbortEx(EX_SEGMENT_FILE_READ,
|
||||
segFilename.c_str(), strerror(errno));
|
||||
}
|
||||
logger->info(MSG_LOADED_SEGMENT_FILE);
|
||||
}
|
||||
|
||||
void TorrentMan::read(FILE* file) {
|
||||
assert(file != NULL);
|
||||
unsigned char savedInfoHash[INFO_HASH_LENGTH];
|
||||
if(fread(savedInfoHash, INFO_HASH_LENGTH, 1, file) < 1) {
|
||||
throw string("readError");
|
||||
}
|
||||
if(Util::toHex(savedInfoHash, INFO_HASH_LENGTH) != Util::toHex(infoHash, INFO_HASH_LENGTH)) {
|
||||
throw new DlAbortEx("Incorrect infoHash.");
|
||||
}
|
||||
unsigned char* savedBitfield = new unsigned char[bitfield->getBitfieldLength()];
|
||||
try {
|
||||
if(fread(savedBitfield, bitfield->getBitfieldLength(), 1, file) < 1) {
|
||||
throw string("readError");
|
||||
}
|
||||
setBitfield(savedBitfield, bitfield->getBitfieldLength());
|
||||
if(fread(&downloadLength, sizeof(downloadLength), 1, file) < 1) {
|
||||
throw string("readError");
|
||||
}
|
||||
if(fread(&uploadLength, sizeof(uploadLength), 1, file) < 1) {
|
||||
throw string("readError");
|
||||
}
|
||||
preDownloadLength = downloadLength;
|
||||
preUploadLength = uploadLength;
|
||||
delete [] savedBitfield;
|
||||
} catch(...) {
|
||||
delete [] savedBitfield;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::save() const {
|
||||
if(!setupComplete) {
|
||||
return;
|
||||
}
|
||||
string segFilename = getSegmentFilePath();
|
||||
logger->info(MSG_SAVING_SEGMENT_FILE, segFilename.c_str());
|
||||
FILE* file = openSegFile(segFilename, "w");
|
||||
try {
|
||||
if(fwrite(infoHash, INFO_HASH_LENGTH, 1, file) < 1) {
|
||||
throw string("writeError");
|
||||
}
|
||||
if(fwrite(bitfield->getBitfield(), bitfield->getBitfieldLength(), 1, file) < 1) {
|
||||
throw string("writeError");
|
||||
}
|
||||
if(fwrite(&downloadLength, sizeof(downloadLength), 1, file) < 1) {
|
||||
throw string("writeError");
|
||||
}
|
||||
if(fwrite(&uploadLength, sizeof(uploadLength), 1, file) < 1) {
|
||||
throw string("writeError");
|
||||
}
|
||||
fclose(file);
|
||||
logger->info(MSG_SAVED_SEGMENT_FILE);
|
||||
} catch(string ex) {
|
||||
fclose(file);
|
||||
throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
|
||||
segFilename.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::remove() const {
|
||||
if(segmentFileExists()) {
|
||||
File f(getSegmentFilePath());
|
||||
f.remove();
|
||||
}
|
||||
}
|
||||
|
||||
bool TorrentMan::isSelectiveDownloadingMode() const {
|
||||
return bitfield->isFilterEnabled();
|
||||
}
|
||||
|
||||
void TorrentMan::finishSelectiveDownloadingMode() {
|
||||
bitfield->clearFilter();
|
||||
diskAdaptor->addAllDownloadEntry();
|
||||
}
|
||||
|
||||
long long int TorrentMan::getCompletedLength() const {
|
||||
return bitfield->getCompletedLength();
|
||||
}
|
||||
|
||||
long long int TorrentMan::getSelectedTotalLength() const {
|
||||
return bitfield->getFilteredTotalLength();
|
||||
}
|
||||
|
||||
void TorrentMan::onDownloadComplete() {
|
||||
save();
|
||||
diskAdaptor->onDownloadComplete();
|
||||
if(isSelectiveDownloadingMode()) {
|
||||
logger->notice(_("Download of selected files was complete."));
|
||||
finishSelectiveDownloadingMode();
|
||||
} else {
|
||||
logger->info(_("The download was complete."));
|
||||
}
|
||||
}
|
||||
|
||||
void TorrentMan::advertisePiece(int cuid, int index) {
|
||||
HaveEntry entry(cuid, index);
|
||||
haves.push_front(entry);
|
||||
};
|
||||
|
||||
PieceIndexes
|
||||
TorrentMan::getAdvertisedPieceIndexes(int myCuid,
|
||||
const Time& lastCheckTime
|
||||
) const
|
||||
{
|
||||
PieceIndexes indexes;
|
||||
for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) {
|
||||
const Haves::value_type& have = *itr;
|
||||
if(have.cuid == myCuid) {
|
||||
continue;
|
||||
}
|
||||
if(lastCheckTime.isNewer(have.registeredTime)) {
|
||||
break;
|
||||
}
|
||||
indexes.push_back(have.index);
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
|
||||
class FindElapsedHave
|
||||
{
|
||||
private:
|
||||
int elapsed;
|
||||
public:
|
||||
FindElapsedHave(int elapsed):elapsed(elapsed) {}
|
||||
|
||||
bool operator()(const HaveEntry& have) {
|
||||
if(have.registeredTime.elapsed(elapsed)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
TorrentMan::removeAdvertisedPiece(int elapsed)
|
||||
{
|
||||
Haves::iterator itr = find_if(haves.begin(), haves.end(), FindElapsedHave(elapsed));
|
||||
if(itr != haves.end()) {
|
||||
logger->debug("Removed %d have entries.", haves.end()-itr);
|
||||
haves.erase(itr, haves.end());
|
||||
}
|
||||
}
|
||||
|
||||
TransferStat TorrentMan::calculateStat() {
|
||||
TransferStat stat;
|
||||
for(Peers::iterator itr = activePeers.begin();
|
||||
itr != activePeers.end(); itr++) {
|
||||
PeerHandle& peer = *itr;
|
||||
stat.downloadSpeed += peer->calculateDownloadSpeed();
|
||||
stat.uploadSpeed += peer->calculateUploadSpeed();
|
||||
stat.sessionDownloadLength += peer->getSessionDownloadLength();
|
||||
stat.sessionUploadLength += peer->getSessionUploadLength();
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
bool TorrentMan::isStoppedAnnounceReady() const {
|
||||
return (trackers == 0 &&
|
||||
isHalt() &&
|
||||
announceList.countStoppedAllowedTier());
|
||||
}
|
||||
|
||||
bool TorrentMan::isCompletedAnnounceReady() const {
|
||||
return (trackers == 0 &&
|
||||
downloadComplete() &&
|
||||
announceList.countCompletedAllowedTier());
|
||||
}
|
||||
|
||||
bool TorrentMan::isDefaultAnnounceReady() const {
|
||||
return (trackers == 0 &&
|
||||
announceInterval.elapsed(minInterval));
|
||||
}
|
||||
|
||||
bool TorrentMan::isAnnounceReady() const {
|
||||
return
|
||||
isStoppedAnnounceReady() ||
|
||||
isCompletedAnnounceReady() ||
|
||||
isDefaultAnnounceReady();
|
||||
}
|
||||
|
||||
string TorrentMan::getAnnounceUrl() {
|
||||
if(isStoppedAnnounceReady()) {
|
||||
announceList.moveToStoppedAllowedTier();
|
||||
announceList.setEvent(AnnounceTier::STOPPED);
|
||||
} else if(isCompletedAnnounceReady()) {
|
||||
announceList.moveToCompletedAllowedTier();
|
||||
announceList.setEvent(AnnounceTier::COMPLETED);
|
||||
} else if(isDefaultAnnounceReady()) {
|
||||
// If download completed before "started" event is sent to a tracker,
|
||||
// we change the event to something else to prevent us from
|
||||
// sending "completed" event.
|
||||
if(downloadComplete() &&
|
||||
announceList.getEvent() == AnnounceTier::STARTED) {
|
||||
announceList.setEvent(AnnounceTier::STARTED_AFTER_COMPLETION);
|
||||
}
|
||||
}
|
||||
int numWant = 50;
|
||||
if(connections >= MIN_PEERS || isHalt()) {
|
||||
numWant = 0;
|
||||
}
|
||||
string url = announceList.getAnnounce()+"?"+
|
||||
"info_hash="+Util::torrentUrlencode(getInfoHash(), 20)+"&"+
|
||||
"peer_id="+peerId+"&"+
|
||||
"port="+Util::itos(getPort())+"&"+
|
||||
"uploaded="+Util::llitos(getSessionUploadLength())+"&"+
|
||||
"downloaded="+Util::llitos(getSessionDownloadLength())+"&"+
|
||||
"left="+(getTotalLength()-getDownloadLength() <= 0
|
||||
? "0" : Util::llitos(getTotalLength()-getDownloadLength()))+"&"+
|
||||
"compact=1"+"&"+
|
||||
"key="+key+"&"+
|
||||
"numwant="+Util::itos(numWant)+"&"+
|
||||
"no_peer_id=1";
|
||||
string event = announceList.getEventString();
|
||||
if(!event.empty()) {
|
||||
url += string("&")+"event="+event;
|
||||
}
|
||||
if(!trackerId.empty()) {
|
||||
url += string("&")+"trackerid="+trackerId;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
void TorrentMan::announceStart() {
|
||||
trackers++;
|
||||
}
|
||||
|
||||
void TorrentMan::announceFailure() {
|
||||
trackers = 0;
|
||||
trackerNumTry++;
|
||||
announceList.announceFailure();
|
||||
}
|
||||
|
||||
void TorrentMan::announceSuccess() {
|
||||
trackers = 0;
|
||||
announceList.announceSuccess();
|
||||
}
|
||||
|
||||
bool TorrentMan::isAllAnnounceFailed() const {
|
||||
return
|
||||
trackerNumTry >= option->getAsInt(PREF_TRACKER_MAX_TRIES);
|
||||
}
|
||||
|
||||
void TorrentMan::resetAnnounce() {
|
||||
announceInterval.reset();
|
||||
trackerNumTry = 0;
|
||||
}
|
||||
|
||||
void TorrentMan::processAnnounceResponse(const char* trackerResponse,
|
||||
size_t trackerResponseLength) {
|
||||
SharedHandle<MetaEntry> entry(MetaFileUtil::bdecoding(trackerResponse,
|
||||
trackerResponseLength));
|
||||
Dictionary* response = (Dictionary*)entry.get();
|
||||
Data* failureReasonData = (Data*)response->get("failure reason");
|
||||
if(failureReasonData) {
|
||||
throw new DlAbortEx("Tracker returned failure reason: %s",
|
||||
failureReasonData->toString().c_str());
|
||||
}
|
||||
Data* warningMessageData = (Data*)response->get("warning message");
|
||||
if(warningMessageData) {
|
||||
logger->warn(MSG_TRACKER_WARNING_MESSAGE,
|
||||
warningMessageData->toString().c_str());
|
||||
}
|
||||
Data* trackerIdData = (Data*)response->get("tracker id");
|
||||
if(trackerIdData) {
|
||||
trackerId = trackerIdData->toString();
|
||||
logger->debug("Tracker ID:%s", trackerId.c_str());
|
||||
}
|
||||
Data* intervalData = (Data*)response->get("interval");
|
||||
if(intervalData) {
|
||||
interval = intervalData->toInt();
|
||||
logger->debug("Interval:%d", interval);
|
||||
}
|
||||
Data* minIntervalData = (Data*)response->get("min interval");
|
||||
if(minIntervalData) {
|
||||
minInterval = minIntervalData->toInt();
|
||||
logger->debug("Min interval:%d", minInterval);
|
||||
}
|
||||
if(minInterval > interval) {
|
||||
minInterval = interval;
|
||||
}
|
||||
Data* completeData = (Data*)response->get("complete");
|
||||
if(completeData) {
|
||||
complete = completeData->toInt();
|
||||
logger->debug("Complete:%d", complete);
|
||||
}
|
||||
Data* incompleteData = (Data*)response->get("incomplete");
|
||||
if(incompleteData) {
|
||||
incomplete = incompleteData->toInt();
|
||||
logger->debug("Incomplete:%d", incomplete);
|
||||
}
|
||||
const MetaEntry* peersEntry = response->get("peers");
|
||||
if(peersEntry && !isHalt() && connections < MIN_PEERS) {
|
||||
DelegatingPeerListProcessor proc(pieceLength, getTotalLength());
|
||||
Peers peers = proc.extractPeer(peersEntry);
|
||||
addPeer(peers);
|
||||
}
|
||||
if(!peersEntry) {
|
||||
logger->info("No peer list received.");
|
||||
}
|
||||
}
|
||||
|
||||
bool TorrentMan::needMorePeerConnection() const {
|
||||
return isPeerAvailable() && connections < MIN_PEERS;
|
||||
}
|
||||
|
||||
bool TorrentMan::noMoreAnnounce() const {
|
||||
return (trackers == 0 &&
|
||||
isHalt() &&
|
||||
!announceList.countStoppedAllowedTier());
|
||||
}
|
326
src/TorrentMan.h
326
src/TorrentMan.h
|
@ -1,326 +0,0 @@
|
|||
/* <!-- copyright */
|
||||
/*
|
||||
* aria2 - The high speed download utility
|
||||
*
|
||||
* Copyright (C) 2006 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* In addition, as a special exception, the copyright holders give
|
||||
* permission to link the code of portions of this program with the
|
||||
* OpenSSL library under certain conditions as described in each
|
||||
* individual source file, and distribute linked combinations
|
||||
* including the two.
|
||||
* You must obey the GNU General Public License in all respects
|
||||
* for all of the code used other than OpenSSL. If you modify
|
||||
* file(s) with this exception, you may extend this exception to your
|
||||
* version of the file(s), but you are not obligated to do so. If you
|
||||
* do not wish to do so, delete this exception statement from your
|
||||
* version. If you delete this exception statement from all source
|
||||
* files in the program, then also delete it here.
|
||||
*/
|
||||
/* copyright --> */
|
||||
#ifndef _D_TORRENT_MAN_H_
|
||||
#define _D_TORRENT_MAN_H_
|
||||
|
||||
#include "Peer.h"
|
||||
#include "common.h"
|
||||
#include "Logger.h"
|
||||
#include "BitfieldMan.h"
|
||||
#include "DiskWriter.h"
|
||||
#include "Piece.h"
|
||||
#include "Dictionary.h"
|
||||
#include "Option.h"
|
||||
#include "FileEntry.h"
|
||||
#include "DiskAdaptor.h"
|
||||
#include "AnnounceList.h"
|
||||
#include "TimeA2.h"
|
||||
#include "PeerListProcessor.h"
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define INFO_HASH_LENGTH 20
|
||||
#define PEER_ID_LENGTH 20
|
||||
#define DEFAULT_ANNOUNCE_INTERVAL 1800
|
||||
#define DEFAULT_ANNOUNCE_MIN_INTERVAL 1800
|
||||
#define MAX_PEERS 55
|
||||
#define MIN_PEERS 15
|
||||
#define MAX_PEER_LIST_SIZE 100
|
||||
#define END_GAME_PIECE_NUM 20
|
||||
#define MAX_PEER_ERROR 5
|
||||
|
||||
class TransferStat {
|
||||
public:
|
||||
int downloadSpeed;
|
||||
int uploadSpeed;
|
||||
long long int sessionDownloadLength;
|
||||
long long int sessionUploadLength;
|
||||
public:
|
||||
TransferStat():downloadSpeed(0), uploadSpeed(0),
|
||||
sessionDownloadLength(0), sessionUploadLength(0) {}
|
||||
};
|
||||
|
||||
class HaveEntry {
|
||||
public:
|
||||
int cuid;
|
||||
int index;
|
||||
Time registeredTime;
|
||||
HaveEntry(int cuid, int index):
|
||||
cuid(cuid),
|
||||
index(index) {}
|
||||
};
|
||||
|
||||
typedef deque<HaveEntry> Haves;
|
||||
typedef deque<int> PieceIndexes;
|
||||
typedef deque<Piece> Pieces;
|
||||
|
||||
class TorrentMan {
|
||||
private:
|
||||
Peers peers;
|
||||
BitfieldMan* bitfield;
|
||||
unsigned char infoHash[INFO_HASH_LENGTH];
|
||||
deque<string> pieceHashes;
|
||||
int peerEntryIdCounter;
|
||||
int cuidCounter;
|
||||
long long int totalLength;
|
||||
long long int downloadLength;
|
||||
long long int uploadLength;
|
||||
long long int preDownloadLength;
|
||||
long long int preUploadLength;
|
||||
int fileMode;
|
||||
string storeDir;
|
||||
int port;
|
||||
Haves haves;
|
||||
Pieces usedPieces;
|
||||
bool setupComplete;
|
||||
const Logger* logger;
|
||||
Peers activePeers;
|
||||
bool halt;
|
||||
|
||||
FILE* openSegFile(const string& segFilename, const string& mode) const;
|
||||
void read(FILE* file);
|
||||
|
||||
Piece findUsedPiece(int index) const;
|
||||
void addUsedPiece(const Piece& piece);
|
||||
void deleteUsedPiece(const Piece& piece);
|
||||
int deleteUsedPiecesByFillRate(int fillRate, int toDelete);
|
||||
void reduceUsedPieces(int max);
|
||||
void readFileEntry(FileEntries& fileEntries, Directory** pTopDir, const Dictionary* infoDic, const string& defaultName);
|
||||
void setFileFilter(const Strings& filePaths);
|
||||
void setupInternal1(const string& metaInfoFile);
|
||||
void setupInternal2();
|
||||
Piece checkOutPiece(int index);
|
||||
bool isStoppedAnnounceReady() const;
|
||||
bool isCompletedAnnounceReady() const;
|
||||
bool isDefaultAnnounceReady() const;
|
||||
|
||||
public:
|
||||
int pieceLength;
|
||||
int pieces;
|
||||
// TODO type char* would be better
|
||||
string peerId;
|
||||
string key;
|
||||
string announce;
|
||||
string trackerId;
|
||||
string name;
|
||||
int interval;
|
||||
int minInterval;
|
||||
int complete;
|
||||
int incomplete;
|
||||
int connections;
|
||||
// The number of tracker request command currently in the command queue.
|
||||
int trackers;
|
||||
int trackerNumTry;
|
||||
Time announceInterval;
|
||||
// tracker request
|
||||
AnnounceList announceList;
|
||||
public:
|
||||
TorrentMan();
|
||||
~TorrentMan();
|
||||
|
||||
DiskAdaptor* diskAdaptor;
|
||||
const Option* option;
|
||||
|
||||
int getNewCuid() { return ++cuidCounter; }
|
||||
|
||||
// TODO do not use this method
|
||||
void updatePeers(const Peers& peers);
|
||||
bool addPeer(const PeerHandle& peer);
|
||||
void addPeer(const Peers& peers);
|
||||
//void updatePeer(const Peer* peer);
|
||||
const Peers& getPeers() const { return peers; }
|
||||
PeerHandle getPeer() const;
|
||||
bool isPeerAvailable() const;
|
||||
void deleteUnusedPeer(int delSize);
|
||||
|
||||
bool hasMissingPiece(const PeerHandle& peer) const;
|
||||
int getMissingPieceIndex(const PeerHandle& peer) const;
|
||||
int getMissingFastPieceIndex(const PeerHandle& peer) const;
|
||||
Piece getMissingPiece(const PeerHandle& peer);
|
||||
Piece getMissingFastPiece(const PeerHandle& peer);
|
||||
void completePiece(const Piece& piece);
|
||||
void cancelPiece(const Piece& piece);
|
||||
void updatePiece(const Piece& piece);
|
||||
void syncPiece(Piece& piece);
|
||||
bool hasPiece(int index) const;
|
||||
void initBitfield();
|
||||
/**
|
||||
* Returns true if the number of missing block is less than or equal to
|
||||
* END_GAME_PIECE_NUM.
|
||||
* If file filter is enabled, only a range specified by the filter is
|
||||
* concerned.
|
||||
*/
|
||||
bool isEndGame() const;
|
||||
/**
|
||||
* Returns true if download has completed. If file filter is enabled,
|
||||
* returns true if download of a range specified by the filter has completed.
|
||||
*/
|
||||
bool downloadComplete() const;
|
||||
bool hasAllPieces() const;
|
||||
void setBitfield(unsigned char* bitfield, int len);
|
||||
const unsigned char* getBitfield() const {
|
||||
return bitfield->getBitfield();
|
||||
}
|
||||
int getBitfieldLength() const { return bitfield->getBitfieldLength(); }
|
||||
int getPieceLength(int index) const {
|
||||
return bitfield->getBlockLength(index);
|
||||
}
|
||||
int getPieceLength() const { return bitfield->getBlockLength(); }
|
||||
|
||||
void setInfoHash(const unsigned char* infoHash) {
|
||||
memcpy(this->infoHash, infoHash, INFO_HASH_LENGTH);
|
||||
}
|
||||
const unsigned char* getInfoHash() const {
|
||||
return infoHash;
|
||||
}
|
||||
|
||||
void setup(const string& metaInfoFile, const Strings& targetFilePaths);
|
||||
void setup(const string& metaInfoFile, const Integers& targetFileIndexes);
|
||||
|
||||
string getPieceHash(int index) const;
|
||||
|
||||
// Adds piece index to advertise to other commands. They send have message
|
||||
// based on this information.
|
||||
void advertisePiece(int cuid, int index);
|
||||
|
||||
// Returns piece index which is not advertised by the caller command and
|
||||
// newer than lastCheckTime.
|
||||
PieceIndexes getAdvertisedPieceIndexes(int myCuid, const Time& lastCheckTime) const;
|
||||
// Removes have entry if specified seconds have elapsed since its registration.
|
||||
void removeAdvertisedPiece(int elapsed);
|
||||
|
||||
long long int getTotalLength() const { return totalLength; }
|
||||
void setTotalLength(long long int length) { totalLength = length; }
|
||||
|
||||
void addDownloadLength(int deltaLength) { downloadLength += deltaLength; }
|
||||
long long int getDownloadLength() const { return downloadLength; }
|
||||
void setDownloadLength(long long int length) { downloadLength = length; }
|
||||
|
||||
void addUploadLength(int deltaLength) { uploadLength += deltaLength; }
|
||||
long long int getUploadLength() const { return uploadLength; }
|
||||
void setUploadLength(long long int length) { uploadLength = length; }
|
||||
|
||||
long long int getSessionDownloadLength() const {
|
||||
return downloadLength-preDownloadLength;
|
||||
}
|
||||
long long int getSessionUploadLength() const {
|
||||
return uploadLength-preUploadLength;
|
||||
}
|
||||
|
||||
void setFileMode(int mode) {
|
||||
fileMode = mode;
|
||||
}
|
||||
|
||||
int getFileMode() const {
|
||||
return fileMode;
|
||||
}
|
||||
|
||||
string getStoreDir() const { return storeDir; }
|
||||
void setStoreDir(const string& dir) { storeDir = dir; }
|
||||
|
||||
string getSegmentFilePath() const;
|
||||
|
||||
bool segmentFileExists() const;
|
||||
void load();
|
||||
void save() const;
|
||||
void remove() const;
|
||||
|
||||
void copySingleFile() const;
|
||||
void splitMultiFile();
|
||||
void fixFilename();
|
||||
void deleteTempFile() const;
|
||||
|
||||
void setPort(int port) { this->port = port; }
|
||||
int getPort() const { return port; }
|
||||
|
||||
int countUsedPiece() const { return usedPieces.size(); }
|
||||
int countAdvertisedPiece() const { return haves.size(); }
|
||||
|
||||
FileEntries readFileEntryFromMetaInfoFile(const string& metaInfoFile);
|
||||
string getName() const;
|
||||
|
||||
void finishSelectiveDownloadingMode();
|
||||
bool isSelectiveDownloadingMode() const;
|
||||
|
||||
long long int getCompletedLength() const;
|
||||
long long int getSelectedTotalLength() const;
|
||||
|
||||
void onDownloadComplete();
|
||||
|
||||
void addActivePeer(const PeerHandle& peer) {
|
||||
peer->activate();
|
||||
activePeers.push_back(peer);
|
||||
}
|
||||
|
||||
Peers& getActivePeers() { return this->activePeers; }
|
||||
|
||||
void deleteActivePeer(const PeerHandle& peer) {
|
||||
Peers::iterator itr = find(activePeers.begin(), activePeers.end(), peer);
|
||||
if(itr != activePeers.end()) {
|
||||
peer->deactivate();
|
||||
activePeers.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
bool isHalt() const { return halt; }
|
||||
void setHalt(bool halt) {
|
||||
this->halt = halt;
|
||||
}
|
||||
// announce related methods.
|
||||
bool isAnnounceReady() const;
|
||||
string getAnnounceUrl();
|
||||
void announceStart();
|
||||
void announceSuccess();
|
||||
void announceFailure();
|
||||
bool isAllAnnounceFailed() const;
|
||||
void resetAnnounce();
|
||||
void processAnnounceResponse(const char* trackerResponse,
|
||||
size_t trackerResponseLength);
|
||||
bool needMorePeerConnection() const;
|
||||
bool noMoreAnnounce() const;
|
||||
|
||||
enum FILE_MODE {
|
||||
SINGLE,
|
||||
MULTI
|
||||
};
|
||||
|
||||
TransferStat calculateStat();
|
||||
};
|
||||
|
||||
#endif // _D_TORRENT_MAN_H_
|
Loading…
Reference in New Issue