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 Removed AI_V4MAPPED from DEFAULT_AI_FLAGS
* src/a2netcompat.h * src/a2netcompat.h

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -96,7 +96,12 @@ bool DHTEntryPointNameResolveCommand::execute()
while(!entryPoints_.empty()) { while(!entryPoints_.empty()) {
std::string hostname = entryPoints_.front().first; std::string hostname = entryPoints_.front().first;
try { 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(); hostname = resolver_->getResolvedAddresses().front();
std::pair<std::string, uint16_t> p(hostname, std::pair<std::string, uint16_t> p(hostname,
entryPoints_.front().second); 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::NODES("nodes");
const std::string DHTFindNodeReplyMessage::NODES6("nodes6");
DHTFindNodeReplyMessage::DHTFindNodeReplyMessage DHTFindNodeReplyMessage::DHTFindNodeReplyMessage
(const SharedHandle<DHTNode>& localNode, (int family,
const SharedHandle<DHTNode>& localNode,
const SharedHandle<DHTNode>& remoteNode, const SharedHandle<DHTNode>& remoteNode,
const std::string& transactionID): const std::string& transactionID):
DHTResponseMessage(localNode, remoteNode, transactionID) {} DHTResponseMessage(localNode, remoteNode, transactionID),
family_(family) {}
DHTFindNodeReplyMessage::~DHTFindNodeReplyMessage() {} DHTFindNodeReplyMessage::~DHTFindNodeReplyMessage() {}
@ -73,23 +77,27 @@ SharedHandle<Dict> DHTFindNodeReplyMessage::getResponse()
{ {
SharedHandle<Dict> aDict = Dict::g(); SharedHandle<Dict> aDict = Dict::g();
aDict->put(DHTMessage::ID, String::g(getLocalNode()->getID(), DHT_ID_LENGTH)); 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; size_t offset = 0;
unsigned char buffer[DHTBucket::K*26]; size_t k = 0;
// TODO if closestKNodes_.size() > DHTBucket::K ??
for(std::vector<SharedHandle<DHTNode> >::const_iterator i = for(std::vector<SharedHandle<DHTNode> >::const_iterator i =
closestKNodes_.begin(), eoi = closestKNodes_.end(); closestKNodes_.begin(), eoi = closestKNodes_.end();
i != eoi && offset < DHTBucket::K*26; ++i) { i != eoi && k < DHTBucket::K; ++i) {
SharedHandle<DHTNode> node = *i; SharedHandle<DHTNode> node = *i;
memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH); memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH);
unsigned char compact[COMPACT_LEN_IPV6]; unsigned char compact[COMPACT_LEN_IPV6];
int compactlen = bittorrent::packcompact int compactlen = bittorrent::packcompact
(compact, node->getIPAddress(), node->getPort()); (compact, node->getIPAddress(), node->getPort());
if(compactlen == COMPACT_LEN_IPV4) { if(compactlen == clen) {
memcpy(buffer+20+offset, compact, compactlen); 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; return aDict;
} }

View File

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

View File

@ -70,18 +70,11 @@ void DHTGetPeersMessage::doReceivedAction()
// Check to see localhost has the contents which has same infohash // Check to see localhost has the contents which has same infohash
std::vector<SharedHandle<Peer> > peers; std::vector<SharedHandle<Peer> > peers;
peerAnnounceStorage_->getPeers(peers, infoHash_); peerAnnounceStorage_->getPeers(peers, infoHash_);
SharedHandle<DHTMessage> reply; std::vector<SharedHandle<DHTNode> > nodes;
if(peers.empty()) { getRoutingTable()->getClosestKNodes(nodes, infoHash_);
std::vector<SharedHandle<DHTNode> > nodes; SharedHandle<DHTMessage> reply =
getRoutingTable()->getClosestKNodes(nodes, infoHash_); getMessageFactory()->createGetPeersReplyMessage
reply = (getRemoteNode(), nodes, peers, token, getTransactionID());
getMessageFactory()->createGetPeersReplyMessage
(getRemoteNode(), nodes, token, getTransactionID());
} else {
reply =
getMessageFactory()->createGetPeersReplyMessage
(getRemoteNode(), peers, token, getTransactionID());
}
getMessageDispatcher()->addMessageToQueue(reply); 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::NODES("nodes");
const std::string DHTGetPeersReplyMessage::NODES6("nodes6");
DHTGetPeersReplyMessage::DHTGetPeersReplyMessage DHTGetPeersReplyMessage::DHTGetPeersReplyMessage
(const SharedHandle<DHTNode>& localNode, (int family,
const SharedHandle<DHTNode>& localNode,
const SharedHandle<DHTNode>& remoteNode, const SharedHandle<DHTNode>& remoteNode,
const std::string& token, const std::string& token,
const std::string& transactionID): const std::string& transactionID):
DHTResponseMessage(localNode, remoteNode, transactionID), DHTResponseMessage(localNode, remoteNode, transactionID),
family_(family),
token_(token) {} token_(token) {}
DHTGetPeersReplyMessage::~DHTGetPeersReplyMessage() {} DHTGetPeersReplyMessage::~DHTGetPeersReplyMessage() {}
@ -77,59 +81,69 @@ SharedHandle<Dict> DHTGetPeersReplyMessage::getResponse()
SharedHandle<Dict> rDict = Dict::g(); SharedHandle<Dict> rDict = Dict::g();
rDict->put(DHTMessage::ID, String::g(getLocalNode()->getID(), DHT_ID_LENGTH)); rDict->put(DHTMessage::ID, String::g(getLocalNode()->getID(), DHT_ID_LENGTH));
rDict->put(TOKEN, token_); 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; size_t offset = 0;
unsigned char buffer[DHTBucket::K*26]; size_t k = 0;
for(std::vector<SharedHandle<DHTNode> >::const_iterator i = for(std::vector<SharedHandle<DHTNode> >::const_iterator i =
closestKNodes_.begin(), eoi = closestKNodes_.end(); closestKNodes_.begin(), eoi = closestKNodes_.end();
i != eoi && offset < DHTBucket::K*26; ++i) { i != eoi && k < DHTBucket::K; ++i) {
SharedHandle<DHTNode> node = *i; SharedHandle<DHTNode> node = *i;
memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH); memcpy(buffer+offset, node->getID(), DHT_ID_LENGTH);
unsigned char compact[COMPACT_LEN_IPV6]; unsigned char compact[COMPACT_LEN_IPV6];
int compactlen = bittorrent::packcompact int compactlen = bittorrent::packcompact
(compact, node->getIPAddress(), node->getPort()); (compact, node->getIPAddress(), node->getPort());
if(compactlen == COMPACT_LEN_IPV4) { if(compactlen == clen) {
memcpy(buffer+20+offset, compact, compactlen); memcpy(buffer+20+offset, compact, compactlen);
offset += 26; offset += unit;
++k;
} }
} }
rDict->put(NODES, String::g(buffer, offset)); rDict->put(family_ == AF_INET?NODES:NODES6, String::g(buffer, offset));
} else { }
if(!values_.empty()) {
// Limit the size of values list. The maxmum size of UDP datagram // Limit the size of values list. The maxmum size of UDP datagram
// is limited to 65535 bytes. aria2 uses 20bytes token and 2byte // is limited to 65535 bytes. aria2 uses 20bytes token and 2byte
// transaction ID. The size of get_peers reply message without // 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 // d1:rd2:id20:aaaaaaaaaaaaaaaaaaaa5:token20:aaaaaaaaaaaaaaaaaaaa
// 6:valueslee1:t2:bb1:y1:re // 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 // Because of Path MTU Discovery, UDP packet size which need not
// to be fragmented is much smaller. Since Linux uses Path MTU // to be fragmented is much smaller. Since Linux uses Path MTU
// Dicoverry by default and returning ICMP message might be // Dicoverry by default and returning ICMP message might be
// filtered, we should avoid fragmentation. MTU of pppoe is 1492 // filtered, we should avoid fragmentation. MTU of pppoe is 1492
// max according to RFC2516. We use maximum packet size to be // max according to RFC2516. We use maximum packet size to be
// 1000. Since it contains 20 bytes IP header and 8 bytes UDP // 1024. Since it contains 20 bytes IP header and 8 bytes UDP
// header and 87 bytes reply message template described above, We // header and 395 bytes reply message template described above, We
// can carry (1000-28-87)/8 = 110 peer info. Since DHT spec // can carry (1024-28-395)/(18+3) = 28 peer info. Since DHT spec
// doesn't specify the maximum size of token, reply message // 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. // 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(); SharedHandle<List> valuesList = List::g();
for(std::vector<SharedHandle<Peer> >::const_iterator i = values_.begin(), for(std::vector<SharedHandle<Peer> >::const_iterator i = values_.begin(),
eoi = values_.end(); i != eoi && valuesList->size() < MAX_VALUES_SIZE; eoi = values_.end(); i != eoi && valuesList->size() < MAX_VALUES_SIZE;
++i) { ++i) {
const SharedHandle<Peer>& peer = *i; const SharedHandle<Peer>& peer = *i;
unsigned char compact[COMPACT_LEN_IPV6]; unsigned char compact[COMPACT_LEN_IPV6];
const int clen = bittorrent::getCompactLength(family_);
int compactlen = bittorrent::packcompact int compactlen = bittorrent::packcompact
(compact, peer->getIPAddress(), peer->getPort()); (compact, peer->getIPAddress(), peer->getPort());
if(compactlen == COMPACT_LEN_IPV4) { if(compactlen == clen) {
valuesList->append(String::g(compact, compactlen)); valuesList->append(String::g(compact, compactlen));
} }
} }
rDict->put(VALUES, valuesList); rDict->put(VALUES, valuesList);
} }
return rDict; return rDict;
} }
const std::string& DHTGetPeersReplyMessage::getMessageType() const const std::string& DHTGetPeersReplyMessage::getMessageType() const

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -49,17 +49,30 @@ namespace aria2 {
DHTRegistry::Data DHTRegistry::data_; 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() void DHTRegistry::clearData()
{ {
data_.localNode.reset(); clear(data_);
data_.routingTable.reset(); }
data_.taskQueue.reset();
data_.taskFactory.reset(); void DHTRegistry::clearData6()
data_.peerAnnounceStorage.reset(); {
data_.tokenTracker.reset(); clear(data6_);
data_.messageDispatcher.reset();
data_.messageReceiver.reset();
data_.messageFactory.reset();
} }
} // namespace aria2 } // namespace aria2

View File

@ -53,6 +53,8 @@ class DHTMessageFactory;
class DHTRegistry { class DHTRegistry {
private: private:
struct Data { struct Data {
bool initialized;
SharedHandle<DHTNode> localNode; SharedHandle<DHTNode> localNode;
SharedHandle<DHTRoutingTable> routingTable; SharedHandle<DHTRoutingTable> routingTable;
@ -70,9 +72,15 @@ private:
SharedHandle<DHTMessageReceiver> messageReceiver; SharedHandle<DHTMessageReceiver> messageReceiver;
SharedHandle<DHTMessageFactory> messageFactory; SharedHandle<DHTMessageFactory> messageFactory;
Data():initialized(false) {}
}; };
static Data data_; static Data data_;
static Data data6_;
static void clear(Data& data);
DHTRegistry(); DHTRegistry();
public: public:
static const Data& getData() static const Data& getData()
@ -86,6 +94,38 @@ public:
} }
static void clearData(); 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 } // namespace aria2

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1325,6 +1325,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_BITTORRENT); op->addTag(TAG_BITTORRENT);
handlers.push_back(op); 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 SharedHandle<OptionHandler> op(new DefaultOptionHandler
(PREF_DHT_FILE_PATH, (PREF_DHT_FILE_PATH,
@ -1334,6 +1344,34 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_BITTORRENT); op->addTag(TAG_BITTORRENT);
handlers.push_back(op); 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 SharedHandle<OptionHandler> op(new IntegerRangeOptionHandler
(PREF_DHT_LISTEN_PORT, (PREF_DHT_LISTEN_PORT,
@ -1363,6 +1401,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
op->addTag(TAG_BITTORRENT); op->addTag(TAG_BITTORRENT);
handlers.push_back(op); 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 SharedHandle<OptionHandler> op(new BooleanOptionHandler
(PREF_ENABLE_PEER_EXCHANGE, (PREF_ENABLE_PEER_EXCHANGE,

View File

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

View File

@ -60,8 +60,13 @@
#include "DHTTaskQueue.h" #include "DHTTaskQueue.h"
#include "DHTTaskFactory.h" #include "DHTTaskFactory.h"
#include "DHTNode.h" #include "DHTNode.h"
#include "DHTSetup.h"
#include "DHTRegistry.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 "PieceStorage.h"
#include "RequestGroup.h" #include "RequestGroup.h"
#include "BtAnnounce.h" #include "BtAnnounce.h"
@ -102,6 +107,17 @@ PeerInteractionCommand::PeerInteractionCommand
setWriteCheckSocket(getSocket()); setWriteCheckSocket(getSocket());
setTimeout(getOption()->getAsInt(PREF_PEER_CONNECTION_TIMEOUT)); 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 = SharedHandle<TorrentAttribute> torrentAttrs =
bittorrent::getTorrentAttrs(requestGroup_->getDownloadContext()); bittorrent::getTorrentAttrs(requestGroup_->getDownloadContext());
bool metadataGetMode = torrentAttrs->metadata.empty(); bool metadataGetMode = torrentAttrs->metadata.empty();
@ -131,11 +147,18 @@ PeerInteractionCommand::PeerInteractionCommand
factory->setPieceStorage(pieceStorage); factory->setPieceStorage(pieceStorage);
factory->setPeerStorage(peerStorage); factory->setPeerStorage(peerStorage);
factory->setExtensionMessageFactory(extensionMessageFactory); factory->setExtensionMessageFactory(extensionMessageFactory);
factory->setPeer(getPeer()); factory->setPeer(getPeer());
factory->setLocalNode(DHTRegistry::getData().localNode); if(family == AF_INET) {
factory->setRoutingTable(DHTRegistry::getData().routingTable); factory->setLocalNode(DHTRegistry::getData().localNode);
factory->setTaskQueue(DHTRegistry::getData().taskQueue); factory->setRoutingTable(DHTRegistry::getData().routingTable);
factory->setTaskFactory(DHTRegistry::getData().taskFactory); 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) { if(metadataGetMode) {
factory->enableMetadataGetMode(); factory->enableMetadataGetMode();
} }
@ -192,10 +215,18 @@ PeerInteractionCommand::PeerInteractionCommand
if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) { if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) {
btInteractive->setUTPexEnabled(true); btInteractive->setUTPexEnabled(true);
} }
if(DHTSetup::initialized()) { if(family == AF_INET) {
btInteractive->setDHTEnabled(true); if(DHTRegistry::isInitialized()) {
btInteractive->setLocalNode(DHTRegistry::getData().localNode); btInteractive->setDHTEnabled(true);
factory->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); btInteractive->setUTMetadataRequestFactory(utMetadataRequestFactory);

View File

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

View File

@ -54,6 +54,7 @@
#include "TimeA2.h" #include "TimeA2.h"
#include "a2functional.h" #include "a2functional.h"
#include "LogFactory.h" #include "LogFactory.h"
#include "A2STR.h"
#ifdef ENABLE_SSL #ifdef ENABLE_SSL
# include "TLSContext.h" # include "TLSContext.h"
#endif // ENABLE_SSL #endif // ENABLE_SSL
@ -215,6 +216,14 @@ static sock_t bindInternal(int family, int socktype, int protocol,
CLOSE(fd); CLOSE(fd);
return -1; 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) { if(::bind(fd, addr, addrlen) == -1) {
error = errorMsg(); error = errorMsg();
CLOSE(fd); 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(); closeConnection();
std::string error; std::string error;
sock_t fd = const char* addrp;
bindTo(addr.c_str(), port, protocolFamily_, sockType_, flags, error); if(addr.empty()) {
if(fd == (sock_t)-1) { addrp = 0;
throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, error.c_str()).str());
} else { } 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()) { 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) { if(fd != (sock_t) -1) {
sockfd_ = fd; sockfd_ = fd;
} }
@ -294,7 +297,11 @@ void SocketCore::bind(uint16_t port, int flags)
error = gai_strerror(s); error = gai_strerror(s);
continue; 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) { if(fd != (sock_t)-1) {
sockfd_ = fd; sockfd_ = fd;
break; 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) void SocketCore::bind(const struct sockaddr* addr, socklen_t addrlen)
{ {
closeConnection(); closeConnection();

View File

@ -137,8 +137,6 @@ public:
void bindWithFamily(uint16_t port, int family, int flags = AI_PASSIVE); 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. * Creates a socket and bind it with locahost's address and port.
* flags is set to struct addrinfo's ai_flags. * 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(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. * Listens form connection on it.
* Call bind(uint16_t) before calling this function. * Call bind(uint16_t) before calling this function.

View File

@ -994,6 +994,17 @@ std::string torrent2Magnet(const SharedHandle<TorrentAttribute>& attrs)
return uri; 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 bittorrent
} // namespace aria2 } // namespace aria2

View File

@ -246,6 +246,9 @@ void extractPeer(const ValueBase* peerData, int family, OutputIterator dest)
const unsigned char* end = base+length; const unsigned char* end = base+length;
for(; base != end; base += unit) { for(; base != end; base += unit) {
std::pair<std::string, uint16_t> p = unpackcompact(base, family_); std::pair<std::string, uint16_t> p = unpackcompact(base, family_);
if(p.first.empty()) {
continue;
}
*dest_++ = SharedHandle<Peer>(new Peer(p.first, p.second)); *dest_++ = SharedHandle<Peer>(new Peer(p.first, p.second));
} }
} }
@ -288,6 +291,8 @@ void extractPeer
return extractPeer(peerData.get(), family, dest); return extractPeer(peerData.get(), family, dest);
} }
int getCompactLength(int family);
} // namespace bittorrent } // namespace bittorrent
} // namespace aria2 } // 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"); const std::string PREF_ENABLE_PEER_EXCHANGE("enable-peer-exchange");
// values: true | false // values: true | false
const std::string PREF_ENABLE_DHT("enable-dht"); const std::string PREF_ENABLE_DHT("enable-dht");
// values: a string
const std::string PREF_DHT_LISTEN_ADDR("dht-listen-addr");
// values: 1*digit // values: 1*digit
const std::string PREF_DHT_LISTEN_PORT("dht-listen-port"); const std::string PREF_DHT_LISTEN_PORT("dht-listen-port");
// values: a string // 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"); const std::string PREF_DHT_ENTRY_POINT("dht-entry-point");
// values: a string // values: a string
const std::string PREF_DHT_FILE_PATH("dht-file-path"); 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 // values: plain | arc4
const std::string PREF_BT_MIN_CRYPTO_LEVEL("bt-min-crypto-level"); const std::string PREF_BT_MIN_CRYPTO_LEVEL("bt-min-crypto-level");
const std::string V_PLAIN("plain"); 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; extern const std::string PREF_ENABLE_PEER_EXCHANGE;
// values: true | false // values: true | false
extern const std::string PREF_ENABLE_DHT; extern const std::string PREF_ENABLE_DHT;
// values: a string
extern const std::string PREF_DHT_LISTEN_ADDR;
// values: 1*digit // values: 1*digit
extern const std::string PREF_DHT_LISTEN_PORT; extern const std::string PREF_DHT_LISTEN_PORT;
// values: a string // values: a string
@ -322,6 +324,18 @@ extern const std::string PREF_DHT_ENTRY_POINT_PORT;
extern const std::string PREF_DHT_ENTRY_POINT; extern const std::string PREF_DHT_ENTRY_POINT;
// values: a string // values: a string
extern const std::string PREF_DHT_FILE_PATH; 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 // values: plain | arc4
extern const std::string PREF_BT_MIN_CRYPTO_LEVEL; extern const std::string PREF_BT_MIN_CRYPTO_LEVEL;
extern const std::string V_PLAIN; extern const std::string V_PLAIN;

View File

@ -297,18 +297,18 @@
#define TEXT_ENABLE_PEER_EXCHANGE \ #define TEXT_ENABLE_PEER_EXCHANGE \
_(" --enable-peer-exchange[=true|false] Enable Peer Exchange extension.") _(" --enable-peer-exchange[=true|false] Enable Peer Exchange extension.")
#define TEXT_ENABLE_DHT \ #define TEXT_ENABLE_DHT \
_(" --enable-dht[=true|false] Enable DHT functionality.") _(" --enable-dht[=true|false] Enable IPv4 DHT functionality.")
#define TEXT_DHT_LISTEN_PORT \ #define TEXT_DHT_LISTEN_PORT \
_(" --dht-listen-port=PORT... Set UDP listening port for DHT.\n" \ _(" --dht-listen-port=PORT... Set UDP listening port for both IPv4 and IPv6\n" \
" Multiple ports can be specified by using ',',\n" \ " DHT. Multiple ports can be specified by using\n" \
" for example: \"6881,6885\". You can also use '-'\n" \ " ',', for example: \"6881,6885\". You can also\n" \
" to specify a range: \"6881-6999\". ',' and '-' can\n" \ " use '-' to specify a range: \"6881-6999\". ','\n" \
" be used together.") " and '-' can be used together.")
#define TEXT_DHT_ENTRY_POINT \ #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.") " network.")
#define TEXT_DHT_FILE_PATH \ #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 \ #define TEXT_BT_MIN_CRYPTO_LEVEL \
_(" --bt-min-crypto-level=plain|arc4 Set minimum level of encryption method.\n" \ _(" --bt-min-crypto-level=plain|arc4 Set minimum level of encryption method.\n" \
" If several encryption methods are provided by a\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" \ _(" --enable-async-dns6[=true|false] Enable IPv6 name resolution in asynchronous\n" \
" DNS resolver. This option will be ignored when\n" \ " DNS resolver. This option will be ignored when\n" \
" --async-dns=false.") " --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 "DHTConnectionImpl.h"
#include "Exception.h"
#include "SocketCore.h"
#include <iostream> #include <iostream>
#include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/HelperMacros.h>
#include "Exception.h"
#include "SocketCore.h"
#include "A2STR.h"
namespace aria2 { namespace aria2 {
class DHTConnectionImplTest:public CppUnit::TestFixture { class DHTConnectionImplTest:public CppUnit::TestFixture {
@ -25,13 +28,13 @@ CPPUNIT_TEST_SUITE_REGISTRATION(DHTConnectionImplTest);
void DHTConnectionImplTest::testWriteAndReadData() void DHTConnectionImplTest::testWriteAndReadData()
{ {
try { try {
DHTConnectionImpl con1; DHTConnectionImpl con1(AF_INET);
uint16_t con1port = 0; 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; uint16_t con2port = 0;
CPPUNIT_ASSERT(con2.bind(con2port)); CPPUNIT_ASSERT(con2.bind(con2port, A2STR::NIL));
std::string message1 = "hello world."; std::string message1 = "hello world.";
// hostname should be "localhost", not 127.0.0.1. Test failed on Mac OSX10.5 // 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_SUITE(DHTFindNodeReplyMessageTest);
CPPUNIT_TEST(testGetBencodedMessage); CPPUNIT_TEST(testGetBencodedMessage);
CPPUNIT_TEST(testGetBencodedMessage6);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
public: public:
void setUp() {} void setUp() {}
@ -22,6 +23,8 @@ public:
void tearDown() {} void tearDown() {}
void testGetBencodedMessage(); void testGetBencodedMessage();
void testGetBencodedMessage6();
}; };
@ -36,7 +39,7 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage()
util::generateRandomData(tid, DHT_TRANSACTION_ID_LENGTH); util::generateRandomData(tid, DHT_TRANSACTION_ID_LENGTH);
std::string transactionID(&tid[0], &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"); msg.setVersion("A200");
std::string compactNodeInfo; std::string compactNodeInfo;
SharedHandle<DHTNode> nodes[8]; SharedHandle<DHTNode> nodes[8];
@ -46,8 +49,8 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage()
nodes[i]->setPort(6881+i); nodes[i]->setPort(6881+i);
unsigned char buf[COMPACT_LEN_IPV6]; unsigned char buf[COMPACT_LEN_IPV6];
bittorrent::packcompact CPPUNIT_ASSERT_EQUAL(COMPACT_LEN_IPV4, bittorrent::packcompact
(buf, nodes[i]->getIPAddress(), nodes[i]->getPort()); (buf, nodes[i]->getIPAddress(), nodes[i]->getPort()));
compactNodeInfo += compactNodeInfo +=
std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+ std::string(&nodes[i]->getID()[0], &nodes[i]->getID()[DHT_ID_LENGTH])+
std::string(&buf[0], &buf[COMPACT_LEN_IPV4]); std::string(&buf[0], &buf[COMPACT_LEN_IPV4]);
@ -69,4 +72,46 @@ void DHTFindNodeReplyMessageTest::testGetBencodedMessage()
CPPUNIT_ASSERT_EQUAL(bencode2::encode(&dict), msgbody); 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 } // namespace aria2

View File

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

View File

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

View File

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

View File

@ -20,6 +20,7 @@ class DHTRoutingTableDeserializerTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DHTRoutingTableDeserializerTest); CPPUNIT_TEST_SUITE(DHTRoutingTableDeserializerTest);
CPPUNIT_TEST(testDeserialize); CPPUNIT_TEST(testDeserialize);
CPPUNIT_TEST(testDeserialize6);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
public: public:
void setUp() {} void setUp() {}
@ -27,6 +28,8 @@ public:
void tearDown() {} void tearDown() {}
void testDeserialize(); void testDeserialize();
void testDeserialize6();
}; };
@ -45,14 +48,14 @@ void DHTRoutingTableDeserializerTest::testDeserialize()
nodesSrc[1]->setIPAddress("non-numerical-name"); nodesSrc[1]->setIPAddress("non-numerical-name");
std::vector<SharedHandle<DHTNode> > nodes(vbegin(nodesSrc), vend(nodesSrc)); std::vector<SharedHandle<DHTNode> > nodes(vbegin(nodesSrc), vend(nodesSrc));
DHTRoutingTableSerializer s; DHTRoutingTableSerializer s(AF_INET);
s.setLocalNode(localNode); s.setLocalNode(localNode);
s.setNodes(nodes); s.setNodes(nodes);
std::stringstream ss; std::stringstream ss;
s.serialize(ss); s.serialize(ss);
DHTRoutingTableDeserializer d; DHTRoutingTableDeserializer d(AF_INET);
d.deserialize(ss); d.deserialize(ss);
CPPUNIT_ASSERT(memcmp(localNode->getID(), d.getLocalNode()->getID(), 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); 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 } // namespace aria2

View File

@ -20,42 +20,35 @@ class DHTRoutingTableSerializerTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DHTRoutingTableSerializerTest); CPPUNIT_TEST_SUITE(DHTRoutingTableSerializerTest);
CPPUNIT_TEST(testSerialize); CPPUNIT_TEST(testSerialize);
CPPUNIT_TEST(testSerialize6);
CPPUNIT_TEST_SUITE_END(); 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: public:
void setUp() {} void setUp()
{
memset(zero, 0, sizeof(zero));
}
void tearDown() {} void tearDown() {}
void testSerialize(); void testSerialize();
void testSerialize6();
}; };
CPPUNIT_TEST_SUITE_REGISTRATION(DHTRoutingTableSerializerTest); 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 // header
ss.read(buf, 8); ss.read(buf, 8);
// magic // magic
@ -89,14 +82,44 @@ void DHTRoutingTableSerializerTest::testSerialize()
// 4bytes reserved // 4bytes reserved
ss.read(buf, 4); ss.read(buf, 4);
CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0); CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0);
}
void DHTRoutingTableSerializerTest::checkNumNodes
(std::istream& ss, size_t expected)
{
// number of nodes saved // number of nodes saved
ss.read(buf, 4); ss.read(buf, 4);
uint32_t numNodes; uint32_t numNodes;
memcpy(&numNodes, buf, sizeof(numNodes)); memcpy(&numNodes, buf, sizeof(numNodes));
numNodes = ntohl(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 // 4bytes reserved
ss.read(buf, 4); ss.read(buf, 4);
CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0); CPPUNIT_ASSERT(memcmp(zero, buf, 4) == 0);
@ -199,4 +222,92 @@ void DHTRoutingTableSerializerTest::testSerialize()
CPPUNIT_ASSERT(ss.eof()); 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 } // namespace aria2

View File

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

View File

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