mirror of https://github.com/aria2/aria2
2010-06-18 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Introduced ValueBase class, which is a replacement of BDE. In this change ValueBase is used instead of BDE except DHT messages, UTMetadata messages and XML-RPC. They'll be replaced in the later commits. DownloadContext::_attrs is now ContextAttribute rather than BDE. * src/ActivePeerConnectionCommand.cc * src/AnnounceList.cc * src/AnnounceList.h * src/BtDependency.cc * src/BtRegistry.cc * src/BtSetup.cc * src/ConsoleStatCalc.cc * src/ContextAttribute.h * src/DefaultBtAnnounce.cc * src/DefaultBtInteractive.cc * src/DownloadContext.cc * src/DownloadContext.h * src/HandshakeExtensionMessage.cc * src/InitiateConnectionCommand.cc * src/LpdReceiveMessageCommand.cc * src/MSEHandshake.cc * src/Makefile.am * src/Makefile.in * src/PeerInteractionCommand.cc * src/PeerListProcessor.h * src/ProtocolDetector.cc * src/RequestGroup.cc * src/RequestGroupMan.cc * src/TorrentAttribute.h * src/TrackerWatcherCommand.cc * src/UTMetadataDataExtensionMessage.cc * src/UTMetadataPostDownloadHandler.cc * src/UTMetadataRequestExtensionMessage.cc * src/ValueBase.cc * src/ValueBase.h * src/XmlRpcMethodImpl.cc * src/XmlRpcMethodImpl.h * src/bencode2.cc * src/bencode2.h * src/bittorrent_helper.cc * src/bittorrent_helper.h * src/download_helper.cc * src/magnet.cc * src/magnet.h * test/AnnounceListTest.cc * test/Bencode2Test.cc * test/BencodeTest.cc * test/BittorrentHelperTest.cc * test/BtDependencyTest.cc * test/BtRegistryTest.cc * test/DefaultBtAnnounceTest.cc * test/DefaultBtProgressInfoFileTest.cc * test/HandshakeExtensionMessageTest.cc * test/MSEHandshakeTest.cc * test/MagnetTest.cc * test/Makefile.am * test/Makefile.in * test/RequestGroupManTest.cc * test/UTMetadataDataExtensionMessageTest.cc * test/UTMetadataPostDownloadHandlerTest.cc * test/UTMetadataRequestExtensionMessageTest.cc * test/ValueBaseTest.cc * test/XmlRpcMethodTest.ccpull/1/head
parent
98dc02192d
commit
8ba97188ce
66
ChangeLog
66
ChangeLog
|
@ -1,3 +1,69 @@
|
||||||
|
2010-06-18 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
|
Introduced ValueBase class, which is a replacement of BDE. In
|
||||||
|
this change ValueBase is used instead of BDE except DHT messages,
|
||||||
|
UTMetadata messages and XML-RPC. They'll be replaced in the later
|
||||||
|
commits. DownloadContext::_attrs is now ContextAttribute rather
|
||||||
|
than BDE.
|
||||||
|
* src/ActivePeerConnectionCommand.cc
|
||||||
|
* src/AnnounceList.cc
|
||||||
|
* src/AnnounceList.h
|
||||||
|
* src/BtDependency.cc
|
||||||
|
* src/BtRegistry.cc
|
||||||
|
* src/BtSetup.cc
|
||||||
|
* src/ConsoleStatCalc.cc
|
||||||
|
* src/ContextAttribute.h
|
||||||
|
* src/DefaultBtAnnounce.cc
|
||||||
|
* src/DefaultBtInteractive.cc
|
||||||
|
* src/DownloadContext.cc
|
||||||
|
* src/DownloadContext.h
|
||||||
|
* src/HandshakeExtensionMessage.cc
|
||||||
|
* src/InitiateConnectionCommand.cc
|
||||||
|
* src/LpdReceiveMessageCommand.cc
|
||||||
|
* src/MSEHandshake.cc
|
||||||
|
* src/Makefile.am
|
||||||
|
* src/Makefile.in
|
||||||
|
* src/PeerInteractionCommand.cc
|
||||||
|
* src/PeerListProcessor.h
|
||||||
|
* src/ProtocolDetector.cc
|
||||||
|
* src/RequestGroup.cc
|
||||||
|
* src/RequestGroupMan.cc
|
||||||
|
* src/TorrentAttribute.h
|
||||||
|
* src/TrackerWatcherCommand.cc
|
||||||
|
* src/UTMetadataDataExtensionMessage.cc
|
||||||
|
* src/UTMetadataPostDownloadHandler.cc
|
||||||
|
* src/UTMetadataRequestExtensionMessage.cc
|
||||||
|
* src/ValueBase.cc
|
||||||
|
* src/ValueBase.h
|
||||||
|
* src/XmlRpcMethodImpl.cc
|
||||||
|
* src/XmlRpcMethodImpl.h
|
||||||
|
* src/bencode2.cc
|
||||||
|
* src/bencode2.h
|
||||||
|
* src/bittorrent_helper.cc
|
||||||
|
* src/bittorrent_helper.h
|
||||||
|
* src/download_helper.cc
|
||||||
|
* src/magnet.cc
|
||||||
|
* src/magnet.h
|
||||||
|
* test/AnnounceListTest.cc
|
||||||
|
* test/Bencode2Test.cc
|
||||||
|
* test/BencodeTest.cc
|
||||||
|
* test/BittorrentHelperTest.cc
|
||||||
|
* test/BtDependencyTest.cc
|
||||||
|
* test/BtRegistryTest.cc
|
||||||
|
* test/DefaultBtAnnounceTest.cc
|
||||||
|
* test/DefaultBtProgressInfoFileTest.cc
|
||||||
|
* test/HandshakeExtensionMessageTest.cc
|
||||||
|
* test/MSEHandshakeTest.cc
|
||||||
|
* test/MagnetTest.cc
|
||||||
|
* test/Makefile.am
|
||||||
|
* test/Makefile.in
|
||||||
|
* test/RequestGroupManTest.cc
|
||||||
|
* test/UTMetadataDataExtensionMessageTest.cc
|
||||||
|
* test/UTMetadataPostDownloadHandlerTest.cc
|
||||||
|
* test/UTMetadataRequestExtensionMessageTest.cc
|
||||||
|
* test/ValueBaseTest.cc
|
||||||
|
* test/XmlRpcMethodTest.cc
|
||||||
|
|
||||||
2010-06-15 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
2010-06-15 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
Fixed assertion error if updateTransferStatFor is called with peer
|
Fixed assertion error if updateTransferStatFor is called with peer
|
||||||
|
|
|
@ -89,8 +89,8 @@ bool ActivePeerConnectionCommand::execute() {
|
||||||
_requestGroup->getMaxDownloadSpeedLimit();
|
_requestGroup->getMaxDownloadSpeedLimit();
|
||||||
const unsigned int maxUploadLimit = _requestGroup->getMaxUploadSpeedLimit();
|
const unsigned int maxUploadLimit = _requestGroup->getMaxUploadSpeedLimit();
|
||||||
unsigned int thresholdSpeed;
|
unsigned int thresholdSpeed;
|
||||||
if(_requestGroup->getDownloadContext()->
|
if(!bittorrent::getTorrentAttrs
|
||||||
getAttribute(bittorrent::BITTORRENT).containsKey(bittorrent::METADATA)) {
|
(_requestGroup->getDownloadContext())->metadata.empty()) {
|
||||||
thresholdSpeed =
|
thresholdSpeed =
|
||||||
_requestGroup->getOption()->getAsInt(PREF_BT_REQUEST_PEER_SPEED_LIMIT);
|
_requestGroup->getOption()->getAsInt(PREF_BT_REQUEST_PEER_SPEED_LIMIT);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -49,7 +49,8 @@ const std::string AnnounceList::STOPPED("stopped");
|
||||||
|
|
||||||
const std::string AnnounceList::COMPLETED("completed");
|
const std::string AnnounceList::COMPLETED("completed");
|
||||||
|
|
||||||
AnnounceList::AnnounceList(const BDE& announceList):
|
AnnounceList::AnnounceList
|
||||||
|
(const std::vector<std::vector<std::string> >& announceList):
|
||||||
_currentTrackerInitialized(false) {
|
_currentTrackerInitialized(false) {
|
||||||
reconfigure(announceList);
|
reconfigure(announceList);
|
||||||
}
|
}
|
||||||
|
@ -60,30 +61,19 @@ AnnounceList::AnnounceList
|
||||||
resetIterator();
|
resetIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnounceList::reconfigure(const BDE& announceList)
|
void AnnounceList::reconfigure
|
||||||
|
(const std::vector<std::vector<std::string> >& announceList)
|
||||||
{
|
{
|
||||||
if(announceList.isList()) {
|
for(std::vector<std::vector<std::string> >::const_iterator itr =
|
||||||
for(BDE::List::const_iterator itr = announceList.listBegin(),
|
announceList.begin(), eoi = announceList.end(); itr != eoi; ++itr) {
|
||||||
eoi = announceList.listEnd(); itr != eoi; ++itr) {
|
if((*itr).empty()) {
|
||||||
const BDE& elemList = *itr;
|
|
||||||
if(!elemList.isList()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::deque<std::string> urls;
|
std::deque<std::string> urls((*itr).begin(), (*itr).end());
|
||||||
for(BDE::List::const_iterator elemItr = elemList.listBegin(),
|
|
||||||
eoi2 = elemList.listEnd(); elemItr != eoi2; ++elemItr) {
|
|
||||||
const BDE& data = *elemItr;
|
|
||||||
if(data.isString()) {
|
|
||||||
urls.push_back(data.s());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!urls.empty()) {
|
|
||||||
SharedHandle<AnnounceTier> tier(new AnnounceTier(urls));
|
SharedHandle<AnnounceTier> tier(new AnnounceTier(urls));
|
||||||
_tiers.push_back(tier);
|
_tiers.push_back(tier);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resetIterator();
|
resetIterator();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnounceList::reconfigure(const std::string& url) {
|
void AnnounceList::reconfigure(const std::string& url) {
|
||||||
|
|
|
@ -38,11 +38,10 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "SharedHandle.h"
|
#include "SharedHandle.h"
|
||||||
#include "AnnounceTier.h"
|
#include "AnnounceTier.h"
|
||||||
|
#include "ValueBase.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
class BDE;
|
|
||||||
|
|
||||||
class AnnounceList {
|
class AnnounceList {
|
||||||
public:
|
public:
|
||||||
private:
|
private:
|
||||||
|
@ -56,10 +55,10 @@ private:
|
||||||
(const std::deque<SharedHandle<AnnounceTier> >::iterator& itr);
|
(const std::deque<SharedHandle<AnnounceTier> >::iterator& itr);
|
||||||
public:
|
public:
|
||||||
AnnounceList():_currentTrackerInitialized(false) {}
|
AnnounceList():_currentTrackerInitialized(false) {}
|
||||||
AnnounceList(const BDE& announceList);
|
AnnounceList(const std::vector<std::vector<std::string> >& announceList);
|
||||||
AnnounceList(const std::deque<SharedHandle<AnnounceTier> >& tiers);
|
AnnounceList(const std::deque<SharedHandle<AnnounceTier> >& tiers);
|
||||||
|
|
||||||
void reconfigure(const BDE& announceList);
|
void reconfigure(const std::vector<std::vector<std::string> >& announceList);
|
||||||
void reconfigure(const std::string& url);
|
void reconfigure(const std::string& url);
|
||||||
|
|
||||||
size_t countTier() const {
|
size_t countTier() const {
|
||||||
|
|
|
@ -85,8 +85,8 @@ bool BtDependency::resolve()
|
||||||
diskAdaptor->openExistingFile();
|
diskAdaptor->openExistingFile();
|
||||||
std::string content = util::toString(diskAdaptor);
|
std::string content = util::toString(diskAdaptor);
|
||||||
if(dependee->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
|
if(dependee->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
|
||||||
const BDE& attrs =
|
SharedHandle<TorrentAttribute> attrs =
|
||||||
dependee->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
|
bittorrent::getTorrentAttrs(dependee->getDownloadContext());
|
||||||
bittorrent::loadFromMemory
|
bittorrent::loadFromMemory
|
||||||
(bittorrent::metadata2Torrent(content, attrs), context, "default");
|
(bittorrent::metadata2Torrent(content, attrs), context, "default");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -56,9 +56,8 @@ BtRegistry::getDownloadContext(const std::string& infoHash) const
|
||||||
SharedHandle<DownloadContext> dctx;
|
SharedHandle<DownloadContext> dctx;
|
||||||
for(std::map<gid_t, BtObject>::const_iterator i = _pool.begin(),
|
for(std::map<gid_t, BtObject>::const_iterator i = _pool.begin(),
|
||||||
eoi = _pool.end(); i != eoi; ++i) {
|
eoi = _pool.end(); i != eoi; ++i) {
|
||||||
const BDE& attrs =
|
if(bittorrent::getTorrentAttrs((*i).second._downloadContext)->infoHash ==
|
||||||
(*i).second._downloadContext->getAttribute(bittorrent::BITTORRENT);
|
infoHash) {
|
||||||
if(attrs[bittorrent::INFO_HASH].s() == infoHash) {
|
|
||||||
dctx = (*i).second._downloadContext;
|
dctx = (*i).second._downloadContext;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
#include "FileAllocationEntry.h"
|
#include "FileAllocationEntry.h"
|
||||||
#include "CheckIntegrityEntry.h"
|
#include "CheckIntegrityEntry.h"
|
||||||
#include "ServerStatMan.h"
|
#include "ServerStatMan.h"
|
||||||
|
#include "DlAbortEx.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -86,9 +87,9 @@ void BtSetup::setup(std::vector<Command*>& commands,
|
||||||
if(!requestGroup->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)){
|
if(!requestGroup->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const BDE& torrentAttrs =
|
SharedHandle<TorrentAttribute> torrentAttrs =
|
||||||
requestGroup->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
|
bittorrent::getTorrentAttrs(requestGroup->getDownloadContext());
|
||||||
bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA);
|
bool metadataGetMode = torrentAttrs->metadata.empty();
|
||||||
BtObject btObject = e->getBtRegistry()->get(requestGroup->getGID());
|
BtObject btObject = e->getBtRegistry()->get(requestGroup->getGID());
|
||||||
SharedHandle<PieceStorage> pieceStorage = btObject._pieceStorage;
|
SharedHandle<PieceStorage> pieceStorage = btObject._pieceStorage;
|
||||||
SharedHandle<PeerStorage> peerStorage = btObject._peerStorage;
|
SharedHandle<PeerStorage> peerStorage = btObject._peerStorage;
|
||||||
|
@ -125,7 +126,7 @@ void BtSetup::setup(std::vector<Command*>& commands,
|
||||||
commands.push_back(c);
|
commands.push_back(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) &&
|
if((metadataGetMode || !torrentAttrs->privateTorrent) &&
|
||||||
DHTSetup::initialized()) {
|
DHTSetup::initialized()) {
|
||||||
DHTGetPeersCommand* command =
|
DHTGetPeersCommand* command =
|
||||||
new DHTGetPeersCommand(e->newCUID(), requestGroup, e);
|
new DHTGetPeersCommand(e->newCUID(), requestGroup, e);
|
||||||
|
@ -179,7 +180,7 @@ void BtSetup::setup(std::vector<Command*>& commands,
|
||||||
btRuntime->setListenPort(listenCommand->getPort());
|
btRuntime->setListenPort(listenCommand->getPort());
|
||||||
}
|
}
|
||||||
if(option->getAsBool(PREF_BT_ENABLE_LPD) &&
|
if(option->getAsBool(PREF_BT_ENABLE_LPD) &&
|
||||||
(metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0)) {
|
(metadataGetMode || !torrentAttrs->privateTorrent)) {
|
||||||
if(LpdReceiveMessageCommand::getNumInstance() == 0) {
|
if(LpdReceiveMessageCommand::getNumInstance() == 0) {
|
||||||
_logger->info("Initializing LpdMessageReceiver.");
|
_logger->info("Initializing LpdMessageReceiver.");
|
||||||
SharedHandle<LpdMessageReceiver> receiver
|
SharedHandle<LpdMessageReceiver> receiver
|
||||||
|
|
|
@ -89,8 +89,7 @@ static void printProgress
|
||||||
|
|
||||||
#ifdef ENABLE_BITTORRENT
|
#ifdef ENABLE_BITTORRENT
|
||||||
if(rg->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT) &&
|
if(rg->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT) &&
|
||||||
rg->getDownloadContext()->getAttribute(bittorrent::BITTORRENT)
|
!bittorrent::getTorrentAttrs(rg->getDownloadContext())->metadata.empty() &&
|
||||||
.containsKey(bittorrent::METADATA) &&
|
|
||||||
rg->downloadFinished()) {
|
rg->downloadFinished()) {
|
||||||
o << "SEEDING" << "(" << "ratio:";
|
o << "SEEDING" << "(" << "ratio:";
|
||||||
if(rg->getCompletedLength() > 0) {
|
if(rg->getCompletedLength() > 0) {
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 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_CONTEXT_ATTRIBUTE_H
|
||||||
|
#define D_CONTEXT_ATTRIBUTE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
struct ContextAttribute {
|
||||||
|
virtual ~ContextAttribute() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // D_CONTEXT_ATTRIBUTE_H
|
|
@ -50,7 +50,7 @@
|
||||||
#include "StringFormat.h"
|
#include "StringFormat.h"
|
||||||
#include "A2STR.h"
|
#include "A2STR.h"
|
||||||
#include "Request.h"
|
#include "Request.h"
|
||||||
#include "bencode.h"
|
#include "bencode2.h"
|
||||||
#include "bittorrent_helper.h"
|
#include "bittorrent_helper.h"
|
||||||
#include "wallclock.h"
|
#include "wallclock.h"
|
||||||
|
|
||||||
|
@ -67,9 +67,7 @@ DefaultBtAnnounce::DefaultBtAnnounce
|
||||||
_userDefinedInterval(0),
|
_userDefinedInterval(0),
|
||||||
_complete(0),
|
_complete(0),
|
||||||
_incomplete(0),
|
_incomplete(0),
|
||||||
_announceList
|
_announceList(bittorrent::getTorrentAttrs(downloadContext)->announceList),
|
||||||
(downloadContext->getAttribute
|
|
||||||
(bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST]),
|
|
||||||
_option(option),
|
_option(option),
|
||||||
_logger(LogFactory::getInstance()),
|
_logger(LogFactory::getInstance()),
|
||||||
_randomizer(SimpleRandomizer::getInstance())
|
_randomizer(SimpleRandomizer::getInstance())
|
||||||
|
@ -219,37 +217,38 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse,
|
||||||
if(_logger->debug()) {
|
if(_logger->debug()) {
|
||||||
_logger->debug("Now processing tracker response.");
|
_logger->debug("Now processing tracker response.");
|
||||||
}
|
}
|
||||||
const BDE dict =
|
SharedHandle<ValueBase> decodedValue =
|
||||||
bencode::decode(trackerResponse, trackerResponseLength);
|
bencode2::decode(trackerResponse, trackerResponseLength);
|
||||||
if(!dict.isDict()) {
|
const Dict* dict = asDict(decodedValue);
|
||||||
|
if(!dict) {
|
||||||
throw DL_ABORT_EX(MSG_NULL_TRACKER_RESPONSE);
|
throw DL_ABORT_EX(MSG_NULL_TRACKER_RESPONSE);
|
||||||
}
|
}
|
||||||
const BDE& failure = dict[BtAnnounce::FAILURE_REASON];
|
const String* failure = asString(dict->get(BtAnnounce::FAILURE_REASON));
|
||||||
if(failure.isString()) {
|
if(failure) {
|
||||||
throw DL_ABORT_EX
|
throw DL_ABORT_EX
|
||||||
(StringFormat(EX_TRACKER_FAILURE, failure.s().c_str()).str());
|
(StringFormat(EX_TRACKER_FAILURE, failure->s().c_str()).str());
|
||||||
}
|
}
|
||||||
const BDE& warn = dict[BtAnnounce::WARNING_MESSAGE];
|
const String* warn = asString(dict->get(BtAnnounce::WARNING_MESSAGE));
|
||||||
if(warn.isString()) {
|
if(warn) {
|
||||||
_logger->warn(MSG_TRACKER_WARNING_MESSAGE, warn.s().c_str());
|
_logger->warn(MSG_TRACKER_WARNING_MESSAGE, warn->s().c_str());
|
||||||
}
|
}
|
||||||
const BDE& tid = dict[BtAnnounce::TRACKER_ID];
|
const String* tid = asString(dict->get(BtAnnounce::TRACKER_ID));
|
||||||
if(tid.isString()) {
|
if(tid) {
|
||||||
_trackerId = tid.s();
|
_trackerId = tid->s();
|
||||||
if(_logger->debug()) {
|
if(_logger->debug()) {
|
||||||
_logger->debug("Tracker ID:%s", _trackerId.c_str());
|
_logger->debug("Tracker ID:%s", _trackerId.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const BDE& ival = dict[BtAnnounce::INTERVAL];
|
const Integer* ival = asInteger(dict->get(BtAnnounce::INTERVAL));
|
||||||
if(ival.isInteger() && ival.i() > 0) {
|
if(ival && ival->i() > 0) {
|
||||||
_interval = ival.i();
|
_interval = ival->i();
|
||||||
if(_logger->debug()) {
|
if(_logger->debug()) {
|
||||||
_logger->debug("Interval:%d", _interval);
|
_logger->debug("Interval:%d", _interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const BDE& mival = dict[BtAnnounce::MIN_INTERVAL];
|
const Integer* mival = asInteger(dict->get(BtAnnounce::MIN_INTERVAL));
|
||||||
if(mival.isInteger() && mival.i() > 0) {
|
if(mival && mival->i() > 0) {
|
||||||
_minInterval = mival.i();
|
_minInterval = mival->i();
|
||||||
if(_logger->debug()) {
|
if(_logger->debug()) {
|
||||||
_logger->debug("Min interval:%d", _minInterval);
|
_logger->debug("Min interval:%d", _minInterval);
|
||||||
}
|
}
|
||||||
|
@ -258,22 +257,22 @@ DefaultBtAnnounce::processAnnounceResponse(const unsigned char* trackerResponse,
|
||||||
// Use interval as a minInterval if minInterval is not supplied.
|
// Use interval as a minInterval if minInterval is not supplied.
|
||||||
_minInterval = _interval;
|
_minInterval = _interval;
|
||||||
}
|
}
|
||||||
const BDE& comp = dict[BtAnnounce::COMPLETE];
|
const Integer* comp = asInteger(dict->get(BtAnnounce::COMPLETE));
|
||||||
if(comp.isInteger()) {
|
if(comp) {
|
||||||
_complete = comp.i();
|
_complete = comp->i();
|
||||||
if(_logger->debug()) {
|
if(_logger->debug()) {
|
||||||
_logger->debug("Complete:%d", _complete);
|
_logger->debug("Complete:%d", _complete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const BDE& incomp = dict[BtAnnounce::INCOMPLETE];
|
const Integer* incomp = asInteger(dict->get(BtAnnounce::INCOMPLETE));
|
||||||
if(incomp.isInteger()) {
|
if(incomp) {
|
||||||
_incomplete = incomp.i();
|
_incomplete = incomp->i();
|
||||||
if(_logger->debug()) {
|
if(_logger->debug()) {
|
||||||
_logger->debug("Incomplete:%d", _incomplete);
|
_logger->debug("Incomplete:%d", _incomplete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const BDE& peerData = dict[BtAnnounce::PEERS];
|
const SharedHandle<ValueBase>& peerData = dict->get(BtAnnounce::PEERS);
|
||||||
if(peerData.isNone()) {
|
if(peerData.isNull()) {
|
||||||
_logger->info(MSG_NO_PEER_LIST_RECEIVED);
|
_logger->info(MSG_NO_PEER_LIST_RECEIVED);
|
||||||
} else {
|
} else {
|
||||||
if(!_btRuntime->isHalt() && _btRuntime->lessThanMinPeers()) {
|
if(!_btRuntime->isHalt() && _btRuntime->lessThanMinPeers()) {
|
||||||
|
|
|
@ -202,9 +202,10 @@ void DefaultBtInteractive::addHandshakeExtendedMessageToQueue()
|
||||||
m->setClientVersion(CLIENT_ARIA2);
|
m->setClientVersion(CLIENT_ARIA2);
|
||||||
m->setTCPPort(_btRuntime->getListenPort());
|
m->setTCPPort(_btRuntime->getListenPort());
|
||||||
m->setExtensions(_extensionMessageRegistry->getExtensions());
|
m->setExtensions(_extensionMessageRegistry->getExtensions());
|
||||||
const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs =
|
||||||
if(attrs.containsKey(bittorrent::METADATA)) {
|
bittorrent::getTorrentAttrs(_downloadContext);
|
||||||
m->setMetadataSize(attrs[bittorrent::METADATA_SIZE].i());
|
if(!attrs->metadata.empty()) {
|
||||||
|
m->setMetadataSize(attrs->metadataSize);
|
||||||
}
|
}
|
||||||
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
|
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
|
||||||
_dispatcher->addMessageToQueue(msg);
|
_dispatcher->addMessageToQueue(msg);
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "StringFormat.h"
|
#include "StringFormat.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "wallclock.h"
|
#include "wallclock.h"
|
||||||
|
#include "DlAbortEx.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -138,36 +139,33 @@ void DownloadContext::setFileFilter(IntSequence seq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadContext::ensureAttrs()
|
void DownloadContext::setAttribute
|
||||||
|
(const std::string& key, const SharedHandle<ContextAttribute>& value)
|
||||||
{
|
{
|
||||||
if(_attrs.isNone()) {
|
std::map<std::string, SharedHandle<ContextAttribute> >::value_type p =
|
||||||
_attrs = BDE::dict();
|
std::make_pair(key, value);
|
||||||
|
std::pair<std::map<std::string, SharedHandle<ContextAttribute> >::iterator,
|
||||||
|
bool> r = _attrs.insert(p);
|
||||||
|
if(!r.second) {
|
||||||
|
(*r.first).second = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadContext::setAttribute(const std::string& key, const BDE& value)
|
const SharedHandle<ContextAttribute>& DownloadContext::getAttribute
|
||||||
|
(const std::string& key)
|
||||||
{
|
{
|
||||||
ensureAttrs();
|
std::map<std::string, SharedHandle<ContextAttribute> >::const_iterator itr =
|
||||||
_attrs[key] = value;
|
_attrs.find(key);
|
||||||
}
|
if(itr == _attrs.end()) {
|
||||||
|
|
||||||
BDE& DownloadContext::getAttribute(const std::string& key)
|
|
||||||
{
|
|
||||||
ensureAttrs();
|
|
||||||
if(_attrs.containsKey(key)) {
|
|
||||||
return _attrs[key];
|
|
||||||
} else {
|
|
||||||
throw DL_ABORT_EX(StringFormat("No attribute named %s", key.c_str()).str());
|
throw DL_ABORT_EX(StringFormat("No attribute named %s", key.c_str()).str());
|
||||||
|
} else {
|
||||||
|
return (*itr).second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DownloadContext::hasAttribute(const std::string& key) const
|
bool DownloadContext::hasAttribute(const std::string& key) const
|
||||||
{
|
{
|
||||||
if(_attrs.isNone()) {
|
return _attrs.count(key) == 1;
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return _attrs.containsKey(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadContext::releaseRuntimeResource()
|
void DownloadContext::releaseRuntimeResource()
|
||||||
|
|
|
@ -45,9 +45,10 @@
|
||||||
#include "Signature.h"
|
#include "Signature.h"
|
||||||
#include "TimerA2.h"
|
#include "TimerA2.h"
|
||||||
#include "A2STR.h"
|
#include "A2STR.h"
|
||||||
#include "BDE.h"
|
#include "ValueBase.h"
|
||||||
#include "IntSequence.h"
|
#include "IntSequence.h"
|
||||||
#include "FileEntry.h"
|
#include "FileEntry.h"
|
||||||
|
#include "TorrentAttribute.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -76,15 +77,13 @@ private:
|
||||||
|
|
||||||
RequestGroup* _ownerRequestGroup;
|
RequestGroup* _ownerRequestGroup;
|
||||||
|
|
||||||
BDE _attrs;
|
std::map<std::string, SharedHandle<ContextAttribute> > _attrs;
|
||||||
|
|
||||||
Timer _downloadStartTime;
|
Timer _downloadStartTime;
|
||||||
|
|
||||||
Timer _downloadStopTime;
|
Timer _downloadStopTime;
|
||||||
|
|
||||||
SharedHandle<Signature> _signature;
|
SharedHandle<Signature> _signature;
|
||||||
|
|
||||||
void ensureAttrs();
|
|
||||||
public:
|
public:
|
||||||
DownloadContext();
|
DownloadContext();
|
||||||
|
|
||||||
|
@ -224,9 +223,10 @@ public:
|
||||||
// this function.
|
// this function.
|
||||||
void setFilePathWithIndex(size_t index, const std::string& path);
|
void setFilePathWithIndex(size_t index, const std::string& path);
|
||||||
|
|
||||||
void setAttribute(const std::string& key, const BDE& value);
|
void setAttribute
|
||||||
|
(const std::string& key, const SharedHandle<ContextAttribute>& value);
|
||||||
|
|
||||||
BDE& getAttribute(const std::string& key);
|
const SharedHandle<ContextAttribute>& getAttribute(const std::string& key);
|
||||||
|
|
||||||
bool hasAttribute(const std::string& key) const;
|
bool hasAttribute(const std::string& key) const;
|
||||||
|
|
||||||
|
|
|
@ -110,21 +110,21 @@ void HandshakeExtensionMessage::doReceivedAction()
|
||||||
const std::map<std::string, uint8_t>::value_type& vt = *itr;
|
const std::map<std::string, uint8_t>::value_type& vt = *itr;
|
||||||
_peer->setExtension(vt.first, vt.second);
|
_peer->setExtension(vt.first, vt.second);
|
||||||
}
|
}
|
||||||
BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs =
|
||||||
if(!attrs.containsKey(bittorrent::METADATA) &&
|
bittorrent::getTorrentAttrs(_dctx);
|
||||||
!_peer->getExtensionMessageID("ut_metadata")) {
|
if(attrs->metadata.empty() && !_peer->getExtensionMessageID("ut_metadata")) {
|
||||||
// TODO In metadataGetMode, if peer don't support metadata
|
// TODO In metadataGetMode, if peer don't support metadata
|
||||||
// transfer, should we drop connection? There is a possibility
|
// transfer, should we drop connection? There is a possibility
|
||||||
// that peer can still tell us peers using PEX.
|
// that peer can still tell us peers using PEX.
|
||||||
throw DL_ABORT_EX("Peer doesn't support ut_metadata extension. Goodbye.");
|
throw DL_ABORT_EX("Peer doesn't support ut_metadata extension. Goodbye.");
|
||||||
}
|
}
|
||||||
if(_metadataSize > 0) {
|
if(_metadataSize > 0) {
|
||||||
if(attrs.containsKey(bittorrent::METADATA_SIZE)) {
|
if(attrs->metadataSize) {
|
||||||
if(_metadataSize != (size_t)attrs[bittorrent::METADATA_SIZE].i()) {
|
if(_metadataSize != attrs->metadataSize) {
|
||||||
throw DL_ABORT_EX("Wrong metadata_size. Which one is correct!?");
|
throw DL_ABORT_EX("Wrong metadata_size. Which one is correct!?");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
attrs[bittorrent::METADATA_SIZE] = _metadataSize;
|
attrs->metadataSize = _metadataSize;
|
||||||
_dctx->getFirstFileEntry()->setLength(_metadataSize);
|
_dctx->getFirstFileEntry()->setLength(_metadataSize);
|
||||||
_dctx->markTotalLengthIsKnown();
|
_dctx->markTotalLengthIsKnown();
|
||||||
_dctx->getOwnerRequestGroup()->initPieceStorage();
|
_dctx->getOwnerRequestGroup()->initPieceStorage();
|
||||||
|
@ -133,7 +133,7 @@ void HandshakeExtensionMessage::doReceivedAction()
|
||||||
_dctx->getOwnerRequestGroup()->getPieceStorage();
|
_dctx->getOwnerRequestGroup()->getPieceStorage();
|
||||||
pieceStorage->setEndGamePieceNum(0);
|
pieceStorage->setEndGamePieceNum(0);
|
||||||
}
|
}
|
||||||
} else if(!attrs.containsKey(bittorrent::METADATA)) {
|
} else if(attrs->metadata.empty()) {
|
||||||
throw DL_ABORT_EX("Peer didn't provide metadata_size."
|
throw DL_ABORT_EX("Peer didn't provide metadata_size."
|
||||||
" It seems that it doesn't have whole metadata.");
|
" It seems that it doesn't have whole metadata.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
#include "ServerStatMan.h"
|
#include "ServerStatMan.h"
|
||||||
#include "FileAllocationEntry.h"
|
#include "FileAllocationEntry.h"
|
||||||
#include "CheckIntegrityEntry.h"
|
#include "CheckIntegrityEntry.h"
|
||||||
|
#include "RecoverableException.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
|
|
@ -100,16 +100,13 @@ bool LpdReceiveMessageCommand::execute()
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const BDE& torrentAttrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
if(bittorrent::getTorrentAttrs(dctx)->privateTorrent) {
|
||||||
if(torrentAttrs.containsKey(bittorrent::PRIVATE)) {
|
|
||||||
if(torrentAttrs[bittorrent::PRIVATE].i() == 1) {
|
|
||||||
if(getLogger()->debug()) {
|
if(getLogger()->debug()) {
|
||||||
getLogger()->debug
|
getLogger()->debug
|
||||||
("Ignore LPD message because the torrent is private.");
|
("Ignore LPD message because the torrent is private.");
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
RequestGroup* group = dctx->getOwnerRequestGroup();
|
RequestGroup* group = dctx->getOwnerRequestGroup();
|
||||||
assert(group);
|
assert(group);
|
||||||
BtObject btobj = reg->get(group->getGID());
|
BtObject btobj = reg->get(group->getGID());
|
||||||
|
|
|
@ -476,14 +476,13 @@ bool MSEHandshake::receiveReceiverHashAndPadCLength
|
||||||
downloadContexts.begin(), eoi = downloadContexts.end();
|
downloadContexts.begin(), eoi = downloadContexts.end();
|
||||||
i != eoi; ++i) {
|
i != eoi; ++i) {
|
||||||
unsigned char md[20];
|
unsigned char md[20];
|
||||||
const BDE& torrentAttrs = (*i)->getAttribute(bittorrent::BITTORRENT);
|
const unsigned char* infohash = bittorrent::getInfoHash(*i);
|
||||||
createReq23Hash(md, torrentAttrs[bittorrent::INFO_HASH].uc());
|
createReq23Hash(md, infohash);
|
||||||
if(memcmp(md, rbufptr, sizeof(md)) == 0) {
|
if(memcmp(md, rbufptr, sizeof(md)) == 0) {
|
||||||
if(_logger->debug()) {
|
if(_logger->debug()) {
|
||||||
_logger->debug("CUID#%s - info hash found: %s",
|
_logger->debug("CUID#%s - info hash found: %s",
|
||||||
util::itos(_cuid).c_str(),
|
util::itos(_cuid).c_str(),
|
||||||
util::toHex
|
util::toHex(infohash, INFO_HASH_LENGTH).c_str());
|
||||||
(torrentAttrs[bittorrent::INFO_HASH].s()).c_str());
|
|
||||||
}
|
}
|
||||||
downloadContext = *i;
|
downloadContext = *i;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -202,7 +202,11 @@ SRCS = Socket.h\
|
||||||
MetadataInfo.cc MetadataInfo.h\
|
MetadataInfo.cc MetadataInfo.h\
|
||||||
SessionSerializer.cc SessionSerializer.h\
|
SessionSerializer.cc SessionSerializer.h\
|
||||||
Event.h\
|
Event.h\
|
||||||
timespec.h
|
timespec.h\
|
||||||
|
ValueBase.cc ValueBase.h\
|
||||||
|
bencode2.cc bencode2.h\
|
||||||
|
ContextAttribute.h\
|
||||||
|
TorrentAttribute.h
|
||||||
|
|
||||||
if ENABLE_XML_RPC
|
if ENABLE_XML_RPC
|
||||||
SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\
|
SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\
|
||||||
|
|
|
@ -437,7 +437,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
|
||||||
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
|
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
|
||||||
download_helper.cc download_helper.h MetadataInfo.cc \
|
download_helper.cc download_helper.h MetadataInfo.cc \
|
||||||
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
|
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
|
||||||
Event.h timespec.h XmlRpcRequestParserController.cc \
|
Event.h timespec.h ValueBase.cc ValueBase.h bencode2.cc \
|
||||||
|
bencode2.h ContextAttribute.h TorrentAttribute.h \
|
||||||
|
XmlRpcRequestParserController.cc \
|
||||||
XmlRpcRequestParserController.h \
|
XmlRpcRequestParserController.h \
|
||||||
XmlRpcRequestParserStateMachine.cc \
|
XmlRpcRequestParserStateMachine.cc \
|
||||||
XmlRpcRequestParserStateMachine.h XmlRpcRequestParserState.h \
|
XmlRpcRequestParserStateMachine.h XmlRpcRequestParserState.h \
|
||||||
|
@ -873,7 +875,8 @@ am__objects_32 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
|
||||||
LongestSequencePieceSelector.$(OBJEXT) bitfield.$(OBJEXT) \
|
LongestSequencePieceSelector.$(OBJEXT) bitfield.$(OBJEXT) \
|
||||||
BDE.$(OBJEXT) CreateRequestCommand.$(OBJEXT) \
|
BDE.$(OBJEXT) CreateRequestCommand.$(OBJEXT) \
|
||||||
download_helper.$(OBJEXT) MetadataInfo.$(OBJEXT) \
|
download_helper.$(OBJEXT) MetadataInfo.$(OBJEXT) \
|
||||||
SessionSerializer.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
|
SessionSerializer.$(OBJEXT) ValueBase.$(OBJEXT) \
|
||||||
|
bencode2.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
|
||||||
$(am__objects_3) $(am__objects_4) $(am__objects_5) \
|
$(am__objects_3) $(am__objects_4) $(am__objects_5) \
|
||||||
$(am__objects_6) $(am__objects_7) $(am__objects_8) \
|
$(am__objects_6) $(am__objects_7) $(am__objects_8) \
|
||||||
$(am__objects_9) $(am__objects_10) $(am__objects_11) \
|
$(am__objects_9) $(am__objects_10) $(am__objects_11) \
|
||||||
|
@ -1213,17 +1216,19 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
|
||||||
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
|
CreateRequestCommand.h DownloadResultCode.h wallclock.h \
|
||||||
download_helper.cc download_helper.h MetadataInfo.cc \
|
download_helper.cc download_helper.h MetadataInfo.cc \
|
||||||
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
|
MetadataInfo.h SessionSerializer.cc SessionSerializer.h \
|
||||||
Event.h timespec.h $(am__append_1) $(am__append_2) \
|
Event.h timespec.h ValueBase.cc ValueBase.h bencode2.cc \
|
||||||
$(am__append_3) $(am__append_4) $(am__append_5) \
|
bencode2.h ContextAttribute.h TorrentAttribute.h \
|
||||||
$(am__append_6) $(am__append_7) $(am__append_8) \
|
$(am__append_1) $(am__append_2) $(am__append_3) \
|
||||||
$(am__append_9) $(am__append_10) $(am__append_11) \
|
$(am__append_4) $(am__append_5) $(am__append_6) \
|
||||||
$(am__append_12) $(am__append_13) $(am__append_14) \
|
$(am__append_7) $(am__append_8) $(am__append_9) \
|
||||||
$(am__append_15) $(am__append_16) $(am__append_17) \
|
$(am__append_10) $(am__append_11) $(am__append_12) \
|
||||||
$(am__append_18) $(am__append_19) $(am__append_20) \
|
$(am__append_13) $(am__append_14) $(am__append_15) \
|
||||||
$(am__append_21) $(am__append_22) $(am__append_23) \
|
$(am__append_16) $(am__append_17) $(am__append_18) \
|
||||||
$(am__append_24) $(am__append_25) $(am__append_26) \
|
$(am__append_19) $(am__append_20) $(am__append_21) \
|
||||||
$(am__append_27) $(am__append_28) $(am__append_29) \
|
$(am__append_22) $(am__append_23) $(am__append_24) \
|
||||||
$(am__append_30) $(am__append_31)
|
$(am__append_25) $(am__append_26) $(am__append_27) \
|
||||||
|
$(am__append_28) $(am__append_29) $(am__append_30) \
|
||||||
|
$(am__append_31)
|
||||||
noinst_LIBRARIES = libaria2c.a
|
noinst_LIBRARIES = libaria2c.a
|
||||||
libaria2c_a_SOURCES = $(SRCS)
|
libaria2c_a_SOURCES = $(SRCS)
|
||||||
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
|
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
|
||||||
|
@ -1612,6 +1617,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessage.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessage.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParser.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParser.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ValueBase.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML2SAXMetalinkProcessor.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XML2SAXMetalinkProcessor.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2XmlRpcRequestProcessor.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2XmlRpcRequestProcessor.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcElements.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcElements.Po@am__quote@
|
||||||
|
@ -1626,6 +1632,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asctime_r.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asctime_r.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bencode2.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitfield.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitfield.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bittorrent_helper.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bittorrent_helper.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_gettime_mingw.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock_gettime_mingw.Po@am__quote@
|
||||||
|
|
|
@ -102,11 +102,9 @@ PeerInteractionCommand::PeerInteractionCommand
|
||||||
setWriteCheckSocket(getSocket());
|
setWriteCheckSocket(getSocket());
|
||||||
setTimeout(getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT));
|
setTimeout(getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT));
|
||||||
}
|
}
|
||||||
|
SharedHandle<TorrentAttribute> torrentAttrs =
|
||||||
const BDE& torrentAttrs =
|
bittorrent::getTorrentAttrs(_requestGroup->getDownloadContext());
|
||||||
_requestGroup->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
|
bool metadataGetMode = torrentAttrs->metadata.empty();
|
||||||
|
|
||||||
bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA);
|
|
||||||
|
|
||||||
SharedHandle<ExtensionMessageRegistry> exMsgRegistry
|
SharedHandle<ExtensionMessageRegistry> exMsgRegistry
|
||||||
(new ExtensionMessageRegistry());
|
(new ExtensionMessageRegistry());
|
||||||
|
@ -189,7 +187,7 @@ PeerInteractionCommand::PeerInteractionCommand
|
||||||
(getOption()->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL));
|
(getOption()->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL));
|
||||||
btInteractive->setRequestGroupMan(getDownloadEngine()->getRequestGroupMan());
|
btInteractive->setRequestGroupMan(getDownloadEngine()->getRequestGroupMan());
|
||||||
btInteractive->setBtMessageFactory(factory);
|
btInteractive->setBtMessageFactory(factory);
|
||||||
if((metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) &&
|
if((metadataGetMode || !torrentAttrs->privateTorrent) &&
|
||||||
!getPeer()->isLocalPeer()) {
|
!getPeer()->isLocalPeer()) {
|
||||||
if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) {
|
if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) {
|
||||||
btInteractive->setUTPexEnabled(true);
|
btInteractive->setUTPexEnabled(true);
|
||||||
|
|
|
@ -42,11 +42,70 @@
|
||||||
#include "a2netcompat.h"
|
#include "a2netcompat.h"
|
||||||
#include "bencode.h"
|
#include "bencode.h"
|
||||||
#include "Peer.h"
|
#include "Peer.h"
|
||||||
|
#include "ValueBase.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
class PeerListProcessor {
|
class PeerListProcessor {
|
||||||
|
private:
|
||||||
|
template<typename OutputIterator>
|
||||||
|
class PeerListValueBaseVisitor:public ValueBaseVisitor {
|
||||||
|
OutputIterator dest_;
|
||||||
|
public:
|
||||||
|
PeerListValueBaseVisitor(OutputIterator dest):dest_(dest) {}
|
||||||
|
|
||||||
|
virtual void visit(const String& peerData)
|
||||||
|
{
|
||||||
|
size_t length = peerData.s().size();
|
||||||
|
if(length%6 == 0) {
|
||||||
|
const char* base = peerData.s().data();
|
||||||
|
for(size_t i = 0; i < length; i += 6) {
|
||||||
|
struct in_addr in;
|
||||||
|
memcpy(&in.s_addr, base+i, sizeof(uint32_t));
|
||||||
|
std::string ipaddr = inet_ntoa(in);
|
||||||
|
uint16_t port_nworder;
|
||||||
|
memcpy(&port_nworder, base+i+4, sizeof(uint16_t));
|
||||||
|
uint16_t port = ntohs(port_nworder);
|
||||||
|
*dest_ = SharedHandle<Peer>(new Peer(ipaddr, port));
|
||||||
|
++dest_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const Integer& v) {}
|
||||||
|
|
||||||
|
virtual void visit(const List& peerData)
|
||||||
|
{
|
||||||
|
for(List::ValueType::const_iterator itr = peerData.begin(),
|
||||||
|
eoi = peerData.end(); itr != eoi; ++itr) {
|
||||||
|
const Dict* peerDict = asDict(*itr);
|
||||||
|
if(!peerDict) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
static const std::string IP = "ip";
|
||||||
|
static const std::string PORT = "port";
|
||||||
|
const String* ip = asString(peerDict->get(IP));
|
||||||
|
const Integer* port = asInteger(peerDict->get(PORT));
|
||||||
|
if(!ip || !port || !(0 < port->i() && port->i() < 65536)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
*dest_ = SharedHandle<Peer>(new Peer(ip->s(), port->i()));
|
||||||
|
++dest_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const Dict& v) {}
|
||||||
|
};
|
||||||
public:
|
public:
|
||||||
|
template<typename OutputIterator>
|
||||||
|
void extractPeer(const SharedHandle<ValueBase>& peerData, OutputIterator dest)
|
||||||
|
{
|
||||||
|
if(!peerData.isNull()) {
|
||||||
|
PeerListValueBaseVisitor<OutputIterator> visitor(dest);
|
||||||
|
peerData->accept(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename OutputIterator>
|
template<typename OutputIterator>
|
||||||
void extractPeer(const BDE& peerData, OutputIterator dest)
|
void extractPeer(const BDE& peerData, OutputIterator dest)
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "Request.h"
|
#include "Request.h"
|
||||||
#include "File.h"
|
#include "File.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "RecoverableException.h"
|
||||||
#ifdef ENABLE_BITTORRENT
|
#ifdef ENABLE_BITTORRENT
|
||||||
# include "bittorrent_helper.h"
|
# include "bittorrent_helper.h"
|
||||||
#endif // ENABLE_BITTORRENT
|
#endif // ENABLE_BITTORRENT
|
||||||
|
|
|
@ -202,16 +202,15 @@ void RequestGroup::createInitialCommand
|
||||||
#ifdef ENABLE_BITTORRENT
|
#ifdef ENABLE_BITTORRENT
|
||||||
{
|
{
|
||||||
if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) {
|
if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) {
|
||||||
const BDE& torrentAttrs =
|
SharedHandle<TorrentAttribute> torrentAttrs =
|
||||||
_downloadContext->getAttribute(bittorrent::BITTORRENT);
|
bittorrent::getTorrentAttrs(_downloadContext);
|
||||||
bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA);
|
bool metadataGetMode = torrentAttrs->metadata.empty();
|
||||||
if(_option->getAsBool(PREF_DRY_RUN)) {
|
if(_option->getAsBool(PREF_DRY_RUN)) {
|
||||||
throw DOWNLOAD_FAILURE_EXCEPTION
|
throw DOWNLOAD_FAILURE_EXCEPTION
|
||||||
("Cancel BitTorrent download in dry-run context.");
|
("Cancel BitTorrent download in dry-run context.");
|
||||||
}
|
}
|
||||||
SharedHandle<BtRegistry> btRegistry = e->getBtRegistry();
|
SharedHandle<BtRegistry> btRegistry = e->getBtRegistry();
|
||||||
if(!btRegistry->getDownloadContext
|
if(!btRegistry->getDownloadContext(torrentAttrs->infoHash).isNull()) {
|
||||||
(torrentAttrs[bittorrent::INFO_HASH].s()).isNull()) {
|
|
||||||
// TODO If metadataGetMode == false and each FileEntry has
|
// TODO If metadataGetMode == false and each FileEntry has
|
||||||
// URI, then go without BT.
|
// URI, then go without BT.
|
||||||
throw DOWNLOAD_FAILURE_EXCEPTION
|
throw DOWNLOAD_FAILURE_EXCEPTION
|
||||||
|
@ -337,20 +336,14 @@ void RequestGroup::createInitialCommand
|
||||||
}
|
}
|
||||||
_progressInfoFile = progressInfoFile;
|
_progressInfoFile = progressInfoFile;
|
||||||
|
|
||||||
if(torrentAttrs[bittorrent::PRIVATE].i() == 0 &&
|
if(!torrentAttrs->privateTorrent && _option->getAsBool(PREF_ENABLE_DHT)) {
|
||||||
_option->getAsBool(PREF_ENABLE_DHT)) {
|
|
||||||
std::vector<Command*> dhtCommands;
|
std::vector<Command*> dhtCommands;
|
||||||
DHTSetup().setup(dhtCommands, e);
|
DHTSetup().setup(dhtCommands, e);
|
||||||
e->addCommand(dhtCommands);
|
e->addCommand(dhtCommands);
|
||||||
if(!torrentAttrs[bittorrent::NODES].empty() && DHTSetup::initialized()) {
|
const std::vector<std::pair<std::string, uint16_t> >& nodes =
|
||||||
std::vector<std::pair<std::string, uint16_t> > entryPoints;
|
torrentAttrs->nodes;
|
||||||
const BDE& nodes = torrentAttrs[bittorrent::NODES];
|
if(!nodes.empty() && DHTSetup::initialized()) {
|
||||||
for(BDE::List::const_iterator i = nodes.listBegin(),
|
std::vector<std::pair<std::string, uint16_t> > entryPoints(nodes);
|
||||||
eoi = nodes.listEnd(); i != eoi; ++i) {
|
|
||||||
std::pair<std::string, uint16_t> addr
|
|
||||||
((*i)[bittorrent::HOSTNAME].s(), (*i)[bittorrent::PORT].i());
|
|
||||||
entryPoints.push_back(addr);
|
|
||||||
}
|
|
||||||
DHTEntryPointNameResolveCommand* command =
|
DHTEntryPointNameResolveCommand* command =
|
||||||
new DHTEntryPointNameResolveCommand(e->newCUID(), e, entryPoints);
|
new DHTEntryPointNameResolveCommand(e->newCUID(), e, entryPoints);
|
||||||
command->setTaskQueue(DHTRegistry::getData().taskQueue);
|
command->setTaskQueue(DHTRegistry::getData().taskQueue);
|
||||||
|
@ -1094,8 +1087,9 @@ void RequestGroup::reportDownloadFinished()
|
||||||
TransferStat stat = calculateStat();
|
TransferStat stat = calculateStat();
|
||||||
double shareRatio =
|
double shareRatio =
|
||||||
((stat.getAllTimeUploadLength()*10)/getCompletedLength())/10.0;
|
((stat.getAllTimeUploadLength()*10)/getCompletedLength())/10.0;
|
||||||
const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs =
|
||||||
if(attrs.containsKey(bittorrent::METADATA)) {
|
bittorrent::getTorrentAttrs(_downloadContext);
|
||||||
|
if(!attrs->metadata.empty()) {
|
||||||
_logger->notice(MSG_SHARE_RATIO_REPORT,
|
_logger->notice(MSG_SHARE_RATIO_REPORT,
|
||||||
shareRatio,
|
shareRatio,
|
||||||
util::abbrevSize(stat.getAllTimeUploadLength()).c_str(),
|
util::abbrevSize(stat.getAllTimeUploadLength()).c_str(),
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
#include "FileAllocationEntry.h"
|
#include "FileAllocationEntry.h"
|
||||||
#include "CheckIntegrityEntry.h"
|
#include "CheckIntegrityEntry.h"
|
||||||
#include "Segment.h"
|
#include "Segment.h"
|
||||||
|
#include "DlAbortEx.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 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_ATTRIBUTE_H
|
||||||
|
#define D_TORRENT_ATTRIBUTE_H
|
||||||
|
|
||||||
|
#include "ContextAttribute.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "a2time.h"
|
||||||
|
|
||||||
|
struct TorrentAttribute:public ContextAttribute {
|
||||||
|
std::string name;
|
||||||
|
std::string mode;
|
||||||
|
std::vector<std::vector<std::string> > announceList;
|
||||||
|
std::vector<std::pair<std::string, uint16_t> > nodes;
|
||||||
|
// raw hash value 20 bytes.
|
||||||
|
std::string infoHash;
|
||||||
|
std::string metadata;
|
||||||
|
size_t metadataSize;
|
||||||
|
bool privateTorrent;
|
||||||
|
time_t creationDate;
|
||||||
|
std::string comment;
|
||||||
|
std::string createdBy;
|
||||||
|
std::vector<std::string> urlList;
|
||||||
|
|
||||||
|
TorrentAttribute():metadataSize(0),
|
||||||
|
privateTorrent(false),
|
||||||
|
creationDate(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // D_TORRENT_ATTRIBUTE_H
|
||||||
|
|
|
@ -200,15 +200,15 @@ SharedHandle<RequestGroup> TrackerWatcherCommand::createAnnounce() {
|
||||||
static bool backupTrackerIsAvailable
|
static bool backupTrackerIsAvailable
|
||||||
(const SharedHandle<DownloadContext>& context)
|
(const SharedHandle<DownloadContext>& context)
|
||||||
{
|
{
|
||||||
const BDE& announceList =
|
SharedHandle<TorrentAttribute> torrentAttrs =
|
||||||
context->getAttribute(bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST];
|
bittorrent::getTorrentAttrs(context);
|
||||||
if(announceList.size() >= 2) {
|
if(torrentAttrs->announceList.size() >= 2) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(announceList.empty()) {
|
if(torrentAttrs->announceList.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(announceList[0].size() >= 2) {
|
if(torrentAttrs->announceList[0].size() >= 2) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -85,9 +85,8 @@ void UTMetadataDataExtensionMessage::doReceivedAction()
|
||||||
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
|
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
|
||||||
MessageDigestContext::SHA1,
|
MessageDigestContext::SHA1,
|
||||||
metadata.data(), metadata.size());
|
metadata.data(), metadata.size());
|
||||||
const BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
|
if(memcmp(infoHash, bittorrent::getInfoHash(_dctx),
|
||||||
if(std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]) ==
|
INFO_HASH_LENGTH) == 0) {
|
||||||
attrs[bittorrent::INFO_HASH].s()){
|
|
||||||
_logger->info("Got ut_metadata");
|
_logger->info("Got ut_metadata");
|
||||||
} else {
|
} else {
|
||||||
_logger->info("Got wrong ut_metadata");
|
_logger->info("Got wrong ut_metadata");
|
||||||
|
|
|
@ -59,8 +59,8 @@ bool UTMetadataPostDownloadHandler::Criteria::match
|
||||||
const SharedHandle<DownloadContext>& dctx =
|
const SharedHandle<DownloadContext>& dctx =
|
||||||
requestGroup->getDownloadContext();
|
requestGroup->getDownloadContext();
|
||||||
if(dctx->hasAttribute(bittorrent::BITTORRENT)) {
|
if(dctx->hasAttribute(bittorrent::BITTORRENT)) {
|
||||||
const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs = bittorrent::getTorrentAttrs(dctx);
|
||||||
if(!attrs.containsKey(bittorrent::METADATA)) {
|
if(attrs->metadata.empty()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups
|
||||||
(std::vector<SharedHandle<RequestGroup> >& groups, RequestGroup* requestGroup)
|
(std::vector<SharedHandle<RequestGroup> >& groups, RequestGroup* requestGroup)
|
||||||
{
|
{
|
||||||
const SharedHandle<DownloadContext>& dctx =requestGroup->getDownloadContext();
|
const SharedHandle<DownloadContext>& dctx =requestGroup->getDownloadContext();
|
||||||
const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs = bittorrent::getTorrentAttrs(dctx);
|
||||||
std::string metadata =
|
std::string metadata =
|
||||||
util::toString(requestGroup->getPieceStorage()->getDiskAdaptor());
|
util::toString(requestGroup->getPieceStorage()->getDiskAdaptor());
|
||||||
std::string torrent = bittorrent::metadata2Torrent(metadata, attrs);
|
std::string torrent = bittorrent::metadata2Torrent(metadata, attrs);
|
||||||
|
@ -85,7 +85,7 @@ void UTMetadataPostDownloadHandler::getNextRequestGroups
|
||||||
if(requestGroup->getOption()->getAsBool(PREF_BT_SAVE_METADATA)) {
|
if(requestGroup->getOption()->getAsBool(PREF_BT_SAVE_METADATA)) {
|
||||||
std::string filename =
|
std::string filename =
|
||||||
util::applyDir(requestGroup->getOption()->get(PREF_DIR),
|
util::applyDir(requestGroup->getOption()->get(PREF_DIR),
|
||||||
util::toHex(attrs[bittorrent::INFO_HASH].s())+".torrent");
|
util::toHex(attrs->infoHash)+".torrent");
|
||||||
if(util::saveAs(filename, torrent)) {
|
if(util::saveAs(filename, torrent)) {
|
||||||
_logger->notice(MSG_METADATA_SAVED, filename.c_str());
|
_logger->notice(MSG_METADATA_SAVED, filename.c_str());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -70,27 +70,25 @@ std::string UTMetadataRequestExtensionMessage::toString() const
|
||||||
|
|
||||||
void UTMetadataRequestExtensionMessage::doReceivedAction()
|
void UTMetadataRequestExtensionMessage::doReceivedAction()
|
||||||
{
|
{
|
||||||
const BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs = bittorrent::getTorrentAttrs(_dctx);
|
||||||
uint8_t id = _peer->getExtensionMessageID("ut_metadata");
|
uint8_t id = _peer->getExtensionMessageID("ut_metadata");
|
||||||
if(!attrs.containsKey(bittorrent::METADATA)) {
|
if(attrs->metadata.empty()) {
|
||||||
SharedHandle<UTMetadataRejectExtensionMessage> m
|
SharedHandle<UTMetadataRejectExtensionMessage> m
|
||||||
(new UTMetadataRejectExtensionMessage(id));
|
(new UTMetadataRejectExtensionMessage(id));
|
||||||
m->setIndex(getIndex());
|
m->setIndex(getIndex());
|
||||||
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
|
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
|
||||||
_dispatcher->addMessageToQueue(msg);
|
_dispatcher->addMessageToQueue(msg);
|
||||||
}else if(getIndex()*METADATA_PIECE_SIZE <
|
}else if(getIndex()*METADATA_PIECE_SIZE < attrs->metadataSize) {
|
||||||
(size_t)attrs[bittorrent::METADATA_SIZE].i()){
|
|
||||||
SharedHandle<UTMetadataDataExtensionMessage> m
|
SharedHandle<UTMetadataDataExtensionMessage> m
|
||||||
(new UTMetadataDataExtensionMessage(id));
|
(new UTMetadataDataExtensionMessage(id));
|
||||||
m->setIndex(getIndex());
|
m->setIndex(getIndex());
|
||||||
m->setTotalSize(attrs[bittorrent::METADATA_SIZE].i());
|
m->setTotalSize(attrs->metadataSize);
|
||||||
const BDE& metadata = attrs[bittorrent::METADATA];
|
|
||||||
std::string::const_iterator begin =
|
std::string::const_iterator begin =
|
||||||
metadata.s().begin()+getIndex()*METADATA_PIECE_SIZE;
|
attrs->metadata.begin()+getIndex()*METADATA_PIECE_SIZE;
|
||||||
std::string::const_iterator end =
|
std::string::const_iterator end =
|
||||||
(getIndex()+1)*METADATA_PIECE_SIZE <= metadata.s().size()?
|
(getIndex()+1)*METADATA_PIECE_SIZE <= attrs->metadata.size()?
|
||||||
metadata.s().begin()+(getIndex()+1)*METADATA_PIECE_SIZE:
|
attrs->metadata.begin()+(getIndex()+1)*METADATA_PIECE_SIZE:
|
||||||
metadata.s().end();
|
attrs->metadata.end();
|
||||||
m->setData(std::string(begin, end));
|
m->setData(std::string(begin, end));
|
||||||
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
|
SharedHandle<BtMessage> msg = _messageFactory->createBtExtendedMessage(m);
|
||||||
_dispatcher->addMessageToQueue(msg);
|
_dispatcher->addMessageToQueue(msg);
|
||||||
|
|
|
@ -0,0 +1,347 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 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 "ValueBase.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
const SharedHandle<ValueBase> ValueBase::none;
|
||||||
|
|
||||||
|
String::String(const ValueType& string):str_(string) {}
|
||||||
|
|
||||||
|
String::String(const char* cstring):str_(cstring) {}
|
||||||
|
|
||||||
|
String::String(const char* data, size_t length):str_(&data[0], &data[length]) {}
|
||||||
|
|
||||||
|
String::String(const unsigned char* data, size_t length):
|
||||||
|
str_(&data[0], &data[length]) {}
|
||||||
|
|
||||||
|
String::String() {}
|
||||||
|
|
||||||
|
const String::ValueType& String::s() const
|
||||||
|
{
|
||||||
|
return str_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* String::uc() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const unsigned char*>(str_.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<String> String::g(const ValueType& string)
|
||||||
|
{
|
||||||
|
return SharedHandle<String>(new String(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::accept(ValueBaseVisitor& v) const
|
||||||
|
{
|
||||||
|
v.visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer::Integer(ValueType integer):integer_(integer) {}
|
||||||
|
|
||||||
|
Integer::Integer():integer_(0) {}
|
||||||
|
|
||||||
|
Integer::ValueType Integer::i() const
|
||||||
|
{
|
||||||
|
return integer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<Integer> Integer::g(ValueType integer)
|
||||||
|
{
|
||||||
|
return SharedHandle<Integer>(new Integer(integer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Integer::accept(ValueBaseVisitor& v) const
|
||||||
|
{
|
||||||
|
v.visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
List::List() {}
|
||||||
|
|
||||||
|
const SharedHandle<ValueBase>& List::get(size_t index) const
|
||||||
|
{
|
||||||
|
return list_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::append(const SharedHandle<ValueBase>& v)
|
||||||
|
{
|
||||||
|
list_.push_back(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
List& List::operator<<(const SharedHandle<ValueBase>& v)
|
||||||
|
{
|
||||||
|
list_.push_back(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SharedHandle<ValueBase>& List::operator[](size_t index) const
|
||||||
|
{
|
||||||
|
return list_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
List::ValueType::iterator List::begin()
|
||||||
|
{
|
||||||
|
return list_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
List::ValueType::iterator List::end()
|
||||||
|
{
|
||||||
|
return list_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
List::ValueType::const_iterator List::begin() const
|
||||||
|
{
|
||||||
|
return list_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
List::ValueType::const_iterator List::end() const
|
||||||
|
{
|
||||||
|
return list_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t List::size() const
|
||||||
|
{
|
||||||
|
return list_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool List::empty() const
|
||||||
|
{
|
||||||
|
return list_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<List> List::g()
|
||||||
|
{
|
||||||
|
return SharedHandle<List>(new List());
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::accept(ValueBaseVisitor& v) const
|
||||||
|
{
|
||||||
|
v.visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict::Dict() {}
|
||||||
|
|
||||||
|
void Dict::put(const std::string& key, const SharedHandle<ValueBase>& vlb)
|
||||||
|
{
|
||||||
|
ValueType::value_type p = std::make_pair(key, vlb);
|
||||||
|
std::pair<ValueType::iterator, bool> r = dict_.insert(p);
|
||||||
|
if(!r.second) {
|
||||||
|
(*r.first).second = vlb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dict::put(const std::string& key, const String::ValueType& string)
|
||||||
|
{
|
||||||
|
put(key, String::g(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
const SharedHandle<ValueBase>& Dict::get(const std::string& key) const
|
||||||
|
{
|
||||||
|
ValueType::const_iterator itr = dict_.find(key);
|
||||||
|
if(itr == dict_.end()) {
|
||||||
|
return ValueBase::none;
|
||||||
|
} else {
|
||||||
|
return (*itr).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<ValueBase>& Dict::operator[](const std::string& key)
|
||||||
|
{
|
||||||
|
return dict_[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
const SharedHandle<ValueBase>& Dict::operator[](const std::string& key) const
|
||||||
|
{
|
||||||
|
return get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dict::containsKey(const std::string& key) const
|
||||||
|
{
|
||||||
|
return dict_.count(key) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dict::removeKey(const std::string& key)
|
||||||
|
{
|
||||||
|
dict_.erase(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict::ValueType::iterator Dict::begin()
|
||||||
|
{
|
||||||
|
return dict_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict::ValueType::iterator Dict::end()
|
||||||
|
{
|
||||||
|
return dict_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict::ValueType::const_iterator Dict::begin() const
|
||||||
|
{
|
||||||
|
return dict_.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict::ValueType::const_iterator Dict::end() const
|
||||||
|
{
|
||||||
|
return dict_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Dict::size() const
|
||||||
|
{
|
||||||
|
return dict_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dict::empty() const
|
||||||
|
{
|
||||||
|
return dict_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<Dict> Dict::g()
|
||||||
|
{
|
||||||
|
return SharedHandle<Dict>(new Dict());
|
||||||
|
}
|
||||||
|
void Dict::accept(ValueBaseVisitor& v) const
|
||||||
|
{
|
||||||
|
v.visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const String* asString(const ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return downcast<String, Integer, List, Dict>(v);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String* asString(ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return const_cast<String*>(downcast<String, Integer, List, Dict>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String* asString(const SharedHandle<ValueBase>& v)
|
||||||
|
{
|
||||||
|
if(v.get()) {
|
||||||
|
return const_cast<String*>(downcast<String, Integer, List, Dict>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Integer* asInteger(const ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return downcast<Integer, String, List, Dict>(v);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer* asInteger(ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return const_cast<Integer*>(downcast<Integer, String, List, Dict>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer* asInteger(const SharedHandle<ValueBase>& v)
|
||||||
|
{
|
||||||
|
if(v.get()) {
|
||||||
|
return const_cast<Integer*>(downcast<Integer, String, List, Dict>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const List* asList(const ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return downcast<List, String, Integer, Dict>(v);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List* asList(ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return const_cast<List*>(downcast<List, String, Integer, Dict>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List* asList(const SharedHandle<ValueBase>& v)
|
||||||
|
{
|
||||||
|
if(v.get()) {
|
||||||
|
return const_cast<List*>(downcast<List, String, Integer, Dict>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Dict* asDict(const ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return downcast<Dict, String, Integer, List>(v);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict* asDict(ValueBase* v)
|
||||||
|
{
|
||||||
|
if(v) {
|
||||||
|
return const_cast<Dict*>(downcast<Dict, String, Integer, List>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict* asDict(const SharedHandle<ValueBase>& v)
|
||||||
|
{
|
||||||
|
if(v.get()) {
|
||||||
|
return const_cast<Dict*>(downcast<Dict, String, Integer, List>(v));
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -0,0 +1,288 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 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_VALUE_BASE_H
|
||||||
|
#define D_VALUE_BASE_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "SharedHandle.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
class ValueBaseVisitor;
|
||||||
|
|
||||||
|
class ValueBase {
|
||||||
|
public:
|
||||||
|
virtual ~ValueBase() {}
|
||||||
|
|
||||||
|
virtual void accept(ValueBaseVisitor& visitor) const = 0;
|
||||||
|
|
||||||
|
static const SharedHandle<ValueBase> none;
|
||||||
|
};
|
||||||
|
|
||||||
|
class String;
|
||||||
|
class Integer;
|
||||||
|
class List;
|
||||||
|
class Dict;
|
||||||
|
|
||||||
|
class ValueBaseVisitor {
|
||||||
|
public:
|
||||||
|
virtual ~ValueBaseVisitor() {}
|
||||||
|
|
||||||
|
virtual void visit(const String& string) = 0;
|
||||||
|
|
||||||
|
virtual void visit(const Integer& integer) = 0;
|
||||||
|
|
||||||
|
virtual void visit(const List& list) = 0;
|
||||||
|
|
||||||
|
virtual void visit(const Dict& dict) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class String:public ValueBase {
|
||||||
|
public:
|
||||||
|
typedef std::string ValueType;
|
||||||
|
|
||||||
|
String(const ValueType& string);
|
||||||
|
|
||||||
|
explicit String(const char* cstring);
|
||||||
|
|
||||||
|
String(const char* data, size_t length);
|
||||||
|
|
||||||
|
String(const unsigned char* data, size_t length);
|
||||||
|
|
||||||
|
String();
|
||||||
|
|
||||||
|
const ValueType& s() const;
|
||||||
|
|
||||||
|
// Returns std::string.data() casted to unsigned char*.
|
||||||
|
// Use s().size() to get length.
|
||||||
|
const unsigned char* uc() const;
|
||||||
|
|
||||||
|
static SharedHandle<String> g(const ValueType& string);
|
||||||
|
|
||||||
|
virtual void accept(ValueBaseVisitor& visitor) const;
|
||||||
|
private:
|
||||||
|
ValueType str_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Integer:public ValueBase {
|
||||||
|
public:
|
||||||
|
typedef int64_t ValueType;
|
||||||
|
|
||||||
|
Integer(ValueType integer);
|
||||||
|
|
||||||
|
Integer();
|
||||||
|
|
||||||
|
// Returns Integer.
|
||||||
|
ValueType i() const;
|
||||||
|
|
||||||
|
static SharedHandle<Integer> g(ValueType integer);
|
||||||
|
|
||||||
|
virtual void accept(ValueBaseVisitor& visitor) const;
|
||||||
|
private:
|
||||||
|
ValueType integer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class List:public ValueBase {
|
||||||
|
public:
|
||||||
|
typedef std::vector<SharedHandle<ValueBase> > ValueType;
|
||||||
|
|
||||||
|
List();
|
||||||
|
|
||||||
|
// Appends given v to list.
|
||||||
|
void append(const SharedHandle<ValueBase>& v);
|
||||||
|
|
||||||
|
// Alias for append()
|
||||||
|
List& operator<<(const SharedHandle<ValueBase>& v);
|
||||||
|
|
||||||
|
// Returns the object at given index.
|
||||||
|
const SharedHandle<ValueBase>& get(size_t index) const;
|
||||||
|
|
||||||
|
// Returns the const reference of the object at the given index.
|
||||||
|
const SharedHandle<ValueBase>& operator[](size_t index) const;
|
||||||
|
|
||||||
|
// Returns a read/write iterator that points to the first object in
|
||||||
|
// list.
|
||||||
|
ValueType::iterator begin();
|
||||||
|
|
||||||
|
// Returns a read/write iterator that points to the one past the
|
||||||
|
// last object in list.
|
||||||
|
ValueType::iterator end();
|
||||||
|
|
||||||
|
// Returns a read/write read-only iterator that points to the first
|
||||||
|
// object in list.
|
||||||
|
ValueType::const_iterator begin() const;
|
||||||
|
|
||||||
|
// Returns a read/write read-only iterator that points to the one
|
||||||
|
// past the last object in list.
|
||||||
|
ValueType::const_iterator end() const;
|
||||||
|
|
||||||
|
// Returns size of list.
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
// Returns true if size of list is 0.
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
static SharedHandle<List> g();
|
||||||
|
|
||||||
|
virtual void accept(ValueBaseVisitor& visitor) const;
|
||||||
|
private:
|
||||||
|
ValueType list_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Dict:public ValueBase {
|
||||||
|
public:
|
||||||
|
typedef std::map<std::string, SharedHandle<ValueBase> > ValueType;
|
||||||
|
|
||||||
|
Dict();
|
||||||
|
|
||||||
|
void put(const std::string& key, const SharedHandle<ValueBase>& vlb);
|
||||||
|
|
||||||
|
// Putting string is so common that we provide shortcut function.
|
||||||
|
void put(const std::string& key, const String::ValueType& string);
|
||||||
|
|
||||||
|
const SharedHandle<ValueBase>& get(const std::string& key) const;
|
||||||
|
|
||||||
|
// Returns the reference to object associated with given key. If
|
||||||
|
// the key is not found, new pair with that key is created using
|
||||||
|
// default values, which is then returned. In other words, this is
|
||||||
|
// the same behavior of std::map's operator[].
|
||||||
|
SharedHandle<ValueBase>& operator[](const std::string& key);
|
||||||
|
|
||||||
|
// Returns the const reference to ojbect associated with given key.
|
||||||
|
// If the key is not found, ValueBase::none is returned.
|
||||||
|
const SharedHandle<ValueBase>& operator[](const std::string& key) const;
|
||||||
|
|
||||||
|
// Returns true if the given key is found in dict.
|
||||||
|
bool containsKey(const std::string& key) const;
|
||||||
|
|
||||||
|
// Removes specified key from dict.
|
||||||
|
void removeKey(const std::string& key);
|
||||||
|
|
||||||
|
// Returns a read/write iterator that points to the first pair in
|
||||||
|
// the dict.
|
||||||
|
ValueType::iterator begin();
|
||||||
|
|
||||||
|
// Returns a read/write read-only iterator that points to one past
|
||||||
|
// the last pair in the dict.
|
||||||
|
ValueType::iterator end();
|
||||||
|
|
||||||
|
// Returns a read/write read-only iterator that points to the first
|
||||||
|
// pair in the dict.
|
||||||
|
ValueType::const_iterator begin() const;
|
||||||
|
|
||||||
|
// Returns a read/write read-only iterator that points to one past
|
||||||
|
// the last pair in the dict.
|
||||||
|
ValueType::const_iterator end() const;
|
||||||
|
|
||||||
|
// Returns size of Dict.
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
// Returns true if size of Dict is 0.
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
static SharedHandle<Dict> g();
|
||||||
|
|
||||||
|
virtual void accept(ValueBaseVisitor& visitor) const;
|
||||||
|
private:
|
||||||
|
ValueType dict_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename T1, typename T2, typename T3>
|
||||||
|
class DowncastValueBaseVisitor:public ValueBaseVisitor {
|
||||||
|
private:
|
||||||
|
const T* result_;
|
||||||
|
public:
|
||||||
|
DowncastValueBaseVisitor():result_(0) {}
|
||||||
|
|
||||||
|
virtual void visit(const T& t)
|
||||||
|
{
|
||||||
|
result_ = &t;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const T1& t1) {}
|
||||||
|
virtual void visit(const T2& t2) {}
|
||||||
|
virtual void visit(const T3& t3) {}
|
||||||
|
|
||||||
|
const T* getResult() const
|
||||||
|
{
|
||||||
|
return result_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setResult(const T* r)
|
||||||
|
{
|
||||||
|
result_ = r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename T1, typename T2, typename T3, typename VPtr>
|
||||||
|
const T* downcast(const VPtr& v)
|
||||||
|
{
|
||||||
|
DowncastValueBaseVisitor<T, T1, T2, T3> visitor;
|
||||||
|
v->accept(visitor);
|
||||||
|
return visitor.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
const String* asString(const ValueBase* v);
|
||||||
|
|
||||||
|
String* asString(ValueBase* v);
|
||||||
|
|
||||||
|
String* asString(const SharedHandle<ValueBase>& v);
|
||||||
|
|
||||||
|
const Integer* asInteger(const ValueBase* v);
|
||||||
|
|
||||||
|
Integer* asInteger(ValueBase* v);
|
||||||
|
|
||||||
|
Integer* asInteger(const SharedHandle<ValueBase>& v);
|
||||||
|
|
||||||
|
const List* asList(const ValueBase* v);
|
||||||
|
|
||||||
|
List* asList(ValueBase* v);
|
||||||
|
|
||||||
|
List* asList(const SharedHandle<ValueBase>& v);
|
||||||
|
|
||||||
|
const Dict* asDict(const ValueBase* v);
|
||||||
|
|
||||||
|
Dict* asDict(ValueBase* v);
|
||||||
|
|
||||||
|
Dict* asDict(const SharedHandle<ValueBase>& v);
|
||||||
|
|
||||||
|
} // namespace aria2
|
||||||
|
|
||||||
|
#endif // D_VALUE_BASE_H
|
|
@ -563,44 +563,43 @@ void gatherProgressCommon
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_BITTORRENT
|
#ifdef ENABLE_BITTORRENT
|
||||||
void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs)
|
void gatherBitTorrentMetadata
|
||||||
|
(BDE& btDict, const SharedHandle<TorrentAttribute>& torrentAttrs)
|
||||||
{
|
{
|
||||||
if(torrentAttrs.containsKey(bittorrent::COMMENT)) {
|
if(!torrentAttrs->comment.empty()) {
|
||||||
btDict[KEY_COMMENT] = torrentAttrs[bittorrent::COMMENT];
|
btDict[KEY_COMMENT] = torrentAttrs->comment;
|
||||||
}
|
}
|
||||||
if(torrentAttrs.containsKey(bittorrent::CREATION_DATE)) {
|
if(torrentAttrs->creationDate) {
|
||||||
btDict[KEY_CREATION_DATE] = torrentAttrs[bittorrent::CREATION_DATE];
|
btDict[KEY_CREATION_DATE] = torrentAttrs->creationDate;
|
||||||
}
|
}
|
||||||
if(torrentAttrs.containsKey(bittorrent::MODE)) {
|
if(!torrentAttrs->mode.empty()) {
|
||||||
btDict[KEY_MODE] = torrentAttrs[bittorrent::MODE];
|
btDict[KEY_MODE] = torrentAttrs->mode;
|
||||||
}
|
}
|
||||||
// Copy announceList to avoid modification on entyDict to be
|
|
||||||
// affected original announceList.
|
|
||||||
// TODO Would it be good to add copy() method in BDE?
|
|
||||||
const BDE& announceList = torrentAttrs[bittorrent::ANNOUNCE_LIST];
|
|
||||||
BDE destAnnounceList = BDE::list();
|
BDE destAnnounceList = BDE::list();
|
||||||
for(BDE::List::const_iterator l = announceList.listBegin(),
|
for(std::vector<std::vector<std::string> >::const_iterator l =
|
||||||
eoi = announceList.listEnd(); l != eoi; ++l) {
|
torrentAttrs->announceList.begin(),
|
||||||
|
eoi = torrentAttrs->announceList.end(); l != eoi; ++l) {
|
||||||
BDE destAnnounceTier = BDE::list();
|
BDE destAnnounceTier = BDE::list();
|
||||||
for(BDE::List::const_iterator t = (*l).listBegin(),
|
for(std::vector<std::string>::const_iterator t = (*l).begin(),
|
||||||
eoi2 = (*l).listEnd(); t != eoi2; ++t) {
|
eoi2 = (*l).end(); t != eoi2; ++t) {
|
||||||
destAnnounceTier << (*t);
|
destAnnounceTier << *t;
|
||||||
}
|
}
|
||||||
destAnnounceList << destAnnounceTier;
|
destAnnounceList << destAnnounceTier;
|
||||||
}
|
}
|
||||||
btDict[KEY_ANNOUNCE_LIST] = destAnnounceList;
|
btDict[KEY_ANNOUNCE_LIST] = destAnnounceList;
|
||||||
if(torrentAttrs.containsKey(bittorrent::METADATA)) {
|
if(!torrentAttrs->metadata.empty()) {
|
||||||
BDE infoDict = BDE::dict();
|
BDE infoDict = BDE::dict();
|
||||||
infoDict[KEY_NAME] = torrentAttrs[bittorrent::NAME];
|
infoDict[KEY_NAME] = torrentAttrs->name;
|
||||||
btDict[KEY_INFO] = infoDict;
|
btDict[KEY_INFO] = infoDict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gatherProgressBitTorrent
|
static void gatherProgressBitTorrent
|
||||||
(BDE& entryDict, const BDE& torrentAttrs, const BtObject& btObject)
|
(BDE& entryDict,
|
||||||
|
const SharedHandle<TorrentAttribute>& torrentAttrs,
|
||||||
|
const BtObject& btObject)
|
||||||
{
|
{
|
||||||
const std::string& infoHash = torrentAttrs[bittorrent::INFO_HASH].s();
|
entryDict[KEY_INFO_HASH] = util::toHex(torrentAttrs->infoHash);
|
||||||
entryDict[KEY_INFO_HASH] = util::toHex(infoHash);
|
|
||||||
BDE btDict = BDE::dict();
|
BDE btDict = BDE::dict();
|
||||||
gatherBitTorrentMetadata(btDict, torrentAttrs);
|
gatherBitTorrentMetadata(btDict, torrentAttrs);
|
||||||
entryDict[KEY_BITTORRENT] = btDict;
|
entryDict[KEY_BITTORRENT] = btDict;
|
||||||
|
@ -651,8 +650,8 @@ static void gatherProgress
|
||||||
gatherProgressCommon(entryDict, group);
|
gatherProgressCommon(entryDict, group);
|
||||||
#ifdef ENABLE_BITTORRENT
|
#ifdef ENABLE_BITTORRENT
|
||||||
if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
|
if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
|
||||||
const BDE& torrentAttrs =
|
SharedHandle<TorrentAttribute> torrentAttrs =
|
||||||
group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
|
bittorrent::getTorrentAttrs(group->getDownloadContext());
|
||||||
BtObject btObject = e->getBtRegistry()->get(group->getGID());
|
BtObject btObject = e->getBtRegistry()->get(group->getGID());
|
||||||
gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
|
gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@
|
||||||
|
|
||||||
#include "BDE.h"
|
#include "BDE.h"
|
||||||
#include "XmlRpcRequest.h"
|
#include "XmlRpcRequest.h"
|
||||||
|
#include "ValueBase.h"
|
||||||
|
#include "TorrentAttribute.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -500,9 +502,9 @@ void gatherProgressCommon
|
||||||
(BDE& entryDict, const SharedHandle<RequestGroup>& group);
|
(BDE& entryDict, const SharedHandle<RequestGroup>& group);
|
||||||
|
|
||||||
#ifdef ENABLE_BITTORRENT
|
#ifdef ENABLE_BITTORRENT
|
||||||
// Helper function to store BitTorrent metadata from torrentAttrs in
|
// Helper function to store BitTorrent metadata from torrentAttrs.
|
||||||
// btDict. btDict must be an BDE::Dict.
|
void gatherBitTorrentMetadata
|
||||||
void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs);
|
(BDE& btDict, const SharedHandle<TorrentAttribute>& torrentAttrs);
|
||||||
#endif // ENABLE_BITTORRENT
|
#endif // ENABLE_BITTORRENT
|
||||||
|
|
||||||
} // namespace xmlrpc
|
} // namespace xmlrpc
|
||||||
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 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 "bencode2.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "StringFormat.h"
|
||||||
|
#include "DlAbortEx.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
namespace bencode2 {
|
||||||
|
|
||||||
|
static SharedHandle<ValueBase> decodeiter(std::istream& ss, size_t depth);
|
||||||
|
|
||||||
|
static void checkdelim(std::istream& ss, const char delim = ':')
|
||||||
|
{
|
||||||
|
char d;
|
||||||
|
if(!(ss.get(d) && d == delim)) {
|
||||||
|
throw DL_ABORT_EX
|
||||||
|
(StringFormat("Bencode decoding failed: Delimiter '%c' not found.",
|
||||||
|
delim).str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string decoderawstring(std::istream& ss)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
ss >> length;
|
||||||
|
if(!ss || length < 0) {
|
||||||
|
throw DL_ABORT_EX("Bencode decoding failed:"
|
||||||
|
" A positive integer expected but none found.");
|
||||||
|
}
|
||||||
|
// TODO check length, it must be less than or equal to INT_MAX
|
||||||
|
checkdelim(ss);
|
||||||
|
char* buf = new char[length];
|
||||||
|
ss.read(buf, length);
|
||||||
|
std::string str(&buf[0], &buf[length]);
|
||||||
|
delete [] buf;
|
||||||
|
if(ss.gcount() != static_cast<int>(length)) {
|
||||||
|
throw DL_ABORT_EX
|
||||||
|
(StringFormat("Bencode decoding failed:"
|
||||||
|
" Expected %lu bytes of data, but only %d read.",
|
||||||
|
static_cast<unsigned long>(length), ss.gcount()).str());
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SharedHandle<ValueBase> decodestring(std::istream& ss)
|
||||||
|
{
|
||||||
|
return String::g(decoderawstring(ss));
|
||||||
|
}
|
||||||
|
|
||||||
|
static SharedHandle<ValueBase> decodeinteger(std::istream& ss)
|
||||||
|
{
|
||||||
|
Integer::ValueType iv;
|
||||||
|
ss >> iv;
|
||||||
|
if(!ss) {
|
||||||
|
throw DL_ABORT_EX("Bencode decoding failed:"
|
||||||
|
" Integer expected but none found");
|
||||||
|
}
|
||||||
|
checkdelim(ss, 'e');
|
||||||
|
return Integer::g(iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SharedHandle<ValueBase> decodedict(std::istream& ss, size_t depth)
|
||||||
|
{
|
||||||
|
SharedHandle<Dict> dict = Dict::g();
|
||||||
|
char c;
|
||||||
|
while(ss.get(c)) {
|
||||||
|
if(c == 'e') {
|
||||||
|
return dict;
|
||||||
|
} else {
|
||||||
|
ss.unget();
|
||||||
|
std::string key = decoderawstring(ss);
|
||||||
|
dict->put(key, decodeiter(ss, depth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw DL_ABORT_EX("Bencode decoding failed:"
|
||||||
|
" Unexpected EOF in dict context. 'e' expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static SharedHandle<ValueBase> decodelist(std::istream& ss, size_t depth)
|
||||||
|
{
|
||||||
|
SharedHandle<List> list = List::g();
|
||||||
|
char c;
|
||||||
|
while(ss.get(c)) {
|
||||||
|
if(c == 'e') {
|
||||||
|
return list;
|
||||||
|
} else {
|
||||||
|
ss.unget();
|
||||||
|
list->append(decodeiter(ss, depth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw DL_ABORT_EX("Bencode decoding failed:"
|
||||||
|
" Unexpected EOF in list context. 'e' expected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkDepth(size_t depth)
|
||||||
|
{
|
||||||
|
if(depth >= MAX_STRUCTURE_DEPTH) {
|
||||||
|
throw DL_ABORT_EX("Bencode decoding failed: Structure is too deep.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SharedHandle<ValueBase> decodeiter(std::istream& ss, size_t depth)
|
||||||
|
{
|
||||||
|
checkDepth(depth);
|
||||||
|
char c;
|
||||||
|
if(!ss.get(c)) {
|
||||||
|
throw DL_ABORT_EX("Bencode decoding failed:"
|
||||||
|
" Unexpected EOF in term context."
|
||||||
|
" 'd', 'l', 'i' or digit is expected.");
|
||||||
|
}
|
||||||
|
if(c == 'd') {
|
||||||
|
return decodedict(ss, depth+1);
|
||||||
|
} else if(c == 'l') {
|
||||||
|
return decodelist(ss, depth+1);
|
||||||
|
} else if(c == 'i') {
|
||||||
|
return decodeinteger(ss);
|
||||||
|
} else {
|
||||||
|
ss.unget();
|
||||||
|
return decodestring(ss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode(std::istream& in)
|
||||||
|
{
|
||||||
|
return decodeiter(in, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode(const std::string& s)
|
||||||
|
{
|
||||||
|
size_t end;
|
||||||
|
return decode(s, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode(const std::string& s, size_t& end)
|
||||||
|
{
|
||||||
|
if(s.empty()) {
|
||||||
|
return SharedHandle<ValueBase>();
|
||||||
|
}
|
||||||
|
std::istringstream ss(s);
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> vlb = decodeiter(ss, 0);
|
||||||
|
end = ss.tellg();
|
||||||
|
return vlb;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode(const unsigned char* data, size_t length)
|
||||||
|
{
|
||||||
|
return decode(std::string(&data[0], &data[length]));
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode(const unsigned char* data, size_t length, size_t& end)
|
||||||
|
{
|
||||||
|
return decode(std::string(&data[0], &data[length]), end);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decodeFromFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream f(filename.c_str(), std::ios::binary);
|
||||||
|
if(f) {
|
||||||
|
return decode(f);
|
||||||
|
} else {
|
||||||
|
throw DL_ABORT_EX
|
||||||
|
(StringFormat("Bencode decoding failed:"
|
||||||
|
" Cannot open file '%s'.", filename.c_str()).str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string encode(const ValueBase* vlb)
|
||||||
|
{
|
||||||
|
class BencodeValueBaseVisitor:public ValueBaseVisitor {
|
||||||
|
private:
|
||||||
|
std::ostringstream out_;
|
||||||
|
public:
|
||||||
|
virtual void visit(const String& string)
|
||||||
|
{
|
||||||
|
const std::string& s = string.s();
|
||||||
|
out_ << s.size() << ":";
|
||||||
|
out_.write(s.data(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const Integer& integer)
|
||||||
|
{
|
||||||
|
out_ << "i" << integer.i() << "e";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const List& list)
|
||||||
|
{
|
||||||
|
out_ << "l";
|
||||||
|
for(List::ValueType::const_iterator i = list.begin(), eoi = list.end();
|
||||||
|
i != eoi; ++i){
|
||||||
|
(*i)->accept(*this);
|
||||||
|
}
|
||||||
|
out_ << "e";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const Dict& dict)
|
||||||
|
{
|
||||||
|
out_ << "d";
|
||||||
|
for(Dict::ValueType::const_iterator i = dict.begin(), eoi = dict.end();
|
||||||
|
i != eoi; ++i){
|
||||||
|
const std::string& key = (*i).first;
|
||||||
|
out_ << key.size() << ":";
|
||||||
|
out_.write(key.data(), key.size());
|
||||||
|
(*i).second->accept(*this);
|
||||||
|
}
|
||||||
|
out_ << "e";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getResult() const
|
||||||
|
{
|
||||||
|
return out_.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BencodeValueBaseVisitor visitor;
|
||||||
|
vlb->accept(visitor);
|
||||||
|
return visitor.getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string encode(const SharedHandle<ValueBase>& vlb)
|
||||||
|
{
|
||||||
|
return encode(vlb.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace bencode2
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -0,0 +1,75 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 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_BENCODE2_H_
|
||||||
|
#define _D_BENCODE2_H_
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
#include "ValueBase.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
namespace bencode2 {
|
||||||
|
|
||||||
|
const size_t MAX_STRUCTURE_DEPTH = 100;
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode(std::istream& in);
|
||||||
|
|
||||||
|
// Decode the data in s.
|
||||||
|
SharedHandle<ValueBase> decode(const std::string& s);
|
||||||
|
|
||||||
|
// Decode the data in s. After decode is done successfully, return the
|
||||||
|
// bencoded string length in end.
|
||||||
|
SharedHandle<ValueBase> decode(const std::string& s, size_t& end);
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode(const unsigned char* data, size_t length);
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decode
|
||||||
|
(const unsigned char* data, size_t length, size_t& end);
|
||||||
|
|
||||||
|
SharedHandle<ValueBase> decodeFromFile(const std::string& filename);
|
||||||
|
|
||||||
|
std::string encode(const ValueBase* vlb);
|
||||||
|
|
||||||
|
std::string encode(const SharedHandle<ValueBase>& vlb);
|
||||||
|
|
||||||
|
} // namespace bencode2
|
||||||
|
|
||||||
|
} // namespace aria2
|
||||||
|
|
||||||
|
#endif // _D_BENCODE2_H_
|
|
@ -54,6 +54,9 @@
|
||||||
#include "bitfield.h"
|
#include "bitfield.h"
|
||||||
#include "base32.h"
|
#include "base32.h"
|
||||||
#include "magnet.h"
|
#include "magnet.h"
|
||||||
|
#include "ValueBase.h"
|
||||||
|
#include "bencode2.h"
|
||||||
|
#include "TorrentAttribute.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -147,23 +150,44 @@ static void extractPieceHash(const SharedHandle<DownloadContext>& ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extractUrlList
|
static void extractUrlList
|
||||||
(BDE& torrent, std::vector<std::string>& uris, const BDE& bde)
|
(const SharedHandle<TorrentAttribute>& torrent, std::vector<std::string>& uris,
|
||||||
|
const ValueBase* v)
|
||||||
{
|
{
|
||||||
if(bde.isList()) {
|
class UrlListVisitor:public ValueBaseVisitor {
|
||||||
for(BDE::List::const_iterator itr = bde.listBegin(), eoi = bde.listEnd();
|
private:
|
||||||
|
std::vector<std::string>& uris_;
|
||||||
|
const SharedHandle<TorrentAttribute>& torrent_;
|
||||||
|
public:
|
||||||
|
UrlListVisitor
|
||||||
|
(std::vector<std::string>& uris,
|
||||||
|
const SharedHandle<TorrentAttribute>& torrent):
|
||||||
|
uris_(uris), torrent_(torrent) {}
|
||||||
|
|
||||||
|
virtual void visit(const String& v)
|
||||||
|
{
|
||||||
|
uris_.push_back(v.s());
|
||||||
|
torrent_->urlList.push_back(v.s());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(const Integer& v) {}
|
||||||
|
|
||||||
|
virtual void visit(const List& v)
|
||||||
|
{
|
||||||
|
for(List::ValueType::const_iterator itr = v.begin(), eoi = v.end();
|
||||||
itr != eoi; ++itr) {
|
itr != eoi; ++itr) {
|
||||||
if((*itr).isString()) {
|
const String* uri = asString(*itr);
|
||||||
uris.push_back((*itr).s());
|
if(uri) {
|
||||||
|
uris_.push_back(uri->s());
|
||||||
|
torrent_->urlList.push_back(uri->s());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
torrent[URL_LIST] = bde;
|
}
|
||||||
} else if(bde.isString()) {
|
virtual void visit(const Dict& v) {}
|
||||||
uris.push_back(bde.s());
|
};
|
||||||
BDE urlList = BDE::list();
|
|
||||||
urlList << bde;
|
if(v) {
|
||||||
torrent[URL_LIST] = urlList;
|
UrlListVisitor visitor(uris, torrent);
|
||||||
} else {
|
v->accept(visitor);
|
||||||
torrent[URL_LIST] = BDE::list();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +208,8 @@ static OutputIterator createUri
|
||||||
|
|
||||||
static void extractFileEntries
|
static void extractFileEntries
|
||||||
(const SharedHandle<DownloadContext>& ctx,
|
(const SharedHandle<DownloadContext>& ctx,
|
||||||
BDE& torrent,
|
const SharedHandle<TorrentAttribute>& torrent,
|
||||||
const BDE& infoDict,
|
const Dict* infoDict,
|
||||||
const std::string& defaultName,
|
const std::string& defaultName,
|
||||||
const std::string& overrideName,
|
const std::string& overrideName,
|
||||||
const std::vector<std::string>& urlList)
|
const std::vector<std::string>& urlList)
|
||||||
|
@ -193,62 +217,71 @@ static void extractFileEntries
|
||||||
std::string name;
|
std::string name;
|
||||||
if(overrideName.empty()) {
|
if(overrideName.empty()) {
|
||||||
std::string nameKey;
|
std::string nameKey;
|
||||||
if(infoDict.containsKey(C_NAME_UTF8)) {
|
if(infoDict->containsKey(C_NAME_UTF8)) {
|
||||||
nameKey = C_NAME_UTF8;
|
nameKey = C_NAME_UTF8;
|
||||||
} else {
|
} else {
|
||||||
nameKey = C_NAME;
|
nameKey = C_NAME;
|
||||||
}
|
}
|
||||||
const BDE& nameData = infoDict[nameKey];
|
const String* nameData = asString(infoDict->get(nameKey));
|
||||||
if(nameData.isString()) {
|
if(nameData) {
|
||||||
if(util::detectDirTraversal(nameData.s())) {
|
if(util::detectDirTraversal(nameData->s())) {
|
||||||
throw DL_ABORT_EX
|
throw DL_ABORT_EX
|
||||||
(StringFormat(MSG_DIR_TRAVERSAL_DETECTED,nameData.s().c_str()).str());
|
(StringFormat
|
||||||
|
(MSG_DIR_TRAVERSAL_DETECTED,nameData->s().c_str()).str());
|
||||||
}
|
}
|
||||||
name = nameData.s();
|
name = nameData->s();
|
||||||
} else {
|
} else {
|
||||||
name = strconcat(File(defaultName).getBasename(), ".file");
|
name = strconcat(File(defaultName).getBasename(), ".file");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
name = overrideName;
|
name = overrideName;
|
||||||
}
|
}
|
||||||
torrent[NAME] = name;
|
torrent->name = name;
|
||||||
|
|
||||||
const BDE& filesList = infoDict[C_FILES];
|
|
||||||
std::vector<SharedHandle<FileEntry> > fileEntries;
|
std::vector<SharedHandle<FileEntry> > fileEntries;
|
||||||
if(filesList.isList()) {
|
const List* filesList = asList(infoDict->get(C_FILES));
|
||||||
fileEntries.reserve(filesList.size());
|
if(filesList) {
|
||||||
|
fileEntries.reserve(filesList->size());
|
||||||
uint64_t length = 0;
|
uint64_t length = 0;
|
||||||
off_t offset = 0;
|
off_t offset = 0;
|
||||||
// multi-file mode
|
// multi-file mode
|
||||||
torrent[MODE] = MULTI;
|
torrent->mode = MULTI;
|
||||||
for(BDE::List::const_iterator itr = filesList.listBegin(),
|
for(List::ValueType::const_iterator itr = filesList->begin(),
|
||||||
eoi = filesList.listEnd(); itr != eoi; ++itr) {
|
eoi = filesList->end(); itr != eoi; ++itr) {
|
||||||
const BDE& fileDict = *itr;
|
const Dict* fileDict = asDict(*itr);
|
||||||
if(!fileDict.isDict()) {
|
if(!fileDict) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const BDE& fileLengthData = fileDict[C_LENGTH];
|
const Integer* fileLengthData = asInteger(fileDict->get(C_LENGTH));
|
||||||
if(!fileLengthData.isInteger()) {
|
if(!fileLengthData) {
|
||||||
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
||||||
C_LENGTH.c_str()).str());
|
C_LENGTH.c_str()).str());
|
||||||
}
|
}
|
||||||
length += fileLengthData.i();
|
length += fileLengthData->i();
|
||||||
|
|
||||||
std::string pathKey;
|
std::string pathKey;
|
||||||
if(fileDict.containsKey(C_PATH_UTF8)) {
|
if(fileDict->containsKey(C_PATH_UTF8)) {
|
||||||
pathKey = C_PATH_UTF8;
|
pathKey = C_PATH_UTF8;
|
||||||
} else {
|
} else {
|
||||||
pathKey = C_PATH;
|
pathKey = C_PATH;
|
||||||
}
|
}
|
||||||
const BDE& pathList = fileDict[pathKey];
|
const List* pathList = asList(fileDict->get(pathKey));
|
||||||
if(!pathList.isList() || pathList.empty()) {
|
if(!pathList || pathList->empty()) {
|
||||||
throw DL_ABORT_EX("Path is empty.");
|
throw DL_ABORT_EX("Path is empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> pathelem(pathList.size()+1);
|
std::vector<std::string> pathelem(pathList->size()+1);
|
||||||
pathelem[0] = name;
|
pathelem[0] = name;
|
||||||
std::transform(pathList.listBegin(), pathList.listEnd(),
|
std::vector<std::string>::iterator pathelemOutItr = pathelem.begin();
|
||||||
pathelem.begin()+1, std::mem_fun_ref(&BDE::s));
|
++pathelemOutItr;
|
||||||
|
for(List::ValueType::const_iterator itr = pathList->begin(),
|
||||||
|
eoi = pathList->end(); itr != eoi; ++itr) {
|
||||||
|
const String* elem = asString(*itr);
|
||||||
|
if(elem) {
|
||||||
|
(*pathelemOutItr++) = elem->s();
|
||||||
|
} else {
|
||||||
|
throw DL_ABORT_EX("Path element is not string.");
|
||||||
|
}
|
||||||
|
}
|
||||||
std::string path = strjoin(pathelem.begin(), pathelem.end(), '/');
|
std::string path = strjoin(pathelem.begin(), pathelem.end(), '/');
|
||||||
if(util::detectDirTraversal(path)) {
|
if(util::detectDirTraversal(path)) {
|
||||||
throw DL_ABORT_EX
|
throw DL_ABORT_EX
|
||||||
|
@ -262,7 +295,7 @@ static void extractFileEntries
|
||||||
createUri(urlList.begin(), urlList.end(),std::back_inserter(uris),pePath);
|
createUri(urlList.begin(), urlList.end(),std::back_inserter(uris),pePath);
|
||||||
SharedHandle<FileEntry> fileEntry
|
SharedHandle<FileEntry> fileEntry
|
||||||
(new FileEntry(util::applyDir(ctx->getDir(), util::escapePath(path)),
|
(new FileEntry(util::applyDir(ctx->getDir(), util::escapePath(path)),
|
||||||
fileLengthData.i(),
|
fileLengthData->i(),
|
||||||
offset, uris));
|
offset, uris));
|
||||||
fileEntry->setOriginalName(path);
|
fileEntry->setOriginalName(path);
|
||||||
fileEntries.push_back(fileEntry);
|
fileEntries.push_back(fileEntry);
|
||||||
|
@ -270,13 +303,13 @@ static void extractFileEntries
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// single-file mode;
|
// single-file mode;
|
||||||
torrent[MODE] = SINGLE;
|
torrent->mode = SINGLE;
|
||||||
const BDE& lengthData = infoDict[C_LENGTH];
|
const Integer* lengthData = asInteger(infoDict->get(C_LENGTH));
|
||||||
if(!lengthData.isInteger()) {
|
if(!lengthData) {
|
||||||
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
||||||
C_LENGTH.c_str()).str());
|
C_LENGTH.c_str()).str());
|
||||||
}
|
}
|
||||||
uint64_t totalLength = lengthData.i();
|
uint64_t totalLength = lengthData->i();
|
||||||
|
|
||||||
// For each uri in urlList, if it ends with '/', then
|
// For each uri in urlList, if it ends with '/', then
|
||||||
// concatenate name to it. Specification just says so.
|
// concatenate name to it. Specification just says so.
|
||||||
|
@ -298,98 +331,103 @@ static void extractFileEntries
|
||||||
fileEntries.push_back(fileEntry);
|
fileEntries.push_back(fileEntry);
|
||||||
}
|
}
|
||||||
ctx->setFileEntries(fileEntries.begin(), fileEntries.end());
|
ctx->setFileEntries(fileEntries.begin(), fileEntries.end());
|
||||||
if(torrent[MODE].s() == MULTI) {
|
if(torrent->mode == MULTI) {
|
||||||
ctx->setBasePath(util::applyDir(ctx->getDir(), name));
|
ctx->setBasePath(util::applyDir(ctx->getDir(), name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extractAnnounce(BDE& torrent, const BDE& rootDict)
|
static void extractAnnounce
|
||||||
|
(const SharedHandle<TorrentAttribute>& torrent, const Dict* rootDict)
|
||||||
{
|
{
|
||||||
const BDE& announceList = rootDict[C_ANNOUNCE_LIST];
|
const List* announceList = asList(rootDict->get(C_ANNOUNCE_LIST));
|
||||||
if(announceList.isList()) {
|
if(announceList) {
|
||||||
torrent[ANNOUNCE_LIST] = announceList;
|
for(List::ValueType::const_iterator tierIter = announceList->begin(),
|
||||||
BDE& tiers = torrent[ANNOUNCE_LIST];
|
eoi = announceList->end(); tierIter != eoi; ++tierIter) {
|
||||||
for(BDE::List::iterator tieriter = tiers.listBegin(),
|
const List* tier = asList(*tierIter);
|
||||||
eoi = tiers.listEnd(); tieriter != eoi; ++tieriter) {
|
if(!tier) {
|
||||||
for(BDE::List::iterator uriiter = (*tieriter).listBegin(),
|
continue;
|
||||||
eoi2 = (*tieriter).listEnd(); uriiter != eoi2; ++uriiter) {
|
|
||||||
if((*uriiter).isString()) {
|
|
||||||
*uriiter = util::trim((*uriiter).s());
|
|
||||||
}
|
}
|
||||||
|
std::vector<std::string> ntier;
|
||||||
|
for(List::ValueType::const_iterator uriIter = tier->begin(),
|
||||||
|
eoi2 = tier->end(); uriIter != eoi2; ++uriIter) {
|
||||||
|
const String* uri = asString(*uriIter);
|
||||||
|
if(uri) {
|
||||||
|
ntier.push_back(util::trim(uri->s()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!ntier.empty()) {
|
||||||
|
torrent->announceList.push_back(ntier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const BDE& announce = rootDict[C_ANNOUNCE];
|
const String* announce = asString(rootDict->get(C_ANNOUNCE));
|
||||||
BDE announceList = BDE::list();
|
if(announce) {
|
||||||
if(announce.isString()) {
|
std::vector<std::string> tier;
|
||||||
announceList << BDE::list();
|
tier.push_back(util::trim(announce->s()));
|
||||||
announceList[0] << util::trim(announce.s());
|
torrent->announceList.push_back(tier);
|
||||||
}
|
}
|
||||||
torrent[ANNOUNCE_LIST] = announceList;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extractNodes(BDE& torrent, const BDE& nodesList)
|
static void extractNodes
|
||||||
|
(const SharedHandle<TorrentAttribute>& torrent, const ValueBase* nodesListSrc)
|
||||||
{
|
{
|
||||||
BDE nodes = BDE::list();
|
const List* nodesList = asList(nodesListSrc);
|
||||||
if(nodesList.isList()) {
|
if(nodesList) {
|
||||||
for(BDE::List::const_iterator i = nodesList.listBegin(),
|
for(List::ValueType::const_iterator i = nodesList->begin(),
|
||||||
eoi = nodesList.listEnd(); i != eoi; ++i) {
|
eoi = nodesList->end(); i != eoi; ++i) {
|
||||||
const BDE& addrPairList = (*i);
|
const List* addrPairList = asList(*i);
|
||||||
if(!addrPairList.isList() || addrPairList.size() != 2) {
|
if(!addrPairList || addrPairList->size() != 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const BDE& hostname = addrPairList[0];
|
const String* hostname = asString(addrPairList->get(0));
|
||||||
if(!hostname.isString()) {
|
if(!hostname) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(util::trim(hostname.s()).empty()) {
|
if(util::trim(hostname->s()).empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const BDE& port = addrPairList[1];
|
const Integer* port = asInteger(addrPairList->get(1));
|
||||||
if(!port.isInteger() || !(0 < port.i() && port.i() < 65536)) {
|
if(!port || !(0 < port->i() && port->i() < 65536)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BDE node = BDE::dict();
|
torrent->nodes.push_back(std::make_pair(hostname->s(), port->i()));
|
||||||
node[HOSTNAME] = hostname;
|
|
||||||
node[PORT] = port;
|
|
||||||
nodes << node;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
torrent[NODES] = nodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void processRootDictionary
|
static void processRootDictionary
|
||||||
(const SharedHandle<DownloadContext>& ctx,
|
(const SharedHandle<DownloadContext>& ctx,
|
||||||
const BDE& rootDict,
|
const SharedHandle<ValueBase>& root,
|
||||||
const std::string& defaultName,
|
const std::string& defaultName,
|
||||||
const std::string& overrideName,
|
const std::string& overrideName,
|
||||||
const std::vector<std::string>& uris)
|
const std::vector<std::string>& uris)
|
||||||
{
|
{
|
||||||
if(!rootDict.isDict()) {
|
const Dict* rootDict = asDict(root);
|
||||||
|
if(!rootDict) {
|
||||||
throw DL_ABORT_EX("torrent file does not contain a root dictionary.");
|
throw DL_ABORT_EX("torrent file does not contain a root dictionary.");
|
||||||
}
|
}
|
||||||
const BDE& infoDict = rootDict[C_INFO];
|
const Dict* infoDict = asDict(rootDict->get(C_INFO));
|
||||||
if(!infoDict.isDict()) {
|
if(!infoDict) {
|
||||||
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
||||||
C_INFO.c_str()).str());
|
C_INFO.c_str()).str());
|
||||||
}
|
}
|
||||||
BDE torrent = BDE::dict();
|
SharedHandle<TorrentAttribute> torrent(new TorrentAttribute());
|
||||||
|
|
||||||
// retrieve infoHash
|
// retrieve infoHash
|
||||||
std::string encodedInfoDict = bencode::encode(infoDict);
|
std::string encodedInfoDict = bencode2::encode(infoDict);
|
||||||
unsigned char infoHash[INFO_HASH_LENGTH];
|
unsigned char infoHash[INFO_HASH_LENGTH];
|
||||||
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
|
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
|
||||||
MessageDigestContext::SHA1,
|
MessageDigestContext::SHA1,
|
||||||
encodedInfoDict.data(),
|
encodedInfoDict.data(),
|
||||||
encodedInfoDict.size());
|
encodedInfoDict.size());
|
||||||
torrent[INFO_HASH] = std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]);
|
torrent->infoHash = std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]);
|
||||||
torrent[METADATA] = encodedInfoDict;
|
torrent->metadata = encodedInfoDict;
|
||||||
torrent[METADATA_SIZE] = encodedInfoDict.size();
|
torrent->metadataSize = encodedInfoDict.size();
|
||||||
|
|
||||||
// calculate the number of pieces
|
// calculate the number of pieces
|
||||||
const BDE& piecesData = infoDict[C_PIECES];
|
const String* piecesData = asString(infoDict->get(C_PIECES));
|
||||||
if(!piecesData.isString()) {
|
if(!piecesData) {
|
||||||
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
||||||
C_PIECES.c_str()).str());
|
C_PIECES.c_str()).str());
|
||||||
}
|
}
|
||||||
|
@ -397,65 +435,68 @@ static void processRootDictionary
|
||||||
// if(piecesData.s().empty()) {
|
// if(piecesData.s().empty()) {
|
||||||
// throw DL_ABORT_EX("The length of piece hash is 0.");
|
// throw DL_ABORT_EX("The length of piece hash is 0.");
|
||||||
// }
|
// }
|
||||||
size_t numPieces = piecesData.s().size()/PIECE_HASH_LENGTH;
|
size_t numPieces = piecesData->s().size()/PIECE_HASH_LENGTH;
|
||||||
// Commented out to download 0 length torrent.
|
// Commented out to download 0 length torrent.
|
||||||
// if(numPieces == 0) {
|
// if(numPieces == 0) {
|
||||||
// throw DL_ABORT_EX("The number of pieces is 0.");
|
// throw DL_ABORT_EX("The number of pieces is 0.");
|
||||||
// }
|
// }
|
||||||
// retrieve piece length
|
// retrieve piece length
|
||||||
const BDE& pieceLengthData = infoDict[C_PIECE_LENGTH];
|
const Integer* pieceLengthData = asInteger(infoDict->get(C_PIECE_LENGTH));
|
||||||
if(!pieceLengthData.isInteger()) {
|
if(!pieceLengthData) {
|
||||||
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
throw DL_ABORT_EX(StringFormat(MSG_MISSING_BT_INFO,
|
||||||
C_PIECE_LENGTH.c_str()).str());
|
C_PIECE_LENGTH.c_str()).str());
|
||||||
}
|
}
|
||||||
size_t pieceLength = pieceLengthData.i();
|
size_t pieceLength = pieceLengthData->i();
|
||||||
ctx->setPieceLength(pieceLength);
|
ctx->setPieceLength(pieceLength);
|
||||||
// retrieve piece hashes
|
// retrieve piece hashes
|
||||||
extractPieceHash(ctx, piecesData.s(), PIECE_HASH_LENGTH, numPieces);
|
extractPieceHash(ctx, piecesData->s(), PIECE_HASH_LENGTH, numPieces);
|
||||||
// private flag
|
// private flag
|
||||||
const BDE& privateData = infoDict[C_PRIVATE];
|
const Integer* privateData = asInteger(infoDict->get(C_PRIVATE));
|
||||||
int privatefg = 0;
|
int privatefg = 0;
|
||||||
if(privateData.isInteger()) {
|
if(privateData) {
|
||||||
if(privateData.i() == 1) {
|
if(privateData->i() == 1) {
|
||||||
privatefg = 1;
|
privatefg = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
torrent[PRIVATE] = BDE((int64_t)privatefg);
|
if(privatefg) {
|
||||||
|
torrent->privateTorrent = true;
|
||||||
|
}
|
||||||
// retrieve uri-list.
|
// retrieve uri-list.
|
||||||
// This implemantation obeys HTTP-Seeding specification:
|
// This implemantation obeys HTTP-Seeding specification:
|
||||||
// see http://www.getright.com/seedtorrent.html
|
// see http://www.getright.com/seedtorrent.html
|
||||||
std::vector<std::string> urlList;
|
std::vector<std::string> urlList;
|
||||||
extractUrlList(torrent, urlList, rootDict[C_URL_LIST]);
|
extractUrlList(torrent, urlList, rootDict->get(C_URL_LIST).get());
|
||||||
urlList.insert(urlList.end(), uris.begin(), uris.end());
|
urlList.insert(urlList.end(), uris.begin(), uris.end());
|
||||||
std::sort(urlList.begin(), urlList.end());
|
std::sort(urlList.begin(), urlList.end());
|
||||||
urlList.erase(std::unique(urlList.begin(), urlList.end()), urlList.end());
|
urlList.erase(std::unique(urlList.begin(), urlList.end()), urlList.end());
|
||||||
|
|
||||||
// retrieve file entries
|
// retrieve file entries
|
||||||
extractFileEntries(ctx, torrent, infoDict, defaultName, overrideName, urlList);
|
extractFileEntries
|
||||||
|
(ctx, torrent, infoDict, defaultName, overrideName, urlList);
|
||||||
if((ctx->getTotalLength()+pieceLength-1)/pieceLength != numPieces) {
|
if((ctx->getTotalLength()+pieceLength-1)/pieceLength != numPieces) {
|
||||||
throw DL_ABORT_EX("Too few/many piece hash.");
|
throw DL_ABORT_EX("Too few/many piece hash.");
|
||||||
}
|
}
|
||||||
// retrieve announce
|
// retrieve announce
|
||||||
extractAnnounce(torrent, rootDict);
|
extractAnnounce(torrent, rootDict);
|
||||||
// retrieve nodes
|
// retrieve nodes
|
||||||
extractNodes(torrent, rootDict[C_NODES]);
|
extractNodes(torrent, rootDict->get(C_NODES).get());
|
||||||
|
|
||||||
const BDE& creationDate = rootDict[C_CREATION_DATE];
|
const Integer* creationDate = asInteger(rootDict->get(C_CREATION_DATE));
|
||||||
if(creationDate.isInteger()) {
|
if(creationDate) {
|
||||||
torrent[CREATION_DATE] = creationDate;
|
torrent->creationDate = creationDate->i();
|
||||||
}
|
}
|
||||||
const BDE& commentUtf8 = rootDict[C_COMMENT_UTF8];
|
const String* commentUtf8 = asString(rootDict->get(C_COMMENT_UTF8));
|
||||||
if(commentUtf8.isString()) {
|
if(commentUtf8) {
|
||||||
torrent[COMMENT] = commentUtf8;
|
torrent->comment = commentUtf8->s();
|
||||||
} else {
|
} else {
|
||||||
const BDE& comment = rootDict[C_COMMENT];
|
const String* comment = asString(rootDict->get(C_COMMENT));
|
||||||
if(comment.isString()) {
|
if(comment) {
|
||||||
torrent[COMMENT] = comment;
|
torrent->comment = comment->s();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const BDE& createdBy = rootDict[C_CREATED_BY];
|
const String* createdBy = asString(rootDict->get(C_CREATED_BY));
|
||||||
if(createdBy.isString()) {
|
if(createdBy) {
|
||||||
torrent[CREATED_BY] = createdBy;
|
torrent->createdBy = createdBy->s();
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->setAttribute(BITTORRENT, torrent);
|
ctx->setAttribute(BITTORRENT, torrent);
|
||||||
|
@ -466,7 +507,7 @@ void load(const std::string& torrentFile,
|
||||||
const std::string& overrideName)
|
const std::string& overrideName)
|
||||||
{
|
{
|
||||||
processRootDictionary(ctx,
|
processRootDictionary(ctx,
|
||||||
bencode::decodeFromFile(torrentFile),
|
bencode2::decodeFromFile(torrentFile),
|
||||||
torrentFile,
|
torrentFile,
|
||||||
overrideName,
|
overrideName,
|
||||||
std::vector<std::string>());
|
std::vector<std::string>());
|
||||||
|
@ -478,7 +519,7 @@ void load(const std::string& torrentFile,
|
||||||
const std::string& overrideName)
|
const std::string& overrideName)
|
||||||
{
|
{
|
||||||
processRootDictionary(ctx,
|
processRootDictionary(ctx,
|
||||||
bencode::decodeFromFile(torrentFile),
|
bencode2::decodeFromFile(torrentFile),
|
||||||
torrentFile,
|
torrentFile,
|
||||||
overrideName,
|
overrideName,
|
||||||
uris);
|
uris);
|
||||||
|
@ -491,7 +532,7 @@ void loadFromMemory(const unsigned char* content,
|
||||||
const std::string& overrideName)
|
const std::string& overrideName)
|
||||||
{
|
{
|
||||||
processRootDictionary(ctx,
|
processRootDictionary(ctx,
|
||||||
bencode::decode(content, length),
|
bencode2::decode(content, length),
|
||||||
defaultName,
|
defaultName,
|
||||||
overrideName,
|
overrideName,
|
||||||
std::vector<std::string>());
|
std::vector<std::string>());
|
||||||
|
@ -505,7 +546,7 @@ void loadFromMemory(const unsigned char* content,
|
||||||
const std::string& overrideName)
|
const std::string& overrideName)
|
||||||
{
|
{
|
||||||
processRootDictionary(ctx,
|
processRootDictionary(ctx,
|
||||||
bencode::decode(content, length),
|
bencode2::decode(content, length),
|
||||||
defaultName,
|
defaultName,
|
||||||
overrideName,
|
overrideName,
|
||||||
uris);
|
uris);
|
||||||
|
@ -518,7 +559,7 @@ void loadFromMemory(const std::string& context,
|
||||||
{
|
{
|
||||||
processRootDictionary
|
processRootDictionary
|
||||||
(ctx,
|
(ctx,
|
||||||
bencode::decode(context),
|
bencode2::decode(context),
|
||||||
defaultName, overrideName,
|
defaultName, overrideName,
|
||||||
std::vector<std::string>());
|
std::vector<std::string>());
|
||||||
}
|
}
|
||||||
|
@ -531,73 +572,82 @@ void loadFromMemory(const std::string& context,
|
||||||
{
|
{
|
||||||
processRootDictionary
|
processRootDictionary
|
||||||
(ctx,
|
(ctx,
|
||||||
bencode::decode(context),
|
bencode2::decode(context),
|
||||||
defaultName, overrideName,
|
defaultName, overrideName,
|
||||||
uris);
|
uris);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char*
|
SharedHandle<TorrentAttribute> getTorrentAttrs
|
||||||
getInfoHash(const SharedHandle<DownloadContext>& downloadContext)
|
(const SharedHandle<DownloadContext>& dctx)
|
||||||
{
|
{
|
||||||
return downloadContext->getAttribute(BITTORRENT)[INFO_HASH].uc();
|
return static_pointer_cast<TorrentAttribute>(dctx->getAttribute(BITTORRENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char*
|
||||||
|
getInfoHash(const SharedHandle<DownloadContext>& dctx)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const unsigned char*>
|
||||||
|
(getTorrentAttrs(dctx)->infoHash.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
getInfoHashString(const SharedHandle<DownloadContext>& downloadContext)
|
getInfoHashString(const SharedHandle<DownloadContext>& dctx)
|
||||||
{
|
{
|
||||||
return util::toHex(downloadContext->getAttribute(BITTORRENT)[INFO_HASH].s());
|
return util::toHex(getTorrentAttrs(dctx)->infoHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print(std::ostream& o, const SharedHandle<DownloadContext>& dctx)
|
void print(std::ostream& o, const SharedHandle<DownloadContext>& dctx)
|
||||||
{
|
{
|
||||||
const BDE& torrentAttrs = dctx->getAttribute(BITTORRENT);
|
SharedHandle<TorrentAttribute> torrentAttrs = getTorrentAttrs(dctx);
|
||||||
o << "*** BitTorrent File Information ***" << "\n";
|
o << "*** BitTorrent File Information ***" << "\n";
|
||||||
if(torrentAttrs.containsKey(COMMENT)) {
|
if(!torrentAttrs->comment.empty()) {
|
||||||
o << "Comment: " << torrentAttrs[COMMENT].s() << "\n";
|
o << "Comment: " << torrentAttrs->comment << "\n";
|
||||||
}
|
}
|
||||||
if(torrentAttrs.containsKey(CREATION_DATE)) {
|
if(torrentAttrs->creationDate) {
|
||||||
struct tm* staticNowtmPtr;
|
struct tm* staticNowtmPtr;
|
||||||
char buf[26];
|
char buf[26];
|
||||||
time_t t = torrentAttrs[CREATION_DATE].i();
|
time_t t = torrentAttrs->creationDate;
|
||||||
if((staticNowtmPtr = localtime(&t)) != 0 &&
|
if((staticNowtmPtr = localtime(&t)) != 0 &&
|
||||||
asctime_r(staticNowtmPtr, buf) != 0) {
|
asctime_r(staticNowtmPtr, buf) != 0) {
|
||||||
// buf includes "\n"
|
// buf includes "\n"
|
||||||
o << "Creation Date: " << buf;
|
o << "Creation Date: " << buf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(torrentAttrs.containsKey(CREATED_BY)) {
|
if(!torrentAttrs->createdBy.empty()) {
|
||||||
o << "Created By: " << torrentAttrs[CREATED_BY].s() << "\n";
|
o << "Created By: " << torrentAttrs->createdBy << "\n";
|
||||||
}
|
}
|
||||||
o << "Mode: " << torrentAttrs[MODE].s() << "\n";
|
o << "Mode: " << torrentAttrs->mode << "\n";
|
||||||
o << "Announce:" << "\n";
|
o << "Announce:" << "\n";
|
||||||
const BDE& announceList = torrentAttrs[ANNOUNCE_LIST];
|
for(std::vector<std::vector<std::string> >::const_iterator tierIter =
|
||||||
for(BDE::List::const_iterator tieritr = announceList.listBegin(),
|
torrentAttrs->announceList.begin(),
|
||||||
eoi = announceList.listEnd(); tieritr != eoi; ++tieritr) {
|
eoi = torrentAttrs->announceList.end(); tierIter != eoi; ++tierIter) {
|
||||||
if(!(*tieritr).isList()) {
|
for(std::vector<std::string>::const_iterator i = (*tierIter).begin(),
|
||||||
continue;
|
eoi2 = (*tierIter).end(); i != eoi2; ++i) {
|
||||||
}
|
o << " " << *i;
|
||||||
for(BDE::List::const_iterator i = (*tieritr).listBegin(),
|
|
||||||
eoi2 = (*tieritr).listEnd(); i != eoi2; ++i) {
|
|
||||||
o << " " << (*i).s();
|
|
||||||
}
|
}
|
||||||
o << "\n";
|
o << "\n";
|
||||||
}
|
}
|
||||||
o << "Info Hash: " << util::toHex(torrentAttrs[INFO_HASH].s()) << "\n";
|
o << "Info Hash: "
|
||||||
o << "Piece Length: " << util::abbrevSize(dctx->getPieceLength()) << "B\n";
|
<< util::toHex(torrentAttrs->infoHash) << "\n"
|
||||||
o << "The Number of Pieces: " << dctx->getNumPieces() << "\n";
|
<< "Piece Length: "
|
||||||
o << "Total Length: " << util::abbrevSize(dctx->getTotalLength()) << "B ("
|
<< util::abbrevSize(dctx->getPieceLength()) << "B\n"
|
||||||
|
<< "The Number of Pieces: "
|
||||||
|
<< dctx->getNumPieces() << "\n"
|
||||||
|
<< "Total Length: "
|
||||||
|
<< util::abbrevSize(dctx->getTotalLength()) << "B ("
|
||||||
<< util::uitos(dctx->getTotalLength(), true) << ")\n";
|
<< util::uitos(dctx->getTotalLength(), true) << ")\n";
|
||||||
if(!torrentAttrs[URL_LIST].empty()) {
|
if(!torrentAttrs->urlList.empty()) {
|
||||||
const BDE& urlList = torrentAttrs[URL_LIST];
|
|
||||||
o << "URL List: " << "\n";
|
o << "URL List: " << "\n";
|
||||||
for(BDE::List::const_iterator i = urlList.listBegin(),
|
for(std::vector<std::string>::const_iterator i =
|
||||||
eoi = urlList.listEnd(); i != eoi; ++i) {
|
torrentAttrs->urlList.begin(),
|
||||||
o << " " << (*i).s() << "\n";
|
eoi = torrentAttrs->urlList.end(); i != eoi; ++i) {
|
||||||
|
o << " " << *i << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o << "Name: " << torrentAttrs[NAME].s() << "\n";
|
o << "Name: " << torrentAttrs->name << "\n"
|
||||||
o << "Magnet URI: " << torrent2Magnet(torrentAttrs) << "\n";
|
<< "Magnet URI: " << torrent2Magnet(torrentAttrs) << "\n";
|
||||||
util::toStream(dctx->getFileEntries().begin(), dctx->getFileEntries().end(), o);
|
util::toStream
|
||||||
|
(dctx->getFileEntries().begin(), dctx->getFileEntries().end(), o);
|
||||||
}
|
}
|
||||||
|
|
||||||
void computeFastSet
|
void computeFastSet
|
||||||
|
@ -857,22 +907,23 @@ void assertID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BDE parseMagnet(const std::string& magnet)
|
SharedHandle<TorrentAttribute> parseMagnet(const std::string& magnet)
|
||||||
{
|
{
|
||||||
BDE result;
|
SharedHandle<Dict> r = magnet::parse(magnet);
|
||||||
BDE r = magnet::parse(magnet);
|
if(r.isNull()) {
|
||||||
if(r.isNone()) {
|
|
||||||
throw DL_ABORT_EX("Bad BitTorrent Magnet URI.");
|
throw DL_ABORT_EX("Bad BitTorrent Magnet URI.");
|
||||||
}
|
}
|
||||||
if(!r.containsKey("xt")) {
|
const List* xts = asList(r->get("xt"));
|
||||||
|
if(!xts) {
|
||||||
throw DL_ABORT_EX("Missing xt parameter in Magnet URI.");
|
throw DL_ABORT_EX("Missing xt parameter in Magnet URI.");
|
||||||
}
|
}
|
||||||
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
std::string infoHash;
|
std::string infoHash;
|
||||||
const BDE& xts = r["xt"];
|
for(List::ValueType::const_iterator xtiter = xts->begin(),
|
||||||
for(BDE::List::const_iterator xtiter = xts.listBegin(),
|
eoi = xts->end(); xtiter != eoi && infoHash.empty(); ++xtiter) {
|
||||||
eoi = xts.listEnd(); xtiter != eoi && infoHash.empty(); ++xtiter) {
|
const String* xt = asString(*xtiter);
|
||||||
if(util::startsWith((*xtiter).s(), "urn:btih:")) {
|
if(util::startsWith(xt->s(), "urn:btih:")) {
|
||||||
std::string xtarg = (*xtiter).s().substr(9);
|
std::string xtarg = xt->s().substr(9);
|
||||||
size_t size = xtarg.size();
|
size_t size = xtarg.size();
|
||||||
if(size == 32) {
|
if(size == 32) {
|
||||||
std::string rawhash = base32::decode(xtarg);
|
std::string rawhash = base32::decode(xtarg);
|
||||||
|
@ -891,74 +942,82 @@ BDE parseMagnet(const std::string& magnet)
|
||||||
throw DL_ABORT_EX("Bad BitTorrent Magnet URI. "
|
throw DL_ABORT_EX("Bad BitTorrent Magnet URI. "
|
||||||
"No valid BitTorrent Info Hash found.");
|
"No valid BitTorrent Info Hash found.");
|
||||||
}
|
}
|
||||||
BDE announceList = BDE::list();
|
const List* trs = asList(r->get("tr"));
|
||||||
if(r.containsKey("tr")) {
|
if(trs) {
|
||||||
const BDE& uris = r["tr"];
|
for(List::ValueType::const_iterator i = trs->begin(), eoi = trs->end();
|
||||||
for(BDE::List::const_iterator i = uris.listBegin(), eoi = uris.listEnd();
|
|
||||||
i != eoi; ++i) {
|
i != eoi; ++i) {
|
||||||
BDE tier = BDE::list();
|
std::vector<std::string> tier;
|
||||||
tier << *i;
|
tier.push_back(asString(*i)->s());
|
||||||
announceList << tier;
|
attrs->announceList.push_back(tier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::string name = "[METADATA]";
|
std::string name = "[METADATA]";
|
||||||
if(r.containsKey("dn") && r["dn"].size()) {
|
const List* dns = asList(r->get("dn"));
|
||||||
name += r["dn"][0].s();
|
if(dns && !dns->empty()) {
|
||||||
|
const String* dn = asString(dns->get(0));
|
||||||
|
name += dn->s();
|
||||||
} else {
|
} else {
|
||||||
name += util::toHex(infoHash);
|
name += util::toHex(infoHash);
|
||||||
}
|
}
|
||||||
BDE attrs = BDE::dict();
|
attrs->infoHash = infoHash;
|
||||||
attrs[INFO_HASH] = infoHash;
|
attrs->name = name;
|
||||||
attrs[NAME] = name;
|
return attrs;
|
||||||
attrs[ANNOUNCE_LIST] = announceList;
|
|
||||||
result = attrs;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadMagnet
|
void loadMagnet
|
||||||
(const std::string& magnet, const SharedHandle<DownloadContext>& dctx)
|
(const std::string& magnet, const SharedHandle<DownloadContext>& dctx)
|
||||||
{
|
{
|
||||||
BDE attrs = parseMagnet(magnet);
|
SharedHandle<TorrentAttribute> attrs = parseMagnet(magnet);
|
||||||
dctx->setAttribute(BITTORRENT, attrs);
|
dctx->setAttribute(BITTORRENT, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string metadata2Torrent(const std::string& metadata, const BDE& attrs)
|
std::string metadata2Torrent
|
||||||
|
(const std::string& metadata, const SharedHandle<TorrentAttribute>& attrs)
|
||||||
{
|
{
|
||||||
std::string torrent = "d";
|
std::string torrent = "d";
|
||||||
if(attrs.containsKey(bittorrent::ANNOUNCE_LIST)) {
|
|
||||||
const BDE& announceList = attrs[bittorrent::ANNOUNCE_LIST];
|
List announceList;
|
||||||
if(announceList.size() > 0) {
|
for(std::vector<std::vector<std::string> >::const_iterator tierIter =
|
||||||
torrent += "13:announce-list";
|
attrs->announceList.begin(),
|
||||||
torrent += bencode::encode(announceList);
|
eoi = attrs->announceList.end(); tierIter != eoi; ++tierIter) {
|
||||||
|
SharedHandle<List> tier = List::g();
|
||||||
|
for(std::vector<std::string>::const_iterator uriIter = (*tierIter).begin(),
|
||||||
|
eoi2 = (*tierIter).end(); uriIter != eoi2; ++uriIter) {
|
||||||
|
tier->append(String::g(*uriIter));
|
||||||
}
|
}
|
||||||
|
if(!tier->empty()) {
|
||||||
|
announceList.append(tier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!announceList.empty()) {
|
||||||
|
torrent += "13:announce-list";
|
||||||
|
torrent += bencode2::encode(&announceList);
|
||||||
}
|
}
|
||||||
torrent +=
|
torrent +=
|
||||||
strconcat("4:info", metadata, "e");
|
strconcat("4:info", metadata, "e");
|
||||||
return torrent;
|
return torrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string torrent2Magnet(const BDE& attrs)
|
std::string torrent2Magnet(const SharedHandle<TorrentAttribute>& attrs)
|
||||||
{
|
{
|
||||||
std::string uri = "magnet:?";
|
std::string uri = "magnet:?";
|
||||||
if(attrs.containsKey(INFO_HASH)) {
|
if(!attrs->infoHash.empty()) {
|
||||||
uri += "xt=urn:btih:";
|
uri += "xt=urn:btih:";
|
||||||
uri += util::toUpper(util::toHex(attrs[INFO_HASH].s()));
|
uri += util::toUpper(util::toHex(attrs->infoHash));
|
||||||
} else {
|
} else {
|
||||||
return A2STR::NIL;
|
return A2STR::NIL;
|
||||||
}
|
}
|
||||||
if(attrs.containsKey(NAME)) {
|
if(!attrs->name.empty()) {
|
||||||
uri += "&dn=";
|
uri += "&dn=";
|
||||||
uri += util::percentEncode(attrs[NAME].s());
|
uri += util::percentEncode(attrs->name);
|
||||||
}
|
}
|
||||||
if(attrs.containsKey(ANNOUNCE_LIST)) {
|
for(std::vector<std::vector<std::string> >::const_iterator tierIter =
|
||||||
const BDE& tiers = attrs[ANNOUNCE_LIST];
|
attrs->announceList.begin(),
|
||||||
for(BDE::List::const_iterator tieriter = tiers.listBegin(),
|
eoi = attrs->announceList.end(); tierIter != eoi; ++tierIter) {
|
||||||
eoi = tiers.listEnd(); tieriter != eoi; ++tieriter) {
|
for(std::vector<std::string>::const_iterator uriIter = (*tierIter).begin(),
|
||||||
for(BDE::List::const_iterator uriiter = (*tieriter).listBegin(),
|
eoi2 = (*tierIter).end(); uriIter != eoi2; ++uriIter) {
|
||||||
eoi2 = (*tieriter).listEnd(); uriiter != eoi2; ++uriiter) {
|
|
||||||
uri += "&tr=";
|
uri += "&tr=";
|
||||||
uri += util::percentEncode((*uriiter).s());
|
uri += util::percentEncode(*uriIter);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return uri;
|
return uri;
|
||||||
|
|
|
@ -43,8 +43,8 @@
|
||||||
|
|
||||||
#include "SharedHandle.h"
|
#include "SharedHandle.h"
|
||||||
#include "AnnounceTier.h"
|
#include "AnnounceTier.h"
|
||||||
#include "BDE.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "TorrentAttribute.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -118,15 +118,16 @@ void loadFromMemory(const std::string& context,
|
||||||
const std::string& defaultName,
|
const std::string& defaultName,
|
||||||
const std::string& overrideName = "");
|
const std::string& overrideName = "");
|
||||||
|
|
||||||
// Parses BitTorrent Magnet URI and returns BDE::dict() which includes
|
// Parses BitTorrent Magnet URI and returns
|
||||||
// infoHash, name and announceList. If parsing operation failed, an
|
// SharedHandle<TorrentAttribute> which includes infoHash, name and
|
||||||
// RecoverableException will be thrown. infoHash and name are string
|
// announceList. If parsing operation failed, an RecoverableException
|
||||||
// and announceList is a list of list of announce URI.
|
// will be thrown. infoHash and name are string and announceList is a
|
||||||
|
// list of list of announce URI.
|
||||||
//
|
//
|
||||||
// magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
|
// magnet:?xt=urn:btih:<info-hash>&dn=<name>&tr=<tracker-url>
|
||||||
// <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii string,
|
// <info-hash> comes in 2 flavors: 40bytes hexadecimal ascii string,
|
||||||
// or 32bytes Base32 encoded string.
|
// or 32bytes Base32 encoded string.
|
||||||
BDE parseMagnet(const std::string& magnet);
|
SharedHandle<TorrentAttribute> parseMagnet(const std::string& magnet);
|
||||||
|
|
||||||
// Parses BitTorrent Magnet URI and set them in ctx as a
|
// Parses BitTorrent Magnet URI and set them in ctx as a
|
||||||
// bittorrent::BITTORRENT attibute. If parsing operation failed, an
|
// bittorrent::BITTORRENT attibute. If parsing operation failed, an
|
||||||
|
@ -161,6 +162,9 @@ void computeFastSet
|
||||||
// Writes the detailed information about torrent loaded in dctx.
|
// Writes the detailed information about torrent loaded in dctx.
|
||||||
void print(std::ostream& o, const SharedHandle<DownloadContext>& dctx);
|
void print(std::ostream& o, const SharedHandle<DownloadContext>& dctx);
|
||||||
|
|
||||||
|
SharedHandle<TorrentAttribute> getTorrentAttrs
|
||||||
|
(const SharedHandle<DownloadContext>& dctx);
|
||||||
|
|
||||||
// Returns the value associated with INFO_HASH key in BITTORRENT
|
// Returns the value associated with INFO_HASH key in BITTORRENT
|
||||||
// attribute.
|
// attribute.
|
||||||
const unsigned char*
|
const unsigned char*
|
||||||
|
@ -227,14 +231,13 @@ void assertPayloadLengthEqual
|
||||||
void assertID
|
void assertID
|
||||||
(uint8_t expected, const unsigned char* data, const std::string& msgName);
|
(uint8_t expected, const unsigned char* data, const std::string& msgName);
|
||||||
|
|
||||||
// Converts attrs into torrent data. attrs must be a BDE::dict. This
|
// Converts attrs into torrent data. This function does not guarantee
|
||||||
// function does not guarantee the returned string is valid torrent
|
// the returned string is valid torrent data.
|
||||||
// data.
|
std::string metadata2Torrent
|
||||||
std::string metadata2Torrent(const std::string& metadata, const BDE& attrs);
|
(const std::string& metadata, const SharedHandle<TorrentAttribute>& attrs);
|
||||||
|
|
||||||
// Constructs BitTorrent Magnet URI using attrs. attrs must be a
|
// Constructs BitTorrent Magnet URI using attrs.
|
||||||
// BDE::dict.
|
std::string torrent2Magnet(const SharedHandle<TorrentAttribute>& attrs);
|
||||||
std::string torrent2Magnet(const BDE& attrs);
|
|
||||||
|
|
||||||
} // namespace bittorrent
|
} // namespace bittorrent
|
||||||
|
|
||||||
|
|
|
@ -276,8 +276,9 @@ createBtMagnetRequestGroup(const std::string& magnetLink,
|
||||||
rg->setFileAllocationEnabled(false);
|
rg->setFileAllocationEnabled(false);
|
||||||
rg->setPreLocalFileCheckEnabled(false);
|
rg->setPreLocalFileCheckEnabled(false);
|
||||||
bittorrent::loadMagnet(magnetLink, dctx);
|
bittorrent::loadMagnet(magnetLink, dctx);
|
||||||
dctx->getFirstFileEntry()->setPath
|
SharedHandle<TorrentAttribute> torrentAttrs =
|
||||||
(dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::NAME].s());
|
bittorrent::getTorrentAttrs(dctx);
|
||||||
|
dctx->getFirstFileEntry()->setPath(torrentAttrs->name);
|
||||||
rg->setDownloadContext(dctx);
|
rg->setDownloadContext(dctx);
|
||||||
rg->clearPostDownloadHandler();
|
rg->clearPostDownloadHandler();
|
||||||
rg->addPostDownloadHandler
|
rg->addPostDownloadHandler
|
||||||
|
|
|
@ -39,31 +39,31 @@ namespace aria2 {
|
||||||
|
|
||||||
namespace magnet {
|
namespace magnet {
|
||||||
|
|
||||||
BDE parse(const std::string& magnet)
|
SharedHandle<Dict> parse(const std::string& magnet)
|
||||||
{
|
{
|
||||||
BDE result;
|
SharedHandle<Dict> dict;
|
||||||
if(!util::startsWith(magnet, "magnet:?")) {
|
if(!util::startsWith(magnet, "magnet:?")) {
|
||||||
return result;
|
return dict;
|
||||||
}
|
}
|
||||||
|
dict.reset(new Dict());
|
||||||
std::vector<std::string> queries;
|
std::vector<std::string> queries;
|
||||||
util::split(std::string(magnet.begin()+8, magnet.end()),
|
util::split(std::string(magnet.begin()+8, magnet.end()),
|
||||||
std::back_inserter(queries), "&");
|
std::back_inserter(queries), "&");
|
||||||
BDE dict = BDE::dict();
|
|
||||||
for(std::vector<std::string>::const_iterator i = queries.begin(),
|
for(std::vector<std::string>::const_iterator i = queries.begin(),
|
||||||
eoi = queries.end(); i != eoi; ++i) {
|
eoi = queries.end(); i != eoi; ++i) {
|
||||||
std::pair<std::string, std::string> kv;
|
std::pair<std::string, std::string> kv;
|
||||||
util::split(kv, *i, '=');
|
util::split(kv, *i, '=');
|
||||||
std::string value = util::percentDecode(kv.second);
|
std::string value = util::percentDecode(kv.second);
|
||||||
if(dict.containsKey(kv.first)) {
|
List* l = asList(dict->get(kv.first));
|
||||||
dict[kv.first] << value;
|
if(l) {
|
||||||
|
l->append(String::g(value));
|
||||||
} else {
|
} else {
|
||||||
BDE list = BDE::list();
|
SharedHandle<List> l = List::g();
|
||||||
list << value;
|
l->append(String::g(value));
|
||||||
dict[kv.first] = list;
|
dict->put(kv.first, l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result = dict;
|
return dict;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace magnet
|
} // namespace magnet
|
||||||
|
|
13
src/magnet.h
13
src/magnet.h
|
@ -36,17 +36,18 @@
|
||||||
#define _D_MAGNET_H_
|
#define _D_MAGNET_H_
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "BDE.h"
|
#include "ValueBase.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
namespace magnet {
|
namespace magnet {
|
||||||
|
|
||||||
// Parses Magnet URI magnet and stores parameters in BDE::dict().
|
// Parses Magnet URI magnet and stores parameters in
|
||||||
// Because same parameter name can appear more than once, the value
|
// SharedHandle<Dict>. Because same parameter name can appear more
|
||||||
// associated with a key is BDE::list(). A parameter value is stored
|
// than once, the value associated with a key is SharedHandle<List>. A
|
||||||
// in a list. If parsing operation failed, BDE::none is returned.
|
// parameter value is stored in a list. If parsing operation failed,
|
||||||
BDE parse(const std::string& magnet);
|
// SharedHandle<Dict>() is returned.
|
||||||
|
SharedHandle<Dict> parse(const std::string& magnet);
|
||||||
|
|
||||||
} // namespace magnet
|
} // namespace magnet
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <cppunit/extensions/HelperMacros.h>
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
#include "bencode.h"
|
#include "bencode2.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -42,13 +42,31 @@ public:
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION( AnnounceListTest );
|
CPPUNIT_TEST_SUITE_REGISTRATION( AnnounceListTest );
|
||||||
|
|
||||||
|
static std::vector<std::vector<std::string> > toVector
|
||||||
|
(const List* announceList)
|
||||||
|
{
|
||||||
|
std::vector<std::vector<std::string> > dest;
|
||||||
|
for(List::ValueType::const_iterator tierIter = announceList->begin(),
|
||||||
|
eoi = announceList->end(); tierIter != eoi; ++tierIter) {
|
||||||
|
std::vector<std::string> ntier;
|
||||||
|
const List* tier = asList(*tierIter);
|
||||||
|
for(List::ValueType::const_iterator uriIter = tier->begin(),
|
||||||
|
eoi2 = tier->end(); uriIter != eoi2; ++uriIter) {
|
||||||
|
const String* uri = asString(*uriIter);
|
||||||
|
ntier.push_back(uri->s());
|
||||||
|
}
|
||||||
|
dest.push_back(ntier);
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
void AnnounceListTest::testSingleElementList() {
|
void AnnounceListTest::testSingleElementList() {
|
||||||
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
|
||||||
// ANNOUNCE_LIST
|
// ANNOUNCE_LIST
|
||||||
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
||||||
AnnounceList announceList(announcesList);
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
|
|
||||||
CPPUNIT_ASSERT(!announceList.allTiersFailed());
|
CPPUNIT_ASSERT(!announceList.allTiersFailed());
|
||||||
std::string url = announceList.getAnnounce();
|
std::string url = announceList.getAnnounce();
|
||||||
|
@ -90,11 +108,11 @@ void AnnounceListTest::testSingleElementList() {
|
||||||
|
|
||||||
void AnnounceListTest::testMultiElementList() {
|
void AnnounceListTest::testMultiElementList() {
|
||||||
std::string peersString = "ll8:tracker18:tracker28:tracker3ee";
|
std::string peersString = "ll8:tracker18:tracker28:tracker3ee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
|
||||||
// ANNOUNCE_LIST
|
// ANNOUNCE_LIST
|
||||||
// [ [ tracker1, tracker2, tracker3 ] ]
|
// [ [ tracker1, tracker2, tracker3 ] ]
|
||||||
AnnounceList announceList(announcesList);
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
|
|
||||||
CPPUNIT_ASSERT(!announceList.allTiersFailed());
|
CPPUNIT_ASSERT(!announceList.allTiersFailed());
|
||||||
std::string url = announceList.getAnnounce();
|
std::string url = announceList.getAnnounce();
|
||||||
|
@ -123,11 +141,11 @@ void AnnounceListTest::testMultiElementList() {
|
||||||
|
|
||||||
void AnnounceListTest::testSingleAndMulti() {
|
void AnnounceListTest::testSingleAndMulti() {
|
||||||
std::string peersString = "ll8:tracker18:tracker2el8:tracker3ee";
|
std::string peersString = "ll8:tracker18:tracker2el8:tracker3ee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
|
||||||
// ANNOUNCE_LIST
|
// ANNOUNCE_LIST
|
||||||
// [ [ tracker1, tracker2 ], [ tracker3 ] ]
|
// [ [ tracker1, tracker2 ], [ tracker3 ] ]
|
||||||
AnnounceList announceList(announcesList);
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
|
|
||||||
std::string url = announceList.getAnnounce();
|
std::string url = announceList.getAnnounce();
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("tracker1"), url);
|
CPPUNIT_ASSERT_EQUAL(std::string("tracker1"), url);
|
||||||
|
@ -149,20 +167,18 @@ void AnnounceListTest::testSingleAndMulti() {
|
||||||
|
|
||||||
void AnnounceListTest::testNoGroup() {
|
void AnnounceListTest::testNoGroup() {
|
||||||
std::string peersString = "llee";
|
std::string peersString = "llee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
AnnounceList announceList(announcesList);
|
|
||||||
|
|
||||||
CPPUNIT_ASSERT(announceList.countTier() == 0);
|
CPPUNIT_ASSERT(announceList.countTier() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnnounceListTest::testNextEventIfAfterStarted() {
|
void AnnounceListTest::testNextEventIfAfterStarted() {
|
||||||
std::string peersString = "ll8:tracker1ee";
|
std::string peersString = "ll8:tracker1ee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
|
||||||
// ANNOUNCE_LIST
|
// ANNOUNCE_LIST
|
||||||
// [ [ tracker1 ] ]
|
// [ [ tracker1 ] ]
|
||||||
AnnounceList announceList(announcesList);
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
announceList.setEvent(AnnounceTier::STOPPED);
|
announceList.setEvent(AnnounceTier::STOPPED);
|
||||||
announceList.announceFailure();
|
announceList.announceFailure();
|
||||||
announceList.resetTier();
|
announceList.resetTier();
|
||||||
|
@ -178,11 +194,11 @@ void AnnounceListTest::testNextEventIfAfterStarted() {
|
||||||
|
|
||||||
void AnnounceListTest::testEvent() {
|
void AnnounceListTest::testEvent() {
|
||||||
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
|
||||||
// ANNOUNCE_LIST
|
// ANNOUNCE_LIST
|
||||||
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
||||||
AnnounceList announceList(announcesList);
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
|
|
||||||
announceList.setEvent(AnnounceTier::STOPPED);
|
announceList.setEvent(AnnounceTier::STOPPED);
|
||||||
announceList.announceSuccess();
|
announceList.announceSuccess();
|
||||||
|
@ -202,11 +218,11 @@ void AnnounceListTest::testEvent() {
|
||||||
|
|
||||||
void AnnounceListTest::testCountStoppedAllowedTier() {
|
void AnnounceListTest::testCountStoppedAllowedTier() {
|
||||||
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
|
||||||
// ANNOUNCE_LIST
|
// ANNOUNCE_LIST
|
||||||
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
||||||
AnnounceList announceList(announcesList);
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)0, announceList.countStoppedAllowedTier());
|
CPPUNIT_ASSERT_EQUAL((size_t)0, announceList.countStoppedAllowedTier());
|
||||||
announceList.setEvent(AnnounceTier::STARTED);
|
announceList.setEvent(AnnounceTier::STARTED);
|
||||||
|
@ -229,11 +245,11 @@ void AnnounceListTest::testCountStoppedAllowedTier() {
|
||||||
|
|
||||||
void AnnounceListTest::testCountCompletedAllowedTier() {
|
void AnnounceListTest::testCountCompletedAllowedTier() {
|
||||||
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
std::string peersString = "ll8:tracker1el8:tracker2el8:tracker3ee";
|
||||||
const BDE announcesList = bencode::decode(peersString);
|
SharedHandle<ValueBase> announcesList = bencode2::decode(peersString);
|
||||||
|
|
||||||
// ANNOUNCE_LIST
|
// ANNOUNCE_LIST
|
||||||
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
// [ [ tracker1 ], [ tracker2 ], [ tracker3 ] ]
|
||||||
AnnounceList announceList(announcesList);
|
AnnounceList announceList(toVector(asList(announcesList)));
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)0, announceList.countCompletedAllowedTier());
|
CPPUNIT_ASSERT_EQUAL((size_t)0, announceList.countCompletedAllowedTier());
|
||||||
announceList.setEvent(AnnounceTier::STARTED);
|
announceList.setEvent(AnnounceTier::STARTED);
|
||||||
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
#include "bencode2.h"
|
||||||
|
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
#include "RecoverableException.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
class Bencode2Test:public CppUnit::TestFixture {
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE(Bencode2Test);
|
||||||
|
CPPUNIT_TEST(testDecode);
|
||||||
|
CPPUNIT_TEST(testDecode_overflow);
|
||||||
|
CPPUNIT_TEST(testEncode);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
private:
|
||||||
|
|
||||||
|
public:
|
||||||
|
void testDecode();
|
||||||
|
void testDecode_overflow();
|
||||||
|
void testEncode();
|
||||||
|
};
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION( Bencode2Test );
|
||||||
|
|
||||||
|
void Bencode2Test::testDecode()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// string, integer and list in dict
|
||||||
|
SharedHandle<ValueBase> r =
|
||||||
|
bencode2::decode("d4:name5:aria24:sizei12345678900e5:filesl3:bin3:docee");
|
||||||
|
const Dict* dict = asDict(r);
|
||||||
|
CPPUNIT_ASSERT(dict);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"),
|
||||||
|
asString(dict->get("name"))->s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<Integer::ValueType>(12345678900LL),
|
||||||
|
asInteger(dict->get("size"))->i());
|
||||||
|
const List* list = asList(dict->get("files"));
|
||||||
|
CPPUNIT_ASSERT(list);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), list->size());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("bin"),
|
||||||
|
asString(list->get(0))->s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("doc"),
|
||||||
|
asString(list->get(1))->s());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// dict in list
|
||||||
|
SharedHandle<ValueBase> r = bencode2::decode("ld1:ki123eee");
|
||||||
|
const List* list = asList(r);
|
||||||
|
CPPUNIT_ASSERT(list);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), list->size());
|
||||||
|
const Dict* dict = asDict(list->get(0));
|
||||||
|
CPPUNIT_ASSERT(dict);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<Integer::ValueType>(123),
|
||||||
|
asInteger(dict->get("k"))->i());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// empty key is allowed
|
||||||
|
SharedHandle<ValueBase> s = bencode2::decode("d0:1:ve");
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// empty string
|
||||||
|
SharedHandle<ValueBase> s = bencode2::decode("0:");
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string(""), asString(s)->s());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// empty dict
|
||||||
|
SharedHandle<ValueBase> d = bencode2::decode("de");
|
||||||
|
CPPUNIT_ASSERT(asDict(d)->empty());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// empty list
|
||||||
|
SharedHandle<ValueBase> l = bencode2::decode("le");
|
||||||
|
CPPUNIT_ASSERT(asList(l)->empty());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// integer, without ending 'e'
|
||||||
|
try {
|
||||||
|
bencode2::decode("i3");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:"
|
||||||
|
" Delimiter 'e' not found."),
|
||||||
|
std::string(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// dict, without ending 'e'
|
||||||
|
try {
|
||||||
|
bencode2::decode("d");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:"
|
||||||
|
" Unexpected EOF in dict context."
|
||||||
|
" 'e' expected."),
|
||||||
|
std::string(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// list, without ending 'e'
|
||||||
|
try {
|
||||||
|
bencode2::decode("l");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:"
|
||||||
|
" Unexpected EOF in list context."
|
||||||
|
" 'e' expected."),
|
||||||
|
std::string(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// string, less than the specified length.
|
||||||
|
try {
|
||||||
|
bencode2::decode("3:ab");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:"
|
||||||
|
" Expected 3 bytes of data,"
|
||||||
|
" but only 2 read."),
|
||||||
|
std::string(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// string, but length is invalid
|
||||||
|
try {
|
||||||
|
bencode2::decode("x:abc");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:"
|
||||||
|
" A positive integer expected"
|
||||||
|
" but none found."),
|
||||||
|
std::string(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// string with minus length
|
||||||
|
try {
|
||||||
|
bencode2::decode("-1:a");
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("Bencode decoding failed:"
|
||||||
|
" A positive integer expected"
|
||||||
|
" but none found."),
|
||||||
|
std::string(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// empty encoded data
|
||||||
|
CPPUNIT_ASSERT(bencode2::decode("").isNull());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// ignore trailing garbage at the end of the input.
|
||||||
|
SharedHandle<ValueBase> s = bencode2::decode("5:aria2trail");
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), asString(s)->s());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Get trailing garbage position
|
||||||
|
size_t end;
|
||||||
|
SharedHandle<ValueBase> s = bencode2::decode("5:aria2trail", end);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), asString(s)->s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL((size_t)7, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bencode2Test::testDecode_overflow()
|
||||||
|
{
|
||||||
|
std::string s;
|
||||||
|
size_t depth = bencode2::MAX_STRUCTURE_DEPTH+1;
|
||||||
|
for(size_t i = 0; i < depth; ++i) {
|
||||||
|
s += "l";
|
||||||
|
}
|
||||||
|
for(size_t i = 0; i < depth; ++i) {
|
||||||
|
s += "e";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
bencode2::decode(s);
|
||||||
|
CPPUNIT_FAIL("exception must be thrown.");
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
// success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bencode2Test::testEncode()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Dict dict;
|
||||||
|
dict["name"] = String::g("aria2");
|
||||||
|
dict["loc"] = Integer::g(80000);
|
||||||
|
SharedHandle<List> files = List::g();
|
||||||
|
files->append(String::g("aria2c"));
|
||||||
|
dict["files"] = files;
|
||||||
|
SharedHandle<Dict> attrs = Dict::g();
|
||||||
|
attrs->put("license", String::g("GPL"));
|
||||||
|
dict["attrs"] = attrs;
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("d"
|
||||||
|
"5:attrsd7:license3:GPLe"
|
||||||
|
"5:filesl6:aria2ce"
|
||||||
|
"3:loci80000e"
|
||||||
|
"4:name5:aria2"
|
||||||
|
"e"),
|
||||||
|
bencode2::encode(&dict));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -1,8 +1,11 @@
|
||||||
#include "bencode.h"
|
#include "bencode.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <cppunit/extensions/HelperMacros.h>
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
#include "RecoverableException.h"
|
#include "RecoverableException.h"
|
||||||
|
#include "TimeA2.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include "array_fun.h"
|
#include "array_fun.h"
|
||||||
#include "messageDigest.h"
|
#include "messageDigest.h"
|
||||||
#include "a2netcompat.h"
|
#include "a2netcompat.h"
|
||||||
#include "bencode.h"
|
#include "bencode2.h"
|
||||||
#include "TestUtil.h"
|
#include "TestUtil.h"
|
||||||
#include "base32.h"
|
#include "base32.h"
|
||||||
|
|
||||||
|
@ -111,26 +111,6 @@ public:
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION(BittorrentHelperTest);
|
CPPUNIT_TEST_SUITE_REGISTRATION(BittorrentHelperTest);
|
||||||
|
|
||||||
static const BDE& getAnnounceList(const SharedHandle<DownloadContext>& dctx)
|
|
||||||
{
|
|
||||||
return dctx->getAttribute(BITTORRENT)[ANNOUNCE_LIST];
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string& getMode(const SharedHandle<DownloadContext>& dctx)
|
|
||||||
{
|
|
||||||
return dctx->getAttribute(BITTORRENT)[MODE].s();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string& getName(const SharedHandle<DownloadContext>& dctx)
|
|
||||||
{
|
|
||||||
return dctx->getAttribute(BITTORRENT)[NAME].s();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const BDE& getNodes(const SharedHandle<DownloadContext>& dctx)
|
|
||||||
{
|
|
||||||
return dctx->getAttribute(BITTORRENT)[NODES];
|
|
||||||
}
|
|
||||||
|
|
||||||
void BittorrentHelperTest::testGetInfoHash() {
|
void BittorrentHelperTest::testGetInfoHash() {
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("test.torrent", dctx);
|
load("test.torrent", dctx);
|
||||||
|
@ -210,21 +190,21 @@ void BittorrentHelperTest::testGetFileModeMulti() {
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("test.torrent", dctx);
|
load("test.torrent", dctx);
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(MULTI, getMode(dctx));
|
CPPUNIT_ASSERT_EQUAL(MULTI, getTorrentAttrs(dctx)->mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testGetFileModeSingle() {
|
void BittorrentHelperTest::testGetFileModeSingle() {
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("single.torrent", dctx);
|
load("single.torrent", dctx);
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(SINGLE, getMode(dctx));
|
CPPUNIT_ASSERT_EQUAL(SINGLE, getTorrentAttrs(dctx)->mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testGetNameMulti() {
|
void BittorrentHelperTest::testGetNameMulti() {
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("test.torrent", dctx);
|
load("test.torrent", dctx);
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2-test"), getName(dctx));
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-test"), getTorrentAttrs(dctx)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testGetNameSingle() {
|
void BittorrentHelperTest::testGetNameSingle() {
|
||||||
|
@ -233,7 +213,8 @@ void BittorrentHelperTest::testGetNameSingle() {
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("./aria2-0.8.2.tar.bz2"),
|
CPPUNIT_ASSERT_EQUAL(std::string("./aria2-0.8.2.tar.bz2"),
|
||||||
dctx->getBasePath());
|
dctx->getBasePath());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.8.2.tar.bz2"), getName(dctx));
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-0.8.2.tar.bz2"),
|
||||||
|
getTorrentAttrs(dctx)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testOverrideName()
|
void BittorrentHelperTest::testOverrideName()
|
||||||
|
@ -242,46 +223,41 @@ void BittorrentHelperTest::testOverrideName()
|
||||||
load("test.torrent", dctx, "aria2-override.name");
|
load("test.torrent", dctx, "aria2-override.name");
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("./aria2-override.name"),
|
CPPUNIT_ASSERT_EQUAL(std::string("./aria2-override.name"),
|
||||||
dctx->getBasePath());
|
dctx->getBasePath());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"), getName(dctx));
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"),
|
||||||
|
getTorrentAttrs(dctx)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BittorrentHelperTest::testGetAnnounceTier() {
|
void BittorrentHelperTest::testGetAnnounceTier() {
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("single.torrent", dctx);
|
load("single.torrent", dctx);
|
||||||
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
const BDE& announceList = getAnnounceList(dctx);
|
|
||||||
|
|
||||||
// There is 1 tier.
|
// There is 1 tier.
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, announceList.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList.size());
|
||||||
|
|
||||||
const BDE& tier = announceList[0];
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[0].size());
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, tier.size());
|
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.com/announce.php"),
|
CPPUNIT_ASSERT_EQUAL(std::string("http://aria.rednoah.com/announce.php"),
|
||||||
tier[0].s());
|
attrs->announceList[0][0]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testGetAnnounceTierAnnounceList() {
|
void BittorrentHelperTest::testGetAnnounceTierAnnounceList() {
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("test.torrent", dctx);
|
load("test.torrent", dctx);
|
||||||
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
const BDE& announceList = getAnnounceList(dctx);
|
|
||||||
|
|
||||||
// There are 3 tiers.
|
// There are 3 tiers.
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)3, announceList.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)3, attrs->announceList.size());
|
||||||
|
|
||||||
const BDE& tier1 = announceList[0];
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[0].size());
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, tier1.size());
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"),
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), tier1[0].s());
|
attrs->announceList[0][0]);
|
||||||
|
|
||||||
const BDE& tier2 = announceList[1];
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[1].size());
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, tier2.size());
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"),
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), tier2[0].s());
|
attrs->announceList[1][0]);
|
||||||
|
|
||||||
const BDE& tier3 = announceList[2];
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->announceList[2].size());
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, tier3.size());
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker3"),
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker3"), tier3[0].s());
|
attrs->announceList[2][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testGetPieceLength() {
|
void BittorrentHelperTest::testGetPieceLength() {
|
||||||
|
@ -440,7 +416,8 @@ void BittorrentHelperTest::testLoadFromMemory_overrideName()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
loadFromMemory(memory, dctx, "default", "aria2-override.name");
|
loadFromMemory(memory, dctx, "default", "aria2-override.name");
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"), getName(dctx));
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2-override.name"),
|
||||||
|
getTorrentAttrs(dctx)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testLoadFromMemory_multiFileDirTraversal()
|
void BittorrentHelperTest::testLoadFromMemory_multiFileDirTraversal()
|
||||||
|
@ -486,12 +463,12 @@ void BittorrentHelperTest::testGetNodes()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
loadFromMemory(memory, dctx, "default");
|
loadFromMemory(memory, dctx, "default");
|
||||||
|
|
||||||
const BDE& nodes = getNodes(dctx);
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)2, nodes.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)2, attrs->nodes.size());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), nodes[0][HOSTNAME].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.1"), attrs->nodes[0].first);
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)6881, (uint16_t)nodes[0][PORT].i());
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6881, attrs->nodes[0].second);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[1][HOSTNAME].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[1].first);
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[1][PORT].i());
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[1].second);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// empty hostname
|
// empty hostname
|
||||||
|
@ -506,10 +483,10 @@ void BittorrentHelperTest::testGetNodes()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
loadFromMemory(memory, dctx, "default");
|
loadFromMemory(memory, dctx, "default");
|
||||||
|
|
||||||
const BDE& nodes = getNodes(dctx);
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first);
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i());
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// bad port
|
// bad port
|
||||||
|
@ -524,10 +501,10 @@ void BittorrentHelperTest::testGetNodes()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
loadFromMemory(memory, dctx, "default");
|
loadFromMemory(memory, dctx, "default");
|
||||||
|
|
||||||
const BDE& nodes = getNodes(dctx);
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first);
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i());
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// port missing
|
// port missing
|
||||||
|
@ -542,10 +519,10 @@ void BittorrentHelperTest::testGetNodes()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
loadFromMemory(memory, dctx, "default");
|
loadFromMemory(memory, dctx, "default");
|
||||||
|
|
||||||
const BDE& nodes = getNodes(dctx);
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first);
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i());
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// nodes is not a list
|
// nodes is not a list
|
||||||
|
@ -559,7 +536,8 @@ void BittorrentHelperTest::testGetNodes()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
loadFromMemory(memory, dctx, "default");
|
loadFromMemory(memory, dctx, "default");
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)0, getNodes(dctx).size());
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
|
CPPUNIT_ASSERT_EQUAL((size_t)0, attrs->nodes.size());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// the element of node is not Data
|
// the element of node is not Data
|
||||||
|
@ -574,10 +552,10 @@ void BittorrentHelperTest::testGetNodes()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
loadFromMemory(memory, dctx, "default");
|
loadFromMemory(memory, dctx, "default");
|
||||||
|
|
||||||
const BDE& nodes = getNodes(dctx);
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, nodes.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, attrs->nodes.size());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), nodes[0][HOSTNAME].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("192.168.0.2"), attrs->nodes[0].first);
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, (uint16_t)nodes[0][PORT].i());
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6882, attrs->nodes[0].second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,11 +621,12 @@ void BittorrentHelperTest::testUTF8Torrent()
|
||||||
{
|
{
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("utf8.torrent", dctx);
|
load("utf8.torrent", dctx);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("name in utf-8"), getName(dctx));
|
CPPUNIT_ASSERT_EQUAL(std::string("name in utf-8"),
|
||||||
|
getTorrentAttrs(dctx)->name);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("./name in utf-8/path in utf-8"),
|
CPPUNIT_ASSERT_EQUAL(std::string("./name in utf-8/path in utf-8"),
|
||||||
dctx->getFirstFileEntry()->getPath());
|
dctx->getFirstFileEntry()->getPath());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("This is utf8 comment."),
|
CPPUNIT_ASSERT_EQUAL(std::string("This is utf8 comment."),
|
||||||
dctx->getAttribute(BITTORRENT)[COMMENT].s());
|
getTorrentAttrs(dctx)->comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testEtc()
|
void BittorrentHelperTest::testEtc()
|
||||||
|
@ -655,11 +634,11 @@ void BittorrentHelperTest::testEtc()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("test.torrent", dctx);
|
load("test.torrent", dctx);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("REDNOAH.COM RULES"),
|
CPPUNIT_ASSERT_EQUAL(std::string("REDNOAH.COM RULES"),
|
||||||
dctx->getAttribute(BITTORRENT)[COMMENT].s());
|
getTorrentAttrs(dctx)->comment);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2"),
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"),
|
||||||
dctx->getAttribute(BITTORRENT)[CREATED_BY].s());
|
getTorrentAttrs(dctx)->createdBy);
|
||||||
CPPUNIT_ASSERT_EQUAL((int64_t)1123456789,
|
CPPUNIT_ASSERT_EQUAL((int64_t)1123456789,
|
||||||
dctx->getAttribute(BITTORRENT)[CREATION_DATE].i());
|
getTorrentAttrs(dctx)->creationDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testCreatecompact()
|
void BittorrentHelperTest::testCreatecompact()
|
||||||
|
@ -698,13 +677,12 @@ void BittorrentHelperTest::testMetadata() {
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
load("test.torrent", dctx);
|
load("test.torrent", dctx);
|
||||||
std::string torrentData = readFile("test.torrent");
|
std::string torrentData = readFile("test.torrent");
|
||||||
BDE tr = bencode::decode(torrentData);
|
SharedHandle<ValueBase> tr = bencode2::decode(torrentData);
|
||||||
BDE infoDic = tr["info"];
|
SharedHandle<ValueBase> infoDic = asDict(tr)->get("info");
|
||||||
std::string metadata = bencode::encode(infoDic);
|
std::string metadata = bencode2::encode(infoDic);
|
||||||
const BDE& attrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs = getTorrentAttrs(dctx);
|
||||||
CPPUNIT_ASSERT(metadata == attrs[bittorrent::METADATA].s());
|
CPPUNIT_ASSERT(metadata == attrs->metadata);
|
||||||
CPPUNIT_ASSERT_EQUAL(metadata.size(),
|
CPPUNIT_ASSERT_EQUAL(metadata.size(), attrs->metadataSize);
|
||||||
(size_t)attrs[bittorrent::METADATA_SIZE].i());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testParseMagnet()
|
void BittorrentHelperTest::testParseMagnet()
|
||||||
|
@ -712,29 +690,28 @@ void BittorrentHelperTest::testParseMagnet()
|
||||||
std::string magnet =
|
std::string magnet =
|
||||||
"magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2"
|
"magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2"
|
||||||
"&tr=http://tracker1&tr=http://tracker2";
|
"&tr=http://tracker1&tr=http://tracker2";
|
||||||
BDE attrs = bittorrent::parseMagnet(magnet);
|
SharedHandle<TorrentAttribute> attrs = bittorrent::parseMagnet(magnet);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
util::toHex(attrs[bittorrent::INFO_HASH].s()));
|
util::toHex(attrs->infoHash));
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("[METADATA]aria2"),
|
CPPUNIT_ASSERT_EQUAL(std::string("[METADATA]aria2"), attrs->name);
|
||||||
attrs[bittorrent::NAME].s());
|
CPPUNIT_ASSERT_EQUAL((size_t)2, attrs->announceList.size());
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)2, attrs[bittorrent::ANNOUNCE_LIST].size());
|
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"),
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"),
|
||||||
attrs[bittorrent::ANNOUNCE_LIST][0][0].s());
|
attrs->announceList[0][0]);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"),
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"),
|
||||||
attrs[bittorrent::ANNOUNCE_LIST][1][0].s());
|
attrs->announceList[1][0]);
|
||||||
|
|
||||||
magnet = "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
magnet = "magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
||||||
attrs = bittorrent::parseMagnet(magnet);
|
attrs = bittorrent::parseMagnet(magnet);
|
||||||
CPPUNIT_ASSERT_EQUAL
|
CPPUNIT_ASSERT_EQUAL
|
||||||
(std::string("[METADATA]248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
(std::string("[METADATA]248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
attrs[bittorrent::NAME].s());
|
attrs->name);
|
||||||
CPPUNIT_ASSERT(attrs[bittorrent::ANNOUNCE_LIST].size() == 0);
|
CPPUNIT_ASSERT(attrs->announceList.empty());
|
||||||
|
|
||||||
magnet = "magnet:?xt=urn:sha1:7899bdb90a026c746f3cbc10839dd9b2a2a3e985&"
|
magnet = "magnet:?xt=urn:sha1:7899bdb90a026c746f3cbc10839dd9b2a2a3e985&"
|
||||||
"xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
"xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
||||||
attrs = bittorrent::parseMagnet(magnet);
|
attrs = bittorrent::parseMagnet(magnet);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
CPPUNIT_ASSERT_EQUAL(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
util::toHex(attrs[bittorrent::INFO_HASH].s()));
|
util::toHex(attrs->infoHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testParseMagnet_base32()
|
void BittorrentHelperTest::testParseMagnet_base32()
|
||||||
|
@ -742,22 +719,20 @@ void BittorrentHelperTest::testParseMagnet_base32()
|
||||||
std::string infoHash = "248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
std::string infoHash = "248d0a1cd08284299de78d5c1ed359bb46717d8c";
|
||||||
std::string base32InfoHash = base32::encode(util::fromHex(infoHash));
|
std::string base32InfoHash = base32::encode(util::fromHex(infoHash));
|
||||||
std::string magnet = "magnet:?xt=urn:btih:"+base32InfoHash+"&dn=aria2";
|
std::string magnet = "magnet:?xt=urn:btih:"+base32InfoHash+"&dn=aria2";
|
||||||
BDE attrs = bittorrent::parseMagnet(magnet);
|
SharedHandle<TorrentAttribute> attrs = bittorrent::parseMagnet(magnet);
|
||||||
CPPUNIT_ASSERT_EQUAL
|
CPPUNIT_ASSERT_EQUAL
|
||||||
(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
(std::string("248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
util::toHex(attrs[bittorrent::INFO_HASH].s()));
|
util::toHex(attrs->infoHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
void BittorrentHelperTest::testMetadata2Torrent()
|
void BittorrentHelperTest::testMetadata2Torrent()
|
||||||
{
|
{
|
||||||
std::string metadata = "METADATA";
|
std::string metadata = "METADATA";
|
||||||
BDE attrs = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
BDE announceList = BDE::list();
|
|
||||||
attrs[ANNOUNCE_LIST] = announceList;
|
|
||||||
CPPUNIT_ASSERT_EQUAL
|
CPPUNIT_ASSERT_EQUAL
|
||||||
(std::string("d4:infoMETADATAe"), metadata2Torrent(metadata, attrs));
|
(std::string("d4:infoMETADATAe"), metadata2Torrent(metadata, attrs));
|
||||||
announceList << BDE::list();
|
attrs->announceList.push_back(std::vector<std::string>());
|
||||||
announceList[0] << std::string("http://localhost/announce");
|
attrs->announceList[0].push_back("http://localhost/announce");
|
||||||
CPPUNIT_ASSERT_EQUAL
|
CPPUNIT_ASSERT_EQUAL
|
||||||
(std::string("d"
|
(std::string("d"
|
||||||
"13:announce-list"
|
"13:announce-list"
|
||||||
|
@ -778,7 +753,7 @@ void BittorrentHelperTest::testTorrent2Magnet()
|
||||||
"&tr=http%3A%2F%2Ftracker1"
|
"&tr=http%3A%2F%2Ftracker1"
|
||||||
"&tr=http%3A%2F%2Ftracker2"
|
"&tr=http%3A%2F%2Ftracker2"
|
||||||
"&tr=http%3A%2F%2Ftracker3"),
|
"&tr=http%3A%2F%2Ftracker3"),
|
||||||
torrent2Magnet(dctx->getAttribute(BITTORRENT)));
|
torrent2Magnet(getTorrentAttrs(dctx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace bittorrent
|
} // namespace bittorrent
|
||||||
|
|
|
@ -179,7 +179,7 @@ void BtDependencyTest::testResolve_metadata()
|
||||||
pieceStorage->setDiskAdaptor(diskAdaptor);
|
pieceStorage->setDiskAdaptor(diskAdaptor);
|
||||||
pieceStorage->setDownloadFinished(true);
|
pieceStorage->setDownloadFinished(true);
|
||||||
dependee->setPieceStorage(pieceStorage);
|
dependee->setPieceStorage(pieceStorage);
|
||||||
BDE attrs = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
dependee->getDownloadContext()->setAttribute(bittorrent::BITTORRENT, attrs);
|
dependee->getDownloadContext()->setAttribute(bittorrent::BITTORRENT, attrs);
|
||||||
|
|
||||||
BtDependency dep(dependant, dependee);
|
BtDependency dep(dependant, dependee);
|
||||||
|
|
|
@ -63,10 +63,10 @@ void BtRegistryTest::testGetDownloadContext_infoHash()
|
||||||
{
|
{
|
||||||
BtRegistry btRegistry;
|
BtRegistry btRegistry;
|
||||||
addTwoDownloadContext(btRegistry);
|
addTwoDownloadContext(btRegistry);
|
||||||
BDE attrs1 = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs1(new TorrentAttribute());
|
||||||
attrs1[bittorrent::INFO_HASH] = std::string("hash1");
|
attrs1->infoHash = "hash1";
|
||||||
BDE attrs2 = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs2(new TorrentAttribute());
|
||||||
attrs2[bittorrent::INFO_HASH] = std::string("hash2");
|
attrs2->infoHash = "hash2";
|
||||||
btRegistry.getDownloadContext(1)->setAttribute
|
btRegistry.getDownloadContext(1)->setAttribute
|
||||||
(bittorrent::BITTORRENT, attrs1);
|
(bittorrent::BITTORRENT, attrs1);
|
||||||
btRegistry.getDownloadContext(2)->setAttribute
|
btRegistry.getDownloadContext(2)->setAttribute
|
||||||
|
|
|
@ -56,9 +56,8 @@ public:
|
||||||
std::string peerId = "-aria2-ultrafastdltl";
|
std::string peerId = "-aria2-ultrafastdltl";
|
||||||
|
|
||||||
_dctx.reset(new DownloadContext(pieceLength, totalLength));
|
_dctx.reset(new DownloadContext(pieceLength, totalLength));
|
||||||
BDE torrentAttrs = BDE::dict();
|
SharedHandle<TorrentAttribute> torrentAttrs(new TorrentAttribute());
|
||||||
torrentAttrs[bittorrent::INFO_HASH] =
|
torrentAttrs->infoHash = std::string(vbegin(infoHash), vend(infoHash));
|
||||||
std::string(vbegin(infoHash), vend(infoHash));
|
|
||||||
_dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs);
|
_dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs);
|
||||||
bittorrent::setStaticPeerId(peerId);
|
bittorrent::setStaticPeerId(peerId);
|
||||||
|
|
||||||
|
@ -97,34 +96,46 @@ public:
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtAnnounceTest);
|
CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtAnnounceTest);
|
||||||
|
|
||||||
template<typename InputIterator>
|
template<typename InputIterator>
|
||||||
static BDE createAnnounceTier(InputIterator first, InputIterator last)
|
static SharedHandle<List> createAnnounceTier
|
||||||
|
(InputIterator first, InputIterator last)
|
||||||
{
|
{
|
||||||
BDE announceTier = BDE::list();
|
SharedHandle<List> announceTier = List::g();
|
||||||
for(; first != last; ++first) {
|
for(; first != last; ++first) {
|
||||||
announceTier << BDE(*first);
|
announceTier->append(String::g(*first));
|
||||||
}
|
}
|
||||||
return announceTier;
|
return announceTier;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BDE createAnnounceTier(const std::string& uri)
|
static SharedHandle<List> createAnnounceTier(const std::string& uri)
|
||||||
{
|
{
|
||||||
BDE announceTier = BDE::list();
|
SharedHandle<List> announceTier = List::g();
|
||||||
announceTier << uri;
|
announceTier->append(String::g(uri));
|
||||||
return announceTier;
|
return announceTier;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setAnnounceList(const SharedHandle<DownloadContext>& dctx,
|
static void setAnnounceList(const SharedHandle<DownloadContext>& dctx,
|
||||||
const BDE& announceList)
|
const SharedHandle<List>& announceList)
|
||||||
{
|
{
|
||||||
dctx->getAttribute(bittorrent::BITTORRENT)[bittorrent::ANNOUNCE_LIST] =
|
std::vector<std::vector<std::string> > dest;
|
||||||
announceList;
|
for(List::ValueType::const_iterator tierIter = announceList->begin(),
|
||||||
|
eoi = announceList->end(); tierIter != eoi; ++tierIter) {
|
||||||
|
std::vector<std::string> ntier;
|
||||||
|
const List* tier = asList(*tierIter);
|
||||||
|
for(List::ValueType::const_iterator uriIter = tier->begin(),
|
||||||
|
eoi2 = tier->end(); uriIter != eoi2; ++uriIter) {
|
||||||
|
const String* uri = asString(*uriIter);
|
||||||
|
ntier.push_back(uri->s());
|
||||||
|
}
|
||||||
|
dest.push_back(ntier);
|
||||||
|
}
|
||||||
|
bittorrent::getTorrentAttrs(dctx)->announceList.swap(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefaultBtAnnounceTest::testNoMoreAnnounce()
|
void DefaultBtAnnounceTest::testNoMoreAnnounce()
|
||||||
{
|
{
|
||||||
BDE announceList = BDE::list();
|
SharedHandle<List> announceList = List::g();
|
||||||
announceList << createAnnounceTier("http://localhost/announce");
|
announceList->append(createAnnounceTier("http://localhost/announce"));
|
||||||
announceList << createAnnounceTier("http://backup/announce");
|
announceList->append(createAnnounceTier("http://backup/announce"));
|
||||||
|
|
||||||
setAnnounceList(_dctx, announceList);
|
setAnnounceList(_dctx, announceList);
|
||||||
|
|
||||||
|
@ -172,8 +183,8 @@ void DefaultBtAnnounceTest::testNoMoreAnnounce()
|
||||||
void DefaultBtAnnounceTest::testGetAnnounceUrl()
|
void DefaultBtAnnounceTest::testGetAnnounceUrl()
|
||||||
{
|
{
|
||||||
|
|
||||||
BDE announceList = BDE::list();
|
SharedHandle<List> announceList = List::g();
|
||||||
announceList << createAnnounceTier("http://localhost/announce");
|
announceList->append(createAnnounceTier("http://localhost/announce"));
|
||||||
setAnnounceList(_dctx, announceList);
|
setAnnounceList(_dctx, announceList);
|
||||||
|
|
||||||
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
||||||
|
@ -203,8 +214,8 @@ void DefaultBtAnnounceTest::testGetAnnounceUrl()
|
||||||
|
|
||||||
void DefaultBtAnnounceTest::testGetAnnounceUrl_withQuery()
|
void DefaultBtAnnounceTest::testGetAnnounceUrl_withQuery()
|
||||||
{
|
{
|
||||||
BDE announceList = BDE::list();
|
SharedHandle<List> announceList = List::g();
|
||||||
announceList << createAnnounceTier("http://localhost/announce?k=v");
|
announceList->append(createAnnounceTier("http://localhost/announce?k=v"));
|
||||||
setAnnounceList(_dctx, announceList);
|
setAnnounceList(_dctx, announceList);
|
||||||
|
|
||||||
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
||||||
|
@ -225,8 +236,8 @@ void DefaultBtAnnounceTest::testGetAnnounceUrl_withQuery()
|
||||||
|
|
||||||
void DefaultBtAnnounceTest::testGetAnnounceUrl_externalIP()
|
void DefaultBtAnnounceTest::testGetAnnounceUrl_externalIP()
|
||||||
{
|
{
|
||||||
BDE announceList = BDE::list();
|
SharedHandle<List> announceList = List::g();
|
||||||
announceList << createAnnounceTier("http://localhost/announce");
|
announceList->append(createAnnounceTier("http://localhost/announce"));
|
||||||
setAnnounceList(_dctx, announceList);
|
setAnnounceList(_dctx, announceList);
|
||||||
|
|
||||||
_option->put(PREF_BT_EXTERNAL_IP, "192.168.1.1");
|
_option->put(PREF_BT_EXTERNAL_IP, "192.168.1.1");
|
||||||
|
@ -248,9 +259,9 @@ void DefaultBtAnnounceTest::testGetAnnounceUrl_externalIP()
|
||||||
|
|
||||||
void DefaultBtAnnounceTest::testIsAllAnnounceFailed()
|
void DefaultBtAnnounceTest::testIsAllAnnounceFailed()
|
||||||
{
|
{
|
||||||
BDE announceList = BDE::list();
|
SharedHandle<List> announceList = List::g();
|
||||||
announceList << createAnnounceTier("http://localhost/announce");
|
announceList->append(createAnnounceTier("http://localhost/announce"));
|
||||||
announceList << createAnnounceTier("http://backup/announce");
|
announceList->append(createAnnounceTier("http://backup/announce"));
|
||||||
setAnnounceList(_dctx, announceList);
|
setAnnounceList(_dctx, announceList);
|
||||||
|
|
||||||
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
||||||
|
@ -281,8 +292,8 @@ void DefaultBtAnnounceTest::testURLOrderInStoppedEvent()
|
||||||
const char* urls[] = { "http://localhost1/announce",
|
const char* urls[] = { "http://localhost1/announce",
|
||||||
"http://localhost2/announce" };
|
"http://localhost2/announce" };
|
||||||
|
|
||||||
BDE announceList = BDE::list();
|
SharedHandle<List> announceList = List::g();
|
||||||
announceList << createAnnounceTier(vbegin(urls), vend(urls));
|
announceList->append(createAnnounceTier(vbegin(urls), vend(urls)));
|
||||||
setAnnounceList(_dctx, announceList);
|
setAnnounceList(_dctx, announceList);
|
||||||
|
|
||||||
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
||||||
|
@ -311,8 +322,8 @@ void DefaultBtAnnounceTest::testURLOrderInCompletedEvent()
|
||||||
const char* urls[] = { "http://localhost1/announce",
|
const char* urls[] = { "http://localhost1/announce",
|
||||||
"http://localhost2/announce" };
|
"http://localhost2/announce" };
|
||||||
|
|
||||||
BDE announceList = BDE::list();
|
SharedHandle<List> announceList = List::g();
|
||||||
announceList << createAnnounceTier(vbegin(urls), vend(urls));
|
announceList->append(createAnnounceTier(vbegin(urls), vend(urls)));
|
||||||
setAnnounceList(_dctx, announceList);
|
setAnnounceList(_dctx, announceList);
|
||||||
|
|
||||||
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
DefaultBtAnnounce btAnnounce(_dctx, _option);
|
||||||
|
|
|
@ -70,9 +70,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
_dctx.reset(new DownloadContext());
|
_dctx.reset(new DownloadContext());
|
||||||
BDE torrentAttrs = BDE::dict();
|
SharedHandle<TorrentAttribute> torrentAttrs(new TorrentAttribute());
|
||||||
torrentAttrs[bittorrent::INFO_HASH] =
|
torrentAttrs->infoHash = std::string(vbegin(infoHash), vend(infoHash));
|
||||||
std::string(vbegin(infoHash), vend(infoHash));
|
|
||||||
_dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs);
|
_dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs);
|
||||||
_dctx->setDir(_option->get(PREF_DIR));
|
_dctx->setDir(_option->get(PREF_DIR));
|
||||||
const SharedHandle<FileEntry> fileEntries[] = {
|
const SharedHandle<FileEntry> fileEntries[] = {
|
||||||
|
|
|
@ -96,7 +96,7 @@ void HandshakeExtensionMessageTest::testDoReceivedAction()
|
||||||
RequestGroup rg(op);
|
RequestGroup rg(op);
|
||||||
rg.setDownloadContext(dctx);
|
rg.setDownloadContext(dctx);
|
||||||
|
|
||||||
BDE attrs = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
||||||
dctx->markTotalLengthIsUnknown();
|
dctx->markTotalLengthIsUnknown();
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ void HandshakeExtensionMessageTest::testDoReceivedAction()
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)6889, peer->getPort());
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6889, peer->getPort());
|
||||||
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((size_t)1024, attrs->metadataSize);
|
||||||
CPPUNIT_ASSERT_EQUAL((uint64_t)1024, dctx->getTotalLength());
|
CPPUNIT_ASSERT_EQUAL((uint64_t)1024, dctx->getTotalLength());
|
||||||
CPPUNIT_ASSERT(dctx->knowsTotalLength());
|
CPPUNIT_ASSERT(dctx->knowsTotalLength());
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,8 @@ public:
|
||||||
_dctx.reset(new DownloadContext());
|
_dctx.reset(new DownloadContext());
|
||||||
unsigned char infoHash[20];
|
unsigned char infoHash[20];
|
||||||
memset(infoHash, 0, sizeof(infoHash));
|
memset(infoHash, 0, sizeof(infoHash));
|
||||||
BDE torrentAttrs = BDE::dict();
|
SharedHandle<TorrentAttribute> torrentAttrs(new TorrentAttribute());
|
||||||
torrentAttrs[bittorrent::INFO_HASH] =
|
torrentAttrs->infoHash = std::string(vbegin(infoHash), vend(infoHash));
|
||||||
std::string(vbegin(infoHash), vend(infoHash));
|
|
||||||
_dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs);
|
_dctx->setAttribute(bittorrent::BITTORRENT, torrentAttrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,19 +20,23 @@ public:
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE_REGISTRATION(MagnetTest);
|
CPPUNIT_TEST_SUITE_REGISTRATION(MagnetTest);
|
||||||
|
|
||||||
|
static const std::string& nthStr(const SharedHandle<ValueBase>& v, size_t index)
|
||||||
|
{
|
||||||
|
return asString(asList(v)->get(index))->s();
|
||||||
|
}
|
||||||
|
|
||||||
void MagnetTest::testParse()
|
void MagnetTest::testParse()
|
||||||
{
|
{
|
||||||
BDE r = parse
|
SharedHandle<Dict> r = parse
|
||||||
("magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2"
|
("magnet:?xt=urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c&dn=aria2"
|
||||||
"&tr=http%3A%2F%2Ftracker1&tr=http://tracker2");
|
"&tr=http%3A%2F%2Ftracker1&tr=http://tracker2");
|
||||||
CPPUNIT_ASSERT_EQUAL
|
CPPUNIT_ASSERT_EQUAL
|
||||||
(std::string("urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
(std::string("urn:btih:248d0a1cd08284299de78d5c1ed359bb46717d8c"),
|
||||||
r["xt"][0].s());
|
nthStr(r->get("xt"), 0));
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), r["dn"][0].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), nthStr(r->get("dn"), 0));
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), r["tr"][0].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker1"), nthStr(r->get("tr"), 0));
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), r["tr"][1].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), nthStr(r->get("tr"), 1));
|
||||||
|
CPPUNIT_ASSERT(parse("http://localhost").isNull());
|
||||||
CPPUNIT_ASSERT(parse("http://localhost").isNone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace magnet
|
} // namespace magnet
|
||||||
|
|
|
@ -72,7 +72,9 @@ aria2c_SOURCES = AllTest.cc\
|
||||||
bitfieldTest.cc\
|
bitfieldTest.cc\
|
||||||
BDETest.cc\
|
BDETest.cc\
|
||||||
DownloadContextTest.cc\
|
DownloadContextTest.cc\
|
||||||
SessionSerializerTest.cc
|
SessionSerializerTest.cc\
|
||||||
|
ValueBaseTest.cc\
|
||||||
|
Bencode2Test.cc
|
||||||
|
|
||||||
if ENABLE_XML_RPC
|
if ENABLE_XML_RPC
|
||||||
aria2c_SOURCES += XmlRpcRequestParserControllerTest.cc\
|
aria2c_SOURCES += XmlRpcRequestParserControllerTest.cc\
|
||||||
|
|
|
@ -214,6 +214,7 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \
|
||||||
InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
|
InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
|
||||||
a2algoTest.cc bitfieldTest.cc BDETest.cc \
|
a2algoTest.cc bitfieldTest.cc BDETest.cc \
|
||||||
DownloadContextTest.cc SessionSerializerTest.cc \
|
DownloadContextTest.cc SessionSerializerTest.cc \
|
||||||
|
ValueBaseTest.cc Bencode2Test.cc \
|
||||||
XmlRpcRequestParserControllerTest.cc \
|
XmlRpcRequestParserControllerTest.cc \
|
||||||
XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \
|
XmlRpcRequestProcessorTest.cc XmlRpcMethodTest.cc \
|
||||||
FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \
|
FallocFileAllocationIteratorTest.cc GZipDecoderTest.cc \
|
||||||
|
@ -408,6 +409,7 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) TestUtil.$(OBJEXT) \
|
||||||
LongestSequencePieceSelectorTest.$(OBJEXT) \
|
LongestSequencePieceSelectorTest.$(OBJEXT) \
|
||||||
a2algoTest.$(OBJEXT) bitfieldTest.$(OBJEXT) BDETest.$(OBJEXT) \
|
a2algoTest.$(OBJEXT) bitfieldTest.$(OBJEXT) BDETest.$(OBJEXT) \
|
||||||
DownloadContextTest.$(OBJEXT) SessionSerializerTest.$(OBJEXT) \
|
DownloadContextTest.$(OBJEXT) SessionSerializerTest.$(OBJEXT) \
|
||||||
|
ValueBaseTest.$(OBJEXT) Bencode2Test.$(OBJEXT) \
|
||||||
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
|
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
|
||||||
$(am__objects_4) $(am__objects_5) $(am__objects_6) \
|
$(am__objects_4) $(am__objects_5) $(am__objects_6) \
|
||||||
$(am__objects_7)
|
$(am__objects_7)
|
||||||
|
@ -644,9 +646,9 @@ aria2c_SOURCES = AllTest.cc TestUtil.cc TestUtil.h SocketCoreTest.cc \
|
||||||
InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
|
InOrderPieceSelector.h LongestSequencePieceSelectorTest.cc \
|
||||||
a2algoTest.cc bitfieldTest.cc BDETest.cc \
|
a2algoTest.cc bitfieldTest.cc BDETest.cc \
|
||||||
DownloadContextTest.cc SessionSerializerTest.cc \
|
DownloadContextTest.cc SessionSerializerTest.cc \
|
||||||
$(am__append_1) $(am__append_2) $(am__append_3) \
|
ValueBaseTest.cc Bencode2Test.cc $(am__append_1) \
|
||||||
$(am__append_4) $(am__append_5) $(am__append_6) \
|
$(am__append_2) $(am__append_3) $(am__append_4) \
|
||||||
$(am__append_7)
|
$(am__append_5) $(am__append_6) $(am__append_7)
|
||||||
|
|
||||||
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
|
||||||
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
|
||||||
|
@ -752,6 +754,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BNodeTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BNodeTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base32Test.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base32Test.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64Test.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64Test.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Bencode2Test.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BencodeTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BencodeTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldManTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldManTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BittorrentHelperTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BittorrentHelperTest.Po@am__quote@
|
||||||
|
@ -899,6 +902,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessageTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessageTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParserTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParserTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ValueBaseTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XORCloserTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XORCloserTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcMethodTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcMethodTest.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcRequestParserControllerTest.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlRpcRequestParserControllerTest.Po@am__quote@
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "ServerStat.h"
|
#include "ServerStat.h"
|
||||||
#include "File.h"
|
#include "File.h"
|
||||||
#include "array_fun.h"
|
#include "array_fun.h"
|
||||||
|
#include "RecoverableException.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ void UTMetadataDataExtensionMessageTest::testDoReceivedAction()
|
||||||
SharedHandle<UTMetadataRequestTracker> tracker
|
SharedHandle<UTMetadataRequestTracker> tracker
|
||||||
(new UTMetadataRequestTracker());
|
(new UTMetadataRequestTracker());
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
BDE attrs = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
|
|
||||||
std::string piece0 = std::string(METADATA_PIECE_SIZE, '0');
|
std::string piece0 = std::string(METADATA_PIECE_SIZE, '0');
|
||||||
std::string piece1 = std::string(METADATA_PIECE_SIZE, '1');
|
std::string piece1 = std::string(METADATA_PIECE_SIZE, '1');
|
||||||
|
@ -83,8 +83,7 @@ void UTMetadataDataExtensionMessageTest::testDoReceivedAction()
|
||||||
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
|
MessageDigestHelper::digest(infoHash, INFO_HASH_LENGTH,
|
||||||
MessageDigestContext::SHA1,
|
MessageDigestContext::SHA1,
|
||||||
metadata.data(), metadata.size());
|
metadata.data(), metadata.size());
|
||||||
attrs[bittorrent::INFO_HASH] = std::string(&infoHash[0], &infoHash[20]);
|
attrs->infoHash = std::string(&infoHash[0], &infoHash[20]);
|
||||||
|
|
||||||
dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
||||||
|
|
||||||
UTMetadataDataExtensionMessage m(1);
|
UTMetadataDataExtensionMessage m(1);
|
||||||
|
|
|
@ -51,13 +51,13 @@ void UTMetadataPostDownloadHandlerTest::testCanHandle()
|
||||||
|
|
||||||
CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get()));
|
CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get()));
|
||||||
|
|
||||||
BDE attrs = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
_dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
_dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
||||||
|
|
||||||
CPPUNIT_ASSERT(handler.canHandle(_requestGroup.get()));
|
CPPUNIT_ASSERT(handler.canHandle(_requestGroup.get()));
|
||||||
|
|
||||||
// Only checks existence of METADATA key
|
// Only checks whether metadata is empty or not
|
||||||
attrs[bittorrent::METADATA] = A2STR::NIL;
|
attrs->metadata = "metadata";
|
||||||
|
|
||||||
CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get()));
|
CPPUNIT_ASSERT(!handler.canHandle(_requestGroup.get()));
|
||||||
}
|
}
|
||||||
|
@ -76,12 +76,13 @@ void UTMetadataPostDownloadHandlerTest::testGetNextRequestGroups()
|
||||||
(infoHash, sizeof(infoHash), MessageDigestContext::SHA1,
|
(infoHash, sizeof(infoHash), MessageDigestContext::SHA1,
|
||||||
reinterpret_cast<const unsigned char*>(metadata.data()), metadata.size());
|
reinterpret_cast<const unsigned char*>(metadata.data()), metadata.size());
|
||||||
_dctx->getFirstFileEntry()->setLength(metadata.size());
|
_dctx->getFirstFileEntry()->setLength(metadata.size());
|
||||||
BDE attrs = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
attrs[bittorrent::INFO_HASH] = std::string(&infoHash[0], &infoHash[20]);
|
attrs->infoHash = std::string(&infoHash[0], &infoHash[20]);
|
||||||
BDE announceList = BDE::list();
|
std::vector<std::vector<std::string> > announceList;
|
||||||
announceList << BDE::list();
|
std::vector<std::string> announceTier;
|
||||||
announceList[0] << std::string("http://tracker");
|
announceTier.push_back("http://tracker");
|
||||||
attrs[bittorrent::ANNOUNCE_LIST] = announceList;
|
announceList.push_back(announceTier);
|
||||||
|
attrs->announceList = announceList;
|
||||||
_dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
_dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
||||||
_requestGroup->setDiskWriterFactory
|
_requestGroup->setDiskWriterFactory
|
||||||
(SharedHandle<DiskWriterFactory>(new ByteArrayDiskWriterFactory()));
|
(SharedHandle<DiskWriterFactory>(new ByteArrayDiskWriterFactory()));
|
||||||
|
@ -97,13 +98,14 @@ void UTMetadataPostDownloadHandlerTest::testGetNextRequestGroups()
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, results.size());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, results.size());
|
||||||
SharedHandle<RequestGroup> newRg = results.front();
|
SharedHandle<RequestGroup> newRg = results.front();
|
||||||
SharedHandle<DownloadContext> newDctx = newRg->getDownloadContext();
|
SharedHandle<DownloadContext> newDctx = newRg->getDownloadContext();
|
||||||
const BDE& newAttrs = newDctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> newAttrs =
|
||||||
CPPUNIT_ASSERT_EQUAL(util::toHex(attrs[bittorrent::INFO_HASH].s()),
|
bittorrent::getTorrentAttrs(newDctx);
|
||||||
util::toHex(newAttrs[bittorrent::INFO_HASH].s()));
|
CPPUNIT_ASSERT_EQUAL(bittorrent::getInfoHashString(_dctx),
|
||||||
CPPUNIT_ASSERT(newAttrs.containsKey(bittorrent::ANNOUNCE_LIST));
|
bittorrent::getInfoHashString(newDctx));
|
||||||
CPPUNIT_ASSERT_EQUAL((size_t)1, newAttrs[bittorrent::ANNOUNCE_LIST].size());
|
const std::vector<std::vector<std::string> >& newAnnounceList =
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker"),
|
newAttrs->announceList;
|
||||||
newAttrs[bittorrent::ANNOUNCE_LIST][0][0].s());
|
CPPUNIT_ASSERT_EQUAL((size_t)1, newAnnounceList.size());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker"), newAnnounceList[0][0]);
|
||||||
CPPUNIT_ASSERT_EQUAL(_option->get("Hello"),
|
CPPUNIT_ASSERT_EQUAL(_option->get("Hello"),
|
||||||
newRg->getOption()->get("Hello"));
|
newRg->getOption()->get("Hello"));
|
||||||
CPPUNIT_ASSERT
|
CPPUNIT_ASSERT
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "UTMetadataDataExtensionMessage.h"
|
#include "UTMetadataDataExtensionMessage.h"
|
||||||
#include "PieceStorage.h"
|
#include "PieceStorage.h"
|
||||||
#include "extension_message_test_helper.h"
|
#include "extension_message_test_helper.h"
|
||||||
|
#include "DlAbortEx.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ public:
|
||||||
_messageFactory.reset(new WrapExtBtMessageFactory());
|
_messageFactory.reset(new WrapExtBtMessageFactory());
|
||||||
_dispatcher.reset(new MockBtMessageDispatcher());
|
_dispatcher.reset(new MockBtMessageDispatcher());
|
||||||
_dctx.reset(new DownloadContext());
|
_dctx.reset(new DownloadContext());
|
||||||
BDE attrs = BDE::dict();
|
SharedHandle<TorrentAttribute> attrs(new TorrentAttribute());
|
||||||
_dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
_dctx->setAttribute(bittorrent::BITTORRENT, attrs);
|
||||||
_peer.reset(new Peer("host", 6880));
|
_peer.reset(new Peer("host", 6880));
|
||||||
_peer->allocateSessionResource(0, 0);
|
_peer->allocateSessionResource(0, 0);
|
||||||
|
@ -124,11 +125,11 @@ void UTMetadataRequestExtensionMessageTest::testDoReceivedAction_data()
|
||||||
msg.setBtMessageDispatcher(_dispatcher);
|
msg.setBtMessageDispatcher(_dispatcher);
|
||||||
|
|
||||||
size_t metadataSize = METADATA_PIECE_SIZE*2;
|
size_t metadataSize = METADATA_PIECE_SIZE*2;
|
||||||
BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> attrs = bittorrent::getTorrentAttrs(_dctx);
|
||||||
std::string first(METADATA_PIECE_SIZE, '0');
|
std::string first(METADATA_PIECE_SIZE, '0');
|
||||||
std::string second(METADATA_PIECE_SIZE, '1');
|
std::string second(METADATA_PIECE_SIZE, '1');
|
||||||
attrs[bittorrent::METADATA] = first+second;
|
attrs->metadata = first+second;
|
||||||
attrs[bittorrent::METADATA_SIZE] = metadataSize;
|
attrs->metadataSize = metadataSize;
|
||||||
|
|
||||||
msg.doReceivedAction();
|
msg.doReceivedAction();
|
||||||
|
|
||||||
|
@ -147,8 +148,8 @@ void UTMetadataRequestExtensionMessageTest::testDoReceivedAction_data()
|
||||||
|
|
||||||
metadataSize += 100;
|
metadataSize += 100;
|
||||||
std::string third(100, '2');
|
std::string third(100, '2');
|
||||||
attrs[bittorrent::METADATA] = attrs[bittorrent::METADATA].s()+third;
|
attrs->metadata = first+second+third;
|
||||||
attrs[bittorrent::METADATA_SIZE] = metadataSize;
|
attrs->metadataSize = metadataSize;
|
||||||
|
|
||||||
msg.doReceivedAction();
|
msg.doReceivedAction();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
#include "ValueBase.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
#include "Exception.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
class ValueBaseTest:public CppUnit::TestFixture {
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE(ValueBaseTest);
|
||||||
|
CPPUNIT_TEST(testString);
|
||||||
|
CPPUNIT_TEST(testDict);
|
||||||
|
CPPUNIT_TEST(testDictIter);
|
||||||
|
CPPUNIT_TEST(testList);
|
||||||
|
CPPUNIT_TEST(testListIter);
|
||||||
|
CPPUNIT_TEST(testDowncast);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
public:
|
||||||
|
void setUp() {}
|
||||||
|
|
||||||
|
void tearDown() {}
|
||||||
|
|
||||||
|
void testString();
|
||||||
|
void testDict();
|
||||||
|
void testDictIter();
|
||||||
|
void testList();
|
||||||
|
void testListIter();
|
||||||
|
void testDowncast();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(ValueBaseTest);
|
||||||
|
|
||||||
|
void ValueBaseTest::testString()
|
||||||
|
{
|
||||||
|
String s(std::string("aria2"));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("aria2"), s.s());
|
||||||
|
|
||||||
|
unsigned char dataWithNull[] = { 0xf0, '\0', 0x0f };
|
||||||
|
String sWithNull(dataWithNull, sizeof(dataWithNull));
|
||||||
|
CPPUNIT_ASSERT(memcmp(dataWithNull, sWithNull.s().c_str(),
|
||||||
|
sizeof(dataWithNull)) == 0);
|
||||||
|
|
||||||
|
String zero("");
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string(""), zero.s());
|
||||||
|
|
||||||
|
String z;
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string(""), z.s());
|
||||||
|
|
||||||
|
const unsigned char uc[] = { 0x08, 0x19, 0x2a, 0x3b };
|
||||||
|
String data(uc, sizeof(uc));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(util::toHex(uc, sizeof(uc)),
|
||||||
|
util::toHex(data.uc(), data.s().size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueBaseTest::testDowncast()
|
||||||
|
{
|
||||||
|
Integer integer(100);
|
||||||
|
const Integer* x = asInteger(&integer);
|
||||||
|
CPPUNIT_ASSERT(x);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<Integer::ValueType>(100), x->i());
|
||||||
|
SharedHandle<Integer> si(new Integer(101));
|
||||||
|
const Integer* x2 = asInteger(si);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<Integer::ValueType>(101), x2->i());
|
||||||
|
|
||||||
|
String str("foo");
|
||||||
|
const String* x3 = asString(&str);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("foo"), x3->s());
|
||||||
|
|
||||||
|
List list;
|
||||||
|
const List* x4 = asList(&list);
|
||||||
|
CPPUNIT_ASSERT(x4);
|
||||||
|
|
||||||
|
Dict dict;
|
||||||
|
const Dict* x5 = asDict(&dict);
|
||||||
|
CPPUNIT_ASSERT(x5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueBaseTest::testDict()
|
||||||
|
{
|
||||||
|
Dict dict;
|
||||||
|
CPPUNIT_ASSERT(dict.empty());
|
||||||
|
|
||||||
|
dict["ki"] = Integer::g(7);
|
||||||
|
dict["ks"] = String::g("abc");
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), dict.size());
|
||||||
|
CPPUNIT_ASSERT(dict.containsKey("ki"));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<Integer::ValueType>(7),
|
||||||
|
asInteger(dict["ki"])->i());
|
||||||
|
CPPUNIT_ASSERT(dict.containsKey("ks"));
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("abc"),
|
||||||
|
asString(dict["ks"])->s());
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT(dict["kn"].isNull()); // This adds kn key with default value.
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), dict.size());
|
||||||
|
CPPUNIT_ASSERT(dict.containsKey("kn"));
|
||||||
|
|
||||||
|
const Dict& ref = dict;
|
||||||
|
ref["kn2"]; // This doesn't add kn2 key.
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), ref.size());
|
||||||
|
CPPUNIT_ASSERT(!ref.containsKey("kn2"));
|
||||||
|
|
||||||
|
dict.removeKey("kn");
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), dict.size());
|
||||||
|
CPPUNIT_ASSERT(!dict.containsKey("kn"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueBaseTest::testDictIter()
|
||||||
|
{
|
||||||
|
Dict dict;
|
||||||
|
dict["alpha2"] = String::g("alpha2");
|
||||||
|
dict["charlie"] = String::g("charlie");
|
||||||
|
dict["bravo"] = String::g("bravo");
|
||||||
|
dict["alpha"] = String::g("alpha");
|
||||||
|
|
||||||
|
Dict::ValueType::iterator i = dict.begin();
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("alpha"), (*i++).first);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("alpha2"), (*i++).first);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("bravo"), (*i++).first);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("charlie"), (*i++).first);
|
||||||
|
CPPUNIT_ASSERT(dict.end() == i);
|
||||||
|
|
||||||
|
const Dict& ref = dict;
|
||||||
|
Dict::ValueType::const_iterator ci = ref.begin();
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("alpha"), (*ci++).first);
|
||||||
|
std::advance(ci, 3);
|
||||||
|
CPPUNIT_ASSERT(ref.end() == ci);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueBaseTest::testList()
|
||||||
|
{
|
||||||
|
List list;
|
||||||
|
CPPUNIT_ASSERT(list.empty());
|
||||||
|
list << Integer::g(7) << String::g("aria2");
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), list.size());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<Integer::ValueType>(7),
|
||||||
|
asInteger(list[0])->i());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("aria2"),
|
||||||
|
asString(list[1])->s());
|
||||||
|
|
||||||
|
const List& ref = list;
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<Integer::ValueType>(7),
|
||||||
|
asInteger(ref[0])->i());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("aria2"),
|
||||||
|
asString(ref[1])->s());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueBaseTest::testListIter()
|
||||||
|
{
|
||||||
|
List list;
|
||||||
|
list << String::g("alpha2")
|
||||||
|
<< String::g("charlie")
|
||||||
|
<< String::g("bravo")
|
||||||
|
<< String::g("alpha");
|
||||||
|
|
||||||
|
List::ValueType::iterator i = list.begin();
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("alpha2"),
|
||||||
|
asString(*i++)->s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("charlie"),
|
||||||
|
asString(*i++)->s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("bravo"),
|
||||||
|
asString(*i++)->s());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("alpha"),
|
||||||
|
asString(*i++)->s());
|
||||||
|
CPPUNIT_ASSERT(list.end() == i);
|
||||||
|
|
||||||
|
const List& ref = list;
|
||||||
|
List::ValueType::const_iterator ci = ref.begin();
|
||||||
|
CPPUNIT_ASSERT_EQUAL(static_cast<String::ValueType>("alpha2"),
|
||||||
|
asString(*ci++)->s());
|
||||||
|
std::advance(ci, 3);
|
||||||
|
CPPUNIT_ASSERT(ref.end() == ci);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -745,7 +745,7 @@ void XmlRpcMethodTest::testGatherBitTorrentMetadata()
|
||||||
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
SharedHandle<DownloadContext> dctx(new DownloadContext());
|
||||||
bittorrent::load("test.torrent", dctx);
|
bittorrent::load("test.torrent", dctx);
|
||||||
BDE btDict = BDE::dict();
|
BDE btDict = BDE::dict();
|
||||||
gatherBitTorrentMetadata(btDict, dctx->getAttribute(bittorrent::BITTORRENT));
|
gatherBitTorrentMetadata(btDict, bittorrent::getTorrentAttrs(dctx));
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("REDNOAH.COM RULES"), btDict["comment"].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("REDNOAH.COM RULES"), btDict["comment"].s());
|
||||||
CPPUNIT_ASSERT_EQUAL((int64_t)1123456789, btDict["creationDate"].i());
|
CPPUNIT_ASSERT_EQUAL((int64_t)1123456789, btDict["creationDate"].i());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("multi"), btDict["mode"].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("multi"), btDict["mode"].s());
|
||||||
|
@ -756,11 +756,11 @@ void XmlRpcMethodTest::testGatherBitTorrentMetadata()
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), announceList[1][0].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker2"), announceList[1][0].s());
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker3"), announceList[2][0].s());
|
CPPUNIT_ASSERT_EQUAL(std::string("http://tracker3"), announceList[2][0].s());
|
||||||
// Remove some keys
|
// Remove some keys
|
||||||
BDE modBtAttrs = dctx->getAttribute(bittorrent::BITTORRENT);
|
SharedHandle<TorrentAttribute> modBtAttrs = bittorrent::getTorrentAttrs(dctx);
|
||||||
modBtAttrs.removeKey(bittorrent::COMMENT);
|
modBtAttrs->comment.clear();
|
||||||
modBtAttrs.removeKey(bittorrent::CREATION_DATE);
|
modBtAttrs->creationDate = 0;
|
||||||
modBtAttrs.removeKey(bittorrent::MODE);
|
modBtAttrs->mode.clear();
|
||||||
modBtAttrs.removeKey(bittorrent::METADATA);
|
modBtAttrs->metadata.clear();
|
||||||
btDict = BDE::dict();
|
btDict = BDE::dict();
|
||||||
gatherBitTorrentMetadata(btDict, modBtAttrs);
|
gatherBitTorrentMetadata(btDict, modBtAttrs);
|
||||||
CPPUNIT_ASSERT(!btDict.containsKey("comment"));
|
CPPUNIT_ASSERT(!btDict.containsKey("comment"));
|
||||||
|
|
Loading…
Reference in New Issue