2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Fixed ut_metadata data handling. Implemented
	UTMetadataDataExtensionMessage::doReceivedAction().  Initialize
	PeerStorage in HandshakeExtensionMessage::doReceivedAction() when
	metadata_size is received.
	* src/DefaultExtensionMessageFactory.cc
	* src/DefaultExtensionMessageFactory.h
	* src/HandshakeExtensionMessage.cc
	* src/HandshakeExtensionMessage.h
	* src/UTMetadataDataExtensionMessage.cc
	* src/UTMetadataDataExtensionMessage.h
	* src/UTMetadataRequestExtensionMessage.cc
	* src/UTMetadataRequestFactory.cc
	* src/UTMetadataRequestFactory.h
	* src/UTMetadataRequestTracker.cc
	* src/UTMetadataRequestTracker.h
	* test/DefaultExtensionMessageFactoryTest.cc
	* test/HandshakeExtensionMessageTest.cc
	* test/MockBtMessage.h
	* test/UTMetadataDataExtensionMessageTest.cc
	* test/UTMetadataRequestExtensionMessageTest.cc
	* test/UTMetadataRequestFactoryTest.cc
	* test/UTMetadataRequestTrackerTest.cc
	* test/extension_message_test_helper.h
pull/1/head
Tatsuhiro Tsujikawa 2009-11-22 15:31:47 +00:00
parent b563621dd1
commit c1730aeea9
20 changed files with 813 additions and 64 deletions

View File

@ -1,3 +1,29 @@
2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Fixed ut_metadata data handling. Implemented
UTMetadataDataExtensionMessage::doReceivedAction(). Initialize
PeerStorage in HandshakeExtensionMessage::doReceivedAction() when
metadata_size is received.
* src/DefaultExtensionMessageFactory.cc
* src/DefaultExtensionMessageFactory.h
* src/HandshakeExtensionMessage.cc
* src/HandshakeExtensionMessage.h
* src/UTMetadataDataExtensionMessage.cc
* src/UTMetadataDataExtensionMessage.h
* src/UTMetadataRequestExtensionMessage.cc
* src/UTMetadataRequestFactory.cc
* src/UTMetadataRequestFactory.h
* src/UTMetadataRequestTracker.cc
* src/UTMetadataRequestTracker.h
* test/DefaultExtensionMessageFactoryTest.cc
* test/HandshakeExtensionMessageTest.cc
* test/MockBtMessage.h
* test/UTMetadataDataExtensionMessageTest.cc
* test/UTMetadataRequestExtensionMessageTest.cc
* test/UTMetadataRequestFactoryTest.cc
* test/UTMetadataRequestTrackerTest.cc
* test/extension_message_test_helper.h
2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net> 2009-11-23 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Drop connection if ut_metadata reject message is received. Drop connection if ut_metadata reject message is received.

View File

@ -50,6 +50,10 @@
#include "UTMetadataRejectExtensionMessage.h" #include "UTMetadataRejectExtensionMessage.h"
#include "message.h" #include "message.h"
#include "bencode.h" #include "bencode.h"
#include "PieceStorage.h"
#include "UTMetadataRequestTracker.h"
#include "BtRuntime.h"
#include "RequestGroup.h"
namespace aria2 { namespace aria2 {
@ -93,16 +97,8 @@ DefaultExtensionMessageFactory::createMessage(const unsigned char* data, size_t
throw DL_ABORT_EX(StringFormat(MSG_TOO_SMALL_PAYLOAD_SIZE, throw DL_ABORT_EX(StringFormat(MSG_TOO_SMALL_PAYLOAD_SIZE,
"ut_metadata", length).str()); "ut_metadata", length).str());
} }
std::string listdata; size_t end;
listdata += 'l'; BDE dict = bencode::decode(data+1, length-1, end);
listdata += std::string(&data[1], &data[length]);
listdata += 'e';
const BDE& list = bencode::decode(listdata);
if(!list.isList() || list.empty()) {
throw DL_ABORT_EX("Bad ut_metadata");
}
const BDE& dict = list[0];
if(!dict.isDict()) { if(!dict.isDict()) {
throw DL_ABORT_EX("Bad ut_metadata: dictionary not found"); throw DL_ABORT_EX("Bad ut_metadata: dictionary not found");
} }
@ -126,13 +122,9 @@ DefaultExtensionMessageFactory::createMessage(const unsigned char* data, size_t
return m; return m;
} }
case 1: { case 1: {
if(list.size() != 2) { if(end == length) {
throw DL_ABORT_EX("Bad ut_metadata data: data not found"); throw DL_ABORT_EX("Bad ut_metadata data: data not found");
} }
const BDE& pieceData = list[1];
if(!pieceData.isString()) {
throw DL_ABORT_EX("Bad ut_metadata data: data is not string");
}
const BDE& totalSize = dict["total_size"]; const BDE& totalSize = dict["total_size"];
if(!totalSize.isInteger()) { if(!totalSize.isInteger()) {
throw DL_ABORT_EX("Bad ut_metadata data: total_size not found"); throw DL_ABORT_EX("Bad ut_metadata data: total_size not found");
@ -141,16 +133,18 @@ DefaultExtensionMessageFactory::createMessage(const unsigned char* data, size_t
(new UTMetadataDataExtensionMessage(extensionMessageID)); (new UTMetadataDataExtensionMessage(extensionMessageID));
m->setIndex(index.i()); m->setIndex(index.i());
m->setTotalSize(totalSize.i()); m->setTotalSize(totalSize.i());
m->setData(pieceData.s()); m->setData(std::string(&data[1+end], &data[length]));
// set tracker m->setUTMetadataRequestTracker(_tracker);
// set piecestorage m->setPieceStorage(_dctx->getOwnerRequestGroup()->getPieceStorage());
m->setDownloadContext(_dctx);
m->setBtRuntime(_btRuntime);
return m; return m;
} }
case 2: { case 2: {
SharedHandle<UTMetadataRejectExtensionMessage> m SharedHandle<UTMetadataRejectExtensionMessage> m
(new UTMetadataRejectExtensionMessage(extensionMessageID)); (new UTMetadataRejectExtensionMessage(extensionMessageID));
m->setIndex(index.i()); m->setIndex(index.i());
// set tracker if disconnecing peer on receive. // No need to inject tracker because peer will be disconnected.
return m; return m;
} }
default: default:

View File

@ -46,6 +46,8 @@ class ExtensionMessageRegistry;
class DownloadContext; class DownloadContext;
class BtMessageFactory; class BtMessageFactory;
class BtMessageDispatcher; class BtMessageDispatcher;
class UTMetadataRequestTracker;
class BtRuntime;
class DefaultExtensionMessageFactory:public ExtensionMessageFactory { class DefaultExtensionMessageFactory:public ExtensionMessageFactory {
private: private:
@ -57,10 +59,14 @@ private:
SharedHandle<DownloadContext> _dctx; SharedHandle<DownloadContext> _dctx;
SharedHandle<BtRuntime> _btRuntime;
WeakHandle<BtMessageFactory> _messageFactory; WeakHandle<BtMessageFactory> _messageFactory;
WeakHandle<BtMessageDispatcher> _dispatcher; WeakHandle<BtMessageDispatcher> _dispatcher;
WeakHandle<UTMetadataRequestTracker> _tracker;
Logger* _logger; Logger* _logger;
public: public:
@ -99,6 +105,17 @@ public:
{ {
_dispatcher = disp; _dispatcher = disp;
} }
void setUTMetadataRequestTracker
(const WeakHandle<UTMetadataRequestTracker>& tracker)
{
_tracker = tracker;
}
void setBtRuntime(const SharedHandle<BtRuntime>& btRuntime)
{
_btRuntime = btRuntime;
}
}; };
typedef SharedHandle<DefaultExtensionMessageFactory> DefaultExtensionMessageFactoryHandle; typedef SharedHandle<DefaultExtensionMessageFactory> DefaultExtensionMessageFactoryHandle;

View File

@ -43,6 +43,8 @@
#include "bencode.h" #include "bencode.h"
#include "DownloadContext.h" #include "DownloadContext.h"
#include "bittorrent_helper.h" #include "bittorrent_helper.h"
#include "RequestGroup.h"
#include "PieceStorage.h"
namespace aria2 { namespace aria2 {
@ -110,8 +112,19 @@ void HandshakeExtensionMessage::doReceivedAction()
} }
if(_metadataSize > 0) { if(_metadataSize > 0) {
BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT); BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
if(!attrs.containsKey(bittorrent::METADATA_SIZE)) { if(attrs.containsKey(bittorrent::METADATA_SIZE)) {
if(_metadataSize != (size_t)attrs[bittorrent::METADATA_SIZE].i()) {
throw DL_ABORT_EX("Wrong metadata_size. Which one is correct!?");
}
} else {
attrs[bittorrent::METADATA_SIZE] = _metadataSize; attrs[bittorrent::METADATA_SIZE] = _metadataSize;
_dctx->getFirstFileEntry()->setLength(_metadataSize);
_dctx->markTotalLengthIsKnown();
_dctx->getOwnerRequestGroup()->initPieceStorage();
SharedHandle<PieceStorage> pieceStorage =
_dctx->getOwnerRequestGroup()->getPieceStorage();
pieceStorage->setEndGamePieceNum(0);
} }
} }
} }

View File

@ -45,9 +45,7 @@ namespace aria2 {
class Peer; class Peer;
class Logger; class Logger;
class HandshakeExtensionMessage;
class DownloadContext; class DownloadContext;
typedef SharedHandle<HandshakeExtensionMessage> HandshakeExtensionMessageHandle;
class HandshakeExtensionMessage:public ExtensionMessage { class HandshakeExtensionMessage:public ExtensionMessage {
private: private:
@ -137,8 +135,8 @@ public:
void setPeer(const SharedHandle<Peer>& peer); void setPeer(const SharedHandle<Peer>& peer);
static HandshakeExtensionMessageHandle create(const unsigned char* data, static SharedHandle<HandshakeExtensionMessage>
size_t dataLength); create(const unsigned char* data, size_t dataLength);
}; };
typedef SharedHandle<HandshakeExtensionMessage> HandshakeExtensionMessageHandle; typedef SharedHandle<HandshakeExtensionMessage> HandshakeExtensionMessageHandle;

View File

@ -37,29 +37,30 @@
#include "bencode.h" #include "bencode.h"
#include "util.h" #include "util.h"
#include "a2functional.h" #include "a2functional.h"
#include "DownloadContext.h"
#include "UTMetadataRequestTracker.h"
#include "PieceStorage.h"
#include "BtConstants.h"
#include "MessageDigestHelper.h"
#include "bittorrent_helper.h"
#include "DiskAdaptor.h"
#include "Piece.h"
#include "BtRuntime.h"
#include "LogFactory.h"
namespace aria2 { namespace aria2 {
UTMetadataDataExtensionMessage::UTMetadataDataExtensionMessage UTMetadataDataExtensionMessage::UTMetadataDataExtensionMessage
(uint8_t extensionMessageID):UTMetadataExtensionMessage(extensionMessageID) {} (uint8_t extensionMessageID):UTMetadataExtensionMessage(extensionMessageID),
_logger(LogFactory::getInstance()) {}
std::string UTMetadataDataExtensionMessage::getBencodedData() std::string UTMetadataDataExtensionMessage::getBencodedData()
{ {
BDE list = BDE::list();
BDE dict = BDE::dict(); BDE dict = BDE::dict();
dict["msg_type"] = 1; dict["msg_type"] = 1;
dict["piece"] = _index; dict["piece"] = _index;
dict["total_size"] = _totalSize; dict["total_size"] = _totalSize;
return bencode::encode(dict)+_data;
BDE data = _data;
list << dict;
list << data;
std::string encodedList = bencode::encode(list);
// Remove first 'l' and last 'e' and return.
return std::string(encodedList.begin()+1, encodedList.end()-1);
} }
std::string UTMetadataDataExtensionMessage::toString() const std::string UTMetadataDataExtensionMessage::toString() const
@ -69,9 +70,36 @@ std::string UTMetadataDataExtensionMessage::toString() const
void UTMetadataDataExtensionMessage::doReceivedAction() void UTMetadataDataExtensionMessage::doReceivedAction()
{ {
// Update tracker if(_tracker->tracks(_index)) {
_logger->debug("ut_metadata index=%lu found in tracking list",
// Write to pieceStorage static_cast<unsigned long>(_index));
_tracker->remove(_index);
_pieceStorage->getDiskAdaptor()->writeData
(reinterpret_cast<const unsigned char*>(_data.c_str()), _data.size(),
_index*METADATA_PIECE_SIZE);
_pieceStorage->completePiece(_pieceStorage->getPiece(_index));
if(_pieceStorage->downloadFinished()) {
std::string metadata = util::toString(_pieceStorage->getDiskAdaptor());
unsigned char infoHash[INFO_HASH_LENGTH];
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
MessageDigestContext::SHA1,
metadata.data(), metadata.size());
const BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
if(std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]) ==
attrs[bittorrent::INFO_HASH].s()){
_logger->info("Got ut_metadata");
_btRuntime->setHalt(true);
} else {
_logger->info("Got wrong ut_metadata");
for(size_t i = 0; i < _dctx->getNumPieces(); ++i) {
_pieceStorage->markPieceMissing(i);
}
}
}
} else {
_logger->debug("ut_metadata index=%lu is not tracked",
static_cast<unsigned long>(_index));
}
} }
} // namespace aria2 } // namespace aria2

View File

@ -39,11 +39,27 @@
namespace aria2 { namespace aria2 {
class DownloadContext;
class PieceStorage;
class UTMetadataRequestTracker;
class BtRuntime;
class Logger;
class UTMetadataDataExtensionMessage:public UTMetadataExtensionMessage { class UTMetadataDataExtensionMessage:public UTMetadataExtensionMessage {
private: private:
size_t _totalSize; size_t _totalSize;
std::string _data; std::string _data;
SharedHandle<DownloadContext> _dctx;
SharedHandle<PieceStorage> _pieceStorage;
SharedHandle<BtRuntime> _btRuntime;
WeakHandle<UTMetadataRequestTracker> _tracker;
Logger* _logger;
public: public:
UTMetadataDataExtensionMessage(uint8_t extensionMessageID); UTMetadataDataExtensionMessage(uint8_t extensionMessageID);
@ -72,6 +88,27 @@ public:
{ {
return _data; return _data;
} }
void setPieceStorage(const SharedHandle<PieceStorage>& pieceStorage)
{
_pieceStorage = pieceStorage;
}
void setUTMetadataRequestTracker
(const WeakHandle<UTMetadataRequestTracker>& tracker)
{
_tracker = tracker;
}
void setDownloadContext(const SharedHandle<DownloadContext>& dctx)
{
_dctx = dctx;
}
void setBtRuntime(const SharedHandle<BtRuntime>& btRuntime)
{
_btRuntime = btRuntime;
}
}; };
} // namespace aria2 } // namespace aria2

View File

@ -48,6 +48,8 @@
#include "BtConstants.h" #include "BtConstants.h"
#include "DownloadContext.h" #include "DownloadContext.h"
#include "BtMessage.h" #include "BtMessage.h"
#include "PieceStorage.h"
#include "BtRuntime.h"
namespace aria2 { namespace aria2 {

View File

@ -0,0 +1,79 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 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 "UTMetadataRequestFactory.h"
#include "PieceStorage.h"
#include "DownloadContext.h"
#include "Peer.h"
#include "BtMessageDispatcher.h"
#include "BtMessageFactory.h"
#include "UTMetadataRequestExtensionMessage.h"
#include "UTMetadataRequestTracker.h"
#include "BtMessage.h"
#include "LogFactory.h"
namespace aria2 {
UTMetadataRequestFactory::UTMetadataRequestFactory():
_logger(LogFactory::getInstance()) {}
void UTMetadataRequestFactory::create
(std::deque<SharedHandle<BtMessage> >& msgs, size_t num,
const SharedHandle<PieceStorage>& pieceStorage)
{
for(size_t index = 0; index < _dctx->getNumPieces() && num; ++index) {
SharedHandle<Piece> p = pieceStorage->getMissingPiece(index);
if(p.isNull()) {
_logger->debug("ut_metadata piece %lu is used or already acquired.");
continue;
}
--num;
_logger->debug("Creating ut_metadata request index=%lu",
static_cast<unsigned long>(index));
SharedHandle<UTMetadataRequestExtensionMessage> m
(new UTMetadataRequestExtensionMessage
(_peer->getExtensionMessageID("ut_metadata")));
m->setIndex(index);
m->setDownloadContext(_dctx);
m->setBtMessageDispatcher(_dispatcher);
m->setBtMessageFactory(_messageFactory);
m->setPeer(_peer);
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
msgs.push_back(msg);
_tracker->add(index);
}
}
} // namespace aria2

View File

@ -0,0 +1,105 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 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 _UT_METADATA_REQUEST_FACTORY_H_
#define _UT_METADATA_REQUEST_FACTORY_H_
#include "common.h"
#include <deque>
#include "SharedHandle.h"
namespace aria2 {
class PieceStorage;
class DownloadContext;
class Peer;
class BtMessageDispatcher;
class BtMessageFactory;
class UTMetadataRequestTracker;
class BtMessage;
class Logger;
class UTMetadataRequestFactory {
private:
SharedHandle<DownloadContext> _dctx;
SharedHandle<Peer> _peer;
WeakHandle<BtMessageDispatcher> _dispatcher;
WeakHandle<BtMessageFactory> _messageFactory;
WeakHandle<UTMetadataRequestTracker> _tracker;
Logger* _logger;
public:
UTMetadataRequestFactory();
// Creates at most num of ut_metadata request message and appends
// them to msgs. pieceStorage is used to identify missing piece.
void create(std::deque<SharedHandle<BtMessage> >& msgs, size_t num,
const SharedHandle<PieceStorage>& pieceStorage);
void setDownloadContext(const SharedHandle<DownloadContext>& dctx)
{
_dctx = dctx;
}
void setBtMessageDispatcher(const WeakHandle<BtMessageDispatcher>& disp)
{
_dispatcher = disp;
}
void setBtMessageFactory(const WeakHandle<BtMessageFactory>& factory)
{
_messageFactory = factory;
}
void setPeer(const SharedHandle<Peer>& peer)
{
_peer = peer;
}
void setUTMetadataRequestTracker
(const WeakHandle<UTMetadataRequestTracker>& tracker)
{
_tracker = tracker;
}
};
} // namespace aria2
#endif // _UT_METADATA_REQUEST_FACTORY_H_

View File

@ -0,0 +1,106 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 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 "UTMetadataRequestTracker.h"
#include <algorithm>
#include "LogFactory.h"
namespace aria2 {
UTMetadataRequestTracker::UTMetadataRequestTracker():
_logger(LogFactory::getInstance()) {}
void UTMetadataRequestTracker::add(size_t index)
{
_trackedRequests.push_back(RequestEntry(index));
}
bool UTMetadataRequestTracker::tracks(size_t index)
{
return std::find(_trackedRequests.begin(), _trackedRequests.end(),
RequestEntry(index)) != _trackedRequests.end();
}
void UTMetadataRequestTracker::remove(size_t index)
{
std::vector<RequestEntry>::iterator i =
std::find(_trackedRequests.begin(), _trackedRequests.end(),
RequestEntry(index));
if(i != _trackedRequests.end()) {
_trackedRequests.erase(i);
}
}
std::vector<size_t> UTMetadataRequestTracker::removeTimeoutEntry()
{
std::vector<size_t> indexes;
const time_t TIMEOUT = 20;
for(std::vector<RequestEntry>::iterator i = _trackedRequests.begin();
i != _trackedRequests.end();) {
if((*i).elapsed(TIMEOUT)) {
LogFactory::getInstance()->debug
("ut_metadata request timeout. index=%lu",
static_cast<unsigned long>((*i)._index));
indexes.push_back((*i)._index);
i = _trackedRequests.erase(i);
} else {
++i;
}
}
return indexes;
}
size_t UTMetadataRequestTracker::avail() const
{
const size_t MAX_OUTSTANDING_REQUEST = 1;
if(MAX_OUTSTANDING_REQUEST > count()) {
return MAX_OUTSTANDING_REQUEST-count();
} else {
return 0;
}
}
std::vector<size_t> UTMetadataRequestTracker::getAllTrackedIndex() const
{
std::vector<size_t> indexes;
for(std::vector<RequestEntry>::const_iterator i = _trackedRequests.begin();
i != _trackedRequests.end(); ++i) {
indexes.push_back((*i)._index);
}
return indexes;
}
} // namespace aria2

View File

@ -0,0 +1,100 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2009 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 _UT_METADATA_REQUEST_TRACKER_H_
#define _UT_METADATA_REQUEST_TRACKER_H_
#include "common.h"
#include <vector>
#include "TimeA2.h"
namespace aria2 {
class Logger;
class UTMetadataRequestTracker {
private:
struct RequestEntry {
size_t _index;
Time _dispatchedTime;
RequestEntry(size_t index):_index(index) {}
bool elapsed(time_t t) const
{
return _dispatchedTime.elapsed(t);
}
bool operator==(const RequestEntry& e) const
{
return _index == e._index;
}
};
std::vector<RequestEntry> _trackedRequests;
Logger* _logger;
public:
UTMetadataRequestTracker();
// Add request index to tracking list.
void add(size_t index);
// Returns true if request index is tracked.
bool tracks(size_t index);
// Remove index from tracking list.
void remove(size_t index);
// Returns all tracking indexes.
std::vector<size_t> getAllTrackedIndex() const;
// Removes request index which is timed out and returns their indexes.
std::vector<size_t> removeTimeoutEntry();
// Returns the number of tracking list.
size_t count() const
{
return _trackedRequests.size();
}
// Returns the number of additional index this tracker can track.
size_t avail() const;
};
} // namespace aria2
#endif // _UT_METADATA_REQUEST_TRACKER_H_

View File

@ -21,6 +21,10 @@
#include "UTMetadataRequestExtensionMessage.h" #include "UTMetadataRequestExtensionMessage.h"
#include "UTMetadataDataExtensionMessage.h" #include "UTMetadataDataExtensionMessage.h"
#include "UTMetadataRejectExtensionMessage.h" #include "UTMetadataRejectExtensionMessage.h"
#include "BtRuntime.h"
#include "PieceStorage.h"
#include "RequestGroup.h"
#include "Option.h"
namespace aria2 { namespace aria2 {
@ -42,6 +46,7 @@ private:
SharedHandle<MockBtMessageDispatcher> _dispatcher; SharedHandle<MockBtMessageDispatcher> _dispatcher;
SharedHandle<MockBtMessageFactory> _messageFactory; SharedHandle<MockBtMessageFactory> _messageFactory;
SharedHandle<DownloadContext> _dctx; SharedHandle<DownloadContext> _dctx;
SharedHandle<RequestGroup> _requestGroup;
public: public:
void setUp() void setUp()
{ {
@ -59,6 +64,11 @@ public:
_dctx.reset(new DownloadContext()); _dctx.reset(new DownloadContext());
SharedHandle<Option> option(new Option());
_requestGroup.reset(new RequestGroup(option));
_requestGroup->setDownloadContext(_dctx);
_dctx->setOwnerRequestGroup(_requestGroup.get());
_factory.reset(new DefaultExtensionMessageFactory()); _factory.reset(new DefaultExtensionMessageFactory());
_factory->setPeerStorage(_peerStorage); _factory->setPeerStorage(_peerStorage);
_factory->setPeer(_peer); _factory->setPeer(_peer);
@ -155,7 +165,7 @@ void DefaultExtensionMessageFactoryTest::testCreateMessage_UTMetadataRequest()
void DefaultExtensionMessageFactoryTest::testCreateMessage_UTMetadataData() void DefaultExtensionMessageFactoryTest::testCreateMessage_UTMetadataData()
{ {
std::string data = getExtensionMessageID("ut_metadata")+ std::string data = getExtensionMessageID("ut_metadata")+
"d8:msg_typei1e5:piecei1e10:total_sizei300ee10:0000000000"; "d8:msg_typei1e5:piecei1e10:total_sizei300ee0000000000";
SharedHandle<UTMetadataDataExtensionMessage> m = SharedHandle<UTMetadataDataExtensionMessage> m =
createMessage<UTMetadataDataExtensionMessage>(data); createMessage<UTMetadataDataExtensionMessage>(data);
CPPUNIT_ASSERT_EQUAL((size_t)1, m->getIndex()); CPPUNIT_ASSERT_EQUAL((size_t)1, m->getIndex());

View File

@ -9,6 +9,8 @@
#include "FileEntry.h" #include "FileEntry.h"
#include "DownloadContext.h" #include "DownloadContext.h"
#include "bittorrent_helper.h" #include "bittorrent_helper.h"
#include "Option.h"
#include "RequestGroup.h"
namespace aria2 { namespace aria2 {
@ -88,9 +90,16 @@ void HandshakeExtensionMessageTest::testToString()
void HandshakeExtensionMessageTest::testDoReceivedAction() void HandshakeExtensionMessageTest::testDoReceivedAction()
{ {
SharedHandle<DownloadContext> ctx(new DownloadContext()); SharedHandle<DownloadContext> dctx
(new DownloadContext(METADATA_PIECE_SIZE, 0));
SharedHandle<Option> op(new Option());
RequestGroup rg(op);
rg.setDownloadContext(dctx);
dctx->setOwnerRequestGroup(&rg);
BDE attrs = BDE::dict(); BDE attrs = BDE::dict();
ctx->setAttribute(bittorrent::BITTORRENT, attrs); dctx->setAttribute(bittorrent::BITTORRENT, attrs);
dctx->markTotalLengthIsUnknown();
SharedHandle<Peer> peer(new Peer("192.168.0.1", 0)); SharedHandle<Peer> peer(new Peer("192.168.0.1", 0));
peer->allocateSessionResource(1024, 1024*1024); peer->allocateSessionResource(1024, 1024*1024);
@ -101,7 +110,7 @@ void HandshakeExtensionMessageTest::testDoReceivedAction()
msg.setExtension("a2_dht", 2); msg.setExtension("a2_dht", 2);
msg.setMetadataSize(1024); msg.setMetadataSize(1024);
msg.setPeer(peer); msg.setPeer(peer);
msg.setDownloadContext(ctx); msg.setDownloadContext(dctx);
msg.doReceivedAction(); msg.doReceivedAction();
@ -109,6 +118,8 @@ void HandshakeExtensionMessageTest::testDoReceivedAction()
CPPUNIT_ASSERT_EQUAL((uint8_t)1, peer->getExtensionMessageID("ut_pex")); CPPUNIT_ASSERT_EQUAL((uint8_t)1, peer->getExtensionMessageID("ut_pex"));
CPPUNIT_ASSERT_EQUAL((uint8_t)2, peer->getExtensionMessageID("a2_dht")); CPPUNIT_ASSERT_EQUAL((uint8_t)2, peer->getExtensionMessageID("a2_dht"));
CPPUNIT_ASSERT_EQUAL((int64_t)1024, attrs[bittorrent::METADATA_SIZE].i()); CPPUNIT_ASSERT_EQUAL((int64_t)1024, attrs[bittorrent::METADATA_SIZE].i());
CPPUNIT_ASSERT_EQUAL((uint64_t)1024, dctx->getTotalLength());
CPPUNIT_ASSERT(dctx->knowsTotalLength());
} }
void HandshakeExtensionMessageTest::testCreate() void HandshakeExtensionMessageTest::testCreate()

View File

@ -98,6 +98,15 @@ public:
}; };
template<typename T>
class WrapBtMessage:public MockBtMessage {
public:
SharedHandle<T> _m;
WrapBtMessage(const SharedHandle<T>& m):_m(m) {}
};
} // namespace aria2 } // namespace aria2
#endif // _D_MOCK_BT_MESSAGE_H_ #endif // _D_MOCK_BT_MESSAGE_H_

View File

@ -5,6 +5,17 @@
#include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/HelperMacros.h>
#include "BtConstants.h" #include "BtConstants.h"
#include "PieceStorage.h"
#include "DownloadContext.h"
#include "BtRuntime.h"
#include "DirectDiskAdaptor.h"
#include "ByteArrayDiskWriter.h"
#include "BDE.h"
#include "DownloadContext.h"
#include "MockPieceStorage.h"
#include "UTMetadataRequestTracker.h"
#include "bittorrent_helper.h"
#include "MessageDigestHelper.h"
namespace aria2 { namespace aria2 {
@ -41,7 +52,7 @@ void UTMetadataDataExtensionMessageTest::testGetBencodedData()
msg.setTotalSize(data.size()); msg.setTotalSize(data.size());
msg.setData(data); msg.setData(data);
CPPUNIT_ASSERT_EQUAL CPPUNIT_ASSERT_EQUAL
(std::string("d8:msg_typei1e5:piecei1e10:total_sizei16384ee16384:")+data, (std::string("d8:msg_typei1e5:piecei1e10:total_sizei16384ee")+data,
msg.getBencodedData()); msg.getBencodedData());
} }
@ -55,6 +66,52 @@ void UTMetadataDataExtensionMessageTest::testToString()
void UTMetadataDataExtensionMessageTest::testDoReceivedAction() void UTMetadataDataExtensionMessageTest::testDoReceivedAction()
{ {
SharedHandle<DirectDiskAdaptor> diskAdaptor(new DirectDiskAdaptor());
SharedHandle<ByteArrayDiskWriter> diskWriter(new ByteArrayDiskWriter());
diskAdaptor->setDiskWriter(diskWriter);
SharedHandle<MockPieceStorage> pieceStorage(new MockPieceStorage());
pieceStorage->setDiskAdaptor(diskAdaptor);
SharedHandle<BtRuntime> btRuntime(new BtRuntime());
SharedHandle<UTMetadataRequestTracker> tracker
(new UTMetadataRequestTracker());
SharedHandle<DownloadContext> dctx(new DownloadContext());
BDE attrs = BDE::dict();
std::string piece0 = std::string(METADATA_PIECE_SIZE, '0');
std::string piece1 = std::string(METADATA_PIECE_SIZE, '1');
std::string metadata = piece0+piece1;
unsigned char infoHash[INFO_HASH_LENGTH];
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
MessageDigestContext::SHA1,
metadata.data(), metadata.size());
attrs[bittorrent::INFO_HASH] = std::string(&infoHash[0], &infoHash[20]);
dctx->setAttribute(bittorrent::BITTORRENT, attrs);
UTMetadataDataExtensionMessage m(1);
m.setPieceStorage(pieceStorage);
m.setBtRuntime(btRuntime);
m.setUTMetadataRequestTracker(tracker);
m.setDownloadContext(dctx);
m.setIndex(1);
m.setData(piece1);
tracker->add(1);
m.doReceivedAction();
CPPUNIT_ASSERT(!tracker->tracks(1));
pieceStorage->setDownloadFinished(true);
// If piece is not tracked, it is ignored.
m.setIndex(0);
m.setData(piece0);
m.doReceivedAction();
CPPUNIT_ASSERT(!btRuntime->isHalt());
tracker->add(0);
m.doReceivedAction();
CPPUNIT_ASSERT(btRuntime->isHalt());
} }
} // namespace aria2 } // namespace aria2

View File

@ -13,6 +13,9 @@
#include "BtHandshakeMessage.h" #include "BtHandshakeMessage.h"
#include "UTMetadataRejectExtensionMessage.h" #include "UTMetadataRejectExtensionMessage.h"
#include "UTMetadataDataExtensionMessage.h" #include "UTMetadataDataExtensionMessage.h"
#include "PieceStorage.h"
#include "BtRuntime.h"
#include "extension_message_test_helper.h"
namespace aria2 { namespace aria2 {
@ -27,30 +30,14 @@ class UTMetadataRequestExtensionMessageTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testDoReceivedAction_data); CPPUNIT_TEST(testDoReceivedAction_data);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
public: public:
class MockExtensionMessage:public MockBtMessage {
public:
SharedHandle<ExtensionMessage> _m;
MockExtensionMessage(const SharedHandle<ExtensionMessage>& m):_m(m) {}
};
class MockBtMessageFactory2:public MockBtMessageFactory {
public:
virtual SharedHandle<BtMessage>
createBtExtendedMessage(const SharedHandle<ExtensionMessage>& extmsg)
{
return SharedHandle<BtMessage>(new MockExtensionMessage(extmsg));
}
};
SharedHandle<DownloadContext> _dctx; SharedHandle<DownloadContext> _dctx;
SharedHandle<MockBtMessageFactory2> _messageFactory; SharedHandle<WrapExtBtMessageFactory> _messageFactory;
SharedHandle<MockBtMessageDispatcher> _dispatcher; SharedHandle<MockBtMessageDispatcher> _dispatcher;
SharedHandle<Peer> _peer; SharedHandle<Peer> _peer;
void setUp() void setUp()
{ {
_messageFactory.reset(new MockBtMessageFactory2()); _messageFactory.reset(new WrapExtBtMessageFactory());
_dispatcher.reset(new MockBtMessageDispatcher()); _dispatcher.reset(new MockBtMessageDispatcher());
_dctx.reset(new DownloadContext()); _dctx.reset(new DownloadContext());
BDE attrs = BDE::dict(); BDE attrs = BDE::dict();
@ -63,8 +50,8 @@ public:
template<typename T> template<typename T>
SharedHandle<T> getFirstDispatchedMessage() SharedHandle<T> getFirstDispatchedMessage()
{ {
SharedHandle<MockExtensionMessage> wrapmsg = SharedHandle<WrapExtBtMessage> wrapmsg =
dynamic_pointer_cast<MockExtensionMessage> dynamic_pointer_cast<WrapExtBtMessage>
(_dispatcher->messageQueue.front()); (_dispatcher->messageQueue.front());
SharedHandle<T> msg = dynamic_pointer_cast<T>(wrapmsg->_m); SharedHandle<T> msg = dynamic_pointer_cast<T>(wrapmsg->_m);

View File

@ -0,0 +1,76 @@
#include "UTMetadataRequestFactory.h"
#include <vector>
#include <deque>
#include <cppunit/extensions/HelperMacros.h>
#include "MockPieceStorage.h"
#include "DownloadContext.h"
#include "Peer.h"
#include "BtMessage.h"
#include "extension_message_test_helper.h"
#include "BtHandshakeMessage.h"
#include "ExtensionMessage.h"
#include "UTMetadataRequestTracker.h"
namespace aria2 {
class UTMetadataRequestFactoryTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(UTMetadataRequestFactoryTest);
CPPUNIT_TEST(testCreate);
CPPUNIT_TEST_SUITE_END();
public:
void testCreate();
class MockPieceStorage2:public MockPieceStorage {
public:
std::set<size_t> missingIndexes;
virtual SharedHandle<Piece> getMissingPiece(size_t index)
{
if(missingIndexes.find(index) != missingIndexes.end()) {
return SharedHandle<Piece>(new Piece(index, 0));
} else {
return SharedHandle<Piece>();
}
}
};
};
CPPUNIT_TEST_SUITE_REGISTRATION(UTMetadataRequestFactoryTest);
void UTMetadataRequestFactoryTest::testCreate()
{
UTMetadataRequestFactory factory;
SharedHandle<DownloadContext> dctx
(new DownloadContext(METADATA_PIECE_SIZE, METADATA_PIECE_SIZE*2));
factory.setDownloadContext(dctx);
SharedHandle<MockPieceStorage2> ps(new MockPieceStorage2());
ps->missingIndexes.insert(0);
ps->missingIndexes.insert(1);
SharedHandle<WrapExtBtMessageFactory> messageFactory
(new WrapExtBtMessageFactory());
factory.setBtMessageFactory(messageFactory);
SharedHandle<Peer> peer(new Peer("peer", 6880));
peer->allocateSessionResource(0, 0);
factory.setPeer(peer);
SharedHandle<UTMetadataRequestTracker> tracker
(new UTMetadataRequestTracker());
factory.setUTMetadataRequestTracker(tracker);
std::deque<SharedHandle<BtMessage> > msgs;
factory.create(msgs, 1, ps);
CPPUNIT_ASSERT_EQUAL((size_t)1, msgs.size());
msgs.clear();
ps->missingIndexes.clear();
factory.create(msgs, 1, ps);
CPPUNIT_ASSERT_EQUAL((size_t)0, msgs.size());
}
} // namespace aria2

View File

@ -0,0 +1,72 @@
#include "UTMetadataRequestTracker.h"
#include <cppunit/extensions/HelperMacros.h>
namespace aria2 {
class UTMetadataRequestTrackerTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(UTMetadataRequestTrackerTest);
CPPUNIT_TEST(testAdd);
CPPUNIT_TEST(testRemove);
CPPUNIT_TEST(testGetAllTrackedIndex);
CPPUNIT_TEST(testCount);
CPPUNIT_TEST(testAvail);
CPPUNIT_TEST_SUITE_END();
public:
void testAdd();
void testRemove();
void testGetAllTrackedIndex();
void testCount();
void testAvail();
};
CPPUNIT_TEST_SUITE_REGISTRATION(UTMetadataRequestTrackerTest);
void UTMetadataRequestTrackerTest::testAdd()
{
UTMetadataRequestTracker tr;
tr.add(1);
CPPUNIT_ASSERT(tr.tracks(1));
}
void UTMetadataRequestTrackerTest::testRemove()
{
UTMetadataRequestTracker tr;
tr.add(1);
tr.remove(1);
CPPUNIT_ASSERT(!tr.tracks(1));
}
void UTMetadataRequestTrackerTest::testGetAllTrackedIndex()
{
UTMetadataRequestTracker tr;
tr.add(1);
tr.add(2);
std::vector<size_t> indexes = tr.getAllTrackedIndex();
CPPUNIT_ASSERT_EQUAL((size_t)2, indexes.size());
CPPUNIT_ASSERT_EQUAL((size_t)1, indexes[0]);
CPPUNIT_ASSERT_EQUAL((size_t)2, indexes[1]);
}
void UTMetadataRequestTrackerTest::testCount()
{
UTMetadataRequestTracker tr;
tr.add(1);
tr.add(2);
CPPUNIT_ASSERT_EQUAL((size_t)2, tr.count());
}
void UTMetadataRequestTrackerTest::testAvail()
{
UTMetadataRequestTracker tr;
CPPUNIT_ASSERT_EQUAL((size_t)1, tr.avail());
tr.add(1);
CPPUNIT_ASSERT_EQUAL((size_t)0, tr.avail());
tr.add(2);
CPPUNIT_ASSERT_EQUAL((size_t)0, tr.avail());
}
} // namespace aria2

View File

@ -0,0 +1,22 @@
#ifndef _D_EXTENSION_MESSAGE_TEST_HELPER_H_
#define _D_EXTENSION_MESSAGE_TEST_HELPER_H_
#include "MockBtMessage.h"
#include "MockBtMessageFactory.h"
namespace aria2 {
typedef WrapBtMessage<ExtensionMessage> WrapExtBtMessage;
class WrapExtBtMessageFactory:public MockBtMessageFactory {
public:
virtual SharedHandle<BtMessage>
createBtExtendedMessage(const SharedHandle<ExtensionMessage>& extmsg)
{
return SharedHandle<BtMessage>(new WrapExtBtMessage(extmsg));
}
};
} // namespace aria2
#endif // _D_EXTENSION_MESSAGE_TEST_HELPER_H_