summaryrefslogtreecommitdiff
path: root/src/DefaultBtProgressInfoFile.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/DefaultBtProgressInfoFile.cc')
-rw-r--r--src/DefaultBtProgressInfoFile.cc291
1 files changed, 198 insertions, 93 deletions
diff --git a/src/DefaultBtProgressInfoFile.cc b/src/DefaultBtProgressInfoFile.cc
index 7c0c9a77..955d11bb 100644
--- a/src/DefaultBtProgressInfoFile.cc
+++ b/src/DefaultBtProgressInfoFile.cc
@@ -33,6 +33,9 @@
*/
/* copyright --> */
#include "DefaultBtProgressInfoFile.h"
+#include "DownloadContext.h"
+#include "PieceStorage.h"
+#include "Option.h"
#include "BtRegistry.h"
#include "LogFactory.h"
#include "prefs.h"
@@ -41,143 +44,245 @@
#include "File.h"
#include "Util.h"
#include "a2io.h"
+#include <fstream>
#include <errno.h>
-DefaultBtProgressInfoFile::DefaultBtProgressInfoFile(const BtContextHandle& btContext,
+DefaultBtProgressInfoFile::DefaultBtProgressInfoFile(const DownloadContextHandle& dctx,
+ const PieceStorageHandle& pieceStorage,
const Option* option):
- btContext(btContext),
- option(option),
- pieceStorage(PIECE_STORAGE(btContext)),
- btRuntime(BT_RUNTIME(btContext)),
- peerStorage(PEER_STORAGE(btContext))
+ _dctx(dctx),
+ _pieceStorage(pieceStorage),
+ _option(option),
+ _logger(LogFactory::getInstance())
{
- logger = LogFactory::getInstance();
- string storeDir = option->get(PREF_DIR);
- filename = storeDir+"/"+btContext->getName()+".aria2";
+ _filename = _dctx->getActualBasePath()+".aria2";
}
DefaultBtProgressInfoFile::~DefaultBtProgressInfoFile() {}
+bool DefaultBtProgressInfoFile::isTorrentDownload()
+{
+ return !BtContextHandle(_dctx).isNull();
+}
+
void DefaultBtProgressInfoFile::save() {
- logger->info(MSG_SAVING_SEGMENT_FILE, filename.c_str());
- string filenameTemp = filename+"__temp";
- FILE* file = openFile(filenameTemp, "wb");
+ _logger->info(MSG_SAVING_SEGMENT_FILE, _filename.c_str());
+ string filenameTemp = _filename+"__temp";
+ ofstream o(filenameTemp.c_str(), ios::out|ios::binary);
+ o.exceptions(ios::failbit);
try {
- if(fwrite(btContext->getInfoHash(),
- btContext->getInfoHashLength(), 1, file) < 1) {
- throw string("writeError:info hash");
+ bool torrentDownload = isTorrentDownload();
+ // file version: 16 bits
+ // value: '0'
+ int16_t version = 0;
+ o.write(reinterpret_cast<const char*>(&version), sizeof(int16_t));
+ // extension: 32 bits
+ // If this is BitTorrent download, then 0x00000001
+ // Otherwise, 0x00000000
+ char extension[4];
+ memset(extension, 0, sizeof(extension));
+ if(torrentDownload) {
+ extension[3] = 1;
}
- if(fwrite(pieceStorage->getBitfield(),
- pieceStorage->getBitfieldLength(), 1, file) < 1) {
- throw string("writeError:bitfield");
+ o.write(reinterpret_cast<const char*>(&extension), sizeof(extension));
+ if(torrentDownload) {
+ // infoHashLength:
+ // length: 32 bits
+ BtContextHandle btContext = _dctx;
+ int32_t infoHashLength = btContext->getInfoHashLength();
+ o.write(reinterpret_cast<const char*>(&infoHashLength), sizeof(int32_t));
+ // infoHash:
+ o.write(reinterpret_cast<const char*>(btContext->getInfoHash()),
+ btContext->getInfoHashLength());
+ } else {
+ // infoHashLength:
+ // length: 32 bits
+ int32_t infoHashLength = 0;
+ o.write(reinterpret_cast<const char*>(&infoHashLength), sizeof(int32_t));
}
- TransferStat stat = peerStorage->calculateStat();
- int64_t allTimeDownloadLength = pieceStorage->getCompletedLength();
- if(fwrite(&allTimeDownloadLength,
- sizeof(allTimeDownloadLength), 1, file) < 1) {
- throw string("writeError:download length");
+ // pieceLength: 32 bits
+ int32_t pieceLength = _dctx->getPieceLength();
+ o.write(reinterpret_cast<const char*>(&pieceLength), sizeof(int32_t));
+ // totalLength: 64 bits
+ int64_t totalLength = _dctx->getTotalLength();
+ o.write(reinterpret_cast<const char*>(&totalLength), sizeof(int64_t));
+ // uploadLength: 64 bits
+ int64_t uploadLength = 0;
+ if(torrentDownload) {
+ BtContextHandle btContext = _dctx;
+ TransferStat stat = PEER_STORAGE(btContext)->calculateStat();
+ uploadLength = stat.getAllTimeUploadLength();
}
- int64_t allTimeUploadLength =
- btRuntime->getUploadLengthAtStartup()+
- stat.getSessionUploadLength();
- if(fwrite(&allTimeUploadLength,
- sizeof(allTimeUploadLength), 1, file) < 1) {
- throw string("writeError:upload length");
+ o.write(reinterpret_cast<const char*>(&uploadLength), sizeof(int64_t));
+ // bitfieldLength: 32 bits
+ int32_t bitfieldLength = _pieceStorage->getBitfieldLength();
+ o.write(reinterpret_cast<const char*>(&bitfieldLength), sizeof(int32_t));
+ // bitfield
+ o.write(reinterpret_cast<const char*>(_pieceStorage->getBitfield()), _pieceStorage->getBitfieldLength());
+ // the number of in-flight piece: 32 bits
+ // TODO implement this
+ int32_t numInFlightPiece = _pieceStorage->countInFlightPiece();
+ o.write(reinterpret_cast<const char*>(&numInFlightPiece), sizeof(int32_t));
+ Pieces inFlightPieces = _pieceStorage->getInFlightPieces();
+ for(Pieces::const_iterator itr = inFlightPieces.begin();
+ itr != inFlightPieces.end(); ++itr) {
+ int32_t index = (*itr)->getIndex();
+ o.write(reinterpret_cast<const char*>(&index), sizeof(int32_t));
+ int32_t length = (*itr)->getLength();
+ o.write(reinterpret_cast<const char*>(&length), sizeof(int32_t));
+ int32_t bitfieldLength = (*itr)->getBitfieldLength();
+ o.write(reinterpret_cast<const char*>(&bitfieldLength), sizeof(int32_t));
+ o.write(reinterpret_cast<const char*>((*itr)->getBitfield()), bitfieldLength);
}
- fclose(file);
- logger->info(MSG_SAVED_SEGMENT_FILE);
- } catch(string ex) {
- fclose(file);
+
+ o.close();
+ _logger->info(MSG_SAVED_SEGMENT_FILE);
+ } catch(ios::failure const& exception) {
+ // TODO ios::failure doesn't give us the reasons of failure...
throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
- filename.c_str(), strerror(errno));
+ _filename.c_str(), strerror(errno));
}
-
- if(rename(filenameTemp.c_str(), filename.c_str()) == -1) {
+ if(rename(filenameTemp.c_str(), _filename.c_str()) == -1) {
throw new DlAbortEx(EX_SEGMENT_FILE_WRITE,
- filename.c_str(), strerror(errno));
+ _filename.c_str(), strerror(errno));
}
}
-void DefaultBtProgressInfoFile::load() {
- logger->info(MSG_LOADING_SEGMENT_FILE, filename.c_str());
- FILE* file = openFile(filename, "r+b");
+void DefaultBtProgressInfoFile::load()
+{
+ _logger->info(MSG_LOADING_SEGMENT_FILE, _filename.c_str());
+ ifstream in(_filename.c_str(), ios::in|ios::binary);
+ in.exceptions(ios::failbit);
unsigned char* savedInfoHash = 0;
unsigned char* savedBitfield = 0;
try {
- savedInfoHash = new unsigned char[btContext->getInfoHashLength()];
- savedBitfield = new unsigned char[pieceStorage->getBitfieldLength()];
- if(fread(savedInfoHash, btContext->getInfoHashLength(), 1, file) < 1) {
- throw string("readError");
+ unsigned char version[2];
+ in.read((char*)version, sizeof(version));
+ if(string("0000") != Util::toHex(version, sizeof(version))) {
+ throw new DlAbortEx("Unsupported ctrl file version: %s",
+ Util::toHex(version, sizeof(version)).c_str());
+ }
+ unsigned char extension[4];
+ in.read((char*)extension, sizeof(extension));
+
+ bool infoHashCheckEnabled = false;
+ if(extension[3]&1 && isTorrentDownload()) {
+ infoHashCheckEnabled = true;
+ _logger->debug("InfoHash checking enabled.");
+ }
+
+ int32_t infoHashLength;
+ in.read(reinterpret_cast<char*>(&infoHashLength), sizeof(infoHashLength));
+ if(infoHashLength < 0 || infoHashLength == 0 && infoHashCheckEnabled) {
+ throw new DlAbortEx("Invalid info hash length: %d", infoHashLength);
+ }
+ if(infoHashLength > 0) {
+ savedInfoHash = new unsigned char[infoHashLength];
+ in.read(reinterpret_cast<char*>(savedInfoHash), infoHashLength);
+ BtContextHandle btContext = _dctx;
+ if(infoHashCheckEnabled &&
+ Util::toHex(savedInfoHash, infoHashLength) != btContext->getInfoHashAsString()) {
+ throw new DlAbortEx("info hash mismatch. expected: %s, actual: %s",
+ btContext->getInfoHashAsString().c_str(),
+ Util::toHex(savedInfoHash, infoHashLength).c_str());
+ }
+ delete [] savedInfoHash;
+ savedInfoHash = 0;
}
- if(Util::toHex(savedInfoHash, btContext->getInfoHashLength()) !=
- btContext->getInfoHashAsString()) {
- throw string("infoHashMismatch");
+
+ // TODO implement the conversion mechanism between different piece length.
+ int32_t pieceLength;
+ in.read(reinterpret_cast<char*>(&pieceLength), sizeof(pieceLength));
+ if(pieceLength != _dctx->getPieceLength()) {
+ throw new DlAbortEx("piece length mismatch. expected: %d, actual: %d",
+ _dctx->getPieceLength(), pieceLength);
}
- if(fread(savedBitfield, pieceStorage->getBitfieldLength(), 1, file) < 1) {
- throw string("readError");
+
+ int64_t totalLength;
+ in.read(reinterpret_cast<char*>(&totalLength), sizeof(totalLength));
+ if(totalLength != _dctx->getTotalLength()) {
+ throw new DlAbortEx("total length mismatch. expected: %s, actual: %s",
+ Util::llitos(_dctx->getTotalLength()).c_str(),
+ Util::llitos(totalLength).c_str());
}
- pieceStorage->setBitfield(savedBitfield,
- pieceStorage->getBitfieldLength());
- // allTimeDownloadLength exists for only a compatibility reason.
- int64_t allTimeDownloadLength;
- if(fread(&allTimeDownloadLength,
- sizeof(allTimeDownloadLength), 1, file) < 1) {
- throw string("readError");
+ int64_t uploadLength;
+ in.read(reinterpret_cast<char*>(&uploadLength), sizeof(uploadLength));
+ if(isTorrentDownload()) {
+ BT_RUNTIME(BtContextHandle(_dctx))->setUploadLengthAtStartup(uploadLength);
}
- int64_t allTimeUploadLength;
- if(fread(&allTimeUploadLength,
- sizeof(allTimeUploadLength), 1, file) < 1) {
- throw string("readError");
+
+ // TODO implement the conversion mechanism between different piece length.
+ int32_t bitfieldLength;
+ in.read(reinterpret_cast<char*>(&bitfieldLength), sizeof(bitfieldLength));
+ if(_pieceStorage->getBitfieldLength() != bitfieldLength) {
+ throw new DlAbortEx("bitfield length mismatch. expected: %d, actual: %d",
+ _pieceStorage->getBitfieldLength(),
+ bitfieldLength);
}
- btRuntime->setUploadLengthAtStartup(allTimeUploadLength);
+
+ // TODO implement the conversion mechanism between different piece length.
+ savedBitfield = new unsigned char[bitfieldLength];
+ in.read(reinterpret_cast<char*>(savedBitfield), bitfieldLength);
+ _pieceStorage->setBitfield(savedBitfield, bitfieldLength);
delete [] savedBitfield;
savedBitfield = 0;
- delete [] savedInfoHash;
- savedInfoHash = 0;
- fclose(file);
- } catch(string ex) {
- if(savedBitfield) {
+
+ int32_t numInFlightPiece;
+ in.read(reinterpret_cast<char*>(&numInFlightPiece), sizeof(numInFlightPiece));
+
+ Pieces inFlightPieces;
+ while(numInFlightPiece--) {
+ int32_t index;
+ in.read(reinterpret_cast<char*>(&index), sizeof(index));
+ if(!(0 <= index && index < _dctx->getNumPieces())) {
+ throw new DlAbortEx("piece index out of range: %d", index);
+ }
+ int32_t length;
+ in.read(reinterpret_cast<char*>(&length), sizeof(length));
+ if(!(0 < length && length <=_dctx->getPieceLength())) {
+ throw new DlAbortEx("piece length out of range: %d", length);
+ }
+ PieceHandle piece = new Piece(index, length);
+ int32_t bitfieldLength;
+ in.read(reinterpret_cast<char*>(&bitfieldLength), sizeof(bitfieldLength));
+ if(piece->getBitfieldLength() != bitfieldLength) {
+ throw new DlAbortEx("piece bitfield length mismatch. expected: %d actual: %d",
+ piece->getBitfieldLength(), bitfieldLength);
+ }
+ savedBitfield = new unsigned char[bitfieldLength];
+ in.read(reinterpret_cast<char*>(savedBitfield), bitfieldLength);
+ piece->setBitfield(savedBitfield, bitfieldLength);
delete [] savedBitfield;
+ savedBitfield = 0;
+
+ inFlightPieces.push_back(piece);
}
- if(savedInfoHash) {
- delete [] savedInfoHash;
- }
- fclose(file);
- if(ex == "infoHashMismatch") {
- throw new DlAbortEx(EX_INFOHASH_MISMATCH_IN_SEGFILE);
- } else {
- throw new DlAbortEx(EX_SEGMENT_FILE_READ,
- filename.c_str(), strerror(errno));
- }
- }
- logger->info(MSG_LOADED_SEGMENT_FILE);
+ _pieceStorage->addInFlightPiece(inFlightPieces);
+
+ _logger->info(MSG_LOADED_SEGMENT_FILE);
+ } catch(ios::failure const& exception) {
+ delete [] savedBitfield;
+ delete [] savedInfoHash;
+ // TODO ios::failure doesn't give us the reasons of failure...
+ throw new DlAbortEx(EX_SEGMENT_FILE_READ,
+ _filename.c_str(), strerror(errno));
+ }
}
void DefaultBtProgressInfoFile::removeFile() {
if(exists()) {
- File f(filename);
+ File f(_filename);
f.remove();
}
}
-FILE* DefaultBtProgressInfoFile::openFile(const string& filename,
- const string& mode) const
-{
- FILE* file = fopen(filename.c_str(), mode.c_str());
- if(!file) {
- throw new DlAbortEx(EX_SEGMENT_FILE_OPEN,
- filename.c_str(), strerror(errno));
- }
- return file;
-}
-
bool DefaultBtProgressInfoFile::exists() {
- File f(filename);
+ File f(_filename);
if(f.isFile()) {
- logger->info(MSG_SEGMENT_FILE_EXISTS, filename.c_str());
+ _logger->info(MSG_SEGMENT_FILE_EXISTS, _filename.c_str());
return true;
} else {
- logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, filename.c_str());
+ _logger->info(MSG_SEGMENT_FILE_DOES_NOT_EXIST, _filename.c_str());
return false;
}
}