2010-08-07 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

Added IPv6 DHT. Added --dht-entry-porint6, --dht-file-path6,
	--dht-listen-addr6 and --enable-dht6 option.  IPv6 DHT is disabled
	by default. To use IPv6 DHT, you need to use --enable-dht6 and
	specify a global unicast address to --dht-listen-addr6.  IPv6 DHT
	is highly experimental.
	* src/BtSetup.cc
	* src/DHTAutoSaveCommand.cc
	* src/DHTAutoSaveCommand.h
	* src/DHTConnectionImpl.cc
	* src/DHTConnectionImpl.h
	* src/DHTEntryPointNameResolveCommand.cc
	* src/DHTFindNodeReplyMessage.cc
	* src/DHTFindNodeReplyMessage.h
	* src/DHTGetPeersMessage.cc
	* src/DHTGetPeersReplyMessage.cc
	* src/DHTGetPeersReplyMessage.h
	* src/DHTMessageFactory.h
	* src/DHTMessageFactoryImpl.cc
	* src/DHTMessageFactoryImpl.h
	* src/DHTMessageTracker.cc
	* src/DHTRegistry.cc
	* src/DHTRegistry.h
	* src/DHTRoutingTableDeserializer.cc
	* src/DHTRoutingTableDeserializer.h
	* src/DHTRoutingTableSerializer.cc
	* src/DHTRoutingTableSerializer.h
	* src/DHTSetup.cc
	* src/DHTSetup.h
	* src/FtpConnection.cc
	* src/LpdMessageReceiver.cc
	* src/OptionHandlerFactory.cc
	* src/OptionHandlerImpl.h
	* src/PeerInteractionCommand.cc
	* src/RequestGroup.cc
	* src/SocketCore.cc
	* src/SocketCore.h
	* src/bittorrent_helper.cc
	* src/bittorrent_helper.h
	* src/prefs.cc
	* src/prefs.h
	* src/usage_text.h
	* test/DHTConnectionImplTest.cc
	* test/DHTFindNodeReplyMessageTest.cc
	* test/DHTGetPeersMessageTest.cc
	* test/DHTGetPeersReplyMessageTest.cc
	* test/DHTMessageFactoryImplTest.cc
	* test/DHTRoutingTableDeserializerTest.cc
	* test/DHTRoutingTableSerializerTest.cc
	* test/LpdMessageDispatcherTest.cc
	* test/MockDHTMessageFactory.h
pull/1/head
Tatsuhiro Tsujikawa 2010-08-07 14:15:21 +00:00
parent be7012272d
commit 26d6692376
46 changed files with 1098 additions and 415 deletions

View File

@ -1,4 +1,57 @@
2010-08-05 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
2010-08-07 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added IPv6 DHT. Added --dht-entry-porint6, --dht-file-path6,
--dht-listen-addr6 and --enable-dht6 option. IPv6 DHT is disabled
by default. To use IPv6 DHT, you need to use --enable-dht6 and
specify a global unicast address to --dht-listen-addr6. IPv6 DHT
is highly experimental.
* src/BtSetup.cc
* src/DHTAutoSaveCommand.cc
* src/DHTAutoSaveCommand.h
* src/DHTConnectionImpl.cc
* src/DHTConnectionImpl.h
* src/DHTEntryPointNameResolveCommand.cc
* src/DHTFindNodeReplyMessage.cc
* src/DHTFindNodeReplyMessage.h
* src/DHTGetPeersMessage.cc
* src/DHTGetPeersReplyMessage.cc
* src/DHTGetPeersReplyMessage.h
* src/DHTMessageFactory.h
* src/DHTMessageFactoryImpl.cc
* src/DHTMessageFactoryImpl.h
* src/DHTMessageTracker.cc
* src/DHTRegistry.cc
* src/DHTRegistry.h
* src/DHTRoutingTableDeserializer.cc
* src/DHTRoutingTableDeserializer.h
* src/DHTRoutingTableSerializer.cc
* src/DHTRoutingTableSerializer.h
* src/DHTSetup.cc
* src/DHTSetup.h
* src/FtpConnection.cc
* src/LpdMessageReceiver.cc
* src/OptionHandlerFactory.cc
* src/OptionHandlerImpl.h
* src/PeerInteractionCommand.cc
* src/RequestGroup.cc
* src/SocketCore.cc
* src/SocketCore.h
* src/bittorrent_helper.cc
* src/bittorrent_helper.h
* src/prefs.cc
* src/prefs.h
* src/usage_text.h
* test/DHTConnectionImplTest.cc
* test/DHTFindNodeReplyMessageTest.cc
* test/DHTGetPeersMessageTest.cc
* test/DHTGetPeersReplyMessageTest.cc
* test/DHTMessageFactoryImplTest.cc
* test/DHTRoutingTableDeserializerTest.cc
* test/DHTRoutingTableSerializerTest.cc
* test/LpdMessageDispatcherTest.cc
* test/MockDHTMessageFactory.h
2010-08-07 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Removed AI_V4MAPPED from DEFAULT_AI_FLAGS
* src/a2netcompat.h

View File

@ -58,6 +58,15 @@
#include "DHTPeerAnnounceStorage.h"
#include "DHTSetup.h"
#include "DHTRegistry.h"
#include "DHTNode.h"
#include "DHTRoutingTable.h"
#include "DHTTaskQueue.h"
#include "DHTTaskFactory.h"
#include "DHTTokenTracker.h"
#include "DHTMessageDispatcher.h"
#include "DHTMessageReceiver.h"
#include "DHTMessageFactory.h"
#include "DHTMessageCallback.h"
#include "BtProgressInfoFile.h"
#include "BtAnnounce.h"
#include "BtRuntime.h"
@ -126,15 +135,25 @@ void BtSetup::setup(std::vector<Command*>& commands,
commands.push_back(c);
}
if((metadataGetMode || !torrentAttrs->privateTorrent) &&
DHTSetup::initialized()) {
DHTGetPeersCommand* command =
new DHTGetPeersCommand(e->newCUID(), requestGroup, e);
command->setTaskQueue(DHTRegistry::getData().taskQueue);
command->setTaskFactory(DHTRegistry::getData().taskFactory);
command->setBtRuntime(btRuntime);
command->setPeerStorage(peerStorage);
commands.push_back(command);
if(metadataGetMode || !torrentAttrs->privateTorrent) {
if(DHTRegistry::isInitialized()) {
DHTGetPeersCommand* command =
new DHTGetPeersCommand(e->newCUID(), requestGroup, e);
command->setTaskQueue(DHTRegistry::getData().taskQueue);
command->setTaskFactory(DHTRegistry::getData().taskFactory);
command->setBtRuntime(btRuntime);
command->setPeerStorage(peerStorage);
commands.push_back(command);
}
if(DHTRegistry::isInitialized6()) {
DHTGetPeersCommand* command =
new DHTGetPeersCommand(e->newCUID(), requestGroup, e);
command->setTaskQueue(DHTRegistry::getData6().taskQueue);
command->setTaskFactory(DHTRegistry::getData6().taskFactory);
command->setBtRuntime(btRuntime);
command->setPeerStorage(peerStorage);
commands.push_back(command);
}
}
if(!metadataGetMode) {
SharedHandle<UnionSeedCriteria> unionCri(new UnionSeedCriteria());

View File

@ -62,8 +62,9 @@
namespace aria2 {
DHTAutoSaveCommand::DHTAutoSaveCommand
(cuid_t cuid, DownloadEngine* e, time_t interval):
TimeBasedCommand(cuid, e, interval) {}
(cuid_t cuid, DownloadEngine* e, int family, time_t interval):
TimeBasedCommand(cuid, e, interval),
family_(family) {}
DHTAutoSaveCommand::~DHTAutoSaveCommand() {}
@ -84,7 +85,8 @@ void DHTAutoSaveCommand::process()
void DHTAutoSaveCommand::save()
{
std::string dhtFile =
getDownloadEngine()->getOption()->get(PREF_DHT_FILE_PATH);
getDownloadEngine()->getOption()->
get(family_ == AF_INET? PREF_DHT_FILE_PATH : PREF_DHT_FILE_PATH6);
getLogger()->info("Saving DHT routing table to %s.", dhtFile.c_str());
std::string tempFile = dhtFile;
@ -116,7 +118,7 @@ void DHTAutoSaveCommand::save()
nodes.insert(nodes.end(), goodNodes.begin(), goodNodes.end());
}
DHTRoutingTableSerializer serializer;
DHTRoutingTableSerializer serializer(family_);
serializer.setLocalNode(localNode_);
serializer.setNodes(nodes);

View File

@ -46,13 +46,16 @@ class DHTNode;
class DHTAutoSaveCommand : public TimeBasedCommand
{
private:
int family_;
SharedHandle<DHTNode> localNode_;
SharedHandle<DHTRoutingTable> routingTable_;
void save();
public:
DHTAutoSaveCommand(cuid_t cuid, DownloadEngine* e, time_t interval);
DHTAutoSaveCommand
(cuid_t cuid, DownloadEngine* e, int family, time_t interval);
virtual ~DHTAutoSaveCommand();

View File

@ -46,12 +46,15 @@
namespace aria2 {
DHTConnectionImpl::DHTConnectionImpl():socket_(new SocketCore(SOCK_DGRAM)),
logger_(LogFactory::getInstance()) {}
DHTConnectionImpl::DHTConnectionImpl(int family):
socket_(new SocketCore(SOCK_DGRAM)),
family_(family),
logger_(LogFactory::getInstance()) {}
DHTConnectionImpl::~DHTConnectionImpl() {}
bool DHTConnectionImpl::bind(uint16_t& port, IntSequence& ports)
bool DHTConnectionImpl::bind
(uint16_t& port, const std::string& addr, IntSequence& ports)
{
std::vector<int32_t> randPorts = ports.flush();
std::random_shuffle(randPorts.begin(), randPorts.end(),
@ -63,25 +66,30 @@ bool DHTConnectionImpl::bind(uint16_t& port, IntSequence& ports)
continue;
}
port = (*portItr);
if(bind(port)) {
if(bind(port, addr)) {
return true;
}
}
return false;
}
bool DHTConnectionImpl::bind(uint16_t& port)
bool DHTConnectionImpl::bind(uint16_t& port, const std::string& addr)
{
int ipv = family_ == AF_INET?4:6;
try {
socket_->bind(port);
if(addr.empty()) {
socket_->bind(A2STR::NIL, port, family_);
} else {
socket_->bind(addr, port, family_);
}
socket_->setNonBlockingMode();
std::pair<std::string, uint16_t> svaddr;
socket_->getAddrInfo(svaddr);
port = svaddr.second;
logger_->notice("DHT: listening to port %d", port);
logger_->notice("IPv%d DHT: listening to port %d", ipv, port);
return true;
} catch(RecoverableException& e) {
logger_->error("Failed to bind for DHT. port=%u", e, port);
logger_->error("Failed to bind for IPv%d DHT. port=%u", e, ipv, port);
}
return false;
}

View File

@ -48,28 +48,33 @@ class DHTConnectionImpl:public DHTConnection {
private:
SharedHandle<SocketCore> socket_;
int family_;
Logger* logger_;
public:
DHTConnectionImpl();
DHTConnectionImpl(int family);
virtual ~DHTConnectionImpl();
/**
* Binds port. All number in ports are tried.
* If successful, the binded port is assigned to port and returns true.
* Otherwise return false and port is undefined in this case.
* Binds port. All number in ports are tried. If successful, the
* binded port is assigned to port and returns true. Otherwise
* return false and port is undefined in this case. If non-empty
* string addr is given, the socket is associated to the address.
*/
bool bind(uint16_t& port, IntSequence& ports);
bool bind(uint16_t& port, const std::string& addr, IntSequence& ports);
/**
* Binds port. The port number specified by port is used to bind.
* If successful, the binded port is assigned to port and returns true.
* Otherwise return false and port is undefined in this case.
* If successful, the binded port is assigned to port and returns
* true. Otherwise return false and port is undefined in this case.
* If non-empty string addr is given, the socket is associated to
* the address.
*
* If you want to bind arbitrary port, give 0 as port and if successful,
* the binded port is assigned to port.
*/
bool bind(uint16_t& port);
bool bind(uint16_t& port, const std::string& addr);
virtual ssize_t receiveMessage(unsigned char* data, size_t len,
std::string& host, uint16_t& port);

View File

@ -96,7 +96,12 @@ bool DHTEntryPointNameResolveCommand::execute()
while(!entryPoints_.empty()) {
std::string hostname = entryPoints_.front().first;
try {
if(resolveHostname(hostname, resolver_)) {
if(util::isNumericHost(hostname)) {
std::pair<std::string, uint16_t> p
(hostname, entryPoints_.front().second);
resolvedEntryPoints_.push_back(p);
addPingTask(p);
} else if(resolveHostname(hostname, resolver_)) {
hostname = resolver_->getResolvedAddresses().front();
std::pair<std::string, uint16_t> p(hostname,
entryPoints_.front().second);

View File

@ -51,11 +51,15 @@ const std::string DHTFindNodeReplyMessage::FIND_NODE("find_node");
const std::string DHTFindNodeReplyMessage::NODES("nodes");
const std::string DHTFindNodeReplyMessage::NODES6("nodes6");
DHTFindNodeReplyMessage::DHTFindNodeReplyMessage
(const SharedHandle<DHTNode>& localNode,
(int family,
const SharedHandle<DHTNode>& localNode,
const SharedHandle<DHTNode>& remoteNode,
const std::string& transactionID):
DHTResponseMessage(localNode, remoteNode, transactionID) {}
DHTResponseMessage(localNode, remoteNode, transactionID),
family_(family) {}
DHTFindNodeReplyMessage::~DHTFindNodeReplyMessage() {}
@ -73,23 +77,27 @@ SharedHandle<Dict> DHTFindNodeReplyMessage::getResponse()
{
SharedHandle<Dict> aDict = Dict::g();
aDict->put(DHTMessage::ID, String::g(getLocalNode()->getID(), DHT_ID_LENGTH));
unsigned char buffer[DHTBucket::K*38];
const int clen = bittorrent::getCompactLength(family_);
const int unit = clen+20;
assert(unit <= 38);
size_t offset = 0;
unsigned char buffer[DHTBucket::K*26];
// TODO if closestKNodes_.size() > DHTBucket::K ??
size_t k = 0;
for(std::vector<SharedHandle<DHTNode> >::const_iterator i =
closestKNodes_.begin(), eoi = closestKNodes_.end();
i != eoi && offset < DHTBucket::K*26; ++i) {
i != eoi && k < DHTBucket::K; ++i) {
SharedHandle<DHTNode> node = *i;
memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH);
unsigned char compact[COMPACT_LEN_IPV6];
int compactlen = bittorrent::packcompact
(compact, node->getIPAddress(), node->getPort());
if(compactlen == COMPACT_LEN_IPV4) {
if(compactlen == clen) {
memcpy(buffer+20+offset, compact, compactlen);
offset += 26;
offset += unit;
++k;
}
}
aDict->put(NODES, String::g(buffer, offset));
aDict->put(family_ == AF_INET?NODES:NODES6, String::g(buffer, offset));
return aDict;
}

View File

@ -42,11 +42,14 @@ namespace aria2 {
class DHTFindNodeReplyMessage:public DHTResponseMessage {
private:
int family_;
std::vector<SharedHandle<DHTNode> > closestKNodes_;
protected:
virtual std::string toStringOptional() const;
public:
DHTFindNodeReplyMessage(const SharedHandle<DHTNode>& localNode,
DHTFindNodeReplyMessage(int family,
const SharedHandle<DHTNode>& localNode,
const SharedHandle<DHTNode>& remoteNode,
const std::string& transactionID);
@ -71,6 +74,8 @@ public:
static const std::string FIND_NODE;
static const std::string NODES;
static const std::string NODES6;
};
} // namespace aria2

View File

@ -70,18 +70,11 @@ void DHTGetPeersMessage::doReceivedAction()
// Check to see localhost has the contents which has same infohash
std::vector<SharedHandle<Peer> > peers;
peerAnnounceStorage_->getPeers(peers, infoHash_);
SharedHandle<DHTMessage> reply;
if(peers.empty()) {
std::vector<SharedHandle<DHTNode> > nodes;
getRoutingTable()->getClosestKNodes(nodes, infoHash_);
reply =
getMessageFactory()->createGetPeersReplyMessage
(getRemoteNode(), nodes, token, getTransactionID());
} else {
reply =
getMessageFactory()->createGetPeersReplyMessage
(getRemoteNode(), peers, token, getTransactionID());
}
std::vector<SharedHandle<DHTNode> > nodes;
getRoutingTable()->getClosestKNodes(nodes, infoHash_);
SharedHandle<DHTMessage> reply =
getMessageFactory()->createGetPeersReplyMessage
(getRemoteNode(), nodes, peers, token, getTransactionID());
getMessageDispatcher()->addMessageToQueue(reply);
}

View File

@ -57,12 +57,16 @@ const std::string DHTGetPeersReplyMessage::VALUES("values");
const std::string DHTGetPeersReplyMessage::NODES("nodes");
const std::string DHTGetPeersReplyMessage::NODES6("nodes6");
DHTGetPeersReplyMessage::DHTGetPeersReplyMessage
(const SharedHandle<DHTNode>& localNode,
(int family,
const SharedHandle<DHTNode>& localNode,
const SharedHandle<DHTNode>& remoteNode,
const std::string& token,
const std::string& transactionID):
DHTResponseMessage(localNode, remoteNode, transactionID),
family_(family),
token_(token) {}
DHTGetPeersReplyMessage::~DHTGetPeersReplyMessage() {}
@ -77,59 +81,69 @@ SharedHandle<Dict> DHTGetPeersReplyMessage::getResponse()
SharedHandle<Dict> rDict = Dict::g();
rDict->put(DHTMessage::ID, String::g(getLocalNode()->getID(), DHT_ID_LENGTH));
rDict->put(TOKEN, token_);
if(values_.empty()) {
// TODO want parameter
if(!closestKNodes_.empty()) {
unsigned char buffer[DHTBucket::K*38];
const int clen = bittorrent::getCompactLength(family_);
const int unit = clen+20;
size_t offset = 0;
unsigned char buffer[DHTBucket::K*26];
size_t k = 0;
for(std::vector<SharedHandle<DHTNode> >::const_iterator i =
closestKNodes_.begin(), eoi = closestKNodes_.end();
i != eoi && offset < DHTBucket::K*26; ++i) {
i != eoi && k < DHTBucket::K; ++i) {
SharedHandle<DHTNode> node = *i;
memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH);
unsigned char compact[COMPACT_LEN_IPV6];
int compactlen = bittorrent::packcompact
(compact, node->getIPAddress(), node->getPort());
if(compactlen == COMPACT_LEN_IPV4) {
if(compactlen == clen) {
memcpy(buffer+20+offset, compact, compactlen);
offset += 26;
offset += unit;
++k;
}
}
rDict->put(NODES, String::g(buffer, offset));
} else {
rDict->put(family_ == AF_INET?NODES:NODES6, String::g(buffer, offset));
}
if(!values_.empty()) {
// Limit the size of values list. The maxmum size of UDP datagram
// is limited to 65535 bytes. aria2 uses 20bytes token and 2byte
// transaction ID. The size of get_peers reply message without
// values list is 87bytes:
// values list and nodes is 87bytes:
//
// d1:rd2:id20:aaaaaaaaaaaaaaaaaaaa5:token20:aaaaaaaaaaaaaaaaaaaa
// 6:valueslee1:t2:bb1:y1:re
//
// nodes are 38 bytes per host for IPv6 and the number of hosts is
// K(=8) max. So without values list, we already 87+38*8+4 = 395.
//
// Because of Path MTU Discovery, UDP packet size which need not
// to be fragmented is much smaller. Since Linux uses Path MTU
// Dicoverry by default and returning ICMP message might be
// filtered, we should avoid fragmentation. MTU of pppoe is 1492
// max according to RFC2516. We use maximum packet size to be
// 1000. Since it contains 20 bytes IP header and 8 bytes UDP
// header and 87 bytes reply message template described above, We
// can carry (1000-28-87)/8 = 110 peer info. Since DHT spec
// 1024. Since it contains 20 bytes IP header and 8 bytes UDP
// header and 395 bytes reply message template described above, We
// can carry (1024-28-395)/(18+3) = 28 peer info. Since DHT spec
// doesn't specify the maximum size of token, reply message
// template may get bigger than 87 bytes. So we use 100 as maximum
// template may get bigger than 395 bytes. So we use 25 as maximum
// number of peer info that a message can carry.
static const size_t MAX_VALUES_SIZE = 100;
static const size_t MAX_VALUES_SIZE = 25;
SharedHandle<List> valuesList = List::g();
for(std::vector<SharedHandle<Peer> >::const_iterator i = values_.begin(),
eoi = values_.end(); i != eoi && valuesList->size() < MAX_VALUES_SIZE;
++i) {
const SharedHandle<Peer>& peer = *i;
unsigned char compact[COMPACT_LEN_IPV6];
const int clen = bittorrent::getCompactLength(family_);
int compactlen = bittorrent::packcompact
(compact, peer->getIPAddress(), peer->getPort());
if(compactlen == COMPACT_LEN_IPV4) {
if(compactlen == clen) {
valuesList->append(String::g(compact, compactlen));
}
}
rDict->put(VALUES, valuesList);
}
return rDict;
return rDict;
}
const std::string& DHTGetPeersReplyMessage::getMessageType() const

View File

@ -47,6 +47,8 @@ class Peer;
class DHTGetPeersReplyMessage:public DHTResponseMessage {
private:
int family_;
std::string token_;
std::vector<SharedHandle<DHTNode> > closestKNodes_;
@ -55,7 +57,8 @@ private:
protected:
virtual std::string toStringOptional() const;
public:
DHTGetPeersReplyMessage(const SharedHandle<DHTNode>& localNode,
DHTGetPeersReplyMessage(int family,
const SharedHandle<DHTNode>& localNode,
const SharedHandle<DHTNode>& remoteNode,
const std::string& token,
const std::string& transactionID);
@ -103,6 +106,8 @@ public:
static const std::string VALUES;
static const std::string NODES;
static const std::string NODES6;
};
} // namespace aria2

View File

@ -94,12 +94,6 @@ public:
createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<DHTNode> >& closestKNodes,
const std::string& token,
const std::string& transactionID) = 0;
virtual SharedHandle<DHTResponseMessage>
createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<Peer> >& peers,
const std::string& token,
const std::string& transactionID) = 0;

View File

@ -64,7 +64,8 @@
namespace aria2 {
DHTMessageFactoryImpl::DHTMessageFactoryImpl():
DHTMessageFactoryImpl::DHTMessageFactoryImpl(int family):
family_(family),
logger_(LogFactory::getInstance()) {}
DHTMessageFactoryImpl::~DHTMessageFactoryImpl() {}
@ -261,21 +262,7 @@ DHTMessageFactoryImpl::createResponseMessage
} else if(messageType == DHTFindNodeReplyMessage::FIND_NODE) {
msg = createFindNodeReplyMessage(remoteNode, dict, transactionID->s());
} else if(messageType == DHTGetPeersReplyMessage::GET_PEERS) {
const List* valuesList =
asList(rDict->get(DHTGetPeersReplyMessage::VALUES));
if(valuesList) {
msg = createGetPeersReplyMessageWithValues
(remoteNode, dict, transactionID->s());
} else {
const String* nodes = asString
(rDict->get(DHTGetPeersReplyMessage::NODES));
if(nodes) {
msg = createGetPeersReplyMessageWithNodes
(remoteNode, dict, transactionID->s());
} else {
throw DL_ABORT_EX("Malformed DHT message: missing nodes/values");
}
}
msg = createGetPeersReplyMessage(remoteNode, dict, transactionID->s());
} else if(messageType == DHTAnnouncePeerReplyMessage::ANNOUNCE_PEER) {
msg = createAnnouncePeerReplyMessage(remoteNode, transactionID->s());
} else {
@ -349,23 +336,26 @@ DHTMessageFactoryImpl::createFindNodeReplyMessage
const std::string& transactionID)
{
SharedHandle<DHTFindNodeReplyMessage> m
(new DHTFindNodeReplyMessage(localNode_, remoteNode, transactionID));
(new DHTFindNodeReplyMessage
(family_, localNode_, remoteNode, transactionID));
m->setClosestKNodes(closestKNodes);
setCommonProperty(m);
return m;
}
std::vector<SharedHandle<DHTNode> >
DHTMessageFactoryImpl::extractNodes(const unsigned char* src, size_t length)
void DHTMessageFactoryImpl::extractNodes
(std::vector<SharedHandle<DHTNode> >& nodes,
const unsigned char* src, size_t length)
{
if(length%26 != 0) {
throw DL_ABORT_EX("Nodes length is not multiple of 26");
int unit = bittorrent::getCompactLength(family_)+20;
if(length%unit != 0) {
throw DL_ABORT_EX
(StringFormat("Nodes length is not multiple of %d", unit).str());
}
std::vector<SharedHandle<DHTNode> > nodes;
for(size_t offset = 0; offset < length; offset += 26) {
for(size_t offset = 0; offset < length; offset += unit) {
SharedHandle<DHTNode> node(new DHTNode(src+offset));
std::pair<std::string, uint16_t> addr =
bittorrent::unpackcompact(src+offset+DHT_ID_LENGTH, AF_INET);
bittorrent::unpackcompact(src+offset+DHT_ID_LENGTH, family_);
if(addr.first.empty()) {
continue;
}
@ -373,7 +363,6 @@ DHTMessageFactoryImpl::extractNodes(const unsigned char* src, size_t length)
node->setPort(addr.second);
nodes.push_back(node);
}
return nodes;
}
SharedHandle<DHTResponseMessage>
@ -383,10 +372,13 @@ DHTMessageFactoryImpl::createFindNodeReplyMessage
const std::string& transactionID)
{
const String* nodesData =
getString(getDictionary(dict, DHTResponseMessage::R),
DHTFindNodeReplyMessage::NODES);
std::vector<SharedHandle<DHTNode> > nodes =
extractNodes(nodesData->uc(), nodesData->s().size());
asString(getDictionary(dict, DHTResponseMessage::R)->
get(family_ == AF_INET?DHTFindNodeReplyMessage::NODES:
DHTFindNodeReplyMessage::NODES6));
std::vector<SharedHandle<DHTNode> > nodes;
if(nodesData) {
extractNodes(nodes, nodesData->uc(), nodesData->s().size());
}
return createFindNodeReplyMessage(remoteNode, nodes, transactionID);
}
@ -405,68 +397,55 @@ DHTMessageFactoryImpl::createGetPeersMessage
}
SharedHandle<DHTResponseMessage>
DHTMessageFactoryImpl::createGetPeersReplyMessageWithNodes
DHTMessageFactoryImpl::createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const Dict* dict,
const std::string& transactionID)
{
const Dict* rDict = getDictionary(dict, DHTResponseMessage::R);
const String* nodesData = getString(rDict, DHTGetPeersReplyMessage::NODES);
std::vector<SharedHandle<DHTNode> > nodes = extractNodes
(nodesData->uc(), nodesData->s().size());
const String* nodesData =
asString(rDict->get(family_ == AF_INET?DHTGetPeersReplyMessage::NODES:
DHTGetPeersReplyMessage::NODES6));
std::vector<SharedHandle<DHTNode> > nodes;
if(nodesData) {
extractNodes(nodes, nodesData->uc(), nodesData->s().size());
}
const List* valuesList =
asList(rDict->get(DHTGetPeersReplyMessage::VALUES));
std::vector<SharedHandle<Peer> > peers;
size_t clen = bittorrent::getCompactLength(family_);
if(valuesList) {
for(List::ValueType::const_iterator i = valuesList->begin(),
eoi = valuesList->end(); i != eoi; ++i) {
const String* data = asString(*i);
if(data && data->s().size() == clen) {
std::pair<std::string, uint16_t> addr =
bittorrent::unpackcompact(data->uc(), family_);
if(addr.first.empty()) {
continue;
}
SharedHandle<Peer> peer(new Peer(addr.first, addr.second));
peers.push_back(peer);
}
}
}
const String* token = getString(rDict, DHTGetPeersReplyMessage::TOKEN);
return createGetPeersReplyMessage
(remoteNode, nodes, token->s(), transactionID);
(remoteNode, nodes, peers, token->s(), transactionID);
}
SharedHandle<DHTResponseMessage>
DHTMessageFactoryImpl::createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<DHTNode> >& closestKNodes,
const std::string& token,
const std::string& transactionID)
{
SharedHandle<DHTGetPeersReplyMessage> m
(new DHTGetPeersReplyMessage(localNode_, remoteNode, token, transactionID));
m->setClosestKNodes(closestKNodes);
setCommonProperty(m);
return m;
}
SharedHandle<DHTResponseMessage>
DHTMessageFactoryImpl::createGetPeersReplyMessageWithValues
(const SharedHandle<DHTNode>& remoteNode,
const Dict* dict,
const std::string& transactionID)
{
const Dict* rDict = getDictionary(dict, DHTResponseMessage::R);
const List* valuesList = getList(rDict,
DHTGetPeersReplyMessage::VALUES);
std::vector<SharedHandle<Peer> > peers;
for(List::ValueType::const_iterator i = valuesList->begin(),
eoi = valuesList->end(); i != eoi; ++i) {
const String* data = asString(*i);
if(data && data->s().size() == 6) {
std::pair<std::string, uint16_t> addr =
bittorrent::unpackcompact(data->uc(), AF_INET);
SharedHandle<Peer> peer(new Peer(addr.first, addr.second));
peers.push_back(peer);
}
}
const String* token = getString(rDict, DHTGetPeersReplyMessage::TOKEN);
return createGetPeersReplyMessage
(remoteNode, peers, token->s(), transactionID);
}
SharedHandle<DHTResponseMessage>
DHTMessageFactoryImpl::createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<Peer> >& values,
const std::string& token,
const std::string& transactionID)
{
SharedHandle<DHTGetPeersReplyMessage> m
(new DHTGetPeersReplyMessage(localNode_, remoteNode, token, transactionID));
(new DHTGetPeersReplyMessage
(family_, localNode_, remoteNode, token, transactionID));
m->setClosestKNodes(closestKNodes);
m->setValues(values);
setCommonProperty(m);
return m;

View File

@ -51,6 +51,8 @@ class DHTAbstractMessage;
class DHTMessageFactoryImpl:public DHTMessageFactory {
private:
int family_;
SharedHandle<DHTNode> localNode_;
WeakHandle<DHTConnection> connection_;
@ -73,13 +75,14 @@ private:
void validatePort(const Integer* i) const;
std::vector<SharedHandle<DHTNode> >
extractNodes(const unsigned char* src, size_t length);
void extractNodes
(std::vector<SharedHandle<DHTNode> >& nodes,
const unsigned char* src, size_t length);
void setCommonProperty(const SharedHandle<DHTAbstractMessage>& m);
public:
DHTMessageFactoryImpl();
DHTMessageFactoryImpl(int family);
virtual ~DHTMessageFactoryImpl();
@ -127,25 +130,15 @@ public:
createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<DHTNode> >& closestKNodes,
const std::string& token,
const std::string& transactionID);
SharedHandle<DHTResponseMessage>
createGetPeersReplyMessageWithNodes(const SharedHandle<DHTNode>& remoteNode,
const Dict* dict,
const std::string& transactionID);
virtual SharedHandle<DHTResponseMessage>
createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<Peer> >& peers,
const std::string& token,
const std::string& transactionID);
SharedHandle<DHTResponseMessage>
createGetPeersReplyMessageWithValues(const SharedHandle<DHTNode>& remoteNode,
const Dict* dict,
const std::string& transactionID);
createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const Dict* dict,
const std::string& transactionID);
virtual SharedHandle<DHTQueryMessage>
createAnnouncePeerMessage(const SharedHandle<DHTNode>& remoteNode,

View File

@ -84,19 +84,24 @@ DHTMessageTracker::messageArrived
logger_->debug("Tracker entry found.");
}
SharedHandle<DHTNode> targetNode = entry->getTargetNode();
try {
SharedHandle<DHTResponseMessage> message =
factory_->createResponseMessage(entry->getMessageType(), dict,
targetNode->getIPAddress(),
targetNode->getPort());
SharedHandle<DHTResponseMessage> message =
factory_->createResponseMessage(entry->getMessageType(), dict,
targetNode->getIPAddress(),
targetNode->getPort());
int64_t rtt = entry->getElapsedMillis();
if(logger_->debug()) {
logger_->debug("RTT is %s", util::itos(rtt).c_str());
int64_t rtt = entry->getElapsedMillis();
if(logger_->debug()) {
logger_->debug("RTT is %s", util::itos(rtt).c_str());
}
message->getRemoteNode()->updateRTT(rtt);
SharedHandle<DHTMessageCallback> callback = entry->getCallback();
return std::make_pair(message, callback);
} catch(RecoverableException& e) {
entry->getCallback()->onTimeout(targetNode);
return std::pair<SharedHandle<DHTResponseMessage>,
SharedHandle<DHTMessageCallback> >();
}
message->getRemoteNode()->updateRTT(rtt);
SharedHandle<DHTMessageCallback> callback = entry->getCallback();
return std::make_pair(message, callback);
}
}
if(logger_->debug()) {

View File

@ -49,17 +49,30 @@ namespace aria2 {
DHTRegistry::Data DHTRegistry::data_;
DHTRegistry::Data DHTRegistry::data6_;
void DHTRegistry::clear(DHTRegistry::Data& data)
{
data.initialized = false;
data.localNode.reset();
data.routingTable.reset();
data.taskQueue.reset();
data.taskFactory.reset();
data.peerAnnounceStorage.reset();
data.tokenTracker.reset();
data.messageDispatcher.reset();
data.messageReceiver.reset();
data.messageFactory.reset();
}
void DHTRegistry::clearData()
{
data_.localNode.reset();
data_.routingTable.reset();
data_.taskQueue.reset();
data_.taskFactory.reset();
data_.peerAnnounceStorage.reset();
data_.tokenTracker.reset();
data_.messageDispatcher.reset();
data_.messageReceiver.reset();
data_.messageFactory.reset();
clear(data_);
}
void DHTRegistry::clearData6()
{
clear(data6_);
}
} // namespace aria2

View File

@ -53,6 +53,8 @@ class DHTMessageFactory;
class DHTRegistry {
private:
struct Data {
bool initialized;
SharedHandle<DHTNode> localNode;
SharedHandle<DHTRoutingTable> routingTable;
@ -70,9 +72,15 @@ private:
SharedHandle<DHTMessageReceiver> messageReceiver;
SharedHandle<DHTMessageFactory> messageFactory;
Data():initialized(false) {}
};
static Data data_;
static Data data6_;
static void clear(Data& data);
DHTRegistry();
public:
static const Data& getData()
@ -86,6 +94,38 @@ public:
}
static void clearData();
static bool isInitialized()
{
return data_.initialized;
}
static void setInitialized(bool f)
{
data_.initialized = f;
}
static const Data& getData6()
{
return data6_;
}
static Data& getMutableData6()
{
return data6_;
}
static void clearData6();
static bool isInitialized6()
{
return data6_.initialized;
}
static void setInitialized6(bool f)
{
data6_.initialized = f;
}
};
} // namespace aria2

View File

@ -52,7 +52,8 @@
namespace aria2 {
DHTRoutingTableDeserializer::DHTRoutingTableDeserializer() {}
DHTRoutingTableDeserializer::DHTRoutingTableDeserializer(int family):
family_(family) {}
DHTRoutingTableDeserializer::~DHTRoutingTableDeserializer() {}
@ -99,7 +100,7 @@ void DHTRoutingTableDeserializer::deserialize(std::istream& in)
headerCompat[6] = 0;
headerCompat[7] = 0x02;
char zero[8];
char zero[18];
memset(zero, 0, sizeof(zero));
int version;
@ -159,44 +160,39 @@ void DHTRoutingTableDeserializer::deserialize(std::istream& in)
std::vector<SharedHandle<DHTNode> > nodes;
// nodes
const int compactlen = bittorrent::getCompactLength(family_);
for(size_t i = 0; i < numNodes; ++i) {
// Currently, only IPv4 addresses are supported.
// 1byte compact peer info length
uint8_t peerInfoLen;
in >> peerInfoLen;
if(peerInfoLen != 6) {
if(peerInfoLen != compactlen) {
// skip this entry
readBytes(buf, buf.size(), in, 42+7+6);
CHECK_STREAM(in, 42+7+6);
readBytes(buf, buf.size(), in, 7+48);
CHECK_STREAM(in, 7+48);
continue;
}
// 7bytes reserved
readBytes(buf, buf.size(), in, 7);
CHECK_STREAM(in, 7);
// 6bytes compact peer info
readBytes(buf, buf.size(), in, 6);
CHECK_STREAM(in, 6);
if(memcmp(zero, buf, 6) == 0) {
// compactlen bytes compact peer info
readBytes(buf, buf.size(), in, compactlen);
CHECK_STREAM(in, compactlen);
if(memcmp(zero, buf, compactlen) == 0) {
// skip this entry
readBytes(buf, buf.size(), in, 42);
CHECK_STREAM(in, 42);
readBytes(buf, buf.size(), in, 48-compactlen);
CHECK_STREAM(in, 48-compactlen);
continue;
}
// TODO DHT6 protocol family should be configurable.
std::pair<std::string, uint16_t> peer =
bittorrent::unpackcompact(buf, AF_INET);
bittorrent::unpackcompact(buf, family_);
if(peer.first.empty()) {
// skip this entry
readBytes(buf, buf.size(), in, 42);
CHECK_STREAM(in, 42);
readBytes(buf, buf.size(), in, 48-compactlen);
CHECK_STREAM(in, 48-compactlen);
continue;
}
// 2bytes reserved
readBytes(buf, buf.size(), in, 2);
CHECK_STREAM(in, 2);
// 16byte reserved
readBytes(buf, buf.size(), in, 16);
CHECK_STREAM(in, 16);
// 24-compactlen bytes reserved
readBytes(buf, buf.size(), in, 24-compactlen);
// node ID
readBytes(buf, buf.size(), in, DHT_ID_LENGTH);
CHECK_STREAM(in, DHT_ID_LENGTH);

View File

@ -49,13 +49,15 @@ class DHTNode;
class DHTRoutingTableDeserializer {
private:
int family_;
SharedHandle<DHTNode> localNode_;
std::vector<SharedHandle<DHTNode> > nodes_;
Time serializedTime_;
public:
DHTRoutingTableDeserializer();
DHTRoutingTableDeserializer(int family);
~DHTRoutingTableDeserializer();

View File

@ -50,7 +50,8 @@
namespace aria2 {
DHTRoutingTableSerializer::DHTRoutingTableSerializer() {}
DHTRoutingTableSerializer::DHTRoutingTableSerializer(int family):
family_(family) {}
DHTRoutingTableSerializer::~DHTRoutingTableSerializer() {}
@ -79,7 +80,7 @@ void DHTRoutingTableSerializer::serialize(std::ostream& o)
header[6] = 0;
header[7] = 0x03;
char zero[16];
char zero[18];
memset(zero, 0, sizeof(zero));
o.write(header, 8);
@ -101,29 +102,26 @@ void DHTRoutingTableSerializer::serialize(std::ostream& o)
// 4bytes reserved
o.write(zero, 4);
const int clen = bittorrent::getCompactLength(family_);
// nodes
for(std::vector<SharedHandle<DHTNode> >::const_iterator i = nodes_.begin(),
eoi = nodes_.end(); i != eoi; ++i) {
const SharedHandle<DHTNode>& node = *i;
// Currently, only IPv4 addresses are saved.
// 6bytes: write IP address + port in Compact IP-address/port info form.
// Write IP address + port in Compact IP-address/port info form.
unsigned char compactPeer[COMPACT_LEN_IPV6];
int compactlen = bittorrent::packcompact
(compactPeer, node->getIPAddress(), node->getPort());
if(compactlen != COMPACT_LEN_IPV4) {
compactlen = COMPACT_LEN_IPV4;
memset(compactPeer, 0, COMPACT_LEN_IPV4);
if(compactlen != clen) {
memset(compactPeer, 0, clen);
}
// 1byte compact peer format length
o << static_cast<uint8_t>(compactlen);
o << static_cast<uint8_t>(clen);
// 7bytes reserved
o.write(zero, 7);
// 6 bytes compact peer
o.write(reinterpret_cast<const char*>(compactPeer), compactlen);
// 2bytes reserved
o.write(zero, 2);
// 16bytes reserved
o.write(zero, 16);
// clen bytes compact peer
o.write(reinterpret_cast<const char*>(compactPeer), clen);
// 24-clen bytes reserved
o.write(zero, 24-clen);
// 20bytes: node ID
o.write(reinterpret_cast<const char*>(node->getID()), DHT_ID_LENGTH);
// 4bytes reserved

View File

@ -48,11 +48,13 @@ class DHTNode;
class DHTRoutingTableSerializer {
private:
int family_;
SharedHandle<DHTNode> localNode_;
std::vector<SharedHandle<DHTNode> > nodes_;
public:
DHTRoutingTableSerializer();
DHTRoutingTableSerializer(int family);
~DHTRoutingTableSerializer();

View File

@ -79,16 +79,18 @@
namespace aria2 {
// TODO DownloadEngine should hold this flag.
bool DHTSetup::initialized_ = false;
DHTSetup::DHTSetup():logger_(LogFactory::getInstance()) {}
DHTSetup::~DHTSetup() {}
void DHTSetup::setup(std::vector<Command*>& commands, DownloadEngine* e)
void DHTSetup::setup
(std::vector<Command*>& commands, DownloadEngine* e, int family)
{
if(initialized_) {
if(family != AF_INET && family != AF_INET6) {
return;
}
if((family == AF_INET && DHTRegistry::isInitialized()) ||
(family == AF_INET6 && DHTRegistry::isInitialized6())) {
return;
}
try {
@ -98,8 +100,10 @@ void DHTSetup::setup(std::vector<Command*>& commands, DownloadEngine* e)
SharedHandle<DHTNode> localNode;
DHTRoutingTableDeserializer deserializer;
std::string dhtFile = e->getOption()->get(PREF_DHT_FILE_PATH);
DHTRoutingTableDeserializer deserializer(family);
const std::string& dhtFile =
e->getOption()->get(family == AF_INET?PREF_DHT_FILE_PATH:
PREF_DHT_FILE_PATH6);
try {
std::ifstream in(dhtFile.c_str(), std::ios::binary);
if(!in) {
@ -115,12 +119,15 @@ void DHTSetup::setup(std::vector<Command*>& commands, DownloadEngine* e)
localNode.reset(new DHTNode());
}
SharedHandle<DHTConnectionImpl> connection(new DHTConnectionImpl());
SharedHandle<DHTConnectionImpl> connection(new DHTConnectionImpl(family));
{
IntSequence seq =
util::parseIntRange(e->getOption()->get(PREF_DHT_LISTEN_PORT));
uint16_t port;
if(!connection->bind(port, seq)) {
const std::string& addr =
e->getOption()->get(family == AF_INET?PREF_DHT_LISTEN_ADDR:
PREF_DHT_LISTEN_ADDR6);
if(!connection->bind(port, addr, seq)) {
throw DL_ABORT_EX("Error occurred while binding port for DHT");
}
localNode->setPort(port);
@ -131,7 +138,8 @@ void DHTSetup::setup(std::vector<Command*>& commands, DownloadEngine* e)
}
SharedHandle<DHTRoutingTable> routingTable(new DHTRoutingTable(localNode));
SharedHandle<DHTMessageFactoryImpl> factory(new DHTMessageFactoryImpl());
SharedHandle<DHTMessageFactoryImpl> factory
(new DHTMessageFactoryImpl(family));
SharedHandle<DHTMessageTracker> tracker(new DHTMessageTracker());
@ -179,16 +187,27 @@ void DHTSetup::setup(std::vector<Command*>& commands, DownloadEngine* e)
factory->setLocalNode(localNode);
// assign them into DHTRegistry
DHTRegistry::getMutableData().localNode = localNode;
DHTRegistry::getMutableData().routingTable = routingTable;
DHTRegistry::getMutableData().taskQueue = taskQueue;
DHTRegistry::getMutableData().taskFactory = taskFactory;
DHTRegistry::getMutableData().peerAnnounceStorage = peerAnnounceStorage;
DHTRegistry::getMutableData().tokenTracker = tokenTracker;
DHTRegistry::getMutableData().messageDispatcher = dispatcher;
DHTRegistry::getMutableData().messageReceiver = receiver;
DHTRegistry::getMutableData().messageFactory = factory;
if(family == AF_INET) {
DHTRegistry::getMutableData().localNode = localNode;
DHTRegistry::getMutableData().routingTable = routingTable;
DHTRegistry::getMutableData().taskQueue = taskQueue;
DHTRegistry::getMutableData().taskFactory = taskFactory;
DHTRegistry::getMutableData().peerAnnounceStorage = peerAnnounceStorage;
DHTRegistry::getMutableData().tokenTracker = tokenTracker;
DHTRegistry::getMutableData().messageDispatcher = dispatcher;
DHTRegistry::getMutableData().messageReceiver = receiver;
DHTRegistry::getMutableData().messageFactory = factory;
} else {
DHTRegistry::getMutableData6().localNode = localNode;
DHTRegistry::getMutableData6().routingTable = routingTable;
DHTRegistry::getMutableData6().taskQueue = taskQueue;
DHTRegistry::getMutableData6().taskFactory = taskFactory;
DHTRegistry::getMutableData6().peerAnnounceStorage = peerAnnounceStorage;
DHTRegistry::getMutableData6().tokenTracker = tokenTracker;
DHTRegistry::getMutableData6().messageDispatcher = dispatcher;
DHTRegistry::getMutableData6().messageReceiver = receiver;
DHTRegistry::getMutableData6().messageFactory = factory;
}
// add deserialized nodes to routing table
const std::vector<SharedHandle<DHTNode> >& desnodes =
deserializer.getNodes();
@ -206,11 +225,16 @@ void DHTSetup::setup(std::vector<Command*>& commands, DownloadEngine* e)
taskQueue->addPeriodicTask1(task);
}
if(!e->getOption()->get(PREF_DHT_ENTRY_POINT_HOST).empty()) {
const std::string& prefEntryPointHost =
family == AF_INET?PREF_DHT_ENTRY_POINT_HOST:PREF_DHT_ENTRY_POINT_HOST6;
if(!e->getOption()->get(prefEntryPointHost).empty()) {
{
const std::string& prefEntryPointPort =
family == AF_INET?PREF_DHT_ENTRY_POINT_PORT:
PREF_DHT_ENTRY_POINT_PORT6;
std::pair<std::string, uint16_t> addr
(e->getOption()->get(PREF_DHT_ENTRY_POINT_HOST),
e->getOption()->getAsInt(PREF_DHT_ENTRY_POINT_PORT));
(e->getOption()->get(prefEntryPointHost),
e->getOption()->getAsInt(prefEntryPointPort));
std::vector<std::pair<std::string, uint16_t> > entryPoints;
entryPoints.push_back(addr);
DHTEntryPointNameResolveCommand* command =
@ -258,24 +282,27 @@ void DHTSetup::setup(std::vector<Command*>& commands, DownloadEngine* e)
}
{
DHTAutoSaveCommand* command =
new DHTAutoSaveCommand(e->newCUID(), e, 30*60);
new DHTAutoSaveCommand(e->newCUID(), e, family, 30*60);
command->setLocalNode(localNode);
command->setRoutingTable(routingTable);
tempCommands->push_back(command);
}
initialized_ = true;
if(family == AF_INET) {
DHTRegistry::setInitialized(true);
} else {
DHTRegistry::setInitialized6(true);
}
commands.insert(commands.end(), tempCommands->begin(), tempCommands->end());
tempCommands->clear();
} catch(RecoverableException& e) {
logger_->error("Exception caught while initializing DHT functionality."
" DHT is disabled.", e);
DHTRegistry::clearData();
if(family == AF_INET) {
DHTRegistry::clearData();
} else {
DHTRegistry::clearData6();
}
}
}
bool DHTSetup::initialized()
{
return initialized_;
}
} // namespace aria2

View File

@ -45,18 +45,13 @@ class Command;
class DHTSetup {
private:
static bool initialized_;
Logger* logger_;
public:
DHTSetup();
~DHTSetup();
void setup(std::vector<Command*>& commands, DownloadEngine* e);
static bool initialized();
void setup(std::vector<Command*>& commands, DownloadEngine* e, int family);
};
} // namespace aria2

View File

@ -223,7 +223,7 @@ SharedHandle<SocketCore> FtpConnection::createServerSocket()
std::pair<std::string, uint16_t> addrinfo;
socket_->getAddrInfo(addrinfo);
SharedHandle<SocketCore> serverSocket(new SocketCore());
serverSocket->bind(addrinfo.first, 0);
serverSocket->bind(addrinfo.first, 0, AF_UNSPEC);
serverSocket->beginListen();
serverSocket->setNonBlockingMode();
return serverSocket;

View File

@ -56,7 +56,7 @@ bool LpdMessageReceiver::init(const std::string& localAddr)
// Binding multicast address fails under Windows.
socket_->bindWithFamily(multicastPort_, AF_INET);
#else // !__MINGW32__
socket_->bind(multicastAddress_, multicastPort_);
socket_->bind(multicastAddress_, multicastPort_, AF_INET);
#endif // !__MINGW32__
if(logger_->debug()) {
logger_->debug("Joining multicast group. %s:%u, localAddr=%s",

View File

@ -1325,6 +1325,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new HostPortOptionHandler
(PREF_DHT_ENTRY_POINT6,
TEXT_DHT_ENTRY_POINT6,
NO_DEFAULT_VALUE,
PREF_DHT_ENTRY_POINT_HOST6,
PREF_DHT_ENTRY_POINT_PORT6));
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new DefaultOptionHandler
(PREF_DHT_FILE_PATH,
@ -1334,6 +1344,34 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new DefaultOptionHandler
(PREF_DHT_FILE_PATH6,
TEXT_DHT_FILE_PATH6,
util::getHomeDir()+"/.aria2/dht6.dat",
"/PATH/TO/DHT_DAT"));
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new DefaultOptionHandler
(PREF_DHT_LISTEN_ADDR,
NO_DESCRIPTION,
NO_DEFAULT_VALUE));
op->hide();
op->addTag(TAG_BASIC);
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new DefaultOptionHandler
(PREF_DHT_LISTEN_ADDR6,
TEXT_DHT_LISTEN_ADDR6,
NO_DEFAULT_VALUE));
op->addTag(TAG_BASIC);
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new IntegerRangeOptionHandler
(PREF_DHT_LISTEN_PORT,
@ -1363,6 +1401,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new BooleanOptionHandler
(PREF_ENABLE_DHT6,
TEXT_ENABLE_DHT6,
V_FALSE,
OptionHandler::OPT_ARG));
op->addTag(TAG_BASIC);
op->addTag(TAG_BITTORRENT);
handlers.push_back(op);
}
{
SharedHandle<OptionHandler> op(new BooleanOptionHandler
(PREF_ENABLE_PEER_EXCHANGE,

View File

@ -522,17 +522,18 @@ public:
virtual void parseArg(Option& option, const std::string& optarg)
{
std::pair<std::string, std::string> proxy = util::split(optarg, ":");
int32_t port = util::parseInt(proxy.second);
if(proxy.first.empty() || proxy.second.empty() ||
port <= 0 || 65535 < port) {
throw DL_ABORT_EX(_("unrecognized proxy format"));
std::string uri = "http://";
uri += optarg;
Request req;
if(!req.setUri(uri)) {
throw DL_ABORT_EX(_("Unrecognized format"));
}
option.put(optName_, optarg);
setHostAndPort(option, proxy.first, port);
setHostAndPort(option, req.getHost(), req.getPort());
}
void setHostAndPort(Option& option, const std::string& hostname, uint16_t port)
void setHostAndPort
(Option& option, const std::string& hostname, uint16_t port)
{
option.put(hostOptionName_, hostname);
option.put(portOptionName_, util::uitos(port));

View File

@ -60,8 +60,13 @@
#include "DHTTaskQueue.h"
#include "DHTTaskFactory.h"
#include "DHTNode.h"
#include "DHTSetup.h"
#include "DHTRegistry.h"
#include "DHTPeerAnnounceStorage.h"
#include "DHTTokenTracker.h"
#include "DHTMessageDispatcher.h"
#include "DHTMessageReceiver.h"
#include "DHTMessageFactory.h"
#include "DHTMessageCallback.h"
#include "PieceStorage.h"
#include "RequestGroup.h"
#include "BtAnnounce.h"
@ -102,6 +107,17 @@ PeerInteractionCommand::PeerInteractionCommand
setWriteCheckSocket(getSocket());
setTimeout(getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT));
}
int family;
unsigned char compact[COMPACT_LEN_IPV6];
int compactlen = bittorrent::packcompact
(compact, getPeer()->getIPAddress(), getPeer()->getPort());
if(compactlen == COMPACT_LEN_IPV6) {
family = AF_INET6;
} else {
family = AF_INET;
}
SharedHandle<TorrentAttribute> torrentAttrs =
bittorrent::getTorrentAttrs(requestGroup_->getDownloadContext());
bool metadataGetMode = torrentAttrs->metadata.empty();
@ -131,11 +147,18 @@ PeerInteractionCommand::PeerInteractionCommand
factory->setPieceStorage(pieceStorage);
factory->setPeerStorage(peerStorage);
factory->setExtensionMessageFactory(extensionMessageFactory);
factory->setPeer(getPeer());
factory->setLocalNode(DHTRegistry::getData().localNode);
factory->setRoutingTable(DHTRegistry::getData().routingTable);
factory->setTaskQueue(DHTRegistry::getData().taskQueue);
factory->setTaskFactory(DHTRegistry::getData().taskFactory);
factory->setPeer(getPeer());
if(family == AF_INET) {
factory->setLocalNode(DHTRegistry::getData().localNode);
factory->setRoutingTable(DHTRegistry::getData().routingTable);
factory->setTaskQueue(DHTRegistry::getData().taskQueue);
factory->setTaskFactory(DHTRegistry::getData().taskFactory);
} else {
factory->setLocalNode(DHTRegistry::getData6().localNode);
factory->setRoutingTable(DHTRegistry::getData6().routingTable);
factory->setTaskQueue(DHTRegistry::getData6().taskQueue);
factory->setTaskFactory(DHTRegistry::getData6().taskFactory);
}
if(metadataGetMode) {
factory->enableMetadataGetMode();
}
@ -192,10 +215,18 @@ PeerInteractionCommand::PeerInteractionCommand
if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) {
btInteractive->setUTPexEnabled(true);
}
if(DHTSetup::initialized()) {
btInteractive->setDHTEnabled(true);
btInteractive->setLocalNode(DHTRegistry::getData().localNode);
factory->setDHTEnabled(true);
if(family == AF_INET) {
if(DHTRegistry::isInitialized()) {
btInteractive->setDHTEnabled(true);
factory->setDHTEnabled(true);
btInteractive->setLocalNode(DHTRegistry::getData().localNode);
}
} else {
if(DHTRegistry::isInitialized6()) {
btInteractive->setDHTEnabled(true);
factory->setDHTEnabled(true);
btInteractive->setLocalNode(DHTRegistry::getData6().localNode);
}
}
}
btInteractive->setUTMetadataRequestFactory(utMetadataRequestFactory);

View File

@ -94,6 +94,15 @@
# include "BtPostDownloadHandler.h"
# include "DHTSetup.h"
# include "DHTRegistry.h"
# include "DHTNode.h"
# include "DHTRoutingTable.h"
# include "DHTTaskQueue.h"
# include "DHTTaskFactory.h"
# include "DHTTokenTracker.h"
# include "DHTMessageDispatcher.h"
# include "DHTMessageReceiver.h"
# include "DHTMessageFactory.h"
# include "DHTMessageCallback.h"
# include "BtMessageFactory.h"
# include "BtRequestFactory.h"
# include "BtMessageDispatcher.h"
@ -283,10 +292,18 @@ void RequestGroup::createInitialCommand
SharedHandle<BtProgressInfoFile>
(progressInfoFile))));
if(metadataGetMode) {
if(option_->getAsBool(PREF_ENABLE_DHT)) {
std::vector<Command*> dhtCommands;
DHTSetup().setup(dhtCommands, e);
e->addCommand(dhtCommands);
if(option_->getAsBool(PREF_ENABLE_DHT) ||
option_->getAsBool(PREF_ENABLE_DHT6)) {
if(option_->getAsBool(PREF_ENABLE_DHT)) {
std::vector<Command*> dhtCommands;
DHTSetup().setup(dhtCommands, e, AF_INET);
e->addCommand(dhtCommands);
}
if(option_->getAsBool(PREF_ENABLE_DHT6)) {
std::vector<Command*> dhtCommands;
DHTSetup().setup(dhtCommands, e, AF_INET6);
e->addCommand(dhtCommands);
}
} else {
logger_->notice("For BitTorrent Magnet URI, enabling DHT is strongly"
" recommended. See --enable-dht option.");
@ -343,16 +360,25 @@ void RequestGroup::createInitialCommand
}
progressInfoFile_ = progressInfoFile;
if(!torrentAttrs->privateTorrent && option_->getAsBool(PREF_ENABLE_DHT)) {
std::vector<Command*> dhtCommands;
DHTSetup().setup(dhtCommands, e);
e->addCommand(dhtCommands);
if(!torrentAttrs->privateTorrent &&
(option_->getAsBool(PREF_ENABLE_DHT) ||
option_->getAsBool(PREF_ENABLE_DHT6))) {
if(option_->getAsBool(PREF_ENABLE_DHT)) {
std::vector<Command*> dhtCommands;
DHTSetup().setup(dhtCommands, e, AF_INET);
e->addCommand(dhtCommands);
}
if(option_->getAsBool(PREF_ENABLE_DHT6)) {
std::vector<Command*> dhtCommands;
DHTSetup().setup(dhtCommands, e, AF_INET6);
e->addCommand(dhtCommands);
}
const std::vector<std::pair<std::string, uint16_t> >& nodes =
torrentAttrs->nodes;
if(!nodes.empty() && DHTSetup::initialized()) {
std::vector<std::pair<std::string, uint16_t> > entryPoints(nodes);
// TODO Are nodes in torrent IPv4 only?
if(!nodes.empty() && DHTRegistry::isInitialized()) {
DHTEntryPointNameResolveCommand* command =
new DHTEntryPointNameResolveCommand(e->newCUID(), e, entryPoints);
new DHTEntryPointNameResolveCommand(e->newCUID(), e, nodes);
command->setTaskQueue(DHTRegistry::getData().taskQueue);
command->setTaskFactory(DHTRegistry::getData().taskFactory);
command->setRoutingTable(DHTRegistry::getData().routingTable);

View File

@ -54,6 +54,7 @@
#include "TimeA2.h"
#include "a2functional.h"
#include "LogFactory.h"
#include "A2STR.h"
#ifdef ENABLE_SSL
# include "TLSContext.h"
#endif // ENABLE_SSL
@ -215,6 +216,14 @@ static sock_t bindInternal(int family, int socktype, int protocol,
CLOSE(fd);
return -1;
}
if(family == AF_INET6) {
int sockopt = 1;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (a2_sockopt_t) &sockopt,
sizeof(sockopt)) < 0) {
CLOSE(fd);
return -1;
}
}
if(::bind(fd, addr, addrlen) == -1) {
error = errorMsg();
CLOSE(fd);
@ -258,25 +267,19 @@ void SocketCore::bindWithFamily(uint16_t port, int family, int flags)
}
}
void SocketCore::bind(const std::string& addr, uint16_t port, int flags)
void SocketCore::bind
(const std::string& addr, uint16_t port, int family, int flags)
{
closeConnection();
std::string error;
sock_t fd =
bindTo(addr.c_str(), port, protocolFamily_, sockType_, flags, error);
if(fd == (sock_t)-1) {
throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, error.c_str()).str());
const char* addrp;
if(addr.empty()) {
addrp = 0;
} else {
sockfd_ = fd;
addrp = addr.c_str();
}
}
void SocketCore::bind(uint16_t port, int flags)
{
closeConnection();
std::string error;
if(!(flags&AI_PASSIVE) || bindAddrs_.empty()) {
sock_t fd = bindTo(0, port, protocolFamily_, sockType_, flags, error);
sock_t fd = bindTo(addrp, port, family, sockType_, flags, error);
if(fd != (sock_t) -1) {
sockfd_ = fd;
}
@ -294,7 +297,11 @@ void SocketCore::bind(uint16_t port, int flags)
error = gai_strerror(s);
continue;
}
sock_t fd = bindTo(host, port, protocolFamily_, sockType_, flags, error);
if(addrp && strcmp(host, addrp) != 0) {
// TODO we should assign something to error?
continue;
}
sock_t fd = bindTo(addrp, port, family, sockType_, flags, error);
if(fd != (sock_t)-1) {
sockfd_ = fd;
break;
@ -306,6 +313,11 @@ void SocketCore::bind(uint16_t port, int flags)
}
}
void SocketCore::bind(uint16_t port, int flags)
{
bind(A2STR::NIL, port, protocolFamily_, flags);
}
void SocketCore::bind(const struct sockaddr* addr, socklen_t addrlen)
{
closeConnection();

View File

@ -137,8 +137,6 @@ public:
void bindWithFamily(uint16_t port, int family, int flags = AI_PASSIVE);
void bind(const std::string& addr, uint16_t port, int flags = AI_PASSIVE);
/**
* Creates a socket and bind it with locahost's address and port.
* flags is set to struct addrinfo's ai_flags.
@ -147,6 +145,9 @@ public:
*/
void bind(uint16_t port, int flags = AI_PASSIVE);
void bind
(const std::string& addr, uint16_t port, int family, int flags = AI_PASSIVE);
/**
* Listens form connection on it.
* Call bind(uint16_t) before calling this function.

View File

@ -994,6 +994,17 @@ std::string torrent2Magnet(const SharedHandle<TorrentAttribute>& attrs)
return uri;
}
int getCompactLength(int family)
{
if(family == AF_INET) {
return COMPACT_LEN_IPV4;
} else if(family == AF_INET6) {
return COMPACT_LEN_IPV6;
} else {
return 0;
}
}
} // namespace bittorrent
} // namespace aria2

View File

@ -246,6 +246,9 @@ void extractPeer(const ValueBase* peerData, int family, OutputIterator dest)
const unsigned char* end = base+length;
for(; base != end; base += unit) {
std::pair<std::string, uint16_t> p = unpackcompact(base, family_);
if(p.first.empty()) {
continue;
}
*dest_++ = SharedHandle<Peer>(new Peer(p.first, p.second));
}
}
@ -288,6 +291,8 @@ void extractPeer
return extractPeer(peerData.get(), family, dest);
}
int getCompactLength(int family);
} // namespace bittorrent
} // namespace aria2

View File

@ -308,6 +308,8 @@ const std::string PREF_PEER_ID_PREFIX("peer-id-prefix");
const std::string PREF_ENABLE_PEER_EXCHANGE("enable-peer-exchange");
// values: true | false
const std::string PREF_ENABLE_DHT("enable-dht");
// values: a string
const std::string PREF_DHT_LISTEN_ADDR("dht-listen-addr");
// values: 1*digit
const std::string PREF_DHT_LISTEN_PORT("dht-listen-port");
// values: a string
@ -318,6 +320,18 @@ const std::string PREF_DHT_ENTRY_POINT_PORT("dht-entry-point-port");
const std::string PREF_DHT_ENTRY_POINT("dht-entry-point");
// values: a string
const std::string PREF_DHT_FILE_PATH("dht-file-path");
// values: true | false
const std::string PREF_ENABLE_DHT6("enable-dht6");
// values: a string
const std::string PREF_DHT_LISTEN_ADDR6("dht-listen-addr6");
// values: a string
const std::string PREF_DHT_ENTRY_POINT_HOST6("dht-entry-point-host6");
// values: 1*digit
const std::string PREF_DHT_ENTRY_POINT_PORT6("dht-entry-point-port6");
// values: a string (hostname:port)
const std::string PREF_DHT_ENTRY_POINT6("dht-entry-point6");
// values: a string
const std::string PREF_DHT_FILE_PATH6("dht-file-path6");
// values: plain | arc4
const std::string PREF_BT_MIN_CRYPTO_LEVEL("bt-min-crypto-level");
const std::string V_PLAIN("plain");

View File

@ -312,6 +312,8 @@ extern const std::string PREF_PEER_ID_PREFIX;
extern const std::string PREF_ENABLE_PEER_EXCHANGE;
// values: true | false
extern const std::string PREF_ENABLE_DHT;
// values: a string
extern const std::string PREF_DHT_LISTEN_ADDR;
// values: 1*digit
extern const std::string PREF_DHT_LISTEN_PORT;
// values: a string
@ -322,6 +324,18 @@ extern const std::string PREF_DHT_ENTRY_POINT_PORT;
extern const std::string PREF_DHT_ENTRY_POINT;
// values: a string
extern const std::string PREF_DHT_FILE_PATH;
// values: true | false
extern const std::string PREF_ENABLE_DHT6;
// values: a string
extern const std::string PREF_DHT_LISTEN_ADDR6;
// values: a string
extern const std::string PREF_DHT_ENTRY_POINT_HOST6;
// values: 1*digit
extern const std::string PREF_DHT_ENTRY_POINT_PORT6;
// values: a string (hostname:port)
extern const std::string PREF_DHT_ENTRY_POINT6;
// values: a string
extern const std::string PREF_DHT_FILE_PATH6;
// values: plain | arc4
extern const std::string PREF_BT_MIN_CRYPTO_LEVEL;
extern const std::string V_PLAIN;

View File

@ -297,18 +297,18 @@
#define TEXT_ENABLE_PEER_EXCHANGE \
_(" --enable-peer-exchange[=true|false] Enable Peer Exchange extension.")
#define TEXT_ENABLE_DHT \
_(" --enable-dht[=true|false] Enable DHT functionality.")
_(" --enable-dht[=true|false] Enable IPv4 DHT functionality.")
#define TEXT_DHT_LISTEN_PORT \
_(" --dht-listen-port=PORT... Set UDP listening port for DHT.\n" \
" Multiple ports can be specified by using ',',\n" \
" for example: \"6881,6885\". You can also use '-'\n" \
" to specify a range: \"6881-6999\". ',' and '-' can\n" \
" be used together.")
_(" --dht-listen-port=PORT... Set UDP listening port for both IPv4 and IPv6\n" \
" DHT. Multiple ports can be specified by using\n" \
" ',', for example: \"6881,6885\". You can also\n" \
" use '-' to specify a range: \"6881-6999\". ','\n" \
" and '-' can be used together.")
#define TEXT_DHT_ENTRY_POINT \
_(" --dht-entry-point=HOST:PORT Set host and port as an entry point to DHT\n" \
_(" --dht-entry-point=HOST:PORT Set host and port as an entry point to IPv4 DHT\n" \
" network.")
#define TEXT_DHT_FILE_PATH \
_(" --dht-file-path=PATH Change the DHT routing table file to PATH.")
_(" --dht-file-path=PATH Change the IPv4 DHT routing table file to PATH.")
#define TEXT_BT_MIN_CRYPTO_LEVEL \
_(" --bt-min-crypto-level=plain|arc4 Set minimum level of encryption method.\n" \
" If several encryption methods are provided by a\n" \
@ -714,3 +714,15 @@
_(" --enable-async-dns6[=true|false] Enable IPv6 name resolution in asynchronous\n" \
" DNS resolver. This option will be ignored when\n" \
" --async-dns=false.")
#define TEXT_ENABLE_DHT6 \
_(" --enable-dht6[=true|false] Enable IPv6 DHT functionality. See also\n" \
" --dht-listen-addr6 option.")
#define TEXT_DHT_LISTEN_ADDR6 \
_(" --dht-listen-addr6=ADDR Specify address to bind socket for IPv6 DHT. \n" \
" It should be a global unicast IPv6 address of the\n" \
" host.")
#define TEXT_DHT_ENTRY_POINT6 \
_(" --dht-entry-point6=HOST:PORT Set host and port as an entry point to IPv6 DHT\n" \
" network.")
#define TEXT_DHT_FILE_PATH6 \
_(" --dht-file-path6=PATH Change the IPv6 DHT routing table file to PATH.")

View File

@ -1,9 +1,12 @@
#include "DHTConnectionImpl.h"
#include "Exception.h"
#include "SocketCore.h"
#include <iostream>
#include <cppunit/extensions/HelperMacros.h>
#include "Exception.h"
#include "SocketCore.h"
#include "A2STR.h"
namespace aria2 {
class DHTConnectionImplTest:public CppUnit::TestFixture {
@ -25,13 +28,13 @@ CPPUNIT_TEST_SUITE_REGISTRATION(DHTConnectionImplTest);
void DHTConnectionImplTest::testWriteAndReadData()
{
try {
DHTConnectionImpl con1;
DHTConnectionImpl con1(AF_INET);
uint16_t con1port = 0;
CPPUNIT_ASSERT(con1.bind(con1port));
CPPUNIT_ASSERT(con1.bind(con1port, A2STR::NIL));
DHTConnectionImpl con2;
DHTConnectionImpl con2(AF_INET);
uint16_t con2port = 0;
CPPUNIT_ASSERT(con2.bind(con2port));
CPPUNIT_ASSERT(con2.bind(con2port, A2STR::NIL));
std::string message1 = "hello world.";
// hostname should be "localhost", not 127.0.0.1. Test failed on Mac OSX10.5

View File

@ -15,6 +15,7 @@ class DHTFindNodeReplyMessageTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DHTFindNodeReplyMessageTest);
CPPUNIT_TEST(testGetBencodedMessage);
CPPUNIT_TEST(testGetBencodedMessage6);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {}
@ -22,6 +23,8 @@ public:
void tearDown() {}
void testGetBencodedMessage();
void testGetBencodedMessage6();
};
@ -36,7 +39,7 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage()
util::generateRandomData(tid, DHT_TRANSACTION_ID_LENGTH);
std::string transactionID(&tid[0], &tid[DHT_TRANSACTION_ID_LENGTH]);
DHTFindNodeReplyMessage msg(localNode, remoteNode, transactionID);
DHTFindNodeReplyMessage msg(AF_INET, localNode, remoteNode, transactionID);
msg.setVersion("A200");
std::string compactNodeInfo;
SharedHandle<DHTNode> nodes[8];
@ -46,8 +49,8 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage()
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort());
CPPUNIT_ASSERT_EQUAL(COMPACT_LEN_IPV4, bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
@ -69,4 +72,46 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage()
CPPUNIT_ASSERT_EQUAL(bencode2::encode(&dict), msgbody);
}
void DHTFindNodeReplyMessageTest::testGetBencodedMessage6()
{
SharedHandle<DHTNode> localNode(new DHTNode());
SharedHandle<DHTNode> remoteNode(new DHTNode());
unsigned char tid[DHT_TRANSACTION_ID_LENGTH];
util::generateRandomData(tid, DHT_TRANSACTION_ID_LENGTH);
std::string transactionID(&tid[0], &tid[DHT_TRANSACTION_ID_LENGTH]);
DHTFindNodeReplyMessage msg(AF_INET6, localNode, remoteNode, transactionID);
msg.setVersion("A200");
std::string compactNodeInfo;
SharedHandle<DHTNode> nodes[8];
for(size_t i = 0; i < DHTBucket::K; ++i) {
nodes[i].reset(new DHTNode());
nodes[i]->setIPAddress("2001::000"+util::uitos(i+1));
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
CPPUNIT_ASSERT_EQUAL(COMPACT_LEN_IPV6, bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV6]);
}
msg.setClosestKNodes
(std::vector<SharedHandle<DHTNode> >(&nodes[0], &nodes[DHTBucket::K]));
std::string msgbody = msg.getBencodedMessage();
Dict dict;
dict.put("t", transactionID);
dict.put("v", "A200");
dict.put("y", "r");
SharedHandle<Dict> rDict = Dict::g();
rDict->put("id", String::g(localNode->getID(), DHT_ID_LENGTH));
rDict->put("nodes6", compactNodeInfo);
dict.put("r", rDict);
CPPUNIT_ASSERT_EQUAL(bencode2::encode(&dict), msgbody);
}
} // namespace aria2

View File

@ -31,24 +31,11 @@ public:
class MockDHTMessageFactory2:public MockDHTMessageFactory {
public:
virtual SharedHandle<DHTResponseMessage>
createGetPeersReplyMessage(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<Peer> >& peers,
const std::string& token,
const std::string& transactionID)
{
SharedHandle<MockDHTResponseMessage> m
(new MockDHTResponseMessage
(localNode_, remoteNode, "get_peers", transactionID));
m->peers_ = peers;
m->token_ = token;
return m;
}
virtual SharedHandle<DHTResponseMessage>
createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<DHTNode> >& closestKNodes,
const std::vector<SharedHandle<Peer> >& peers,
const std::string& token,
const std::string& transactionID)
{
@ -56,10 +43,10 @@ public:
(new MockDHTResponseMessage
(localNode_, remoteNode, "get_peers", transactionID));
m->nodes_ = closestKNodes;
m->peers_ = peers;
m->token_ = token;
return m;
}
};
};
@ -115,14 +102,13 @@ void DHTGetPeersMessageTest::testDoReceivedAction()
MockDHTMessageDispatcher dispatcher;
MockDHTMessageFactory2 factory;
factory.setLocalNode(localNode);
DHTRoutingTable routingTable(localNode);
DHTGetPeersMessage msg(localNode, remoteNode, infoHash, transactionID);
msg.setTokenTracker(WeakHandle<DHTTokenTracker>
(&tokenTracker));
msg.setMessageDispatcher(WeakHandle<DHTMessageDispatcher>
(&dispatcher));
msg.setMessageFactory(WeakHandle<DHTMessageFactory>
(&factory));
msg.setRoutingTable(WeakHandle<DHTRoutingTable>(&routingTable));
msg.setTokenTracker(WeakHandle<DHTTokenTracker>(&tokenTracker));
msg.setMessageDispatcher(WeakHandle<DHTMessageDispatcher>(&dispatcher));
msg.setMessageFactory(WeakHandle<DHTMessageFactory>(&factory));
{
// localhost has peer contact information for that infohash.
DHTPeerAnnounceStorage peerAnnounceStorage;

View File

@ -16,6 +16,7 @@ class DHTGetPeersReplyMessageTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DHTGetPeersReplyMessageTest);
CPPUNIT_TEST(testGetBencodedMessage);
CPPUNIT_TEST(testGetBencodedMessage6);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {}
@ -23,6 +24,8 @@ public:
void tearDown() {}
void testGetBencodedMessage();
void testGetBencodedMessage6();
};
@ -39,7 +42,8 @@ void DHTGetPeersReplyMessageTest::testGetBencodedMessage()
std::string token = "token";
DHTGetPeersReplyMessage msg(localNode, remoteNode, token, transactionID);
DHTGetPeersReplyMessage msg
(AF_INET, localNode, remoteNode, token, transactionID);
msg.setVersion("A200");
Dict dict;
dict.put("t", transactionID);
@ -58,38 +62,97 @@ void DHTGetPeersReplyMessageTest::testGetBencodedMessage()
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort());
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV4,
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
}
msg.setClosestKNodes
(std::vector<SharedHandle<DHTNode> >(&nodes[0], &nodes[DHTBucket::K]));
std::string msgbody = msg.getBencodedMessage();
rDict->put("nodes", compactNodeInfo);
CPPUNIT_ASSERT_EQUAL(util::percentEncode(bencode2::encode(&dict)),
util::percentEncode(msgbody));
}
rDict->removeKey("nodes");
{
std::vector<SharedHandle<Peer> > peers;
SharedHandle<List> valuesList = List::g();
for(size_t i = 0; i < 4; ++i) {
SharedHandle<Peer> peer(new Peer("192.168.0."+util::uitos(i+1), 6881+i));
unsigned char buffer[COMPACT_LEN_IPV6];
bittorrent::packcompact(buffer, peer->getIPAddress(), peer->getPort());
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV4,
bittorrent::packcompact
(buffer, peer->getIPAddress(), peer->getPort()));
valuesList->append(String::g(buffer, COMPACT_LEN_IPV4));
peers.push_back(peer);
}
msg.setValues(peers);
rDict->put("values", valuesList);
msg.setValues(peers);
std::string msgbody = msg.getBencodedMessage();
std::string msgbody = msg.getBencodedMessage();
CPPUNIT_ASSERT_EQUAL(util::percentEncode(bencode2::encode(&dict)),
util::percentEncode(msgbody));
}
}
void DHTGetPeersReplyMessageTest::testGetBencodedMessage6()
{
SharedHandle<DHTNode> localNode(new DHTNode());
SharedHandle<DHTNode> remoteNode(new DHTNode());
unsigned char tid[DHT_TRANSACTION_ID_LENGTH];
util::generateRandomData(tid, DHT_TRANSACTION_ID_LENGTH);
std::string transactionID(&tid[0], &tid[DHT_TRANSACTION_ID_LENGTH]);
std::string token = "token";
DHTGetPeersReplyMessage msg
(AF_INET6, localNode, remoteNode, token, transactionID);
msg.setVersion("A200");
Dict dict;
dict.put("t", transactionID);
dict.put("v", "A200");
dict.put("y", "r");
SharedHandle<Dict> rDict = Dict::g();
rDict->put("id", String::g(localNode->getID(), DHT_ID_LENGTH));
rDict->put("token", token);
dict.put("r", rDict);
{
std::string compactNodeInfo;
SharedHandle<DHTNode> nodes[8];
for(size_t i = 0; i < DHTBucket::K; ++i) {
nodes[i].reset(new DHTNode());
nodes[i]->setIPAddress("2001::000"+util::uitos(i+1));
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV6, bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV6]);
}
msg.setClosestKNodes
(std::vector<SharedHandle<DHTNode> >(&nodes[0], &nodes[DHTBucket::K]));
rDict->put("nodes6", compactNodeInfo);
std::vector<SharedHandle<Peer> > peers;
SharedHandle<List> valuesList = List::g();
for(size_t i = 0; i < 4; ++i) {
SharedHandle<Peer> peer(new Peer("2001::100"+util::uitos(i+1), 6881+i));
unsigned char buffer[COMPACT_LEN_IPV6];
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV6,
bittorrent::packcompact
(buffer, peer->getIPAddress(), peer->getPort()));
valuesList->append(String::g(buffer, COMPACT_LEN_IPV6));
peers.push_back(peer);
}
msg.setValues(peers);
rDict->put("values", valuesList);
std::string msgbody = msg.getBencodedMessage();
CPPUNIT_ASSERT_EQUAL(util::percentEncode(bencode2::encode(&dict)),
util::percentEncode(msgbody));
}

View File

@ -31,9 +31,10 @@ class DHTMessageFactoryImplTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testCreatePingReplyMessage);
CPPUNIT_TEST(testCreateFindNodeMessage);
CPPUNIT_TEST(testCreateFindNodeReplyMessage);
CPPUNIT_TEST(testCreateFindNodeReplyMessage6);
CPPUNIT_TEST(testCreateGetPeersMessage);
CPPUNIT_TEST(testCreateGetPeersReplyMessage_nodes);
CPPUNIT_TEST(testCreateGetPeersReplyMessage_values);
CPPUNIT_TEST(testCreateGetPeersReplyMessage);
CPPUNIT_TEST(testCreateGetPeersReplyMessage6);
CPPUNIT_TEST(testCreateAnnouncePeerMessage);
CPPUNIT_TEST(testCreateAnnouncePeerReplyMessage);
CPPUNIT_TEST(testReceivedErrorMessage);
@ -52,7 +53,7 @@ public:
void setUp()
{
localNode.reset(new DHTNode());
factory.reset(new DHTMessageFactoryImpl());
factory.reset(new DHTMessageFactoryImpl(AF_INET));
factory->setLocalNode(localNode);
memset(transactionID, 0xff, DHT_TRANSACTION_ID_LENGTH);
memset(remoteNodeID, 0x0f, DHT_ID_LENGTH);
@ -66,9 +67,10 @@ public:
void testCreatePingReplyMessage();
void testCreateFindNodeMessage();
void testCreateFindNodeReplyMessage();
void testCreateFindNodeReplyMessage6();
void testCreateGetPeersMessage();
void testCreateGetPeersReplyMessage_nodes();
void testCreateGetPeersReplyMessage_values();
void testCreateGetPeersReplyMessage();
void testCreateGetPeersReplyMessage6();
void testCreateAnnouncePeerMessage();
void testCreateAnnouncePeerReplyMessage();
void testReceivedErrorMessage();
@ -169,8 +171,10 @@ void DHTMessageFactoryImplTest::testCreateFindNodeReplyMessage()
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort());
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV4,
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
@ -200,6 +204,58 @@ void DHTMessageFactoryImplTest::testCreateFindNodeReplyMessage()
}
}
void DHTMessageFactoryImplTest::testCreateFindNodeReplyMessage6()
{
factory.reset(new DHTMessageFactoryImpl(AF_INET6));
factory->setLocalNode(localNode);
factory->setRoutingTable(routingTable);
try {
Dict dict;
dict.put("t", String::g(transactionID, DHT_TRANSACTION_ID_LENGTH));
dict.put("y", "r");
SharedHandle<Dict> rDict = Dict::g();
rDict->put("id", String::g(remoteNodeID, DHT_ID_LENGTH));
std::string compactNodeInfo;
SharedHandle<DHTNode> nodes[8];
for(size_t i = 0; i < DHTBucket::K; ++i) {
nodes[i].reset(new DHTNode());
nodes[i]->setIPAddress("2001::000"+util::uitos(i+1));
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV6,
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV6]);
}
rDict->put("nodes6", compactNodeInfo);
dict.put("r", rDict);
SharedHandle<DHTNode> remoteNode(new DHTNode(remoteNodeID));
remoteNode->setIPAddress("2001::2001");
remoteNode->setPort(6881);
SharedHandle<DHTFindNodeReplyMessage> m
(dynamic_pointer_cast<DHTFindNodeReplyMessage>
(factory->createResponseMessage("find_node", &dict,
remoteNode->getIPAddress(),
remoteNode->getPort())));
CPPUNIT_ASSERT(localNode == m->getLocalNode());
CPPUNIT_ASSERT(remoteNode == m->getRemoteNode());
CPPUNIT_ASSERT_EQUAL((size_t)DHTBucket::K, m->getClosestKNodes().size());
CPPUNIT_ASSERT(nodes[0] == m->getClosestKNodes()[0]);
CPPUNIT_ASSERT(nodes[7] == m->getClosestKNodes()[7]);
CPPUNIT_ASSERT_EQUAL(util::toHex(transactionID, DHT_TRANSACTION_ID_LENGTH),
util::toHex(m->getTransactionID()));
} catch(Exception& e) {
CPPUNIT_FAIL(e.stackTrace());
}
}
void DHTMessageFactoryImplTest::testCreateGetPeersMessage()
{
Dict dict;
@ -228,7 +284,7 @@ void DHTMessageFactoryImplTest::testCreateGetPeersMessage()
util::toHex(m->getInfoHash(), DHT_ID_LENGTH));
}
void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes()
void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage()
{
try {
Dict dict;
@ -244,13 +300,30 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes()
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort());
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV4,
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
}
rDict->put("nodes", compactNodeInfo);
std::deque<SharedHandle<Peer> > peers;
SharedHandle<List> valuesList = List::g();
for(size_t i = 0; i < 4; ++i) {
SharedHandle<Peer> peer(new Peer("192.168.0."+util::uitos(i+1), 6881+i));
unsigned char buffer[COMPACT_LEN_IPV6];
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV4,
bittorrent::packcompact
(buffer, peer->getIPAddress(), peer->getPort()));
valuesList->append(String::g(buffer, COMPACT_LEN_IPV4));
peers.push_back(peer);
}
rDict->put("values", valuesList);
rDict->put("token", "token");
dict.put("r", rDict);
@ -270,6 +343,9 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes()
CPPUNIT_ASSERT_EQUAL((size_t)DHTBucket::K, m->getClosestKNodes().size());
CPPUNIT_ASSERT(nodes[0] == m->getClosestKNodes()[0]);
CPPUNIT_ASSERT(nodes[7] == m->getClosestKNodes()[7]);
CPPUNIT_ASSERT_EQUAL((size_t)4, m->getValues().size());
CPPUNIT_ASSERT(peers[0] == m->getValues()[0]);
CPPUNIT_ASSERT(peers[3] == m->getValues()[3]);
CPPUNIT_ASSERT_EQUAL(util::toHex(transactionID, DHT_TRANSACTION_ID_LENGTH),
util::toHex(m->getTransactionID()));
} catch(Exception& e) {
@ -277,31 +353,54 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_nodes()
}
}
void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_values()
void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage6()
{
factory.reset(new DHTMessageFactoryImpl(AF_INET6));
factory->setLocalNode(localNode);
factory->setRoutingTable(routingTable);
try {
Dict dict;
dict.put("t", String::g(transactionID, DHT_TRANSACTION_ID_LENGTH));
dict.put("y", "r");
SharedHandle<Dict> rDict = Dict::g();
rDict->put("id", String::g(remoteNodeID, DHT_ID_LENGTH));
std::string compactNodeInfo;
SharedHandle<DHTNode> nodes[8];
for(size_t i = 0; i < DHTBucket::K; ++i) {
nodes[i].reset(new DHTNode());
nodes[i]->setIPAddress("2001::000"+util::uitos(i+1));
nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6];
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV6,
bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV6]);
}
rDict->put("nodes6", compactNodeInfo);
std::deque<SharedHandle<Peer> > peers;
SharedHandle<List> valuesList = List::g();
for(size_t i = 0; i < 4; ++i) {
SharedHandle<Peer> peer(new Peer("192.168.0."+util::uitos(i+1), 6881+i));
SharedHandle<Peer> peer(new Peer("2001::100"+util::uitos(i+1), 6881+i));
unsigned char buffer[COMPACT_LEN_IPV6];
bittorrent::packcompact
(buffer, peer->getIPAddress(), peer->getPort());
valuesList->append(String::g(buffer, COMPACT_LEN_IPV4));
CPPUNIT_ASSERT_EQUAL
(COMPACT_LEN_IPV6,
bittorrent::packcompact
(buffer, peer->getIPAddress(), peer->getPort()));
valuesList->append(String::g(buffer, COMPACT_LEN_IPV6));
peers.push_back(peer);
}
rDict->put("values", valuesList);
rDict->put("token", "token");
dict.put("r", rDict);
SharedHandle<DHTNode> remoteNode(new DHTNode(remoteNodeID));
remoteNode->setIPAddress("192.168.0.1");
remoteNode->setIPAddress("2001::2001");
remoteNode->setPort(6881);
SharedHandle<DHTGetPeersReplyMessage> m
@ -313,6 +412,9 @@ void DHTMessageFactoryImplTest::testCreateGetPeersReplyMessage_values()
CPPUNIT_ASSERT(localNode == m->getLocalNode());
CPPUNIT_ASSERT(remoteNode == m->getRemoteNode());
CPPUNIT_ASSERT_EQUAL(std::string("token"), m->getToken());
CPPUNIT_ASSERT_EQUAL((size_t)DHTBucket::K, m->getClosestKNodes().size());
CPPUNIT_ASSERT(nodes[0] == m->getClosestKNodes()[0]);
CPPUNIT_ASSERT(nodes[7] == m->getClosestKNodes()[7]);
CPPUNIT_ASSERT_EQUAL((size_t)4, m->getValues().size());
CPPUNIT_ASSERT(peers[0] == m->getValues()[0]);
CPPUNIT_ASSERT(peers[3] == m->getValues()[3]);

View File

@ -20,6 +20,7 @@ class DHTRoutingTableDeserializerTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DHTRoutingTableDeserializerTest);
CPPUNIT_TEST(testDeserialize);
CPPUNIT_TEST(testDeserialize6);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {}
@ -27,6 +28,8 @@ public:
void tearDown() {}
void testDeserialize();
void testDeserialize6();
};
@ -45,14 +48,14 @@ void DHTRoutingTableDeserializerTest::testDeserialize()
nodesSrc[1]->setIPAddress("non-numerical-name");
std::vector<SharedHandle<DHTNode> > nodes(vbegin(nodesSrc), vend(nodesSrc));
DHTRoutingTableSerializer s;
DHTRoutingTableSerializer s(AF_INET);
s.setLocalNode(localNode);
s.setNodes(nodes);
std::stringstream ss;
s.serialize(ss);
DHTRoutingTableDeserializer d;
DHTRoutingTableDeserializer d(AF_INET);
d.deserialize(ss);
CPPUNIT_ASSERT(memcmp(localNode->getID(), d.getLocalNode()->getID(),
@ -70,4 +73,44 @@ void DHTRoutingTableDeserializerTest::testDeserialize()
CPPUNIT_ASSERT(memcmp(nodes[2]->getID(), dsnodes[1]->getID(), DHT_ID_LENGTH) == 0);
}
void DHTRoutingTableDeserializerTest::testDeserialize6()
{
SharedHandle<DHTNode> localNode(new DHTNode());
SharedHandle<DHTNode> nodesSrc[3];
for(size_t i = 0; i < A2_ARRAY_LEN(nodesSrc); ++i) {
nodesSrc[i].reset(new DHTNode());
nodesSrc[i]->setIPAddress("2001::100"+util::uitos(i+1));
nodesSrc[i]->setPort(6881+i);
}
nodesSrc[1]->setIPAddress("non-numerical-name");
std::vector<SharedHandle<DHTNode> > nodes(vbegin(nodesSrc), vend(nodesSrc));
DHTRoutingTableSerializer s(AF_INET6);
s.setLocalNode(localNode);
s.setNodes(nodes);
std::stringstream ss;
s.serialize(ss);
DHTRoutingTableDeserializer d(AF_INET6);
d.deserialize(ss);
CPPUNIT_ASSERT(memcmp(localNode->getID(), d.getLocalNode()->getID(),
DHT_ID_LENGTH) == 0);
std::cout << d.getSerializedTime().getTime() << std::endl;
CPPUNIT_ASSERT_EQUAL((size_t)2, d.getNodes().size());
const std::vector<SharedHandle<DHTNode> >& dsnodes = d.getNodes();
CPPUNIT_ASSERT_EQUAL(std::string("2001::1001"), dsnodes[0]->getIPAddress());
CPPUNIT_ASSERT_EQUAL((uint16_t)6881, dsnodes[0]->getPort());
CPPUNIT_ASSERT(memcmp(nodes[0]->getID(), dsnodes[0]->getID(),
DHT_ID_LENGTH) == 0);
CPPUNIT_ASSERT_EQUAL(std::string("2001::1003"), dsnodes[1]->getIPAddress());
CPPUNIT_ASSERT_EQUAL((uint16_t)6883, dsnodes[1]->getPort());
CPPUNIT_ASSERT(memcmp(nodes[2]->getID(), dsnodes[1]->getID(),
DHT_ID_LENGTH) == 0);
}
} // namespace aria2

View File

@ -20,42 +20,35 @@ class DHTRoutingTableSerializerTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DHTRoutingTableSerializerTest);
CPPUNIT_TEST(testSerialize);
CPPUNIT_TEST(testSerialize6);
CPPUNIT_TEST_SUITE_END();
private:
char zero[256];
char buf[20];
void checkToLocalnode
(std::istream& ss, const SharedHandle<DHTNode>& localNode);
void checkNumNodes(std::istream& ss, size_t expected);
public:
void setUp() {}
void setUp()
{
memset(zero, 0, sizeof(zero));
}
void tearDown() {}
void testSerialize();
void testSerialize6();
};
CPPUNIT_TEST_SUITE_REGISTRATION(DHTRoutingTableSerializerTest);
void DHTRoutingTableSerializerTest::testSerialize()
void DHTRoutingTableSerializerTest::checkToLocalnode
(std::istream& ss, const SharedHandle<DHTNode>& localNode)
{
SharedHandle<DHTNode> localNode(new DHTNode());
SharedHandle<DHTNode> nodesSrc[3];
for(size_t i = 0; i < A2_ARRAY_LEN(nodesSrc); ++i) {
nodesSrc[i].reset(new DHTNode());
nodesSrc[i]->setIPAddress("192.168.0."+util::uitos(i+1));
nodesSrc[i]->setPort(6881+i);
}
nodesSrc[1]->setIPAddress("non-numerical-name");
std::vector<SharedHandle<DHTNode> > nodes(vbegin(nodesSrc), vend(nodesSrc));
DHTRoutingTableSerializer s;
s.setLocalNode(localNode);
s.setNodes(nodes);
std::stringstream ss;
s.serialize(ss);
char zero[16];
memset(zero, 0, sizeof(zero));
char buf[20];
// header
ss.read(buf, 8);
// magic
@ -89,14 +82,44 @@ void DHTRoutingTableSerializerTest::testSerialize()
// 4bytes reserved
ss.read(buf, 4);
CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0);
}
void DHTRoutingTableSerializerTest::checkNumNodes
(std::istream& ss, size_t expected)
{
// number of nodes saved
ss.read(buf, 4);
uint32_t numNodes;
memcpy(&numNodes, buf, sizeof(numNodes));
numNodes = ntohl(numNodes);
CPPUNIT_ASSERT_EQUAL((uint32_t)3, numNodes);
CPPUNIT_ASSERT_EQUAL((uint32_t)expected, numNodes);
}
void DHTRoutingTableSerializerTest::testSerialize()
{
SharedHandle<DHTNode> localNode(new DHTNode());
SharedHandle<DHTNode> nodesSrc[3];
for(size_t i = 0; i < A2_ARRAY_LEN(nodesSrc); ++i) {
nodesSrc[i].reset(new DHTNode());
nodesSrc[i]->setIPAddress("192.168.0."+util::uitos(i+1));
nodesSrc[i]->setPort(6881+i);
}
nodesSrc[1]->setIPAddress("non-numerical-name");
std::vector<SharedHandle<DHTNode> > nodes(vbegin(nodesSrc), vend(nodesSrc));
DHTRoutingTableSerializer s(AF_INET);
s.setLocalNode(localNode);
s.setNodes(nodes);
std::stringstream ss;
s.serialize(ss);
checkToLocalnode(ss, localNode);
size_t numNodes = 3;
checkNumNodes(ss, numNodes);
// 4bytes reserved
ss.read(buf, 4);
CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0);
@ -199,4 +222,92 @@ void DHTRoutingTableSerializerTest::testSerialize()
CPPUNIT_ASSERT(ss.eof());
}
void DHTRoutingTableSerializerTest::testSerialize6()
{
SharedHandle<DHTNode> localNode(new DHTNode());
SharedHandle<DHTNode> nodesSrc[2];
for(size_t i = 0; i < A2_ARRAY_LEN(nodesSrc); ++i) {
nodesSrc[i].reset(new DHTNode());
nodesSrc[i]->setIPAddress("2001::100"+util::uitos(i+1));
nodesSrc[i]->setPort(6881+i);
}
nodesSrc[1]->setIPAddress("non-numerical-name");
std::vector<SharedHandle<DHTNode> > nodes(vbegin(nodesSrc), vend(nodesSrc));
DHTRoutingTableSerializer s(AF_INET6);
s.setLocalNode(localNode);
s.setNodes(nodes);
std::stringstream ss;
s.serialize(ss);
checkToLocalnode(ss, localNode);
size_t numNodes = 2;
checkNumNodes(ss, numNodes);
// 4bytes reserved
ss.read(buf, 4);
CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0);
// node[0]
// 1byte compatc peer format length
{
uint8_t len;
ss >> len;
CPPUNIT_ASSERT_EQUAL((uint8_t)18, len);
}
// 7bytes reserved
ss.read(buf, 7);
CPPUNIT_ASSERT(memcmp(zero, buf, 7) == 0);
// 18 bytes compact peer info
ss.read(buf, 18);
{
std::pair<std::string, uint16_t> peer =
bittorrent::unpackcompact(reinterpret_cast<const unsigned char*>(buf),
AF_INET6);
CPPUNIT_ASSERT_EQUAL(std::string("2001::1001"), peer.first);
CPPUNIT_ASSERT_EQUAL((uint16_t)6881, peer.second);
}
// 6bytes reserved
ss.read(buf, 6);
CPPUNIT_ASSERT(memcmp(zero, buf, 6) == 0);
// localnode ID
ss.read(buf, DHT_ID_LENGTH);
CPPUNIT_ASSERT(memcmp(nodes[0]->getID(), buf, DHT_ID_LENGTH) == 0);
// 4bytes reserved
ss.read(buf, 4);
CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0);
// node[1]
// 1byte compatc peer format length
{
uint8_t len;
ss >> len;
CPPUNIT_ASSERT_EQUAL((uint8_t)18, len);
}
// 7bytes reserved
ss.read(buf, 7);
CPPUNIT_ASSERT(memcmp(zero, buf, 7) == 0);
// 18bytes compact peer info
ss.read(buf, 18);
// zero filled because node[1]'s hostname is not numerical form
// deserializer should skip this entry
CPPUNIT_ASSERT(memcmp(zero, buf, 18) == 0);
// 6bytes reserved
ss.read(buf, 6);
CPPUNIT_ASSERT(memcmp(zero, buf, 6) == 0);
// localnode ID
ss.read(buf, DHT_ID_LENGTH);
CPPUNIT_ASSERT(memcmp(nodes[1]->getID(), buf, DHT_ID_LENGTH) == 0);
// 4bytes reserved
ss.read(buf, 4);
CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0);
// check to see stream ends
ss.read(buf, 1);
CPPUNIT_ASSERT_EQUAL((std::streamsize)0, ss.gcount());
CPPUNIT_ASSERT(ss.eof());
}
} // namespace aria2

View File

@ -46,7 +46,7 @@ void LpdMessageDispatcherTest::testSendMessage()
#ifdef __MINGW32__
recvsock->bindWithFamily(LPD_MULTICAST_PORT, AF_INET);
#else // !__MINGW32__
recvsock->bind(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT);
recvsock->bind(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, AF_INET);
#endif // !__MINGW32__
recvsock->joinMulticastGroup(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, "");

View File

@ -81,18 +81,9 @@ public:
createGetPeersReplyMessage
(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<DHTNode> >& closestKNodes,
const std::string& token,
const std::string& transactionID)
{
return SharedHandle<DHTResponseMessage>();
}
virtual SharedHandle<DHTResponseMessage>
createGetPeersReplyMessage(const SharedHandle<DHTNode>& remoteNode,
const std::vector<SharedHandle<Peer> >& peers,
const std::string& token,
const std::string& transactionID)
const std::vector<SharedHandle<Peer> >& peers,
const std::string& token,
const std::string& transactionID)
{
return SharedHandle<DHTResponseMessage>();
}