mirror of https://github.com/aria2/aria2
2008-06-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Calculate piece hash when data is arrived if the data is arrived in order. This removes additional read operation for hash calculation. If the data is arrived in out of order, the hash is calucated when the piece is completed. This is the same behavior as the old implementation. * src/BtPieceMessage.cc * src/DefaultBtProgressInfoFile.cc * src/DefaultPieceStorage.cc * src/DownloadCommand.cc * src/DownloadCommand.h * src/DownloadEngine.cc * src/GrowSegment.cc * src/GrowSegment.h * src/Piece.cc * src/Piece.h * src/PiecedSegment.cc * src/PiecedSegment.h * src/Segment.h * test/PieceTest.ccpull/1/head
parent
20f5fcfc0f
commit
7d63daed22
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
||||||
|
2008-06-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
|
Calculate piece hash when data is arrived if the data is arrived in
|
||||||
|
order. This removes additional read operation for hash calculation.
|
||||||
|
If the data is arrived in out of order, the hash is calucated when the
|
||||||
|
piece is completed. This is the same behavior as the old implementation.
|
||||||
|
* src/BtPieceMessage.cc
|
||||||
|
* src/DefaultBtProgressInfoFile.cc
|
||||||
|
* src/DefaultPieceStorage.cc
|
||||||
|
* src/DownloadCommand.cc
|
||||||
|
* src/DownloadCommand.h
|
||||||
|
* src/DownloadEngine.cc
|
||||||
|
* src/GrowSegment.cc
|
||||||
|
* src/GrowSegment.h
|
||||||
|
* src/Piece.cc
|
||||||
|
* src/Piece.h
|
||||||
|
* src/PiecedSegment.cc
|
||||||
|
* src/PiecedSegment.h
|
||||||
|
* src/Segment.h
|
||||||
|
* test/PieceTest.cc
|
||||||
|
|
||||||
2008-06-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
2008-06-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
Try to keep the ordering of outgoing piece message.
|
Try to keep the ordering of outgoing piece message.
|
||||||
|
|
|
@ -97,6 +97,7 @@ void BtPieceMessage::doReceivedAction() {
|
||||||
logger->debug(MSG_PIECE_BITFIELD, cuid,
|
logger->debug(MSG_PIECE_BITFIELD, cuid,
|
||||||
Util::toHex(piece->getBitfield(),
|
Util::toHex(piece->getBitfield(),
|
||||||
piece->getBitfieldLength()).c_str());
|
piece->getBitfieldLength()).c_str());
|
||||||
|
piece->updateHash(begin, block, blockLength);
|
||||||
dispatcher->removeOutstandingRequest(slot);
|
dispatcher->removeOutstandingRequest(slot);
|
||||||
if(piece->pieceComplete()) {
|
if(piece->pieceComplete()) {
|
||||||
if(checkPieceHash(piece)) {
|
if(checkPieceHash(piece)) {
|
||||||
|
@ -202,10 +203,15 @@ std::string BtPieceMessage::toString() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BtPieceMessage::checkPieceHash(const PieceHandle& piece) {
|
bool BtPieceMessage::checkPieceHash(const PieceHandle& piece) {
|
||||||
off_t offset = (off_t)piece->getIndex()*btContext->getPieceLength();
|
if(piece->isHashCalculated()) {
|
||||||
|
logger->debug("Hash is available!! index=%zu", piece->getIndex());
|
||||||
return MessageDigestHelper::staticSHA1Digest(pieceStorage->getDiskAdaptor(), offset, piece->getLength())
|
return piece->getHashString() == btContext->getPieceHash(piece->getIndex());
|
||||||
== btContext->getPieceHash(piece->getIndex());
|
} else {
|
||||||
|
off_t offset = (off_t)piece->getIndex()*btContext->getPieceLength();
|
||||||
|
|
||||||
|
return MessageDigestHelper::staticSHA1Digest(pieceStorage->getDiskAdaptor(), offset, piece->getLength())
|
||||||
|
== btContext->getPieceHash(piece->getIndex());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BtPieceMessage::onNewPiece(const PieceHandle& piece) {
|
void BtPieceMessage::onNewPiece(const PieceHandle& piece) {
|
||||||
|
@ -218,6 +224,7 @@ void BtPieceMessage::onWrongPiece(const PieceHandle& piece) {
|
||||||
logger->info(MSG_GOT_WRONG_PIECE, cuid, piece->getIndex());
|
logger->info(MSG_GOT_WRONG_PIECE, cuid, piece->getIndex());
|
||||||
erasePieceOnDisk(piece);
|
erasePieceOnDisk(piece);
|
||||||
piece->clearAllBlock();
|
piece->clearAllBlock();
|
||||||
|
piece->destroyHashContext();
|
||||||
requestFactory->removeTargetPiece(piece);
|
requestFactory->removeTargetPiece(piece);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -280,6 +280,13 @@ void DefaultBtProgressInfoFile::load()
|
||||||
savedBitfield = new unsigned char[bitfieldLength];
|
savedBitfield = new unsigned char[bitfieldLength];
|
||||||
in.read(reinterpret_cast<char*>(savedBitfield), bitfieldLength);
|
in.read(reinterpret_cast<char*>(savedBitfield), bitfieldLength);
|
||||||
piece->setBitfield(savedBitfield, bitfieldLength);
|
piece->setBitfield(savedBitfield, bitfieldLength);
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
piece->setHashAlgo(_dctx->getPieceHashAlgo());
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
delete [] savedBitfield;
|
delete [] savedBitfield;
|
||||||
savedBitfield = 0;
|
savedBitfield = 0;
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,13 @@ PieceHandle DefaultPieceStorage::checkOutPiece(size_t index)
|
||||||
PieceHandle piece = findUsedPiece(index);
|
PieceHandle piece = findUsedPiece(index);
|
||||||
if(piece.isNull()) {
|
if(piece.isNull()) {
|
||||||
piece.reset(new Piece(index, bitfieldMan->getBlockLength(index)));
|
piece.reset(new Piece(index, bitfieldMan->getBlockLength(index)));
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
piece->setHashAlgo(downloadContext->getPieceHashAlgo());
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
addUsedPiece(piece);
|
addUsedPiece(piece);
|
||||||
return piece;
|
return piece;
|
||||||
} else {
|
} else {
|
||||||
|
@ -548,9 +555,17 @@ void DefaultPieceStorage::markPiecesDone(uint64_t length)
|
||||||
size_t r = (length%bitfieldMan->getBlockLength())/Piece::BLOCK_LENGTH;
|
size_t r = (length%bitfieldMan->getBlockLength())/Piece::BLOCK_LENGTH;
|
||||||
if(r > 0) {
|
if(r > 0) {
|
||||||
PieceHandle p(new Piece(numPiece, bitfieldMan->getBlockLength(numPiece)));
|
PieceHandle p(new Piece(numPiece, bitfieldMan->getBlockLength(numPiece)));
|
||||||
|
|
||||||
for(size_t i = 0; i < r; ++i) {
|
for(size_t i = 0; i < r; ++i) {
|
||||||
p->completeBlock(i);
|
p->completeBlock(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
p->setHashAlgo(downloadContext->getPieceHashAlgo());
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
addUsedPiece(p);
|
addUsedPiece(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,14 +68,21 @@ DownloadCommand::DownloadCommand(int cuid,
|
||||||
DownloadEngine* e,
|
DownloadEngine* e,
|
||||||
const SocketHandle& s):
|
const SocketHandle& s):
|
||||||
AbstractCommand(cuid, req, requestGroup, e, s)
|
AbstractCommand(cuid, req, requestGroup, e, s)
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
, _pieceHashValidationEnabled(false)
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_MESSAGE_DIGEST
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
{
|
{
|
||||||
std::string algo = _requestGroup->getDownloadContext()->getPieceHashAlgo();
|
if(e->option->getAsBool(PREF_REALTIME_CHUNK_CHECKSUM)) {
|
||||||
if(MessageDigestContext::supports(algo)) {
|
std::string algo = _requestGroup->getDownloadContext()->getPieceHashAlgo();
|
||||||
_messageDigestContext.reset(new MessageDigestContext());
|
if(MessageDigestContext::supports(algo)) {
|
||||||
_messageDigestContext->trySetAlgo(algo);
|
_messageDigestContext.reset(new MessageDigestContext());
|
||||||
_messageDigestContext->digestInit();
|
_messageDigestContext->trySetAlgo(algo);
|
||||||
|
_messageDigestContext->digestInit();
|
||||||
|
|
||||||
|
_pieceHashValidationEnabled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // ENABLE_MESSAGE_DIGEST
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
@ -116,7 +123,17 @@ bool DownloadCommand::executeInternal() {
|
||||||
_requestGroup->getPieceStorage()->getDiskAdaptor()->writeData(buf, bufSize,
|
_requestGroup->getPieceStorage()->getDiskAdaptor()->writeData(buf, bufSize,
|
||||||
segment->getPositionToWrite());
|
segment->getPositionToWrite());
|
||||||
//logger->debug("bufSize = %d, posToWrite = %lld", bufSize, segment->getPositionToWrite());
|
//logger->debug("bufSize = %d, posToWrite = %lld", bufSize, segment->getPositionToWrite());
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
if(_pieceHashValidationEnabled) {
|
||||||
|
segment->updateHash(segment->getWrittenLength(), buf, bufSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
segment->updateWrittenLength(bufSize);
|
segment->updateWrittenLength(bufSize);
|
||||||
|
|
||||||
|
|
||||||
//logger->debug("overflow length = %d, next posToWrite = %lld", segment->getOverflowLength(), segment->getPositionToWrite());
|
//logger->debug("overflow length = %d, next posToWrite = %lld", segment->getOverflowLength(), segment->getPositionToWrite());
|
||||||
//logger->debug("%s", Util::toHex(segment->getPiece()->getBitfield(),
|
//logger->debug("%s", Util::toHex(segment->getPiece()->getBitfield(),
|
||||||
//segment->getPiece()->getBitfieldLength()).c_str());
|
//segment->getPiece()->getBitfieldLength()).c_str());
|
||||||
|
@ -128,7 +145,17 @@ bool DownloadCommand::executeInternal() {
|
||||||
transferDecoder->inflate(infbuf, infbufSize, buf, bufSize);
|
transferDecoder->inflate(infbuf, infbufSize, buf, bufSize);
|
||||||
_requestGroup->getPieceStorage()->getDiskAdaptor()->writeData(infbuf, infbufSize,
|
_requestGroup->getPieceStorage()->getDiskAdaptor()->writeData(infbuf, infbufSize,
|
||||||
segment->getPositionToWrite());
|
segment->getPositionToWrite());
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
if(_pieceHashValidationEnabled) {
|
||||||
|
segment->updateHash(segment->getWrittenLength(), infbuf, infbufSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
segment->updateWrittenLength(infbufSize);
|
segment->updateWrittenLength(infbufSize);
|
||||||
|
|
||||||
//segment->writtenLength += infbufSize;
|
//segment->writtenLength += infbufSize;
|
||||||
peerStat->updateDownloadLength(infbufSize);
|
peerStat->updateDownloadLength(infbufSize);
|
||||||
}
|
}
|
||||||
|
@ -140,7 +167,36 @@ bool DownloadCommand::executeInternal() {
|
||||||
|| bufSize == 0) {
|
|| bufSize == 0) {
|
||||||
if(!transferDecoder.isNull()) transferDecoder->end();
|
if(!transferDecoder.isNull()) transferDecoder->end();
|
||||||
logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid);
|
logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid);
|
||||||
validatePieceHash(segment);
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string expectedPieceHash =
|
||||||
|
_requestGroup->getDownloadContext()->getPieceHash(segment->getIndex());
|
||||||
|
if(_pieceHashValidationEnabled && !expectedPieceHash.empty()) {
|
||||||
|
if(segment->isHashCalculated()) {
|
||||||
|
logger->debug("Hash is available! index=%zu", segment->getIndex());
|
||||||
|
validatePieceHash(segment, expectedPieceHash, segment->getHashString());
|
||||||
|
} else {
|
||||||
|
_messageDigestContext->digestReset();
|
||||||
|
validatePieceHash(segment, expectedPieceHash,
|
||||||
|
MessageDigestHelper::digest
|
||||||
|
(_messageDigestContext.get(),
|
||||||
|
_requestGroup->getPieceStorage()->getDiskAdaptor(),
|
||||||
|
segment->getPosition(),
|
||||||
|
segment->getLength()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_requestGroup->getSegmentMan()->completeSegment(cuid, segment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
_requestGroup->getSegmentMan()->completeSegment(cuid, segment);
|
||||||
|
|
||||||
|
#endif // !ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
checkLowestDownloadSpeed();
|
checkLowestDownloadSpeed();
|
||||||
// this unit is going to download another segment.
|
// this unit is going to download another segment.
|
||||||
return prepareForNextSegment();
|
return prepareForNextSegment();
|
||||||
|
@ -195,41 +251,30 @@ bool DownloadCommand::prepareForNextSegment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadCommand::validatePieceHash(const SegmentHandle& segment)
|
|
||||||
{
|
|
||||||
#ifdef ENABLE_MESSAGE_DIGEST
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
std::string expectedPieceHash =
|
|
||||||
_requestGroup->getDownloadContext()->getPieceHash(segment->getIndex());
|
void DownloadCommand::validatePieceHash(const SharedHandle<Segment>& segment,
|
||||||
if(!_messageDigestContext.isNull() &&
|
const std::string& expectedPieceHash,
|
||||||
e->option->getAsBool(PREF_REALTIME_CHUNK_CHECKSUM) &&
|
const std::string& actualPieceHash)
|
||||||
!expectedPieceHash.empty()) {
|
{
|
||||||
_messageDigestContext->digestReset();
|
if(actualPieceHash == expectedPieceHash) {
|
||||||
std::string actualPieceHash =
|
logger->info(MSG_GOOD_CHUNK_CHECKSUM, actualPieceHash.c_str());
|
||||||
MessageDigestHelper::digest(_messageDigestContext.get(),
|
_requestGroup->getSegmentMan()->completeSegment(cuid, segment);
|
||||||
_requestGroup->getPieceStorage()->getDiskAdaptor(),
|
} else {
|
||||||
segment->getPosition(),
|
logger->info(EX_INVALID_CHUNK_CHECKSUM,
|
||||||
segment->getLength());
|
segment->getIndex(),
|
||||||
if(actualPieceHash == expectedPieceHash) {
|
Util::itos(segment->getPosition(), true).c_str(),
|
||||||
logger->info(MSG_GOOD_CHUNK_CHECKSUM, actualPieceHash.c_str());
|
expectedPieceHash.c_str(),
|
||||||
_requestGroup->getSegmentMan()->completeSegment(cuid, segment);
|
actualPieceHash.c_str());
|
||||||
} else {
|
segment->clear();
|
||||||
logger->info(EX_INVALID_CHUNK_CHECKSUM,
|
_requestGroup->getSegmentMan()->cancelSegment(cuid);
|
||||||
segment->getIndex(),
|
throw DlRetryEx
|
||||||
Util::itos(segment->getPosition(), true).c_str(),
|
(StringFormat("Invalid checksum index=%d", segment->getIndex()).str());
|
||||||
expectedPieceHash.c_str(),
|
}
|
||||||
actualPieceHash.c_str());
|
|
||||||
segment->clear();
|
|
||||||
_requestGroup->getSegmentMan()->cancelSegment(cuid);
|
|
||||||
throw DlRetryEx
|
|
||||||
(StringFormat("Invalid checksum index=%d", segment->getIndex()).str());
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif // ENABLE_MESSAGE_DIGEST
|
|
||||||
{
|
|
||||||
_requestGroup->getSegmentMan()->completeSegment(cuid, segment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
void DownloadCommand::setTransferDecoder(const TransferEncodingHandle& transferDecoder)
|
void DownloadCommand::setTransferDecoder(const TransferEncodingHandle& transferDecoder)
|
||||||
{
|
{
|
||||||
this->transferDecoder = transferDecoder;
|
this->transferDecoder = transferDecoder;
|
||||||
|
|
|
@ -51,11 +51,18 @@ private:
|
||||||
time_t startupIdleTime;
|
time_t startupIdleTime;
|
||||||
unsigned int lowestDownloadSpeedLimit;
|
unsigned int lowestDownloadSpeedLimit;
|
||||||
SharedHandle<PeerStat> peerStat;
|
SharedHandle<PeerStat> peerStat;
|
||||||
|
|
||||||
#ifdef ENABLE_MESSAGE_DIGEST
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
bool _pieceHashValidationEnabled;
|
||||||
|
|
||||||
SharedHandle<MessageDigestContext> _messageDigestContext;
|
SharedHandle<MessageDigestContext> _messageDigestContext;
|
||||||
|
|
||||||
#endif // ENABLE_MESSAGE_DIGEST
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
void validatePieceHash(const SharedHandle<Segment>& segment);
|
void validatePieceHash(const SharedHandle<Segment>& segment,
|
||||||
|
const std::string& expectedPieceHash,
|
||||||
|
const std::string& actualPieceHash);
|
||||||
|
|
||||||
void checkLowestDownloadSpeed() const;
|
void checkLowestDownloadSpeed() const;
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -133,12 +133,12 @@ void ADNSEvent::processEvents(int events)
|
||||||
{
|
{
|
||||||
ares_socket_t readfd;
|
ares_socket_t readfd;
|
||||||
ares_socket_t writefd;
|
ares_socket_t writefd;
|
||||||
if(events&EPOLLIN) {
|
if(events&(SocketEntry::EVENT_READ|SocketEntry::EVENT_ERROR|SocketEntry::EVENT_HUP)) {
|
||||||
readfd = _socket;
|
readfd = _socket;
|
||||||
} else {
|
} else {
|
||||||
readfd = ARES_SOCKET_BAD;
|
readfd = ARES_SOCKET_BAD;
|
||||||
}
|
}
|
||||||
if(events&EPOLLOUT) {
|
if(events&(SocketEntry::EVENT_WRITE|SocketEntry::EVENT_ERROR|SocketEntry::EVENT_HUP)) {
|
||||||
writefd = _socket;
|
writefd = _socket;
|
||||||
} else {
|
} else {
|
||||||
writefd = ARES_SOCKET_BAD;
|
writefd = ARES_SOCKET_BAD;
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
/* copyright --> */
|
/* copyright --> */
|
||||||
#include "GrowSegment.h"
|
#include "GrowSegment.h"
|
||||||
#include "Piece.h"
|
#include "Piece.h"
|
||||||
|
#include "A2STR.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -49,6 +50,15 @@ void GrowSegment::updateWrittenLength(size_t bytes)
|
||||||
_piece->setAllBlock();
|
_piece->setAllBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
std::string GrowSegment::getHashString()
|
||||||
|
{
|
||||||
|
return A2STR::NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
void GrowSegment::clear()
|
void GrowSegment::clear()
|
||||||
{
|
{
|
||||||
_writtenLength = 0;
|
_writtenLength = 0;
|
||||||
|
|
|
@ -90,6 +90,23 @@ public:
|
||||||
|
|
||||||
virtual void updateWrittenLength(size_t bytes);
|
virtual void updateWrittenLength(size_t bytes);
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
virtual bool updateHash(size_t begin,
|
||||||
|
const unsigned char* data, size_t dataLength)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isHashCalculated() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string getHashString();
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
|
|
||||||
virtual SharedHandle<Piece> getPiece() const;
|
virtual SharedHandle<Piece> getPiece() const;
|
||||||
|
|
73
src/Piece.cc
73
src/Piece.cc
|
@ -36,12 +36,25 @@
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "BitfieldManFactory.h"
|
#include "BitfieldManFactory.h"
|
||||||
#include "BitfieldMan.h"
|
#include "BitfieldMan.h"
|
||||||
|
#include "A2STR.h"
|
||||||
|
#include "Util.h"
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
# include "messageDigest.h"
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
Piece::Piece():index(0), length(0), _blockLength(BLOCK_LENGTH), bitfield(0) {}
|
Piece::Piece():index(0), length(0), _blockLength(BLOCK_LENGTH), bitfield(0)
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
, _nextBegin(0)
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
{}
|
||||||
|
|
||||||
Piece::Piece(size_t index, size_t length, size_t blockLength):index(index), length(length), _blockLength(blockLength) {
|
Piece::Piece(size_t index, size_t length, size_t blockLength):index(index), length(length), _blockLength(blockLength)
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
, _nextBegin(0)
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
{
|
||||||
bitfield =
|
bitfield =
|
||||||
BitfieldManFactory::getFactoryInstance()->createBitfieldMan(_blockLength, length);
|
BitfieldManFactory::getFactoryInstance()->createBitfieldMan(_blockLength, length);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +68,11 @@ Piece::Piece(const Piece& piece) {
|
||||||
} else {
|
} else {
|
||||||
bitfield = new BitfieldMan(*piece.bitfield);
|
bitfield = new BitfieldMan(*piece.bitfield);
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
_nextBegin = piece._nextBegin;
|
||||||
|
// TODO Is this OK?
|
||||||
|
_mdctx = piece._mdctx;
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
}
|
}
|
||||||
|
|
||||||
Piece::~Piece()
|
Piece::~Piece()
|
||||||
|
@ -200,4 +218,55 @@ size_t Piece::getCompletedLength()
|
||||||
return bitfield->getCompletedLength();
|
return bitfield->getCompletedLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
void Piece::setHashAlgo(const std::string& algo)
|
||||||
|
{
|
||||||
|
_hashAlgo = algo;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Piece::updateHash(size_t begin, const unsigned char* data, size_t dataLength)
|
||||||
|
{
|
||||||
|
if(_hashAlgo.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(begin == _nextBegin && _nextBegin+dataLength <= length) {
|
||||||
|
|
||||||
|
if(_mdctx.isNull()) {
|
||||||
|
_mdctx.reset(new MessageDigestContext());
|
||||||
|
_mdctx->trySetAlgo(_hashAlgo);
|
||||||
|
_mdctx->digestInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
_mdctx->digestUpdate(data, dataLength);
|
||||||
|
_nextBegin += dataLength;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Piece::isHashCalculated() const
|
||||||
|
{
|
||||||
|
return !_mdctx.isNull() && _nextBegin == length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO should be getHashString()
|
||||||
|
std::string Piece::getHashString()
|
||||||
|
{
|
||||||
|
if(_mdctx.isNull()) {
|
||||||
|
return A2STR::NIL;
|
||||||
|
} else {
|
||||||
|
return Util::toHex(_mdctx->digestFinal());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Piece::destroyHashContext()
|
||||||
|
{
|
||||||
|
_mdctx.reset();
|
||||||
|
_nextBegin = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
36
src/Piece.h
36
src/Piece.h
|
@ -45,12 +45,29 @@ namespace aria2 {
|
||||||
|
|
||||||
class BitfieldMan;
|
class BitfieldMan;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
class MessageDigestContext;
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
class Piece {
|
class Piece {
|
||||||
private:
|
private:
|
||||||
size_t index;
|
size_t index;
|
||||||
size_t length;
|
size_t length;
|
||||||
size_t _blockLength;
|
size_t _blockLength;
|
||||||
BitfieldMan* bitfield;
|
BitfieldMan* bitfield;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
size_t _nextBegin;
|
||||||
|
|
||||||
|
std::string _hashAlgo;
|
||||||
|
|
||||||
|
SharedHandle<MessageDigestContext> _mdctx;
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static const size_t BLOCK_LENGTH = 16*1024;
|
static const size_t BLOCK_LENGTH = 16*1024;
|
||||||
|
@ -116,6 +133,25 @@ public:
|
||||||
// Calculates completed length
|
// Calculates completed length
|
||||||
size_t getCompletedLength();
|
size_t getCompletedLength();
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
void setHashAlgo(const std::string& algo);
|
||||||
|
|
||||||
|
// Updates hash value. This function compares begin and private variable
|
||||||
|
// _nextBegin and only when they are equal, hash is updated eating data and
|
||||||
|
// returns true. Otherwise returns false.
|
||||||
|
bool updateHash(size_t begin, const unsigned char* data, size_t dataLength);
|
||||||
|
|
||||||
|
bool isHashCalculated() const;
|
||||||
|
|
||||||
|
// Returns hash value in ASCII hexadecimal form.
|
||||||
|
// WARN: This function must be called only once.
|
||||||
|
std::string getHashString();
|
||||||
|
|
||||||
|
void destroyHashContext();
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loses current bitfield state.
|
* Loses current bitfield state.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -90,11 +90,37 @@ void PiecedSegment::updateWrittenLength(size_t bytes)
|
||||||
_writtenLength = newWrittenLength;
|
_writtenLength = newWrittenLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
bool PiecedSegment::updateHash(size_t begin,
|
||||||
|
const unsigned char* data, size_t dataLength)
|
||||||
|
{
|
||||||
|
return _piece->updateHash(begin, data, dataLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PiecedSegment::isHashCalculated() const
|
||||||
|
{
|
||||||
|
return _piece->isHashCalculated();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PiecedSegment::getHashString()
|
||||||
|
{
|
||||||
|
return _piece->getHashString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
void PiecedSegment::clear()
|
void PiecedSegment::clear()
|
||||||
{
|
{
|
||||||
_writtenLength = 0;
|
_writtenLength = 0;
|
||||||
_overflowLength = 0;
|
_overflowLength = 0;
|
||||||
_piece->clearAllBlock();
|
_piece->clearAllBlock();
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
_piece->destroyHashContext();
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
}
|
}
|
||||||
|
|
||||||
PieceHandle PiecedSegment::getPiece() const
|
PieceHandle PiecedSegment::getPiece() const
|
||||||
|
|
|
@ -82,6 +82,18 @@ public:
|
||||||
|
|
||||||
virtual void updateWrittenLength(size_t bytes);
|
virtual void updateWrittenLength(size_t bytes);
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
// `begin' is a offset inside this segment.
|
||||||
|
virtual bool updateHash(size_t begin,
|
||||||
|
const unsigned char* data, size_t dataLength);
|
||||||
|
|
||||||
|
virtual bool isHashCalculated() const;
|
||||||
|
|
||||||
|
virtual std::string getHashString();
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
|
|
||||||
virtual SharedHandle<Piece> getPiece() const;
|
virtual SharedHandle<Piece> getPiece() const;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -67,6 +68,18 @@ public:
|
||||||
|
|
||||||
virtual void updateWrittenLength(size_t bytes) = 0;
|
virtual void updateWrittenLength(size_t bytes) = 0;
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
// `begin' is a offset inside this segment.
|
||||||
|
virtual bool updateHash(size_t begin,
|
||||||
|
const unsigned char* data, size_t dataLength) = 0;
|
||||||
|
|
||||||
|
virtual bool isHashCalculated() const = 0;
|
||||||
|
|
||||||
|
virtual std::string getHashString() = 0;
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
virtual void clear() = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
virtual SharedHandle<Piece> getPiece() const = 0;
|
virtual SharedHandle<Piece> getPiece() const = 0;
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
#include "Piece.h"
|
#include "Piece.h"
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
# include "messageDigest.h"
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cppunit/extensions/HelperMacros.h>
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
@ -9,6 +12,13 @@ class PieceTest:public CppUnit::TestFixture {
|
||||||
CPPUNIT_TEST_SUITE(PieceTest);
|
CPPUNIT_TEST_SUITE(PieceTest);
|
||||||
CPPUNIT_TEST(testCompleteBlock);
|
CPPUNIT_TEST(testCompleteBlock);
|
||||||
CPPUNIT_TEST(testGetCompletedLength);
|
CPPUNIT_TEST(testGetCompletedLength);
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
CPPUNIT_TEST(testUpdateHash);
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -17,6 +27,12 @@ public:
|
||||||
|
|
||||||
void testCompleteBlock();
|
void testCompleteBlock();
|
||||||
void testGetCompletedLength();
|
void testGetCompletedLength();
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
void testUpdateHash();
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,4 +61,30 @@ void PieceTest::testGetCompletedLength()
|
||||||
CPPUNIT_ASSERT_EQUAL(blockLength*3+100, p.getCompletedLength());
|
CPPUNIT_ASSERT_EQUAL(blockLength*3+100, p.getCompletedLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
void PieceTest::testUpdateHash()
|
||||||
|
{
|
||||||
|
Piece p(0, 16, 2*1024*1024);
|
||||||
|
p.setHashAlgo(MessageDigestContext::SHA1);
|
||||||
|
|
||||||
|
std::string spam("SPAM!");
|
||||||
|
CPPUNIT_ASSERT(p.updateHash
|
||||||
|
(0, reinterpret_cast<const unsigned char*>(spam.c_str()),
|
||||||
|
spam.size()));
|
||||||
|
CPPUNIT_ASSERT(!p.isHashCalculated());
|
||||||
|
|
||||||
|
std::string spamspam("SPAM!SPAM!!");
|
||||||
|
CPPUNIT_ASSERT(p.updateHash
|
||||||
|
(spam.size(),
|
||||||
|
reinterpret_cast<const unsigned char*>(spamspam.c_str()),
|
||||||
|
spamspam.size()));
|
||||||
|
CPPUNIT_ASSERT(p.isHashCalculated());
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("d9189aff79e075a2e60271b9556a710dc1bc7de7"),
|
||||||
|
p.getHashString());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
Loading…
Reference in New Issue